Skip to content

Commit f43b39f

Browse files
committed
chat bot changes
1 parent 6c73f5d commit f43b39f

3 files changed

Lines changed: 186 additions & 10 deletions

File tree

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,3 +22,6 @@ dist-ssr
2222
*.njsproj
2323
*.sln
2424
*.sw?
25+
.env
26+
.env.local
27+
.env.*.local

src/index.css

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,3 +155,8 @@ select option {
155155
display: flex;
156156
flex-direction: column;
157157
}
158+
159+
@keyframes spin {
160+
0% { transform: rotate(0deg); }
161+
100% { transform: rotate(360deg); }
162+
}

src/pages/Chat.tsx

Lines changed: 178 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,131 @@
1+
import { useState, useRef, useEffect } from 'react';
12
import { useParams, Link } from 'react-router';
23
import { useAppContext } from '../context/AppContext';
34

5+
// Mock AI responses as fallback
6+
const ALIEN_RESPONSES = [
7+
"My optic sensors appreciate your visual symmetry. Shall we exchange genetic material samples?",
8+
"Your carbon-based form is adequate. How many standard galactic rotations have you survived?",
9+
"I observe you only have two manipulating appendages. How do you efficiently consume nutrient paste?",
10+
"Your transmission implies affectionate intent. My emotion-processing subroutines are currently downloading an update.",
11+
"Interesting. Most species on my planet communicate via scent-gland excretion. Your vocal vibrations are... quaint.",
12+
"Warning: Your bio-signature is dangerously attractive. Please lower your gravitational pull.",
13+
"Are you emitting pheromones or is my atmospheric analyzer malfunctioning?",
14+
];
15+
16+
type Message = {
17+
id: string;
18+
sender: 'user' | 'alien';
19+
text: string;
20+
};
21+
422
export default function Chat() {
523
const { id } = useParams();
624
const { matches } = useAppContext();
725

26+
const [messages, setMessages] = useState<Message[]>([]);
27+
const [inputValue, setInputValue] = useState('');
28+
const [isTranslating, setIsTranslating] = useState(false);
29+
const messagesEndRef = useRef<HTMLDivElement>(null);
30+
831
const alien = matches.find(m => m.id === id);
932

33+
const scrollToBottom = () => {
34+
messagesEndRef.current?.scrollIntoView({ behavior: "smooth" });
35+
};
36+
37+
useEffect(() => {
38+
scrollToBottom();
39+
}, [messages, isTranslating]);
40+
41+
// Simulate an AI or API call to get the alien's response
42+
const generateAlienResponse = async (userText: string, currentMessages: Message[]) => {
43+
// Check if the user has provided a Gemini API Key in their environment variables (optional AI integration)
44+
const geminiApiKey = import.meta.env.VITE_GEMINI_API_KEY;
45+
46+
if (geminiApiKey && geminiApiKey !== 'YOUR_GEMINI_API_KEY_HERE') {
47+
// Format the last few messages for conversational context
48+
const chatHistory = currentMessages.slice(-4).map(m =>
49+
`${m.sender === 'user' ? 'Human' : alien?.name}: ${m.text}`
50+
).join('\n');
51+
52+
const promptText = `You are a user named ${alien?.name} on the dating app "ALIGNED".
53+
${chatHistory ? `Here is the recent chat history:\n${chatHistory}\n` : ''}
54+
Human: "${userText}"
55+
56+
Reply directly to the Human's latest message as ${alien?.name}.
57+
The twist: Act like your response went through a VERY CHEAP intergalactic translation software.
58+
You must use VERY SIMPLE, basic English. However, insert exactly 1 or 2 awkwardly literal or slightly confusing words that sound like a funny misunderstanding of human culture. DO NOT be creepy, gross, or overly biological. Keep it harmless and charmingly awkward.
59+
60+
For example:
61+
- Instead of "You have beautiful eyes", say: "Your visual orbs are very shiny... good looking."
62+
- Instead of "I am doing well", say: "I am having an excellent rotation today."
63+
- Instead of "What are you doing?", say: "What hobbies are your human hands performing?"
64+
65+
Keep it friendly, slightly flirtatious, and warmly confusing. Keep the grammar simple like a bad tourist translator, but drop in that one hilariously literal phrase. Maximum 2 sentences. Do not prefix the text with your name.`;
66+
67+
try {
68+
const response = await fetch(`https://generativelanguage.googleapis.com/v1beta/models/gemini-flash-latest:generateContent?key=${geminiApiKey}`, {
69+
method: 'POST',
70+
headers: {
71+
'Content-Type': 'application/json'
72+
},
73+
body: JSON.stringify({
74+
contents: [{
75+
parts: [{ text: promptText }]
76+
}]
77+
})
78+
});
79+
80+
const data = await response.json();
81+
if (data.error) {
82+
console.error("Gemini API Error:", data.error);
83+
return `[TRANSLATOR ERROR: ${data.error.message || "Invalid API parameters"}]`;
84+
}
85+
86+
if (data && data.candidates && data.candidates.length > 0) {
87+
return data.candidates[0].content.parts[0].text;
88+
}
89+
} catch (e) {
90+
console.error("AI translation failed:", e);
91+
return "[TRANSLATOR COMMUNICATION FAILURE: Unable to reach Gemini backend. Did you restart the server?]";
92+
}
93+
}
94+
95+
// Fallback ONLY if there is no API key configured at all
96+
return ALIEN_RESPONSES[Math.floor(Math.random() * ALIEN_RESPONSES.length)];
97+
};
98+
99+
const handleSendMessage = async () => {
100+
if (!inputValue.trim() || isTranslating) return;
101+
102+
const userMessage: Message = {
103+
id: Date.now().toString(),
104+
sender: 'user',
105+
text: inputValue.trim()
106+
};
107+
108+
setMessages(prev => [...prev, userMessage]);
109+
setInputValue('');
110+
setIsTranslating(true);
111+
112+
// Simulate "Processing Translation..." delay
113+
const delay = Math.floor(Math.random() * 1500) + 1500; // 1.5s - 3.0s delay
114+
115+
setTimeout(async () => {
116+
// Pass the previous messages list array AND the new user message
117+
const responseText = await generateAlienResponse(userMessage.text, [...messages, userMessage]);
118+
const alienMessage: Message = {
119+
id: (Date.now() + 1).toString(),
120+
sender: 'alien',
121+
text: responseText
122+
};
123+
124+
setMessages(prev => [...prev, alienMessage]);
125+
setIsTranslating(false);
126+
}, delay);
127+
};
128+
10129
if (!alien) {
11130
return (
12131
<div style={{ padding: '40px', textAlign: 'center' }}>
@@ -18,11 +137,12 @@ export default function Chat() {
18137
}
19138

20139
return (
21-
<div style={{ maxWidth: '800px', margin: '20px auto', padding: '0 20px', flex: 1, display: 'flex', flexDirection: 'column' }}>
22-
<div className="glass-panel" style={{ display: 'flex', flexDirection: 'column', height: 'calc(100vh - 120px)' }}>
140+
<div style={{ width: '100%', maxWidth: '800px', margin: '20px auto', padding: '0 20px', flex: 1, display: 'flex', flexDirection: 'column' }}>
141+
<div className="glass-panel" style={{ backgroundColor: '#1a1829', border: 'none', display: 'flex', flexDirection: 'column', height: 'calc(100vh - 120px)' }}>
23142

24143
{/* Chat Header */}
25-
<div style={{ padding: '20px', borderBottom: '1px solid var(--glass-border)', display: 'flex', alignItems: 'center', gap: '16px' }}>
144+
<div style={{ padding: '20px', position: 'relative', display: 'flex', alignItems: 'center', gap: '16px' }}>
145+
<div style={{ position: 'absolute', bottom: 0, left: '5%', right: '5%', height: '1px', background: 'linear-gradient(90deg, transparent, var(--color-secondary), transparent)', opacity: 0.5 }}></div>
26146
<img src={alien.profilePic} alt={alien.name} style={{ width: '50px', height: '50px', borderRadius: '50%', objectFit: 'cover' }} />
27147
<div>
28148
<h3 style={{ margin: 0, color: 'var(--color-primary)' }}>{alien.name}</h3>
@@ -31,16 +151,64 @@ export default function Chat() {
31151
</div>
32152

33153
{/* Chat Messages */}
34-
<div style={{ flex: 1, padding: '20px', overflowY: 'auto' }}>
35-
<div style={{ textAlign: 'center', margin: '20px 0', color: 'rgba(234, 222, 218, 0.4)', fontSize: '0.9rem' }}>
36-
Connection established across {alien.distanceAU} AU. Say hello!
37-
</div>
154+
<div style={{ flex: 1, padding: '20px', overflowY: 'auto', display: 'flex', flexDirection: 'column', gap: '16px' }}>
155+
{messages.length === 0 && (
156+
<div style={{ textAlign: 'center', margin: '20px 0', color: 'rgba(234, 222, 218, 0.4)', fontSize: '0.9rem' }}>
157+
Connection established across {alien.distanceAU} AU. Say hello!
158+
</div>
159+
)}
160+
161+
{messages.map((msg) => (
162+
<div
163+
key={msg.id}
164+
style={{
165+
alignSelf: msg.sender === 'user' ? 'flex-end' : 'flex-start',
166+
maxWidth: '80%',
167+
backgroundColor: msg.sender === 'user' ? 'var(--color-secondary)' : '#2A263A',
168+
border: `1px solid ${msg.sender === 'user' ? 'var(--color-secondary)' : '#3F3956'}`,
169+
padding: '12px 16px',
170+
borderRadius: msg.sender === 'user' ? '16px 16px 0 16px' : '16px 16px 16px 0',
171+
color: 'white',
172+
boxShadow: msg.sender === 'user' ? '0 4px 12px rgba(217, 3, 104, 0.3)' : '0 4px 12px rgba(0, 0, 0, 0.2)',
173+
lineHeight: 1.5,
174+
fontWeight: 500
175+
}}
176+
>
177+
{msg.text}
178+
</div>
179+
))}
180+
181+
{isTranslating && (
182+
<div style={{ alignSelf: 'flex-start', color: 'var(--color-secondary)', fontSize: '0.9rem', fontStyle: 'italic', display: 'flex', alignItems: 'center', gap: '8px' }}>
183+
<span style={{ display: 'inline-block', width: '12px', height: '12px', border: '2px solid var(--color-secondary)', borderTopColor: 'transparent', borderRadius: '50%', animation: 'spin 1s linear infinite' }}></span>
184+
Processing Translation...
185+
</div>
186+
)}
187+
188+
<div ref={messagesEndRef} />
38189
</div>
39190

40191
{/* Chat Input */}
41-
<div style={{ padding: '20px', borderTop: '1px solid var(--glass-border)', display: 'flex', gap: '12px' }}>
42-
<input type="text" placeholder="Send a transmission..." style={{ flex: 1 }} />
43-
<button className="btn-primary">Send</button>
192+
<div style={{ padding: '20px', position: 'relative', display: 'flex', gap: '12px' }}>
193+
<div style={{ position: 'absolute', top: 0, left: '5%', right: '5%', height: '1px', background: 'linear-gradient(90deg, transparent, var(--color-secondary), transparent)', opacity: 0.5 }}></div>
194+
<input
195+
type="text"
196+
placeholder="Send a transmission..."
197+
style={{ flex: 1, backgroundColor: 'rgba(255, 255, 255, 0.05)', border: '1px solid var(--glass-border)', borderRadius: '8px', padding: '10px 16px', color: 'white' }}
198+
value={inputValue}
199+
onChange={(e) => setInputValue(e.target.value)}
200+
onKeyDown={(e) => {
201+
if (e.key === 'Enter') handleSendMessage();
202+
}}
203+
disabled={isTranslating}
204+
/>
205+
<button
206+
className="btn-primary"
207+
onClick={handleSendMessage}
208+
disabled={!inputValue.trim() || isTranslating}
209+
>
210+
Send
211+
</button>
44212
</div>
45213

46214
</div>

0 commit comments

Comments
 (0)