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
@@ -19,7 +19,6 @@ Please solve the provided question based on its type and provide the correct res
|
|||||||
- For choice questions, output the exact index(es) of the correct answer(s).
|
- For choice questions, output the exact index(es) of the correct answer(s).
|
||||||
- For text/numerical questions, provide the exact wording or number.
|
- 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.
|
- 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();
|
`.trim();
|
||||||
|
|
||||||
const SYSTEM_INSTRUCTION_MESSAGE = {
|
const SYSTEM_INSTRUCTION_MESSAGE = {
|
||||||
|
|||||||
@@ -21,7 +21,8 @@ async function getChatGPTResponse(
|
|||||||
const timeoutControler = setTimeout(() => controller.abort(), (config.timeoutValue || 20) * 1000);
|
const timeoutControler = setTimeout(() => controller.abort(), (config.timeoutValue || 20) * 1000);
|
||||||
|
|
||||||
// Get the content to send to chatgpt
|
// 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 contentHandler = await getContentWithHistory(config, questionElement, question);
|
||||||
|
|
||||||
const client = new OpenAI({
|
const client = new OpenAI({
|
||||||
@@ -40,17 +41,16 @@ async function getChatGPTResponse(
|
|||||||
const requestPayload: any = {
|
const requestPayload: any = {
|
||||||
model: config.model,
|
model: config.model,
|
||||||
messages: contentHandler.messages.map(msg => ({ ...msg })),
|
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) {
|
if (targetSchema) {
|
||||||
requestPayload.response_format = {
|
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), {
|
const req = await client.chat.completions.create(fixeO(config.model, requestPayload), {
|
||||||
@@ -60,17 +60,13 @@ async function getChatGPTResponse(
|
|||||||
clearTimeout(timeoutControler);
|
clearTimeout(timeoutControler);
|
||||||
|
|
||||||
const rawResponse = req.choices[0].message.content ?? '';
|
const rawResponse = req.choices[0].message.content ?? '';
|
||||||
let structuredResponse: MoodleQuestionResponse | null = null;
|
|
||||||
|
|
||||||
if (targetSchema) {
|
let structuredResponse: MoodleQuestionResponse | null = null;
|
||||||
|
if (targetSchema && rawResponse) {
|
||||||
try {
|
try {
|
||||||
const cleanedResponse = rawResponse
|
structuredResponse = JSON.parse(rawResponse);
|
||||||
.replace(/^```(json)?[\s\S]*?\n([\s\S]*?)```$/g, '$2')
|
|
||||||
.replace(/^```(json)?|```$/gm, '')
|
|
||||||
.trim();
|
|
||||||
structuredResponse = JSON.parse(cleanedResponse);
|
|
||||||
} catch (e) {
|
} 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