fatmayousuf commited on
Commit
cf3b01d
Β·
verified Β·
1 Parent(s): aca0531

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +132 -214
app.py CHANGED
@@ -12,166 +12,106 @@ print("google-genai version loaded")
12
  # For Hugging Face Spaces, use Secrets
13
  GOOGLE_API_KEY = os.environ.get("GOOGLE_API_KEY", "")
14
 
15
- TITLE = """<h1 align="center" style="
16
- background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
17
- -webkit-background-clip: text;
18
- -webkit-text-fill-color: transparent;
19
- background-clip: text;
20
- font-size: 2.8em;
21
- font-weight: 800;
22
- margin: 20px 0 10px 0;
23
- text-shadow: 2px 2px 4px rgba(0,0,0,0.1);">
24
- πŸ’¬ Gemini AI Chatbot
25
- </h1>"""
26
 
27
- SUBTITLE = """<h3 align="center" style="
28
- color: #5a67d8;
29
- font-size: 1.3em;
30
- margin: 10px 0 5px 0;
31
- font-weight: 600;">
32
- 🎨 Powered by Google Gemini AI
33
- </h3>"""
34
 
35
  DESCRIPTION = """
36
- <p align="center" style="
37
- color: #4a5568;
38
- font-size: 1.05em;
39
- margin: 15px auto;
40
- max-width: 600px;
41
- line-height: 1.6;">
42
- Chat with Google's advanced AI model. Get your free API key from
43
- <a href="https://aistudio.google.com/app/apikey"
44
- target="_blank"
45
- style="color: #667eea; font-weight: 600; text-decoration: none; border-bottom: 2px solid #667eea;">
46
- Google AI Studio
47
- </a>
48
  </p>
49
  """
50
 
51
  IMAGE_WIDTH = 512
52
 
53
- # Improved Custom CSS with better colors and contrast
54
  CUSTOM_CSS = """
55
- /* Main container with soft gradient */
56
  .gradio-container {
57
  max-width: 1400px !important;
58
  margin: auto !important;
59
- background: linear-gradient(to bottom, #f7fafc 0%, #edf2f7 100%) !important;
60
- font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif !important;
 
 
 
61
  }
62
 
63
- /* Better button styling */
64
  button {
65
- background: linear-gradient(135deg, #667eea 0%, #764ba2 100%) !important;
66
  border: none !important;
67
  color: white !important;
68
  font-weight: 600 !important;
69
- border-radius: 10px !important;
70
- padding: 12px 24px !important;
71
  transition: all 0.3s ease !important;
72
- box-shadow: 0 4px 6px rgba(102, 126, 234, 0.2) !important;
73
  }
74
 
75
  button:hover {
76
- background: linear-gradient(135deg, #5a67d8 0%, #6b46a1 100%) !important;
77
- transform: translateY(-2px) !important;
78
- box-shadow: 0 6px 12px rgba(102, 126, 234, 0.3) !important;
79
  }
80
 
81
- button:active {
82
- transform: translateY(0px) !important;
83
- }
84
-
85
- /* Input fields with better visibility */
86
- .input-text, textarea, input[type="text"], input[type="password"] {
87
- border: 2px solid #cbd5e0 !important;
88
  border-radius: 10px !important;
89
- padding: 12px !important;
90
- background: white !important;
91
- color: #2d3748 !important;
92
- font-size: 15px !important;
93
  }
94
 
95
  .input-text:focus, textarea:focus, input:focus {
96
- border-color: #667eea !important;
97
- box-shadow: 0 0 0 3px rgba(102, 126, 234, 0.1) !important;
98
  outline: none !important;
99
- background: #ffffff !important;
100
  }
101
 
102
- /* Labels with better readability */
103
  label {
104
- color: #2d3748 !important;
105
  font-weight: 600 !important;
106
- font-size: 14px !important;
107
  margin-bottom: 8px !important;
108
  }
109
 
110
- /* Chatbot container */
111
- .chatbot {
112
- border: 2px solid #e2e8f0 !important;
113
- border-radius: 15px !important;
114
- background: white !important;
115
- box-shadow: 0 4px 6px rgba(0, 0, 0, 0.05) !important;
116
  }
117
 
118
- /* User messages - vibrant purple */
119
- .message.user, .user {
120
- background: linear-gradient(135deg, #667eea 0%, #764ba2 100%) !important;
121
  color: white !important;
122
- border-radius: 18px 18px 4px 18px !important;
123
  padding: 12px 16px !important;
124
- margin: 8px 0 !important;
125
- box-shadow: 0 2px 4px rgba(102, 126, 234, 0.2) !important;
126
- font-size: 15px !important;
127
- line-height: 1.5 !important;
128
  }
129
 
130
- /* Bot messages - soft blue with better contrast */
131
- .message.bot, .bot {
132
- background: linear-gradient(135deg, #ebf4ff 0%, #e0e7ff 100%) !important;
133
- color: #1a202c !important;
134
- border-radius: 18px 18px 18px 4px !important;
135
  padding: 12px 16px !important;
136
- margin: 8px 0 !important;
137
- border-left: 4px solid #667eea !important;
138
- box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05) !important;
139
- font-size: 15px !important;
140
- line-height: 1.6 !important;
141
  }
142
 
143
  /* Accordion styling */
144
  .accordion {
145
- background: white !important;
146
- border: 2px solid #e2e8f0 !important;
147
- border-radius: 12px !important;
148
- margin: 15px 0 !important;
149
- box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05) !important;
150
  }
151
 
152
- /* Image upload area */
153
  .image-container {
154
- border: 3px dashed #cbd5e0 !important;
155
  border-radius: 15px !important;
156
- padding: 15px !important;
157
  background: white !important;
158
- transition: all 0.3s ease !important;
159
- }
160
-
161
- .image-container:hover {
162
- border-color: #667eea !important;
163
- background: #f7fafc !important;
164
  }
165
 
166
  /* Slider styling */
167
  input[type="range"] {
168
- accent-color: #667eea !important;
169
- }
170
-
171
- /* Info text */
172
- .info {
173
- color: #718096 !important;
174
- font-size: 13px !important;
175
  }
176
 
177
  /* Better spacing */
@@ -180,62 +120,13 @@ input[type="range"] {
180
  }
181
 
182
  .block {
183
- padding: 20px !important;
184
- border-radius: 12px !important;
185
- background: white !important;
186
  }
187
 
188
- /* Remove footer */
189
  footer {
190
  display: none !important;
191
  }
192
-
193
- /* Placeholder text */
194
- ::placeholder {
195
- color: #a0aec0 !important;
196
- opacity: 1 !important;
197
- }
198
-
199
- /* Scrollbar styling */
200
- ::-webkit-scrollbar {
201
- width: 10px;
202
- }
203
-
204
- ::-webkit-scrollbar-track {
205
- background: #f1f1f1;
206
- border-radius: 10px;
207
- }
208
-
209
- ::-webkit-scrollbar-thumb {
210
- background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
211
- border-radius: 10px;
212
- }
213
-
214
- ::-webkit-scrollbar-thumb:hover {
215
- background: linear-gradient(135deg, #5a67d8 0%, #6b46a1 100%);
216
- }
217
-
218
- /* Example prompts styling */
219
- .examples {
220
- background: white !important;
221
- border-radius: 12px !important;
222
- padding: 15px !important;
223
- border: 2px solid #e2e8f0 !important;
224
- }
225
-
226
- /* Better contrast for dark text */
227
- .markdown-text {
228
- color: #2d3748 !important;
229
- }
230
-
231
- /* Success/Error messages */
232
- .success {
233
- color: #38a169 !important;
234
- }
235
-
236
- .error {
237
- color: #e53e3e !important;
238
- }
239
  """
240
 
241
  # ===================== HELPERS =====================
@@ -274,6 +165,7 @@ def user(message: str, history: Optional[List[Dict]]) -> tuple:
274
  if not message or message.strip() == "":
275
  return "", history
276
 
 
277
  history.append({"role": "user", "content": message.strip()})
278
  return "", history
279
  except Exception as e:
@@ -292,36 +184,42 @@ def bot(
292
  ):
293
  """Generate bot response with comprehensive error handling."""
294
  try:
 
295
  if not history or len(history) == 0:
296
  yield history or []
297
  return
298
 
 
299
  api_key = google_key.strip() if google_key else GOOGLE_API_KEY
300
  if not api_key:
301
  history.append({
302
  "role": "assistant",
303
- "content": "πŸ”‘ **API Key Required**\n\nPlease enter your Google API key to start chatting.\n\nGet your free API key from [Google AI Studio](https://aistudio.google.com/app/apikey)"
304
  })
305
  yield history
306
  return
307
 
 
308
  try:
309
  client = genai.Client(api_key=api_key)
310
  except Exception as e:
311
  history.append({
312
  "role": "assistant",
313
- "content": f"❌ **Invalid API Key**\n\n{str(e)}\n\nPlease check your API key and try again."
314
  })
315
  yield history
316
  return
317
 
 
318
  user_message = history[-1]["content"]
319
 
 
320
  temperature = max(0.0, min(2.0, float(temperature)))
321
  max_output_tokens = max(1, min(8192, int(max_output_tokens)))
322
  top_k = max(1, min(100, int(top_k))) if top_k > 0 else None
323
  top_p = max(0.0, min(1.0, float(top_p)))
324
 
 
325
  config = types.GenerateContentConfig(
326
  temperature=temperature,
327
  max_output_tokens=max_output_tokens,
@@ -332,6 +230,7 @@ def bot(
332
  if preprocess_stop_sequences(stop_sequences):
333
  config.stop_sequences = preprocess_stop_sequences(stop_sequences)
334
 
 
335
  if image_prompt is None:
336
  contents = [user_message]
337
  else:
@@ -339,12 +238,13 @@ def bot(
339
  if processed_image is None:
340
  history.append({
341
  "role": "assistant",
342
- "content": "⚠️ **Image Processing Failed**\n\nCould not process the image. Please try uploading another image."
343
  })
344
  yield history
345
  return
346
  contents = [user_message, processed_image]
347
 
 
348
  try:
349
  response = client.models.generate_content_stream(
350
  model='gemini-2.0-flash-exp',
@@ -360,20 +260,24 @@ def bot(
360
  yield history
361
  time.sleep(0.01)
362
 
 
363
  if not history[-1]["content"]:
364
- history[-1]["content"] = "⚠️ **No Response**\n\nThe content may have been blocked by safety filters. Please try a different prompt."
365
  yield history
366
 
367
  except Exception as e:
368
  error_message = str(e)
369
  if "API_KEY_INVALID" in error_message or "invalid" in error_message.lower():
370
- error_msg = "❌ **Invalid API Key**\n\nPlease check your Google API key and try again."
371
  elif "quota" in error_message.lower():
372
- error_msg = "⚠️ **Quota Exceeded**\n\nYou've reached the API usage limit. Please try again later."
373
  else:
374
- error_msg = f"❌ **Error**\n\n{error_message}"
375
 
376
- history.append({"role": "assistant", "content": error_msg})
 
 
 
377
  yield history
378
  return
379
 
@@ -382,7 +286,7 @@ def bot(
382
  if history:
383
  history.append({
384
  "role": "assistant",
385
- "content": f"❌ **Critical Error**\n\n{str(e)}"
386
  })
387
  yield history or []
388
 
@@ -391,7 +295,7 @@ def clear_chat():
391
  return [], None
392
 
393
  # ===================== UI =====================
394
- with gr.Blocks(title="Gemini AI Chatbot") as demo:
395
 
396
  # Header
397
  gr.HTML(TITLE)
@@ -400,45 +304,43 @@ with gr.Blocks(title="Gemini AI Chatbot") as demo:
400
 
401
  # Main chat interface
402
  with gr.Row(equal_height=False):
403
- with gr.Column(scale=1, min_width=320):
404
  image_prompt = gr.Image(
405
  type="pil",
406
- label="πŸ“Έ Upload Image (Optional)",
407
- height=300,
408
  elem_classes="image-container"
409
  )
410
 
411
  api_key = gr.Textbox(
412
  label="πŸ”‘ Google API Key",
413
  type="password",
414
- placeholder="Paste your API key here...",
415
- info="Get it free from Google AI Studio"
416
  )
417
 
418
- with gr.Row():
419
- clear_btn = gr.Button("πŸ—‘οΈ Clear Chat", variant="secondary", size="sm", scale=1)
420
 
421
  with gr.Column(scale=2):
422
  chatbot = gr.Chatbot(
423
- label="πŸ’¬ Chat with Gemini",
424
- height=500,
425
- elem_classes="chatbot"
426
  )
427
 
428
  # Message input
429
  with gr.Row():
430
  msg = gr.Textbox(
431
- placeholder="πŸ’­ Type your message and press Enter...",
432
- label="Message",
433
  show_label=False,
434
  scale=9,
435
  lines=2,
436
- max_lines=6
437
  )
438
- submit_btn = gr.Button("πŸ“€ Send", scale=1, variant="primary")
439
 
440
  # Parameters accordion
441
- with gr.Accordion("βš™οΈ Advanced Settings", open=False):
442
  with gr.Row():
443
  temperature = gr.Slider(
444
  minimum=0,
@@ -446,53 +348,53 @@ with gr.Blocks(title="Gemini AI Chatbot") as demo:
446
  value=1.0,
447
  step=0.1,
448
  label="🌑️ Temperature",
449
- info="Controls creativity (higher = more creative)"
450
  )
451
  max_tokens = gr.Slider(
452
  minimum=100,
453
  maximum=8192,
454
  value=2048,
455
  step=100,
456
- label="πŸ“ Max Tokens",
457
- info="Maximum response length"
458
- )
459
-
460
- with gr.Row():
461
- top_k = gr.Slider(
462
- minimum=0,
463
- maximum=100,
464
- value=40,
465
- step=1,
466
- label="πŸ” Top-K",
467
- info="Token selection pool size"
468
- )
469
- top_p = gr.Slider(
470
- minimum=0,
471
- maximum=1,
472
- value=0.95,
473
- step=0.05,
474
- label="πŸ“Š Top-P",
475
- info="Nucleus sampling threshold"
476
  )
477
 
478
  stop_seq = gr.Textbox(
479
- label="πŸ›‘ Stop Sequences",
480
- placeholder="STOP, END (comma-separated)",
481
  info="Optional sequences to stop generation",
482
  value=""
483
  )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
484
 
485
  # Examples
486
  gr.Examples(
487
  examples=[
488
  ["Explain quantum computing in simple terms"],
489
- ["Write a Python function to reverse a string"],
490
- ["What are 5 tips for better sleep?"],
491
- ["Tell me a creative short story about AI"],
492
  ],
493
  inputs=msg,
494
- label="πŸ’‘ Try these examples",
495
- elem_classes="examples"
496
  )
497
 
498
  # Event handlers
@@ -503,7 +405,16 @@ with gr.Blocks(title="Gemini AI Chatbot") as demo:
503
  queue=False
504
  ).then(
505
  bot,
506
- inputs=[api_key, image_prompt, temperature, max_tokens, stop_seq, top_k, top_p, chatbot],
 
 
 
 
 
 
 
 
 
507
  outputs=chatbot
508
  )
509
 
@@ -514,7 +425,16 @@ with gr.Blocks(title="Gemini AI Chatbot") as demo:
514
  queue=False
515
  ).then(
516
  bot,
517
- inputs=[api_key, image_prompt, temperature, max_tokens, stop_seq, top_k, top_p, chatbot],
 
 
 
 
 
 
 
 
 
518
  outputs=chatbot
519
  )
520
 
@@ -528,12 +448,10 @@ if __name__ == "__main__":
528
  demo.queue(max_size=20)
529
  demo.launch(
530
  theme=gr.themes.Soft(
531
- primary_hue="indigo",
532
  secondary_hue="blue",
533
- neutral_hue="slate",
534
  spacing_size="md",
535
- radius_size="lg",
536
- font=["Inter", "ui-sans-serif", "system-ui", "sans-serif"]
537
  ),
538
  css=CUSTOM_CSS,
539
  ssr_mode=False
 
12
  # For Hugging Face Spaces, use Secrets
13
  GOOGLE_API_KEY = os.environ.get("GOOGLE_API_KEY", "")
14
 
15
+ TITLE = """<h1 align="center" style="background: linear-gradient(90deg, #9D50BB 0%, #6E48AA 50%, #4A90E2 100%);
16
+ -webkit-background-clip: text; -webkit-text-fill-color: transparent; font-size: 3em; font-weight: bold; margin-bottom: 10px;">
17
+ Gemini Chatbot πŸ”₯ with Kelwa</h1>"""
 
 
 
 
 
 
 
 
18
 
19
+ SUBTITLE = """<h2 align="center" style="color: #B19CD9; font-size: 1.5em; margin-top: 0;">
20
+ 🎨 Create with Multimodal Gemini</h2>"""
 
 
 
 
 
21
 
22
  DESCRIPTION = """
23
+ <p align="center" style="color: #6E48AA; font-size: 1.1em;">
24
+ Enter your Google API Key to start chatting with Gemini AI! Get your API key from
25
+ <a href="https://aistudio.google.com/app/apikey" target="_blank" style="color: #9D50BB; font-weight: bold;">Google AI Studio</a>
 
 
 
 
 
 
 
 
 
26
  </p>
27
  """
28
 
29
  IMAGE_WIDTH = 512
30
 
31
+ # Custom CSS for purple and baby blue theme
32
  CUSTOM_CSS = """
 
33
  .gradio-container {
34
  max-width: 1400px !important;
35
  margin: auto !important;
36
+ background: linear-gradient(to bottom, #f0e6ff 0%, #e6f3ff 100%) !important;
37
+ }
38
+
39
+ .contain {
40
+ max-width: 100% !important;
41
  }
42
 
 
43
  button {
44
+ background: linear-gradient(90deg, #9D50BB 0%, #6E48AA 100%) !important;
45
  border: none !important;
46
  color: white !important;
47
  font-weight: 600 !important;
48
+ border-radius: 8px !important;
49
+ padding: 10px 20px !important;
50
  transition: all 0.3s ease !important;
 
51
  }
52
 
53
  button:hover {
54
+ background: linear-gradient(90deg, #B19CD9 0%, #89CFF0 100%) !important;
55
+ transform: scale(1.05) !important;
 
56
  }
57
 
58
+ .input-text, textarea, input {
59
+ border: 2px solid #B19CD9 !important;
 
 
 
 
 
60
  border-radius: 10px !important;
61
+ padding: 10px !important;
 
 
 
62
  }
63
 
64
  .input-text:focus, textarea:focus, input:focus {
65
+ border-color: #6E48AA !important;
66
+ box-shadow: 0 0 10px rgba(157, 80, 187, 0.3) !important;
67
  outline: none !important;
 
68
  }
69
 
 
70
  label {
71
+ color: #6E48AA !important;
72
  font-weight: 600 !important;
 
73
  margin-bottom: 8px !important;
74
  }
75
 
76
+ /* Chatbot message styling */
77
+ .message-wrap {
78
+ padding: 10px !important;
 
 
 
79
  }
80
 
81
+ .user {
82
+ background: linear-gradient(135deg, #9D50BB 0%, #6E48AA 100%) !important;
 
83
  color: white !important;
84
+ border-radius: 15px !important;
85
  padding: 12px 16px !important;
 
 
 
 
86
  }
87
 
88
+ .bot {
89
+ background: linear-gradient(135deg, #E6F3FF 0%, #D4E4F7 100%) !important;
90
+ color: #333 !important;
91
+ border-radius: 15px !important;
 
92
  padding: 12px 16px !important;
93
+ border-left: 4px solid #89CFF0 !important;
 
 
 
 
94
  }
95
 
96
  /* Accordion styling */
97
  .accordion {
98
+ background: rgba(177, 156, 217, 0.1) !important;
99
+ border: 2px solid #B19CD9 !important;
100
+ border-radius: 10px !important;
101
+ margin: 10px 0 !important;
 
102
  }
103
 
104
+ /* Image container */
105
  .image-container {
106
+ border: 3px solid #89CFF0 !important;
107
  border-radius: 15px !important;
108
+ padding: 10px !important;
109
  background: white !important;
 
 
 
 
 
 
110
  }
111
 
112
  /* Slider styling */
113
  input[type="range"] {
114
+ accent-color: #9D50BB !important;
 
 
 
 
 
 
115
  }
116
 
117
  /* Better spacing */
 
120
  }
121
 
122
  .block {
123
+ padding: 15px !important;
124
+ border-radius: 10px !important;
 
125
  }
126
 
 
127
  footer {
128
  display: none !important;
129
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
130
  """
131
 
132
  # ===================== HELPERS =====================
 
165
  if not message or message.strip() == "":
166
  return "", history
167
 
168
+ # Messages format: list of dicts with 'role' and 'content'
169
  history.append({"role": "user", "content": message.strip()})
170
  return "", history
171
  except Exception as e:
 
184
  ):
185
  """Generate bot response with comprehensive error handling."""
186
  try:
187
+ # Validate history
188
  if not history or len(history) == 0:
189
  yield history or []
190
  return
191
 
192
+ # Validate API key
193
  api_key = google_key.strip() if google_key else GOOGLE_API_KEY
194
  if not api_key:
195
  history.append({
196
  "role": "assistant",
197
+ "content": "❌ **Error**: API key is missing. Please provide a valid Google API key in the textbox below.\n\nGet your free API key from [Google AI Studio](https://aistudio.google.com/app/apikey)"
198
  })
199
  yield history
200
  return
201
 
202
+ # Configure API with new package
203
  try:
204
  client = genai.Client(api_key=api_key)
205
  except Exception as e:
206
  history.append({
207
  "role": "assistant",
208
+ "content": f"❌ **Error**: Invalid API key.\n\n{str(e)}\n\nPlease check your API key and try again."
209
  })
210
  yield history
211
  return
212
 
213
+ # Get user message
214
  user_message = history[-1]["content"]
215
 
216
+ # Validate parameters
217
  temperature = max(0.0, min(2.0, float(temperature)))
218
  max_output_tokens = max(1, min(8192, int(max_output_tokens)))
219
  top_k = max(1, min(100, int(top_k))) if top_k > 0 else None
220
  top_p = max(0.0, min(1.0, float(top_p)))
221
 
222
+ # Build config
223
  config = types.GenerateContentConfig(
224
  temperature=temperature,
225
  max_output_tokens=max_output_tokens,
 
230
  if preprocess_stop_sequences(stop_sequences):
231
  config.stop_sequences = preprocess_stop_sequences(stop_sequences)
232
 
233
+ # Prepare content
234
  if image_prompt is None:
235
  contents = [user_message]
236
  else:
 
238
  if processed_image is None:
239
  history.append({
240
  "role": "assistant",
241
+ "content": "❌ **Error**: Could not process the image. Please try uploading another image."
242
  })
243
  yield history
244
  return
245
  contents = [user_message, processed_image]
246
 
247
+ # Generate response
248
  try:
249
  response = client.models.generate_content_stream(
250
  model='gemini-2.0-flash-exp',
 
260
  yield history
261
  time.sleep(0.01)
262
 
263
+ # Handle empty response
264
  if not history[-1]["content"]:
265
+ history[-1]["content"] = "⚠️ No response generated. The content may have been blocked by safety filters. Please try a different prompt."
266
  yield history
267
 
268
  except Exception as e:
269
  error_message = str(e)
270
  if "API_KEY_INVALID" in error_message or "invalid" in error_message.lower():
271
+ error_msg = "❌ **Invalid API Key**. Please check your Google API key and try again."
272
  elif "quota" in error_message.lower():
273
+ error_msg = "❌ **Quota Exceeded**. You've reached the API usage limit. Please try again later or check your quota."
274
  else:
275
+ error_msg = f"❌ **Error generating response**: {error_message}"
276
 
277
+ history.append({
278
+ "role": "assistant",
279
+ "content": error_msg
280
+ })
281
  yield history
282
  return
283
 
 
286
  if history:
287
  history.append({
288
  "role": "assistant",
289
+ "content": f"❌ **Critical error**: {str(e)}"
290
  })
291
  yield history or []
292
 
 
295
  return [], None
296
 
297
  # ===================== UI =====================
298
+ with gr.Blocks(title="Gemini Chatbot with Kelwa") as demo:
299
 
300
  # Header
301
  gr.HTML(TITLE)
 
304
 
305
  # Main chat interface
306
  with gr.Row(equal_height=False):
307
+ with gr.Column(scale=1, min_width=300):
308
  image_prompt = gr.Image(
309
  type="pil",
310
+ label="πŸ–ΌοΈ Upload Image (Optional)",
311
+ height=350,
312
  elem_classes="image-container"
313
  )
314
 
315
  api_key = gr.Textbox(
316
  label="πŸ”‘ Google API Key",
317
  type="password",
318
+ placeholder="Enter your Google API key here...",
319
+ info="Your API key is not stored. Get one from Google AI Studio."
320
  )
321
 
322
+ clear_btn = gr.Button("πŸ—‘οΈ Clear Chat", variant="secondary", size="sm")
 
323
 
324
  with gr.Column(scale=2):
325
  chatbot = gr.Chatbot(
326
+ label="πŸ’¬ Gemini Chat",
327
+ height=550
 
328
  )
329
 
330
  # Message input
331
  with gr.Row():
332
  msg = gr.Textbox(
333
+ placeholder="✨ Type your message here and press Enter...",
334
+ label="Your Message",
335
  show_label=False,
336
  scale=9,
337
  lines=2,
338
+ max_lines=5
339
  )
340
+ submit_btn = gr.Button("Send πŸ“€", scale=1, variant="primary")
341
 
342
  # Parameters accordion
343
+ with gr.Accordion("βš™οΈ Generation Parameters", open=False):
344
  with gr.Row():
345
  temperature = gr.Slider(
346
  minimum=0,
 
348
  value=1.0,
349
  step=0.1,
350
  label="🌑️ Temperature",
351
+ info="Higher = more creative, Lower = more focused"
352
  )
353
  max_tokens = gr.Slider(
354
  minimum=100,
355
  maximum=8192,
356
  value=2048,
357
  step=100,
358
+ label="πŸ“ Max Output Tokens",
359
+ info="Maximum length of response"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
360
  )
361
 
362
  stop_seq = gr.Textbox(
363
+ label="πŸ›‘ Stop Sequences (comma-separated)",
364
+ placeholder="STOP, END, ###",
365
  info="Optional sequences to stop generation",
366
  value=""
367
  )
368
+
369
+ with gr.Accordion("πŸ”¬ Advanced Parameters", open=False):
370
+ with gr.Row():
371
+ top_k = gr.Slider(
372
+ minimum=0,
373
+ maximum=100,
374
+ value=40,
375
+ step=1,
376
+ label="πŸ” Top-K",
377
+ info="Limits token selection pool (0 = disabled)"
378
+ )
379
+ top_p = gr.Slider(
380
+ minimum=0,
381
+ maximum=1,
382
+ value=0.95,
383
+ step=0.01,
384
+ label="πŸ“Š Top-P (Nucleus)",
385
+ info="Cumulative probability threshold"
386
+ )
387
 
388
  # Examples
389
  gr.Examples(
390
  examples=[
391
  ["Explain quantum computing in simple terms"],
392
+ ["Write a Python function to sort a list"],
393
+ ["What are the health benefits of meditation?"],
394
+ ["Create a short story about a robot learning to paint"],
395
  ],
396
  inputs=msg,
397
+ label="πŸ’‘ Example Prompts"
 
398
  )
399
 
400
  # Event handlers
 
405
  queue=False
406
  ).then(
407
  bot,
408
+ inputs=[
409
+ api_key,
410
+ image_prompt,
411
+ temperature,
412
+ max_tokens,
413
+ stop_seq,
414
+ top_k,
415
+ top_p,
416
+ chatbot
417
+ ],
418
  outputs=chatbot
419
  )
420
 
 
425
  queue=False
426
  ).then(
427
  bot,
428
+ inputs=[
429
+ api_key,
430
+ image_prompt,
431
+ temperature,
432
+ max_tokens,
433
+ stop_seq,
434
+ top_k,
435
+ top_p,
436
+ chatbot
437
+ ],
438
  outputs=chatbot
439
  )
440
 
 
448
  demo.queue(max_size=20)
449
  demo.launch(
450
  theme=gr.themes.Soft(
451
+ primary_hue="purple",
452
  secondary_hue="blue",
 
453
  spacing_size="md",
454
+ radius_size="lg"
 
455
  ),
456
  css=CUSTOM_CSS,
457
  ssr_mode=False