Restored to '7aa09373aacdcc1083018c718e608e30b6be2b33'

Replit-Restored-To: 7aa09373aa
This commit is contained in:
sebastjanartic
2026-02-28 20:34:36 +00:00
parent a8643ecdd2
commit abd322871b
76 changed files with 213 additions and 4640 deletions
-3
View File
@@ -1,3 +0,0 @@
export { registerChatRoutes } from "./routes";
export { chatStorage, type IChatStorage } from "./storage";
-118
View File
@@ -1,118 +0,0 @@
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" });
}
}
});
}
@@ -1,43 +0,0 @@
import { db } from "../../db";
import { conversations, messages } from "@shared/schema";
import { eq, desc } from "drizzle-orm";
export interface IChatStorage {
getConversation(id: number): Promise<typeof conversations.$inferSelect | undefined>;
getAllConversations(): Promise<(typeof conversations.$inferSelect)[]>;
createConversation(title: string): Promise<typeof conversations.$inferSelect>;
deleteConversation(id: number): Promise<void>;
getMessagesByConversation(conversationId: number): Promise<(typeof messages.$inferSelect)[]>;
createMessage(conversationId: number, role: string, content: string): Promise<typeof messages.$inferSelect>;
}
export const chatStorage: IChatStorage = {
async getConversation(id: number) {
const [conversation] = await db.select().from(conversations).where(eq(conversations.id, id));
return conversation;
},
async getAllConversations() {
return db.select().from(conversations).orderBy(desc(conversations.createdAt));
},
async createConversation(title: string) {
const [conversation] = await db.insert(conversations).values({ title }).returning();
return conversation;
},
async deleteConversation(id: number) {
await db.delete(messages).where(eq(messages.conversationId, id));
await db.delete(conversations).where(eq(conversations.id, id));
},
async getMessagesByConversation(conversationId: number) {
return db.select().from(messages).where(eq(messages.conversationId, conversationId)).orderBy(messages.createdAt);
},
async createMessage(conversationId: number, role: string, content: string) {
const [message] = await db.insert(messages).values({ conversationId, role, content }).returning();
return message;
},
};