shukdevdatta123 commited on
Commit
da5f4ec
·
verified ·
1 Parent(s): bc2b13d

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +594 -235
app.py CHANGED
@@ -4,6 +4,7 @@ from groq import Groq
4
  import json
5
  from datetime import datetime
6
  import time
 
7
 
8
  class RealTimeFactChecker:
9
  def __init__(self):
@@ -14,9 +15,9 @@ class RealTimeFactChecker:
14
  """Initialize Groq client with API key"""
15
  try:
16
  self.client = Groq(api_key=api_key)
17
- return True, "<div class='status success'>✅ API Key validated successfully!</div>"
18
  except Exception as e:
19
- return False, f"<div class='status error'>❌ Error initializing client: {str(e)}</div>"
20
 
21
  def get_system_prompt(self):
22
  """Get the system prompt for consistent behavior"""
@@ -38,7 +39,7 @@ WHEN TO SEARCH:
38
  - Weather conditions or forecasts
39
  - Recent scientific discoveries or research
40
  - Current political developments
41
- - Real-time statics or data
42
  - Verification of recent claims or rumors
43
  RESPONSE FORMAT:
44
  - Lead with key facts
@@ -51,11 +52,12 @@ Remember: Your goal is to be the most reliable, up-to-date source of information
51
  def query_compound_model(self, query, model, temperature=0.7, custom_system_prompt=None):
52
  """Query the compound model and return response with tool execution info"""
53
  if not self.client:
54
- return "<div class='status error'>❌ Please set a valid API key first.</div>", None, None
55
 
56
  try:
57
  start_time = time.time()
58
 
 
59
  system_prompt = custom_system_prompt if custom_system_prompt else self.get_system_prompt()
60
 
61
  chat_completion = self.client.chat.completions.create(
@@ -77,25 +79,47 @@ Remember: Your goal is to be the most reliable, up-to-date source of information
77
  end_time = time.time()
78
  response_time = round(end_time - start_time, 2)
79
 
 
80
  response_content = chat_completion.choices[0].message.content
81
 
 
82
  executed_tools = getattr(chat_completion.choices[0].message, 'executed_tools', None)
83
 
 
84
  tool_info = self.format_tool_info(executed_tools)
85
 
86
  return response_content, tool_info, response_time
87
 
88
  except Exception as e:
89
- return f"<div class='status error'>❌ Error querying model: {str(e)}</div>", None, None
90
 
91
  def format_tool_info(self, executed_tools):
92
  """Format executed tools information for display"""
93
  if not executed_tools:
94
- return "<div class='tool-info'><strong>Tools Used:</strong> None (Used existing knowledge)</div>"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
95
 
96
- tool_info = "<div class='tool-info'><strong>Tools Used:</strong><ul>"
97
  for i, tool in enumerate(executed_tools, 1):
98
  try:
 
99
  if hasattr(tool, 'name'):
100
  tool_name = tool.name
101
  elif hasattr(tool, 'tool_name'):
@@ -105,64 +129,113 @@ Remember: Your goal is to be the most reliable, up-to-date source of information
105
  else:
106
  tool_name = str(tool)
107
 
108
- tool_info += f"<li>{i}. <strong>{tool_name}</strong>"
 
 
 
109
 
 
110
  if hasattr(tool, 'parameters'):
111
  params = tool.parameters
112
  if isinstance(params, dict):
113
- tool_info += "<ul>"
114
  for key, value in params.items():
115
- tool_info += f"<li>{key}: {value}</li>"
116
- tool_info += "</ul>"
117
  elif hasattr(tool, 'input'):
118
- tool_info += f"<ul><li>Input: {tool.input}</li></ul>"
119
- tool_info += "</li>"
 
120
 
121
  except Exception as e:
122
- tool_info += f"<li>{i}. <strong>Tool {i}</strong> (Error parsing details)</li>"
123
 
124
- tool_info += "</ul></div>"
125
- return tool_info
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
126
 
127
  def get_example_queries(self):
128
  """Return categorized example queries"""
129
  return {
130
- "Latest News": [
131
  "What are the top 3 news stories today?",
132
  "Latest developments in AI technology this week",
133
  "Recent political events in the United States",
134
  "Breaking news about climate change",
135
  "What happened in the stock market today?"
136
  ],
137
- "Financial Data": [
138
  "Current price of Bitcoin",
139
  "Tesla stock price today",
140
  "How is the S&P 500 performing today?",
141
  "Latest cryptocurrency market trends",
142
  "What's the current inflation rate?"
143
  ],
144
- "Weather Updates": [
145
  "Current weather in New York City",
146
  "Weather forecast for London this week",
147
  "Is it going to rain in San Francisco today?",
148
  "Temperature in Tokyo right now",
149
  "Weather conditions in Sydney"
150
  ],
151
- "Science & Technology": [
152
  "Latest breakthroughs in fusion energy",
153
  "Recent discoveries in space exploration",
154
  "New developments in quantum computing",
155
  "Latest medical research findings",
156
  "Recent advances in renewable energy"
157
  ],
158
- "Sports & Entertainment": [
159
  "Latest football match results",
160
  "Who won the recent tennis tournament?",
161
  "Box office numbers for this weekend",
162
  "Latest movie releases this month",
163
  "Recent celebrity news"
164
  ],
165
- "Fact Checking": [
166
  "Is it true that the Earth's population reached 8 billion?",
167
  "Verify: Did company X announce layoffs recently?",
168
  "Check if the recent earthquake in Turkey was magnitude 7+",
@@ -174,215 +247,429 @@ Remember: Your goal is to be the most reliable, up-to-date source of information
174
  def get_custom_prompt_examples(self):
175
  """Return custom system prompt examples"""
176
  return {
177
- "Fact-Checker": "You are a fact-checker. Always verify claims with multiple sources and clearly indicate confidence levels in your assessments. Use phrases like 'highly confident', 'moderately confident', or 'requires verification' when presenting information.",
178
- "News Analyst": "You are a news analyst. Focus on providing balanced, unbiased reporting with multiple perspectives on current events. Always present different viewpoints and avoid partisan language.",
179
- "Financial Advisor": "You are a financial advisor. Provide accurate market data with context about trends and implications for investors. Always include disclaimers about market risks and the importance of professional financial advice.",
180
- "Research Assistant": "You are a research assistant specializing in scientific and technical information. Provide detailed, evidence-based responses with proper context about methodology and limitations of studies.",
181
- "Global News Correspondent": "You are a global news correspondent. Focus on international events and their interconnections. Provide cultural context and explain how events in one region might affect others.",
182
- "Market Analyst": "You are a market analyst. Provide detailed financial analysis including technical indicators, market sentiment, and economic factors affecting price movements."
 
 
 
 
 
183
  }
184
 
185
  def create_interface():
186
  fact_checker = RealTimeFactChecker()
187
 
 
188
  custom_css = """
189
- <style>
 
 
 
 
 
 
 
 
 
 
 
 
 
190
  .gradio-container {
191
- max-width: 1200px;
192
  margin: 0 auto;
193
- background: #f5f7fa;
194
- font-family: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif;
195
  padding: 20px;
 
196
  }
197
 
198
- .header {
199
- background: #ffffff;
 
 
200
  padding: 2rem;
201
- border-radius: 12px;
202
- text-align: center;
203
- box-shadow: 0 2px 8px rgba(0,0,0,0.05);
204
  margin-bottom: 2rem;
 
 
205
  }
206
 
207
- .header h1 {
208
- font-size: 2rem;
209
- color: #1a202c;
210
- margin: 0;
211
  }
212
 
213
- .header p {
214
- font-size: 1rem;
215
- color: #4a5568;
216
- margin: 0.5rem 0 0;
217
  }
218
 
 
219
  .card {
220
- background: #ffffff;
221
  border-radius: 12px;
222
  padding: 1.5rem;
223
  margin-bottom: 1.5rem;
224
- box-shadow: 0 2px 8px rgba(0,0,0,0.05);
225
  border: 1px solid #e2e8f0;
226
  }
227
 
228
  .card h3 {
 
229
  font-size: 1.25rem;
230
- color: #2d3748;
231
- margin: 0 0 1rem;
 
 
 
232
  }
233
 
234
- .status.success {
235
- background: #e6fffa;
236
- color: #2b6cb0;
237
- padding: 0.75rem;
 
238
  border-radius: 8px;
239
- border-left: 4px solid #2b6cb0;
240
  }
241
 
242
- .status.error {
243
- background: #fff5f5;
244
- color: #c53030;
245
- padding: 0.75rem;
246
  border-radius: 8px;
247
- border-left: 4px solid #c53030;
248
  }
249
 
250
- .tool-info {
251
- background: #edf2f7;
252
- padding: 1rem;
 
253
  border-radius: 8px;
254
- margin: 1rem 0;
255
- color: #2d3748;
 
 
 
 
 
 
 
 
 
 
 
 
 
256
  }
257
 
258
- .tool-info ul {
 
 
 
 
 
 
 
 
 
 
 
259
  margin: 0.5rem 0;
260
- padding-left: 1.5rem;
 
261
  }
262
 
263
- .result-card {
264
- background: #ffffff;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
265
  border-radius: 12px;
 
 
 
 
 
 
 
266
  padding: 1.5rem;
267
- margin: 1.5rem 0;
268
- box-shadow: 0 2px 8px rgba(0,0,0,0.05);
269
  }
270
 
271
- .result-card h3 {
272
- font-size: 1.25rem;
273
- color: #2d3748;
274
- margin: 0 0 1rem;
 
275
  }
276
 
277
- .result-content {
278
- color: #4a5568;
279
- line-height: 1.6;
 
 
 
280
  }
281
 
282
- .performance {
283
- font-size: 0.9rem;
284
- color: #2b6cb0;
 
285
  margin-top: 1rem;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
286
  font-style: italic;
287
  }
288
 
289
- .example-grid {
290
- display: grid;
291
- grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
292
- gap: 1rem;
293
- margin-top: 1rem;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
294
  }
295
 
296
- .example-item {
297
- background: #edf2f7;
 
 
 
 
 
 
 
 
 
 
 
 
298
  padding: 1rem;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
299
  border-radius: 8px;
 
300
  cursor: pointer;
301
- transition: background 0.2s;
 
302
  }
303
 
304
- .example-item:hover {
305
  background: #e2e8f0;
306
  }
307
 
308
- .prompt-example {
309
- background: #e6fffa;
310
  padding: 1rem;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
311
  border-radius: 8px;
312
- margin: 0.5rem 0;
313
  cursor: pointer;
314
- transition: background 0.2s;
315
  }
316
 
317
- .prompt-example:hover {
318
- background: #b2f5ea;
319
  }
320
 
321
- .prompt-title {
322
- font-weight: 600;
323
- color: #2b6cb0;
324
- margin-bottom: 0.25rem;
 
 
 
 
 
325
  }
326
 
327
- .prompt-text {
328
- font-size: 0.9rem;
329
- color: #4a5568;
330
  }
331
 
 
332
  .footer {
333
- background: #2d3748;
334
- color: #e2e8f0;
335
  padding: 2rem;
336
  border-radius: 12px;
337
- text-align: center;
338
  margin-top: 2rem;
 
 
 
 
 
 
339
  }
340
 
341
  .footer a {
342
- color: #63b3ed;
343
  text-decoration: none;
344
  font-weight: 500;
345
  }
346
 
347
  .footer a:hover {
348
- color: #90cdf4;
349
  text-decoration: underline;
350
  }
351
 
352
- .gr-button-primary {
353
- background: #2b6cb0;
354
- color: #ffffff;
355
- border: none;
356
- padding: 0.75rem 1.5rem;
357
- border-radius: 8px;
358
- font-weight: 500;
359
  }
360
 
361
- .gr-button-secondary {
362
- background: #e2e8f0;
363
- color: #2d3748;
364
- border: none;
365
- padding: 0.5rem 1rem;
366
- border-radius: 8px;
367
- font-weight: 500;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
368
  }
369
- </style>
370
  """
371
 
372
  def validate_api_key(api_key):
373
  if not api_key or api_key.strip() == "":
374
- return "<div class='status error'>❌ Please enter a valid API key</div>", False
375
 
376
  success, message = fact_checker.initialize_client(api_key.strip())
377
  return message, success
378
 
379
  def process_query(query, model, temperature, api_key, system_prompt):
380
  if not api_key or api_key.strip() == "":
381
- return "<div class='status error'>❌ Please set your API key first</div>", "", ""
382
 
383
  if not query or query.strip() == "":
384
- return "<div class='status error'>❌ Please enter a query</div>", "", ""
385
 
 
386
  if not fact_checker.client:
387
  success, message = fact_checker.initialize_client(api_key.strip())
388
  if not success:
@@ -392,18 +679,10 @@ def create_interface():
392
  query.strip(), model, temperature, system_prompt.strip() if system_prompt else None
393
  )
394
 
395
- timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
396
- formatted_response = f"""
397
- <div class='result-content'>
398
- <h4>Query:</h4>
399
- <p>{query}</p>
400
- <h4>Response:</h4>
401
- <p>{response}</p>
402
- <p class='performance'>Generated at {timestamp} in {response_time}s</p>
403
- </div>
404
- """
405
 
406
- return formatted_response, tool_info or "", f"<div class='performance'>⚡ Response time: {response_time}s</div>"
407
 
408
  def reset_system_prompt():
409
  return fact_checker.get_system_prompt()
@@ -414,125 +693,183 @@ def create_interface():
414
  def load_custom_prompt(prompt_text):
415
  return prompt_text
416
 
417
- with gr.Blocks(title="Real-time Fact Checker", css=custom_css) as demo:
 
418
 
 
419
  gr.HTML("""
420
- <div class="header">
421
- <h1>🔍 Real-time Fact Checker</h1>
422
- <p>Instantly verify facts and get the latest news with Groq's Compound Models</p>
423
  </div>
424
  """)
425
 
426
  with gr.Row():
427
- with gr.Column(scale=3):
428
- with gr.Group():
429
- gr.HTML('<div class="card">')
430
- gr.Markdown("### API Configuration")
431
- api_key_input = gr.Textbox(
432
- label="Groq API Key",
433
- placeholder="Enter your Groq API key...",
434
- type="password",
435
- info="Obtain your free API key from https://console.groq.com/"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
436
  )
437
- api_status = gr.HTML(
438
- value="<div class='status error'>⚠️ Please enter your API key</div>"
 
 
 
 
 
439
  )
440
- validate_btn = gr.Button("Validate API Key", variant="secondary")
441
- gr.HTML('</div>')
442
 
443
- with gr.Group():
444
- gr.HTML('<div class="card">')
445
- gr.Markdown("### System Prompt")
446
- with gr.Accordion("Customize System Prompt", open=False):
447
- system_prompt_input = gr.Textbox(
448
- label="System Prompt",
449
- value=fact_checker.get_system_prompt(),
450
- lines=6,
451
- info="Customize the AI's behavior"
 
 
 
 
 
 
 
 
 
452
  )
453
- reset_prompt_btn = gr.Button("Reset to Default", variant="secondary")
454
-
455
- gr.Markdown("#### Prompt Examples")
456
- custom_prompts = fact_checker.get_custom_prompt_examples()
457
- for title, prompt in custom_prompts.items():
458
- gr.HTML(f"""
459
- <div class="prompt-example" onclick="document.getElementById('system_prompt_input').value = '{prompt}'">
460
- <div class="prompt-title">{title}</div>
461
- <div class="prompt-text">{prompt[:80]}...</div>
462
- </div>
463
- """)
464
- gr.HTML('</div>')
465
 
466
- with gr.Group():
467
- gr.HTML('<div class="card">')
468
- gr.Markdown("### Your Query")
469
- query_input = gr.Textbox(
470
- label="Ask a Question",
471
- placeholder="e.g., What's the latest news on AI developments?",
472
- lines=3
473
- )
474
- with gr.Row():
475
- model_choice = gr.Dropdown(
476
- choices=fact_checker.model_options,
477
- value="compound-beta",
478
- label="Model"
479
  )
480
- temperature = gr.Slider(
481
- minimum=0.0,
482
- maximum=1.0,
483
- value=0.7,
484
- step=0.1,
485
- label="Temperature"
 
486
  )
487
- submit_btn = gr.Button("🔍 Get Answer", variant="primary")
488
- clear_btn = gr.Button("Clear", variant="secondary")
489
- gr.HTML('</div>')
490
-
491
- with gr.Column(scale=2):
492
- with gr.Group():
493
- gr.HTML('<div class="card">')
494
- gr.Markdown("### Example Queries")
495
- examples = fact_checker.get_example_queries()
496
- with gr.Tabs():
497
- for category, queries in examples.items():
498
- with gr.Tab(category):
499
- for query in queries:
500
- gr.HTML(f'<div class="example-item" onclick="document.getElementById(\'query_input\').value = \'{query}\'">{query}</div>')
501
- gr.HTML('</div>')
 
 
 
 
 
 
 
 
 
 
 
 
 
 
502
 
503
- gr.HTML('<div class="result-card">')
504
- gr.Markdown("### Results")
505
  with gr.Row():
506
- with gr.Column(scale=3):
507
  response_output = gr.HTML(
508
- value="<div class='result-content'>Enter a query to see results...</div>"
509
  )
510
- with gr.Column(scale=2):
 
511
  tool_info_output = gr.HTML(
512
- value="<div class='tool-info'>Tool execution details will appear here...</div>"
513
  )
514
- performance_output = gr.HTML(
515
- value=""
 
 
 
516
  )
517
- gr.HTML('</div>')
518
-
519
- gr.HTML("""
520
- <div class="footer">
521
- <h3>Links</h3>
522
- <p>
523
- <a href="https://console.groq.com/" target="_blank">Groq Console</a> |
524
- <a href="https://console.groq.com/docs/quickstart" target="_blank">Documentation</a> |
525
- <a href="https://console.groq.com/docs/models" target="_blank">Models Info</a>
526
- </p>
527
- <h3>Tips</h3>
528
- <ul style="text-align: left; display: inline-block;">
529
- <li>Use compound-beta for detailed responses</li>
530
- <li>Adjust temperature for creative or factual responses</li>
531
- <li>Check tool execution info for source transparency</li>
532
- </ul>
533
- </div>
534
- """)
535
 
 
536
  validate_btn.click(
537
  fn=validate_api_key,
538
  inputs=[api_key_input],
@@ -551,12 +888,34 @@ def create_interface():
551
  )
552
 
553
  clear_btn.click(
554
- fn=lambda: ("", "<div class='result-content'>Enter a query to see results...</div>", "<div class='tool-info'>Tool execution details will appear here...</div>", ""),
555
  outputs=[query_input, response_output, tool_info_output, performance_output]
556
  )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
557
 
558
  return demo
559
 
 
560
  if __name__ == "__main__":
561
  demo = create_interface()
562
  demo.launch(
 
4
  import json
5
  from datetime import datetime
6
  import time
7
+ import re
8
 
9
  class RealTimeFactChecker:
10
  def __init__(self):
 
15
  """Initialize Groq client with API key"""
16
  try:
17
  self.client = Groq(api_key=api_key)
18
+ return True, " API Key validated successfully!"
19
  except Exception as e:
20
+ return False, f" Error initializing client: {str(e)}"
21
 
22
  def get_system_prompt(self):
23
  """Get the system prompt for consistent behavior"""
 
39
  - Weather conditions or forecasts
40
  - Recent scientific discoveries or research
41
  - Current political developments
42
+ - Real-time statistics or data
43
  - Verification of recent claims or rumors
44
  RESPONSE FORMAT:
45
  - Lead with key facts
 
52
  def query_compound_model(self, query, model, temperature=0.7, custom_system_prompt=None):
53
  """Query the compound model and return response with tool execution info"""
54
  if not self.client:
55
+ return " Please set a valid API key first.", None, None
56
 
57
  try:
58
  start_time = time.time()
59
 
60
+ # Use custom system prompt if provided
61
  system_prompt = custom_system_prompt if custom_system_prompt else self.get_system_prompt()
62
 
63
  chat_completion = self.client.chat.completions.create(
 
79
  end_time = time.time()
80
  response_time = round(end_time - start_time, 2)
81
 
82
+ # Extract response
83
  response_content = chat_completion.choices[0].message.content
84
 
85
+ # Check for executed tools
86
  executed_tools = getattr(chat_completion.choices[0].message, 'executed_tools', None)
87
 
88
+ # Format tool execution info
89
  tool_info = self.format_tool_info(executed_tools)
90
 
91
  return response_content, tool_info, response_time
92
 
93
  except Exception as e:
94
+ return f" Error querying model: {str(e)}", None, None
95
 
96
  def format_tool_info(self, executed_tools):
97
  """Format executed tools information for display"""
98
  if not executed_tools:
99
+ return """
100
+ <div class="tool-info-card">
101
+ <div class="tool-info-header">
102
+ <i class="icon">🧠</i>
103
+ <h3>Knowledge Source</h3>
104
+ </div>
105
+ <div class="tool-info-content">
106
+ <p>Response generated from existing knowledge base</p>
107
+ </div>
108
+ </div>
109
+ """
110
+
111
+ tool_html = """
112
+ <div class="tool-info-card">
113
+ <div class="tool-info-header">
114
+ <i class="icon">🔍</i>
115
+ <h3>Tools Executed</h3>
116
+ </div>
117
+ <div class="tool-info-content">
118
+ """
119
 
 
120
  for i, tool in enumerate(executed_tools, 1):
121
  try:
122
+ # Handle different tool object types
123
  if hasattr(tool, 'name'):
124
  tool_name = tool.name
125
  elif hasattr(tool, 'tool_name'):
 
129
  else:
130
  tool_name = str(tool)
131
 
132
+ tool_html += f"""
133
+ <div class="tool-item">
134
+ <div class="tool-name">{i}. {tool_name}</div>
135
+ """
136
 
137
+ # Add tool parameters if available
138
  if hasattr(tool, 'parameters'):
139
  params = tool.parameters
140
  if isinstance(params, dict):
 
141
  for key, value in params.items():
142
+ tool_html += f'<div class="tool-param">{key}: {value}</div>'
 
143
  elif hasattr(tool, 'input'):
144
+ tool_html += f'<div class="tool-param">Input: {tool.input}</div>'
145
+
146
+ tool_html += "</div>"
147
 
148
  except Exception as e:
149
+ tool_html += f'<div class="tool-item"><div class="tool-name">{i}. Tool {i}</div><div class="tool-param">Error parsing details</div></div>'
150
 
151
+ tool_html += """
152
+ </div>
153
+ </div>
154
+ """
155
+
156
+ return tool_html
157
+
158
+ def format_response(self, response_content, query, response_time):
159
+ """Format the response with proper HTML structure"""
160
+ # Convert markdown-like formatting to HTML
161
+ formatted_content = response_content
162
+
163
+ # Convert **bold** to <strong>
164
+ formatted_content = re.sub(r'\*\*(.*?)\*\*', r'<strong>\1</strong>', formatted_content)
165
+
166
+ # Convert *italic* to <em>
167
+ formatted_content = re.sub(r'\*(.*?)\*', r'<em>\1</em>', formatted_content)
168
+
169
+ # Convert newlines to <br> for better formatting
170
+ formatted_content = formatted_content.replace('\n', '<br>')
171
+
172
+ # Convert numbered lists
173
+ formatted_content = re.sub(r'^(\d+\.\s)', r'<br><strong>\1</strong>', formatted_content, flags=re.MULTILINE)
174
+
175
+ timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
176
+
177
+ html_response = f"""
178
+ <div class="response-card">
179
+ <div class="response-header">
180
+ <div class="query-section">
181
+ <h3>📝 Query</h3>
182
+ <p class="query-text">{query}</p>
183
+ </div>
184
+ <div class="meta-info">
185
+ <span class="timestamp">🕐 {timestamp}</span>
186
+ <span class="response-time">⚡ {response_time}s</span>
187
+ </div>
188
+ </div>
189
+ <div class="response-content">
190
+ <h3>💬 Response</h3>
191
+ <div class="response-text">
192
+ {formatted_content}
193
+ </div>
194
+ </div>
195
+ </div>
196
+ """
197
+
198
+ return html_response
199
 
200
  def get_example_queries(self):
201
  """Return categorized example queries"""
202
  return {
203
+ "📰 Latest News": [
204
  "What are the top 3 news stories today?",
205
  "Latest developments in AI technology this week",
206
  "Recent political events in the United States",
207
  "Breaking news about climate change",
208
  "What happened in the stock market today?"
209
  ],
210
+ "💰 Financial Data": [
211
  "Current price of Bitcoin",
212
  "Tesla stock price today",
213
  "How is the S&P 500 performing today?",
214
  "Latest cryptocurrency market trends",
215
  "What's the current inflation rate?"
216
  ],
217
+ "🌤️ Weather Updates": [
218
  "Current weather in New York City",
219
  "Weather forecast for London this week",
220
  "Is it going to rain in San Francisco today?",
221
  "Temperature in Tokyo right now",
222
  "Weather conditions in Sydney"
223
  ],
224
+ "🔬 Science & Technology": [
225
  "Latest breakthroughs in fusion energy",
226
  "Recent discoveries in space exploration",
227
  "New developments in quantum computing",
228
  "Latest medical research findings",
229
  "Recent advances in renewable energy"
230
  ],
231
+ "🏆 Sports & Entertainment": [
232
  "Latest football match results",
233
  "Who won the recent tennis tournament?",
234
  "Box office numbers for this weekend",
235
  "Latest movie releases this month",
236
  "Recent celebrity news"
237
  ],
238
+ "🔍 Fact Checking": [
239
  "Is it true that the Earth's population reached 8 billion?",
240
  "Verify: Did company X announce layoffs recently?",
241
  "Check if the recent earthquake in Turkey was magnitude 7+",
 
247
  def get_custom_prompt_examples(self):
248
  """Return custom system prompt examples"""
249
  return {
250
+ "🎯 Fact-Checker": "You are a fact-checker. Always verify claims with multiple sources and clearly indicate confidence levels in your assessments. Use phrases like 'highly confident', 'moderately confident', or 'requires verification' when presenting information.",
251
+
252
+ "📊 News Analyst": "You are a news analyst. Focus on providing balanced, unbiased reporting with multiple perspectives on current events. Always present different viewpoints and avoid partisan language.",
253
+
254
+ "💼 Financial Advisor": "You are a financial advisor. Provide accurate market data with context about trends and implications for investors. Always include disclaimers about market risks and the importance of professional financial advice.",
255
+
256
+ "🔬 Research Assistant": "You are a research assistant specializing in scientific and technical information. Provide detailed, evidence-based responses with proper context about methodology and limitations of studies.",
257
+
258
+ "🌍 Global News Correspondent": "You are a global news correspondent. Focus on international events and their interconnections. Provide cultural context and explain how events in one region might affect others.",
259
+
260
+ "📈 Market Analyst": "You are a market analyst. Provide detailed financial analysis including technical indicators, market sentiment, and economic factors affecting price movements."
261
  }
262
 
263
  def create_interface():
264
  fact_checker = RealTimeFactChecker()
265
 
266
+ # Modern CSS design
267
  custom_css = """
268
+ /* Reset and base styles */
269
+ * {
270
+ margin: 0;
271
+ padding: 0;
272
+ box-sizing: border-box;
273
+ }
274
+
275
+ body {
276
+ font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
277
+ background: #f8fafc;
278
+ color: #334155;
279
+ line-height: 1.6;
280
+ }
281
+
282
  .gradio-container {
283
+ max-width: 1200px !important;
284
  margin: 0 auto;
 
 
285
  padding: 20px;
286
+ background: #f8fafc;
287
  }
288
 
289
+ /* Header */
290
+ .app-header {
291
+ background: linear-gradient(135deg, #3b82f6 0%, #1e40af 100%);
292
+ color: white;
293
  padding: 2rem;
294
+ border-radius: 16px;
 
 
295
  margin-bottom: 2rem;
296
+ text-align: center;
297
+ box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1);
298
  }
299
 
300
+ .app-header h1 {
301
+ font-size: 2.5rem;
302
+ font-weight: 700;
303
+ margin-bottom: 0.5rem;
304
  }
305
 
306
+ .app-header p {
307
+ font-size: 1.1rem;
308
+ opacity: 0.9;
309
+ font-weight: 400;
310
  }
311
 
312
+ /* Cards */
313
  .card {
314
+ background: white;
315
  border-radius: 12px;
316
  padding: 1.5rem;
317
  margin-bottom: 1.5rem;
318
+ box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.1);
319
  border: 1px solid #e2e8f0;
320
  }
321
 
322
  .card h3 {
323
+ color: #1e293b;
324
  font-size: 1.25rem;
325
+ font-weight: 600;
326
+ margin-bottom: 1rem;
327
+ display: flex;
328
+ align-items: center;
329
+ gap: 0.5rem;
330
  }
331
 
332
+ /* Status indicators */
333
+ .status-success {
334
+ background: #10b981;
335
+ color: white;
336
+ padding: 0.75rem 1rem;
337
  border-radius: 8px;
338
+ font-weight: 500;
339
  }
340
 
341
+ .status-warning {
342
+ background: #f59e0b;
343
+ color: white;
344
+ padding: 0.75rem 1rem;
345
  border-radius: 8px;
346
+ font-weight: 500;
347
  }
348
 
349
+ .status-error {
350
+ background: #ef4444;
351
+ color: white;
352
+ padding: 0.75rem 1rem;
353
  border-radius: 8px;
354
+ font-weight: 500;
355
+ }
356
+
357
+ /* Example buttons */
358
+ .example-btn {
359
+ background: #f1f5f9;
360
+ border: 1px solid #e2e8f0;
361
+ color: #475569;
362
+ padding: 0.75rem 1rem;
363
+ border-radius: 8px;
364
+ cursor: pointer;
365
+ transition: all 0.2s ease;
366
+ margin: 0.25rem;
367
+ font-size: 0.875rem;
368
+ text-align: left;
369
  }
370
 
371
+ .example-btn:hover {
372
+ background: #e2e8f0;
373
+ border-color: #3b82f6;
374
+ color: #1e40af;
375
+ }
376
+
377
+ /* Custom prompt examples */
378
+ .prompt-example {
379
+ background: #f8fafc;
380
+ border: 1px solid #e2e8f0;
381
+ border-radius: 8px;
382
+ padding: 1rem;
383
  margin: 0.5rem 0;
384
+ cursor: pointer;
385
+ transition: all 0.2s ease;
386
  }
387
 
388
+ .prompt-example:hover {
389
+ background: #e2e8f0;
390
+ border-color: #3b82f6;
391
+ }
392
+
393
+ .prompt-example-title {
394
+ font-weight: 600;
395
+ color: #1e40af;
396
+ margin-bottom: 0.5rem;
397
+ }
398
+
399
+ .prompt-example-text {
400
+ font-size: 0.875rem;
401
+ color: #64748b;
402
+ line-height: 1.4;
403
+ }
404
+
405
+ /* Response card */
406
+ .response-card {
407
+ background: white;
408
  border-radius: 12px;
409
+ border: 1px solid #e2e8f0;
410
+ overflow: hidden;
411
+ box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.1);
412
+ }
413
+
414
+ .response-header {
415
+ background: #f8fafc;
416
  padding: 1.5rem;
417
+ border-bottom: 1px solid #e2e8f0;
 
418
  }
419
 
420
+ .query-section h3 {
421
+ color: #1e293b;
422
+ font-size: 1.1rem;
423
+ font-weight: 600;
424
+ margin-bottom: 0.5rem;
425
  }
426
 
427
+ .query-text {
428
+ background: #e2e8f0;
429
+ padding: 1rem;
430
+ border-radius: 8px;
431
+ font-style: italic;
432
+ color: #475569;
433
  }
434
 
435
+ .meta-info {
436
+ display: flex;
437
+ justify-content: space-between;
438
+ align-items: center;
439
  margin-top: 1rem;
440
+ font-size: 0.875rem;
441
+ color: #64748b;
442
+ }
443
+
444
+ .timestamp, .response-time {
445
+ background: #f1f5f9;
446
+ padding: 0.5rem 0.75rem;
447
+ border-radius: 6px;
448
+ font-weight: 500;
449
+ }
450
+
451
+ .response-content {
452
+ padding: 1.5rem;
453
+ }
454
+
455
+ .response-content h3 {
456
+ color: #1e293b;
457
+ font-size: 1.1rem;
458
+ font-weight: 600;
459
+ margin-bottom: 1rem;
460
+ }
461
+
462
+ .response-text {
463
+ color: #374151;
464
+ line-height: 1.7;
465
+ font-size: 0.95rem;
466
+ }
467
+
468
+ .response-text strong {
469
+ color: #1e293b;
470
+ font-weight: 600;
471
+ }
472
+
473
+ .response-text em {
474
+ color: #6366f1;
475
  font-style: italic;
476
  }
477
 
478
+ /* Tool info card */
479
+ .tool-info-card {
480
+ background: white;
481
+ border-radius: 12px;
482
+ border: 1px solid #e2e8f0;
483
+ overflow: hidden;
484
+ box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.1);
485
+ }
486
+
487
+ .tool-info-header {
488
+ background: #f0f9ff;
489
+ padding: 1rem 1.5rem;
490
+ border-bottom: 1px solid #e2e8f0;
491
+ display: flex;
492
+ align-items: center;
493
+ gap: 0.75rem;
494
+ }
495
+
496
+ .tool-info-header .icon {
497
+ font-size: 1.5rem;
498
  }
499
 
500
+ .tool-info-header h3 {
501
+ color: #1e40af;
502
+ font-size: 1.1rem;
503
+ font-weight: 600;
504
+ margin: 0;
505
+ }
506
+
507
+ .tool-info-content {
508
+ padding: 1.5rem;
509
+ }
510
+
511
+ .tool-item {
512
+ background: #f8fafc;
513
+ border-radius: 8px;
514
  padding: 1rem;
515
+ margin-bottom: 0.75rem;
516
+ border: 1px solid #e2e8f0;
517
+ }
518
+
519
+ .tool-item:last-child {
520
+ margin-bottom: 0;
521
+ }
522
+
523
+ .tool-name {
524
+ font-weight: 600;
525
+ color: #1e293b;
526
+ margin-bottom: 0.5rem;
527
+ }
528
+
529
+ .tool-param {
530
+ font-size: 0.875rem;
531
+ color: #64748b;
532
+ margin-left: 1rem;
533
+ }
534
+
535
+ /* Accordion styles */
536
+ .accordion-header {
537
+ background: #f8fafc;
538
+ border: 1px solid #e2e8f0;
539
  border-radius: 8px;
540
+ padding: 1rem;
541
  cursor: pointer;
542
+ transition: all 0.2s ease;
543
+ margin-bottom: 0.5rem;
544
  }
545
 
546
+ .accordion-header:hover {
547
  background: #e2e8f0;
548
  }
549
 
550
+ .accordion-content {
 
551
  padding: 1rem;
552
+ border: 1px solid #e2e8f0;
553
+ border-top: none;
554
+ border-radius: 0 0 8px 8px;
555
+ background: white;
556
+ }
557
+
558
+ /* Performance badge */
559
+ .performance-badge {
560
+ background: #10b981;
561
+ color: white;
562
+ padding: 0.5rem 1rem;
563
+ border-radius: 20px;
564
+ font-size: 0.875rem;
565
+ font-weight: 500;
566
+ display: inline-block;
567
+ }
568
+
569
+ /* Buttons */
570
+ .btn-primary {
571
+ background: #3b82f6;
572
+ color: white;
573
+ border: none;
574
+ padding: 0.75rem 1.5rem;
575
  border-radius: 8px;
576
+ font-weight: 500;
577
  cursor: pointer;
578
+ transition: all 0.2s ease;
579
  }
580
 
581
+ .btn-primary:hover {
582
+ background: #2563eb;
583
  }
584
 
585
+ .btn-secondary {
586
+ background: #f1f5f9;
587
+ color: #475569;
588
+ border: 1px solid #e2e8f0;
589
+ padding: 0.75rem 1.5rem;
590
+ border-radius: 8px;
591
+ font-weight: 500;
592
+ cursor: pointer;
593
+ transition: all 0.2s ease;
594
  }
595
 
596
+ .btn-secondary:hover {
597
+ background: #e2e8f0;
598
+ border-color: #3b82f6;
599
  }
600
 
601
+ /* Footer */
602
  .footer {
603
+ background: #1e293b;
604
+ color: white;
605
  padding: 2rem;
606
  border-radius: 12px;
 
607
  margin-top: 2rem;
608
+ text-align: center;
609
+ }
610
+
611
+ .footer h3 {
612
+ color: white;
613
+ margin-bottom: 1rem;
614
  }
615
 
616
  .footer a {
617
+ color: #60a5fa;
618
  text-decoration: none;
619
  font-weight: 500;
620
  }
621
 
622
  .footer a:hover {
623
+ color: #93c5fd;
624
  text-decoration: underline;
625
  }
626
 
627
+ .footer ul {
628
+ list-style: none;
629
+ padding: 0;
630
+ margin: 1rem 0;
 
 
 
631
  }
632
 
633
+ .footer ul li {
634
+ margin: 0.5rem 0;
635
+ }
636
+
637
+ /* Responsive design */
638
+ @media (max-width: 768px) {
639
+ .gradio-container {
640
+ padding: 1rem;
641
+ }
642
+
643
+ .app-header h1 {
644
+ font-size: 2rem;
645
+ }
646
+
647
+ .card {
648
+ padding: 1rem;
649
+ }
650
+
651
+ .meta-info {
652
+ flex-direction: column;
653
+ gap: 0.5rem;
654
+ }
655
  }
 
656
  """
657
 
658
  def validate_api_key(api_key):
659
  if not api_key or api_key.strip() == "":
660
+ return " Please enter a valid API key", False
661
 
662
  success, message = fact_checker.initialize_client(api_key.strip())
663
  return message, success
664
 
665
  def process_query(query, model, temperature, api_key, system_prompt):
666
  if not api_key or api_key.strip() == "":
667
+ return " Please set your API key first", "", ""
668
 
669
  if not query or query.strip() == "":
670
+ return " Please enter a query", "", ""
671
 
672
+ # Initialize client if not already done
673
  if not fact_checker.client:
674
  success, message = fact_checker.initialize_client(api_key.strip())
675
  if not success:
 
679
  query.strip(), model, temperature, system_prompt.strip() if system_prompt else None
680
  )
681
 
682
+ # Format response with HTML
683
+ formatted_response = fact_checker.format_response(response, query, response_time)
 
 
 
 
 
 
 
 
684
 
685
+ return formatted_response, tool_info or "", f" Response time: {response_time}s"
686
 
687
  def reset_system_prompt():
688
  return fact_checker.get_system_prompt()
 
693
  def load_custom_prompt(prompt_text):
694
  return prompt_text
695
 
696
+ # Create the Gradio interface
697
+ with gr.Blocks(title="Real-time Fact Checker & News Agent", css=custom_css) as demo:
698
 
699
+ # Header
700
  gr.HTML("""
701
+ <div class="app-header">
702
+ <h1>🔍 Real-time Fact Checker & News Agent</h1>
703
+ <p>Powered by Groq's Compound Models with Built-in Web Search</p>
704
  </div>
705
  """)
706
 
707
  with gr.Row():
708
+ with gr.Column(scale=2):
709
+ # API Key section
710
+ gr.HTML('<div class="card">')
711
+ gr.HTML('<h3>🔑 API Configuration</h3>')
712
+ api_key_input = gr.Textbox(
713
+ label="Groq API Key",
714
+ placeholder="Enter your Groq API key here...",
715
+ type="password",
716
+ info="Get your free API key from https://console.groq.com/"
717
+ )
718
+ api_status = gr.Textbox(
719
+ label="Status",
720
+ value="⚠️ Please enter your API key",
721
+ interactive=False
722
+ )
723
+ validate_btn = gr.Button("Validate API Key", variant="secondary")
724
+ gr.HTML('</div>')
725
+
726
+ # Advanced options
727
+ gr.HTML('<div class="card">')
728
+ gr.HTML('<h3>⚙️ Advanced Options</h3>')
729
+
730
+ # Custom System Prompt Examples
731
+ with gr.Accordion("📝 System Prompt Examples", open=False):
732
+ gr.Markdown("**Click any example to load it as your system prompt:**")
733
+
734
+ custom_prompts = fact_checker.get_custom_prompt_examples()
735
+ for title, prompt in custom_prompts.items():
736
+ with gr.Row():
737
+ prompt_btn = gr.Button(title, variant="secondary", size="sm")
738
+ prompt_btn.click(
739
+ fn=lambda p=prompt: p,
740
+ outputs=[gr.Textbox(elem_id="system_prompt_input")]
741
+ )
742
+
743
+ with gr.Accordion("🔧 System Prompt Customization", open=False):
744
+ system_prompt_input = gr.Textbox(
745
+ label="System Prompt",
746
+ value=fact_checker.get_system_prompt(),
747
+ lines=8,
748
+ info="Customize how the AI behaves and responds",
749
+ elem_id="system_prompt_input"
750
+ )
751
+ reset_prompt_btn = gr.Button("Reset to Default", variant="secondary", size="sm")
752
+
753
+ # Add buttons for each custom prompt
754
+ gr.Markdown("**Quick Load Custom Prompts:**")
755
+ custom_prompts = fact_checker.get_custom_prompt_examples()
756
+ for title, prompt in custom_prompts.items():
757
+ prompt_btn = gr.Button(title, variant="secondary", size="sm")
758
+ prompt_btn.click(
759
+ fn=lambda p=prompt: p,
760
+ outputs=[system_prompt_input]
761
+ )
762
+
763
+ gr.HTML('</div>')
764
+
765
+ # Query section
766
+ gr.HTML('<div class="card">')
767
+ gr.HTML('<h3>💭 Your Query</h3>')
768
+ query_input = gr.Textbox(
769
+ label="Ask anything that requires real-time information",
770
+ placeholder="e.g., What are the latest AI developments today?",
771
+ lines=4
772
+ )
773
+
774
+ with gr.Row():
775
+ model_choice = gr.Dropdown(
776
+ choices=fact_checker.model_options,
777
+ value="compound-beta",
778
+ label="Model",
779
+ info="compound-beta: More capable | compound-beta-mini: Faster"
780
  )
781
+ temperature = gr.Slider(
782
+ minimum=0.0,
783
+ maximum=1.0,
784
+ value=0.7,
785
+ step=0.1,
786
+ label="Temperature",
787
+ info="Higher = more creative, Lower = more focused"
788
  )
 
 
789
 
790
+ submit_btn = gr.Button("🔍 Get Real-time Information", variant="primary", size="lg")
791
+ clear_btn = gr.Button("Clear", variant="secondary")
792
+ gr.HTML('</div>')
793
+
794
+ with gr.Column(scale=1):
795
+ # Example queries
796
+ gr.HTML('<div class="card">')
797
+ gr.HTML('<h3>📝 Example Queries</h3>')
798
+ gr.Markdown("Click any example to load it:")
799
+
800
+ examples = fact_checker.get_example_queries()
801
+
802
+ with gr.Accordion("📰 Latest News", open=True):
803
+ for query in examples["📰 Latest News"]:
804
+ example_btn = gr.Button(query, variant="secondary", size="sm")
805
+ example_btn.click(
806
+ fn=lambda q=query: q,
807
+ outputs=[query_input]
808
  )
 
 
 
 
 
 
 
 
 
 
 
 
809
 
810
+ with gr.Accordion("💰 Financial Data", open=False):
811
+ for query in examples["💰 Financial Data"]:
812
+ example_btn = gr.Button(query, variant="secondary", size="sm")
813
+ example_btn.click(
814
+ fn=lambda q=query: q,
815
+ outputs=[query_input]
 
 
 
 
 
 
 
816
  )
817
+
818
+ with gr.Accordion("🌤️ Weather Updates", open=False):
819
+ for query in examples["🌤️ Weather Updates"]:
820
+ example_btn = gr.Button(query, variant="secondary", size="sm")
821
+ example_btn.click(
822
+ fn=lambda q=query: q,
823
+ outputs=[query_input]
824
  )
825
+
826
+ with gr.Accordion("🔬 Science & Technology", open=False):
827
+ for query in examples["🔬 Science & Technology"]:
828
+ example_btn = gr.Button(query, variant="secondary", size="sm")
829
+ example_btn.click(
830
+ fn=lambda q=query: q,
831
+ outputs=[query_input]
832
+ )
833
+
834
+ with gr.Accordion("🏆 Sports & Entertainment", open=False):
835
+ for query in examples["🏆 Sports & Entertainment"]:
836
+ example_btn = gr.Button(query, variant="secondary", size="sm")
837
+ example_btn.click(
838
+ fn=lambda q=query: q,
839
+ outputs=[query_input]
840
+ )
841
+
842
+ with gr.Accordion("🔍 Fact Checking", open=False):
843
+ for query in examples["🔍 Fact Checking"]:
844
+ example_btn = gr.Button(query, variant="secondary", size="sm")
845
+ example_btn.click(
846
+ fn=lambda q=query: q,
847
+ outputs=[query_input]
848
+ )
849
+
850
+ gr.HTML('</div>')
851
+
852
+ # Results section
853
+ gr.HTML('<h3 style="margin: 2rem 0 1rem 0; color: #1e293b; font-size: 1.5rem;">📊 Results</h3>')
854
 
 
 
855
  with gr.Row():
856
+ with gr.Column(scale=2):
857
  response_output = gr.HTML(
858
+ value="<div style='padding: 2rem; text-align: center; color: #64748b; font-style: italic;'>Your response will appear here...</div>"
859
  )
860
+
861
+ with gr.Column(scale=1):
862
  tool_info_output = gr.HTML(
863
+ value="<div style='padding: 2rem; text-align: center; color: #64748b; font-style: italic;'>Tool execution details will appear here...</div>"
864
  )
865
+
866
+ performance_output = gr.Textbox(
867
+ label="Performance",
868
+ value="",
869
+ interactive=False
870
  )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
871
 
872
+ # Event handlers
873
  validate_btn.click(
874
  fn=validate_api_key,
875
  inputs=[api_key_input],
 
888
  )
889
 
890
  clear_btn.click(
891
+ fn=lambda: ("", "<div style='padding: 2rem; text-align: center; color: #64748b; font-style: italic;'>Your response will appear here...</div>", "<div style='padding: 2rem; text-align: center; color: #64748b; font-style: italic;'>Tool execution details will appear here...</div>", ""),
892
  outputs=[query_input, response_output, tool_info_output, performance_output]
893
  )
894
+
895
+ # Footer
896
+ gr.HTML("""
897
+ <div class="footer">
898
+ <h3>🔗 Useful Links</h3>
899
+ <p>
900
+ <a href="https://console.groq.com/" target="_blank">Groq Console</a> - Get your free API key<br>
901
+ <a href="https://console.groq.com/docs/quickstart" target="_blank">Groq Documentation</a> - Learn more about Groq models<br>
902
+ <a href="https://console.groq.com/docs/models" target="_blank">Compound Models Info</a> - Details about compound models
903
+ </p>
904
+
905
+ <h3>💡 Tips</h3>
906
+ <ul>
907
+ <li>The compound models automatically use web search when real-time information is needed</li>
908
+ <li>Try different temperature settings: 0.1 for factual queries, 0.7-0.9 for creative questions</li>
909
+ <li>compound-beta is more capable but slower, compound-beta-mini is faster but less capable</li>
910
+ <li>Use custom system prompts to specialize the AI for different types of queries</li>
911
+ <li>Check the Tool Execution Info to see when web search was used</li>
912
+ </ul>
913
+ </div>
914
+ """)
915
 
916
  return demo
917
 
918
+ # Launch the application
919
  if __name__ == "__main__":
920
  demo = create_interface()
921
  demo.launch(