setup postgres and kyseley for most data instead of milvus
parent
511f05af83
commit
7a9f0c956c
@ -0,0 +1,11 @@
|
|||||||
|
const { makeKyselyHook } = require("kanel-kysely");
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
connection: "postgres://neondb_owner:npg_sOVmj8vWq2zG@ep-withered-king-adiz9gpi-pooler.c-2.us-east-1.aws.neon.tech:5432/neondb?sslmode=require&channel_binding=true",
|
||||||
|
enumStyle: "type",
|
||||||
|
outputPath: "./database/generated",
|
||||||
|
preRenderHooks: [makeKyselyHook()],
|
||||||
|
customTypeMap: {
|
||||||
|
"pg_catalog.timestamp": "string",
|
||||||
|
}
|
||||||
|
};
|
@ -1,10 +0,0 @@
|
|||||||
import { usePageContext } from "vike-react/usePageContext";
|
|
||||||
import { NavLink } from "@mantine/core";
|
|
||||||
|
|
||||||
export function Link({ href, label }: { href: string; label: string }) {
|
|
||||||
const pageContext = usePageContext();
|
|
||||||
const { urlPathname } = pageContext;
|
|
||||||
const isActive =
|
|
||||||
href === "/" ? urlPathname === href : urlPathname.startsWith(href);
|
|
||||||
return <NavLink href={href} label={label} active={isActive} />;
|
|
||||||
}
|
|
@ -0,0 +1,8 @@
|
|||||||
|
// @generated
|
||||||
|
// This file is automatically generated by Kanel. Do not modify manually.
|
||||||
|
|
||||||
|
import type { default as PublicSchema } from './public/PublicSchema';
|
||||||
|
|
||||||
|
type Database = PublicSchema;
|
||||||
|
|
||||||
|
export default Database;
|
@ -0,0 +1,25 @@
|
|||||||
|
// @generated
|
||||||
|
// This file is automatically generated by Kanel. Do not modify manually.
|
||||||
|
|
||||||
|
import type { UsersId } from './Users';
|
||||||
|
import type { ColumnType, Selectable, Insertable, Updateable } from 'kysely';
|
||||||
|
|
||||||
|
/** Identifier type for public.conversations */
|
||||||
|
export type ConversationsId = number & { __brand: 'public.conversations' };
|
||||||
|
|
||||||
|
/** Represents the table public.conversations */
|
||||||
|
export default interface ConversationsTable {
|
||||||
|
id: ColumnType<ConversationsId, never, never>;
|
||||||
|
|
||||||
|
title: ColumnType<string | null, string | null, string | null>;
|
||||||
|
|
||||||
|
created_at: ColumnType<string | null, string | null, string | null>;
|
||||||
|
|
||||||
|
user_id: ColumnType<UsersId | null, UsersId | null, UsersId | null>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type Conversations = Selectable<ConversationsTable>;
|
||||||
|
|
||||||
|
export type NewConversations = Insertable<ConversationsTable>;
|
||||||
|
|
||||||
|
export type ConversationsUpdate = Updateable<ConversationsTable>;
|
@ -0,0 +1,32 @@
|
|||||||
|
// @generated
|
||||||
|
// This file is automatically generated by Kanel. Do not modify manually.
|
||||||
|
|
||||||
|
import type { FactsId } from './Facts';
|
||||||
|
import type { ConversationsId } from './Conversations';
|
||||||
|
import type { ColumnType, Selectable, Insertable, Updateable } from 'kysely';
|
||||||
|
|
||||||
|
/** Identifier type for public.fact_triggers */
|
||||||
|
export type FactTriggersId = number & { __brand: 'public.fact_triggers' };
|
||||||
|
|
||||||
|
/** Represents the table public.fact_triggers */
|
||||||
|
export default interface FactTriggersTable {
|
||||||
|
id: ColumnType<FactTriggersId, never, never>;
|
||||||
|
|
||||||
|
fact_id: ColumnType<FactsId | null, FactsId | null, FactsId | null>;
|
||||||
|
|
||||||
|
trigger_phrase: ColumnType<string | null, string | null, string | null>;
|
||||||
|
|
||||||
|
priority_multiplier: ColumnType<number | null, number | null, number | null>;
|
||||||
|
|
||||||
|
priority_multiplier_reason: ColumnType<string | null, string | null, string | null>;
|
||||||
|
|
||||||
|
scope_conversation_id: ColumnType<ConversationsId | null, ConversationsId | null, ConversationsId | null>;
|
||||||
|
|
||||||
|
created_at: ColumnType<string | null, string | null, string | null>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type FactTriggers = Selectable<FactTriggersTable>;
|
||||||
|
|
||||||
|
export type NewFactTriggers = Insertable<FactTriggersTable>;
|
||||||
|
|
||||||
|
export type FactTriggersUpdate = Updateable<FactTriggersTable>;
|
@ -0,0 +1,28 @@
|
|||||||
|
// @generated
|
||||||
|
// This file is automatically generated by Kanel. Do not modify manually.
|
||||||
|
|
||||||
|
import type { UsersId } from './Users';
|
||||||
|
import type { MessagesId } from './Messages';
|
||||||
|
import type { ColumnType, Selectable, Insertable, Updateable } from 'kysely';
|
||||||
|
|
||||||
|
/** Identifier type for public.facts */
|
||||||
|
export type FactsId = number & { __brand: 'public.facts' };
|
||||||
|
|
||||||
|
/** Represents the table public.facts */
|
||||||
|
export default interface FactsTable {
|
||||||
|
id: ColumnType<FactsId, never, never>;
|
||||||
|
|
||||||
|
user_id: ColumnType<UsersId | null, UsersId | null, UsersId | null>;
|
||||||
|
|
||||||
|
source_message_id: ColumnType<MessagesId | null, MessagesId | null, MessagesId | null>;
|
||||||
|
|
||||||
|
content: ColumnType<string | null, string | null, string | null>;
|
||||||
|
|
||||||
|
created_at: ColumnType<string | null, string | null, string | null>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type Facts = Selectable<FactsTable>;
|
||||||
|
|
||||||
|
export type NewFacts = Insertable<FactsTable>;
|
||||||
|
|
||||||
|
export type FactsUpdate = Updateable<FactsTable>;
|
@ -0,0 +1,32 @@
|
|||||||
|
// @generated
|
||||||
|
// This file is automatically generated by Kanel. Do not modify manually.
|
||||||
|
|
||||||
|
import type { ConversationsId } from './Conversations';
|
||||||
|
import type { default as Role } from './Role';
|
||||||
|
import type { ColumnType, Selectable, Insertable, Updateable } from 'kysely';
|
||||||
|
|
||||||
|
/** Identifier type for public.messages */
|
||||||
|
export type MessagesId = number & { __brand: 'public.messages' };
|
||||||
|
|
||||||
|
/** Represents the table public.messages */
|
||||||
|
export default interface MessagesTable {
|
||||||
|
id: ColumnType<MessagesId, never, never>;
|
||||||
|
|
||||||
|
conversation_id: ColumnType<ConversationsId | null, ConversationsId | null, ConversationsId | null>;
|
||||||
|
|
||||||
|
index: ColumnType<number | null, number | null, number | null>;
|
||||||
|
|
||||||
|
content: ColumnType<string | null, string | null, string | null>;
|
||||||
|
|
||||||
|
running_summary: ColumnType<string | null, string | null, string | null>;
|
||||||
|
|
||||||
|
created_at: ColumnType<string | null, string | null, string | null>;
|
||||||
|
|
||||||
|
role: ColumnType<Role | null, Role | null, Role | null>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type Messages = Selectable<MessagesTable>;
|
||||||
|
|
||||||
|
export type NewMessages = Insertable<MessagesTable>;
|
||||||
|
|
||||||
|
export type MessagesUpdate = Updateable<MessagesTable>;
|
@ -0,0 +1,23 @@
|
|||||||
|
// @generated
|
||||||
|
// This file is automatically generated by Kanel. Do not modify manually.
|
||||||
|
|
||||||
|
import type { default as UsersTable } from './Users';
|
||||||
|
import type { default as MessagesTable } from './Messages';
|
||||||
|
import type { default as ToolsTable } from './Tools';
|
||||||
|
import type { default as FactTriggersTable } from './FactTriggers';
|
||||||
|
import type { default as FactsTable } from './Facts';
|
||||||
|
import type { default as ConversationsTable } from './Conversations';
|
||||||
|
|
||||||
|
export default interface PublicSchema {
|
||||||
|
users: UsersTable;
|
||||||
|
|
||||||
|
messages: MessagesTable;
|
||||||
|
|
||||||
|
tools: ToolsTable;
|
||||||
|
|
||||||
|
fact_triggers: FactTriggersTable;
|
||||||
|
|
||||||
|
facts: FactsTable;
|
||||||
|
|
||||||
|
conversations: ConversationsTable;
|
||||||
|
}
|
@ -0,0 +1,10 @@
|
|||||||
|
// @generated
|
||||||
|
// This file is automatically generated by Kanel. Do not modify manually.
|
||||||
|
|
||||||
|
/** Represents the enum public.role */
|
||||||
|
type Role =
|
||||||
|
| 'user'
|
||||||
|
| 'assistant'
|
||||||
|
| 'system';
|
||||||
|
|
||||||
|
export default Role;
|
@ -0,0 +1,36 @@
|
|||||||
|
// @generated
|
||||||
|
// This file is automatically generated by Kanel. Do not modify manually.
|
||||||
|
|
||||||
|
import type { UsersId } from './Users';
|
||||||
|
import type { MessagesId } from './Messages';
|
||||||
|
import type { ColumnType, Selectable, Insertable, Updateable } from 'kysely';
|
||||||
|
|
||||||
|
/** Identifier type for public.tools */
|
||||||
|
export type ToolsId = number & { __brand: 'public.tools' };
|
||||||
|
|
||||||
|
/** Represents the table public.tools */
|
||||||
|
export default interface ToolsTable {
|
||||||
|
id: ColumnType<ToolsId, never, never>;
|
||||||
|
|
||||||
|
user_id: ColumnType<UsersId | null, UsersId | null, UsersId | null>;
|
||||||
|
|
||||||
|
source_message_id: ColumnType<MessagesId | null, MessagesId | null, MessagesId | null>;
|
||||||
|
|
||||||
|
name: ColumnType<string | null, string | null, string | null>;
|
||||||
|
|
||||||
|
description: ColumnType<string | null, string | null, string | null>;
|
||||||
|
|
||||||
|
parameter_schema: ColumnType<unknown | null, unknown | null, unknown | null>;
|
||||||
|
|
||||||
|
implementation_language: ColumnType<string | null, string | null, string | null>;
|
||||||
|
|
||||||
|
implementation_code: ColumnType<string | null, string | null, string | null>;
|
||||||
|
|
||||||
|
created_at: ColumnType<string | null, string | null, string | null>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type Tools = Selectable<ToolsTable>;
|
||||||
|
|
||||||
|
export type NewTools = Insertable<ToolsTable>;
|
||||||
|
|
||||||
|
export type ToolsUpdate = Updateable<ToolsTable>;
|
@ -0,0 +1,28 @@
|
|||||||
|
// @generated
|
||||||
|
// This file is automatically generated by Kanel. Do not modify manually.
|
||||||
|
|
||||||
|
import type { ColumnType, Selectable, Insertable, Updateable } from 'kysely';
|
||||||
|
|
||||||
|
/** Identifier type for public.users */
|
||||||
|
export type UsersId = number & { __brand: 'public.users' };
|
||||||
|
|
||||||
|
/** Represents the table public.users */
|
||||||
|
export default interface UsersTable {
|
||||||
|
id: ColumnType<UsersId, never, never>;
|
||||||
|
|
||||||
|
username: ColumnType<string | null, string | null, string | null>;
|
||||||
|
|
||||||
|
password: ColumnType<string | null, string | null, string | null>;
|
||||||
|
|
||||||
|
email: ColumnType<string | null, string | null, string | null>;
|
||||||
|
|
||||||
|
last_login: ColumnType<string | null, string | null, string | null>;
|
||||||
|
|
||||||
|
created_at: ColumnType<string | null, string | null, string | null>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type Users = Selectable<UsersTable>;
|
||||||
|
|
||||||
|
export type NewUsers = Insertable<UsersTable>;
|
||||||
|
|
||||||
|
export type UsersUpdate = Updateable<UsersTable>;
|
@ -0,0 +1,21 @@
|
|||||||
|
import { Pool } from "pg";
|
||||||
|
import { Kysely, PostgresDialect } from "kysely";
|
||||||
|
import type Database from "./generated/Database";
|
||||||
|
|
||||||
|
export const pool = new Pool({
|
||||||
|
connectionString:
|
||||||
|
"postgres://neondb_owner:npg_sOVmj8vWq2zG@ep-withered-king-adiz9gpi-pooler.c-2.us-east-1.aws.neon.tech:5432/neondb?sslmode=require&channel_binding=true",
|
||||||
|
// channelBinding: require ?
|
||||||
|
});
|
||||||
|
|
||||||
|
const dialect = new PostgresDialect({
|
||||||
|
pool,
|
||||||
|
});
|
||||||
|
|
||||||
|
// Database interface is passed to Kysely's constructor, and from now on, Kysely
|
||||||
|
// knows your database structure.
|
||||||
|
// Dialect is passed to Kysely's constructor, and from now on, Kysely knows how
|
||||||
|
// to communicate with your database.
|
||||||
|
export const db = new Kysely<Database>({
|
||||||
|
dialect,
|
||||||
|
});
|
@ -0,0 +1,20 @@
|
|||||||
|
.hover-container .show-on-hover {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hover-container:hover .show-on-hover {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hover-container .show-by-default {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hover-container:hover .show-by-default {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.border-on-hover:hover {
|
||||||
|
border: 1px solid var(--mantine-color-gray-9);
|
||||||
|
border-radius: var(--mantine-radius-sm);
|
||||||
|
}
|
@ -1,112 +0,0 @@
|
|||||||
import { JsonInput, Tabs, Textarea } from "@mantine/core";
|
|
||||||
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 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="message">
|
|
||||||
<Tabs.List>
|
|
||||||
<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="message">
|
|
||||||
<Messages messages={messages} />
|
|
||||||
<Textarea
|
|
||||||
resize="vertical"
|
|
||||||
placeholder="Type your message here..."
|
|
||||||
value={message}
|
|
||||||
disabled={loading}
|
|
||||||
onChange={(e) => setMessage(e.target.value)}
|
|
||||||
onKeyDown={async (e) => {
|
|
||||||
if (e.key === "Enter") {
|
|
||||||
e.preventDefault();
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</Tabs.Panel>
|
|
||||||
<Tabs.Panel value="system-prompt">
|
|
||||||
<Textarea
|
|
||||||
resize="vertical"
|
|
||||||
placeholder={defaultSystemPrompt}
|
|
||||||
value={systemPrompt}
|
|
||||||
onChange={(e) => setSystemPrompt(e.target.value)}
|
|
||||||
/>
|
|
||||||
</Tabs.Panel>
|
|
||||||
<Tabs.Panel value="parameters">
|
|
||||||
<JsonInput
|
|
||||||
resize="vertical"
|
|
||||||
formatOnBlur
|
|
||||||
placeholder={JSON.stringify(defaultParameters)}
|
|
||||||
value={JSON.stringify(parameters)}
|
|
||||||
onChange={(value) => setParameters(JSON.parse(value))}
|
|
||||||
/>
|
|
||||||
</Tabs.Panel>
|
|
||||||
</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>
|
|
||||||
);
|
|
||||||
}
|
|
@ -0,0 +1,142 @@
|
|||||||
|
import { JsonInput, Tabs, Textarea } from "@mantine/core";
|
||||||
|
import { trpc } from "../../../trpc/client";
|
||||||
|
import type { Message as UIMessage } from "ai";
|
||||||
|
import { useEffect } from "react";
|
||||||
|
import {
|
||||||
|
defaultParameters,
|
||||||
|
defaultSystemPrompt,
|
||||||
|
useStore,
|
||||||
|
} from "../../../state";
|
||||||
|
import { usePageContext } from "vike-react/usePageContext";
|
||||||
|
import { useData } from "vike-react/useData";
|
||||||
|
import type { Data } from "./+data";
|
||||||
|
import type { ConversationsId } from "../../../database/generated/public/Conversations";
|
||||||
|
|
||||||
|
export default function ChatPage() {
|
||||||
|
const pageContext = usePageContext();
|
||||||
|
const conversationId = Number(pageContext.routeParams.id) as ConversationsId;
|
||||||
|
const conversationTitle = useStore((state) => state.conversationTitle);
|
||||||
|
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 setConversationId = useStore((state) => state.setConversationId);
|
||||||
|
const setConversationTitle = useStore((state) => state.setConversationTitle);
|
||||||
|
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);
|
||||||
|
|
||||||
|
const conversation = useData<Data>();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setConversationId(conversationId);
|
||||||
|
}, [conversationId, setConversationId]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (conversation?.id && conversation?.title) {
|
||||||
|
setConversationId(conversation.id);
|
||||||
|
setConversationTitle(conversation.title);
|
||||||
|
}
|
||||||
|
}, [
|
||||||
|
conversation?.id,
|
||||||
|
conversation?.title,
|
||||||
|
setConversationId,
|
||||||
|
setConversationTitle,
|
||||||
|
]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<div>
|
||||||
|
<span>Conversation #{conversationId} - </span>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
value={conversationTitle}
|
||||||
|
onChange={(e) => {
|
||||||
|
setConversationTitle(e.target.value);
|
||||||
|
}}
|
||||||
|
onBlur={(e) => {
|
||||||
|
trpc.chat.updateConversationTitle.mutate({
|
||||||
|
id: conversationId,
|
||||||
|
title: e.target.value,
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<Tabs defaultValue="message">
|
||||||
|
<Tabs.List>
|
||||||
|
<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="message">
|
||||||
|
<Messages messages={messages} />
|
||||||
|
<Textarea
|
||||||
|
resize="vertical"
|
||||||
|
placeholder="Type your message here..."
|
||||||
|
value={message}
|
||||||
|
disabled={loading}
|
||||||
|
onChange={(e) => setMessage(e.target.value)}
|
||||||
|
onKeyDown={async (e) => {
|
||||||
|
if (e.key === "Enter") {
|
||||||
|
e.preventDefault();
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Tabs.Panel>
|
||||||
|
<Tabs.Panel value="system-prompt">
|
||||||
|
<Textarea
|
||||||
|
resize="vertical"
|
||||||
|
placeholder={defaultSystemPrompt}
|
||||||
|
value={systemPrompt}
|
||||||
|
onChange={(e) => setSystemPrompt(e.target.value)}
|
||||||
|
/>
|
||||||
|
</Tabs.Panel>
|
||||||
|
<Tabs.Panel value="parameters">
|
||||||
|
<JsonInput
|
||||||
|
resize="vertical"
|
||||||
|
formatOnBlur
|
||||||
|
placeholder={JSON.stringify(defaultParameters)}
|
||||||
|
value={JSON.stringify(parameters)}
|
||||||
|
onChange={(value) => setParameters(JSON.parse(value))}
|
||||||
|
/>
|
||||||
|
</Tabs.Panel>
|
||||||
|
</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>
|
||||||
|
);
|
||||||
|
}
|
@ -0,0 +1,13 @@
|
|||||||
|
import type { PageContextServer } from "vike/types";
|
||||||
|
import { createCaller } from "../trpc.js";
|
||||||
|
|
||||||
|
export type Data = Awaited<ReturnType<typeof data>>;
|
||||||
|
|
||||||
|
export const data = async (pageContext: PageContextServer) => {
|
||||||
|
const { id } = pageContext.routeParams;
|
||||||
|
const caller = createCaller({});
|
||||||
|
const conversation = await caller.fetchConversation({
|
||||||
|
id: Number(id),
|
||||||
|
});
|
||||||
|
return conversation;
|
||||||
|
};
|
@ -1,20 +0,0 @@
|
|||||||
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;
|
|
||||||
};
|
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,38 @@
|
|||||||
|
import { create } from "zustand";
|
||||||
|
import type { OtherParameters, Store } from "./types.js";
|
||||||
|
import type { ConversationsId } from "./database/generated/public/Conversations.js";
|
||||||
|
|
||||||
|
export 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.`;
|
||||||
|
export const defaultParameters = {
|
||||||
|
temperature: 0.5,
|
||||||
|
max_tokens: 100,
|
||||||
|
} as OtherParameters;
|
||||||
|
|
||||||
|
export const useStore = create<Store>()((set) => ({
|
||||||
|
conversationId: 0 as ConversationsId,
|
||||||
|
conversationTitle: "",
|
||||||
|
conversations: [],
|
||||||
|
messages: [],
|
||||||
|
message: "",
|
||||||
|
systemPrompt: defaultSystemPrompt,
|
||||||
|
parameters: defaultParameters,
|
||||||
|
loading: false,
|
||||||
|
setConversationId: (conversationId) => set({ conversationId }),
|
||||||
|
setConversationTitle: (conversationTitle) => set({ conversationTitle }),
|
||||||
|
setConversations: (conversations) => set({ conversations }),
|
||||||
|
addConversation: (conversation) =>
|
||||||
|
set((state) => ({
|
||||||
|
conversations: [...state.conversations, conversation],
|
||||||
|
})),
|
||||||
|
removeConversation: (conversationId) =>
|
||||||
|
set((state) => ({
|
||||||
|
conversations: state.conversations.filter(
|
||||||
|
(conversation) => conversation.id !== conversationId,
|
||||||
|
),
|
||||||
|
})),
|
||||||
|
setMessages: (messages) => set({ messages }),
|
||||||
|
setMessage: (message) => set({ message }),
|
||||||
|
setSystemPrompt: (systemPrompt) => set({ systemPrompt }),
|
||||||
|
setParameters: (parameters) => set({ parameters }),
|
||||||
|
setLoading: (loading) => set({ loading }),
|
||||||
|
}));
|
@ -0,0 +1,36 @@
|
|||||||
|
import type { Message as UIMessage } from "ai";
|
||||||
|
import type { generateText } from "ai";
|
||||||
|
import type {
|
||||||
|
Conversations,
|
||||||
|
ConversationsId,
|
||||||
|
} from "./database/generated/public/Conversations";
|
||||||
|
|
||||||
|
export type OtherParameters = Omit<
|
||||||
|
Parameters<typeof generateText>[0],
|
||||||
|
"model" | "messages" | "abortSignal"
|
||||||
|
>;
|
||||||
|
|
||||||
|
export type ConversationUI = Conversations & {};
|
||||||
|
|
||||||
|
export type Store = {
|
||||||
|
/** This is a string because Milvus sends it as a string, and the value
|
||||||
|
* overflows the JS integer anyway. */
|
||||||
|
conversationId: ConversationsId;
|
||||||
|
conversationTitle: string;
|
||||||
|
conversations: Array<ConversationUI>;
|
||||||
|
messages: Array<UIMessage>;
|
||||||
|
message: string;
|
||||||
|
systemPrompt: string;
|
||||||
|
parameters: OtherParameters;
|
||||||
|
loading: boolean;
|
||||||
|
setConversationId: (conversationId: ConversationsId) => void;
|
||||||
|
setConversationTitle: (conversationTitle: string) => void;
|
||||||
|
setConversations: (conversations: Array<ConversationUI>) => void;
|
||||||
|
addConversation: (conversation: ConversationUI) => void;
|
||||||
|
removeConversation: (conversationId: ConversationsId) => void;
|
||||||
|
setMessages: (messages: Array<UIMessage>) => void;
|
||||||
|
setMessage: (message: string) => void;
|
||||||
|
setSystemPrompt: (systemPrompt: string) => void;
|
||||||
|
setParameters: (parameters: OtherParameters) => void;
|
||||||
|
setLoading: (loading: boolean) => void;
|
||||||
|
};
|
Loading…
Reference in New Issue