| import gradio as gr |
| import pandas as pd |
| import matplotlib.pyplot as plt |
| import matplotlib |
| matplotlib.use("Agg") |
| import seaborn as sns |
| import requests |
| import io |
| from pathlib import Path |
| from vaderSentiment.vaderSentiment import SentimentIntensityAnalyzer |
|
|
| |
| |
| |
| try: |
| df_pricing = pd.read_csv("artifacts/pricing_decisions.csv") |
| df_sales = pd.read_csv("artifacts/dashboard_data.csv") |
| ARTIFACTS_OK = True |
| except Exception: |
| ARTIFACTS_OK = False |
| df_pricing = pd.DataFrame() |
| df_sales = pd.DataFrame() |
|
|
| |
| |
| |
| analyzer = SentimentIntensityAnalyzer() |
|
|
| def get_sentiment_label(text): |
| score = analyzer.polarity_scores(text)["compound"] |
| if score >= 0.05: |
| return "positive" |
| elif score <= -0.05: |
| return "negative" |
| else: |
| return "neutral" |
|
|
| def pricing_decision(avg_units, positive_ratio, negative_ratio): |
| if avg_units >= 120 and positive_ratio >= 0.6: |
| return "📈 Increase Price" |
| elif avg_units <= 60 and negative_ratio >= 0.4: |
| return "📉 Decrease Price" |
| else: |
| return "➡️ Keep Price" |
|
|
| def analyze_book(title, reviews_text, avg_units_sold): |
| if not title or not reviews_text: |
| return "⚠️ Please enter a title and at least one review.", "", None |
|
|
| |
| lines = [r.strip() for r in reviews_text.strip().split("\n") if r.strip()] |
| labels = [get_sentiment_label(line) for line in lines] |
|
|
| total = len(labels) |
| positive_ratio = labels.count("positive") / total |
| negative_ratio = labels.count("negative") / total |
| neutral_ratio = labels.count("neutral") / total |
|
|
| decision = pricing_decision(avg_units_sold, positive_ratio, negative_ratio) |
|
|
| |
| summary = f""" |
| 📚 **{title}** |
| |
| 🔢 Reviews analysées : {total} |
| 😊 Positive : {positive_ratio:.0%} |
| 😐 Neutral : {neutral_ratio:.0%} |
| 😞 Negative : {negative_ratio:.0%} |
| 📦 Avg units sold : {avg_units_sold} |
| |
| 💡 **Pricing Decision : {decision}** |
| """ |
|
|
| |
| fig, ax = plt.subplots(figsize=(4, 4)) |
| colors = ["#4CAF50", "#FFC107", "#F44336"] |
| ax.pie( |
| [positive_ratio, neutral_ratio, negative_ratio], |
| labels=["Positive", "Neutral", "Negative"], |
| autopct="%1.0f%%", |
| colors=colors, |
| startangle=90 |
| ) |
| ax.set_title(f"Sentiment — {title}") |
| plt.tight_layout() |
|
|
| return summary, "\n".join(f"{l} → {s}" for l, s in zip(lines, labels)), fig |
|
|
| |
| |
| |
| with gr.Blocks(title="📚 Book Price Decider", theme=gr.themes.Soft()) as app: |
|
|
| gr.Markdown("# 📚 Book Price Decider — Group A4") |
| gr.Markdown("Sentiment analysis + ARIMA-based pricing decisions for books.") |
|
|
| with gr.Tabs(): |
|
|
| |
| with gr.Tab("📊 Dashboard"): |
| gr.Markdown("### Pre-computed results from the analysis notebooks") |
|
|
| if ARTIFACTS_OK: |
| with gr.Row(): |
| gr.Image(value="artifacts/sales_trends.png", |
| label="Sales Trends") |
| gr.Image(value="artifacts/sentiment_distribution.png", |
| label="Sentiment Distribution") |
| gr.Dataframe(value=df_pricing, label="Pricing Decisions Table") |
| else: |
| gr.Markdown( |
| "⚠️ No artifacts found yet. " |
| "Run the notebooks and upload the `artifacts/` folder." |
| ) |
|
|
| |
| with gr.Tab("🔮 Analyze a New Book"): |
| gr.Markdown("### Enter book info to get a live pricing recommendation") |
|
|
| with gr.Row(): |
| title_input = gr.Textbox(label="Book Title", placeholder="e.g. The Great Gatsby") |
| units_input = gr.Number(label="Avg Monthly Units Sold", value=100) |
|
|
| reviews_input = gr.Textbox( |
| label="Paste reviews here (one per line)", |
| lines=6, |
| placeholder="This book was amazing!\nNot what I expected.\nDecent read overall." |
| ) |
|
|
| analyze_btn = gr.Button("🚀 Analyze & Decide", variant="primary") |
|
|
| with gr.Row(): |
| summary_output = gr.Markdown(label="Summary") |
| details_output = gr.Textbox(label="Review-by-review labels", lines=6) |
|
|
| chart_output = gr.Plot(label="Sentiment Chart") |
|
|
| analyze_btn.click( |
| fn=analyze_book, |
| inputs=[title_input, reviews_input, units_input], |
| outputs=[summary_output, details_output, chart_output] |
| ) |
|
|
| |
| with gr.Tab("ℹ️ About"): |
| gr.Markdown(""" |
| ## About this app |
| |
| This app is part of the **AI for Big Data Management** group project at ESCP Business School. |
| |
| ### Pipeline |
| 1. **Real-world data** scraped from Books to Scrape |
| 2. **Synthetic data** generated to enrich with reviews & sales history |
| 3. **VADER sentiment analysis** on customer reviews |
| 4. **ARIMA forecasting** on sales time series |
| 5. **Rule-based pricing decisions** combining sentiment + sales volume |
| 6. **This Hugging Face app** as the final automation layer |
| |
| ### Team — Group A4 |
| - Project Manager |
| - Data Analyst |
| - UX Designer(s) |
| - Content Specialist |
| """) |
|
|
| app.launch() |