Merge 02f573907022fbac168d45e67ca0fbe08c6924a0 into da1123d84baa8ced8a9427f866b068b4652e7d9c

This commit is contained in:
sjiampojamarn
2025-04-07 23:50:34 +05:30
committed by GitHub
6 changed files with 129 additions and 3 deletions

View File

@ -29,6 +29,7 @@ type Message = {
messageId: string;
chatId: string;
content: string;
userSessionId: string;
};
type ChatModel = {
@ -138,6 +139,7 @@ const handleHistorySave = async (
where: eq(chats.id, message.chatId),
});
let currentDate = new Date();
if (!chat) {
await db
.insert(chats)
@ -147,6 +149,8 @@ const handleHistorySave = async (
createdAt: new Date().toString(),
focusMode: focusMode,
files: files.map(getFileDetails),
userSessionId: message.userSessionId,
timestamp: currentDate.toISOString(),
})
.execute();
}

View File

@ -1,10 +1,47 @@
import db from '@/lib/db';
import { chats } from '@/lib/db/schema';
import { eq, sql} from 'drizzle-orm';
export const GET = async (req: Request) => {
try {
let chats = await db.query.chats.findMany();
chats = chats.reverse();
return Response.json({ chats: chats }, { status: 200 });
// get header from request
const headers = await req.headers;
const userSessionId = headers.get('user-session-id')?.toString() ?? '';
const maxRecordLimit = parseInt(headers.get('max-record-limit') || '20', 10);
if (userSessionId == '') {
return Response.json({ chats: {} }, { status: 200 });
}
let chatsRes = await db.query.chats.findMany({
where: eq(chats.userSessionId, userSessionId),
});
chatsRes = chatsRes.reverse();
// Keep only the latest records in the database. Delete older records.
if (chatsRes.length > maxRecordLimit) {
const deleteChatsQuery = sql`DELETE FROM chats
WHERE userSessionId = ${userSessionId} AND (
timestamp IS NULL OR
timestamp NOT in (
SELECT timestamp FROM chats
WHERE userSessionId = ${userSessionId}
ORDER BY timestamp DESC
LIMIT ${maxRecordLimit}
)
)
`;
await db.run(deleteChatsQuery);
// Delete messages that no longer link with the chat from the database.
const deleteMessagesQuery = sql`DELETE FROM messages
WHERE chatId NOT IN (
SELECT id FROM chats
)
`;
await db.run(deleteMessagesQuery);
}
return Response.json({ chats: chatsRes }, { status: 200 });
} catch (err) {
console.error('Error in getting chats: ', err);
return Response.json(

View File

@ -1,5 +1,6 @@
'use client';
import crypto from 'crypto';
import DeleteChat from '@/components/DeleteChat';
import { cn, formatTimeDifference } from '@/lib/utils';
import { BookOpenText, ClockIcon, Delete, ScanEye } from 'lucide-react';
@ -21,10 +22,34 @@ const Page = () => {
const fetchChats = async () => {
setLoading(true);
let userSessionId = localStorage.getItem('userSessionId');
if (!userSessionId) {
userSessionId = crypto.randomBytes(20).toString('hex');
localStorage.setItem('userSessionId', userSessionId)
}
// Get maxRecordLimit from localStorage or set default
let maxRecordLimit = localStorage.getItem('maxRecordLimit');
if (!maxRecordLimit) {
maxRecordLimit = '20';
localStorage.setItem('maxRecordLimit', maxRecordLimit);
} else {
let valueInt = parseInt(maxRecordLimit, 10) || 20;
if (valueInt < 1) {
valueInt = 1;
} else if (valueInt > 100) {
valueInt = 100;
}
maxRecordLimit = valueInt.toString();
localStorage.setItem('maxRecordLimit', maxRecordLimit);
}
const res = await fetch(`/api/chats`, {
method: 'GET',
headers: {
'Content-Type': 'application/json',
'user-session-id': userSessionId!,
'max-record-limit': maxRecordLimit,
},
});

View File

@ -24,6 +24,7 @@ interface SettingsType {
customOpenaiApiKey: string;
customOpenaiApiUrl: string;
customOpenaiModelName: string;
maxRecordLimit: string;
}
interface InputProps extends React.InputHTMLAttributes<HTMLInputElement> {
@ -146,6 +147,7 @@ const Page = () => {
const [automaticVideoSearch, setAutomaticVideoSearch] = useState(false);
const [systemInstructions, setSystemInstructions] = useState<string>('');
const [savingStates, setSavingStates] = useState<Record<string, boolean>>({});
const [maxRecordLimit, setMaxRecordLimit] = useState<string>('20');
useEffect(() => {
const fetchConfig = async () => {
@ -208,6 +210,8 @@ const Page = () => {
setSystemInstructions(localStorage.getItem('systemInstructions')!);
setMaxRecordLimit(localStorage.getItem('maxRecordLimit') || data.maxRecordLimit || '20');
setIsLoading(false);
};
@ -366,6 +370,15 @@ const Page = () => {
localStorage.setItem('embeddingModel', value);
} else if (key === 'systemInstructions') {
localStorage.setItem('systemInstructions', value);
} else if (key === 'maxRecordLimit') {
let valueInt = parseInt(value, 10) || 20;
if (valueInt < 1) {
valueInt = 1;
} else if (valueInt > 100) {
valueInt = 100;
}
setMaxRecordLimit(valueInt.toString());
localStorage.setItem('maxRecordLimit', valueInt.toString());
}
} catch (err) {
console.error('Failed to save:', err);
@ -860,6 +873,37 @@ const Page = () => {
</div>
</div>
</SettingsSection>
<SettingsSection title="Chat History">
<div className="flex flex-col space-y-4">
<div className="flex flex-col space-y-1">
<p className="text-black/70 dark:text-white/70 text-sm">
Maximum Chat History Records
</p>
<div className="flex items-center space-x-2">
<Input
type="number"
min="1"
max="100"
pattern="[0-9]*"
inputMode="numeric"
value={maxRecordLimit}
isSaving={savingStates['maxRecordLimit']}
onChange={(e) => {
setMaxRecordLimit(e.target.value);
}}
onSave={(value) => saveConfig('maxRecordLimit', value)}
/>
<span className="text-black/60 dark:text-white/60 text-sm">
records
</span>
</div>
<p className="text-xs text-black/60 dark:text-white/60 mt-1">
Maximum number of chat records to keep in history. Older records will be automatically deleted.
</p>
</div>
</div>
</SettingsSection>
</div>
)
)}

View File

@ -95,6 +95,18 @@ const checkConfig = async (
if (!embeddingModel || !embeddingModelProvider) {
const embeddingModelProviders = providers.embeddingModelProviders;
let userSessionId = localStorage.getItem('userSessionId');
if (!userSessionId) {
userSessionId = crypto.randomBytes(20).toString('hex');
localStorage.setItem('userSessionId', userSessionId!)
}
let maxRecordLimit = localStorage.getItem('maxRecordLimit');
if (!maxRecordLimit) {
maxRecordLimit = '20';
localStorage.setItem('maxRecordLimit', maxRecordLimit);
}
if (
!embeddingModelProviders ||
Object.keys(embeddingModelProviders).length === 0
@ -342,6 +354,7 @@ const ChatWindow = ({ id }: { id?: string }) => {
let added = false;
messageId = messageId ?? crypto.randomBytes(7).toString('hex');
let userSessionId = localStorage.getItem('userSessionId');
setMessages((prevMessages) => [
...prevMessages,
@ -466,6 +479,7 @@ const ChatWindow = ({ id }: { id?: string }) => {
messageId: messageId,
chatId: chatId!,
content: message,
userSessionId: userSessionId,
},
chatId: chatId!,
files: fileIds,

View File

@ -25,4 +25,6 @@ export const chats = sqliteTable('chats', {
files: text('files', { mode: 'json' })
.$type<File[]>()
.default(sql`'[]'`),
userSessionId: text('userSessionId'),
timestamp: text('timestamp'),
});