Spaces:
Running
Running
| import re | |
| import math | |
| from typing import Optional | |
| # ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| # 1. SALES ESTIMATOR v2 β category-specific BSR β monthly sales | |
| # ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| CATEGORY_MULTIPLIERS = { | |
| "kitchen": {"base": 8000, "decay": 0.55}, | |
| "home": {"base": 7000, "decay": 0.55}, | |
| "sports": {"base": 6000, "decay": 0.52}, | |
| "toys": {"base": 9000, "decay": 0.58}, | |
| "beauty": {"base": 7500, "decay": 0.54}, | |
| "health": {"base": 6500, "decay": 0.53}, | |
| "tools": {"base": 5000, "decay": 0.50}, | |
| "office": {"base": 5500, "decay": 0.51}, | |
| "pet": {"base": 6000, "decay": 0.52}, | |
| "garden": {"base": 4500, "decay": 0.50}, | |
| "default": {"base": 6000, "decay": 0.52}, | |
| } | |
| def estimate_sales_v2(bsr: int, category: str = "default", price: float = 25.0) -> dict: | |
| cat = CATEGORY_MULTIPLIERS.get(category.lower(), CATEGORY_MULTIPLIERS["default"]) | |
| if bsr <= 0: | |
| bsr = 50000 | |
| monthly_sales = int(cat["base"] * math.pow(bsr, -cat["decay"]) * 1000) | |
| monthly_sales = max(1, min(monthly_sales, 50000)) | |
| monthly_revenue = round(monthly_sales * price, 2) | |
| daily_sales = round(monthly_sales / 30, 1) | |
| # Confidence based on BSR range | |
| if bsr < 5000: | |
| confidence = "High" | |
| elif bsr < 50000: | |
| confidence = "Medium" | |
| else: | |
| confidence = "Low" | |
| return { | |
| "monthly_sales": monthly_sales, | |
| "daily_sales": daily_sales, | |
| "monthly_revenue": monthly_revenue, | |
| "confidence": confidence, | |
| "category": category, | |
| "bsr": bsr, | |
| "price": price, | |
| "annual_revenue": round(monthly_revenue * 12, 2), | |
| } | |
| # ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| # 2. REVIEW ANALYZER β sentiment + patterns | |
| # ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| POSITIVE_WORDS = ["great","excellent","perfect","love","amazing","best","good","quality","easy","fast","recommend","happy","pleased","works","nice","fantastic","awesome","solid","durable","comfortable"] | |
| NEGATIVE_WORDS = ["poor","bad","terrible","worst","broken","useless","cheap","waste","disappointed","defective","fragile","flimsy","slow","wrong","missing","return","refund","fake","stopped","horrible"] | |
| QUALITY_WORDS = ["quality","durable","sturdy","solid","premium","cheap","flimsy","fragile","well-made","poorly made"] | |
| DELIVERY_WORDS = ["fast","quick","slow","delivery","shipping","arrived","late","early","package","damaged"] | |
| VALUE_WORDS = ["worth","value","price","expensive","cheap","affordable","overpriced","deal","bargain"] | |
| def analyze_reviews(rating: float, review_count: int, title: str = "") -> dict: | |
| """Analyze product based on available data β real NLP would need actual review text.""" | |
| # Star distribution estimate | |
| if rating >= 4.5: | |
| stars = {"5": 70, "4": 20, "3": 5, "2": 3, "1": 2} | |
| elif rating >= 4.0: | |
| stars = {"5": 55, "4": 25, "3": 10, "2": 5, "1": 5} | |
| elif rating >= 3.5: | |
| stars = {"5": 40, "4": 25, "3": 15, "2": 10, "1": 10} | |
| elif rating >= 3.0: | |
| stars = {"5": 30, "4": 20, "3": 20, "2": 15, "1": 15} | |
| else: | |
| stars = {"5": 20, "4": 15, "3": 15, "2": 20, "1": 30} | |
| positive_pct = stars["5"] + stars["4"] | |
| negative_pct = stars["1"] + stars["2"] | |
| # Sentiment | |
| if rating >= 4.3: | |
| sentiment = "Very Positive" | |
| sentiment_color = "#34d399" | |
| elif rating >= 3.8: | |
| sentiment = "Positive" | |
| sentiment_color = "#86efac" | |
| elif rating >= 3.3: | |
| sentiment = "Mixed" | |
| sentiment_color = "#fbbf24" | |
| elif rating >= 2.8: | |
| sentiment = "Negative" | |
| sentiment_color = "#fb923c" | |
| else: | |
| sentiment = "Very Negative" | |
| sentiment_color = "#f87171" | |
| # Review velocity | |
| if review_count > 10000: | |
| velocity = "Saturated" | |
| elif review_count > 1000: | |
| velocity = "High" | |
| elif review_count > 200: | |
| velocity = "Medium" | |
| elif review_count > 50: | |
| velocity = "Growing" | |
| else: | |
| velocity = "Low" | |
| # Market opportunity from reviews | |
| if review_count < 100 and rating >= 4.0: | |
| opportunity = "High β low reviews, good rating. Easy entry." | |
| elif review_count < 500 and rating >= 3.8: | |
| opportunity = "Medium β manageable competition." | |
| elif review_count > 1000 and rating < 3.8: | |
| opportunity = "Medium β saturated but poor quality. Can disrupt." | |
| elif review_count > 1000 and rating >= 4.2: | |
| opportunity = "Low β strong competition, hard to enter." | |
| else: | |
| opportunity = "Medium β assess further." | |
| return { | |
| "rating": rating, | |
| "review_count": review_count, | |
| "sentiment": sentiment, | |
| "sentiment_color": sentiment_color, | |
| "positive_pct": positive_pct, | |
| "negative_pct": negative_pct, | |
| "star_distribution": stars, | |
| "review_velocity": velocity, | |
| "market_opportunity": opportunity, | |
| "common_positives": ["Good quality", "Fast delivery", "Value for money", "Easy to use", "As described"][:3], | |
| "common_negatives": ["Quality issues", "Poor packaging", "Not as described"][:2] if negative_pct > 15 else [], | |
| "entry_barrier": "Low" if review_count < 100 else "Medium" if review_count < 500 else "High", | |
| "entry_barrier_color": "#34d399" if review_count < 100 else "#fbbf24" if review_count < 500 else "#f87171", | |
| } | |
| # ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| # 3. BUY BOX ANALYZER | |
| # ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| def analyze_buy_box(price: float, rating: float, review_count: int, is_fba: bool = True, is_prime: bool = True) -> dict: | |
| score = 0 | |
| factors = [] | |
| # Price competitiveness | |
| if price < 20: | |
| score += 25 | |
| factors.append({"factor": "Price", "status": "Competitive", "color": "#34d399", "detail": f"${price:.2f} β low price helps win buy box"}) | |
| elif price < 50: | |
| score += 20 | |
| factors.append({"factor": "Price", "status": "Moderate", "color": "#fbbf24", "detail": f"${price:.2f} β average price range"}) | |
| else: | |
| score += 10 | |
| factors.append({"factor": "Price", "status": "High", "color": "#f87171", "detail": f"${price:.2f} β high price hurts buy box chances"}) | |
| # FBA | |
| if is_fba: | |
| score += 30 | |
| factors.append({"factor": "Fulfillment", "status": "FBA β", "color": "#34d399", "detail": "FBA strongly favored for buy box"}) | |
| else: | |
| score += 5 | |
| factors.append({"factor": "Fulfillment", "status": "FBM", "color": "#f87171", "detail": "FBM sellers rarely win buy box"}) | |
| # Prime | |
| if is_prime: | |
| score += 20 | |
| factors.append({"factor": "Prime", "status": "Eligible β", "color": "#34d399", "detail": "Prime eligibility required for buy box"}) | |
| else: | |
| score += 0 | |
| factors.append({"factor": "Prime", "status": "Not Eligible", "color": "#f87171", "detail": "No Prime = very low buy box chance"}) | |
| # Seller rating | |
| if rating >= 4.5: | |
| score += 15 | |
| factors.append({"factor": "Seller Rating", "status": "Excellent", "color": "#34d399", "detail": f"{rating}β β Amazon favors high-rated sellers"}) | |
| elif rating >= 4.0: | |
| score += 10 | |
| factors.append({"factor": "Seller Rating", "status": "Good", "color": "#fbbf24", "detail": f"{rating}β β acceptable for buy box"}) | |
| else: | |
| score += 3 | |
| factors.append({"factor": "Seller Rating", "status": "Needs Work", "color": "#f87171", "detail": f"{rating}β β low rating hurts buy box"}) | |
| # Review count | |
| if review_count > 100: | |
| score += 10 | |
| factors.append({"factor": "Reviews", "status": "Established", "color": "#34d399", "detail": f"{review_count:,} reviews β trusted seller signal"}) | |
| else: | |
| score += 5 | |
| factors.append({"factor": "Reviews", "status": "New Seller", "color": "#fbbf24", "detail": f"{review_count} reviews β building trust"}) | |
| score = min(score, 100) | |
| if score >= 75: | |
| verdict = "Strong Buy Box Candidate" | |
| verdict_color = "#34d399" | |
| elif score >= 50: | |
| verdict = "Moderate Chance" | |
| verdict_color = "#fbbf24" | |
| elif score >= 25: | |
| verdict = "Low Chance" | |
| verdict_color = "#fb923c" | |
| else: | |
| verdict = "Unlikely to Win" | |
| verdict_color = "#f87171" | |
| return { | |
| "score": score, | |
| "verdict": verdict, | |
| "verdict_color": verdict_color, | |
| "factors": factors, | |
| "tips": [ | |
| "Use FBA for best buy box eligibility", | |
| "Price within 2% of lowest FBA offer", | |
| "Maintain 95%+ seller feedback rating", | |
| "Keep order defect rate below 1%", | |
| "Ship on time β late shipments hurt score", | |
| ][:3] | |
| } | |
| # ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| # 4. NICHE FINDER | |
| # ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| def analyze_niche(keyword: str, avg_bsr: float, avg_reviews: float, avg_price: float, product_count: int = 100) -> dict: | |
| # Demand score (lower BSR = higher demand) | |
| if avg_bsr < 5000: | |
| demand = 95 | |
| elif avg_bsr < 20000: | |
| demand = 80 | |
| elif avg_bsr < 50000: | |
| demand = 60 | |
| elif avg_bsr < 100000: | |
| demand = 40 | |
| else: | |
| demand = 20 | |
| # Competition score (lower reviews = less competition) | |
| if avg_reviews < 50: | |
| competition = 10 # low competition | |
| elif avg_reviews < 200: | |
| competition = 30 | |
| elif avg_reviews < 500: | |
| competition = 55 | |
| elif avg_reviews < 1000: | |
| competition = 75 | |
| else: | |
| competition = 90 | |
| # Price attractiveness | |
| if 20 <= avg_price <= 60: | |
| price_score = 90 | |
| price_note = "Sweet spot for FBA ($20-$60)" | |
| elif 10 <= avg_price < 20: | |
| price_score = 60 | |
| price_note = "Low margin risk under $20" | |
| elif 60 < avg_price <= 100: | |
| price_score = 75 | |
| price_note = "Good margin, lower volume" | |
| else: | |
| price_score = 40 | |
| price_note = "High price = niche market" | |
| # Opportunity score | |
| opportunity = round((demand * 0.4) + ((100 - competition) * 0.4) + (price_score * 0.2)) | |
| if opportunity >= 70: | |
| verdict = "π’ Great Niche" | |
| verdict_color = "#34d399" | |
| elif opportunity >= 50: | |
| verdict = "π‘ Decent Niche" | |
| verdict_color = "#fbbf24" | |
| elif opportunity >= 35: | |
| verdict = "π Challenging" | |
| verdict_color = "#fb923c" | |
| else: | |
| verdict = "π΄ Avoid" | |
| verdict_color = "#f87171" | |
| est_monthly_sales = estimate_sales_v2(int(avg_bsr), price=avg_price)["monthly_sales"] | |
| market_size = round(est_monthly_sales * avg_price * product_count / 1000, 0) | |
| return { | |
| "keyword": keyword, | |
| "opportunity_score": opportunity, | |
| "verdict": verdict, | |
| "verdict_color": verdict_color, | |
| "demand_score": demand, | |
| "competition_score": competition, | |
| "price_score": price_score, | |
| "price_note": price_note, | |
| "avg_bsr": int(avg_bsr), | |
| "avg_reviews": int(avg_reviews), | |
| "avg_price": avg_price, | |
| "est_monthly_sales": est_monthly_sales, | |
| "market_size_k": market_size, | |
| "recommendation": ( | |
| "Low competition β great entry opportunity!" if competition < 30 | |
| else "Medium competition β differentiate product." if competition < 60 | |
| else "High competition β need strong differentiation." | |
| ) | |
| } | |
| # ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| # 5. KEYWORD RESEARCH | |
| # ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| def generate_keywords(seed_keyword: str, category: str = "") -> dict: | |
| seed = seed_keyword.lower().strip() | |
| words = seed.split() | |
| # Generate variations | |
| modifiers_prefix = ["best", "top", "premium", "cheap", "professional", "heavy duty", "large", "small", "portable", "electric"] | |
| modifiers_suffix = ["for home", "for kitchen", "for office", "set", "kit", "bundle", "with lid", "non stick", "stainless steel", "organic"] | |
| keywords = [] | |
| # Main keyword | |
| keywords.append({ | |
| "keyword": seed, | |
| "search_volume": "High", | |
| "competition": "High", | |
| "opportunity": "Low", | |
| "type": "Head" | |
| }) | |
| # Long tail variations | |
| for mod in modifiers_prefix[:5]: | |
| kw = f"{mod} {seed}" | |
| keywords.append({ | |
| "keyword": kw, | |
| "search_volume": "Medium", | |
| "competition": "Medium", | |
| "opportunity": "Medium", | |
| "type": "Long-tail" | |
| }) | |
| for mod in modifiers_suffix[:5]: | |
| kw = f"{seed} {mod}" | |
| keywords.append({ | |
| "keyword": kw, | |
| "search_volume": "Low", | |
| "competition": "Low", | |
| "opportunity": "High", | |
| "type": "Long-tail" | |
| }) | |
| # Backend keywords (for listing) | |
| backend = [seed] + words + [f"{words[-1]} set", f"buy {seed}", f"{seed} amazon"] | |
| return { | |
| "seed_keyword": seed, | |
| "total_keywords": len(keywords), | |
| "keywords": keywords, | |
| "backend_keywords": backend, | |
| "top_opportunity": [k for k in keywords if k["opportunity"] == "High"][:3], | |
| "tip": f"Target '{seed} for home' or '{seed} set' β lower competition, high buyer intent." | |
| } |