fix(llm): 強化 OpenCode JSON 回應解析
This commit is contained in:
+61
-1
@@ -111,9 +111,69 @@ export async function chat(systemPrompt, userContent) {
|
||||
export async function chatJSON(systemPrompt, userContent) {
|
||||
const text = await chat(systemPrompt, userContent);
|
||||
try {
|
||||
return JSON.parse(text.trim().replace(/^```[^\n]*\n?/, '').replace(/```$/, '').trim());
|
||||
return JSON.parse(extractJSONText(text));
|
||||
} catch (e) {
|
||||
line(`[LLM] JSON 解析失敗: ${e.message}`);
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
function stripOuterFence(text) {
|
||||
return String(text)
|
||||
.trim()
|
||||
.replace(/^```[a-zA-Z0-9_-]*\n?/, '')
|
||||
.replace(/```$/, '')
|
||||
.trim();
|
||||
}
|
||||
|
||||
function extractBalancedJSON(text, startIndex) {
|
||||
const source = String(text);
|
||||
const open = source[startIndex];
|
||||
const close = open === '{' ? '}' : ']';
|
||||
let depth = 0;
|
||||
let inString = false;
|
||||
let escaped = false;
|
||||
|
||||
for (let i = startIndex; i < source.length; i++) {
|
||||
const ch = source[i];
|
||||
if (inString) {
|
||||
if (escaped) {
|
||||
escaped = false;
|
||||
} else if (ch === '\\') {
|
||||
escaped = true;
|
||||
} else if (ch === '"') {
|
||||
inString = false;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (ch === '"') {
|
||||
inString = true;
|
||||
continue;
|
||||
}
|
||||
if (ch === open) depth += 1;
|
||||
else if (ch === close) {
|
||||
depth -= 1;
|
||||
if (depth === 0) return source.slice(startIndex, i + 1);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function extractJSONText(text) {
|
||||
const stripped = stripOuterFence(text);
|
||||
try {
|
||||
JSON.parse(stripped);
|
||||
return stripped;
|
||||
} catch {}
|
||||
|
||||
for (let i = 0; i < stripped.length; i++) {
|
||||
if (stripped[i] !== '[' && stripped[i] !== '{') continue;
|
||||
const candidate = extractBalancedJSON(stripped, i);
|
||||
if (!candidate) continue;
|
||||
try {
|
||||
JSON.parse(candidate);
|
||||
return candidate;
|
||||
} catch {}
|
||||
}
|
||||
return stripped;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user