Commit
·
e3e7ab8
1
Parent(s):
9cb2bd5
first
Browse files- .gitignore +157 -0
- app.py +163 -6
- gradio_ui.py +8 -7
- requirements.txt +2 -3
- system_prompt.py +19 -0
.gitignore
ADDED
@@ -0,0 +1,157 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# Byte-compiled / optimized / DLL files
|
2 |
+
__pycache__/
|
3 |
+
*.py[cod]
|
4 |
+
*$py.class
|
5 |
+
*.pyc
|
6 |
+
|
7 |
+
# C extensions
|
8 |
+
*.so
|
9 |
+
|
10 |
+
# Distribution / packaging
|
11 |
+
.Python
|
12 |
+
build/
|
13 |
+
develop-eggs/
|
14 |
+
dist/
|
15 |
+
downloads/
|
16 |
+
.eggs/
|
17 |
+
.eggs/
|
18 |
+
lib/
|
19 |
+
lib64/
|
20 |
+
parts/
|
21 |
+
sdist/
|
22 |
+
var/
|
23 |
+
wheels/
|
24 |
+
*.egg-info/
|
25 |
+
.installed.cfg
|
26 |
+
*.egg
|
27 |
+
MANIFEST
|
28 |
+
|
29 |
+
# PyInstaller
|
30 |
+
*.manifest
|
31 |
+
*.spec
|
32 |
+
|
33 |
+
# Installer logs
|
34 |
+
pip-log.txt
|
35 |
+
pip-delete-this-directory.txt
|
36 |
+
|
37 |
+
# Unit test / coverage reports
|
38 |
+
htmlcov/
|
39 |
+
.tox/
|
40 |
+
.nox/
|
41 |
+
.coverage
|
42 |
+
.coverage.*
|
43 |
+
.cache
|
44 |
+
nosetests.xml
|
45 |
+
coverage.xml
|
46 |
+
*.cover
|
47 |
+
*.py,cover
|
48 |
+
.hypothesis/
|
49 |
+
.pytest_cache/
|
50 |
+
cover/
|
51 |
+
|
52 |
+
# Translations
|
53 |
+
*.mo
|
54 |
+
*.pot
|
55 |
+
|
56 |
+
# Django stuff:
|
57 |
+
*.log
|
58 |
+
local_settings.py
|
59 |
+
db.sqlite3
|
60 |
+
db.sqlite3-journal
|
61 |
+
|
62 |
+
# Flask stuff:
|
63 |
+
instance/
|
64 |
+
.webassets-cache
|
65 |
+
|
66 |
+
# Scrapy stuff:
|
67 |
+
.scrapy
|
68 |
+
|
69 |
+
# Sphinx documentation
|
70 |
+
docs/_build/
|
71 |
+
|
72 |
+
# PyBuilder
|
73 |
+
.pybuilder/
|
74 |
+
target/
|
75 |
+
|
76 |
+
# Jupyter Notebook
|
77 |
+
.ipynb_checkpoints
|
78 |
+
|
79 |
+
# IPython
|
80 |
+
profile_default/
|
81 |
+
ipython_config.py
|
82 |
+
|
83 |
+
# pyenv
|
84 |
+
.python-version
|
85 |
+
|
86 |
+
# pipenv
|
87 |
+
Pipfile.lock
|
88 |
+
|
89 |
+
# poetry
|
90 |
+
poetry.lock
|
91 |
+
|
92 |
+
# Environments
|
93 |
+
.env
|
94 |
+
.venv
|
95 |
+
env/
|
96 |
+
venv/
|
97 |
+
ENV/
|
98 |
+
env.bak/
|
99 |
+
venv.bak/
|
100 |
+
|
101 |
+
# Spyder project settings
|
102 |
+
.spyderproject
|
103 |
+
.spyproject
|
104 |
+
|
105 |
+
# Rope project settings
|
106 |
+
.ropeproject
|
107 |
+
|
108 |
+
# mkdocs documentation
|
109 |
+
/site
|
110 |
+
|
111 |
+
# mypy
|
112 |
+
.mypy_cache/
|
113 |
+
.dmypy.json
|
114 |
+
dmypy.json
|
115 |
+
|
116 |
+
# Pyre type checker
|
117 |
+
.pyre/
|
118 |
+
|
119 |
+
# pytype static type analyzer
|
120 |
+
.pytype/
|
121 |
+
|
122 |
+
# Cython debug symbols
|
123 |
+
cython_debug/
|
124 |
+
|
125 |
+
# PyCharm
|
126 |
+
.idea/
|
127 |
+
|
128 |
+
# VS Code
|
129 |
+
.vscode/
|
130 |
+
|
131 |
+
# Operating System
|
132 |
+
.DS_Store
|
133 |
+
.DS_Store?
|
134 |
+
._*
|
135 |
+
.Spotlight-V100
|
136 |
+
.Trashes
|
137 |
+
ehthumbs.db
|
138 |
+
Thumbs.db
|
139 |
+
|
140 |
+
# Temporary files
|
141 |
+
*.tmp
|
142 |
+
*.temp
|
143 |
+
|
144 |
+
# Gradio
|
145 |
+
.gradio/
|
146 |
+
|
147 |
+
# Flask instance folder
|
148 |
+
instance/
|
149 |
+
|
150 |
+
# API keys and sensitive data
|
151 |
+
*.key
|
152 |
+
secrets.json
|
153 |
+
config.ini
|
154 |
+
|
155 |
+
# Log files
|
156 |
+
*.log
|
157 |
+
logs/
|
app.py
CHANGED
@@ -1,7 +1,164 @@
|
|
1 |
-
from smolagents import VisitWebpageTool, InferenceClientModel, CodeAgent,
|
2 |
-
from
|
|
|
|
|
|
|
|
|
|
|
3 |
|
4 |
-
|
5 |
-
|
6 |
-
|
7 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from smolagents import VisitWebpageTool, InferenceClientModel, CodeAgent, WebSearchTool, tool
|
2 |
+
from flask import Flask, request, jsonify
|
3 |
+
from crawl4ai import AsyncWebCrawler, CrawlerRunConfig
|
4 |
+
from crawl4ai.deep_crawling import BFSDeepCrawlStrategy
|
5 |
+
from crawl4ai.content_scraping_strategy import LXMLWebScrapingStrategy
|
6 |
+
from system_prompt import get_system_prompt
|
7 |
+
import xml.etree.ElementTree as ET
|
8 |
|
9 |
+
app = Flask(__name__)
|
10 |
+
|
11 |
+
model = InferenceClientModel(model_id="meta-llama/Llama-3.3-70B-Instruct", provider="together")
|
12 |
+
crawler_config = CrawlerRunConfig(
|
13 |
+
deep_crawl_strategy=BFSDeepCrawlStrategy(
|
14 |
+
max_depth=0,
|
15 |
+
include_external=False
|
16 |
+
),
|
17 |
+
scraping_strategy=LXMLWebScrapingStrategy(),
|
18 |
+
verbose=True
|
19 |
+
)
|
20 |
+
|
21 |
+
def extract_vehicle_info_as_string(adf_xml):
|
22 |
+
root = ET.fromstring(adf_xml)
|
23 |
+
|
24 |
+
# Find the vehicle element
|
25 |
+
vehicle = root.find('.//vehicle')
|
26 |
+
|
27 |
+
if vehicle is not None:
|
28 |
+
year = vehicle.find('year').text if vehicle.find('year') is not None else ""
|
29 |
+
make = vehicle.find('make').text if vehicle.find('make') is not None else ""
|
30 |
+
model = vehicle.find('model').text if vehicle.find('model') is not None else ""
|
31 |
+
vehicle_info = f"{year} {make} {model}".strip()
|
32 |
+
|
33 |
+
# Extract first name
|
34 |
+
first_name = ""
|
35 |
+
name_element = root.find('.//name[@part="first"]')
|
36 |
+
if name_element is not None:
|
37 |
+
first_name = name_element.text.strip() if name_element.text else ""
|
38 |
+
return first_name, vehicle_info
|
39 |
+
|
40 |
+
def safe_get_attr(obj, attr, default=None):
|
41 |
+
try:
|
42 |
+
return getattr(obj, attr, default)
|
43 |
+
except (AttributeError, TypeError):
|
44 |
+
return default
|
45 |
+
|
46 |
+
@tool
|
47 |
+
def custom_site_crawler(website_url: str) -> str:
|
48 |
+
"""
|
49 |
+
Crawl the car gurus site for the specific dealership and return the markdown content or crawl the dealership website and return the markdown content. Use this when the user asks about the car or dealership and cannot be answered by the ADF Lead.
|
50 |
+
|
51 |
+
Args:
|
52 |
+
website_url: The url of the website (car gurus or dealership website) to crawl.
|
53 |
+
|
54 |
+
Returns:
|
55 |
+
A string of markdown content of the website.
|
56 |
+
"""
|
57 |
+
import asyncio
|
58 |
+
|
59 |
+
async def _crawl_site(url):
|
60 |
+
async with AsyncWebCrawler() as crawler:
|
61 |
+
try:
|
62 |
+
result_container = await crawler.arun(url, config=crawler_config)
|
63 |
+
|
64 |
+
# Handle different result types from crawler
|
65 |
+
if hasattr(result_container, '__iter__') and not isinstance(result_container, str):
|
66 |
+
try:
|
67 |
+
# Try to get first result if it's a list-like container
|
68 |
+
result = next(iter(result_container))
|
69 |
+
except (StopIteration, TypeError):
|
70 |
+
result = result_container
|
71 |
+
else:
|
72 |
+
result = result_container
|
73 |
+
|
74 |
+
markdown_result = safe_get_attr(result, 'markdown', None)
|
75 |
+
if markdown_result:
|
76 |
+
raw_markdown = safe_get_attr(markdown_result, 'raw_markdown', '')
|
77 |
+
return raw_markdown if raw_markdown else ""
|
78 |
+
else:
|
79 |
+
return ""
|
80 |
+
except Exception as e:
|
81 |
+
print(f"Error crawling {url}: {e}")
|
82 |
+
return ""
|
83 |
+
|
84 |
+
return asyncio.run(_crawl_site(website_url))
|
85 |
+
|
86 |
+
agent = CodeAgent(tools=[VisitWebpageTool(), WebSearchTool(), custom_site_crawler], model=model, additional_authorized_imports=["xml.etree.ElementTree"])
|
87 |
+
|
88 |
+
|
89 |
+
dealership_phone = "(513) 800-0805"
|
90 |
+
car_gurus_site = "https://www.cargurus.com/Cars/m-Ohio-Cars-sp458596"
|
91 |
+
car_site = "https://www.Ohiocars.com"
|
92 |
+
adf_lead = "<?xml version=\"1.0\"?><?ADF version=\"1.0\"?><adf><prospect><requestdate>2025-05-12T13:59:30</requestdate><vehicle status=\"used\"><id source=\"CarsForSale.com\">16f3114e-825f-4eb0-8165-ce43fe5143b6</id><year>2016</year><make>Toyota</make><model>Corolla</model><vin>5YFBURHE4GP511115</vin><stock></stock><comments>DP</comments><colorcombination><exteriorcolor>Super White</exteriorcolor></colorcombination><miles>131024.0</miles><price type=\"asking\">9950</price></vehicle><customer><contact><name part=\"first\">Test</name><name part=\"last\">Lead</name><name part=\"full\">Test Lead</name><email>[email protected]</email><phone>2582584568</phone><address><city></city><state></state><postalcode></postalcode></address></contact><comments><![CDATA[I'm interested and want to know more about the 2016 Toyota Corolla S Plus you have listed for $9,950 on Cars For Sale.]]></comments><timeframe><description></description></timeframe></customer><provider><id>19971</id><name part=\"full\">Carsforsale.com</name><service>Carsforsale.com</service><phone>866-388-9778</phone></provider><vendor><id>114483</id><vendorname>Ohio Cars</vendorname></vendor></prospect></adf>"
|
93 |
+
first_name, vehicle_info = extract_vehicle_info_as_string(adf_lead)
|
94 |
+
|
95 |
+
agent.prompt_templates["system_prompt"] = agent.prompt_templates["system_prompt"] + get_system_prompt(car_gurus_site, car_site, adf_lead, dealership_phone)
|
96 |
+
|
97 |
+
@app.route('/chat', methods=['POST'])
|
98 |
+
def chat():
|
99 |
+
"""
|
100 |
+
Main chat endpoint to interact with the agent.
|
101 |
+
Expects JSON payload with 'message' field.
|
102 |
+
"""
|
103 |
+
try:
|
104 |
+
data = request.get_json()
|
105 |
+
if not data or 'message' not in data:
|
106 |
+
return jsonify({'error': 'Missing message field in request'}), 400
|
107 |
+
|
108 |
+
message = data['message']
|
109 |
+
response = agent.run(message)
|
110 |
+
|
111 |
+
return jsonify({
|
112 |
+
'response': response,
|
113 |
+
'status': 'success'
|
114 |
+
})
|
115 |
+
|
116 |
+
except Exception as e:
|
117 |
+
return jsonify({
|
118 |
+
'error': str(e),
|
119 |
+
'status': 'error'
|
120 |
+
}), 500
|
121 |
+
|
122 |
+
@app.route('/crawl', methods=['POST'])
|
123 |
+
def crawl_website():
|
124 |
+
"""
|
125 |
+
Endpoint to directly crawl a website using the custom site crawler.
|
126 |
+
Expects JSON payload with 'url' field.
|
127 |
+
"""
|
128 |
+
try:
|
129 |
+
data = request.get_json()
|
130 |
+
if not data or 'url' not in data:
|
131 |
+
return jsonify({'error': 'Missing url field in request'}), 400
|
132 |
+
|
133 |
+
url = data['url']
|
134 |
+
content = custom_site_crawler(url)
|
135 |
+
|
136 |
+
return jsonify({
|
137 |
+
'content': content,
|
138 |
+
'url': url,
|
139 |
+
'status': 'success'
|
140 |
+
})
|
141 |
+
|
142 |
+
except Exception as e:
|
143 |
+
return jsonify({
|
144 |
+
'error': str(e),
|
145 |
+
'status': 'error'
|
146 |
+
}), 500
|
147 |
+
|
148 |
+
@app.route('/health', methods=['GET'])
|
149 |
+
def health_check():
|
150 |
+
"""Health check endpoint."""
|
151 |
+
return jsonify({'status': 'healthy'})
|
152 |
+
|
153 |
+
if __name__ == '__main__':
|
154 |
+
app.run(debug=True, host='0.0.0.0', port=4000)
|
155 |
+
|
156 |
+
|
157 |
+
# "(513) 800-0805"
|
158 |
+
# "https://www.cargurus.com/Cars/m-Ohio-Cars-sp458596"
|
159 |
+
# "https://www.Ohiocars.com"
|
160 |
+
# "<?xml version=\"1.0\"?><?ADF version=\"1.0\"?><adf><prospect><requestdate>2025-05-12T13:59:30</requestdate><vehicle status=\"used\"><id source=\"CarsForSale.com\">16f3114e-825f-4eb0-8165-ce43fe5143b6</id><year>2016</year><make>Toyota</make><model>Corolla</model><vin>5YFBURHE4GP511115</vin><stock></stock><comments>DP</comments><colorcombination><exteriorcolor>Super White</exteriorcolor></colorcombination><miles>131024.0</miles><price type=\"asking\">9950</price></vehicle><customer><contact><name part=\"first\">Test</name><name part=\"last\">Lead</name><name part=\"full\">Test Lead</name><email>[email protected]</email><phone>2582584568</phone><address><city></city><state></state><postalcode></postalcode></address></contact><comments><![CDATA[I'm interested and want to know more about the 2016 Toyota Corolla S Plus you have listed for $9,950 on Cars For Sale.]]></comments><timeframe><description></description></timeframe></customer><provider><id>19971</id><name part=\"full\">Carsforsale.com</name><service>Carsforsale.com</service><phone>866-388-9778</phone></provider><vendor><id>114483</id><vendorname>Ohio Cars</vendorname></vendor></prospect></adf>"
|
161 |
+
# "Hi {first_name}! The {vehicle_info} you're interested in is available at [OhioCars.com](https://www.ohiocars.com). Would you like to schedule a visit to check it out? We have appointment slots at 11 AM, 1 PM, or 3 PM. Which time works best for you?"
|
162 |
+
|
163 |
+
|
164 |
+
# first_name, vehicle_info = extract_vehicle_info_as_string(adf_lead.value)
|
gradio_ui.py
CHANGED
@@ -9,7 +9,7 @@ from smolagents.memory import ActionStep, FinalAnswerStep, MemoryStep
|
|
9 |
from smolagents.models import ChatMessageStreamDelta
|
10 |
from smolagents.utils import _is_package_available
|
11 |
import xml.etree.ElementTree as ET
|
12 |
-
|
13 |
|
14 |
def get_step_footnote_content(step_log: MemoryStep, step_name: str) -> str:
|
15 |
"""Get a footnote string for a step log with duration and token information"""
|
@@ -241,10 +241,9 @@ class GradioUI:
|
|
241 |
if not self.file_upload_folder.exists():
|
242 |
self.file_upload_folder.mkdir(parents=True, exist_ok=True)
|
243 |
|
244 |
-
def interact_with_agent(self, prompt, messages, session_state, car_site, adf_lead):
|
245 |
import gradio as gr
|
246 |
-
self.agent.prompt_templates["system_prompt"]
|
247 |
-
# Get the agent type from the template agent
|
248 |
if "agent" not in session_state:
|
249 |
session_state["agent"] = self.agent
|
250 |
|
@@ -344,8 +343,10 @@ class GradioUI:
|
|
344 |
)
|
345 |
submit_btn = gr.Button("Submit", variant="primary")
|
346 |
with gr.Accordion("Dealership Info", open=False):
|
347 |
-
|
|
|
348 |
adf_lead = gr.Textbox(label="ADF Lead", lines=4, value="<?xml version=\"1.0\"?><?ADF version=\"1.0\"?><adf><prospect><requestdate>2025-05-12T13:59:30</requestdate><vehicle status=\"used\"><id source=\"CarsForSale.com\">16f3114e-825f-4eb0-8165-ce43fe5143b6</id><year>2016</year><make>Toyota</make><model>Corolla</model><vin>5YFBURHE4GP511115</vin><stock></stock><comments>DP</comments><colorcombination><exteriorcolor>Super White</exteriorcolor></colorcombination><miles>131024.0</miles><price type=\"asking\">9950</price></vehicle><customer><contact><name part=\"first\">Test</name><name part=\"last\">Lead</name><name part=\"full\">Test Lead</name><email>[email protected]</email><phone>2582584568</phone><address><city></city><state></state><postalcode></postalcode></address></contact><comments><![CDATA[I'm interested and want to know more about the 2016 Toyota Corolla S Plus you have listed for $9,950 on Cars For Sale.]]></comments><timeframe><description></description></timeframe></customer><provider><id>19971</id><name part=\"full\">Carsforsale.com</name><service>Carsforsale.com</service><phone>866-388-9778</phone></provider><vendor><id>114483</id><vendorname>Ohio Cars</vendorname></vendor></prospect></adf>", interactive=False)
|
|
|
349 |
# If an upload folder is provided, enable the upload feature
|
350 |
if self.file_upload_folder is not None:
|
351 |
upload_file = gr.File(label="Upload a file")
|
@@ -376,7 +377,7 @@ class GradioUI:
|
|
376 |
self.log_user_message,
|
377 |
[text_input, file_uploads_log],
|
378 |
[stored_messages, text_input, submit_btn],
|
379 |
-
).then(self.interact_with_agent, [stored_messages, chatbot, session_state, car_site, adf_lead], [chatbot]).then(
|
380 |
lambda: (
|
381 |
gr.Textbox(
|
382 |
interactive=True, placeholder="Enter your prompt here and press Shift+Enter or the button"
|
@@ -391,7 +392,7 @@ class GradioUI:
|
|
391 |
self.log_user_message,
|
392 |
[text_input, file_uploads_log],
|
393 |
[stored_messages, text_input, submit_btn],
|
394 |
-
).then(self.interact_with_agent, [stored_messages, chatbot, session_state, car_site, adf_lead], [chatbot]).then(
|
395 |
lambda: (
|
396 |
gr.Textbox(
|
397 |
interactive=True, placeholder="Enter your prompt here and press Shift+Enter or the button"
|
|
|
9 |
from smolagents.models import ChatMessageStreamDelta
|
10 |
from smolagents.utils import _is_package_available
|
11 |
import xml.etree.ElementTree as ET
|
12 |
+
from system_prompt import get_system_prompt
|
13 |
|
14 |
def get_step_footnote_content(step_log: MemoryStep, step_name: str) -> str:
|
15 |
"""Get a footnote string for a step log with duration and token information"""
|
|
|
241 |
if not self.file_upload_folder.exists():
|
242 |
self.file_upload_folder.mkdir(parents=True, exist_ok=True)
|
243 |
|
244 |
+
def interact_with_agent(self, prompt, messages, session_state, car_gurus_site, car_site, adf_lead, dealership_phone):
|
245 |
import gradio as gr
|
246 |
+
self.agent.prompt_templates["system_prompt"] = self.agent.prompt_templates["system_prompt"] + get_system_prompt(car_gurus_site, car_site, adf_lead, dealership_phone)
|
|
|
247 |
if "agent" not in session_state:
|
248 |
session_state["agent"] = self.agent
|
249 |
|
|
|
343 |
)
|
344 |
submit_btn = gr.Button("Submit", variant="primary")
|
345 |
with gr.Accordion("Dealership Info", open=False):
|
346 |
+
car_gurus_site = gr.Textbox(label="Car Gurus Dealership Site", lines=2, value="https://www.cargurus.com/Cars/m-Ohio-Cars-sp458596", interactive=True)
|
347 |
+
car_site = gr.Textbox(label="Dealership Site", lines=2, value="https://www.Ohiocars.com", interactive=True)
|
348 |
adf_lead = gr.Textbox(label="ADF Lead", lines=4, value="<?xml version=\"1.0\"?><?ADF version=\"1.0\"?><adf><prospect><requestdate>2025-05-12T13:59:30</requestdate><vehicle status=\"used\"><id source=\"CarsForSale.com\">16f3114e-825f-4eb0-8165-ce43fe5143b6</id><year>2016</year><make>Toyota</make><model>Corolla</model><vin>5YFBURHE4GP511115</vin><stock></stock><comments>DP</comments><colorcombination><exteriorcolor>Super White</exteriorcolor></colorcombination><miles>131024.0</miles><price type=\"asking\">9950</price></vehicle><customer><contact><name part=\"first\">Test</name><name part=\"last\">Lead</name><name part=\"full\">Test Lead</name><email>[email protected]</email><phone>2582584568</phone><address><city></city><state></state><postalcode></postalcode></address></contact><comments><![CDATA[I'm interested and want to know more about the 2016 Toyota Corolla S Plus you have listed for $9,950 on Cars For Sale.]]></comments><timeframe><description></description></timeframe></customer><provider><id>19971</id><name part=\"full\">Carsforsale.com</name><service>Carsforsale.com</service><phone>866-388-9778</phone></provider><vendor><id>114483</id><vendorname>Ohio Cars</vendorname></vendor></prospect></adf>", interactive=False)
|
349 |
+
dealership_phone = gr.Textbox(label="Dealership Phone", lines=2, value="(513) 800-0805", interactive=True)
|
350 |
# If an upload folder is provided, enable the upload feature
|
351 |
if self.file_upload_folder is not None:
|
352 |
upload_file = gr.File(label="Upload a file")
|
|
|
377 |
self.log_user_message,
|
378 |
[text_input, file_uploads_log],
|
379 |
[stored_messages, text_input, submit_btn],
|
380 |
+
).then(self.interact_with_agent, [stored_messages, chatbot, session_state, car_gurus_site, car_site, adf_lead, dealership_phone], [chatbot]).then(
|
381 |
lambda: (
|
382 |
gr.Textbox(
|
383 |
interactive=True, placeholder="Enter your prompt here and press Shift+Enter or the button"
|
|
|
392 |
self.log_user_message,
|
393 |
[text_input, file_uploads_log],
|
394 |
[stored_messages, text_input, submit_btn],
|
395 |
+
).then(self.interact_with_agent, [stored_messages, chatbot, session_state, car_gurus_site, car_site, adf_lead, dealership_phone], [chatbot]).then(
|
396 |
lambda: (
|
397 |
gr.Textbox(
|
398 |
interactive=True, placeholder="Enter your prompt here and press Shift+Enter or the button"
|
requirements.txt
CHANGED
@@ -1,5 +1,4 @@
|
|
|
|
1 |
smolagents
|
|
|
2 |
gradio
|
3 |
-
markdownify
|
4 |
-
requests
|
5 |
-
beautifulsoup4
|
|
|
1 |
+
flask>=2.3.0
|
2 |
smolagents
|
3 |
+
crawl4ai
|
4 |
gradio
|
|
|
|
|
|
system_prompt.py
ADDED
@@ -0,0 +1,19 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
SYSTEM_PROMPT = """You are a helpful customer support assistant.
|
2 |
+
Keep your answers to a 35 word limit. You are a sms text box so keep it informal.
|
3 |
+
Take the final result and format it as a sms text message to a customer. Dont show your thinking in the final message.
|
4 |
+
When the user mentions a time that works for them for a scheduled appointment, reply with `Great! We can schedule your visit for that time. Please call {car_site} at {dealership_phone} to confirm your appointment. Looking forward to seeing you then!
|
5 |
+
When it makes sense, end messages asking if the customer would like to schedule an appointment to visit and check out the vehicle.
|
6 |
+
When answering a customer's question about the car (e.g. price, features, mileage, etc.), use this ADF lead: {adf_lead} to find the information.
|
7 |
+
If the answer cannot be found, then use the custom_site_crawler tool with this site: {car_gurus_site} to find the information. This site will hold information regarding the dealership inventory, business hours, address, etc.
|
8 |
+
If the answer still cannot be found, then use the custom_site_crawler tool with this site: {car_site} to find the information. This is the dealership's website and will hold all up to date information.
|
9 |
+
Lastly, if the other sources still don;t have the answer, then use the WebSearchTool to find the information as a final resort.
|
10 |
+
If the question from the user is not related to the car, the dealership, or scheduling an appointment, then do not use the WebSearchTool and do not answer the question. Instead reply with `I'm sorry, I can only help with information about the car, the dealership, or scheduling an appointment. Would you like the schedule a visit?`
|
11 |
+
"""
|
12 |
+
|
13 |
+
def get_system_prompt(car_gurus_site, car_site, adf_lead, dealership_phone):
|
14 |
+
return SYSTEM_PROMPT.format(
|
15 |
+
car_gurus_site=car_gurus_site,
|
16 |
+
car_site=car_site,
|
17 |
+
adf_lead=adf_lead,
|
18 |
+
dealership_phone=dealership_phone
|
19 |
+
)
|