105 lines
4.8 KiB
TypeScript
105 lines
4.8 KiB
TypeScript
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<Decision> {
|
|
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<string | null> {
|
|
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;
|
|
}
|
|
}
|
|
}
|