Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
@@ -18,16 +18,6 @@ from huggingface_hub import InferenceClient
|
|
18 |
import inspect
|
19 |
import logging
|
20 |
import shutil
|
21 |
-
from sentence_transformers import CrossEncoder
|
22 |
-
from datetime import datetime
|
23 |
-
from dateutil import parser as date_parser
|
24 |
-
from sklearn.feature_extraction.text import TfidfVectorizer
|
25 |
-
from sklearn.metrics.pairwise import cosine_similarity
|
26 |
-
from trafilatura import fetch_url, extract
|
27 |
-
import json
|
28 |
-
from requests.exceptions import RequestException
|
29 |
-
|
30 |
-
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
|
31 |
|
32 |
|
33 |
# Set up basic configuration for logging
|
@@ -281,66 +271,10 @@ def generate_chunked_response(prompt, model, max_tokens=10000, num_calls=3, temp
|
|
281 |
print(f"Final clean response: {final_response[:100]}...")
|
282 |
return final_response
|
283 |
|
284 |
-
class SimpleDDGSearch:
|
285 |
-
def search(self, query: str, num_results: int = 5):
|
286 |
-
results = []
|
287 |
-
with DDGS() as ddgs:
|
288 |
-
for r in ddgs.text(query, region='wt-wt', safesearch='off', max_results=num_results * 2): # Request more results than needed
|
289 |
-
results.append(r["href"])
|
290 |
-
if len(results) >= num_results:
|
291 |
-
break
|
292 |
-
return results
|
293 |
-
|
294 |
-
class TrafilaturaWebCrawler:
|
295 |
-
def get_website_content_from_url(self, url: str) -> str:
|
296 |
-
try:
|
297 |
-
downloaded = fetch_url(url)
|
298 |
-
if downloaded is None:
|
299 |
-
raise RequestException(f"Failed to fetch content from URL: {url}")
|
300 |
-
|
301 |
-
result = extract(downloaded, output_format='json', include_comments=False, with_metadata=True, url=url)
|
302 |
-
if result:
|
303 |
-
result_dict = json.loads(result)
|
304 |
-
title = result_dict.get('title', 'No title found')
|
305 |
-
content = result_dict.get('text', 'No content extracted')
|
306 |
-
|
307 |
-
if content == 'No content extracted':
|
308 |
-
content = extract(downloaded, include_comments=False)
|
309 |
-
|
310 |
-
return f'=========== Website Title: {title} ===========\n\n=========== Website URL: {url} ===========\n\n=========== Website Content ===========\n\n{content}\n\n=========== Website Content End ===========\n\n'
|
311 |
-
else:
|
312 |
-
raise ValueError(f"No content extracted from URL: {url}")
|
313 |
-
except Exception as e:
|
314 |
-
logging.error(f"An error occurred while processing {url}: {str(e)}")
|
315 |
-
return None
|
316 |
-
|
317 |
-
def search_and_crawl(query: str, num_results: int = 10):
|
318 |
-
searcher = SimpleDDGSearch()
|
319 |
-
search_results = searcher.search(query, num_results=num_results * 2) # Request more results than needed
|
320 |
-
|
321 |
-
crawler = TrafilaturaWebCrawler()
|
322 |
-
output = ""
|
323 |
-
successful_crawls = 0
|
324 |
-
|
325 |
-
for url in search_results:
|
326 |
-
if successful_crawls >= num_results:
|
327 |
-
break
|
328 |
-
|
329 |
-
content = crawler.get_website_content_from_url(url)
|
330 |
-
if content:
|
331 |
-
output += f"Results for URL {successful_crawls + 1}: {url}\n\n"
|
332 |
-
output += content + "\n"
|
333 |
-
output += "------------------------------------------------------------\n\n"
|
334 |
-
successful_crawls += 1
|
335 |
-
|
336 |
-
if successful_crawls == 0:
|
337 |
-
logging.warning(f"No successful crawls for query: {query}")
|
338 |
-
return "No results could be fetched for the given query."
|
339 |
-
|
340 |
-
return output
|
341 |
-
|
342 |
def duckduckgo_search(query):
|
343 |
-
|
|
|
|
|
344 |
|
345 |
class CitingSources(BaseModel):
|
346 |
sources: List[str] = Field(
|
@@ -373,19 +307,17 @@ def retry_last_response(history, use_web_search, model, temperature, num_calls):
|
|
373 |
|
374 |
return chatbot_interface(last_user_msg, history, use_web_search, model, temperature, num_calls)
|
375 |
|
376 |
-
|
|
|
|
|
377 |
logging.info(f"User Query: {message}")
|
378 |
-
logging.info(f"Model Used: {model}")
|
379 |
logging.info(f"Search Type: {'Web Search' if use_web_search else 'PDF Search'}")
|
380 |
-
|
381 |
logging.info(f"Selected Documents: {selected_docs}")
|
382 |
|
383 |
try:
|
384 |
if use_web_search:
|
385 |
for main_content, sources in get_response_with_search(message, model, num_calls=num_calls, temperature=temperature):
|
386 |
response = f"{main_content}\n\n{sources}"
|
387 |
-
first_line = response.split('\n')[0] if response else ''
|
388 |
-
# logging.info(f"Generated Response (first line): {first_line}")
|
389 |
yield response
|
390 |
else:
|
391 |
embed = get_embeddings()
|
@@ -393,7 +325,6 @@ def respond(message, history, model, temperature, num_calls, use_web_search, sel
|
|
393 |
database = FAISS.load_local("faiss_database", embed, allow_dangerous_deserialization=True)
|
394 |
retriever = database.as_retriever(search_kwargs={"k": 20})
|
395 |
|
396 |
-
# Filter relevant documents based on user selection
|
397 |
all_relevant_docs = retriever.get_relevant_documents(message)
|
398 |
relevant_docs = [doc for doc in all_relevant_docs if doc.metadata["source"] in selected_docs]
|
399 |
|
@@ -407,26 +338,21 @@ def respond(message, history, model, temperature, num_calls, use_web_search, sel
|
|
407 |
yield "No documents available. Please upload PDF documents to answer questions."
|
408 |
return
|
409 |
|
410 |
-
|
411 |
-
|
412 |
-
|
413 |
-
|
414 |
-
|
415 |
-
|
416 |
-
|
417 |
-
|
418 |
-
|
419 |
-
|
420 |
-
|
421 |
-
|
422 |
except Exception as e:
|
423 |
-
logging.error(f"Error
|
424 |
-
|
425 |
-
logging.info("Falling back to Mistral model due to Phi-3 error")
|
426 |
-
fallback_model = "mistralai/Mistral-7B-Instruct-v0.3"
|
427 |
-
yield from respond(message, history, fallback_model, temperature, num_calls, use_web_search, selected_docs)
|
428 |
-
else:
|
429 |
-
yield f"An error occurred with the {model} model: {str(e)}. Please try again or select a different model."
|
430 |
|
431 |
logging.basicConfig(level=logging.DEBUG)
|
432 |
|
@@ -485,119 +411,51 @@ After writing the document, please provide a list of sources used in your respon
|
|
485 |
if not full_response:
|
486 |
yield "I apologize, but I couldn't generate a response at this time. Please try again later."
|
487 |
|
488 |
-
def rank_results(query, results):
|
489 |
-
# Sort by date, most recent first
|
490 |
-
results.sort(key=lambda x: x['date'], reverse=True)
|
491 |
-
|
492 |
-
# Calculate relevance scores
|
493 |
-
vectorizer = TfidfVectorizer().fit_transform([query] + [f"{r['title']} {r['body']}" for r in results])
|
494 |
-
relevance_scores = cosine_similarity(vectorizer[0:1], vectorizer[1:])[0]
|
495 |
-
|
496 |
-
# Combine date priority and relevance score
|
497 |
-
for i, result in enumerate(results):
|
498 |
-
days_old = (datetime.now() - result['date']).days
|
499 |
-
date_score = 1 / (days_old + 1) # Newer articles get higher scores
|
500 |
-
result['combined_score'] = (date_score + relevance_scores[i]) / 2
|
501 |
-
|
502 |
-
# Sort by combined score and return top 3
|
503 |
-
return sorted(results, key=lambda x: x['combined_score'], reverse=True)[:3]
|
504 |
-
|
505 |
def create_web_search_vectors(search_results):
|
506 |
embed = get_embeddings()
|
507 |
|
508 |
documents = []
|
509 |
for result in search_results:
|
510 |
if 'body' in result:
|
511 |
-
content = f"{result['title']}\n{result['body']}\nSource: {result['href']}
|
512 |
-
documents.append(Document(page_content=content, metadata={"source": result['href']
|
513 |
|
514 |
return FAISS.from_documents(documents, embed)
|
515 |
|
516 |
def get_response_with_search(query, model, num_calls=3, temperature=0.2):
|
517 |
search_results = duckduckgo_search(query)
|
|
|
518 |
|
519 |
-
|
520 |
-
yield "No web search results available. Please try again.", ""
|
521 |
-
return
|
522 |
-
|
523 |
-
accumulated_response = ""
|
524 |
-
|
525 |
-
# Split the search results into separate documents
|
526 |
-
documents = search_results.split("------------------------------------------------------------")
|
527 |
-
|
528 |
-
for i, doc in enumerate(documents, 1):
|
529 |
-
if not doc.strip(): # Skip empty documents
|
530 |
-
continue
|
531 |
-
|
532 |
-
# Extract title, URL, and content from the document
|
533 |
-
title_start = doc.find("Website Title:") + len("Website Title:")
|
534 |
-
title_end = doc.find("===========", title_start)
|
535 |
-
title = doc[title_start:title_end].strip()
|
536 |
-
|
537 |
-
url_start = doc.find("Website URL:") + len("Website URL:")
|
538 |
-
url_end = doc.find("===========", url_start)
|
539 |
-
source = doc[url_start:url_end].strip()
|
540 |
-
|
541 |
-
content_start = doc.find("Website Content") + len("Website Content ===========")
|
542 |
-
content_end = doc.find("Website Content End")
|
543 |
-
context = doc[content_start:content_end].strip()
|
544 |
-
|
545 |
-
prompt = f"""Using the following context from a web search result:
|
546 |
{context}
|
547 |
-
|
548 |
-
|
549 |
-
|
550 |
-
|
551 |
-
|
552 |
-
|
553 |
-
|
554 |
-
|
555 |
-
|
556 |
-
|
557 |
-
|
558 |
-
|
559 |
-
|
560 |
-
|
561 |
-
|
562 |
-
|
563 |
-
source_response = ""
|
564 |
-
for message in client.chat_completion(
|
565 |
-
messages=[{"role": "user", "content": prompt}],
|
566 |
-
max_tokens=10000,
|
567 |
-
temperature=temperature,
|
568 |
-
stream=True,
|
569 |
-
):
|
570 |
-
if message.choices and message.choices[0].delta and message.choices[0].delta.content:
|
571 |
-
chunk = message.choices[0].delta.content
|
572 |
-
source_response += chunk
|
573 |
-
accumulated_response += f"Source {i} ({source}):\n\n{source_response}\n\n"
|
574 |
-
yield accumulated_response, ""
|
575 |
-
|
576 |
-
# Generate an overall summary after processing all sources
|
577 |
-
overall_prompt = f"""Based on the summaries you've generated for each source: '{accumulated_response}', provide a concise overall summary that addresses the user's query: '{query}'
|
578 |
-
Highlight any conflicting information or gaps in the available data."""
|
579 |
|
580 |
-
|
581 |
-
|
582 |
-
overall_response = ""
|
583 |
-
for response in get_response_from_cloudflare(prompt="", context="", query=overall_prompt, num_calls=1, temperature=temperature, search_type="web"):
|
584 |
-
overall_response += response
|
585 |
-
accumulated_response += f"Overall Summary:\n\n{overall_response}\n\n"
|
586 |
-
yield accumulated_response, ""
|
587 |
-
else:
|
588 |
-
# Use Hugging Face API for overall summary
|
589 |
-
overall_summary = ""
|
590 |
for message in client.chat_completion(
|
591 |
-
messages=[{"role": "user", "content":
|
592 |
max_tokens=10000,
|
593 |
temperature=temperature,
|
594 |
stream=True,
|
595 |
):
|
596 |
if message.choices and message.choices[0].delta and message.choices[0].delta.content:
|
597 |
chunk = message.choices[0].delta.content
|
598 |
-
|
599 |
-
|
600 |
-
yield accumulated_response, ""
|
601 |
|
602 |
def get_response_from_pdf(query, model, selected_docs, num_calls=3, temperature=0.2):
|
603 |
logging.info(f"Entering get_response_from_pdf with query: {query}, model: {model}, selected_docs: {selected_docs}")
|
@@ -611,7 +469,6 @@ def get_response_from_pdf(query, model, selected_docs, num_calls=3, temperature=
|
|
611 |
yield "No documents available. Please upload PDF documents to answer questions."
|
612 |
return
|
613 |
|
614 |
-
# Pre-filter the documents
|
615 |
filtered_docs = []
|
616 |
for doc_id, doc in database.docstore._dict.items():
|
617 |
if isinstance(doc, Document) and doc.metadata.get("source") in selected_docs:
|
@@ -624,7 +481,6 @@ def get_response_from_pdf(query, model, selected_docs, num_calls=3, temperature=
|
|
624 |
yield "No relevant information found in the selected documents. Please try selecting different documents or rephrasing your query."
|
625 |
return
|
626 |
|
627 |
-
# Create a new FAISS index with only the selected documents
|
628 |
filtered_db = FAISS.from_documents(filtered_docs, embed)
|
629 |
|
630 |
retriever = filtered_db.as_retriever(search_kwargs={"k": 10})
|
@@ -632,40 +488,20 @@ def get_response_from_pdf(query, model, selected_docs, num_calls=3, temperature=
|
|
632 |
relevant_docs = retriever.get_relevant_documents(query)
|
633 |
logging.info(f"Number of relevant documents retrieved: {len(relevant_docs)}")
|
634 |
|
635 |
-
for doc in relevant_docs:
|
636 |
-
logging.info(f"Document source: {doc.metadata['source']}")
|
637 |
-
logging.info(f"Document content preview: {doc.page_content[:100]}...") # Log first 100 characters of each document
|
638 |
-
|
639 |
context_str = "\n".join([doc.page_content for doc in relevant_docs])
|
640 |
logging.info(f"Total context length: {len(context_str)}")
|
641 |
|
642 |
-
|
643 |
-
logging.info("Using Cloudflare API")
|
644 |
-
# Use Cloudflare API with the retrieved context
|
645 |
-
for response in get_response_from_cloudflare(prompt="", context=context_str, query=query, num_calls=num_calls, temperature=temperature, search_type="pdf"):
|
646 |
-
yield response
|
647 |
-
else:
|
648 |
-
logging.info("Using Hugging Face API")
|
649 |
-
# Use Hugging Face API
|
650 |
-
prompt = f"""Using the following context from the PDF documents:
|
651 |
{context_str}
|
652 |
Write a detailed and complete response that answers the following user question: '{query}'"""
|
653 |
-
|
654 |
-
|
655 |
-
|
656 |
-
response
|
657 |
-
|
658 |
-
|
659 |
-
|
660 |
-
|
661 |
-
max_tokens=10000,
|
662 |
-
temperature=temperature,
|
663 |
-
stream=True,
|
664 |
-
):
|
665 |
-
if message.choices and message.choices[0].delta and message.choices[0].delta.content:
|
666 |
-
chunk = message.choices[0].delta.content
|
667 |
-
response += chunk
|
668 |
-
yield response # Yield partial response
|
669 |
|
670 |
logging.info("Finished generating response")
|
671 |
|
@@ -807,4 +643,4 @@ with demo:
|
|
807 |
)
|
808 |
|
809 |
if __name__ == "__main__":
|
810 |
-
demo.launch(share=True)
|
|
|
18 |
import inspect
|
19 |
import logging
|
20 |
import shutil
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
21 |
|
22 |
|
23 |
# Set up basic configuration for logging
|
|
|
271 |
print(f"Final clean response: {final_response[:100]}...")
|
272 |
return final_response
|
273 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
274 |
def duckduckgo_search(query):
|
275 |
+
with DDGS() as ddgs:
|
276 |
+
results = ddgs.text(query, max_results=5)
|
277 |
+
return results
|
278 |
|
279 |
class CitingSources(BaseModel):
|
280 |
sources: List[str] = Field(
|
|
|
307 |
|
308 |
return chatbot_interface(last_user_msg, history, use_web_search, model, temperature, num_calls)
|
309 |
|
310 |
+
from duckduckgo_search import DDGS
|
311 |
+
|
312 |
+
def respond(message, history, use_web_search, model, temperature, num_calls, selected_docs):
|
313 |
logging.info(f"User Query: {message}")
|
|
|
314 |
logging.info(f"Search Type: {'Web Search' if use_web_search else 'PDF Search'}")
|
|
|
315 |
logging.info(f"Selected Documents: {selected_docs}")
|
316 |
|
317 |
try:
|
318 |
if use_web_search:
|
319 |
for main_content, sources in get_response_with_search(message, model, num_calls=num_calls, temperature=temperature):
|
320 |
response = f"{main_content}\n\n{sources}"
|
|
|
|
|
321 |
yield response
|
322 |
else:
|
323 |
embed = get_embeddings()
|
|
|
325 |
database = FAISS.load_local("faiss_database", embed, allow_dangerous_deserialization=True)
|
326 |
retriever = database.as_retriever(search_kwargs={"k": 20})
|
327 |
|
|
|
328 |
all_relevant_docs = retriever.get_relevant_documents(message)
|
329 |
relevant_docs = [doc for doc in all_relevant_docs if doc.metadata["source"] in selected_docs]
|
330 |
|
|
|
338 |
yield "No documents available. Please upload PDF documents to answer questions."
|
339 |
return
|
340 |
|
341 |
+
prompt = f"""Using the following context from the PDF documents:
|
342 |
+
{context_str}
|
343 |
+
Write a detailed and complete response that answers the following user question: '{message}'"""
|
344 |
+
|
345 |
+
try:
|
346 |
+
response = DDGS().chat(prompt, model="llama-3-70b")
|
347 |
+
yield response
|
348 |
+
except Exception as e:
|
349 |
+
logging.error(f"Error with DuckDuckGo chat API: {str(e)}")
|
350 |
+
logging.info("Falling back to Hugging Face API")
|
351 |
+
yield from get_response_from_pdf(message, model, selected_docs, num_calls=num_calls, temperature=temperature)
|
352 |
+
|
353 |
except Exception as e:
|
354 |
+
logging.error(f"Error: {str(e)}")
|
355 |
+
yield f"An error occurred: {str(e)}. Please try again or select a different model."
|
|
|
|
|
|
|
|
|
|
|
356 |
|
357 |
logging.basicConfig(level=logging.DEBUG)
|
358 |
|
|
|
411 |
if not full_response:
|
412 |
yield "I apologize, but I couldn't generate a response at this time. Please try again later."
|
413 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
414 |
def create_web_search_vectors(search_results):
|
415 |
embed = get_embeddings()
|
416 |
|
417 |
documents = []
|
418 |
for result in search_results:
|
419 |
if 'body' in result:
|
420 |
+
content = f"{result['title']}\n{result['body']}\nSource: {result['href']}"
|
421 |
+
documents.append(Document(page_content=content, metadata={"source": result['href']}))
|
422 |
|
423 |
return FAISS.from_documents(documents, embed)
|
424 |
|
425 |
def get_response_with_search(query, model, num_calls=3, temperature=0.2):
|
426 |
search_results = duckduckgo_search(query)
|
427 |
+
context = "\n".join([f"{result['title']}\n{result['body']}" for result in search_results])
|
428 |
|
429 |
+
prompt = f"""Using the following context from web search results:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
430 |
{context}
|
431 |
+
You are an expert AI assistant, write a detailed and complete research document that fulfills the following user request: '{query}'
|
432 |
+
Base your entire response strictly on the information retrieved from trusted sources. Importantly, only include information that is directly supported by the retrieved content.
|
433 |
+
If any part of the information cannot be verified from the given sources, clearly state that it could not be confirmed.
|
434 |
+
After writing the document, please provide a list of sources used in your response."""
|
435 |
+
|
436 |
+
try:
|
437 |
+
response = DDGS().chat(prompt, model="llama-3-70b")
|
438 |
+
yield response, ""
|
439 |
+
except Exception as e:
|
440 |
+
logging.error(f"Error with DuckDuckGo chat API: {str(e)}")
|
441 |
+
logging.info("Falling back to Hugging Face API")
|
442 |
+
yield from get_response_from_huggingface(prompt, model, num_calls, temperature)
|
443 |
+
|
444 |
+
def get_response_from_huggingface(prompt, model, num_calls=3, temperature=0.2):
|
445 |
+
client = InferenceClient(model, token=huggingface_token)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
446 |
|
447 |
+
main_content = ""
|
448 |
+
for i in range(num_calls):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
449 |
for message in client.chat_completion(
|
450 |
+
messages=[{"role": "user", "content": prompt}],
|
451 |
max_tokens=10000,
|
452 |
temperature=temperature,
|
453 |
stream=True,
|
454 |
):
|
455 |
if message.choices and message.choices[0].delta and message.choices[0].delta.content:
|
456 |
chunk = message.choices[0].delta.content
|
457 |
+
main_content += chunk
|
458 |
+
yield main_content, "" # Yield partial main content without sources
|
|
|
459 |
|
460 |
def get_response_from_pdf(query, model, selected_docs, num_calls=3, temperature=0.2):
|
461 |
logging.info(f"Entering get_response_from_pdf with query: {query}, model: {model}, selected_docs: {selected_docs}")
|
|
|
469 |
yield "No documents available. Please upload PDF documents to answer questions."
|
470 |
return
|
471 |
|
|
|
472 |
filtered_docs = []
|
473 |
for doc_id, doc in database.docstore._dict.items():
|
474 |
if isinstance(doc, Document) and doc.metadata.get("source") in selected_docs:
|
|
|
481 |
yield "No relevant information found in the selected documents. Please try selecting different documents or rephrasing your query."
|
482 |
return
|
483 |
|
|
|
484 |
filtered_db = FAISS.from_documents(filtered_docs, embed)
|
485 |
|
486 |
retriever = filtered_db.as_retriever(search_kwargs={"k": 10})
|
|
|
488 |
relevant_docs = retriever.get_relevant_documents(query)
|
489 |
logging.info(f"Number of relevant documents retrieved: {len(relevant_docs)}")
|
490 |
|
|
|
|
|
|
|
|
|
491 |
context_str = "\n".join([doc.page_content for doc in relevant_docs])
|
492 |
logging.info(f"Total context length: {len(context_str)}")
|
493 |
|
494 |
+
prompt = f"""Using the following context from the PDF documents:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
495 |
{context_str}
|
496 |
Write a detailed and complete response that answers the following user question: '{query}'"""
|
497 |
+
|
498 |
+
try:
|
499 |
+
response = DDGS().chat(prompt, model="llama-3-70b")
|
500 |
+
yield response
|
501 |
+
except Exception as e:
|
502 |
+
logging.error(f"Error with DuckDuckGo chat API: {str(e)}")
|
503 |
+
logging.info("Falling back to Hugging Face API")
|
504 |
+
yield from get_response_from_huggingface(prompt, model, num_calls, temperature)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
505 |
|
506 |
logging.info("Finished generating response")
|
507 |
|
|
|
643 |
)
|
644 |
|
645 |
if __name__ == "__main__":
|
646 |
+
demo.launch(share=True)
|