Leonardo commited on
Commit
b6141a9
·
verified ·
1 Parent(s): 17b14f2

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +280 -2
app.py CHANGED
@@ -256,6 +256,264 @@ def stream_to_gradio(
256
  )
257
 
258
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
259
  class GradioUI:
260
  """A one-line interface to launch your agent in Gradio."""
261
 
@@ -351,7 +609,26 @@ class GradioUI:
351
 
352
  def log_user_message(self, text_input, file_uploads_log):
353
  """Process user message and handle file references."""
354
- message = text_input
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
355
 
356
  if file_uploads_log:
357
  message += f"\nYou have been provided with these files, which might be helpful or not: {file_uploads_log}" # Added file list
@@ -464,7 +741,7 @@ class GradioUI:
464
  file_uploads_log = gr.State([])
465
 
466
  chatbot = gr.Chatbot(
467
- label="open-Deep-Research",
468
  type="messages",
469
  avatar_images=(
470
  None,
@@ -603,3 +880,4 @@ def main():
603
 
604
  if __name__ == "__main__":
605
  main()
 
 
256
  )
257
 
258
 
259
+ """Main application for the OpenDeepResearch Gradio interface."""
260
+
261
+ import mimetypes
262
+ import os
263
+ import re
264
+ import shutil
265
+ from typing import Optional
266
+
267
+ from dotenv import load_dotenv
268
+ from huggingface_hub import login
269
+ import gradio as gr
270
+
271
+ from scripts.text_inspector_tool import TextInspectorTool
272
+ from scripts.text_web_browser import (
273
+ ArchiveSearchTool,
274
+ FinderTool,
275
+ FindNextTool,
276
+ PageDownTool,
277
+ PageUpTool,
278
+ SimpleTextBrowser,
279
+ VisitTool,
280
+ )
281
+ from scripts.visual_qa import visualizer
282
+ from scripts.text_cleaner_tool import TextCleanerTool
283
+
284
+ from smolagents import (
285
+ CodeAgent,
286
+ HfApiModel,
287
+ LiteLLMModel,
288
+ OpenAIServerModel,
289
+ TransformersModel,
290
+ GoogleSearchTool,
291
+ Tool,
292
+ )
293
+ from smolagents.agent_types import AgentText, AgentImage, AgentAudio
294
+ from smolagents.gradio_ui import pull_messages_from_step, handle_agent_output_types
295
+
296
+
297
+ # Constants and configurations
298
+ AUTHORIZED_IMPORTS = [
299
+ "requests",
300
+ "zipfile",
301
+ "pandas",
302
+ "numpy",
303
+ "sympy",
304
+ "json",
305
+ "bs4",
306
+ "pubchempy",
307
+ "xml",
308
+ "yahoo_finance",
309
+ "Bio",
310
+ "sklearn",
311
+ "scipy",
312
+ "pydub",
313
+ "PIL",
314
+ "chess",
315
+ "PyPDF2",
316
+ "pptx",
317
+ "torch",
318
+ "datetime",
319
+ "fractions",
320
+ "csv",
321
+ "clean-text",
322
+ ]
323
+
324
+ USER_AGENT = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36 Edg/119.0.0.0"
325
+ BROWSER_CONFIG = {
326
+ "viewport_size": 1024 * 5,
327
+ "downloads_folder": "downloads_folder",
328
+ "request_kwargs": {
329
+ "headers": {"User-Agent": USER_AGENT},
330
+ "timeout": 300,
331
+ },
332
+ "serpapi_key": os.getenv("SERPAPI_API_KEY"),
333
+ }
334
+
335
+ CUSTOM_ROLE_CONVERSIONS = {"tool-call": "assistant", "tool-response": "user"}
336
+
337
+
338
+ ALLOWED_FILE_TYPES = [
339
+ "application/pdf",
340
+ "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
341
+ "text/plain",
342
+ "text/markdown", # Added Markdown support
343
+ "application/json", # Added JSON support
344
+ "image/png",
345
+ "image/webp",
346
+ "image/jpeg", # Added JPEG support
347
+ "image/gif", # Added GIF support
348
+ "video/mp4",
349
+ "audio/mpeg", # Added MP3 support
350
+ "audio/wav", # Added WAV support
351
+ "audio/ogg", # Added OGG support
352
+ ]
353
+
354
+
355
+ def setup_environment():
356
+ """Initialize environment variables and authentication."""
357
+ load_dotenv(override=True)
358
+ hf_token = os.getenv("HF_TOKEN")
359
+ if hf_token: # Check if token is actually set
360
+ login(hf_token)
361
+ print("HF_TOKEN (last 10 characters):", hf_token[-10:])
362
+ else:
363
+ print("HF_TOKEN not found in environment variables.")
364
+
365
+
366
+ class ModelManager:
367
+ """Manages model loading and initialization."""
368
+
369
+ @staticmethod
370
+ def load_model(chosen_inference: str, model_id: str, key_manager=None):
371
+ """Load the specified model with appropriate configuration."""
372
+ try:
373
+ if chosen_inference == "hf_api":
374
+ return HfApiModel(model_id=model_id)
375
+
376
+ if chosen_inference == "hf_api_provider":
377
+ return HfApiModel(provider="together")
378
+
379
+ if chosen_inference == "litellm":
380
+ return LiteLLMModel(model_id=model_id)
381
+
382
+ if chosen_inference == "openai":
383
+ if not key_manager:
384
+ raise ValueError("Key manager required for OpenAI model")
385
+ return OpenAIServerModel(
386
+ model_id=model_id, api_key=key_manager.get_key("openai_api_key")
387
+ )
388
+
389
+ if chosen_inference == "transformers":
390
+ return TransformersModel(
391
+ model_id="HuggingFaceTB/SmolLM2-1.7B-Instruct",
392
+ device_map="auto",
393
+ max_new_tokens=1000,
394
+ )
395
+
396
+ raise ValueError(f"Invalid inference type: {chosen_inference}")
397
+ except Exception as e:
398
+ print(f"✗ Couldn't load model: {e}")
399
+ raise
400
+
401
+
402
+ class ToolRegistry:
403
+ """Manages tool initialization and organization."""
404
+
405
+ @staticmethod
406
+ def load_web_tools(model, browser, text_limit=20000):
407
+ """Initialize and return web-related tools."""
408
+ return [
409
+ GoogleSearchTool(provider="serper"),
410
+ VisitTool(browser),
411
+ PageUpTool(browser),
412
+ PageDownTool(browser),
413
+ FinderTool(browser),
414
+ FindNextTool(browser),
415
+ ArchiveSearchTool(browser),
416
+ TextInspectorTool(model, text_limit),
417
+ ]
418
+
419
+ @staticmethod
420
+ def load_image_generation_tools():
421
+ """Initialize and return image generation tools."""
422
+ try:
423
+ return Tool.from_space(
424
+ space_id="xkerser/FLUX.1-dev",
425
+ name="image_generator",
426
+ description="Generates high-quality AgentImage with text prompt (77 token limit).",
427
+ )
428
+ except Exception as e:
429
+ print(f"✗ Couldn't initialize image generation tool: {e}")
430
+ raise
431
+
432
+ @staticmethod
433
+ def load_clean_text_tool():
434
+ """Initialize and return image generation tools."""
435
+ try:
436
+ return TextCleanerTool
437
+ except Exception as e:
438
+ print(f"✗ Couldn't initialize clean text tool: {e}")
439
+ raise
440
+
441
+
442
+ def create_agent():
443
+ """Creates a fresh agent instance with properly configured tools."""
444
+ # Initialize model
445
+ model = LiteLLMModel(
446
+ custom_role_conversions=CUSTOM_ROLE_CONVERSIONS,
447
+ model_id="openrouter/deepseek/deepseek-chat-v3-0324:free", # currently serving:
448
+ ) # DEEPSEEK = openrouter/perplexity/r1-1776 <--- boss model
449
+
450
+ # Initialize tools
451
+ text_limit = 30000
452
+ browser = SimpleTextBrowser(**BROWSER_CONFIG)
453
+
454
+ # Collect all tools in a single list
455
+ web_tools = ToolRegistry.load_web_tools(model, browser, text_limit)
456
+ image_generator = ToolRegistry.load_image_generation_tools()
457
+ clean_text = TextCleanerTool() # Instantiate TextCleanerTool
458
+
459
+ # Combine all tools into a single list (not a tuple)
460
+ all_tools = [visualizer] + web_tools + [image_generator] + [clean_text]
461
+
462
+ # Validate tools before creating agent
463
+ for tool in all_tools:
464
+ if not isinstance(tool, Tool):
465
+ raise ValueError(
466
+ "Invalid tool type: "
467
+ f"{type(tool)}. All tools must be instances of Tool class."
468
+ )
469
+
470
+ return CodeAgent(
471
+ model=model,
472
+ tools=all_tools, # Pass a single list containing all tools
473
+ max_steps=12,
474
+ verbosity_level=2,
475
+ additional_authorized_imports=AUTHORIZED_IMPORTS,
476
+ planning_interval=4,
477
+ )
478
+
479
+
480
+ def stream_to_gradio(
481
+ agent,
482
+ task: str,
483
+ reset_agent_memory: bool = False,
484
+ additional_args: Optional[dict] = None,
485
+ ):
486
+ """Runs an agent with the given task and streams messages as Gradio ChatMessages."""
487
+ for step_log in agent.run(
488
+ task, stream=True, reset=reset_agent_memory, additional_args=additional_args
489
+ ):
490
+ yield from pull_messages_from_step(step_log)
491
+
492
+ # Process final answer : Use a more comprehensive media output
493
+ final_answer = step_log # Last log is the run's final_answer
494
+ final_answer = handle_agent_output_types(final_answer)
495
+
496
+ if isinstance(final_answer, AgentText):
497
+ yield gr.ChatMessage(
498
+ role="assistant",
499
+ content=f"**Final answer:**\n{final_answer.to_string()}\n",
500
+ )
501
+ elif isinstance(final_answer, AgentImage):
502
+ yield gr.ChatMessage(
503
+ role="assistant",
504
+ content={"image": final_answer.to_string(), "type": "file"},
505
+ ) # Send as Gradio-compatible file object:
506
+ elif isinstance(final_answer, AgentAudio):
507
+ yield gr.ChatMessage(
508
+ role="assistant",
509
+ content={"audio": final_answer.to_string(), "type": "file"},
510
+ ) # Send as Gradio-compatible file object
511
+ else:
512
+ yield gr.ChatMessage(
513
+ role="assistant", content=f"**Final answer:** {str(final_answer)}"
514
+ )
515
+
516
+
517
  class GradioUI:
518
  """A one-line interface to launch your agent in Gradio."""
519
 
 
609
 
610
  def log_user_message(self, text_input, file_uploads_log):
611
  """Process user message and handle file references."""
612
+ # Clean the user input using the TextCleanerTool
613
+ from cleantext import clean
614
+
615
+ cleaned_message = clean(
616
+ text_input,
617
+ fix_unicode=True,
618
+ to_ascii=True,
619
+ lower=True,
620
+ no_line_breaks=False,
621
+ no_urls=False,
622
+ no_emails=False,
623
+ no_phone_numbers=False,
624
+ no_numbers=False,
625
+ no_digits=False,
626
+ no_currency_symbols=False,
627
+ no_punct=False,
628
+ lang="en",
629
+ ) # Can change default behaviour by instantiating an object of TextCleanerTool class.
630
+
631
+ message = cleaned_message # Use the cleaned message
632
 
633
  if file_uploads_log:
634
  message += f"\nYou have been provided with these files, which might be helpful or not: {file_uploads_log}" # Added file list
 
741
  file_uploads_log = gr.State([])
742
 
743
  chatbot = gr.Chatbot(
744
+ label="ODR",
745
  type="messages",
746
  avatar_images=(
747
  None,
 
880
 
881
  if __name__ == "__main__":
882
  main()
883
+