Shinhati2023 commited on
Commit
57baca0
Β·
verified Β·
1 Parent(s): 94f720e

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +82 -80
app.py CHANGED
@@ -16,7 +16,7 @@ from functools import lru_cache
16
  # ==================== CONFIGURATION ====================
17
  # Set these environment variables:
18
  # GROQ_API_KEY - Your Groq API key
19
- # GITHUB_TOKEN - Your GitHub Personal Access Token
20
  # GITHUB_REPO - Your repo (format: username/repo-name)
21
 
22
  GROQ_API_KEY = os.getenv("GROQ_API_KEY", "")
@@ -61,7 +61,7 @@ class GroqClient:
61
  "Content-Type": "application/json"
62
  }
63
  self.available_models = []
64
-
65
  def fetch_models(self) -> List[str]:
66
  """Fetch available models from Groq API"""
67
  url = f"{self.base_url}/models"
@@ -75,7 +75,7 @@ class GroqClient:
75
  except Exception as e:
76
  print(f"Error fetching models: {e}")
77
  return []
78
-
79
  def chat_completion(
80
  self,
81
  messages: List[Dict[str, str]],
@@ -90,7 +90,7 @@ class GroqClient:
90
  Returns: (response_dict, model_used)
91
  """
92
  url = f"{self.base_url}/chat/completions"
93
-
94
  # Determine which models to try
95
  models_to_try = [model]
96
  if retry_with_fallback and model in MODEL_FALLBACK_CHAIN:
@@ -99,9 +99,9 @@ class GroqClient:
99
  models_to_try.extend(MODEL_FALLBACK_CHAIN[idx+1:])
100
  elif retry_with_fallback:
101
  models_to_try.extend(MODEL_FALLBACK_CHAIN)
102
-
103
  last_error = None
104
-
105
  for try_model in models_to_try:
106
  payload = {
107
  "model": try_model,
@@ -110,30 +110,30 @@ class GroqClient:
110
  "max_completion_tokens": max_tokens,
111
  "stream": stream
112
  }
113
-
114
  try:
115
  response = requests.post(url, headers=self.headers, json=payload, timeout=60)
116
-
117
  if response.status_code == 200:
118
  return response.json(), try_model
119
-
120
  # Handle specific errors
121
  error_data = response.json() if response.text else {}
122
  error_msg = error_data.get("error", {}).get("message", "")
123
-
124
  # If model not found, try next
125
  if "model_not_found" in error_msg or "does not exist" in error_msg:
126
  print(f"Model {try_model} not available, trying fallback...")
127
  last_error = f"{try_model}: {error_msg}"
128
  continue
129
-
130
  # For other errors, return immediately
131
  return {"error": error_msg or f"HTTP {response.status_code}", "detail": response.text}, try_model
132
-
133
  except requests.exceptions.RequestException as e:
134
  last_error = str(e)
135
  continue
136
-
137
  # All models failed
138
  return {"error": f"All models failed. Last error: {last_error}"}, model
139
 
@@ -147,7 +147,7 @@ class GitHubIntegration:
147
  "Authorization": f"token {token}",
148
  "Accept": "application/vnd.github.v3+json"
149
  }
150
-
151
  def commit_file(
152
  self,
153
  content: str,
@@ -158,20 +158,20 @@ class GitHubIntegration:
158
  """Commit a file to GitHub repository"""
159
  if not self.token or not self.repo:
160
  return {"status": "error", "message": "GitHub credentials not configured"}
161
-
162
  timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
163
  full_filename = f"{timestamp}_{filename}"
164
  file_path = f"{path}/{full_filename}"
165
-
166
  content_bytes = content.encode('utf-8')
167
  content_b64 = base64.b64encode(content_bytes).decode('utf-8')
168
-
169
  check_url = f"{self.base_url}/repos/{self.repo}/contents/{file_path}"
170
-
171
  try:
172
  check_resp = requests.get(check_url, headers=self.headers)
173
  sha = check_resp.json().get("sha") if check_resp.status_code == 200 else None
174
-
175
  data = {
176
  "message": message or f"Update from Groq Studio - {timestamp}",
177
  "content": content_b64,
@@ -179,10 +179,10 @@ class GitHubIntegration:
179
  }
180
  if sha:
181
  data["sha"] = sha
182
-
183
  resp = requests.put(check_url, headers=self.headers, json=data)
184
  resp.raise_for_status()
185
-
186
  result = resp.json()
187
  return {
188
  "status": "success",
@@ -192,12 +192,12 @@ class GitHubIntegration:
192
  }
193
  except Exception as e:
194
  return {"status": "error", "message": str(e)}
195
-
196
  def create_gist(self, content: str, description: str = "Groq Studio Export", public: bool = False) -> Dict[str, str]:
197
  """Create a GitHub Gist"""
198
  if not self.token:
199
  return {"status": "error", "message": "GitHub token not configured"}
200
-
201
  url = f"{self.base_url}/gists"
202
  data = {
203
  "description": description,
@@ -208,7 +208,7 @@ class GitHubIntegration:
208
  }
209
  }
210
  }
211
-
212
  try:
213
  resp = requests.post(url, headers=self.headers, json=data)
214
  resp.raise_for_status()
@@ -227,10 +227,10 @@ def refresh_models(api_key: str) -> gr.update:
227
  key = api_key or GROQ_API_KEY
228
  if not key:
229
  return gr.update(choices=DEFAULT_MODELS, value=DEFAULT_MODELS[0])
230
-
231
  client = GroqClient(key)
232
  models = client.fetch_models()
233
-
234
  if models:
235
  # Prioritize common models at top
236
  priority = ["llama-3.3-70b-versatile", "meta-llama/llama-4", "gpt-oss", "qwen", "llama-3.1"]
@@ -239,7 +239,7 @@ def refresh_models(api_key: str) -> gr.update:
239
  sorted_models.extend([m for m in models if p in m and m not in sorted_models])
240
  sorted_models.extend([m for m in models if m not in sorted_models])
241
  return gr.update(choices=sorted_models, value=sorted_models[0])
242
-
243
  return gr.update(choices=DEFAULT_MODELS, value=DEFAULT_MODELS[0])
244
 
245
  def process_chat(
@@ -255,26 +255,26 @@ def process_chat(
255
  """Process chat message with Groq API and auto-fallback"""
256
  if not api_key and not GROQ_API_KEY:
257
  return history + [[message, "❌ Error: Please provide a Groq API Key in settings or environment variable."]], "", "⚠️ No API Key"
258
-
259
  key = api_key or GROQ_API_KEY
260
  client = GroqClient(key)
261
-
262
  # Build messages
263
  messages = []
264
  if system_prompt:
265
  messages.append({"role": "system", "content": system_prompt})
266
-
267
  for human, assistant in history:
268
  messages.append({"role": "user", "content": human})
269
  if assistant:
270
  messages.append({"role": "assistant", "content": assistant})
271
-
272
  messages.append({"role": "user", "content": message})
273
-
274
  # Show typing indicator
275
  history = history + [[message, "⏳ Thinking..."]]
276
  yield history, "", f"πŸ”„ Using {model}..."
277
-
278
  # Get response with fallback
279
  response, model_used = client.chat_completion(
280
  messages=messages,
@@ -283,7 +283,7 @@ def process_chat(
283
  max_tokens=max_tokens,
284
  retry_with_fallback=auto_fallback
285
  )
286
-
287
  # Update history
288
  if "error" in response:
289
  error_msg = f"❌ Error: {response['error']}"
@@ -295,19 +295,19 @@ def process_chat(
295
  try:
296
  content = response["choices"][0]["message"]["content"]
297
  usage = response.get("usage", {})
298
-
299
  # Add model info footer
300
  fallback_notice = ""
301
  if model_used != model:
302
  fallback_notice = f" (⚠️ Fallback from {model})"
303
-
304
  info = f"\n\n---\n*Model: {model_used}{fallback_notice} | Tokens: {usage.get('total_tokens', 'N/A')}*"
305
  history[-1][1] = content + info
306
  status = f"βœ… Success with {model_used}" + (" (fallback)" if model_used != model else "")
307
  except Exception as e:
308
  history[-1][1] = f"❌ Error parsing response: {str(e)}"
309
  status = f"❌ Parse Error"
310
-
311
  yield history, "", status
312
 
313
  def export_to_github(
@@ -320,14 +320,14 @@ def export_to_github(
320
  """Export chat history to GitHub"""
321
  token = github_token or GITHUB_TOKEN
322
  repo = github_repo or GITHUB_REPO
323
-
324
  if not token or not repo:
325
  return "❌ Error: GitHub token and repo not configured."
326
-
327
  content = format_conversation(history)
328
  gh = GitHubIntegration(token, repo)
329
  result = gh.commit_file(content, filename or "session.md", message=commit_msg)
330
-
331
  if result["status"] == "success":
332
  return f"βœ… Committed successfully!\n\nπŸ”— [View on GitHub]({result['url']})"
333
  else:
@@ -340,14 +340,14 @@ def create_gist_export(
340
  ) -> str:
341
  """Export as GitHub Gist"""
342
  token = github_token or GITHUB_TOKEN
343
-
344
  if not token:
345
  return "❌ Error: GitHub token not configured."
346
-
347
  content = format_conversation(history)
348
  gh = GitHubIntegration(token, "")
349
  result = gh.create_gist(content, description)
350
-
351
  if result["status"] == "success":
352
  return f"βœ… Gist created!\n\nπŸ”— [View Gist]({result['url']})"
353
  else:
@@ -358,14 +358,14 @@ def format_conversation(history: List[List[str]]) -> str:
358
  content = "# Groq Studio Session\n\n"
359
  content += f"**Date:** {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}\n\n"
360
  content += "## Conversation\n\n"
361
-
362
  for i, (human, assistant) in enumerate(history, 1):
363
  if not assistant or assistant == "⏳ Thinking...":
364
  continue
365
  content += f"### Turn {i}\n\n"
366
  content += f"**User:**\n{human}\n\n"
367
  content += f"**Assistant:**\n{assistant}\n\n---\n\n"
368
-
369
  return content
370
 
371
  def clear_chat():
@@ -383,7 +383,7 @@ def debug_request(
383
  ) -> str:
384
  """Generate debug/curl command"""
385
  key = api_key or GROQ_API_KEY
386
-
387
  messages = []
388
  if system_prompt:
389
  messages.append({"role": "system", "content": system_prompt})
@@ -392,19 +392,19 @@ def debug_request(
392
  if assistant:
393
  messages.append({"role": "assistant", "content": assistant})
394
  messages.append({"role": "user", "content": message})
395
-
396
  payload = {
397
  "model": model,
398
  "messages": messages,
399
  "temperature": temperature,
400
  "max_completion_tokens": max_tokens
401
  }
402
-
403
  curl_cmd = f"""curl -X POST https://api.groq.com/openai/v1/chat/completions \\
404
  -H "Authorization: Bearer {key[:10]}...{key[-4:] if len(key) > 14 else ''}" \\
405
  -H "Content-Type: application/json" \\
406
  -d '{json.dumps(payload, indent=2)}'"""
407
-
408
  python_code = f"""import requests
409
  import json
410
  import os
@@ -420,7 +420,7 @@ payload = {json.dumps(payload, indent=2)}
420
  response = requests.post(url, headers=headers, json=payload)
421
  print(f"Status: {{response.status_code}}")
422
  print(f"Response: {{response.text}}")"""
423
-
424
  return f"## cURL Command\n```bash\n{curl_cmd}\n```\n\n## Python Code\n```python\n{python_code}\n```"
425
 
426
  # ==================== CUSTOM CSS ====================
@@ -526,8 +526,9 @@ button:hover {
526
 
527
  # ==================== GRADIO INTERFACE ====================
528
  def create_interface():
529
- with gr.Blocks(css=CUSTOM_CSS, title="Groq AI Studio Pro") as demo:
530
-
 
531
  # Header
532
  with gr.Row():
533
  with gr.Column():
@@ -541,21 +542,21 @@ def create_interface():
541
  </p>
542
  </div>
543
  """)
544
-
545
  # State
546
  state_history = gr.State([])
547
-
548
  with gr.Row():
549
  # Left Panel - Chat
550
  with gr.Column(scale=3):
551
  with gr.Group(elem_classes="glass-panel"):
 
552
  chatbot = gr.Chatbot(
553
  label="Conversation",
554
  elem_classes="chatbot",
555
- bubble_full_width=False,
556
  show_copy_button=True
557
  )
558
-
559
  with gr.Row():
560
  msg_input = gr.Textbox(
561
  placeholder="Type your message here... (Shift+Enter for new line)",
@@ -565,12 +566,12 @@ def create_interface():
565
  lines=1
566
  )
567
  send_btn = gr.Button("Send ➀", scale=1, variant="primary")
568
-
569
  with gr.Row():
570
  clear_btn = gr.Button("πŸ—‘οΈ Clear", variant="secondary")
571
  debug_btn = gr.Button("πŸ”§ Debug", variant="secondary")
572
  export_btn = gr.Button("πŸ“€ Export", variant="secondary")
573
-
574
  # Status bar
575
  status_text = gr.Textbox(
576
  value="πŸ”„ Ready",
@@ -578,12 +579,12 @@ def create_interface():
578
  interactive=False,
579
  elem_classes="status-bar"
580
  )
581
-
582
  # Right Panel - Settings
583
  with gr.Column(scale=1):
584
  with gr.Group(elem_classes="glass-panel"):
585
  gr.Markdown("### βš™οΈ Configuration")
586
-
587
  with gr.Accordion("πŸ”‘ API Settings", open=False):
588
  api_key_input = gr.Textbox(
589
  label="Groq API Key",
@@ -591,20 +592,20 @@ def create_interface():
591
  type="password",
592
  value=GROQ_API_KEY
593
  )
594
-
595
  github_token_input = gr.Textbox(
596
  label="GitHub Token",
597
  placeholder="ghp_...",
598
  type="password",
599
  value=GITHUB_TOKEN
600
  )
601
-
602
  github_repo_input = gr.Textbox(
603
  label="GitHub Repo",
604
  placeholder="username/repo",
605
  value=GITHUB_REPO
606
  )
607
-
608
  with gr.Row():
609
  model_dropdown = gr.Dropdown(
610
  choices=DEFAULT_MODELS,
@@ -612,30 +613,30 @@ def create_interface():
612
  label="Model"
613
  )
614
  refresh_btn = gr.Button("πŸ”„", size="sm")
615
-
616
  auto_fallback = gr.Checkbox(
617
  label="Auto-Fallback if Model Fails",
618
  value=True,
619
  info="Automatically try backup models"
620
  )
621
-
622
  system_prompt = gr.Textbox(
623
  label="System Prompt",
624
  placeholder="You are a helpful assistant...",
625
  lines=3,
626
  value="You are a helpful, creative AI assistant powered by Groq. Respond concisely but thoroughly."
627
  )
628
-
629
  with gr.Row():
630
  temperature = gr.Slider(0, 2, value=0.7, label="Temperature")
631
  max_tokens = gr.Slider(100, 8192, value=4096, label="Max Tokens")
632
-
633
  # Debug Modal
634
  with gr.Row(visible=False) as debug_row:
635
  with gr.Column():
636
  debug_output = gr.Code(label="Debug Request", language="python")
637
  close_debug = gr.Button("Close")
638
-
639
  # Export Modal
640
  with gr.Row(visible=False) as export_row:
641
  with gr.Column():
@@ -647,51 +648,51 @@ def create_interface():
647
  gist_btn = gr.Button("πŸ“„ Create Gist")
648
  export_result = gr.Markdown()
649
  close_export = gr.Button("Close")
650
-
651
  # Event Handlers
652
  refresh_btn.click(
653
  refresh_models,
654
  [api_key_input],
655
  [model_dropdown]
656
  )
657
-
658
  send_event = msg_input.submit(
659
  process_chat,
660
  [msg_input, chatbot, model_dropdown, temperature, max_tokens, system_prompt, api_key_input, auto_fallback],
661
  [chatbot, msg_input, status_text]
662
  )
663
-
664
  send_btn.click(
665
  process_chat,
666
  [msg_input, chatbot, model_dropdown, temperature, max_tokens, system_prompt, api_key_input, auto_fallback],
667
  [chatbot, msg_input, status_text]
668
  )
669
-
670
  clear_btn.click(clear_chat, outputs=[chatbot, state_history, status_text])
671
-
672
  debug_btn.click(
673
  debug_request,
674
  [msg_input, chatbot, model_dropdown, temperature, max_tokens, system_prompt, api_key_input],
675
  [debug_output]
676
  ).then(lambda: gr.update(visible=True), outputs=[debug_row])
677
-
678
  close_debug.click(lambda: gr.update(visible=False), outputs=[debug_row])
679
-
680
  export_btn.click(lambda: gr.update(visible=True), outputs=[export_row])
681
  close_export.click(lambda: gr.update(visible=False), outputs=[export_row])
682
-
683
  commit_btn.click(
684
  export_to_github,
685
  [state_history, export_filename, export_message, github_token_input, github_repo_input],
686
  [export_result]
687
  )
688
-
689
  gist_btn.click(
690
  create_gist_export,
691
  [state_history, export_message, github_token_input],
692
  [export_result]
693
  )
694
-
695
  # Footer
696
  gr.HTML("""
697
  <div style="text-align: center; padding: 20px; color: #666; font-size: 12px;">
@@ -699,10 +700,11 @@ def create_interface():
699
  <a href="https://console.groq.com" target="_blank" style="color: #4ecdc4;">Get API Key</a></p>
700
  </div>
701
  """)
702
-
703
  return demo
704
 
705
  # Launch
706
  if __name__ == "__main__":
707
  demo = create_interface()
708
- demo.launch(server_name="0.0.0.0", server_port=7860)
 
 
16
  # ==================== CONFIGURATION ====================
17
  # Set these environment variables:
18
  # GROQ_API_KEY - Your Groq API key
19
+ # GITHUB_TOKEN - Your GitHub Personal Access Token
20
  # GITHUB_REPO - Your repo (format: username/repo-name)
21
 
22
  GROQ_API_KEY = os.getenv("GROQ_API_KEY", "")
 
61
  "Content-Type": "application/json"
62
  }
63
  self.available_models = []
64
+
65
  def fetch_models(self) -> List[str]:
66
  """Fetch available models from Groq API"""
67
  url = f"{self.base_url}/models"
 
75
  except Exception as e:
76
  print(f"Error fetching models: {e}")
77
  return []
78
+
79
  def chat_completion(
80
  self,
81
  messages: List[Dict[str, str]],
 
90
  Returns: (response_dict, model_used)
91
  """
92
  url = f"{self.base_url}/chat/completions"
93
+
94
  # Determine which models to try
95
  models_to_try = [model]
96
  if retry_with_fallback and model in MODEL_FALLBACK_CHAIN:
 
99
  models_to_try.extend(MODEL_FALLBACK_CHAIN[idx+1:])
100
  elif retry_with_fallback:
101
  models_to_try.extend(MODEL_FALLBACK_CHAIN)
102
+
103
  last_error = None
104
+
105
  for try_model in models_to_try:
106
  payload = {
107
  "model": try_model,
 
110
  "max_completion_tokens": max_tokens,
111
  "stream": stream
112
  }
113
+
114
  try:
115
  response = requests.post(url, headers=self.headers, json=payload, timeout=60)
116
+
117
  if response.status_code == 200:
118
  return response.json(), try_model
119
+
120
  # Handle specific errors
121
  error_data = response.json() if response.text else {}
122
  error_msg = error_data.get("error", {}).get("message", "")
123
+
124
  # If model not found, try next
125
  if "model_not_found" in error_msg or "does not exist" in error_msg:
126
  print(f"Model {try_model} not available, trying fallback...")
127
  last_error = f"{try_model}: {error_msg}"
128
  continue
129
+
130
  # For other errors, return immediately
131
  return {"error": error_msg or f"HTTP {response.status_code}", "detail": response.text}, try_model
132
+
133
  except requests.exceptions.RequestException as e:
134
  last_error = str(e)
135
  continue
136
+
137
  # All models failed
138
  return {"error": f"All models failed. Last error: {last_error}"}, model
139
 
 
147
  "Authorization": f"token {token}",
148
  "Accept": "application/vnd.github.v3+json"
149
  }
150
+
151
  def commit_file(
152
  self,
153
  content: str,
 
158
  """Commit a file to GitHub repository"""
159
  if not self.token or not self.repo:
160
  return {"status": "error", "message": "GitHub credentials not configured"}
161
+
162
  timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
163
  full_filename = f"{timestamp}_{filename}"
164
  file_path = f"{path}/{full_filename}"
165
+
166
  content_bytes = content.encode('utf-8')
167
  content_b64 = base64.b64encode(content_bytes).decode('utf-8')
168
+
169
  check_url = f"{self.base_url}/repos/{self.repo}/contents/{file_path}"
170
+
171
  try:
172
  check_resp = requests.get(check_url, headers=self.headers)
173
  sha = check_resp.json().get("sha") if check_resp.status_code == 200 else None
174
+
175
  data = {
176
  "message": message or f"Update from Groq Studio - {timestamp}",
177
  "content": content_b64,
 
179
  }
180
  if sha:
181
  data["sha"] = sha
182
+
183
  resp = requests.put(check_url, headers=self.headers, json=data)
184
  resp.raise_for_status()
185
+
186
  result = resp.json()
187
  return {
188
  "status": "success",
 
192
  }
193
  except Exception as e:
194
  return {"status": "error", "message": str(e)}
195
+
196
  def create_gist(self, content: str, description: str = "Groq Studio Export", public: bool = False) -> Dict[str, str]:
197
  """Create a GitHub Gist"""
198
  if not self.token:
199
  return {"status": "error", "message": "GitHub token not configured"}
200
+
201
  url = f"{self.base_url}/gists"
202
  data = {
203
  "description": description,
 
208
  }
209
  }
210
  }
211
+
212
  try:
213
  resp = requests.post(url, headers=self.headers, json=data)
214
  resp.raise_for_status()
 
227
  key = api_key or GROQ_API_KEY
228
  if not key:
229
  return gr.update(choices=DEFAULT_MODELS, value=DEFAULT_MODELS[0])
230
+
231
  client = GroqClient(key)
232
  models = client.fetch_models()
233
+
234
  if models:
235
  # Prioritize common models at top
236
  priority = ["llama-3.3-70b-versatile", "meta-llama/llama-4", "gpt-oss", "qwen", "llama-3.1"]
 
239
  sorted_models.extend([m for m in models if p in m and m not in sorted_models])
240
  sorted_models.extend([m for m in models if m not in sorted_models])
241
  return gr.update(choices=sorted_models, value=sorted_models[0])
242
+
243
  return gr.update(choices=DEFAULT_MODELS, value=DEFAULT_MODELS[0])
244
 
245
  def process_chat(
 
255
  """Process chat message with Groq API and auto-fallback"""
256
  if not api_key and not GROQ_API_KEY:
257
  return history + [[message, "❌ Error: Please provide a Groq API Key in settings or environment variable."]], "", "⚠️ No API Key"
258
+
259
  key = api_key or GROQ_API_KEY
260
  client = GroqClient(key)
261
+
262
  # Build messages
263
  messages = []
264
  if system_prompt:
265
  messages.append({"role": "system", "content": system_prompt})
266
+
267
  for human, assistant in history:
268
  messages.append({"role": "user", "content": human})
269
  if assistant:
270
  messages.append({"role": "assistant", "content": assistant})
271
+
272
  messages.append({"role": "user", "content": message})
273
+
274
  # Show typing indicator
275
  history = history + [[message, "⏳ Thinking..."]]
276
  yield history, "", f"πŸ”„ Using {model}..."
277
+
278
  # Get response with fallback
279
  response, model_used = client.chat_completion(
280
  messages=messages,
 
283
  max_tokens=max_tokens,
284
  retry_with_fallback=auto_fallback
285
  )
286
+
287
  # Update history
288
  if "error" in response:
289
  error_msg = f"❌ Error: {response['error']}"
 
295
  try:
296
  content = response["choices"][0]["message"]["content"]
297
  usage = response.get("usage", {})
298
+
299
  # Add model info footer
300
  fallback_notice = ""
301
  if model_used != model:
302
  fallback_notice = f" (⚠️ Fallback from {model})"
303
+
304
  info = f"\n\n---\n*Model: {model_used}{fallback_notice} | Tokens: {usage.get('total_tokens', 'N/A')}*"
305
  history[-1][1] = content + info
306
  status = f"βœ… Success with {model_used}" + (" (fallback)" if model_used != model else "")
307
  except Exception as e:
308
  history[-1][1] = f"❌ Error parsing response: {str(e)}"
309
  status = f"❌ Parse Error"
310
+
311
  yield history, "", status
312
 
313
  def export_to_github(
 
320
  """Export chat history to GitHub"""
321
  token = github_token or GITHUB_TOKEN
322
  repo = github_repo or GITHUB_REPO
323
+
324
  if not token or not repo:
325
  return "❌ Error: GitHub token and repo not configured."
326
+
327
  content = format_conversation(history)
328
  gh = GitHubIntegration(token, repo)
329
  result = gh.commit_file(content, filename or "session.md", message=commit_msg)
330
+
331
  if result["status"] == "success":
332
  return f"βœ… Committed successfully!\n\nπŸ”— [View on GitHub]({result['url']})"
333
  else:
 
340
  ) -> str:
341
  """Export as GitHub Gist"""
342
  token = github_token or GITHUB_TOKEN
343
+
344
  if not token:
345
  return "❌ Error: GitHub token not configured."
346
+
347
  content = format_conversation(history)
348
  gh = GitHubIntegration(token, "")
349
  result = gh.create_gist(content, description)
350
+
351
  if result["status"] == "success":
352
  return f"βœ… Gist created!\n\nπŸ”— [View Gist]({result['url']})"
353
  else:
 
358
  content = "# Groq Studio Session\n\n"
359
  content += f"**Date:** {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}\n\n"
360
  content += "## Conversation\n\n"
361
+
362
  for i, (human, assistant) in enumerate(history, 1):
363
  if not assistant or assistant == "⏳ Thinking...":
364
  continue
365
  content += f"### Turn {i}\n\n"
366
  content += f"**User:**\n{human}\n\n"
367
  content += f"**Assistant:**\n{assistant}\n\n---\n\n"
368
+
369
  return content
370
 
371
  def clear_chat():
 
383
  ) -> str:
384
  """Generate debug/curl command"""
385
  key = api_key or GROQ_API_KEY
386
+
387
  messages = []
388
  if system_prompt:
389
  messages.append({"role": "system", "content": system_prompt})
 
392
  if assistant:
393
  messages.append({"role": "assistant", "content": assistant})
394
  messages.append({"role": "user", "content": message})
395
+
396
  payload = {
397
  "model": model,
398
  "messages": messages,
399
  "temperature": temperature,
400
  "max_completion_tokens": max_tokens
401
  }
402
+
403
  curl_cmd = f"""curl -X POST https://api.groq.com/openai/v1/chat/completions \\
404
  -H "Authorization: Bearer {key[:10]}...{key[-4:] if len(key) > 14 else ''}" \\
405
  -H "Content-Type: application/json" \\
406
  -d '{json.dumps(payload, indent=2)}'"""
407
+
408
  python_code = f"""import requests
409
  import json
410
  import os
 
420
  response = requests.post(url, headers=headers, json=payload)
421
  print(f"Status: {{response.status_code}}")
422
  print(f"Response: {{response.text}}")"""
423
+
424
  return f"## cURL Command\n```bash\n{curl_cmd}\n```\n\n## Python Code\n```python\n{python_code}\n```"
425
 
426
  # ==================== CUSTOM CSS ====================
 
526
 
527
  # ==================== GRADIO INTERFACE ====================
528
  def create_interface():
529
+ # FIX: Removed css parameter from Blocks constructor
530
+ with gr.Blocks(title="Groq AI Studio Pro") as demo:
531
+
532
  # Header
533
  with gr.Row():
534
  with gr.Column():
 
542
  </p>
543
  </div>
544
  """)
545
+
546
  # State
547
  state_history = gr.State([])
548
+
549
  with gr.Row():
550
  # Left Panel - Chat
551
  with gr.Column(scale=3):
552
  with gr.Group(elem_classes="glass-panel"):
553
+ # FIX: Removed bubble_full_width parameter
554
  chatbot = gr.Chatbot(
555
  label="Conversation",
556
  elem_classes="chatbot",
 
557
  show_copy_button=True
558
  )
559
+
560
  with gr.Row():
561
  msg_input = gr.Textbox(
562
  placeholder="Type your message here... (Shift+Enter for new line)",
 
566
  lines=1
567
  )
568
  send_btn = gr.Button("Send ➀", scale=1, variant="primary")
569
+
570
  with gr.Row():
571
  clear_btn = gr.Button("πŸ—‘οΈ Clear", variant="secondary")
572
  debug_btn = gr.Button("πŸ”§ Debug", variant="secondary")
573
  export_btn = gr.Button("πŸ“€ Export", variant="secondary")
574
+
575
  # Status bar
576
  status_text = gr.Textbox(
577
  value="πŸ”„ Ready",
 
579
  interactive=False,
580
  elem_classes="status-bar"
581
  )
582
+
583
  # Right Panel - Settings
584
  with gr.Column(scale=1):
585
  with gr.Group(elem_classes="glass-panel"):
586
  gr.Markdown("### βš™οΈ Configuration")
587
+
588
  with gr.Accordion("πŸ”‘ API Settings", open=False):
589
  api_key_input = gr.Textbox(
590
  label="Groq API Key",
 
592
  type="password",
593
  value=GROQ_API_KEY
594
  )
595
+
596
  github_token_input = gr.Textbox(
597
  label="GitHub Token",
598
  placeholder="ghp_...",
599
  type="password",
600
  value=GITHUB_TOKEN
601
  )
602
+
603
  github_repo_input = gr.Textbox(
604
  label="GitHub Repo",
605
  placeholder="username/repo",
606
  value=GITHUB_REPO
607
  )
608
+
609
  with gr.Row():
610
  model_dropdown = gr.Dropdown(
611
  choices=DEFAULT_MODELS,
 
613
  label="Model"
614
  )
615
  refresh_btn = gr.Button("πŸ”„", size="sm")
616
+
617
  auto_fallback = gr.Checkbox(
618
  label="Auto-Fallback if Model Fails",
619
  value=True,
620
  info="Automatically try backup models"
621
  )
622
+
623
  system_prompt = gr.Textbox(
624
  label="System Prompt",
625
  placeholder="You are a helpful assistant...",
626
  lines=3,
627
  value="You are a helpful, creative AI assistant powered by Groq. Respond concisely but thoroughly."
628
  )
629
+
630
  with gr.Row():
631
  temperature = gr.Slider(0, 2, value=0.7, label="Temperature")
632
  max_tokens = gr.Slider(100, 8192, value=4096, label="Max Tokens")
633
+
634
  # Debug Modal
635
  with gr.Row(visible=False) as debug_row:
636
  with gr.Column():
637
  debug_output = gr.Code(label="Debug Request", language="python")
638
  close_debug = gr.Button("Close")
639
+
640
  # Export Modal
641
  with gr.Row(visible=False) as export_row:
642
  with gr.Column():
 
648
  gist_btn = gr.Button("πŸ“„ Create Gist")
649
  export_result = gr.Markdown()
650
  close_export = gr.Button("Close")
651
+
652
  # Event Handlers
653
  refresh_btn.click(
654
  refresh_models,
655
  [api_key_input],
656
  [model_dropdown]
657
  )
658
+
659
  send_event = msg_input.submit(
660
  process_chat,
661
  [msg_input, chatbot, model_dropdown, temperature, max_tokens, system_prompt, api_key_input, auto_fallback],
662
  [chatbot, msg_input, status_text]
663
  )
664
+
665
  send_btn.click(
666
  process_chat,
667
  [msg_input, chatbot, model_dropdown, temperature, max_tokens, system_prompt, api_key_input, auto_fallback],
668
  [chatbot, msg_input, status_text]
669
  )
670
+
671
  clear_btn.click(clear_chat, outputs=[chatbot, state_history, status_text])
672
+
673
  debug_btn.click(
674
  debug_request,
675
  [msg_input, chatbot, model_dropdown, temperature, max_tokens, system_prompt, api_key_input],
676
  [debug_output]
677
  ).then(lambda: gr.update(visible=True), outputs=[debug_row])
678
+
679
  close_debug.click(lambda: gr.update(visible=False), outputs=[debug_row])
680
+
681
  export_btn.click(lambda: gr.update(visible=True), outputs=[export_row])
682
  close_export.click(lambda: gr.update(visible=False), outputs=[export_row])
683
+
684
  commit_btn.click(
685
  export_to_github,
686
  [state_history, export_filename, export_message, github_token_input, github_repo_input],
687
  [export_result]
688
  )
689
+
690
  gist_btn.click(
691
  create_gist_export,
692
  [state_history, export_message, github_token_input],
693
  [export_result]
694
  )
695
+
696
  # Footer
697
  gr.HTML("""
698
  <div style="text-align: center; padding: 20px; color: #666; font-size: 12px;">
 
700
  <a href="https://console.groq.com" target="_blank" style="color: #4ecdc4;">Get API Key</a></p>
701
  </div>
702
  """)
703
+
704
  return demo
705
 
706
  # Launch
707
  if __name__ == "__main__":
708
  demo = create_interface()
709
+ # FIX: Moved CSS to launch() method
710
+ demo.launch(server_name="0.0.0.0", server_port=7860, css=CUSTOM_CSS)