AiActivity commited on
Commit
6a5bbc8
·
verified ·
1 Parent(s): 2c0c571

fix more efficent

Browse files
Files changed (1) hide show
  1. app.py +255 -383
app.py CHANGED
@@ -13,15 +13,11 @@ from markdown import markdown
13
  # Set environment variables
14
  os.environ["TOKENIZERS_PARALLELISM"] = "false"
15
 
16
- # Global variable to track model loading success
17
- MODEL_LOADED = False
18
- MODEL_TYPE = "none"
19
-
20
  print("Loading model... Please wait...")
21
 
22
- # Try to load the models with better error handling
23
  try:
24
- # First try with Phi-2
25
  MODEL_ID = "microsoft/phi-2"
26
 
27
  tokenizer = AutoTokenizer.from_pretrained(
@@ -36,8 +32,6 @@ try:
36
  trust_remote_code=True
37
  )
38
 
39
- MODEL_LOADED = True
40
- MODEL_TYPE = "phi"
41
  print("Successfully loaded Phi-2 model")
42
  except Exception as e:
43
  print(f"Error loading Phi-2: {e}")
@@ -55,157 +49,20 @@ except Exception as e:
55
  device_map="auto"
56
  )
57
 
58
- MODEL_LOADED = True
59
- MODEL_TYPE = "t5"
60
  print("Successfully loaded fallback model")
61
  except Exception as e:
62
  print(f"Error loading fallback model: {e}")
63
- print("Will use hard-coded responses only")
64
-
65
- # Pre-written answers for common topics
66
- COMMON_ANSWERS = {
67
- "computer": """A computer is an electronic device that manipulates information, or data. It can store, retrieve, and process data [1]. Computers were originally designed to perform mathematical calculations, but they have evolved to handle a wide range of tasks including word processing, communication, multimedia playback, and more [2].
68
-
69
- Modern computers typically consist of several key components:
70
-
71
- - **Central Processing Unit (CPU)**: The "brain" of the computer that executes instructions
72
- - **Memory (RAM)**: Temporary storage used while running programs
73
- - **Storage Devices**: Permanent storage for data and programs (hard drives, SSDs)
74
- - **Input Devices**: Allow users to interact with the computer (keyboard, mouse)
75
- - **Output Devices**: Display or communicate information (monitor, speakers)
76
-
77
- Computers operate using binary code (0s and 1s) and follow instructions provided through software programs [3]. They can be categorized into different types including desktop computers, laptops, tablets, smartphones, servers, and supercomputers, each designed for specific use cases.
78
-
79
- The field of computer science involves the study of computers, their design, and their applications. As technology continues to advance, computers are becoming increasingly powerful, smaller, and more integrated into daily life.""",
80
-
81
- "artificial intelligence": """Artificial Intelligence (AI) refers to the simulation of human intelligence in machines that are programmed to think like humans and mimic their actions [1]. The term may also be applied to any machine that exhibits traits associated with a human mind such as learning and problem-solving.
82
-
83
- The core problems of artificial intelligence include programming computers for certain traits such as:
84
-
85
- - **Knowledge**: Having information and the ability to use it
86
- - **Reasoning**: Using knowledge to draw conclusions
87
- - **Problem solving**: Finding solutions to complex problems
88
- - **Perception**: Analyzing sensory inputs like visual, auditory, or textual information
89
- - **Learning**: Acquiring new knowledge and adapting to new situations
90
-
91
- AI can be categorized in different ways:
92
- - **Narrow AI (or Weak AI)**: Systems designed for a specific task
93
- - **General AI (or Strong AI)**: Systems with generalized human cognitive abilities
94
-
95
- Modern AI techniques include machine learning (particularly deep learning), which enables computers to learn from data without being explicitly programmed [2]. Applications of AI include virtual assistants, healthcare diagnostics, autonomous vehicles, facial recognition, recommendation systems, and much more [3].
96
-
97
- As AI technology continues to advance, it raises important ethical, social, and philosophical questions about the impact of these systems on society, privacy, employment, and the future of humanity.""",
98
 
99
- "quantum computing": """Quantum computing is a rapidly emerging technology that harnesses the laws of quantum mechanics to solve problems too complex for classical computers [1]. Unlike traditional computers that use bits (0s and 1s), quantum computers use quantum bits or "qubits" that can exist in multiple states simultaneously due to a property called superposition [2].
100
-
101
- Key concepts in quantum computing include:
102
-
103
- - **Superposition**: Qubits can represent multiple states at once, enabling parallel computation
104
- - **Entanglement**: Quantum particles become interconnected, with the state of one instantly influencing the other
105
- - **Quantum Interference**: Used to control quantum states and amplify correct answers
106
-
107
- These properties potentially allow quantum computers to solve certain problems exponentially faster than classical computers. Promising applications include [3]:
108
-
109
- - Cryptography and security (both breaking and creating new encryption methods)
110
- - Drug discovery and molecular modeling
111
- - Optimization problems in fields like logistics and finance
112
- - Machine learning and artificial intelligence
113
- - Climate modeling and materials science
114
-
115
- Currently, quantum computers are still in early development. Companies like IBM, Google, Microsoft, and D-Wave are building increasingly powerful quantum processors, though practical, error-corrected quantum computers that can outperform classical supercomputers for a wide range of problems are still being developed.
116
-
117
- Challenges in quantum computing include maintaining quantum coherence (qubits are fragile and easily disrupted by environmental noise), error correction, and scaling up to more qubits while maintaining control."""
118
- }
119
-
120
- # Pre-curated sources for common topics
121
- COMMON_SOURCES = {
122
- "computer": [
123
- {
124
- 'title': "Wikipedia - Computer",
125
- 'url': "https://en.wikipedia.org/wiki/Computer",
126
- 'snippet': "A computer is a digital electronic machine that can be programmed to carry out sequences of arithmetic or logical operations (computation) automatically."
127
- },
128
- {
129
- 'title': "Computer - Encyclopedia Britannica",
130
- 'url': "https://www.britannica.com/technology/computer",
131
- 'snippet': "Computer, device for processing, storing, and displaying information. Computer once meant a person who did computations, but now the term almost universally refers to automated electronic machinery."
132
- },
133
- {
134
- 'title': "How Computers Work - Khan Academy",
135
- 'url': "https://www.khanacademy.org/computing/computer-science/how-computers-work2",
136
- 'snippet': "Computers are everywhere and they're used for everything, but how do they actually work? In this course you'll learn how computers work from the bottom up."
137
- }
138
- ],
139
- "artificial intelligence": [
140
- {
141
- 'title': "Wikipedia - Artificial intelligence",
142
- 'url': "https://en.wikipedia.org/wiki/Artificial_intelligence",
143
- 'snippet': "Artificial intelligence (AI) is intelligence—perceiving, synthesizing, and inferring information—demonstrated by machines, as opposed to intelligence displayed by humans or by other animals."
144
- },
145
- {
146
- 'title': "What is Artificial Intelligence (AI)? - IBM",
147
- 'url': "https://www.ibm.com/topics/artificial-intelligence",
148
- 'snippet': "Artificial intelligence is the simulation of human intelligence processes by machines, especially computer systems. Specific applications of AI include expert systems, natural language processing, speech recognition and machine vision."
149
- },
150
- {
151
- 'title': "Artificial Intelligence - Stanford Encyclopedia of Philosophy",
152
- 'url': "https://plato.stanford.edu/entries/artificial-intelligence/",
153
- 'snippet': "Artificial intelligence (AI) is both the intelligence of machines and the branch of computer science which aims to create it. AI textbooks define the field as 'the study and design of intelligent agents.'"
154
- }
155
- ],
156
- "quantum computing": [
157
- {
158
- 'title': "Wikipedia - Quantum computing",
159
- 'url': "https://en.wikipedia.org/wiki/Quantum_computing",
160
- 'snippet': "Quantum computing is a type of computation whose operations can harness the phenomena of quantum mechanics, such as superposition, interference, and entanglement."
161
- },
162
- {
163
- 'title': "What is quantum computing? - IBM",
164
- 'url': "https://www.ibm.com/topics/quantum-computing",
165
- 'snippet': "Quantum computing harnesses the phenomena of quantum mechanics to deliver a huge leap forward in computation to solve certain problems."
166
- },
167
- {
168
- 'title': "Quantum Computing - MIT Technology Review",
169
- 'url': "https://www.technologyreview.com/topic/computing/quantum-computing/",
170
- 'snippet': "Quantum computers leverage the strange properties of quantum physics to theoretically solve certain types of problems that are effectively impossible for classical computers."
171
- }
172
- ]
173
- }
174
-
175
- # Related topics for common searches
176
- COMMON_TOPICS = {
177
- "computer": [
178
- "History of computers",
179
- "How do computers work?",
180
- "Types of computer systems"
181
- ],
182
- "artificial intelligence": [
183
- "Machine learning vs AI",
184
- "Future of artificial intelligence",
185
- "Ethical concerns in AI"
186
- ],
187
- "quantum computing": [
188
- "Quantum supremacy",
189
- "Quantum entanglement",
190
- "Quantum computing applications"
191
- ]
192
- }
193
-
194
- def search_web(query, max_results=3):
195
- """Search the web using Wikipedia API with reliable fallbacks"""
196
- # Check for common topics first
197
- query_lower = query.lower()
198
- for key in COMMON_SOURCES.keys():
199
- if key in query_lower:
200
- print(f"Using pre-curated sources for '{key}'")
201
- return COMMON_SOURCES[key]
202
-
203
- # If not a common topic, try Wikipedia API
204
  results = []
 
 
 
205
  try:
206
- # Try Wikipedia API
207
  wiki_url = f"https://en.wikipedia.org/w/api.php?action=opensearch&search={urllib.parse.quote(query)}&limit={max_results}&namespace=0&format=json"
208
- response = requests.get(wiki_url)
209
 
210
  if response.status_code == 200:
211
  data = response.json()
@@ -215,16 +72,14 @@ def search_web(query, max_results=3):
215
  for i in range(min(len(titles), len(urls))):
216
  # Get summary for each page
217
  page_url = f"https://en.wikipedia.org/w/api.php?action=query&prop=extracts&exintro&explaintext&titles={urllib.parse.quote(titles[i])}&format=json"
218
- page_response = requests.get(page_url)
219
 
220
  if page_response.status_code == 200:
221
  page_data = page_response.json()
222
- # Extract page ID
223
  try:
224
  page_id = next(iter(page_data['query']['pages'].keys()))
225
- if page_id != "-1": # Valid page
226
  extract = page_data['query']['pages'][page_id].get('extract', '')
227
- # Truncate to a reasonable snippet length
228
  snippet = extract[:200] + "..." if len(extract) > 200 else extract
229
 
230
  results.append({
@@ -232,236 +87,252 @@ def search_web(query, max_results=3):
232
  'url': urls[i],
233
  'snippet': snippet
234
  })
235
- except:
236
- pass
 
237
  except Exception as e:
238
- print(f"Wikipedia API error: {e}")
239
 
240
- # If we still don't have enough results, use fallback
241
  if len(results) < max_results:
242
- # Reliable fallback results
243
- fallback_results = [
244
- {
245
- 'title': f"Wikipedia - {query}",
246
- 'url': f"https://en.wikipedia.org/wiki/Special:Search?search={urllib.parse.quote(query)}",
247
- 'snippet': f"Information about {query} from the free encyclopedia Wikipedia."
248
- },
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
249
  {
250
- 'title': f"{query} - Overview",
251
  'url': f"https://www.google.com/search?q={urllib.parse.quote(query)}",
252
- 'snippet': f"Comprehensive information about {query} including definitions, applications, and history."
253
- },
254
- {
255
- 'title': f"Latest on {query}",
256
- 'url': f"https://news.google.com/search?q={urllib.parse.quote(query)}",
257
- 'snippet': f"Recent news and updates about {query}."
258
  }
259
  ]
260
-
261
- # Add fallback results until we have enough
262
- for result in fallback_results:
263
- if len(results) >= max_results:
264
- break
265
- results.append(result)
266
 
267
  return results[:max_results]
268
 
269
- def generate_response(prompt, max_new_tokens=256):
270
- """Generate response with comprehensive error handling and fallbacks"""
271
- # If model isn't loaded, return a generic response
272
- if not MODEL_LOADED:
273
- print("Model not loaded, using pre-written responses")
274
- # Check for common topics
275
- for key, answer in COMMON_ANSWERS.items():
276
- if key in prompt.lower():
277
- return answer
278
-
279
- # Generic response for unknown topics
280
- return f"Based on the search results, I can provide some information about your query. The topic appears to be related to {prompt.split(':')[-1].strip()}. For more detailed information, please check the sources provided below."
281
-
282
- # With loaded model, try to generate a response
283
  try:
284
- if MODEL_TYPE == "t5":
285
- # T5 models
286
- inputs = tokenizer(prompt, return_tensors="pt").to(model.device)
287
 
288
  with torch.no_grad():
289
  outputs = model.generate(
290
  inputs.input_ids,
291
  max_new_tokens=max_new_tokens,
292
  temperature=0.7,
293
- num_beams=1,
294
  do_sample=True
295
  )
296
 
297
  response = tokenizer.decode(outputs[0], skip_special_tokens=True)
298
  return response
299
- else: # phi or other models
300
- # Format for Phi-2
301
- if MODEL_TYPE == "phi":
302
- phi_prompt = f"Instruct: {prompt}\nOutput:"
303
- else:
304
- phi_prompt = prompt
305
 
306
- # Tokenize input
307
- inputs = tokenizer(phi_prompt, return_tensors="pt").to(model.device)
 
 
 
 
 
 
308
 
309
- # Generate with efficient settings
310
  with torch.no_grad():
311
  outputs = model.generate(
312
  inputs.input_ids,
313
  max_new_tokens=max_new_tokens,
314
  temperature=0.7,
315
  top_p=0.9,
316
- num_beams=1,
317
  do_sample=True,
318
  pad_token_id=tokenizer.eos_token_id
319
  )
320
 
321
- # Decode response
322
  response = tokenizer.decode(outputs[0][inputs.input_ids.size(1):], skip_special_tokens=True).strip()
323
 
324
- # Check if response is empty and use fallback if needed
325
- if not response or len(response) < 20:
326
- # Try to find a pre-written answer
327
- query = prompt.split(':')[-1].strip()
328
- for key, answer in COMMON_ANSWERS.items():
329
- if key in query.lower():
330
- return answer
 
 
 
 
331
 
332
- # Generic fallback response
333
- return f"Based on the search results, I can provide information about {query}. The sources listed below contain more detailed information about this topic."
334
 
335
  return response
336
-
337
  except Exception as e:
338
  print(f"Error generating response: {e}")
339
-
340
- # Try to find a pre-written answer
341
- query = prompt.split(':')[-1].strip()
342
- for key, answer in COMMON_ANSWERS.items():
343
- if key in query.lower():
344
- return answer
345
-
346
- # Last resort fallback
347
- return f"Based on the search results, I can tell you that {query} is a topic with various aspects covered in the sources below. For more detailed information, please check those sources."
348
-
349
- # Answer cache for better performance
350
- answer_cache = {}
351
 
352
- def extract_citations(text, search_results):
353
  """Ensure citations are properly added to the text"""
354
- # If text is None or empty, return a fallback
355
  if not text or len(text.strip()) < 10:
356
- return "I couldn't generate a specific response for this query. Please check the sources below for information."
357
 
358
  # Add citations if not present
359
  if not re.search(r'\[\d+\]', text):
 
360
  for i, result in enumerate(search_results, 1):
361
- # Try to find snippet content in the answer
362
  key_phrases = result['snippet'].split('.')
363
  for phrase in key_phrases:
364
- if phrase and len(phrase) > 20 and phrase.strip() in text:
365
  text = text.replace(phrase, f"{phrase} [{i}]", 1)
366
 
367
- # If still no citations, add at least one at the end
368
  if not re.search(r'\[\d+\]', text):
369
- text += f" [1]"
370
 
371
  return text
372
 
373
- def generate_related_topics(query):
374
- """Generate related topics with reliable fallbacks"""
375
- # Check for common topics first
376
- query_lower = query.lower()
377
- for key, topics in COMMON_TOPICS.items():
378
- if key in query_lower:
379
- return topics
380
-
381
- # Generic topics for any query
382
- generic_topics = [
383
- f"History of {query}",
384
- f"Latest developments in {query}",
385
- f"How does {query} work?"
386
- ]
387
-
388
- return generic_topics
389
-
390
- def search_and_answer(query):
391
- """Main function to search and generate answer with robust fallbacks"""
392
  try:
393
- # Check cache first
394
- cache_key = query.lower().strip()
395
- if cache_key in answer_cache:
396
- return answer_cache[cache_key]
 
 
 
 
397
 
398
- # Step 1: Search the web
399
- search_results = search_web(query, max_results=3)
 
400
 
401
- # Step 2: Check for pre-written answers
402
- for key, answer in COMMON_ANSWERS.items():
403
- if key in cache_key:
404
- result = {
405
- "answer": answer,
406
- "sources": COMMON_SOURCES.get(key, search_results),
407
- "related_topics": COMMON_TOPICS.get(key, generate_related_topics(query))
408
- }
409
- answer_cache[cache_key] = result
410
- return result
 
 
 
 
 
 
 
 
 
 
 
 
 
411
 
412
- # Step 3: Create context for the model
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
413
  context = f"Query: {query}\n\nSearch Results:\n\n"
414
 
415
  for i, result in enumerate(search_results, 1):
416
  context += f"Source {i}:\n"
417
  context += f"Title: {result['title']}\n"
 
418
  context += f"Content: {result['snippet']}\n\n"
419
 
420
- # Step 4: Create prompt for the model
421
  prompt = f"""You are a helpful AI assistant that provides accurate and comprehensive answers based on search results.
422
 
423
  {context}
424
 
425
- Based on these search results, please provide a concise answer to the query: "{query}"
426
  Include citations like [1], [2], etc. to reference the sources.
427
  Be factual and accurate. If the search results don't contain enough information, acknowledge this limitation.
428
  Format your answer in clear paragraphs with bullet points where appropriate."""
429
 
430
- # Step 5: Generate answer with optimized settings
431
- answer = generate_response(prompt, max_new_tokens=256)
432
-
433
- # Step 6: Ensure we have an answer
434
- if not answer or len(answer.strip()) < 20:
435
- # Generic fallback answer
436
- answer = f"""Based on the search results, I can provide some information about {query}.
437
-
438
- The sources show that this topic has various aspects and applications. For more detailed information, please refer to the sources listed below [1][2].
439
-
440
- To learn more about specific aspects of {query}, you might want to explore the related topics listed below."""
441
 
442
- # Step 7: Ensure citations
443
- answer = extract_citations(answer, search_results)
444
 
445
- # Step 8: Generate related topics
446
- related_topics = generate_related_topics(query)
447
 
448
- # Store in cache for future use
449
- result = {
450
  "answer": answer,
451
  "sources": search_results,
452
  "related_topics": related_topics
453
  }
454
- answer_cache[cache_key] = result
455
-
456
- return result
457
 
458
  except Exception as e:
459
- print(f"Error in search_and_answer: {e}")
460
- # Comprehensive fallback
461
  return {
462
- "answer": f"I found some information about {query} that you might find useful. Please check the sources below for more details.",
463
- "sources": search_web(query),
464
- "related_topics": generate_related_topics(query)
465
  }
466
 
467
  def format_sources(sources):
@@ -489,10 +360,10 @@ def format_related(topics):
489
  if not topics:
490
  return ""
491
 
492
- # Use a more reliable approach for clicking topics
493
  html = "<div style='display: flex; flex-wrap: wrap; gap: 10px; margin-top: 15px;'>"
494
  for i, topic in enumerate(topics):
495
- # Each topic is a button with a unique ID that we'll handle with JavaScript
496
  html += f"""
497
  <div id="topic-{i}" style="background-color: #EFF6FF; padding: 10px 16px; border-radius: 100px;
498
  color: #2563EB; font-size: 14px; font-weight: 500; cursor: pointer; display: inline-block;
@@ -505,83 +376,95 @@ def format_related(topics):
505
  """
506
  html += "</div>"
507
 
508
- # Add JavaScript for clicking topics
509
  html += """
510
  <script>
511
- // Function to handle topic clicks with error handling
512
  function setupTopicClicks() {
513
- try {
514
- // Select all topic elements
515
- const topics = document.querySelectorAll('[id^="topic-"]');
516
-
517
- // Add click event listener to each topic
518
- topics.forEach(topic => {
519
- topic.addEventListener('click', function() {
520
- try {
521
- // Get the topic text
522
- const topicText = this.getAttribute('data-topic');
523
- console.log("Clicked topic:", topicText);
524
-
525
- // Set the search input value
526
- const inputElement = document.getElementById('query-input');
527
- if (inputElement) {
528
- inputElement.value = topicText;
529
-
530
- // Find and click the search button
531
- const searchButton = document.querySelector('button[data-testid="submit"]');
532
- if (searchButton) {
533
- searchButton.click();
534
- } else {
535
- // Alternative: try to find by aria-label
536
- const altButton = document.querySelector('button[aria-label="Submit"]');
537
- if (altButton) {
538
- altButton.click();
539
- } else {
540
- // Last resort: try all buttons
541
- const buttons = document.querySelectorAll('button');
542
- for (let btn of buttons) {
543
- if (btn.innerText.includes("Search")) {
544
- btn.click();
545
- break;
546
- }
547
- }
548
- }
549
- }
550
- }
551
- } catch (err) {
552
- console.error("Error handling topic click:", err);
553
  }
554
- });
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
555
  });
556
- } catch (error) {
557
- console.error("Error setting up topic clicks:", error);
558
- }
559
  }
560
 
561
- // Run immediately and also when DOM changes
562
  setupTopicClicks();
563
 
564
- // Set up a mutation observer to handle dynamically added topics
565
- try {
566
- const observer = new MutationObserver(function(mutations) {
567
- setupTopicClicks();
568
- });
569
-
570
- // Start observing the document body for changes
571
- observer.observe(document.body, {
572
- childList: true,
573
- subtree: true
574
  });
575
- } catch (error) {
576
- console.error("Error setting up observer:", error);
577
- }
 
 
 
 
 
 
578
  </script>
579
  """
580
 
581
  return html
582
 
583
  def search_interface(query):
584
- """Main function for the Gradio interface with reliable error handling"""
585
  if not query.strip():
586
  return (
587
  "Please enter a search query.",
@@ -593,14 +476,10 @@ def search_interface(query):
593
 
594
  try:
595
  # Show loading message while processing
596
- yield ("Searching...", "", "")
597
 
598
- # Perform search and answer generation
599
- result = search_and_answer(query)
600
-
601
- # Ensure we have a valid answer
602
- if not result["answer"] or len(result["answer"].strip()) < 10:
603
- result["answer"] = f"I found some information about '{query}'. Please check the sources below for more details."
604
 
605
  # Format answer with markdown
606
  answer_html = markdown(result["answer"])
@@ -625,8 +504,8 @@ def search_interface(query):
625
  # Return a fallback response
626
  yield (
627
  "I encountered an issue while processing your query. Please try again with a different search term.",
628
- format_sources(search_web(query)),
629
- format_related(generate_related_topics(query))
630
  )
631
 
632
  # Create the Gradio interface with modern UI
@@ -732,13 +611,6 @@ h3 {
732
  border-bottom: 1px solid currentColor;
733
  }
734
 
735
- /* Empty answer styling */
736
- .answer:empty::after {
737
- content: 'Enter a search query to see results';
738
- color: #9CA3AF;
739
- font-style: italic;
740
- }
741
-
742
  /* Loading state */
743
  .answer.loading {
744
  display: flex;
@@ -768,12 +640,12 @@ footer {
768
  """
769
 
770
  with gr.Blocks(css=css, theme=gr.themes.Default()) as demo:
771
- # Custom header with improved design
772
  gr.HTML("""
773
  <div class="header">
774
  <h1 style="color: #2563EB; font-size: 2.2rem; font-weight: 700; margin-bottom: 0.5rem;">🔍 AI Search System</h1>
775
  <p style="color: #64748B; font-size: 1.1rem; max-width: 600px; margin: 0 auto;">
776
- Get comprehensive answers with reliable sources for any question you have.
777
  </p>
778
  </div>
779
  """)
@@ -825,6 +697,6 @@ with gr.Blocks(css=css, theme=gr.themes.Default()) as demo:
825
  </footer>
826
  """)
827
 
828
- # Launch app with queue to prevent overloading
829
  demo.queue(max_size=10)
830
  demo.launch()
 
13
  # Set environment variables
14
  os.environ["TOKENIZERS_PARALLELISM"] = "false"
15
 
 
 
 
 
16
  print("Loading model... Please wait...")
17
 
18
+ # Load the model with proper error handling
19
  try:
20
+ # Try with Phi-2
21
  MODEL_ID = "microsoft/phi-2"
22
 
23
  tokenizer = AutoTokenizer.from_pretrained(
 
32
  trust_remote_code=True
33
  )
34
 
 
 
35
  print("Successfully loaded Phi-2 model")
36
  except Exception as e:
37
  print(f"Error loading Phi-2: {e}")
 
49
  device_map="auto"
50
  )
51
 
 
 
52
  print("Successfully loaded fallback model")
53
  except Exception as e:
54
  print(f"Error loading fallback model: {e}")
55
+ print("Operating in reduced functionality mode")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
56
 
57
+ def search_web(query, max_results=5):
58
+ """Perform real web searches using multiple search endpoints"""
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
59
  results = []
60
+
61
+ # Try multiple search methods for reliability
62
+ # Method 1: Wikipedia API
63
  try:
 
64
  wiki_url = f"https://en.wikipedia.org/w/api.php?action=opensearch&search={urllib.parse.quote(query)}&limit={max_results}&namespace=0&format=json"
65
+ response = requests.get(wiki_url, timeout=5)
66
 
67
  if response.status_code == 200:
68
  data = response.json()
 
72
  for i in range(min(len(titles), len(urls))):
73
  # Get summary for each page
74
  page_url = f"https://en.wikipedia.org/w/api.php?action=query&prop=extracts&exintro&explaintext&titles={urllib.parse.quote(titles[i])}&format=json"
75
+ page_response = requests.get(page_url, timeout=5)
76
 
77
  if page_response.status_code == 200:
78
  page_data = page_response.json()
 
79
  try:
80
  page_id = next(iter(page_data['query']['pages'].keys()))
81
+ if page_id != "-1":
82
  extract = page_data['query']['pages'][page_id].get('extract', '')
 
83
  snippet = extract[:200] + "..." if len(extract) > 200 else extract
84
 
85
  results.append({
 
87
  'url': urls[i],
88
  'snippet': snippet
89
  })
90
+ except Exception as e:
91
+ print(f"Error extracting wiki data: {e}")
92
+ continue
93
  except Exception as e:
94
+ print(f"Wikipedia search error: {e}")
95
 
96
+ # Method 2: Public Search API (SerpAPI demo)
97
  if len(results) < max_results:
98
+ try:
99
+ serpapi_url = f"https://serpapi.com/search.json?engine=google&q={urllib.parse.quote(query)}&api_key=demo"
100
+ response = requests.get(serpapi_url, timeout=5)
101
+
102
+ if response.status_code == 200:
103
+ data = response.json()
104
+ if "organic_results" in data:
105
+ for result in data["organic_results"][:max_results - len(results)]:
106
+ results.append({
107
+ 'title': result.get('title', ''),
108
+ 'url': result.get('link', ''),
109
+ 'snippet': result.get('snippet', '')
110
+ })
111
+ except Exception as e:
112
+ print(f"SerpAPI error: {e}")
113
+
114
+ # Method 3: Direct web scraping (as last resort)
115
+ if len(results) < max_results:
116
+ try:
117
+ headers = {
118
+ 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36'
119
+ }
120
+ url = f"https://www.bing.com/search?q={urllib.parse.quote(query)}"
121
+ response = requests.get(url, headers=headers, timeout=10)
122
+
123
+ if response.status_code == 200:
124
+ soup = BeautifulSoup(response.text, 'html.parser')
125
+ search_results = soup.find_all('li', class_='b_algo')
126
+
127
+ for result in search_results[:max_results - len(results)]:
128
+ title_elem = result.find('h2')
129
+ if title_elem and title_elem.find('a'):
130
+ title = title_elem.text
131
+ url = title_elem.find('a')['href']
132
+
133
+ snippet_elem = result.find('div', class_='b_caption')
134
+ snippet = snippet_elem.find('p').text if snippet_elem and snippet_elem.find('p') else ""
135
+
136
+ results.append({
137
+ 'title': title,
138
+ 'url': url,
139
+ 'snippet': snippet
140
+ })
141
+ except Exception as e:
142
+ print(f"Web scraping error: {e}")
143
+
144
+ # If we still don't have results, create minimal placeholder results
145
+ # This ensures the UI doesn't break if all search methods fail
146
+ if not results:
147
+ results = [
148
  {
149
+ 'title': f"Search: {query}",
150
  'url': f"https://www.google.com/search?q={urllib.parse.quote(query)}",
151
+ 'snippet': "Search engine results for your query."
 
 
 
 
 
152
  }
153
  ]
 
 
 
 
 
 
154
 
155
  return results[:max_results]
156
 
157
+ def generate_response(model, tokenizer, prompt, max_new_tokens=512):
158
+ """Generate response using the AI model with proper error handling"""
 
 
 
 
 
 
 
 
 
 
 
 
159
  try:
160
+ # For T5 models
161
+ if "t5" in MODEL_ID.lower():
162
+ inputs = tokenizer(prompt, return_tensors="pt", truncation=True, max_length=512).to(model.device)
163
 
164
  with torch.no_grad():
165
  outputs = model.generate(
166
  inputs.input_ids,
167
  max_new_tokens=max_new_tokens,
168
  temperature=0.7,
 
169
  do_sample=True
170
  )
171
 
172
  response = tokenizer.decode(outputs[0], skip_special_tokens=True)
173
  return response
 
 
 
 
 
 
174
 
175
+ # For Phi and other models
176
+ else:
177
+ if "phi" in MODEL_ID.lower():
178
+ formatted_prompt = f"Instruct: {prompt}\nOutput:"
179
+ else:
180
+ formatted_prompt = prompt
181
+
182
+ inputs = tokenizer(formatted_prompt, return_tensors="pt", truncation=True, max_length=512).to(model.device)
183
 
 
184
  with torch.no_grad():
185
  outputs = model.generate(
186
  inputs.input_ids,
187
  max_new_tokens=max_new_tokens,
188
  temperature=0.7,
189
  top_p=0.9,
 
190
  do_sample=True,
191
  pad_token_id=tokenizer.eos_token_id
192
  )
193
 
 
194
  response = tokenizer.decode(outputs[0][inputs.input_ids.size(1):], skip_special_tokens=True).strip()
195
 
196
+ # Check if response is empty or too short
197
+ if not response or len(response) < 10:
198
+ # Try again with different parameters
199
+ outputs = model.generate(
200
+ inputs.input_ids,
201
+ max_new_tokens=max_new_tokens,
202
+ num_beams=3, # Use beam search instead
203
+ temperature=1.0,
204
+ do_sample=False, # Deterministic generation
205
+ pad_token_id=tokenizer.eos_token_id
206
+ )
207
 
208
+ response = tokenizer.decode(outputs[0][inputs.input_ids.size(1):], skip_special_tokens=True).strip()
 
209
 
210
  return response
 
211
  except Exception as e:
212
  print(f"Error generating response: {e}")
213
+ # Return a simple error message
214
+ return "I encountered a technical issue while generating a response. Please try another query."
 
 
 
 
 
 
 
 
 
 
215
 
216
+ def ensure_citations(text, search_results):
217
  """Ensure citations are properly added to the text"""
218
+ # If text is too short, return a generic message
219
  if not text or len(text.strip()) < 10:
220
+ return "I couldn't generate a proper response for this query. Please try a different search term."
221
 
222
  # Add citations if not present
223
  if not re.search(r'\[\d+\]', text):
224
+ # Try to find snippets in the answer
225
  for i, result in enumerate(search_results, 1):
 
226
  key_phrases = result['snippet'].split('.')
227
  for phrase in key_phrases:
228
+ if phrase and len(phrase) > 15 and phrase.strip() in text:
229
  text = text.replace(phrase, f"{phrase} [{i}]", 1)
230
 
231
+ # If still no citations, add a generic one at the end
232
  if not re.search(r'\[\d+\]', text):
233
+ text += f" [{1}]"
234
 
235
  return text
236
 
237
+ def generate_related_topics(model, tokenizer, query, answer):
238
+ """Generate related topics based on the AI model"""
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
239
  try:
240
+ # Craft a prompt to generate related topics
241
+ related_prompt = f"""Based on the original search query "{query}" and the information in this answer:
242
+ "{answer[:300]}...", generate 3 related topics or questions that someone might want to explore next.
243
+ Each should be specific and directly related to the query but explore a different aspect.
244
+ Format as a simple list with 3 items only."""
245
+
246
+ # Use the model to generate topics
247
+ related_text = generate_response(model, tokenizer, related_prompt, max_new_tokens=200)
248
 
249
+ # Parse the generated text into individual topics
250
+ lines = related_text.split('\n')
251
+ topics = []
252
 
253
+ for line in lines:
254
+ # Clean up line by removing numbers, bullet points, etc.
255
+ clean_line = re.sub(r'^[\d\-\*\•\.\s]+', '', line.strip())
256
+ if clean_line and len(clean_line) > 5:
257
+ topics.append(clean_line)
258
+
259
+ # Ensure we have at least 3 topics
260
+ if len(topics) < 3:
261
+ # Add generic but relevant topics based on the query
262
+ base_topics = [
263
+ f"History of {query}",
264
+ f"Latest developments in {query}",
265
+ f"How does {query} work?",
266
+ f"Applications of {query}",
267
+ f"Future of {query}"
268
+ ]
269
+
270
+ # Add topics until we have at least 3
271
+ for topic in base_topics:
272
+ if len(topics) >= 3:
273
+ break
274
+ if topic not in topics:
275
+ topics.append(topic)
276
 
277
+ return topics[:3] # Return top 3 topics
278
+
279
+ except Exception as e:
280
+ print(f"Error generating related topics: {e}")
281
+ # Return generic topics as fallback
282
+ return [
283
+ f"More about {query}",
284
+ f"Latest developments in {query}",
285
+ f"Applications of {query}"
286
+ ]
287
+
288
+ def process_query(query):
289
+ """Main function to process a query with real search and AI responses"""
290
+ try:
291
+ # Step 1: Search the web for real results
292
+ search_results = search_web(query, max_results=5)
293
+
294
+ # Step 2: Create context from search results
295
  context = f"Query: {query}\n\nSearch Results:\n\n"
296
 
297
  for i, result in enumerate(search_results, 1):
298
  context += f"Source {i}:\n"
299
  context += f"Title: {result['title']}\n"
300
+ context += f"URL: {result['url']}\n"
301
  context += f"Content: {result['snippet']}\n\n"
302
 
303
+ # Step 3: Create prompt for the AI model
304
  prompt = f"""You are a helpful AI assistant that provides accurate and comprehensive answers based on search results.
305
 
306
  {context}
307
 
308
+ Based on these search results, please provide a detailed answer to the query: "{query}"
309
  Include citations like [1], [2], etc. to reference the sources.
310
  Be factual and accurate. If the search results don't contain enough information, acknowledge this limitation.
311
  Format your answer in clear paragraphs with bullet points where appropriate."""
312
 
313
+ # Step 4: Generate answer using the AI model
314
+ answer = generate_response(model, tokenizer, prompt, max_new_tokens=512)
 
 
 
 
 
 
 
 
 
315
 
316
+ # Step 5: Ensure citations
317
+ answer = ensure_citations(answer, search_results)
318
 
319
+ # Step 6: Generate related topics using the AI model
320
+ related_topics = generate_related_topics(model, tokenizer, query, answer)
321
 
322
+ # Return the complete result
323
+ return {
324
  "answer": answer,
325
  "sources": search_results,
326
  "related_topics": related_topics
327
  }
 
 
 
328
 
329
  except Exception as e:
330
+ print(f"Error in process_query: {e}")
331
+ # Return a minimal result that won't break the UI
332
  return {
333
+ "answer": f"I encountered an error while processing your query about '{query}'. Please try again or try a different search term.",
334
+ "sources": search_web(query, max_results=2), # Try to get at least some sources
335
+ "related_topics": [f"More about {query}", f"Different aspects of {query}", f"Applications of {query}"]
336
  }
337
 
338
  def format_sources(sources):
 
360
  if not topics:
361
  return ""
362
 
363
+ # Create HTML with unique IDs for each topic
364
  html = "<div style='display: flex; flex-wrap: wrap; gap: 10px; margin-top: 15px;'>"
365
  for i, topic in enumerate(topics):
366
+ # Each topic is a button with a unique ID
367
  html += f"""
368
  <div id="topic-{i}" style="background-color: #EFF6FF; padding: 10px 16px; border-radius: 100px;
369
  color: #2563EB; font-size: 14px; font-weight: 500; cursor: pointer; display: inline-block;
 
376
  """
377
  html += "</div>"
378
 
379
+ # Add JavaScript to handle topic clicks
380
  html += """
381
  <script>
382
+ // Set up event listeners for topic clicks
383
  function setupTopicClicks() {
384
+ // Find all topic elements
385
+ const topics = document.querySelectorAll('[id^="topic-"]');
386
+
387
+ // Add click listeners to each topic
388
+ topics.forEach(topic => {
389
+ topic.addEventListener('click', function() {
390
+ // Get the topic text
391
+ const topicText = this.getAttribute('data-topic');
392
+ console.log("Clicked topic:", topicText);
393
+
394
+ // Set input value to the topic text
395
+ const inputElement = document.getElementById('query-input');
396
+ if (inputElement) {
397
+ inputElement.value = topicText;
398
+
399
+ // Try multiple methods to trigger the search
400
+
401
+ // Method 1: Click the search button
402
+ const searchButton = document.querySelector('button[data-testid="submit"]');
403
+ if (searchButton) {
404
+ searchButton.click();
405
+ return;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
406
  }
407
+
408
+ // Method 2: Try other button selectors
409
+ const altButton = document.querySelector('button[aria-label="Submit"]') ||
410
+ document.querySelector('button:contains("Search")');
411
+ if (altButton) {
412
+ altButton.click();
413
+ return;
414
+ }
415
+
416
+ // Method 3: Find button by text content
417
+ const buttons = Array.from(document.querySelectorAll('button'));
418
+ const searchBtn = buttons.find(btn =>
419
+ btn.textContent.includes('Search') ||
420
+ btn.innerHTML.includes('Search')
421
+ );
422
+
423
+ if (searchBtn) {
424
+ searchBtn.click();
425
+ return;
426
+ }
427
+
428
+ // Method 4: Trigger form submission directly
429
+ const form = inputElement.closest('form');
430
+ if (form) {
431
+ const event = new Event('submit', { bubbles: true });
432
+ form.dispatchEvent(event);
433
+ return;
434
+ }
435
+
436
+ console.log("Could not find a way to trigger search");
437
+ }
438
  });
439
+ });
 
 
440
  }
441
 
442
+ // Run the setup function
443
  setupTopicClicks();
444
 
445
+ // Set up an observer to handle dynamically loaded topics
446
+ const observer = new MutationObserver(function(mutations) {
447
+ mutations.forEach(function(mutation) {
448
+ if (mutation.addedNodes.length) {
449
+ setupTopicClicks();
450
+ }
 
 
 
 
451
  });
452
+ });
453
+
454
+ // Start observing the document
455
+ observer.observe(document.body, { childList: true, subtree: true });
456
+
457
+ // jQuery-like helper function
458
+ Element.prototype.contains = function(text) {
459
+ return this.innerText.includes(text);
460
+ };
461
  </script>
462
  """
463
 
464
  return html
465
 
466
  def search_interface(query):
467
+ """Main function for the Gradio interface with progress updates"""
468
  if not query.strip():
469
  return (
470
  "Please enter a search query.",
 
476
 
477
  try:
478
  # Show loading message while processing
479
+ yield ("Searching and generating response...", "", "")
480
 
481
+ # Process the query
482
+ result = process_query(query)
 
 
 
 
483
 
484
  # Format answer with markdown
485
  answer_html = markdown(result["answer"])
 
504
  # Return a fallback response
505
  yield (
506
  "I encountered an issue while processing your query. Please try again with a different search term.",
507
+ "",
508
+ ""
509
  )
510
 
511
  # Create the Gradio interface with modern UI
 
611
  border-bottom: 1px solid currentColor;
612
  }
613
 
 
 
 
 
 
 
 
614
  /* Loading state */
615
  .answer.loading {
616
  display: flex;
 
640
  """
641
 
642
  with gr.Blocks(css=css, theme=gr.themes.Default()) as demo:
643
+ # Custom header with professional design
644
  gr.HTML("""
645
  <div class="header">
646
  <h1 style="color: #2563EB; font-size: 2.2rem; font-weight: 700; margin-bottom: 0.5rem;">🔍 AI Search System</h1>
647
  <p style="color: #64748B; font-size: 1.1rem; max-width: 600px; margin: 0 auto;">
648
+ Get comprehensive answers with real sources for any question.
649
  </p>
650
  </div>
651
  """)
 
697
  </footer>
698
  """)
699
 
700
+ # Launch app with queue for better performance
701
  demo.queue(max_size=10)
702
  demo.launch()