Spaces:
Running
Running
Update app.py
Browse files
app.py
CHANGED
@@ -15,6 +15,7 @@ import sys
|
|
15 |
import concurrent.futures
|
16 |
from concurrent.futures import ThreadPoolExecutor
|
17 |
import threading
|
|
|
18 |
|
19 |
# Import OpenAI library
|
20 |
import openai
|
@@ -80,7 +81,10 @@ if not GROQ_API_KEY:
|
|
80 |
logger.error("GROQ_API_KEY environment variable not set.")
|
81 |
|
82 |
openai.api_key = GROQ_API_KEY
|
83 |
-
openai.api_base = "https://api.groq.com/openai/v1"
|
|
|
|
|
|
|
84 |
|
85 |
# Global variables for models to enable lazy loading
|
86 |
embedding_model = None
|
@@ -168,21 +172,20 @@ def generate_summary_and_assign_category(bookmark):
|
|
168 |
"""
|
169 |
logger.info(f"Generating summary and assigning category for bookmark: {bookmark.get('url')}")
|
170 |
|
171 |
-
max_retries =
|
172 |
retry_count = 0
|
|
|
173 |
|
174 |
while retry_count < max_retries:
|
175 |
try:
|
176 |
html_content = bookmark.get('html_content', '')
|
177 |
|
178 |
-
#
|
179 |
soup = BeautifulSoup(html_content, 'html.parser')
|
180 |
-
|
181 |
-
# Extract metadata and main content
|
182 |
metadata = get_page_metadata(soup)
|
183 |
main_content = extract_main_content(soup)
|
184 |
|
185 |
-
# Prepare
|
186 |
content_parts = []
|
187 |
if metadata['title']:
|
188 |
content_parts.append(f"Title: {metadata['title']}")
|
@@ -195,18 +198,17 @@ def generate_summary_and_assign_category(bookmark):
|
|
195 |
|
196 |
content_text = '\n'.join(content_parts)
|
197 |
|
198 |
-
#
|
199 |
error_keywords = ['Access Denied', 'Security Check', 'Cloudflare', 'captcha', 'unusual traffic']
|
200 |
if not content_text or len(content_text.split()) < 50:
|
201 |
use_prior_knowledge = True
|
202 |
-
logger.info(f"Content for {bookmark.get('url')} is insufficient.
|
203 |
elif any(keyword.lower() in content_text.lower() for keyword in error_keywords):
|
204 |
use_prior_knowledge = True
|
205 |
-
logger.info(f"Content for {bookmark.get('url')} contains error messages.
|
206 |
else:
|
207 |
use_prior_knowledge = False
|
208 |
|
209 |
-
# Shortened prompts
|
210 |
if use_prior_knowledge:
|
211 |
prompt = f"""
|
212 |
You are a knowledgeable assistant with up-to-date information as of 2023.
|
@@ -235,52 +237,28 @@ Summary: [Your summary]
|
|
235 |
Category: [One category]
|
236 |
"""
|
237 |
|
238 |
-
#
|
239 |
-
|
240 |
-
|
241 |
-
|
242 |
-
|
243 |
-
|
244 |
-
|
245 |
-
|
246 |
-
|
247 |
-
|
248 |
-
tokens_per_second = tokens_per_minute / 60
|
249 |
-
required_delay = total_tokens / tokens_per_second
|
250 |
-
sleep_time = max(required_delay, 1)
|
251 |
-
|
252 |
-
# Call the LLM via Groq Cloud API
|
253 |
-
response = openai.ChatCompletion.create(
|
254 |
-
model='llama-3.1-70b-versatile', # Using the specified model
|
255 |
-
messages=[
|
256 |
-
{"role": "user", "content": prompt}
|
257 |
-
],
|
258 |
-
max_tokens=int(max_tokens),
|
259 |
-
temperature=0.5,
|
260 |
-
)
|
261 |
content = response['choices'][0]['message']['content'].strip()
|
262 |
if not content:
|
263 |
raise ValueError("Empty response received from the model.")
|
264 |
|
265 |
-
# Parse
|
266 |
summary_match = re.search(r"Summary:\s*(.*)", content)
|
267 |
category_match = re.search(r"Category:\s*(.*)", content)
|
268 |
|
269 |
-
if summary_match
|
270 |
-
|
271 |
-
else:
|
272 |
-
bookmark['summary'] = 'No summary available.'
|
273 |
-
|
274 |
-
if category_match:
|
275 |
-
category = category_match.group(1).strip().strip('"')
|
276 |
-
if category in CATEGORIES:
|
277 |
-
bookmark['category'] = category
|
278 |
-
else:
|
279 |
-
bookmark['category'] = 'Uncategorized'
|
280 |
-
else:
|
281 |
-
bookmark['category'] = 'Uncategorized'
|
282 |
|
283 |
-
#
|
284 |
summary_lower = bookmark['summary'].lower()
|
285 |
url_lower = bookmark['url'].lower()
|
286 |
if 'social media' in summary_lower or 'twitter' in summary_lower or 'x.com' in url_lower:
|
@@ -289,20 +267,23 @@ Category: [One category]
|
|
289 |
bookmark['category'] = 'Reference and Knowledge Bases'
|
290 |
|
291 |
logger.info("Successfully generated summary and assigned category")
|
292 |
-
|
293 |
-
break # Exit the retry loop upon success
|
294 |
|
295 |
except openai.error.RateLimitError as e:
|
296 |
retry_count += 1
|
297 |
-
wait_time =
|
298 |
-
logger.warning(f"Rate limit reached. Waiting for {wait_time} seconds before retrying...")
|
299 |
time.sleep(wait_time)
|
300 |
except Exception as e:
|
301 |
logger.error(f"Error generating summary and assigning category: {e}", exc_info=True)
|
302 |
-
# Ensure 'summary' is always set, even on failure
|
303 |
bookmark['summary'] = 'No summary available.'
|
304 |
bookmark['category'] = 'Uncategorized'
|
305 |
-
break # Exit
|
|
|
|
|
|
|
|
|
|
|
306 |
|
307 |
def parse_bookmarks(file_content):
|
308 |
"""
|
@@ -521,12 +502,12 @@ def process_uploaded_file(file, state_bookmarks):
|
|
521 |
|
522 |
# Fetch bookmark info concurrently
|
523 |
logger.info("Fetching URL info concurrently")
|
524 |
-
with ThreadPoolExecutor(max_workers=
|
525 |
executor.map(fetch_url_info, bookmarks)
|
526 |
|
527 |
# Generate summaries and assign categories
|
528 |
logger.info("Generating summaries and assigning categories")
|
529 |
-
with ThreadPoolExecutor(max_workers=
|
530 |
executor.map(generate_summary_and_assign_category, bookmarks)
|
531 |
|
532 |
# Log bookmarks to verify 'summary' and 'category' presence
|
@@ -725,15 +706,16 @@ Bookmarks:
|
|
725 |
Provide a concise and helpful response.
|
726 |
"""
|
727 |
|
728 |
-
# Call the LLM via Groq Cloud API
|
729 |
-
|
730 |
-
|
731 |
-
|
732 |
-
|
733 |
-
|
734 |
-
|
735 |
-
|
736 |
-
|
|
|
737 |
answer = response['choices'][0]['message']['content'].strip()
|
738 |
logger.info("Chatbot response generated")
|
739 |
return chat_history + [{"role": "user", "content": user_query}, {"role": "assistant", "content": answer}]
|
|
|
15 |
import concurrent.futures
|
16 |
from concurrent.futures import ThreadPoolExecutor
|
17 |
import threading
|
18 |
+
from ratelimiter import RateLimiter # Optional
|
19 |
|
20 |
# Import OpenAI library
|
21 |
import openai
|
|
|
81 |
logger.error("GROQ_API_KEY environment variable not set.")
|
82 |
|
83 |
openai.api_key = GROQ_API_KEY
|
84 |
+
openai.api_base = "https://api.groq.com/openai/v1" # Ensure this is the correct base URL
|
85 |
+
|
86 |
+
# Initialize rate limiter (optional, adjust based on rate limits)
|
87 |
+
llm_rate_limiter = RateLimiter(max_calls=20, period=60) # Example: 20 calls per minute
|
88 |
|
89 |
# Global variables for models to enable lazy loading
|
90 |
embedding_model = None
|
|
|
172 |
"""
|
173 |
logger.info(f"Generating summary and assigning category for bookmark: {bookmark.get('url')}")
|
174 |
|
175 |
+
max_retries = 5
|
176 |
retry_count = 0
|
177 |
+
base_wait = 1 # Initial wait time in seconds
|
178 |
|
179 |
while retry_count < max_retries:
|
180 |
try:
|
181 |
html_content = bookmark.get('html_content', '')
|
182 |
|
183 |
+
# Parse HTML content
|
184 |
soup = BeautifulSoup(html_content, 'html.parser')
|
|
|
|
|
185 |
metadata = get_page_metadata(soup)
|
186 |
main_content = extract_main_content(soup)
|
187 |
|
188 |
+
# Prepare prompt
|
189 |
content_parts = []
|
190 |
if metadata['title']:
|
191 |
content_parts.append(f"Title: {metadata['title']}")
|
|
|
198 |
|
199 |
content_text = '\n'.join(content_parts)
|
200 |
|
201 |
+
# Determine prompt type
|
202 |
error_keywords = ['Access Denied', 'Security Check', 'Cloudflare', 'captcha', 'unusual traffic']
|
203 |
if not content_text or len(content_text.split()) < 50:
|
204 |
use_prior_knowledge = True
|
205 |
+
logger.info(f"Content for {bookmark.get('url')} is insufficient. Using prior knowledge.")
|
206 |
elif any(keyword.lower() in content_text.lower() for keyword in error_keywords):
|
207 |
use_prior_knowledge = True
|
208 |
+
logger.info(f"Content for {bookmark.get('url')} contains error messages. Using prior knowledge.")
|
209 |
else:
|
210 |
use_prior_knowledge = False
|
211 |
|
|
|
212 |
if use_prior_knowledge:
|
213 |
prompt = f"""
|
214 |
You are a knowledgeable assistant with up-to-date information as of 2023.
|
|
|
237 |
Category: [One category]
|
238 |
"""
|
239 |
|
240 |
+
# Call the LLM via Groq Cloud API with rate limiting
|
241 |
+
with llm_rate_limiter:
|
242 |
+
response = openai.ChatCompletion.create(
|
243 |
+
model='llama-3.1-70b-versatile', # Ensure this is the correct model name
|
244 |
+
messages=[
|
245 |
+
{"role": "user", "content": prompt}
|
246 |
+
],
|
247 |
+
max_tokens=150,
|
248 |
+
temperature=0.5,
|
249 |
+
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
250 |
content = response['choices'][0]['message']['content'].strip()
|
251 |
if not content:
|
252 |
raise ValueError("Empty response received from the model.")
|
253 |
|
254 |
+
# Parse response
|
255 |
summary_match = re.search(r"Summary:\s*(.*)", content)
|
256 |
category_match = re.search(r"Category:\s*(.*)", content)
|
257 |
|
258 |
+
bookmark['summary'] = summary_match.group(1).strip() if summary_match else 'No summary available.'
|
259 |
+
bookmark['category'] = category_match.group(1).strip().strip('"') if category_match else 'Uncategorized'
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
260 |
|
261 |
+
# Additional validation (optional)
|
262 |
summary_lower = bookmark['summary'].lower()
|
263 |
url_lower = bookmark['url'].lower()
|
264 |
if 'social media' in summary_lower or 'twitter' in summary_lower or 'x.com' in url_lower:
|
|
|
267 |
bookmark['category'] = 'Reference and Knowledge Bases'
|
268 |
|
269 |
logger.info("Successfully generated summary and assigned category")
|
270 |
+
break # Exit loop on success
|
|
|
271 |
|
272 |
except openai.error.RateLimitError as e:
|
273 |
retry_count += 1
|
274 |
+
wait_time = base_wait * (2 ** retry_count) # Exponential backoff
|
275 |
+
logger.warning(f"Rate limit reached. Waiting for {wait_time} seconds before retrying... (Attempt {retry_count}/{max_retries})")
|
276 |
time.sleep(wait_time)
|
277 |
except Exception as e:
|
278 |
logger.error(f"Error generating summary and assigning category: {e}", exc_info=True)
|
|
|
279 |
bookmark['summary'] = 'No summary available.'
|
280 |
bookmark['category'] = 'Uncategorized'
|
281 |
+
break # Exit loop on non-rate limit errors
|
282 |
+
|
283 |
+
if retry_count == max_retries:
|
284 |
+
logger.error(f"Failed to generate summary for {bookmark.get('url')} after {max_retries} attempts.")
|
285 |
+
bookmark['summary'] = 'No summary available.'
|
286 |
+
bookmark['category'] = 'Uncategorized'
|
287 |
|
288 |
def parse_bookmarks(file_content):
|
289 |
"""
|
|
|
502 |
|
503 |
# Fetch bookmark info concurrently
|
504 |
logger.info("Fetching URL info concurrently")
|
505 |
+
with ThreadPoolExecutor(max_workers=5) as executor: # Reduced max_workers from 10 to 5
|
506 |
executor.map(fetch_url_info, bookmarks)
|
507 |
|
508 |
# Generate summaries and assign categories
|
509 |
logger.info("Generating summaries and assigning categories")
|
510 |
+
with ThreadPoolExecutor(max_workers=2) as executor: # Reduced max_workers from 3 to 2
|
511 |
executor.map(generate_summary_and_assign_category, bookmarks)
|
512 |
|
513 |
# Log bookmarks to verify 'summary' and 'category' presence
|
|
|
706 |
Provide a concise and helpful response.
|
707 |
"""
|
708 |
|
709 |
+
# Call the LLM via Groq Cloud API with rate limiting
|
710 |
+
with llm_rate_limiter:
|
711 |
+
response = openai.ChatCompletion.create(
|
712 |
+
model='llama-3.1-70b-versatile', # Ensure this is the correct model name
|
713 |
+
messages=[
|
714 |
+
{"role": "user", "content": prompt}
|
715 |
+
],
|
716 |
+
max_tokens=300,
|
717 |
+
temperature=0.7,
|
718 |
+
)
|
719 |
answer = response['choices'][0]['message']['content'].strip()
|
720 |
logger.info("Chatbot response generated")
|
721 |
return chat_history + [{"role": "user", "content": user_query}, {"role": "assistant", "content": answer}]
|