65 lines
2.0 KiB
JavaScript
65 lines
2.0 KiB
JavaScript
const FALLBACK = {
|
|
identity_title: 'A Better Version of Me',
|
|
identity_summary: 'You are starting a journey to transform yourself, step by step. Every small action counts.',
|
|
suggested_habits: [
|
|
'Do one small positive action today',
|
|
'Avoid one bad habit',
|
|
'Reflect for 2 minutes before sleep',
|
|
],
|
|
};
|
|
|
|
/**
|
|
* Safely parse AI JSON response.
|
|
* Handles markdown wrapping, broken JSON, and missing fields.
|
|
* Always returns a valid result — never throws.
|
|
*
|
|
* @param {string} raw - Raw text from AI response
|
|
* @returns {{ identity_title: string, identity_summary: string, suggested_habits: string[] }}
|
|
*/
|
|
export default function safeParseAI(raw) {
|
|
if (!raw || typeof raw !== 'string') return { ...FALLBACK };
|
|
|
|
try {
|
|
// Strip markdown code fences
|
|
let cleaned = raw.trim();
|
|
cleaned = cleaned.replace(/```json\s*/gi, '').replace(/```\s*/gi, '');
|
|
cleaned = cleaned.trim();
|
|
|
|
// Find first { and last } to extract JSON object
|
|
const start = cleaned.indexOf('{');
|
|
const end = cleaned.lastIndexOf('}');
|
|
if (start === -1 || end === -1) return { ...FALLBACK };
|
|
|
|
cleaned = cleaned.slice(start, end + 1);
|
|
const parsed = JSON.parse(cleaned);
|
|
|
|
// Validate required fields
|
|
const title = typeof parsed.identity_title === 'string' && parsed.identity_title.trim()
|
|
? parsed.identity_title.trim()
|
|
: FALLBACK.identity_title;
|
|
|
|
const summary = typeof parsed.identity_summary === 'string' && parsed.identity_summary.trim()
|
|
? parsed.identity_summary.trim()
|
|
: FALLBACK.identity_summary;
|
|
|
|
let habits = FALLBACK.suggested_habits;
|
|
if (Array.isArray(parsed.suggested_habits) && parsed.suggested_habits.length > 0) {
|
|
habits = parsed.suggested_habits
|
|
.filter((h) => typeof h === 'string' && h.trim())
|
|
.map((h) => h.trim());
|
|
}
|
|
|
|
if (habits.length === 0) habits = FALLBACK.suggested_habits;
|
|
|
|
return {
|
|
identity_title: title,
|
|
identity_summary: summary,
|
|
suggested_habits: habits,
|
|
};
|
|
} catch (_) {
|
|
return { ...FALLBACK };
|
|
}
|
|
}
|
|
|
|
export { FALLBACK };
|