File size: 4,488 Bytes
ea1a0d3 9b5b26a ea1a0d3 c19d193 ea1a0d3 9b5b26a ea1a0d3 9b5b26a ea1a0d3 9b5b26a ea1a0d3 9b5b26a ea1a0d3 9b5b26a ea1a0d3 9b5b26a ea1a0d3 9b5b26a ea1a0d3 9b5b26a ea1a0d3 8c01ffb ea1a0d3 8c01ffb ea1a0d3 ae7a494 ea1a0d3 8c01ffb ea1a0d3 8c01ffb ea1a0d3 8c01ffb ea1a0d3 861422e ea1a0d3 8c01ffb 8fe992b ea1a0d3 8c01ffb 861422e 8fe992b ea1a0d3 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 |
from smolagents import CodeAgent, DuckDuckGoSearchTool, tool, load_tool, HfApiModel
import requests
from bs4 import BeautifulSoup
import pandas as pd
import yaml
import datetime
import pytz
from textblob import TextBlob # Simple sentiment analysis
from Gradio_UI import GradioUI # For building Gradio UI
#### TOOL 1: Scrape GSMArena Reviews & Specs ####
@tool
def scrape_gsmarena_reviews(phone_name: str) -> dict:
"""Scrapes GSMArena for reviews and specs of a given smartphone.
Args:
phone_name: The model name (exact/substantial match).
Returns:
Dictionary with keys: 'reviews', 'price', 'specs'
"""
# You’ll need accurate GSMArena URL fetching logic per phone_name.
search_url = f"https://www.gsmarena.com/res.php3?sSearch={phone_name.replace(' ', '+')}"
res = requests.get(search_url)
soup = BeautifulSoup(res.text, "html.parser")
# Find first matching phone page link
link = soup.find("div", class_="makers").find("a")["href"]
phone_url = f"https://www.gsmarena.com/{link}"
phone_page = requests.get(phone_url)
phone_soup = BeautifulSoup(phone_page.text, "html.parser")
# Parse reviews and price
reviews = []
for rev in phone_soup.find_all("div", class_="user-review"):
reviews.append(rev.text)
# Fallback if structure changes
price = "Unknown"
for spec in phone_soup.find_all("td", string="Price"):
price = spec.find_next_sibling("td").text
specs = {li.find('span').text: li.text for li in phone_soup.find_all("li")}
return {"reviews": reviews, "price": price, "specs": specs}
#### TOOL 2: Churn/Sentiment Scoring ####
@tool
def score_churn(reviews: list) -> float:
"""Calculates aggregate churn score from reviews using sentiment analysis.
Args:
reviews: List of review texts.
Returns:
float churn score (avg polarity; lower = less churn)
"""
scores = [TextBlob(r).sentiment.polarity for r in reviews]
churn_score = 1 - (sum(scores) / len(scores)) if scores else 1 # Lower is better
return churn_score
#### TOOL 3: Find Competing Phones ####
@tool
def find_competitors(price: str) -> list:
"""Scrapes or queries GSM Arena for phones in the same price bracket.
Args:
price: The reference price.
Returns:
List of phone names.
"""
price_value = ''.join(filter(str.isdigit, price))
# For demo: just pick other search results in same price bracket
# Expand with real price logic as needed
return ["Phone1", "Phone2", "Phone3"]
#### FINAL TOOL: Recommend Phone ####
@tool
def recommend_smartphone(user_phone: str):
"""Main logic for recommendation."""
user_data = scrape_gsmarena_reviews(user_phone)
user_reviews = user_data['reviews']
user_score = score_churn(user_reviews)
user_price = user_data['price']
competitors = find_competitors(user_price)
best_score = user_score
best_phone = user_phone
for c in competitors:
c_data = scrape_gsmarena_reviews(c)
c_reviews = c_data['reviews']
c_score = score_churn(c_reviews)
if c_score < best_score:
best_score = c_score
best_phone = c
# If best_phone is not user's, recommend; else try next bracket
result = {
"Your phone": user_phone,
"Your phone score": user_score,
"Best competitor": best_phone,
"Best score": best_score,
"Recommended": "Yes" if best_phone != user_phone else "No better phone in range",
}
return result
#### Gradio UI ####
def agent_ui(user_phone_name):
"""Gradio UI interface handler."""
result = recommend_smartphone(user_phone_name)
return f"""
**Your phone:** {result['Your phone']}
**Churn score:** {result['Your phone score']}
**Best alternative:** {result['Best competitor']} (score: {result['Best score']})
**Recommended:** {result['Recommended']}
"""
# Connect everything for Hugging Face Space
with open("prompts.yaml", 'r') as stream:
prompt_templates = yaml.safe_load(stream)
model = HfApiModel(
max_tokens=2096,
temperature=0.5,
model_id='Qwen/Qwen2.5-Coder-32B-Instruct',
)
agent = CodeAgent(
model=model,
tools=[recommend_smartphone], # add your main tool, you can add others as desired
max_steps=6,
verbosity_level=1,
grammar=None,
planning_interval=None,
name=None,
description=None,
prompt_templates=prompt_templates
)
GradioUI(agent_ui).launch()
|