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()