Mehdi commited on
Commit
e64e72a
·
verified ·
1 Parent(s): 1df6d30

Upload components/ChatInterface.jsx with huggingface_hub

Browse files
Files changed (1) hide show
  1. components/ChatInterface.jsx +266 -0
components/ChatInterface.jsx ADDED
@@ -0,0 +1,266 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { useState, useRef, useEffect } from 'react'
2
+ import { motion, AnimatePresence } from 'framer-motion'
3
+ import { FaRobot, FaUser, FaPaperPlane, FaMicrophone, FaStop, FaCopy, FaThumbsUp, FaThumbsDown, FaRedo, FaLanguage, FaBrain, FaGlobe, FaCheckCircle, FaExclamationTriangle } from 'react-icons/fa'
4
+ import ReactMarkdown from 'react-markdown'
5
+ import { Prism as SyntaxHighlighter } from 'react-syntax-highlighter'
6
+ import { vscDarkPlus } from 'react-syntax-highlighter/dist/cjs/styles/prism'
7
+ import toast from 'react-hot-toast'
8
+
9
+ export default function ChatInterface({ language, theme }) {
10
+ const [messages, setMessages] = useState([
11
+ {
12
+ id: 1,
13
+ type: 'assistant',
14
+ content: language === 'fa' ?
15
+ 'سلام! من GhadirSync-AI هستم، دستیار هوشمند شما. چطور می‌توانم به شما کمک کنم؟' :
16
+ 'Hello! I am GhadirSync-AI, your intelligent assistant. How can I help you?',
17
+ timestamp: new Date(),
18
+ sources: [],
19
+ confidence: 0.95
20
+ }
21
+ ])
22
+ const [input, setInput] = useState('')
23
+ const [isTyping, setIsTyping] = useState(false)
24
+ const [isListening, setIsListening] = useState(false)
25
+ const [selectedModel, setSelectedModel] = useState('local')
26
+ const [useInternet, setUseInternet] = useState(false)
27
+ const messagesEndRef = useRef(null)
28
+ const inputRef = useRef(null)
29
+
30
+ const models = [
31
+ { id: 'local', name: language === 'fa' ? 'مدل محلی' : 'Local Model', icon: FaBrain, color: 'text-green-400' },
32
+ { id: 'gpt4', name: 'GPT-4', icon: FaGlobe, color: 'text-blue-400' },
33
+ { id: 'claude', name: 'Claude', icon: FaBrain, color: 'text-purple-400' },
34
+ ]
35
+
36
+ const scrollToBottom = () => {
37
+ messagesEndRef.current?.scrollIntoView({ behavior: 'smooth' })
38
+ }
39
+
40
+ useEffect(() => {
41
+ scrollToBottom()
42
+ }, [messages])
43
+
44
+ const handleSend = async () => {
45
+ if (!input.trim()) return
46
+
47
+ const userMessage = {
48
+ id: Date.now(),
49
+ type: 'user',
50
+ content: input,
51
+ timestamp: new Date(),
52
+ }
53
+
54
+ setMessages(prev => [...prev, userMessage])
55
+ setInput('')
56
+ setIsTyping(true)
57
+
58
+ // Simulate AI response
59
+ setTimeout(() => {
60
+ const aiResponse = {
61
+ id: Date.now() + 1,
62
+ type: 'assistant',
63
+ content: generateAIResponse(input),
64
+ timestamp: new Date(),
65
+ sources: useInternet ? [
66
+ { title: 'Wikipedia', url: 'https://wikipedia.org' },
67
+ { title: 'Stack Overflow', url: 'https://stackoverflow.com' }
68
+ ] : [],
69
+ confidence: Math.random() * 0.3 + 0.7,
70
+ model: selectedModel
71
+ }
72
+ setMessages(prev => [...prev, aiResponse])
73
+ setIsTyping(false)
74
+ }, 1500)
75
+ }
76
+
77
+ const generateAIResponse = (userInput) => {
78
+ const responses = {
79
+ fa: [
80
+ `برای سوال "${userInput}"، من تحلیل کاملی ارائه می‌دهم:\n\n## تحلیل اصلی\n\n1. **نکته اول**: این یک موضوع مهم است\n2. **نکته دوم**: نیاز به بررسی بیشتر دارد\n3. **نکته سوم**: پیشنهادات عملی\n\n\`\`\`javascript\n// نمونه کد\nfunction example() {\n return "Hello World";\n}\n\`\`\`\n\n**نتیجه‌گیری**: بر اساس تحلیل، بهترین راهکار...`,
81
+ `در پاسخ به "${userInput}":\n\n### اطلاعات کلیدی\n\n- 🎯 هدف اصلی\n- 📊 تحلیل داده‌ها\n- 💡 راهکارهای نوآورانه\n\n## پیشنهادات\n\n1. راهکار اول\n2. راهکار دوم\n3. راهکار سوم\n\n**توجه**: این اطلاعات بر اساس بهترین منابع موجود است.`,
82
+ ],
83
+ en: [
84
+ `For your question "${userInput}", here's my comprehensive analysis:\n\n## Main Analysis\n\n1. **First Point**: This is an important topic\n2. **Second Point**: Requires further investigation\n3. **Third Point**: Practical suggestions\n\n\`\`\`python\n# Sample code\ndef example():\n return "Hello World"\n\`\`\`\n\n**Conclusion**: Based on the analysis, the best solution is...`,
85
+ `In response to "${userInput}":\n\n### Key Information\n\n- 🎯 Main objective\n- 📊 Data analysis\n- 💡 Innovative solutions\n\n## Recommendations\n\n1. First solution\n2. Second solution\n3. Third solution\n\n**Note**: This information is based on the best available sources.`,
86
+ ]
87
+ }
88
+
89
+ const langResponses = responses[language] || responses.en
90
+ return langResponses[Math.floor(Math.random() * langResponses.length)]
91
+ }
92
+
93
+ const handleVoiceInput = () => {
94
+ if (isListening) {
95
+ setIsListening(false)
96
+ toast.success(language === 'fa' ? 'ضبط صدا متوقف شد' : 'Voice recording stopped')
97
+ } else {
98
+ setIsListening(true)
99
+ toast.success(language === 'fa' ? 'در حال ضبط صدا...' : 'Recording voice...')
100
+
101
+ // Simulate voice recognition
102
+ setTimeout(() => {
103
+ setInput(language === 'fa' ? 'این یک متن نمونه از تشخیص صدا است' : 'This is a sample text from voice recognition')
104
+ setIsListening(false)
105
+ }, 3000)
106
+ }
107
+ }
108
+
109
+ const handleCopyMessage = (content) => {
110
+ navigator.clipboard.writeText(content)
111
+ toast.success(language === 'fa' ? 'کپی شد!' : 'Copied!')
112
+ }
113
+
114
+ const handleRegenerateResponse = (messageId) => {
115
+ setIsTyping(true)
116
+ setTimeout(() => {
117
+ setMessages(prev => prev.map(msg =>
118
+ msg.id === messageId
119
+ ? {
120
+ ...msg,
121
+ content: generateAIResponse(' regenerated response'),
122
+ timestamp: new Date()
123
+ }
124
+ : msg
125
+ ))
126
+ setIsTyping(false)
127
+ }, 1500)
128
+ }
129
+
130
+ return (
131
+ <div className="flex flex-col h-full space-y-4">
132
+ {/* Model Selection */}
133
+ <div className="flex items-center justify-between p-4 bg-gray-800 rounded-lg">
134
+ <div className="flex items-center space-x-reverse space-x-4">
135
+ <span className="text-sm font-medium">
136
+ {language === 'fa' ? 'مدل هوش مصنوعی:' : 'AI Model:'}
137
+ </span>
138
+ <div className="flex space-x-reverse space-x-2">
139
+ {models.map(model => {
140
+ const Icon = model.icon
141
+ return (
142
+ <button
143
+ key={model.id}
144
+ onClick={() => setSelectedModel(model.id)}
145
+ className={`flex items-center space-x-reverse space-x-2 px-3 py-2 rounded-lg transition-all ${
146
+ selectedModel === model.id
147
+ ? 'bg-primary-600 text-white'
148
+ : 'bg-gray-700 text-gray-300 hover:bg-gray-600'
149
+ }`}
150
+ >
151
+ <Icon className={`w-4 h-4 ${model.color}`} />
152
+ <span className="text-sm">{model.name}</span>
153
+ </button>
154
+ )
155
+ })}
156
+ </div>
157
+ </div>
158
+
159
+ <button
160
+ onClick={() => setUseInternet(!useInternet)}
161
+ className={`flex items-center space-x-reverse space-x-2 px-3 py-2 rounded-lg transition-all ${
162
+ useInternet
163
+ ? 'bg-green-600 text-white'
164
+ : 'bg-gray-700 text-gray-300 hover:bg-gray-600'
165
+ }`}
166
+ >
167
+ <FaGlobe className="w-4 h-4" />
168
+ <span className="text-sm">
169
+ {language === 'fa' ? 'اینترنت' : 'Internet'}
170
+ </span>
171
+ </button>
172
+ </div>
173
+
174
+ {/* Messages */}
175
+ <div className="flex-1 overflow-y-auto space-y-4 p-4 bg-gray-800 rounded-lg">
176
+ <AnimatePresence>
177
+ {messages.map(message => (
178
+ <motion.div
179
+ key={message.id}
180
+ initial={{ opacity: 0, y: 20 }}
181
+ animate={{ opacity: 1, y: 0 }}
182
+ exit={{ opacity: 0, y: -20 }}
183
+ className={`flex ${message.type === 'user' ? 'justify-start' : 'justify-end'}`}
184
+ >
185
+ <div className={`flex space-x-reverse space-x-3 max-w-3xl ${
186
+ message.type === 'user' ? 'flex-row' : 'flex-row-reverse'
187
+ }`}>
188
+ <div className={`w-10 h-10 rounded-full flex items-center justify-center flex-shrink-0 ${
189
+ message.type === 'user' ? 'bg-primary-500' : 'bg-secondary-500'
190
+ }`}>
191
+ {message.type === 'user' ? (
192
+ <FaUser className="w-5 h-5 text-white" />
193
+ ) : (
194
+ <FaRobot className="w-5 h-5 text-white" />
195
+ )}
196
+ </div>
197
+
198
+ <div className={`flex-1 p-4 rounded-lg ${
199
+ message.type === 'user'
200
+ ? 'bg-primary-600 text-white'
201
+ : 'bg-gray-700 text-gray-100'
202
+ }`}>
203
+ <div className="flex items-start justify-between mb-2">
204
+ <span className="text-xs opacity-75">
205
+ {message.timestamp.toLocaleTimeString()}
206
+ </span>
207
+ {message.type === 'assistant' && (
208
+ <div className="flex items-center space-x-reverse space-x-2">
209
+ {message.confidence && (
210
+ <span className="text-xs opacity-75">
211
+ {Math.round(message.confidence * 100)}%
212
+ </span>
213
+ )}
214
+ <button
215
+ onClick={() => handleCopyMessage(message.content)}
216
+ className="opacity-50 hover:opacity-100 transition-opacity"
217
+ >
218
+ <FaCopy className="w-3 h-3" />
219
+ </button>
220
+ <button
221
+ onClick={() => handleRegenerateResponse(message.id)}
222
+ className="opacity-50 hover:opacity-100 transition-opacity"
223
+ >
224
+ <FaRedo className="w-3 h-3" />
225
+ </button>
226
+ </div>
227
+ )}
228
+ </div>
229
+
230
+ <div className="prose prose-sm max-w-none prose-invert">
231
+ <ReactMarkdown
232
+ components={{
233
+ code({ node, inline, className, children, ...props }) {
234
+ const match = /language-(\w+)/.exec(className || '')
235
+ return !inline && match ? (
236
+ <SyntaxHighlighter
237
+ style={vscDarkPlus}
238
+ language={match[1]}
239
+ PreTag="div"
240
+ className="rounded-lg"
241
+ {...props}
242
+ >
243
+ {String(children).replace(/\n$/, '')}
244
+ </SyntaxHighlighter>
245
+ ) : (
246
+ <code className={className} {...props}>
247
+ {children}
248
+ </code>
249
+ )
250
+ }
251
+
252
+ >
253
+ {message.content}
254
+ </ReactMarkdown>
255
+ </div>
256
+
257
+ {message.sources && message.sources.length > 0 && (
258
+ <div className="mt-4 pt-4 border-t border-gray-600">
259
+ <p className="text-xs font-medium mb-2 opacity-75">
260
+ {language === 'fa' ? 'منابع:' : 'Sources:'}
261
+ </p>
262
+ <div className="space-y-1">
263
+ {message.sources.map((source, index) => (
264
+ <a
265
+ key={index}
266
+ href={source.url}