iisadia commited on
Commit
e547834
·
verified ·
1 Parent(s): 2036e83

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +500 -0
app.py ADDED
@@ -0,0 +1,500 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import streamlit as st
2
+ import time
3
+ import requests
4
+ from streamlit.components.v1 import html
5
+ import os
6
+ from dotenv import load_dotenv
7
+
8
+ # Import transformers and cache the help agent for performance
9
+ @st.cache_resource
10
+ def get_help_agent():
11
+ from transformers import pipeline
12
+ # Using BlenderBot 400M Distill as the public conversational model (used elsewhere)
13
+ return pipeline("conversational", model="facebook/blenderbot-400M-distill")
14
+
15
+ # Enhanced Custom CSS with modern design
16
+ def inject_custom_css():
17
+ st.markdown("""
18
+ <style>
19
+ @import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap');
20
+ @import url('https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css');
21
+
22
+ * {
23
+ font-family: 'Inter', sans-serif;
24
+ }
25
+
26
+ body {
27
+ background: linear-gradient(135deg, #f8f9fa 0%, #e9ecef 100%);
28
+ }
29
+
30
+ .title {
31
+ font-size: 2.8rem !important;
32
+ font-weight: 800 !important;
33
+ background: linear-gradient(45deg, #6C63FF, #3B82F6);
34
+ -webkit-background-clip: text;
35
+ -webkit-text-fill-color: transparent;
36
+ text-align: center;
37
+ margin: 1rem 0;
38
+ letter-spacing: -1px;
39
+ }
40
+
41
+ .subtitle {
42
+ font-size: 1.1rem !important;
43
+ text-align: center;
44
+ color: #64748B !important;
45
+ margin-bottom: 2.5rem;
46
+ animation: fadeInSlide 1s ease;
47
+ }
48
+
49
+ .question-box {
50
+ background: white;
51
+ border-radius: 20px;
52
+ padding: 2rem;
53
+ margin: 1.5rem 0;
54
+ box-shadow: 0 10px 25px rgba(0,0,0,0.08);
55
+ border: 1px solid #e2e8f0;
56
+ position: relative;
57
+ transition: transform 0.2s ease;
58
+ color: black;
59
+ }
60
+
61
+ .question-box:hover {
62
+ transform: translateY(-3px);
63
+ }
64
+
65
+ .question-box::before {
66
+ content: "🕹️";
67
+ position: absolute;
68
+ left: -15px;
69
+ top: -15px;
70
+ background: white;
71
+ border-radius: 50%;
72
+ padding: 8px;
73
+ box-shadow: 0 4px 6px rgba(0,0,0,0.1);
74
+ font-size: 1.2rem;
75
+ }
76
+
77
+ .input-box {
78
+ background: white;
79
+ border-radius: 12px;
80
+ padding: 1.5rem;
81
+ margin: 1rem 0;
82
+ box-shadow: 0 4px 6px rgba(0,0,0,0.05);
83
+ }
84
+
85
+ .stTextInput input {
86
+ border: 2px solid #e2e8f0 !important;
87
+ border-radius: 10px !important;
88
+ padding: 12px 16px !important;
89
+ transition: all 0.3s ease !important;
90
+ }
91
+
92
+ .stTextInput input:focus {
93
+ border-color: #6C63FF !important;
94
+ box-shadow: 0 0 0 3px rgba(108, 99, 255, 0.2) !important;
95
+ }
96
+
97
+ button {
98
+ background: linear-gradient(45deg, #6C63FF, #3B82F6) !important;
99
+ color: white !important;
100
+ border: none !important;
101
+ border-radius: 10px !important;
102
+ padding: 12px 24px !important;
103
+ font-weight: 600 !important;
104
+ transition: all 0.3s ease !important;
105
+ }
106
+
107
+ button:hover {
108
+ transform: translateY(-2px);
109
+ box-shadow: 0 5px 15px rgba(108, 99, 255, 0.3) !important;
110
+ }
111
+
112
+ .final-reveal {
113
+ animation: fadeInUp 1s ease;
114
+ font-size: 2.8rem;
115
+ background: linear-gradient(45deg, #6C63FF, #3B82F6);
116
+ -webkit-background-clip: text;
117
+ -webkit-text-fill-color: transparent;
118
+ text-align: center;
119
+ margin: 2rem 0;
120
+ font-weight: 800;
121
+ }
122
+
123
+ .help-chat {
124
+ background: rgba(255,255,255,0.9);
125
+ backdrop-filter: blur(10px);
126
+ border-radius: 15px;
127
+ padding: 1rem;
128
+ margin: 1rem 0;
129
+ box-shadow: 0 8px 30px rgba(0,0,0,0.12);
130
+ }
131
+
132
+ @keyframes fadeInSlide {
133
+ 0% { opacity: 0; transform: translateY(20px); }
134
+ 100% { opacity: 1; transform: translateY(0); }
135
+ }
136
+
137
+ @keyframes fadeInUp {
138
+ 0% { opacity: 0; transform: translateY(30px); }
139
+ 100% { opacity: 1; transform: translateY(0); }
140
+ }
141
+
142
+ .progress-bar {
143
+ height: 6px;
144
+ background: #e2e8f0;
145
+ border-radius: 3px;
146
+ margin: 1.5rem 0;
147
+ overflow: hidden;
148
+ }
149
+
150
+ .progress-fill {
151
+ height: 100%;
152
+ background: linear-gradient(90deg, #6C63FF, #3B82F6);
153
+ transition: width 0.5s ease;
154
+ }
155
+
156
+ .question-count {
157
+ color: #6C63FF;
158
+ font-weight: 600;
159
+ font-size: 0.9rem;
160
+ margin-bottom: 0.5rem;
161
+ }
162
+ </style>
163
+ """, unsafe_allow_html=True)
164
+
165
+ # Confetti animation (enhanced)
166
+ def show_confetti():
167
+ html("""
168
+ <canvas id="confetti-canvas" class="confetti"></canvas>
169
+ <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/confetti.browser.min.js"></script>
170
+ <script>
171
+ const count = 200;
172
+ const defaults = {
173
+ origin: { y: 0.7 },
174
+ zIndex: 1050
175
+ };
176
+
177
+ function fire(particleRatio, opts) {
178
+ confetti(Object.assign({}, defaults, opts, {
179
+ particleCount: Math.floor(count * particleRatio)
180
+ }));
181
+ }
182
+
183
+ fire(0.25, { spread: 26, startVelocity: 55 });
184
+ fire(0.2, { spread: 60 });
185
+ fire(0.35, { spread: 100, decay: 0.91, scalar: 0.8 });
186
+ fire(0.1, { spread: 120, startVelocity: 25, decay: 0.92, scalar: 1.2 });
187
+ fire(0.1, { spread: 120, startVelocity: 45 });
188
+ </script>
189
+ """)
190
+
191
+ # Enhanced AI question generation for guessing game using Llama model
192
+ def ask_llama(conversation_history, category, is_final_guess=False):
193
+ api_url = "https://api.groq.com/openai/v1/chat/completions"
194
+ headers = {
195
+ "Authorization": "Bearer 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",
196
+ "Content-Type": "application/json"
197
+ }
198
+
199
+ system_prompt = f"""You're playing 20 questions to guess a {category}. Follow these rules:
200
+ 1. Ask strategic, non-repeating yes/no questions that narrow down possibilities
201
+ 2. Consider all previous answers carefully before asking next question
202
+ 3. If you're very confident (80%+ sure), respond with "Final Guess: [your guess]"
203
+ 4. For places: ask about continent, climate, famous landmarks, country, city or population
204
+ 5. For people: ask about fictional or real, profession, gender, alive/dead, nationality, or fame
205
+ 6. For objects: ask about size, color, usage, material, or where it's found
206
+ 7. Never repeat questions and always make progress toward guessing"""
207
+
208
+ if is_final_guess:
209
+ prompt = f"""Based on these answers about a {category}, provide ONLY your final guess with no extra text:
210
+ {conversation_history}"""
211
+ else:
212
+ prompt = "Ask your next strategic yes/no question that will best narrow down the possibilities."
213
+
214
+ messages = [
215
+ {"role": "system", "content": system_prompt},
216
+ *conversation_history,
217
+ {"role": "user", "content": prompt}
218
+ ]
219
+
220
+ data = {
221
+ "model": "llama-3.3-70b-versatile",
222
+ "messages": messages,
223
+ "temperature": 0.7 if is_final_guess else 0.8,
224
+ "max_tokens": 100
225
+ }
226
+
227
+ try:
228
+ response = requests.post(api_url, headers=headers, json=data)
229
+ response.raise_for_status()
230
+ return response.json()["choices"][0]["message"]["content"]
231
+ except Exception as e:
232
+ st.error(f"Error calling Llama API: {str(e)}")
233
+ return "Could not generate question"
234
+
235
+ # New function for the help AI assistant using the Hugging Face InferenceClient
236
+ MISTRAL_API_KEY = "wm5eLl09b9I9cOxR3E9n5rrRr1CRQQjn"
237
+ def ask_help_agent(query):
238
+ try:
239
+ # Prepare Mistral API request
240
+ url = "https://api.mistral.ai/v1/chat/completions"
241
+ headers = {
242
+ "Authorization": f"Bearer {MISTRAL_API_KEY}",
243
+ "Content-Type": "application/json"
244
+ }
245
+
246
+ system_message = "You are a friendly Chatbot."
247
+
248
+ # Build message history
249
+ messages = [{"role": "system", "content": system_message}]
250
+ if "help_conversation" in st.session_state:
251
+ for msg in st.session_state.help_conversation:
252
+ if msg.get("query"):
253
+ messages.append({"role": "user", "content": msg["query"]})
254
+ if msg.get("response"):
255
+ messages.append({"role": "assistant", "content": msg["response"]})
256
+
257
+ # Add current user query
258
+ messages.append({"role": "user", "content": query})
259
+
260
+ # API payload
261
+ payload = {
262
+ "model": "mistral-tiny",
263
+ "messages": messages,
264
+ "temperature": 0.7,
265
+ "top_p": 0.95
266
+ }
267
+
268
+ # Send POST request
269
+ response = requests.post(url, headers=headers, json=payload)
270
+
271
+ if response.status_code == 200:
272
+ result = response.json()
273
+ return result["choices"][0]["message"]["content"]
274
+ else:
275
+ return f"API Error {response.status_code}: {response.text}"
276
+
277
+ except Exception as e:
278
+ return f"Error in help agent: {str(e)}"
279
+
280
+
281
+ # Main game logic with enhanced UI
282
+ def main():
283
+ inject_custom_css()
284
+
285
+ st.markdown('<div class="title">KASOTI</div>', unsafe_allow_html=True)
286
+ st.markdown('<div class="subtitle">AI-Powered Guessing Game Challenge</div>', unsafe_allow_html=True)
287
+
288
+ if 'game_state' not in st.session_state:
289
+ st.session_state.game_state = "start"
290
+ st.session_state.questions = []
291
+ st.session_state.current_q = 0
292
+ st.session_state.answers = []
293
+ st.session_state.conversation_history = []
294
+ st.session_state.category = None
295
+ st.session_state.final_guess = None
296
+ st.session_state.help_conversation = [] # separate history for help agent
297
+
298
+ # Start screen with enhanced layout
299
+ if st.session_state.game_state == "start":
300
+ with st.container():
301
+ st.markdown("""
302
+ <div class="question-box">
303
+ <h3 style="color: #6C63FF; margin-bottom: 1.5rem;">🎮 Welcome to KASOTI</h3>
304
+ <p style="line-height: 1.6; color: #64748B;">
305
+ Think of something and I'll try to guess it in 20 questions or less!<br>
306
+ Choose from these categories:
307
+ </p>
308
+ <div style="display: grid; gap: 1rem; margin: 2rem 0;">
309
+ <div style="padding: 1.5rem; background: #f8f9fa; border-radius: 12px;">
310
+ <h4 style="margin: 0; color: #6C63FF;">🧑 Person</h4>
311
+ <p style="margin: 0.5rem 0 0; color: #64748B;">Celebrity, fictional character, historical figure</p>
312
+ </div>
313
+ <div style="padding: 1.5rem; background: #f8f9fa; border-radius: 12px;">
314
+ <h4 style="margin: 0; color: #6C63FF;">🌍 Place</h4>
315
+ <p style="margin: 0.5rem 0 0; color: #64748B;">City, country, landmark, geographical location</p>
316
+ </div>
317
+ <div style="padding: 1.5rem; background: #f8f9fa; border-radius: 12px;">
318
+ <h4 style="margin: 0; color: #6C63FF;">🎯 Object</h4>
319
+ <p style="margin: 0.5rem 0 0; color: #64748B;">Everyday item, tool, vehicle, or concept</p>
320
+ </div>
321
+ </div>
322
+ </div>
323
+ """, unsafe_allow_html=True)
324
+
325
+ with st.form("start_form"):
326
+ category_input = st.text_input("Enter category (person/place/object):").strip().lower()
327
+ if st.form_submit_button("Start Game"):
328
+ if not category_input:
329
+ st.error("Please enter a category!")
330
+ elif category_input not in ["person", "place", "object"]:
331
+ st.error("Please enter either 'person', 'place', or 'object'!")
332
+ else:
333
+ st.session_state.category = category_input
334
+ first_question = ask_llama([
335
+ {"role": "user", "content": "Ask your first strategic yes/no question."}
336
+ ], category_input)
337
+ st.session_state.questions = [first_question]
338
+ st.session_state.conversation_history = [
339
+ {"role": "assistant", "content": first_question}
340
+ ]
341
+ st.session_state.game_state = "gameplay"
342
+ st.experimental_rerun()
343
+
344
+ # Gameplay screen with progress bar
345
+ elif st.session_state.game_state == "gameplay":
346
+ with st.container():
347
+ # Add progress bar
348
+ progress = (st.session_state.current_q + 1) / 20
349
+ st.markdown(f"""
350
+ <div class="question-count">QUESTION {st.session_state.current_q + 1} OF 20</div>
351
+ <div class="progress-bar">
352
+ <div class="progress-fill" style="width: {progress * 100}%"></div>
353
+ </div>
354
+ """, unsafe_allow_html=True)
355
+
356
+ current_question = st.session_state.questions[st.session_state.current_q]
357
+
358
+ # Enhanced question box
359
+ st.markdown(f'''
360
+ <div class="question-box">
361
+ <div style="display: flex; align-items: center; gap: 1rem; margin-bottom: 1.5rem;">
362
+ <div style="background: #6C63FF; width: 40px; height: 40px; border-radius: 50%;
363
+ display: flex; align-items: center; justify-content: center; color: white;">
364
+ <i class="fas fa-robot"></i>
365
+ </div>
366
+ <h3 style="margin: 0; color: #1E293B;">AI Question</h3>
367
+ </div>
368
+ <p style="font-size: 1.1rem; line-height: 1.6; color: #1E293B;">{current_question}</p>
369
+ </div>
370
+ ''', unsafe_allow_html=True)
371
+
372
+ # Check if AI made a guess
373
+ if "Final Guess:" in current_question:
374
+ st.session_state.final_guess = current_question.split("Final Guess:")[1].strip()
375
+ st.session_state.game_state = "confirm_guess"
376
+ st.experimental_rerun()
377
+
378
+ with st.form("answer_form"):
379
+ answer_input = st.text_input("Your answer (yes/no/both):",
380
+ key=f"answer_{st.session_state.current_q}").strip().lower()
381
+ if st.form_submit_button("Submit"):
382
+ if answer_input not in ["yes", "no", "both"]:
383
+ st.error("Please answer with 'yes', 'no', or 'both'!")
384
+ else:
385
+ st.session_state.answers.append(answer_input)
386
+ st.session_state.conversation_history.append(
387
+ {"role": "user", "content": answer_input}
388
+ )
389
+
390
+ # Generate next response
391
+ next_response = ask_llama(
392
+ st.session_state.conversation_history,
393
+ st.session_state.category
394
+ )
395
+
396
+ # Check if AI made a guess
397
+ if "Final Guess:" in next_response:
398
+ st.session_state.final_guess = next_response.split("Final Guess:")[1].strip()
399
+ st.session_state.game_state = "confirm_guess"
400
+ else:
401
+ st.session_state.questions.append(next_response)
402
+ st.session_state.conversation_history.append(
403
+ {"role": "assistant", "content": next_response}
404
+ )
405
+ st.session_state.current_q += 1
406
+
407
+ # Stop after 20 questions max
408
+ if st.session_state.current_q >= 20:
409
+ st.session_state.game_state = "result"
410
+
411
+ st.experimental_rerun()
412
+
413
+ # Side Help Option: independent chat with an AI help assistant using Hugging Face model
414
+ with st.expander("Need Help? Chat with AI Assistant"):
415
+ help_query = st.text_input("Enter your help query:", key="help_query")
416
+ if st.button("Send", key="send_help"):
417
+ if help_query:
418
+ help_response = ask_help_agent(help_query)
419
+ st.session_state.help_conversation.append({"query": help_query, "response": help_response})
420
+ else:
421
+ st.error("Please enter a query!")
422
+ if st.session_state.help_conversation:
423
+ for msg in st.session_state.help_conversation:
424
+ st.markdown(f"**You:** {msg['query']}")
425
+ st.markdown(f"**Help Assistant:** {msg['response']}")
426
+
427
+ # Guess confirmation screen using text input response
428
+ elif st.session_state.game_state == "confirm_guess":
429
+ st.markdown(f'''
430
+ <div class="question-box">
431
+ <div style="display: flex; align-items: center; gap: 1rem; margin-bottom: 1.5rem;">
432
+ <div style="background: #6C63FF; width: 40px; height: 40px; border-radius: 50%;
433
+ display: flex; align-items: center; justify-content: center; color: white;">
434
+ <i class="fas fa-lightbulb"></i>
435
+ </div>
436
+ <h3 style="margin: 0; color: #1E293B;">AI's Final Guess</h3>
437
+ </div>
438
+ <p style="font-size: 1.2rem; line-height: 1.6; color: #1E293B;">
439
+ Is it <strong style="color: #6C63FF;">{st.session_state.final_guess}</strong>?
440
+ </p>
441
+ </div>
442
+ ''', unsafe_allow_html=True)
443
+
444
+ with st.form("confirm_form"):
445
+ confirm_input = st.text_input("Type your answer (yes/no/both):", key="confirm_input").strip().lower()
446
+ if st.form_submit_button("Submit"):
447
+ if confirm_input not in ["yes", "no", "both"]:
448
+ st.error("Please answer with 'yes', 'no', or 'both'!")
449
+ else:
450
+ if confirm_input == "yes":
451
+ st.session_state.game_state = "result"
452
+ st.experimental_rerun()
453
+ st.stop() # Immediately halt further execution
454
+ else:
455
+ # Add negative response to history and continue gameplay
456
+ st.session_state.conversation_history.append(
457
+ {"role": "user", "content": "no"}
458
+ )
459
+ st.session_state.game_state = "gameplay"
460
+ next_response = ask_llama(
461
+ st.session_state.conversation_history,
462
+ st.session_state.category
463
+ )
464
+ st.session_state.questions.append(next_response)
465
+ st.session_state.conversation_history.append(
466
+ {"role": "assistant", "content": next_response}
467
+ )
468
+ st.session_state.current_q += 1
469
+ st.experimental_rerun()
470
+
471
+ # Result screen with enhanced celebration
472
+ elif st.session_state.game_state == "result":
473
+ if not st.session_state.final_guess:
474
+ # Generate final guess if not already made
475
+ qa_history = "\n".join(
476
+ [f"Q{i+1}: {q}\nA: {a}"
477
+ for i, (q, a) in enumerate(zip(st.session_state.questions, st.session_state.answers))]
478
+ )
479
+
480
+ final_guess = ask_llama(
481
+ [{"role": "user", "content": qa_history}],
482
+ st.session_state.category,
483
+ is_final_guess=True
484
+ )
485
+ st.session_state.final_guess = final_guess.split("Final Guess:")[-1].strip()
486
+
487
+ show_confetti()
488
+ st.markdown(f'<div class="final-reveal">🎉 It\'s...</div>', unsafe_allow_html=True)
489
+ time.sleep(1)
490
+ st.markdown(f'<div class="final-reveal" style="font-size:3.5rem;color:#6C63FF;">{st.session_state.final_guess}</div>',
491
+ unsafe_allow_html=True)
492
+ st.markdown(f"<p style='text-align:center; color:#64748B;'>Guessed in {len(st.session_state.questions)} questions</p>",
493
+ unsafe_allow_html=True)
494
+
495
+ if st.button("Play Again", key="play_again"):
496
+ st.session_state.clear()
497
+ st.experimental_rerun()
498
+
499
+ if __name__ == "__main__":
500
+ main()