aboutsummaryrefslogtreecommitdiff
path: root/packages/tools/test/chatapp/app/page.tsx
blob: 6eea7cfcf9babbc72bb1221cf301807eae464e6d (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
"use client"

import type { ModelMessage } from "ai"
import { useState } from "react"

export default function Page() {
	const [input, setInput] = useState("")
	const [messages, setMessages] = useState<ModelMessage[]>([])
	const [isLoading, setIsLoading] = useState(false)

	const handleSendMessage = async () => {
		if (!input.trim() || isLoading) return

		const userMessage = { role: "user" as const, content: input }
		setMessages((currentMessages) => [...currentMessages, userMessage])
		setInput("")
		setIsLoading(true)

		try {
			const response = await fetch("/api/chat", {
				method: "POST",
				headers: {
					"Content-Type": "application/json",
				},
				body: JSON.stringify({
					messages: [...messages, userMessage],
				}),
			})

			const { messages: newMessages } = await response.json()
			setMessages((currentMessages) => [...currentMessages, ...newMessages])
		} catch (error) {
			console.error("Error sending message:", error)
		} finally {
			setIsLoading(false)
		}
	}

	return (
		<div className="min-h-screen bg-background">
			<div className="max-w-4xl mx-auto p-4 h-screen flex flex-col">
				{/* Header */}
				<div className="mb-6">
					<h1 className="text-2xl font-bold text-foreground">Chat App</h1>
					<p className="text-muted-foreground">
						Chat with AI using Supermemory
					</p>
				</div>

				{/* Messages Container */}
				<div className="flex-1 overflow-y-auto space-y-4 mb-4">
					{messages.length === 0 && (
						<div className="text-center text-muted-foreground py-8">
							Start a conversation by typing a message below
						</div>
					)}
					{messages.map((message, index) => (
						<div
							key={`${message.role}-${index}`}
							className={`flex ${
								message.role === "user" ? "justify-end" : "justify-start"
							}`}
						>
							<div
								className={`max-w-[80%] rounded-lg px-4 py-2 ${
									message.role === "user"
										? "bg-blue-500 text-white"
										: "bg-gray-100 text-gray-900 dark:bg-gray-800 dark:text-gray-100"
								}`}
							>
								<div className="text-sm font-medium mb-1 capitalize">
									{message.role}
								</div>
								<div>
									{typeof message.content === "string"
										? message.content
										: message.content
												.filter((part) => part.type === "text")
												.map((part, partIndex) => (
													<div key={`${message.role}-${partIndex}`}>
														{part.text}
													</div>
												))}
								</div>
							</div>
						</div>
					))}
					{isLoading && (
						<div className="flex justify-start">
							<div className="bg-gray-100 dark:bg-gray-800 rounded-lg px-4 py-2">
								<div className="flex items-center space-x-2">
									<div className="animate-spin rounded-full h-4 w-4 border-b-2 border-gray-600" />
									<span className="text-sm text-muted-foreground">
										AI is thinking...
									</span>
								</div>
							</div>
						</div>
					)}
				</div>

				{/* Input Container */}
				<div className="flex gap-2">
					<input
						value={input}
						onChange={(event) => setInput(event.target.value)}
						onKeyDown={(event) => {
							if (event.key === "Enter" && !event.shiftKey) {
								event.preventDefault()
								handleSendMessage()
							}
						}}
						placeholder="Type your message here..."
						disabled={isLoading}
						className="flex-1 px-4 py-2 border border-gray-300 dark:border-gray-600 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent bg-background text-foreground placeholder:text-muted-foreground disabled:opacity-50 disabled:cursor-not-allowed"
					/>
					<button
						type="button"
						onClick={handleSendMessage}
						disabled={!input.trim() || isLoading}
						className="px-6 py-2 bg-blue-500 text-white rounded-lg hover:bg-blue-600 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 disabled:opacity-50 disabled:cursor-not-allowed transition-colors"
					>
						Send
					</button>
				</div>
			</div>
		</div>
	)
}