Ram2005 commited on
Commit
2a548b8
·
verified ·
1 Parent(s): 8dff38c

Upload frontend/src/components/ChatWidget.jsx

Browse files
frontend/src/components/ChatWidget.jsx ADDED
@@ -0,0 +1,114 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import React, { useState, useRef, useEffect } from 'react'
2
+
3
+ const SUGGESTIONS = [
4
+ "What are the top fintech unicorns?",
5
+ "Tell me about SaaS startups in Bangalore",
6
+ "What is DPIIT recognition?",
7
+ "Which sectors are growing fastest?",
8
+ "Compare edtech vs healthtech",
9
+ ]
10
+
11
+ export default function ChatWidget({ onClose }) {
12
+ const [messages, setMessages] = useState([
13
+ { role: 'assistant', content: '👋 Hi! I\'m Bharat Tech Atlas AI. Ask me about Indian startups, sectors, funding trends, or any company!' }
14
+ ])
15
+ const [input, setInput] = useState('')
16
+ const [loading, setLoading] = useState(false)
17
+ const scrollRef = useRef(null)
18
+
19
+ useEffect(() => {
20
+ scrollRef.current?.scrollIntoView({ behavior: 'smooth' })
21
+ }, [messages])
22
+
23
+ const sendMessage = async (text) => {
24
+ if (!text.trim() || loading) return
25
+ const userMsg = { role: 'user', content: text }
26
+ setMessages(prev => [...prev, userMsg])
27
+ setInput('')
28
+ setLoading(true)
29
+
30
+ try {
31
+ const resp = await fetch('/api/chat/completions', {
32
+ method: 'POST',
33
+ headers: { 'Content-Type': 'application/json' },
34
+ body: JSON.stringify({ messages: [...messages, userMsg].map(m => ({ role: m.role, content: m.content })) }),
35
+ })
36
+ const data = await resp.json()
37
+ setMessages(prev => [...prev, { role: 'assistant', content: data.content || 'Sorry, I had trouble responding.' }])
38
+ } catch (err) {
39
+ setMessages(prev => [...prev, { role: 'assistant', content: '⚠️ Network error. Please try again.' }])
40
+ } finally {
41
+ setLoading(false)
42
+ }
43
+ }
44
+
45
+ return (
46
+ <div className="fixed bottom-4 right-4 z-50 w-[380px] max-w-[calc(100vw-2rem)] h-[520px] max-h-[calc(100vh-2rem)] bg-atlas-bg border border-atlas-border rounded-2xl shadow-2xl flex flex-col overflow-hidden">
47
+ {/* Header */}
48
+ <div className="flex items-center justify-between px-4 py-3 border-b border-atlas-border bg-atlas-surface">
49
+ <div className="flex items-center gap-2">
50
+ <span className="text-lg">🤖</span>
51
+ <div>
52
+ <h3 className="text-sm font-semibold text-atlas-text">Bharat Tech Atlas AI</h3>
53
+ <p className="text-[10px] text-atlas-muted">Powered by Qwen2.5-0.5B</p>
54
+ </div>
55
+ </div>
56
+ <button onClick={onClose} className="text-atlas-muted hover:text-atlas-text text-lg">✕</button>
57
+ </div>
58
+
59
+ {/* Messages */}
60
+ <div className="flex-1 overflow-y-auto p-3 space-y-3">
61
+ {messages.map((m, i) => (
62
+ <div key={i} className={`flex ${m.role === 'user' ? 'justify-end' : 'justify-start'}`}>
63
+ <div className={`max-w-[85%] rounded-xl px-3 py-2 text-xs leading-relaxed ${
64
+ m.role === 'user'
65
+ ? 'bg-brand-500/20 text-brand-300 rounded-br-none'
66
+ : 'bg-atlas-surface text-atlas-muted rounded-bl-none'
67
+ }`}>
68
+ {m.content}
69
+ </div>
70
+ </div>
71
+ ))}
72
+ {loading && (
73
+ <div className="flex justify-start">
74
+ <div className="bg-atlas-surface rounded-xl rounded-bl-none px-3 py-2">
75
+ <div className="flex gap-1">
76
+ <span className="w-1.5 h-1.5 bg-atlas-muted rounded-full animate-bounce" style={{ animationDelay: '0ms' }} />
77
+ <span className="w-1.5 h-1.5 bg-atlas-muted rounded-full animate-bounce" style={{ animationDelay: '150ms' }} />
78
+ <span className="w-1.5 h-1.5 bg-atlas-muted rounded-full animate-bounce" style={{ animationDelay: '300ms' }} />
79
+ </div>
80
+ </div>
81
+ </div>
82
+ )}
83
+ <div ref={scrollRef} />
84
+ </div>
85
+
86
+ {/* Suggestions (only show when few messages) */}
87
+ {messages.length < 3 && (
88
+ <div className="px-3 pb-2 flex flex-wrap gap-1.5">
89
+ {SUGGESTIONS.map(s => (
90
+ <button key={s} onClick={() => sendMessage(s)}
91
+ className="text-[10px] px-2 py-1 rounded-full bg-atlas-surface border border-atlas-border text-atlas-muted hover:text-atlas-text hover:border-brand-500/30 transition-colors">
92
+ {s}
93
+ </button>
94
+ ))}
95
+ </div>
96
+ )}
97
+
98
+ {/* Input */}
99
+ <div className="px-3 py-2 border-t border-atlas-border flex gap-2">
100
+ <input
101
+ value={input}
102
+ onChange={e => setInput(e.target.value)}
103
+ onKeyDown={e => e.key === 'Enter' && sendMessage(input)}
104
+ placeholder="Ask about startups, sectors, funding..."
105
+ className="flex-1 bg-atlas-surface border border-atlas-border rounded-lg px-3 py-2 text-xs text-atlas-text placeholder:text-atlas-muted/50 focus:outline-none focus:border-brand-500/50"
106
+ />
107
+ <button onClick={() => sendMessage(input)} disabled={loading || !input.trim()}
108
+ className="px-3 py-2 bg-brand-500/20 text-brand-400 rounded-lg text-xs font-medium hover:bg-brand-500/30 disabled:opacity-30 transition-colors">
109
+ Send
110
+ </button>
111
+ </div>
112
+ </div>
113
+ )
114
+ }