works up to LLM request

This commit is contained in:
aodulov
2025-10-10 15:04:28 +03:00
parent 0111938b43
commit b8c42c4604
6 changed files with 94 additions and 84 deletions

View File

@@ -1,8 +1,4 @@
manifest.json:1 Manifest: Line: 1, column: 1, Syntax error.
websocket.ts:20 WebSocket connected
websocket.ts:28 WebSocketService: Received and parsed message: {type: 'STATE_UPDATE', payload: {…}}payload: session: clients: [[Prototype]]: ObjectexpectedResponses: 0finalResult: nullresponses: [[Prototype]]: Objectstate: "SETUP"submittedCount: 0[[Prototype]]: Object[[Prototype]]: Objecttype: "STATE_UPDATE"[[Prototype]]: Object
useSession.ts:81 useSession: Processing incoming message: {type: 'STATE_UPDATE', payload: {…}}payload: session: clients: [[Prototype]]: ObjectexpectedResponses: 0finalResult: nullresponses: [[Prototype]]: Objectstate: "SETUP"submittedCount: 0[[Prototype]]: Object[[Prototype]]: Objecttype: "STATE_UPDATE"[[Prototype]]: Object
websocket.ts:28 WebSocketService: Received and parsed message: {type: 'STATE_UPDATE', payload: {…}}payload: session: clients: [[Prototype]]: ObjectexpectedResponses: 2finalResult: nullresponses: [[Prototype]]: Objectstate: "GATHERING"submittedCount: 0[[Prototype]]: Object[[Prototype]]: Objecttype: "STATE_UPDATE"[[Prototype]]: Object
useSession.ts:81 useSession: Processing incoming message: {type: 'STATE_UPDATE', payload: {…}}payload: session: clients: [[Prototype]]: ObjectexpectedResponses: 2finalResult: nullresponses: [[Prototype]]: Objectstate: "GATHERING"submittedCount: 0[[Prototype]]: Object[[Prototype]]: Objecttype: "STATE_UPDATE"[[Prototype]]: Object
browser-integration.js:2 port disconnected from addon code: 8258ac25-409c-4e4d-8c4a-46b4ab8d1ff7
(anonymous) @ browser-integration.js:2
websocket.ts:28 WebSocketService: Received and parsed message: {type: 'STATE_UPDATE', payload: {…}}payload: session: clients: Array(2)0: "24620bff-a27e-49f7-8e1a-bebc5f4aeec7"1: "685ac684-d79c-4ae6-89cb-7665870f7c0e"length: 2[[Prototype]]: Array(0)expectedResponses: 2finalResult: nullresponses: 685ac684-d79c-4ae6-89cb-7665870f7c0e: {participantId: '685ac684-d79c-4ae6-89cb-7665870f7c0e', wants: Array(1), accepts: Array(1), noGoes: Array(1)}24620bff-a27e-49f7-8e1a-bebc5f4aeec7: {participantId: '24620bff-a27e-49f7-8e1a-bebc5f4aeec7', wants: Array(1), accepts: Array(1), noGoes: Array(1)}[[Prototype]]: Objectstate: "HARMONIZING"submittedCount: 2topic: "Drinks?"[[Prototype]]: Object[[Prototype]]: Objecttype: "STATE_UPDATE"[[Prototype]]: Object
useSession.ts:81 useSession: Processing incoming message: {type: 'STATE_UPDATE', payload: {…}}payload: session: {state: 'HARMONIZING', topic: 'Drinks?', expectedResponses: 2, submittedCount: 2, responses: {…}, …}[[Prototype]]: Objecttype: "STATE_UPDATE"[[Prototype]]: Object
websocket.ts:28 WebSocketService: Received and parsed message: {type: 'STATE_UPDATE', payload: {…}}payload: session: clients: Array(2)0: "24620bff-a27e-49f7-8e1a-bebc5f4aeec7"1: "685ac684-d79c-4ae6-89cb-7665870f7c0e"length: 2[[Prototype]]: Array(0)expectedResponses: 2finalResult: nullresponses: 685ac684-d79c-4ae6-89cb-7665870f7c0e: {participantId: '685ac684-d79c-4ae6-89cb-7665870f7c0e', wants: Array(1), accepts: Array(1), noGoes: Array(1)}24620bff-a27e-49f7-8e1a-bebc5f4aeec7: {participantId: '24620bff-a27e-49f7-8e1a-bebc5f4aeec7', wants: Array(1), accepts: Array(1), noGoes: Array(1)}[[Prototype]]: Objectstate: "GATHERING"submittedCount: 2topic: "Drinks?"[[Prototype]]: Object[[Prototype]]: Objecttype: "STATE_UPDATE"[[Prototype]]: Object
useSession.ts:81 useSession: Processing incoming message: {type: 'STATE_UPDATE', payload: {…}}payload: session: clients: Array(2)0: "24620bff-a27e-49f7-8e1a-bebc5f4aeec7"1: "685ac684-d79c-4ae6-89cb-7665870f7c0e"length: 2[[Prototype]]: Array(0)expectedResponses: 2finalResult: nullresponses: 685ac684-d79c-4ae6-89cb-7665870f7c0e: {participantId: '685ac684-d79c-4ae6-89cb-7665870f7c0e', wants: Array(1), accepts: Array(1), noGoes: Array(1)}24620bff-a27e-49f7-8e1a-bebc5f4aeec7: {participantId: '24620bff-a27e-49f7-8e1a-bebc5f4aeec7', wants: Array(1), accepts: Array(1), noGoes: Array(1)}[[Prototype]]: Objectstate: "GATHERING"submittedCount: 2topic: "Drinks?"[[Prototype]]: Object[[Prototype]]: Objecttype: "STATE_UPDATE"[[Prototype]]: Object

3
.gitignore vendored
View File

@@ -1,2 +1,3 @@
/frontend/node_modules
/backend/node_modules
/backend/node_modules
/.context

View File

@@ -1 +1 @@
GEMINI_API_KEY=AIzaSyDke9H2NhiG6rBwxT0qrdYgnNoNZm_0j58
GEMINI_API_KEY="AIzaSyDke9H2NhiG6rBwxT0qrdYgnNoNZm_0j58"

View File

@@ -21,6 +21,7 @@ export enum SessionState {
GATHERING = 'GATHERING',
HARMONIZING = 'HARMONIZING',
FINAL = 'FINAL',
ERROR = 'ERROR',
}
// A map to hold session data, including clients and the latest state
@@ -146,85 +147,89 @@ export const createWebSocketServer = (server: any) => {
broadcastToSession(sessionId, { type: 'STATE_UPDATE', payload: {} });
console.log(`Session ${sessionId} moved to HARMONIZING. Triggering LLM analysis.`);
try {
const allDesires = Array.from(sessionData.responses.values());
const canonicalMap = await llmService.analyzeDesires(allDesires);
// Perform LLM analysis asynchronously
(async () => {
try {
const allDesires = Array.from(sessionData.responses.values());
const canonicalMap = await llmService.analyzeDesires(allDesires);
const semanticDesiresMap = new Map<string, SemanticDesire>();
const semanticDesiresMap = new Map<string, SemanticDesire>();
for (const originalDesire in canonicalMap) {
const canonicalName = canonicalMap[originalDesire];
if (!semanticDesiresMap.has(canonicalName)) {
semanticDesiresMap.set(canonicalName, { title: canonicalName, rawInputs: [] });
for (const originalDesire in canonicalMap) {
const canonicalName = canonicalMap[originalDesire];
if (!semanticDesiresMap.has(canonicalName)) {
semanticDesiresMap.set(canonicalName, { title: canonicalName, rawInputs: [] });
}
semanticDesiresMap.get(canonicalName)?.rawInputs.push(originalDesire);
}
semanticDesiresMap.get(canonicalName)?.rawInputs.push(originalDesire);
const decision: Decision = {
goTos: [],
alsoGoods: [],
considerables: [],
noGoes: [],
};
const participantIds = Array.from(sessionData.responses.keys());
semanticDesiresMap.forEach(semanticDesire => {
let isNoGo = false;
let allWant = true;
let atLeastOneWant = false;
let allAcceptOrWant = true;
for (const pId of participantIds) {
const participantDesireSet = sessionData.responses.get(pId);
if (!participantDesireSet) continue;
const participantWants = new Set(participantDesireSet.wants.map((d: string) => canonicalMap[d] || d));
const participantAccepts = new Set(participantDesireSet.accepts.map((d: string) => canonicalMap[d] || d));
const participantNoGoes = new Set(participantDesireSet.noGoes.map((d: string) => canonicalMap[d] || d));
const canonicalTitle = semanticDesire.title;
if (participantNoGoes.has(canonicalTitle)) {
isNoGo = true;
break;
}
if (!participantWants.has(canonicalTitle)) {
allWant = false;
}
if (participantWants.has(canonicalTitle)) {
atLeastOneWant = true;
}
if (!participantWants.has(canonicalTitle) && !participantAccepts.has(canonicalTitle)) {
allAcceptOrWant = false;
}
}
if (isNoGo) {
decision.noGoes.push(semanticDesire);
} else if (allWant) {
decision.goTos.push(semanticDesire);
} else if (atLeastOneWant && allAcceptOrWant) {
decision.alsoGoods.push(semanticDesire);
} else if (atLeastOneWant || !allAcceptOrWant) {
decision.considerables.push(semanticDesire);
}
});
sessionData.finalResult = decision;
sessionData.state = SessionState.FINAL;
broadcastToSession(sessionId, { type: 'STATE_UPDATE', payload: {} });
console.log(`Analysis complete for session ${sessionId}. Result:`, decision);
} catch (error) {
console.error(`Error during analysis for session ${sessionId}:`, error);
sessionData.state = SessionState.ERROR;
broadcastToSession(sessionId, { type: 'STATE_UPDATE', payload: {} });
}
const decision: Decision = {
goTos: [],
alsoGoods: [],
considerables: [],
noGoes: [],
};
const participantIds = Array.from(sessionData.responses.keys());
semanticDesiresMap.forEach(semanticDesire => {
let isNoGo = false;
let allWant = true;
let atLeastOneWant = false;
let allAcceptOrWant = true;
for (const pId of participantIds) {
const participantDesireSet = sessionData.responses.get(pId);
if (!participantDesireSet) continue;
const participantWants = new Set(participantDesireSet.wants.map((d: string) => canonicalMap[d] || d));
const participantAccepts = new Set(participantDesireSet.accepts.map((d: string) => canonicalMap[d] || d));
const participantNoGoes = new Set(participantDesireSet.noGoes.map((d: string) => canonicalMap[d] || d));
const canonicalTitle = semanticDesire.title;
if (participantNoGoes.has(canonicalTitle)) {
isNoGo = true;
break;
}
if (!participantWants.has(canonicalTitle)) {
allWant = false;
}
if (participantWants.has(canonicalTitle)) {
atLeastOneWant = true;
}
if (!participantWants.has(canonicalTitle) && !participantAccepts.has(canonicalTitle)) {
allAcceptOrWant = false;
}
}
if (isNoGo) {
decision.noGoes.push(semanticDesire);
} else if (allWant) {
decision.goTos.push(semanticDesire);
} else if (atLeastOneWant && allAcceptOrWant) {
decision.alsoGoods.push(semanticDesire);
} else if (atLeastOneWant || !allAcceptOrWant) {
decision.considerables.push(semanticDesire);
}
});
sessionData.finalResult = decision;
sessionData.state = SessionState.FINAL;
broadcastToSession(sessionId, { type: 'STATE_UPDATE', payload: {} });
console.log(`Analysis complete for session ${sessionId}. Result:`, decision);
} catch (error) {
console.error(`Error during analysis for session ${sessionId}:`, error);
sessionData.state = SessionState.GATHERING;
broadcastToSession(sessionId, { type: 'STATE_UPDATE', payload: {} });
}
})();
} else {
// Only broadcast the latest count if the session is not yet harmonizing
broadcastToSession(sessionId, { type: 'STATE_UPDATE', payload: {} });
}
} else {

View File

@@ -35,6 +35,7 @@ export enum SessionState {
GATHERING = 'GATHERING',
HARMONIZING = 'HARMONIZING',
FINAL = 'FINAL',
ERROR = 'ERROR',
}
export interface Session {

View File

@@ -121,9 +121,16 @@ const SessionPage = () => {
<Typography variant="h6" sx={{ mt: 2 }}>Harmonizing Desires...</Typography>
</Box>
)}
{session.state === SessionState.FINAL && session.finalResult && (
<ResultsDisplay decision={session.finalResult} />
)}
{session.state === SessionState.ERROR && (
<Alert severity="error" sx={{ mt: 4 }}>
An error occurred during analysis. Please try again.
</Alert>
)}
</Box>
</Container>
);