Spaces:
Running
Running
Minor things: revalidate cache, table css, card title (#16)
Browse files
- app/api/upload/route.ts +3 -0
- app/chat/[id]/page.tsx +8 -6
- app/globals.css +0 -1
- components/chat-sidebar/ChatCard.tsx +10 -5
- components/chat/ChatDataLoad.tsx +11 -0
- components/chat/ChatMessage.tsx +1 -2
- components/chat/ImageSelector.tsx +2 -2
- components/chat/PromptForm.tsx +2 -2
- components/ui/ImageLoader.tsx +11 -0
- lib/kv/chat.ts +2 -2
app/api/upload/route.ts
CHANGED
|
@@ -3,6 +3,7 @@ import { upload } from '@/lib/aws';
|
|
| 3 |
import { createKVChat } from '@/lib/kv/chat';
|
| 4 |
import { ChatEntity, MessageBase } from '@/lib/types';
|
| 5 |
import { nanoid } from '@/lib/utils';
|
|
|
|
| 6 |
|
| 7 |
/**
|
| 8 |
* TODO: this should be replaced with actual upload to S3
|
|
@@ -56,6 +57,8 @@ export async function POST(req: Request): Promise<Response> {
|
|
| 56 |
|
| 57 |
await createKVChat(payload);
|
| 58 |
|
|
|
|
|
|
|
| 59 |
return Response.json(payload);
|
| 60 |
} catch (error) {
|
| 61 |
return new Response((error as Error).message, {
|
|
|
|
| 3 |
import { createKVChat } from '@/lib/kv/chat';
|
| 4 |
import { ChatEntity, MessageBase } from '@/lib/types';
|
| 5 |
import { nanoid } from '@/lib/utils';
|
| 6 |
+
import { revalidatePath } from 'next/cache';
|
| 7 |
|
| 8 |
/**
|
| 9 |
* TODO: this should be replaced with actual upload to S3
|
|
|
|
| 57 |
|
| 58 |
await createKVChat(payload);
|
| 59 |
|
| 60 |
+
revalidatePath('/chat', 'layout');
|
| 61 |
+
|
| 62 |
return Response.json(payload);
|
| 63 |
} catch (error) {
|
| 64 |
return new Response((error as Error).message, {
|
app/chat/[id]/page.tsx
CHANGED
|
@@ -1,6 +1,6 @@
|
|
| 1 |
-
import
|
| 2 |
-
import {
|
| 3 |
-
import
|
| 4 |
|
| 5 |
interface PageProps {
|
| 6 |
params: {
|
|
@@ -11,7 +11,9 @@ interface PageProps {
|
|
| 11 |
export default async function Page({ params }: PageProps) {
|
| 12 |
const { id: chatId } = params;
|
| 13 |
|
| 14 |
-
|
| 15 |
-
|
| 16 |
-
|
|
|
|
|
|
|
| 17 |
}
|
|
|
|
| 1 |
+
import ChatDataLoad from '@/components/chat/ChatDataLoad';
|
| 2 |
+
import { Suspense } from 'react';
|
| 3 |
+
import Loading from '@/components/ui/Loading';
|
| 4 |
|
| 5 |
interface PageProps {
|
| 6 |
params: {
|
|
|
|
| 11 |
export default async function Page({ params }: PageProps) {
|
| 12 |
const { id: chatId } = params;
|
| 13 |
|
| 14 |
+
return (
|
| 15 |
+
<Suspense fallback={<Loading />}>
|
| 16 |
+
<ChatDataLoad chatId={chatId} />
|
| 17 |
+
</Suspense>
|
| 18 |
+
);
|
| 19 |
}
|
app/globals.css
CHANGED
|
@@ -141,7 +141,6 @@ table {
|
|
| 141 |
}
|
| 142 |
|
| 143 |
tr {
|
| 144 |
-
background-color: var(--color-canvas-default);
|
| 145 |
border-top: 1px solid var(--color-border-muted);
|
| 146 |
}
|
| 147 |
|
|
|
|
| 141 |
}
|
| 142 |
|
| 143 |
tr {
|
|
|
|
| 144 |
border-top: 1px solid var(--color-border-muted);
|
| 145 |
}
|
| 146 |
|
components/chat-sidebar/ChatCard.tsx
CHANGED
|
@@ -18,7 +18,7 @@ export const ChatCardLayout: React.FC<
|
|
| 18 |
return (
|
| 19 |
<Link
|
| 20 |
className={cn(
|
| 21 |
-
'p-2 m-2 bg-background
|
| 22 |
classNames,
|
| 23 |
)}
|
| 24 |
href={link}
|
|
@@ -31,7 +31,12 @@ export const ChatCardLayout: React.FC<
|
|
| 31 |
const ChatCard: React.FC<ChatCardProps> = ({ chat }) => {
|
| 32 |
const { id: chatIdFromParam } = useParams();
|
| 33 |
const { id, url, messages, user } = chat;
|
| 34 |
-
const firstMessage = messages?.[0]?.content
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 35 |
return (
|
| 36 |
<ChatCardLayout
|
| 37 |
link={`/chat/${id}`}
|
|
@@ -45,9 +50,9 @@ const ChatCard: React.FC<ChatCardProps> = ({ chat }) => {
|
|
| 45 |
height={50}
|
| 46 |
className="rounded w-1/4 "
|
| 47 |
/>
|
| 48 |
-
<
|
| 49 |
-
|
| 50 |
-
</
|
| 51 |
</div>
|
| 52 |
</ChatCardLayout>
|
| 53 |
);
|
|
|
|
| 18 |
return (
|
| 19 |
<Link
|
| 20 |
className={cn(
|
| 21 |
+
'p-2 m-2 bg-background max-h-[100px] rounded-xl shadow-md flex items-center border border-transparent hover:border-gray-500 transition-all cursor-pointer',
|
| 22 |
classNames,
|
| 23 |
)}
|
| 24 |
href={link}
|
|
|
|
| 31 |
const ChatCard: React.FC<ChatCardProps> = ({ chat }) => {
|
| 32 |
const { id: chatIdFromParam } = useParams();
|
| 33 |
const { id, url, messages, user } = chat;
|
| 34 |
+
const firstMessage = messages?.[0]?.content;
|
| 35 |
+
const title = firstMessage
|
| 36 |
+
? firstMessage.length > 50
|
| 37 |
+
? firstMessage.slice(0, 50) + '...'
|
| 38 |
+
: firstMessage
|
| 39 |
+
: '(No messages yet)';
|
| 40 |
return (
|
| 41 |
<ChatCardLayout
|
| 42 |
link={`/chat/${id}`}
|
|
|
|
| 50 |
height={50}
|
| 51 |
className="rounded w-1/4 "
|
| 52 |
/>
|
| 53 |
+
<div className="flex items-start h-full">
|
| 54 |
+
<p className="text-sm w-3/4 ml-3">{title}</p>
|
| 55 |
+
</div>
|
| 56 |
</div>
|
| 57 |
</ChatCardLayout>
|
| 58 |
);
|
components/chat/ChatDataLoad.tsx
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import { getKVChat } from '@/lib/kv/chat';
|
| 2 |
+
import { Chat } from '.';
|
| 3 |
+
|
| 4 |
+
export interface ChatDataLoadProps {
|
| 5 |
+
chatId: string;
|
| 6 |
+
}
|
| 7 |
+
|
| 8 |
+
export default async function ChatDataLoad({ chatId }: ChatDataLoadProps) {
|
| 9 |
+
const chat = await getKVChat(chatId);
|
| 10 |
+
return <Chat chat={chat} />;
|
| 11 |
+
}
|
components/chat/ChatMessage.tsx
CHANGED
|
@@ -15,7 +15,6 @@ export interface ChatMessageProps {
|
|
| 15 |
message: MessageBase;
|
| 16 |
}
|
| 17 |
|
| 18 |
-
|
| 19 |
const PAIRS: Record<string, string> = {
|
| 20 |
'┍': '┑',
|
| 21 |
'┝': '┥',
|
|
@@ -91,7 +90,7 @@ export function ChatMessage({ message, ...props }: ChatMessageProps) {
|
|
| 91 |
</div>
|
| 92 |
<div className="flex-1 px-1 ml-4 space-y-2 overflow-hidden">
|
| 93 |
{logs && message.role !== 'user' && (
|
| 94 |
-
<div className="bg-slate-100 mb-4 p-4 max-h-
|
| 95 |
<div className="text-xl font-bold">Thinking Process</div>
|
| 96 |
<MemoizedReactMarkdown
|
| 97 |
className="break-words text-sm"
|
|
|
|
| 15 |
message: MessageBase;
|
| 16 |
}
|
| 17 |
|
|
|
|
| 18 |
const PAIRS: Record<string, string> = {
|
| 19 |
'┍': '┑',
|
| 20 |
'┝': '┥',
|
|
|
|
| 90 |
</div>
|
| 91 |
<div className="flex-1 px-1 ml-4 space-y-2 overflow-hidden">
|
| 92 |
{logs && message.role !== 'user' && (
|
| 93 |
+
<div className="bg-slate-100 dark:bg-slate-900 mb-4 p-4 max-h-[400px] overflow-auto">
|
| 94 |
<div className="text-xl font-bold">Thinking Process</div>
|
| 95 |
<MemoizedReactMarkdown
|
| 96 |
className="break-words text-sm"
|
components/chat/ImageSelector.tsx
CHANGED
|
@@ -51,13 +51,13 @@ const ImageSelector: React.FC<ImageSelectorProps> = () => {
|
|
| 51 |
)}
|
| 52 |
>
|
| 53 |
<input {...getInputProps()} />
|
| 54 |
-
<
|
| 55 |
{isUploading ? (
|
| 56 |
<Loading />
|
| 57 |
) : (
|
| 58 |
'Drag or drop image here, or click to select images'
|
| 59 |
)}
|
| 60 |
-
</
|
| 61 |
</div>
|
| 62 |
);
|
| 63 |
};
|
|
|
|
| 51 |
)}
|
| 52 |
>
|
| 53 |
<input {...getInputProps()} />
|
| 54 |
+
<div className="text-gray-400 text-lg">
|
| 55 |
{isUploading ? (
|
| 56 |
<Loading />
|
| 57 |
) : (
|
| 58 |
'Drag or drop image here, or click to select images'
|
| 59 |
)}
|
| 60 |
+
</div>
|
| 61 |
</div>
|
| 62 |
);
|
| 63 |
};
|
components/chat/PromptForm.tsx
CHANGED
|
@@ -54,8 +54,8 @@ export function PromptForm({
|
|
| 54 |
<TooltipTrigger asChild>
|
| 55 |
<Image
|
| 56 |
src={url}
|
| 57 |
-
width={
|
| 58 |
-
height={
|
| 59 |
alt="chosen image"
|
| 60 |
className="w-1/5 my-4 mx-2 rounded-md"
|
| 61 |
/>
|
|
|
|
| 54 |
<TooltipTrigger asChild>
|
| 55 |
<Image
|
| 56 |
src={url}
|
| 57 |
+
width={250}
|
| 58 |
+
height={250}
|
| 59 |
alt="chosen image"
|
| 60 |
className="w-1/5 my-4 mx-2 rounded-md"
|
| 61 |
/>
|
components/ui/ImageLoader.tsx
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
// import Image from 'next/image';
|
| 2 |
+
// import React from 'react';
|
| 3 |
+
|
| 4 |
+
// type ImageLoaderProps = typeof Image;
|
| 5 |
+
|
| 6 |
+
// const ImageLoader: React.FC<ImageLoaderProps> = props => {
|
| 7 |
+
// const { alt, width, height } = props;
|
| 8 |
+
// return <Image alt={alt} />;
|
| 9 |
+
// };
|
| 10 |
+
|
| 11 |
+
// export default ImageLoader;
|
lib/kv/chat.ts
CHANGED
|
@@ -64,7 +64,7 @@ export async function createKVChat(chat: ChatEntity) {
|
|
| 64 |
score: Date.now(),
|
| 65 |
member: `chat:${chat.id}`,
|
| 66 |
});
|
| 67 |
-
revalidatePath('/chat
|
| 68 |
}
|
| 69 |
|
| 70 |
export async function saveKVChatMessage(id: string, message: MessageBase) {
|
|
@@ -77,7 +77,7 @@ export async function saveKVChatMessage(id: string, message: MessageBase) {
|
|
| 77 |
...chat,
|
| 78 |
messages: [...messages, message],
|
| 79 |
});
|
| 80 |
-
revalidatePath('/chat
|
| 81 |
}
|
| 82 |
|
| 83 |
export async function removeKVChat({ id, path }: { id: string; path: string }) {
|
|
|
|
| 64 |
score: Date.now(),
|
| 65 |
member: `chat:${chat.id}`,
|
| 66 |
});
|
| 67 |
+
revalidatePath('/chat', 'layout');
|
| 68 |
}
|
| 69 |
|
| 70 |
export async function saveKVChatMessage(id: string, message: MessageBase) {
|
|
|
|
| 77 |
...chat,
|
| 78 |
messages: [...messages, message],
|
| 79 |
});
|
| 80 |
+
revalidatePath('/chat', 'layout');
|
| 81 |
}
|
| 82 |
|
| 83 |
export async function removeKVChat({ id, path }: { id: string; path: string }) {
|