Spaces:
Running
Running
fix more efficent
Browse files
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 |
-
#
|
23 |
try:
|
24 |
-
#
|
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("
|
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 |
-
|
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":
|
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 |
-
|
|
|
237 |
except Exception as e:
|
238 |
-
print(f"Wikipedia
|
239 |
|
240 |
-
#
|
241 |
if len(results) < max_results:
|
242 |
-
|
243 |
-
|
244 |
-
|
245 |
-
|
246 |
-
|
247 |
-
|
248 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
249 |
{
|
250 |
-
'title': f"{query}
|
251 |
'url': f"https://www.google.com/search?q={urllib.parse.quote(query)}",
|
252 |
-
'snippet':
|
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=
|
270 |
-
"""Generate response with
|
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 |
-
|
285 |
-
|
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 |
-
|
307 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
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
|
325 |
-
if not response or len(response) <
|
326 |
-
# Try
|
327 |
-
|
328 |
-
|
329 |
-
|
330 |
-
|
|
|
|
|
|
|
|
|
331 |
|
332 |
-
|
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 |
-
|
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
|
353 |
"""Ensure citations are properly added to the text"""
|
354 |
-
# If text is
|
355 |
if not text or len(text.strip()) < 10:
|
356 |
-
return "I couldn't generate a
|
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) >
|
365 |
text = text.replace(phrase, f"{phrase} [{i}]", 1)
|
366 |
|
367 |
-
# If still no citations, add
|
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
|
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 |
-
#
|
394 |
-
|
395 |
-
|
396 |
-
|
|
|
|
|
|
|
|
|
397 |
|
398 |
-
#
|
399 |
-
|
|
|
400 |
|
401 |
-
|
402 |
-
|
403 |
-
|
404 |
-
|
405 |
-
|
406 |
-
|
407 |
-
|
408 |
-
|
409 |
-
|
410 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
411 |
|
412 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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
|
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
|
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
|
431 |
-
answer = generate_response(prompt, max_new_tokens=
|
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
|
443 |
-
answer =
|
444 |
|
445 |
-
# Step
|
446 |
-
related_topics = generate_related_topics(query)
|
447 |
|
448 |
-
#
|
449 |
-
|
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
|
460 |
-
#
|
461 |
return {
|
462 |
-
"answer": f"I
|
463 |
-
"sources": search_web(query),
|
464 |
-
"related_topics":
|
465 |
}
|
466 |
|
467 |
def format_sources(sources):
|
@@ -489,10 +360,10 @@ def format_related(topics):
|
|
489 |
if not topics:
|
490 |
return ""
|
491 |
|
492 |
-
#
|
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
|
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
|
509 |
html += """
|
510 |
<script>
|
511 |
-
//
|
512 |
function setupTopicClicks() {
|
513 |
-
|
514 |
-
|
515 |
-
|
516 |
-
|
517 |
-
|
518 |
-
|
519 |
-
topic
|
520 |
-
|
521 |
-
|
522 |
-
|
523 |
-
|
524 |
-
|
525 |
-
|
526 |
-
|
527 |
-
|
528 |
-
|
529 |
-
|
530 |
-
|
531 |
-
|
532 |
-
|
533 |
-
|
534 |
-
|
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 |
-
}
|
557 |
-
console.error("Error setting up topic clicks:", error);
|
558 |
-
}
|
559 |
}
|
560 |
|
561 |
-
// Run
|
562 |
setupTopicClicks();
|
563 |
|
564 |
-
// Set up
|
565 |
-
|
566 |
-
|
567 |
-
|
568 |
-
|
569 |
-
|
570 |
-
// Start observing the document body for changes
|
571 |
-
observer.observe(document.body, {
|
572 |
-
childList: true,
|
573 |
-
subtree: true
|
574 |
});
|
575 |
-
}
|
576 |
-
|
577 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
578 |
</script>
|
579 |
"""
|
580 |
|
581 |
return html
|
582 |
|
583 |
def search_interface(query):
|
584 |
-
"""Main function for the Gradio interface with
|
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 |
-
#
|
599 |
-
result =
|
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 |
-
|
629 |
-
|
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
|
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
|
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
|
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()
|