krinya commited on
Commit
1b8e582
Β·
1 Parent(s): cb6cec5

chore: commit all local changes

Browse files
src/sales_assistant/agent_main/tools_node.py CHANGED
@@ -15,6 +15,8 @@ load_dotenv()
15
  from ..agent_tools.execute_sql_query import execute_sql_query
16
  from ..agent_tools.get_exchange_rates import exchange_converter
17
  from ..agent_tools.create_quote import create_quote
 
 
18
 
19
 
20
  class ToolConfig(BaseModel):
@@ -67,7 +69,9 @@ def get_all_tools(config: Optional[ToolConfig] = None) -> List[BaseTool]:
67
  core_tools = [
68
  execute_sql_query,
69
  exchange_converter,
70
- create_quote
 
 
71
  ]
72
 
73
  # Create registry with validation
 
15
  from ..agent_tools.execute_sql_query import execute_sql_query
16
  from ..agent_tools.get_exchange_rates import exchange_converter
17
  from ..agent_tools.create_quote import create_quote
18
+ from ..agent_tools.tavily_search_tool import tavily_search_product_specs
19
+ from ..agent_tools.tavily_web_extract_tool import tavily_extract_product_content
20
 
21
 
22
  class ToolConfig(BaseModel):
 
69
  core_tools = [
70
  execute_sql_query,
71
  exchange_converter,
72
+ create_quote,
73
+ tavily_search_product_specs,
74
+ tavily_extract_product_content
75
  ]
76
 
77
  # Create registry with validation
src/sales_assistant/agent_tools/tavily_search_tool.py ADDED
@@ -0,0 +1,68 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Tavily Search Tool for finding product specifications and tech information.
3
+ https://python.langchain.com/docs/integrations/tools/tavily_search/
4
+ """
5
+ import os
6
+ import requests
7
+ from langchain_core.tools import tool
8
+ from pydantic import BaseModel, Field
9
+ from dotenv import load_dotenv
10
+
11
+ load_dotenv()
12
+
13
+ class TavilySearchInput(BaseModel):
14
+ """Input schema for Tavily search tool."""
15
+ query: str = Field(description="Search query for product specifications, comparisons, or technical details")
16
+
17
+ @tool(args_schema=TavilySearchInput)
18
+ def tavily_search_product_specs(query: str) -> str:
19
+ """
20
+ Search the web for product specifications, comparisons, and technical details.
21
+
22
+ Use this tool when:
23
+ - User asks for product comparisons
24
+ - User needs detailed specifications not available in database
25
+ - User wants latest product information or reviews
26
+ - User asks to compare products with competitors
27
+
28
+ Focus on tech specification sites, manufacturer websites, and review sites.
29
+ """
30
+ try:
31
+ api_key = os.getenv("TAVILY_API_KEY")
32
+ if not api_key:
33
+ return "Error: TAVILY_API_KEY not found in environment variables."
34
+
35
+ # Enhance query for better product spec results
36
+ enhanced_query = f"product specifications technical details {query}"
37
+
38
+ # Tavily API endpoint
39
+ url = "https://api.tavily.com/search"
40
+
41
+ payload = {
42
+ "api_key": api_key,
43
+ "query": enhanced_query,
44
+ "search_depth": "advanced",
45
+ "max_results": 5,
46
+ "include_answer": True
47
+ }
48
+
49
+ response = requests.post(url, json=payload)
50
+ response.raise_for_status()
51
+
52
+ data = response.json()
53
+ results = data.get("results", [])
54
+
55
+ if not results:
56
+ return "No search results found for the given query."
57
+
58
+ # Format results for the agent
59
+ formatted_results = "Web Search Results:\n\n"
60
+ for i, result in enumerate(results, 1):
61
+ formatted_results += f"{i}. **{result.get('title', 'No title')}**\n"
62
+ formatted_results += f" URL: {result.get('url', 'No URL')}\n"
63
+ formatted_results += f" Content: {result.get('content', 'No content')}\n\n"
64
+
65
+ return formatted_results
66
+
67
+ except Exception as e:
68
+ return f"Error performing search: {str(e)}"
src/sales_assistant/agent_tools/tavily_web_extract_tool.py ADDED
@@ -0,0 +1,61 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Tavily Web Extract Tool for extracting content from product specification pages.
3
+ https://python.langchain.com/docs/integrations/tools/tavily_extract/
4
+ """
5
+ import os
6
+ import requests
7
+ from langchain_core.tools import tool
8
+ from pydantic import BaseModel, Field
9
+ from dotenv import load_dotenv
10
+
11
+ load_dotenv()
12
+
13
+ class TavilyExtractInput(BaseModel):
14
+ """Input schema for Tavily web extract tool."""
15
+ url: str = Field(description="URL of the webpage to extract product specifications from")
16
+
17
+ @tool(args_schema=TavilyExtractInput)
18
+ def tavily_extract_product_content(url: str) -> str:
19
+ """
20
+ Extract content from product specification pages and tech review sites.
21
+
22
+ Use this tool when:
23
+ - You have found relevant URLs from tavily_search_product_specs
24
+ - User wants detailed content from a specific product page
25
+ - Need to extract specifications from manufacturer websites
26
+ - Want to get full content from tech review articles
27
+
28
+ Extracts clean, readable content focused on product specifications.
29
+ """
30
+ try:
31
+ api_key = os.getenv("TAVILY_API_KEY")
32
+ if not api_key:
33
+ return "Error: TAVILY_API_KEY not found in environment variables."
34
+
35
+ # Tavily Extract API endpoint
36
+ extract_url = "https://api.tavily.com/extract"
37
+
38
+ payload = {
39
+ "api_key": api_key,
40
+ "urls": [url]
41
+ }
42
+
43
+ response = requests.post(extract_url, json=payload)
44
+ response.raise_for_status()
45
+
46
+ data = response.json()
47
+ results = data.get("results", [])
48
+
49
+ if not results:
50
+ return f"No content could be extracted from the URL: {url}"
51
+
52
+ # Format extracted content
53
+ extracted_content = results[0]
54
+ formatted_content = f"**Extracted Content from: {url}**\n\n"
55
+ formatted_content += f"**Title:** {extracted_content.get('title', 'No title')}\n\n"
56
+ formatted_content += f"**Content:**\n{extracted_content.get('raw_content', 'No content available')}\n"
57
+
58
+ return formatted_content
59
+
60
+ except Exception as e:
61
+ return f"Error extracting content from {url}: {str(e)}"
src/sales_assistant/prompts/system_prompt.py CHANGED
@@ -38,6 +38,16 @@ Help users explore products in a MySQL database and provide comprehensive sales
38
  - Use create_quote tool for generating professional quotes with customer information
39
  - Both tools have detailed descriptions with examples
40
 
 
 
 
 
 
 
 
 
 
 
41
  <thinking>
42
  Remember: Your tools already contain detailed descriptions and examples.
43
  Focus on reasoning through the user's request and choosing the right tool with appropriate parameters.
@@ -49,6 +59,7 @@ Focus on reasoning through the user's request and choosing the right tool with a
49
  - or if a user asks for shorter answer you can leave out some of the fields.
50
  - description can be summarized do not write out what is there use your common senese
51
  - Use LIMITS in your SQL queries to avoid overwhelming results to use less tokens, if you need more results you can always ask for more.
 
52
 
53
  ## Different manufacturers categorize differently e.g.:
54
  - This is why you need to be creative with SQL queries and start broad to look at the categories and sub_categories used by different manufacturers
 
38
  - Use create_quote tool for generating professional quotes with customer information
39
  - Both tools have detailed descriptions with examples
40
 
41
+ ## Web Search for Product Information (Use Sparingly, Carefully, try to limit to 1, max 2 searches per conversation)
42
+ - Use `tavily_search_product_specs` only when user specifically asks for:
43
+ * Product comparisons explicitly
44
+ * Some info is missing from database
45
+ * Detailed specifications not available in database
46
+ * Latest product reviews or information
47
+ - Use `tavily_extract_product_content` to get full content from specific URLs found in search (this is the most costly tool, limit usage)
48
+ - **Always prioritize database information first** - only use web search when database lacks needed details or you need to confirm specifics or when you need to compare products
49
+ - Focus searches on tech specification sites and manufacturer websites
50
+
51
  <thinking>
52
  Remember: Your tools already contain detailed descriptions and examples.
53
  Focus on reasoning through the user's request and choosing the right tool with appropriate parameters.
 
59
  - or if a user asks for shorter answer you can leave out some of the fields.
60
  - description can be summarized do not write out what is there use your common senese
61
  - Use LIMITS in your SQL queries to avoid overwhelming results to use less tokens, if you need more results you can always ask for more.
62
+ - you can use markdown formatting to make the answers more readable e.g for product comparisions you can create a table
63
 
64
  ## Different manufacturers categorize differently e.g.:
65
  - This is why you need to be creative with SQL queries and start broad to look at the categories and sub_categories used by different manufacturers
src/sales_assistant/ui_dashboard/gradio_app.py CHANGED
@@ -261,6 +261,7 @@ class SalesAssistantChat:
261
  def get_intermediate_logs(self) -> str:
262
  """Get console logs for intermediate updates."""
263
  return self.get_console_logs()
 
264
  def create_chat_assistant():
265
  """Create a new chat assistant instance for a session."""
266
  return SalesAssistantChat()
@@ -391,28 +392,6 @@ def create_gradio_interface():
391
  )
392
  send_btn = gr.Button("Send", variant="primary", scale=1)
393
 
394
- # Console logs section
395
- with gr.Accordion("πŸ” Console Logs & Processing Info", open=False):
396
- console_display = gr.Textbox(
397
- value="Console logs will appear here...",
398
- label="Real-time Processing Logs",
399
- lines=20,
400
- max_lines=30,
401
- interactive=False,
402
- elem_classes=["console-logs"],
403
- show_copy_button=True,
404
- autoscroll=True
405
- )
406
-
407
- with gr.Row():
408
- refresh_logs_btn = gr.Button("πŸ”„ Refresh Logs", variant="secondary", scale=1)
409
- clear_logs_btn = gr.Button("πŸ—‘οΈ Clear Logs", variant="secondary", scale=1)
410
- auto_refresh_checkbox = gr.Checkbox(
411
- label="Auto-refresh logs (every 2 seconds)",
412
- value=False,
413
- scale=1
414
- )
415
-
416
  # Example queries
417
  with gr.Row():
418
  gr.Examples(
@@ -428,6 +407,28 @@ def create_gradio_interface():
428
  inputs=msg_input,
429
  label="Example Questions"
430
  )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
431
 
432
  # Generated Quotes Tab
433
  with gr.TabItem("πŸ“„ Generated Quotes", id="quotes_tab"):
 
261
  def get_intermediate_logs(self) -> str:
262
  """Get console logs for intermediate updates."""
263
  return self.get_console_logs()
264
+
265
  def create_chat_assistant():
266
  """Create a new chat assistant instance for a session."""
267
  return SalesAssistantChat()
 
392
  )
393
  send_btn = gr.Button("Send", variant="primary", scale=1)
394
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
395
  # Example queries
396
  with gr.Row():
397
  gr.Examples(
 
407
  inputs=msg_input,
408
  label="Example Questions"
409
  )
410
+
411
+ # Console logs section
412
+ with gr.Accordion("πŸ” Console Logs & Processing Info", open=False):
413
+ console_display = gr.Textbox(
414
+ value="Console logs will appear here...",
415
+ label="Real-time Processing Logs",
416
+ lines=20,
417
+ max_lines=30,
418
+ interactive=False,
419
+ elem_classes=["console-logs"],
420
+ show_copy_button=True,
421
+ autoscroll=True
422
+ )
423
+
424
+ with gr.Row():
425
+ refresh_logs_btn = gr.Button("πŸ”„ Refresh Logs", variant="secondary", scale=1)
426
+ clear_logs_btn = gr.Button("πŸ—‘οΈ Clear Logs", variant="secondary", scale=1)
427
+ auto_refresh_checkbox = gr.Checkbox(
428
+ label="Auto-refresh logs (every 2 seconds)",
429
+ value=False,
430
+ scale=1
431
+ )
432
 
433
  # Generated Quotes Tab
434
  with gr.TabItem("πŸ“„ Generated Quotes", id="quotes_tab"):