1. Recherche: fetchChunkSnippets() — après le classement RRF existant, récupère les passages précis qui matchent depuis NoteEmbeddingChunk. Pur affichage, AUCUN changement de classement. 2. Script migration: scripts/migrate-chunk-embeddings.ts Indexe toutes les notes existantes en fragments. Batch de 10, barre de progression. Usage: npx tsx scripts/migrate-chunk-embeddings.ts 3. Memory Echo chunk-level: à faire (US restante)
194 lines
5.8 KiB
TypeScript
194 lines
5.8 KiB
TypeScript
import express from "express";
|
|
import path from "path";
|
|
import { createServer as createViteServer } from "vite";
|
|
import { v4 as uuidv4 } from "uuid";
|
|
import { WebSocketServer, WebSocket } from "ws";
|
|
import { createServer } from "http";
|
|
|
|
interface BrainstormIdea {
|
|
id: string;
|
|
sessionId: string;
|
|
waveNumber: number;
|
|
title: string;
|
|
description: string;
|
|
connectionToSeed: string;
|
|
noveltyScore: number;
|
|
parentIdeaId?: string;
|
|
convertedToNoteId?: string;
|
|
status: 'active' | 'dismissed' | 'converted';
|
|
position?: { x: number; y: number };
|
|
}
|
|
|
|
interface BrainstormSession {
|
|
id: string;
|
|
seedIdea: string;
|
|
sourceNoteId?: string;
|
|
contextNoteIds?: string[];
|
|
createdAt: string;
|
|
updatedAt: string;
|
|
}
|
|
|
|
// In-memory store
|
|
const sessions: BrainstormSession[] = [];
|
|
const ideas: BrainstormIdea[] = [];
|
|
|
|
async function startServer() {
|
|
const app = express();
|
|
const server = createServer(app);
|
|
const wss = new WebSocketServer({ server });
|
|
const PORT = 4000;
|
|
|
|
app.use(express.json());
|
|
|
|
// WebSocket logic
|
|
const rooms = new Map<string, Set<WebSocket>>();
|
|
const roomUsers = new Map<string, Map<WebSocket, any>>();
|
|
|
|
wss.on('connection', (ws) => {
|
|
let currentRoom: string | null = null;
|
|
|
|
ws.on('message', (message) => {
|
|
const data = JSON.parse(message.toString());
|
|
|
|
if (data.type === 'join') {
|
|
const { sessionId, user } = data;
|
|
currentRoom = sessionId;
|
|
|
|
if (!rooms.has(sessionId)) rooms.set(sessionId, new Set());
|
|
if (!roomUsers.has(sessionId)) roomUsers.set(sessionId, new Map());
|
|
|
|
rooms.get(sessionId)!.add(ws);
|
|
roomUsers.get(sessionId)!.set(ws, user || { id: uuidv4(), name: 'Guest' });
|
|
|
|
// Broadcast presence to the room
|
|
const usersInRoom = Array.from(roomUsers.get(sessionId)!.values());
|
|
rooms.get(sessionId)!.forEach(client => {
|
|
if (client.readyState === WebSocket.OPEN) {
|
|
client.send(JSON.stringify({ type: 'presence', users: usersInRoom }));
|
|
}
|
|
});
|
|
|
|
console.log(`User ${user?.name || 'Guest'} joined session: ${sessionId}`);
|
|
}
|
|
|
|
if (data.type === 'idea_added' || data.type === 'idea_updated' || data.type === 'activity' || data.type === 'living_block_update') {
|
|
if (currentRoom && rooms.has(currentRoom)) {
|
|
rooms.get(currentRoom)!.forEach(client => {
|
|
if (client !== ws && client.readyState === WebSocket.OPEN) {
|
|
client.send(JSON.stringify(data));
|
|
}
|
|
});
|
|
}
|
|
}
|
|
});
|
|
|
|
ws.on('close', () => {
|
|
if (currentRoom && rooms.has(currentRoom)) {
|
|
rooms.get(currentRoom)!.delete(ws);
|
|
roomUsers.get(currentRoom)!.delete(ws);
|
|
|
|
// Update presence
|
|
if (rooms.get(currentRoom)!.size > 0) {
|
|
const usersInRoom = Array.from(roomUsers.get(currentRoom)!.values());
|
|
rooms.get(currentRoom)!.forEach(client => {
|
|
if (client.readyState === WebSocket.OPEN) {
|
|
client.send(JSON.stringify({ type: 'presence', users: usersInRoom }));
|
|
}
|
|
});
|
|
} else {
|
|
rooms.delete(currentRoom);
|
|
roomUsers.delete(currentRoom);
|
|
}
|
|
}
|
|
});
|
|
});
|
|
|
|
// API Routes
|
|
app.get("/api/health", (req, res) => {
|
|
res.json({ status: "ok" });
|
|
});
|
|
|
|
// 1. Create session
|
|
app.post("/api/brainstorm/sessions", (req, res) => {
|
|
const { seedIdea, sourceNoteId, contextNoteIds } = req.body;
|
|
|
|
const session: BrainstormSession = {
|
|
id: uuidv4(),
|
|
seedIdea,
|
|
sourceNoteId,
|
|
contextNoteIds,
|
|
createdAt: new Date().toISOString(),
|
|
updatedAt: new Date().toISOString()
|
|
};
|
|
sessions.unshift(session);
|
|
res.json(session);
|
|
});
|
|
|
|
// 2. Add ideas to session
|
|
app.post("/api/brainstorm/:sessionId/ideas", (req, res) => {
|
|
const { sessionId } = req.params;
|
|
const { ideas: newIdeasData } = req.body;
|
|
|
|
const session = sessions.find(s => s.id === sessionId);
|
|
if (!session) return res.status(404).json({ error: "Session not found" });
|
|
|
|
const newIdeas = newIdeasData.map((item: any) => ({
|
|
id: item.id || uuidv4(),
|
|
sessionId,
|
|
waveNumber: item.waveNumber,
|
|
title: item.title,
|
|
description: item.description,
|
|
connectionToSeed: item.connectionToSeed,
|
|
noveltyScore: item.noveltyScore,
|
|
parentIdeaId: item.parentIdeaId,
|
|
status: 'active'
|
|
}));
|
|
|
|
newIdeas.forEach((i: any) => ideas.push(i));
|
|
res.json(newIdeas);
|
|
});
|
|
|
|
// 3. Get all sessions
|
|
app.get("/api/brainstorm/sessions", (req, res) => {
|
|
res.json(sessions);
|
|
});
|
|
|
|
// 4. Get session with ideas
|
|
app.get("/api/brainstorm/:sessionId", (req, res) => {
|
|
const session = sessions.find(s => s.id === req.params.sessionId);
|
|
if (!session) return res.status(404).json({ error: "Session not found" });
|
|
const sessionIdeas = ideas.filter(i => i.sessionId === session.id);
|
|
res.json({ session, ideas: sessionIdeas });
|
|
});
|
|
|
|
// 5. Update idea (position, status)
|
|
app.patch("/api/brainstorm/ideas/:ideaId", (req, res) => {
|
|
const index = ideas.findIndex(i => i.id === req.params.ideaId);
|
|
if (index === -1) return res.status(404).json({ error: "Idea not found" });
|
|
|
|
ideas[index] = { ...ideas[index], ...req.body };
|
|
res.json(ideas[index]);
|
|
});
|
|
|
|
// Vite middleware for development
|
|
if (process.env.NODE_ENV !== "production") {
|
|
const vite = await createViteServer({
|
|
server: { middlewareMode: true },
|
|
appType: "spa",
|
|
});
|
|
app.use(vite.middlewares);
|
|
} else {
|
|
const distPath = path.join(process.cwd(), 'dist');
|
|
app.use(express.static(distPath));
|
|
app.get('*', (req, res) => {
|
|
res.sendFile(path.join(distPath, 'index.html'));
|
|
});
|
|
}
|
|
|
|
server.listen(PORT, "0.0.0.0", () => {
|
|
console.log(`Server running on http://localhost:${PORT}`);
|
|
});
|
|
}
|
|
|
|
startServer();
|