"""Market trends feed for kant-en-klaar / halal ready meals.""" from __future__ import annotations from typing import Any from app.db import execute_returning, fetch_all, json_param TREND_SEEDS = [ { "category": "kant-en-klaar", "trend_name": "Halal ready-meals groei stedelijk", "description": "Stedelijke gebieden met hoge niet-westerse bevolking tonen vraag naar halal kant-en-klaar zonder voldoende schap-aanbod.", "source": "CBS + retail intelligence", "confidence_score": 0.82, "opportunity_score": 0.88, "related_products": ["halal maaltijden", "microwave meals", "salades"], "action_items": ["Target Plus/Jumbo regio's met halal-gap score >60", "Pilot schap bij 3 filialen"], }, { "category": "halal", "trend_name": "Certificering als vertrouwen-driver", "description": "Filialen met halal-certificering maar beperkt ready-meal assortiment = upsell kans voor Foodlinkk.", "source": "halal_registry + CRM", "confidence_score": 0.75, "opportunity_score": 0.80, "related_products": ["HQC gecertificeerde maaltijden"], "action_items": ["Match HQC stores met CRM pipeline", "Cross-sell bestaande klanten"], }, { "category": "kant-en-klaar", "trend_name": "Convenience trend post-COVID", "description": "Gemiddeld inkomen en eenpersoonshuishoudens correleren met groei kant-en-klaar segment.", "source": "CBS kerncijfers", "confidence_score": 0.70, "opportunity_score": 0.72, "related_products": ["single-serve", "meal kits"], "action_items": ["Filter winkels op huishoudens + inkomen >€35k"], }, ] def refresh_trends_from_social() -> dict[str, Any]: """Derive trend signals from social mentions keywords.""" mentions = fetch_all( """SELECT platform, text, sentiment_score, created_at FROM social_mentions WHERE created_at > NOW() - interval '30 days' ORDER BY created_at DESC LIMIT 100""" ) keywords = { "halal": 0, "kant-en-klaar": 0, "ready meal": 0, "meal prep": 0, "supermarkt": 0, "schap": 0, "afhalen": 0, } for m in mentions: text = (m.get("text") or "").lower() for kw in keywords: if kw in text: keywords[kw] += 1 created = 0 for kw, count in keywords.items(): if count < 1: continue execute_returning( """INSERT INTO market_trends (category, trend_name, description, source, confidence_score, opportunity_score, related_products, data_source) VALUES (%s, %s, %s, 'social_mentions', %s, %s, %s, 'live_feed') RETURNING id""", ( "kant-en-klaar" if "meal" in kw or "kant" in kw else "halal", f"Social buzz: {kw} ({count} mentions)", f"{count} vermeldingen afgelopen 30 dagen rond '{kw}'.", min(0.95, 0.5 + count * 0.05), min(0.95, 0.4 + count * 0.06), [kw], ), ) created += 1 for seed in TREND_SEEDS: exists = fetch_all( "SELECT id FROM market_trends WHERE trend_name = %s LIMIT 1", (seed["trend_name"],), ) if not exists: execute_returning( """INSERT INTO market_trends (category, trend_name, description, source, confidence_score, opportunity_score, related_products, action_items, data_source) VALUES (%s,%s,%s,%s,%s,%s,%s,%s,'seed') RETURNING id""", ( seed["category"], seed["trend_name"], seed["description"], seed["source"], seed["confidence_score"], seed["opportunity_score"], seed["related_products"], seed["action_items"], ), ) created += 1 return {"trends_created": created, "keyword_hits": keywords} def list_live_trends(limit: int = 20) -> list[dict[str, Any]]: return fetch_all( """SELECT * FROM market_trends ORDER BY updated_at DESC NULLS LAST, created_at DESC LIMIT %s""", (limit,), )