Refactor: Use native json_schema structured output, remove manual schema injection
This commit is contained in:
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -14,12 +14,11 @@ type History = {
|
||||
};
|
||||
|
||||
const INSTRUCTION = `
|
||||
You are an expert quiz solver.
|
||||
You are an expert quiz solver.
|
||||
Please solve the provided question based on its type and provide the correct result.
|
||||
- For choice questions, output the exact index(es) of the correct answer(s).
|
||||
- For text/numerical questions, provide the exact wording or number.
|
||||
- For essay questions, provide a highly detailed and complete response, adapting exactly to the requested 'format' (HTML vs plain text) and building upon any 'initial_text' template if supplied.
|
||||
Always output strict JSON according to the requested schema block.
|
||||
`.trim();
|
||||
|
||||
const SYSTEM_INSTRUCTION_MESSAGE = {
|
||||
|
||||
@@ -21,7 +21,8 @@ async function getChatGPTResponse(
|
||||
const timeoutControler = setTimeout(() => controller.abort(), (config.timeoutValue || 20) * 1000);
|
||||
|
||||
// Get the content to send to chatgpt
|
||||
// Including the instructions to the AI, the images as base64 if needed, the question and the past conversation if history is set to true
|
||||
// Including the instructions to the AI, the images as base64 if needed,
|
||||
// the question and the past conversation if history is set to true
|
||||
const contentHandler = await getContentWithHistory(config, questionElement, question);
|
||||
|
||||
const client = new OpenAI({
|
||||
@@ -40,17 +41,16 @@ async function getChatGPTResponse(
|
||||
const requestPayload: any = {
|
||||
model: config.model,
|
||||
messages: contentHandler.messages.map(msg => ({ ...msg })),
|
||||
max_completion_tokens: config.maxTokens || 2000 // Maximum length of the response,
|
||||
max_completion_tokens: config.maxTokens || 2000
|
||||
};
|
||||
|
||||
// Use the modern json_schema structured output when a schema is available.
|
||||
// The model is guaranteed to return schema-valid JSON — no prompt hacks needed.
|
||||
if (targetSchema) {
|
||||
requestPayload.response_format = {
|
||||
type: 'json_object'
|
||||
type: 'json_schema',
|
||||
json_schema: targetSchema
|
||||
};
|
||||
|
||||
if (requestPayload.messages.length > 0 && requestPayload.messages[0].role === 'system') {
|
||||
requestPayload.messages[0].content += `\n\nYou MUST respond in JSON strictly adhering to the following schema. Do NOT wrap the JSON in markdown code blocks. Output raw JSON only.\n\n${JSON.stringify(targetSchema, null, 2)}`;
|
||||
}
|
||||
}
|
||||
|
||||
const req = await client.chat.completions.create(fixeO(config.model, requestPayload), {
|
||||
@@ -60,17 +60,13 @@ async function getChatGPTResponse(
|
||||
clearTimeout(timeoutControler);
|
||||
|
||||
const rawResponse = req.choices[0].message.content ?? '';
|
||||
let structuredResponse: MoodleQuestionResponse | null = null;
|
||||
|
||||
if (targetSchema) {
|
||||
let structuredResponse: MoodleQuestionResponse | null = null;
|
||||
if (targetSchema && rawResponse) {
|
||||
try {
|
||||
const cleanedResponse = rawResponse
|
||||
.replace(/^```(json)?[\s\S]*?\n([\s\S]*?)```$/g, '$2')
|
||||
.replace(/^```(json)?|```$/gm, '')
|
||||
.trim();
|
||||
structuredResponse = JSON.parse(cleanedResponse);
|
||||
structuredResponse = JSON.parse(rawResponse);
|
||||
} catch (e) {
|
||||
console.error('Failed to parse structured JSON from GPT', e);
|
||||
console.error('Failed to parse structured JSON response', e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user