import type { Express, Request, Response } from "express"; import OpenAI from "openai"; import { chatStorage } from "./storage"; const openai = new OpenAI({ apiKey: process.env.AI_INTEGRATIONS_OPENAI_API_KEY, baseURL: process.env.AI_INTEGRATIONS_OPENAI_BASE_URL, }); export function registerChatRoutes(app: Express): void { // Get all conversations app.get("/api/conversations", async (req: Request, res: Response) => { try { const conversations = await chatStorage.getAllConversations(); res.json(conversations); } catch (error) { console.error("Error fetching conversations:", error); res.status(500).json({ error: "Failed to fetch conversations" }); } }); // Get single conversation with messages app.get("/api/conversations/:id", async (req: Request, res: Response) => { try { const id = parseInt(req.params.id); const conversation = await chatStorage.getConversation(id); if (!conversation) { return res.status(404).json({ error: "Conversation not found" }); } const messages = await chatStorage.getMessagesByConversation(id); res.json({ ...conversation, messages }); } catch (error) { console.error("Error fetching conversation:", error); res.status(500).json({ error: "Failed to fetch conversation" }); } }); // Create new conversation app.post("/api/conversations", async (req: Request, res: Response) => { try { const { title } = req.body; const conversation = await chatStorage.createConversation(title || "New Chat"); res.status(201).json(conversation); } catch (error) { console.error("Error creating conversation:", error); res.status(500).json({ error: "Failed to create conversation" }); } }); // Delete conversation app.delete("/api/conversations/:id", async (req: Request, res: Response) => { try { const id = parseInt(req.params.id); await chatStorage.deleteConversation(id); res.status(204).send(); } catch (error) { console.error("Error deleting conversation:", error); res.status(500).json({ error: "Failed to delete conversation" }); } }); // Send message and get AI response (streaming) app.post("/api/conversations/:id/messages", async (req: Request, res: Response) => { try { const conversationId = parseInt(req.params.id); const { content } = req.body; // Save user message await chatStorage.createMessage(conversationId, "user", content); // Get conversation history for context const messages = await chatStorage.getMessagesByConversation(conversationId); const chatMessages = messages.map((m) => ({ role: m.role as "user" | "assistant", content: m.content, })); // Set up SSE res.setHeader("Content-Type", "text/event-stream"); res.setHeader("Cache-Control", "no-cache"); res.setHeader("Connection", "keep-alive"); // Stream response from OpenAI const stream = await openai.chat.completions.create({ model: "gpt-5.1", messages: chatMessages, stream: true, max_completion_tokens: 8192, }); let fullResponse = ""; for await (const chunk of stream) { const content = chunk.choices[0]?.delta?.content || ""; if (content) { fullResponse += content; res.write(`data: ${JSON.stringify({ content })}\n\n`); } } // Save assistant message await chatStorage.createMessage(conversationId, "assistant", fullResponse); res.write(`data: ${JSON.stringify({ done: true })}\n\n`); res.end(); } catch (error) { console.error("Error sending message:", error); // Check if headers already sent (SSE streaming started) if (res.headersSent) { res.write(`data: ${JSON.stringify({ error: "Failed to send message" })}\n\n`); res.end(); } else { res.status(500).json({ error: "Failed to send message" }); } } }); }