import { GoogleGenerativeAI, GenerativeModel } from '@google/generative-ai'; interface DesireSet { wants: string[]; accepts: string[]; noGoes: string[]; } interface Decision { goTo: string; alsoGood: string; considerable: string; noGoes: string; needsDiscussion: string; } export class LLMService { private genAI: GoogleGenerativeAI; private model: GenerativeModel; constructor(apiKey: string) { this.genAI = new GoogleGenerativeAI(apiKey); this.model = this.genAI.getGenerativeModel({ model: "gemini-2.5-flash-lite" }); } async analyzeDesires(desireSets: DesireSet[]): Promise { const prompt = ` You are an AI assistant that analyzes and synthesizes cooperative decisions from a group's desires. Given a list of desire sets from multiple participants, your task is to generate a concise, synthesized text for each of the following categories, reflecting the collective opinion: Here are the rules for categorization and synthesis: - "goTo": Synthesize a text describing what ALL participants want without contradictions. This should be a clear, affirmative statement of shared desire. - "alsoGood": Synthesize a text describing what at least one participant wants, and all other participants accept, and is not a "noGoes" for anyone. This should reflect a generally agreeable outcome. - "considerable": Synthesize a text describing what is wanted or accepted by some, but not all, participants, and is not a "noGoes" for anyone. This should highlight areas of partial agreement or options that could be explored. - "noGoes": Synthesize a text describing what at least ONE participant does not want. This should clearly state the collective exclusions. - "needsDiscussion": Synthesize a text describing where there is a direct conflict (e.g., one participant wants it, another does not want it). This should highlight areas requiring further negotiation. Prioritize the more specific opinions and leave all the specific options if they do not contradict each other drastically. The input will be a JSON object containing a list of desire sets. Each desire set has a participantId and three arrays of strings: "wants", "accepts", and "noGoes". The output should be a JSON object with the following structure, where each category contains a single synthesized text: { "goTo": "Synthesized text for go-to items.", "alsoGood": "Synthesized text for also good items.", "considerable": "Synthesized text for considerable items.", "noGoes": "Synthesized text for no-goes items.", "needsDiscussion": "Synthesized text for needs discussion items." } Here is the input data: ${JSON.stringify(desireSets)} `; try { const result = await this.model.generateContent(prompt); const response = result.response; let text = response.text(); // Clean the response to ensure it is valid JSON const jsonMatch = text.match(/\{.*?\}/s); if (jsonMatch) { text = jsonMatch[0]; } else { // Handle cases where no JSON is found console.error("LLM did not return a valid JSON object. Response:", text); throw new Error('Failed to parse LLM response as JSON.'); } return JSON.parse(text); } catch (error) { console.error("Error calling Gemini API or parsing response:", error); throw error; } } async checkForInnerContradictions(desireSet: DesireSet): Promise { const prompt = ` You are an AI assistant that detects contradictions in a list of desires. Given a JSON object with three lists of desires (wants, accepts, noGoes), determine if there are any contradictions WITHIN each list and across the lists. For example, "I want a dog" and "I don't want any pets" in the same "wants" list is a contradiction; "Pizza" in "wants" and "food" in "do not want" is a contradiction. If a contradiction is found, respond with a concise, single-sentence description of the contradiction. If no contradiction is found, respond with "null". Here is the desire set: ${JSON.stringify(desireSet)} `; try { const result = await this.model.generateContent(prompt); const response = result.response; const text = response.text().trim(); if (text.toLowerCase() === 'null') { return null; } else { return text; } } catch (error) { console.error("Error calling Gemini API for contradiction check:", error); throw error; } } }