akhaliq HF Staff commited on
Commit
eef335e
·
verified ·
1 Parent(s): 2883812

Upload pages/index.js with huggingface_hub

Browse files
Files changed (1) hide show
  1. pages/index.js +211 -0
pages/index.js ADDED
@@ -0,0 +1,211 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { useState, useEffect, useRef } from 'react'
2
+ import ChatMessage from '../components/ChatMessage'
3
+ import ChatInput from '../components/ChatInput'
4
+
5
+ export default function Home() {
6
+ const [messages, setMessages] = useState([
7
+ {
8
+ id: 1,
9
+ role: 'assistant',
10
+ content: 'Hello! I\'m an AI assistant powered by Qwen Vision Language model. I can understand both text and images. You can upload images and ask me questions about them, or just chat with me! How can I help you today?',
11
+ timestamp: new Date().toISOString()
12
+ }
13
+ ])
14
+ const [isLoading, setIsLoading] = useState(false)
15
+ const [isTyping, setIsTyping] = useState(false)
16
+ const messagesEndRef = useRef(null)
17
+
18
+ const scrollToBottom = () => {
19
+ messagesEndRef.current?.scrollIntoView({ behavior: 'smooth' })
20
+ }
21
+
22
+ useEffect(() => {
23
+ scrollToBottom()
24
+ }, [messages])
25
+
26
+ const handleSendMessage = async (messageData) => {
27
+ const userMessage = {
28
+ id: Date.now(),
29
+ role: 'user',
30
+ content: messageData.content,
31
+ image: messageData.image,
32
+ timestamp: new Date().toISOString()
33
+ }
34
+
35
+ setMessages(prev => [...prev, userMessage])
36
+ setIsLoading(true)
37
+ setIsTyping(true)
38
+
39
+ try {
40
+ const response = await fetch('/api/chat', {
41
+ method: 'POST',
42
+ headers: {
43
+ 'Content-Type': 'application/json',
44
+ },
45
+ body: JSON.stringify({
46
+ messages: [...messages, userMessage]
47
+ }),
48
+ })
49
+
50
+ if (!response.ok) {
51
+ throw new Error(`HTTP error! status: ${response.status}`)
52
+ }
53
+
54
+ const reader = response.body.getReader()
55
+ const decoder = new TextDecoder()
56
+ let assistantMessage = {
57
+ id: Date.now() + 1,
58
+ role: 'assistant',
59
+ content: '',
60
+ timestamp: new Date().toISOString()
61
+ }
62
+
63
+ setMessages(prev => [...prev, assistantMessage])
64
+
65
+ while (true) {
66
+ const { done, value } = await reader.read()
67
+ if (done) break
68
+
69
+ const chunk = decoder.decode(value)
70
+ const lines = chunk.split('\n')
71
+
72
+ for (const line of lines) {
73
+ if (line.startsWith('data: ')) {
74
+ const data = line.slice(6)
75
+
76
+ if (data === '[DONE]') {
77
+ setIsTyping(false)
78
+ break
79
+ }
80
+
81
+ try {
82
+ const parsed = JSON.parse(data)
83
+ if (parsed.content) {
84
+ setMessages(prev => {
85
+ const updated = [...prev]
86
+ updated[updated.length - 1] = {
87
+ ...updated[updated.length - 1],
88
+ content: updated[updated.length - 1].content + parsed.content
89
+ }
90
+ return updated
91
+ })
92
+ } else if (parsed.error) {
93
+ throw new Error(parsed.error)
94
+ }
95
+ } catch (e) {
96
+ console.warn('Failed to parse chunk:', data)
97
+ }
98
+ }
99
+ }
100
+ }
101
+
102
+ } catch (error) {
103
+ console.error('Chat error:', error)
104
+ setMessages(prev => [...prev, {
105
+ id: Date.now() + 1,
106
+ role: 'assistant',
107
+ content: `Sorry, I encountered an error: ${error.message}. Please make sure your Hugging Face token is properly configured and try again.`,
108
+ timestamp: new Date().toISOString()
109
+ }])
110
+ } finally {
111
+ setIsLoading(false)
112
+ setIsTyping(false)
113
+ }
114
+ }
115
+
116
+ const clearChat = () => {
117
+ setMessages([
118
+ {
119
+ id: 1,
120
+ role: 'assistant',
121
+ content: 'Hello! I\'m an AI assistant powered by Qwen Vision Language model. I can understand both text and images. You can upload images and ask me questions about them, or just chat with me! How can I help you today?',
122
+ timestamp: new Date().toISOString()
123
+ }
124
+ ])
125
+ }
126
+
127
+ return (
128
+ <div className="min-h-screen flex flex-col bg-gradient-to-br from-slate-900 via-purple-900 to-slate-900">
129
+ {/* Header */}
130
+ <header className="glass-effect border-b border-white border-opacity-20 p-4">
131
+ <div className="max-w-4xl mx-auto flex items-center justify-between">
132
+ <div>
133
+ <h1 className="text-2xl font-bold bg-gradient-to-r from-blue-400 to-purple-400 bg-clip-text text-transparent">
134
+ AI Vision Chat
135
+ </h1>
136
+ <p className="text-sm text-gray-400 mt-1">Powered by Qwen3-VL-8B-Instruct</p>
137
+ </div>
138
+
139
+ <div className="flex items-center gap-4">
140
+ <button
141
+ onClick={clearChat}
142
+ className="px-4 py-2 text-sm bg-gray-700 bg-opacity-50 hover:bg-gray-600 rounded-lg transition-colors"
143
+ disabled={isLoading}
144
+ >
145
+ Clear Chat
146
+ </button>
147
+
148
+ <a
149
+ href="https://huggingface.co/spaces/akhaliq/anycoder"
150
+ target="_blank"
151
+ rel="noopener noreferrer"
152
+ className="text-sm text-blue-400 hover:text-blue-300 transition-colors font-medium"
153
+ >
154
+ Built with anycoder
155
+ </a>
156
+ </div>
157
+ </div>
158
+ </header>
159
+
160
+ {/* Chat Messages */}
161
+ <div className="flex-1 overflow-hidden">
162
+ <div className="max-w-4xl mx-auto h-full px-4 py-6">
163
+ <div className="h-full overflow-y-auto pr-2 scroll-smooth">
164
+ <div className="space-y-6">
165
+ {messages.map((message, index) => (
166
+ <ChatMessage key={message.id} message={message} index={index} />
167
+ ))}
168
+
169
+ {isTyping && (
170
+ <div className="flex gap-3 mb-6 animate-fade-in">
171
+ <div className="flex-shrink-0">
172
+ <div className="w-10 h-10 rounded-full flex items-center justify-center text-white font-semibold bg-gradient-to-r from-green-500 to-blue-500">
173
+ AI
174
+ </div>
175
+ </div>
176
+ <div className="chat-message assistant">
177
+ <div className="flex items-center gap-2">
178
+ <div className="flex gap-1">
179
+ <div className="w-2 h-2 bg-gray-400 rounded-full animate-pulse"></div>
180
+ <div className="w-2 h-2 bg-gray-400 rounded-full animate-pulse" style={{ animationDelay: '0.2s' }}></div>
181
+ <div className="w-2 h-2 bg-gray-400 rounded-full animate-pulse" style={{ animationDelay: '0.4s' }}></div>
182
+ </div>
183
+ <span className="text-xs text-gray-400">AI is typing...</span>
184
+ </div>
185
+ </div>
186
+ </div>
187
+ )}
188
+
189
+ <div ref={messagesEndRef} />
190
+ </div>
191
+ </div>
192
+ </div>
193
+ </div>
194
+
195
+ {/* Input Area */}
196
+ <div className="max-w-4xl mx-auto w-full px-4 pb-6">
197
+ <ChatInput
198
+ onSendMessage={handleSendMessage}
199
+ disabled={isLoading || isTyping}
200
+ />
201
+
202
+ <div className="mt-3 text-center">
203
+ <p className="text-xs text-gray-500">
204
+ Upload images to ask questions about them, or just chat!
205
+ <span className="text-blue-400 ml-1">Powered by Hugging Face</span>
206
+ </p>
207
+ </div>
208
+ </div>
209
+ </div>
210
+ )
211
+ }