CoolFace
Apppublic

nynuzz/SamyAgent

sourceHugging Facemitupdated 1y agoView on Hugging Face
0likes
web_search_tools.py190 linesDownload Raw Back to root
1import os
2from dotenv import load_dotenv
3from urllib.parse import unquote
4import tempfile
5import wikipedia
6from playwright.sync_api import sync_playwright, TimeoutError
7import bs4
8import pandas as pd
9
10from langchain_openai import ChatOpenAI
11from langchain_community.document_loaders import UnstructuredHTMLLoader
12from langchain_google_community import GoogleSearchAPIWrapper
13from langchain_community.utilities import ArxivAPIWrapper
14from langchain_core.tools import tool
15
16
17# Carica le variabili d'ambiente per i tool
18load_dotenv()
19OPENAI_API_KEY = os.getenv("OPENAI_API_KEY")
20OPENAI_API_MODEL = os.getenv("OPENAI_API_MODEL")
21GOOGLE_API_KEY = os.getenv("GOOGLE_API_KEY")
22GOOGLE_CSE_ID = os.getenv("GOOGLE_CSE_ID")
23
24# --- Tool di Ricerca Google ---
25@tool("google_search_tool")
26def google_search_tool(query: str) -> str:
27    """
28    Performs a Google search and returns the top results.
29    Use this for general web searches, finding articles, or recent information.
30    """
31    print(f"--- TOOL: Executing Google Search for: '{query}' ---")
32    google_search = GoogleSearchAPIWrapper(google_api_key=GOOGLE_API_KEY, google_cse_id=GOOGLE_CSE_ID)
33    return google_search.results(query, num_results=3)
34
35
36# --- Tool di Ricerca Wikipedia ---
37@tool("wikipedia_search_tool")
38def wikipedia_search_tool(query_or_url: str, max_results: int = 1) -> str:
39    """
40    Fetches content from a Wikipedia page. This tool is dual-purpose:
41    1. If the input is a search query, it finds the most relevant Wikipedia page and returns its full content.
42    2. If the input is a full Wikipedia URL, it directly fetches and returns the content of that page.
43    
44    This is the preferred tool for all interactions with Wikipedia.
45
46    Args:
47        query_or_url (str): A search query (e.g., "Mercedes Sosa discography") or a full Wikipedia URL.
48    """
49    print(f"--- WIKIPEDIA TOOL (Dual-Purpose): Input is '{query_or_url}' ---")
50    
51    wikipedia.set_lang("en")
52    
53    page_title = ""
54
55    try:
56        # --- LOGICA DI DECISIONE E DECODIFICA ---
57        if query_or_url.startswith("http://") or query_or_url.startswith("https://"):
58            # Caso 1: L'input è un URL
59            # Estraiamo l'ultima parte dell'URL
60            raw_title = query_or_url.split('/')[-1]
61            
62            # CORREZIONE: Decodifica i caratteri speciali (es. %C4%85 -> ą)
63            # e sostituisci gli underscore con spazi.
64            page_title = unquote(raw_title).replace('_', ' ')
65            
66            print(f"Input is a URL. Decoded page title: '{page_title}'")
67            page = wikipedia.page(page_title, auto_suggest=False, redirect=True)
68        else:
69            # Caso 2: L'input è una query di ricerca
70            print("Input is a search query. Finding best page...")
71            search_results = wikipedia.search(query_or_url, results=1)
72            if not search_results:
73                return f"Error: No Wikipedia page found for query '{query_or_url}'."
74            page_title = search_results[0]
75            page = wikipedia.page(page_title, auto_suggest=False, redirect=True)
76            
77        # --- ESTRAZIONE HTML E PARSING (invariato) ---
78        print(f"Fetching HTML for page: '{page.title}'")
79        html_content_str = page.html()
80
81        with tempfile.NamedTemporaryFile(mode='w', delete=False, suffix=".html", encoding='utf-8') as temp_file:
82            temp_file.write(html_content_str)
83            temp_filepath = temp_file.name
84
85        try:
86            loader = UnstructuredHTMLLoader(temp_filepath, strategy="fast")
87            docs = loader.load()
88        finally:
89            os.remove(temp_filepath)
90
91        if not docs:
92            return f"Content from Wikipedia page '{page.title}': Could not extract any content."
93
94        page_content = docs[0].page_content
95        formatted_output = f"Content from Wikipedia page: '{page.title}'\nURL: {page.url}\n\n{page_content[:20000]}"
96        return formatted_output
97
98    except wikipedia.exceptions.DisambiguationError as e:
99        return f"Error: Your query '{query_or_url}' is ambiguous. Options: {e.options[:5]}"
100    except wikipedia.exceptions.PageError:
101        return f"Error: Could not find or load the Wikipedia page for title derived from '{query_or_url}'."
102    except Exception as e:
103        return f"An unexpected error occurred in the Wikipedia tool: {e}"
104    
105
106# --- Tool di Navigazione ---
107@tool("browse_web_page_tool")
108def browse_web_page_tool(url: str) -> str:
109    """
110    Navigates a web page using a headless browser, then uses Unstructured to extract
111    the full, clean content, including text and tables.
112
113    Args:
114        url (str): The full URL of the page to browse and extract content from.
115    """
116    print(f"--- TOOL: Browsing and extracting from: {url} ---")
117    
118    try:
119        # 1. Usa Playwright per ottenere l'HTML completo
120        with sync_playwright() as p:
121            browser = p.chromium.launch(headless=True)
122            page = browser.new_page()
123            page.goto(url, timeout=30000, wait_until="domcontentloaded")
124            html_content = page.content()
125            browser.close()
126
127        # 2. Usa un file temporaneo IN MEMORIA per passare l'HTML a Unstructured
128        # Questo evita di scrivere su disco, è veloce e pulito.
129        with tempfile.NamedTemporaryFile(mode='w', delete=False, suffix=".html", encoding='utf-8') as temp_file:
130            temp_file.write(html_content)
131            temp_filepath = temp_file.name
132
133        try:
134            # 3. Carica e parsa l'HTML con UnstructuredFileLoader
135            loader = UnstructuredHTMLLoader(temp_filepath, strategy="fast")
136            docs = loader.load()
137        finally:
138            # Assicurati di cancellare sempre il file temporaneo
139            os.remove(temp_filepath)
140
141        # 4. Formatta l'output
142        if not docs:
143            return f"Content from URL '{url}': Could not extract any content using Unstructured."
144
145        # Unstructured di solito mette tutto in un unico documento
146        page_content = docs[0].page_content
147        
148        formatted_output = f"Content from URL: '{url}'\n\n{page_content[:20000]}"
149                
150        return formatted_output
151
152    except TimeoutError:
153        return f"Error browsing '{url}': The page took too long to load and timed out."
154    except Exception as e:
155        return f"An unexpected error occurred while browsing '{url}': {e}"
156    
157
158# --- Tool di analisi del contenuto web ---
159@tool("text_analyzer_tool")
160def text_analyzer_tool(text_to_analyze: str, question: str) -> str:
161    """
162    Analyzes a given text to answer a specific question or extract information.
163    Use this tool when you have already gathered content (e.g., from browsing a page)
164    and need to find a specific answer within that text.
165
166    Args:
167        text_to_analyze (str): The text content to be analyzed.
168        question (str): The specific question to answer based on the text.
169    """
170    print(f"--- TOOL: Analyzing text to answer: '{question}' ---")
171    
172    # Usiamo un LLM per fare l'analisi
173    analyzer_llm = ChatOpenAI(model=OPENAI_API_MODEL, temperature=0)
174    
175    prompt = f"""
176        You are a text analysis expert. Your task is to carefully read the provided text and answer the user's question based ONLY on that text.
177        Provide a concise and direct answer.
178
179        **Text to Analyze:**
180        ---
181        {text_to_analyze}
182        ---
183
184        **Question to Answer:**
185        "{question}"
186
187        Your concise answer:
188    """
189    response = analyzer_llm.invoke(prompt)
190    return response.content