Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
156 changes: 128 additions & 28 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@
"next-auth": "^4.24.6",
"next-themes": "^0.3.0",
"openai": "^4.24.7",
"orchid-orm": "^1.17.18",
"orchid-orm": "^1.36.1",
"orchid-orm-schema-to-zod": "^0.4.21",
"parse-diff": "^0.11.1",
"patch-package": "^8.0.0",
Expand Down
14 changes: 13 additions & 1 deletion src/app/dashboard/[org]/[repo]/chat/components/Chat.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { type Evaluation } from "~/server/api/routers/chat";
import { api } from "~/trpc/react";
import { motion, AnimatePresence } from "framer-motion";
import MarkdownRenderer from "../../components/MarkdownRenderer";
import ChatHistoryDropdown from "./ChatHistoryDropdown";

interface ChatProps {
project: Project;
Expand Down Expand Up @@ -39,6 +40,9 @@ export function Chat({ project, contextItems, org, repo }: ChatProps) {
const [isCreatingArtifact, setIsCreatingArtifact] = useState(false);
const [showLoadingCard, setShowLoadingCard] = useState(false);
const [codeFiles, setCodeFiles] = useState<CodeFile[]>([]);
const [selectedSessionId, setSelectedSessionId] = useState<string | null>(
null,
);

const { messages, input, handleInputChange, handleSubmit, isLoading } =
useChat({
Expand Down Expand Up @@ -251,10 +255,18 @@ export function Chat({ project, contextItems, org, repo }: ChatProps) {

if (!mounted) return null;

const handleSelectSession = (sessionId: string) => {
setSelectedSessionId(sessionId);
// TODO: Implement logic to load the selected chat session
};

return (
<div className="flex h-full w-full flex-row space-x-4">
<div className="mx-auto flex h-full w-full max-w-4xl flex-row overflow-clip rounded-md bg-white/50 p-4 shadow-sm dark:bg-slate-800">
<div className="mx-auto mr-4 flex flex-1 flex-col">
<div className="mr-4 flex flex-col">
<ChatHistoryDropdown onSelectSession={handleSelectSession} />
</div>
<div className="mx-auto flex flex-1 flex-col">
<div className="hide-scrollbar mb-4 flex-1 overflow-y-auto">
{messages.map((m: Message, index: number) => (
<div
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
import React, { useState, useEffect } from "react";
import { ChevronDownIcon } from "@heroicons/react/20/solid";

interface ChatSession {
id: string;
timestamp: string;
summary: string;
}

interface ChatHistoryDropdownProps {
onSelectSession: (sessionId: string) => void;
}

const ChatHistoryDropdown: React.FC<ChatHistoryDropdownProps> = ({
onSelectSession,
}) => {
const [sessions, setSessions] = useState<ChatSession[]>([]);
const [isOpen, setIsOpen] = useState(false);

useEffect(() => {
// TODO: Fetch chat sessions from the API
// For now, we'll use mock data
setSessions([
{
id: "1",
timestamp: "2023-05-01 10:00",
summary: "Discussion about React hooks",
},
{
id: "2",
timestamp: "2023-05-02 14:30",
summary: "Debugging session for API integration",
},
]);
}, []);

const handleSelectSession = (sessionId: string) => {
onSelectSession(sessionId);
setIsOpen(false);
};

return (
<div className="relative inline-block text-left">
<div>
<button
onClick={() => setIsOpen(!isOpen)}
className="inline-flex w-full justify-center gap-x-1.5 rounded-md bg-white px-3 py-2 text-sm font-semibold text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 hover:bg-gray-50"
>
Chat History
<ChevronDownIcon
className="-mr-1 h-5 w-5 text-gray-400"
aria-hidden="true"
/>
</button>
</div>
{isOpen && (
<div className="absolute left-0 z-10 mt-2 w-56 origin-top-left rounded-md bg-white shadow-lg ring-1 ring-black ring-opacity-5 focus:outline-none">
<div className="py-1">
{sessions.map((session) => (
<button
key={session.id}
onClick={() => handleSelectSession(session.id)}
className="block w-full px-4 py-2 text-left text-sm hover:bg-gray-100"
>
<div className="font-medium">{session.summary}</div>
<div className="text-xs text-gray-500">{session.timestamp}</div>
</button>
))}
</div>
</div>
)}
</div>
);
};

export default ChatHistoryDropdown;
46 changes: 46 additions & 0 deletions src/server/api/routers/chat.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { TRPCError } from "@trpc/server";
import { z } from "zod";
import { createTRPCRouter, protectedProcedure } from "~/server/api/trpc";
import { chatSessions } from "~/server/db/tables/chatSessions.table";
import { sendGptRequestWithSchema } from "~/server/openai/request";
import { standardizePath } from "~/server/utils/files";

Expand All @@ -17,6 +18,51 @@ const EvaluationSchema = z.object({
export type Evaluation = z.infer<typeof EvaluationSchema>;

export const chatRouter = createTRPCRouter({
getChatSessions: protectedProcedure.query(async ({ ctx }) => {
try {
const sessions = await chatSessions.findMany({
where: { userId: ctx.session.user.id },
orderBy: { sessionStart: "desc" },
select: {
id: true,
sessionStart: true,
summary: true,
},
});
return sessions;
} catch (error) {
console.error("Error fetching chat sessions", error);
throw new TRPCError({
code: "INTERNAL_SERVER_ERROR",
message: "Failed to fetch chat sessions",
});
}
}),

getChatSessionMessages: protectedProcedure
.input(z.object({ sessionId: z.string().uuid() }))
.query(async ({ ctx, input }) => {
try {
const messages = await chatSessions.findFirst({
where: { id: input.sessionId, userId: ctx.session.user.id },
select: { messages: true },
});
if (!messages) {
throw new TRPCError({
code: "NOT_FOUND",
message: "Chat session not found",
});
}
return messages.messages;
} catch (error) {
console.error("Error fetching chat session messages", error);
throw new TRPCError({
code: "INTERNAL_SERVER_ERROR",
message: "Failed to fetch chat session messages",
});
}
}),

evaluateChatMessage: protectedProcedure
.input(
z.object({
Expand Down
Loading