// ============================================================================= // Deletion Analysis Functions // Suggest removals for low-quality or duplicate questions // ============================================================================= import { getOpenAI, getModel, getTemperature } from '../client'; import type { DeletionAnalysis } from '../types'; /** * Analyze questions and suggest deletions (duplicates, unsafe, etc.) */ export async function analyzeQuestionDeletions( questions: { id: string; text: string; partner_text?: string | null; intensity?: number }[], isExplicit: boolean = false ): Promise { const openai = getOpenAI(); const simplifiedQuestions = questions.map(q => ({ id: q.id, text: q.text, partner_text: q.partner_text, intensity: q.intensity, })); const toneInstruction = isExplicit ? 'LEGACY EXPLICIT FLAG: It does not override the universal catalogue safety ceiling. Delete developer-authored sexual acts, explicit anatomy, nudity for stimulation, sex toys, fetishes, BDSM acts, arousal, orgasm, and public sexual activity.' : 'Delete developer-authored sexual acts, explicit anatomy, nudity for stimulation, sex toys, fetishes, BDSM acts, arousal, orgasm, and public sexual activity rather than rewriting them into disguised euphemisms.'; const prompt = ` Identify questions that should be DELETED instead of edited. Only include questions that are better removed than fixed. ${toneInstruction} - duplicate: same core action AND same initiator as another question (near-duplicate). Note: swapped perspectives (e.g., "give" vs "receive") are NOT duplicates. - redundant: minor variation with no added value - off-tone: violates the universal catalogue safety ceiling or the pack's intended tone - unsafe: coercion, minors, illegal acts, or consent violations - too-vague: not actionable or not a clear proposal - broken: grammar/structure too broken to repair without inventing content - off-topic: not relevant to a couples intimacy app 1. Prefer edits over deletions when possible. 2. Duplicates: delete the weaker/less specific version and keep the clearer one. 3. If duplicate, set duplicate_of_id to the kept question's id. 4. Do NOT delete for minor wording issues or intensity mismatches. 5. IMPORTANT: Asymmetric versions of the same activity are NOT duplicates. If one question has text="Do X to your partner" and another has text="Let your partner do X to you", these are DIFFERENT questions because they have different initiators. Only flag as duplicate if both questions have the SAME initiator doing the SAME action. ${JSON.stringify(simplifiedQuestions)} { "deletions": [ { "id": string, "category": "duplicate"|"redundant"|"off-tone"|"unsafe"|"too-vague"|"broken"|"off-topic", "reason": string, "duplicate_of_id": string|null } ] } Only return questions that should be deleted. `; const systemMessage = isExplicit ? 'You are a strict content safety reviewer for a couples connection app. A legacy explicit flag never permits sexual content. Mark content outside the universal safety ceiling for deletion. Always respond with valid JSON only.' : 'You are a strict content safety reviewer for a couples connection app. Mark sexual or explicit content for deletion. Always respond with valid JSON only.'; const response = await openai.chat.completions.create({ model: getModel('fix'), messages: [ { role: 'system', content: systemMessage, }, { role: 'user', content: prompt }, ], response_format: { type: 'json_object' }, temperature: getTemperature('fix', 0.2), }); const content = response.choices[0].message.content; if (!content) throw new Error('No content generated'); let jsonContent = content.trim(); if (jsonContent.startsWith('```')) { jsonContent = jsonContent.replace(/^```(?:json)?\s*\n?/, '').replace(/\n?```\s*$/, ''); } const parsed = JSON.parse(jsonContent); return parsed.deletions || []; }