* trpc same data shape as generateText
* read `.env` file * use zustand for state management * fix peer dependency warnings by installing zod * install milvus client
This commit is contained in:
+69
-12
@@ -1,34 +1,76 @@
|
||||
import { JsonInput, Tabs, Textarea } from "@mantine/core";
|
||||
import { useState } from "react";
|
||||
import { trpc } from "../../trpc/client";
|
||||
import { create } from "zustand";
|
||||
import type { Message as UIMessage } from "ai";
|
||||
import type { OtherParameters, Store } from "./types.js";
|
||||
|
||||
const defaultSystemPrompt = `You are a helpful assistant that answers questions based on the provided context. If you don't know the answer, just say that you don't know, don't try to make up an answer.`;
|
||||
const defaultParameters = {
|
||||
temperature: 0.5,
|
||||
max_tokens: 100,
|
||||
};
|
||||
} as OtherParameters;
|
||||
|
||||
const useStore = create<Store>()((set) => ({
|
||||
messages: [],
|
||||
message: "",
|
||||
systemPrompt: defaultSystemPrompt,
|
||||
parameters: defaultParameters,
|
||||
loading: false,
|
||||
setMessages: (messages) => set({ messages }),
|
||||
setMessage: (message) => set({ message }),
|
||||
setSystemPrompt: (systemPrompt) => set({ systemPrompt }),
|
||||
setParameters: (parameters) => set({ parameters }),
|
||||
setLoading: (loading) => set({ loading }),
|
||||
}));
|
||||
|
||||
export default function ChatPage() {
|
||||
const [prompt, setPrompt] = useState("");
|
||||
const [systemPrompt, setSystemPrompt] = useState(defaultSystemPrompt);
|
||||
const [parameters, setParameters] = useState(defaultParameters);
|
||||
const messages = useStore((state) => state.messages);
|
||||
const message = useStore((state) => state.message);
|
||||
const systemPrompt = useStore((state) => state.systemPrompt);
|
||||
const parameters = useStore((state) => state.parameters);
|
||||
const loading = useStore((state) => state.loading);
|
||||
const setMessages = useStore((state) => state.setMessages);
|
||||
const setMessage = useStore((state) => state.setMessage);
|
||||
const setSystemPrompt = useStore((state) => state.setSystemPrompt);
|
||||
const setParameters = useStore((state) => state.setParameters);
|
||||
const setLoading = useStore((state) => state.setLoading);
|
||||
|
||||
return (
|
||||
<Tabs defaultValue="prompt">
|
||||
<Tabs defaultValue="message">
|
||||
<Tabs.List>
|
||||
<Tabs.Tab value="prompt">Prompt</Tabs.Tab>
|
||||
<Tabs.Tab value="message">Message</Tabs.Tab>
|
||||
<Tabs.Tab value="system-prompt">System Prompt</Tabs.Tab>
|
||||
<Tabs.Tab value="parameters">Parameters</Tabs.Tab>
|
||||
</Tabs.List>
|
||||
<Tabs.Panel value="prompt">
|
||||
<Tabs.Panel value="message">
|
||||
<Messages messages={messages} />
|
||||
<Textarea
|
||||
resize="vertical"
|
||||
placeholder="Type your message here..."
|
||||
value={prompt}
|
||||
onChange={(e) => setPrompt(e.target.value)}
|
||||
onKeyDown={(e) => {
|
||||
value={message}
|
||||
disabled={loading}
|
||||
onChange={(e) => setMessage(e.target.value)}
|
||||
onKeyDown={async (e) => {
|
||||
if (e.key === "Enter") {
|
||||
e.preventDefault();
|
||||
console.log("Sending message...");
|
||||
const messagesWithNewUserMessage = [
|
||||
...messages,
|
||||
{ role: "user" as const, content: message } as UIMessage,
|
||||
];
|
||||
setMessages(messagesWithNewUserMessage);
|
||||
setLoading(true);
|
||||
const response = await trpc.chat.sendMessage.query({
|
||||
messages: messagesWithNewUserMessage,
|
||||
systemPrompt,
|
||||
parameters,
|
||||
});
|
||||
const messagesWithAssistantMessage = [
|
||||
...messagesWithNewUserMessage,
|
||||
{ role: "assistant", content: response.text } as UIMessage,
|
||||
];
|
||||
setMessages(messagesWithAssistantMessage);
|
||||
setMessage("");
|
||||
setLoading(false);
|
||||
}
|
||||
}}
|
||||
/>
|
||||
@@ -53,3 +95,18 @@ export default function ChatPage() {
|
||||
</Tabs>
|
||||
);
|
||||
}
|
||||
|
||||
function Messages({
|
||||
messages,
|
||||
}: {
|
||||
messages: Array<UIMessage>;
|
||||
}) {
|
||||
return (
|
||||
<div>
|
||||
{messages.map((message, index) => (
|
||||
// biome-ignore lint/suspicious/noArrayIndexKey: <explanation>
|
||||
<div key={index}>{message.content}</div>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
+33
-15
@@ -1,22 +1,40 @@
|
||||
import { router, publicProcedure, Validator } from "../../trpc/server";
|
||||
import { Type as T } from "@sinclair/typebox";
|
||||
import {
|
||||
router,
|
||||
publicProcedure,
|
||||
// Validator
|
||||
} from "../../trpc/server";
|
||||
// import { Type as T } from "@sinclair/typebox";
|
||||
import { createOpenRouter } from "@openrouter/ai-sdk-provider";
|
||||
import { generateText } from "ai";
|
||||
import type { Message as UIMessage } from "ai";
|
||||
import type { OtherParameters } from "./types.js";
|
||||
import { env } from "../../server/env.js";
|
||||
|
||||
const openrouter = createOpenRouter({
|
||||
apiKey: env.OPENROUTER_API_KEY,
|
||||
});
|
||||
|
||||
export const chat = router({
|
||||
sendMessage: publicProcedure
|
||||
.input(
|
||||
Validator(
|
||||
T.Object({
|
||||
prompt: T.String(),
|
||||
systemPrompt: T.String(),
|
||||
parameters: T.Object({
|
||||
temperature: T.Number(),
|
||||
max_tokens: T.Number(),
|
||||
}),
|
||||
}),
|
||||
),
|
||||
(x) =>
|
||||
x as {
|
||||
messages: Array<UIMessage>;
|
||||
systemPrompt: string;
|
||||
parameters: OtherParameters;
|
||||
},
|
||||
)
|
||||
.mutation(async ({ input: { prompt, systemPrompt, parameters } }) => {
|
||||
console.log("Received new todo", { prompt, systemPrompt, parameters });
|
||||
return { prompt, systemPrompt, parameters };
|
||||
.query(async ({ input: { messages, systemPrompt, parameters } }) => {
|
||||
const response = await generateText({
|
||||
model: openrouter("mistralai/mistral-nemo"),
|
||||
messages: [
|
||||
{ role: "system" as const, content: systemPrompt },
|
||||
...messages,
|
||||
],
|
||||
maxSteps: 3,
|
||||
tools: undefined,
|
||||
...parameters,
|
||||
});
|
||||
return response;
|
||||
}),
|
||||
});
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
import type { Message as UIMessage } from "ai";
|
||||
import type { generateText } from "ai";
|
||||
|
||||
export type OtherParameters = Omit<
|
||||
Parameters<typeof generateText>[0],
|
||||
"model" | "messages" | "abortSignal"
|
||||
>;
|
||||
|
||||
export type Store = {
|
||||
messages: Array<UIMessage>;
|
||||
message: string;
|
||||
systemPrompt: string;
|
||||
parameters: OtherParameters;
|
||||
loading: boolean;
|
||||
setMessages: (messages: Array<UIMessage>) => void;
|
||||
setMessage: (message: string) => void;
|
||||
setSystemPrompt: (systemPrompt: string) => void;
|
||||
setParameters: (parameters: OtherParameters) => void;
|
||||
setLoading: (loading: boolean) => void;
|
||||
};
|
||||
Reference in New Issue
Block a user