"""Rule-based concierge for the Guide tab. Instant answers about the platform (tiers, models, data, premium access) without loading any LLM β€” so it works on CPU Spaces and while the main model is busy. Keyword-matched topics with a menu fallback. """ CONTACT_EMAIL = "finpy07@gmail.com" TOPICS = { "start": { "keywords": ["start", "begin", "how do i", "what can", "help", "guide", "do here", "use this"], "answer": ( "**Welcome to FinLLM Foundry!** Here's what you can do:\n\n" "1. **Chat (General tier β€” free):** go to the *Chat* tab, keep tier = " "*General*, and ask finance questions β€” filings, IFRS vs GAAP, Basel III, " "market concepts, earnings analysis.\n" "2. **Premium tier:** pick from a catalog of larger finance-tuned models " "(Qwen3, DeepSeek-R1 distills, Llama 3.3, Mistral, Gemma). Ask me " "*'how do I get premium access?'* for details.\n" "3. **Custom domains:** need a model tuned for law, medical, regulatory, " "or your own documents? Ask me about *custom domains*.\n\n" "Try one of the quick questions below, or just type." ), }, "premium": { "keywords": ["premium", "access", "tier 2", "2nd tier", "second tier", "subscribe", "price", "pricing", "pay", "unlock", "code"], "answer": ( "**Getting Premium (2nd-tier) access**\n\n" "Premium unlocks the full model catalog β€” larger models (up to 70B), " "reasoning-tuned variants, and priority for custom requests.\n\n" f"πŸ“§ **Email {CONTACT_EMAIL}** with:\n" "- your name and organisation (if any)\n" "- what you plan to use it for (research, analysis, product…)\n" "- which models you're most interested in\n\n" "You'll receive a personal **access code** β€” enter it in the *Chat* tab " "under *Premium access code* and press *Unlock premium*." ), }, "custom_domain": { "keywords": ["custom", "domain", "law", "legal", "medical", "regulatory", "my data", "own data", "company data", "specific", "bespoke", "other domain"], "answer": ( "**Custom / user-specific domains**\n\n" "The platform currently ships finance-tuned adapters, but the same " "pipeline supports additional domains (law, medical, regulatory, or your " "own document corpus) as dedicated adapters on the model of your choice.\n\n" f"πŸ“§ **Email {CONTACT_EMAIL}** describing:\n" "- the domain and typical questions you need answered\n" "- any data you can provide (filings, policies, internal docs)\n" "- preferred base model and size\n\n" "Custom-domain adapters are part of the premium tier." ), }, "models": { "keywords": ["model", "which", "choose", "qwen", "deepseek", "llama", "mistral", "gemma", "catalog", "difference", "best"], "answer": ( "**Choosing a model**\n\n" "- **General tier (free):** Qwen2.5-7B + finance adapter β€” great default " "for most questions.\n" "- **Qwen3 8B/14B:** strongest all-round quality per GB (premium).\n" "- **DeepSeek-R1 Distill 14B:** best for multi-step *reasoning* β€” " "valuation walk-throughs, ratio analysis (premium).\n" "- **Llama 3.3 70B:** highest ceiling, slower (premium).\n" "- **Mistral Small 24B / Gemma 3 27B:** strong mid-size options (premium).\n\n" "Rule of thumb: start with General; move up if answers lack depth. " "Ask *'how do I get premium access?'* to unlock the catalog." ), }, "data": { "keywords": ["data", "train", "dataset", "source", "sec", "edgar", "filings", "ifrs", "gaap", "basel", "fomc", "cfa"], "answer": ( "**What the finance adapters are trained on**\n\n" "Open instruction datasets (FinGPT suite, FiQA, Finance-Alpaca, Financial " "PhraseBank) plus documents ingested from primary sources: SEC EDGAR " "10-K/10-Q filings, FOMC minutes, and public regulatory texts " "(IFRS, Basel III, FCA, MiFID II).\n\n" "No proprietary or licensed feeds (Bloomberg, WRDS) are redistributed in " "public adapters." ), }, "disclaimer": { "keywords": ["advice", "invest", "buy", "sell", "recommend", "legal advice", "disclaimer", "liability"], "answer": ( "**Important:** FinLLM Foundry is for research and education only. It does " "**not** provide personalized investment, legal, accounting, or regulatory " "advice, and outputs may contain errors β€” always verify against primary " "sources and consult qualified professionals for decisions." ), }, } MENU = ( "I can help with any of these β€” tap a quick question below or type your own:\n\n" "- **Getting started** β€” what you can do here\n" "- **Premium access** β€” how to unlock the 2nd tier\n" "- **Custom domains** β€” law / medical / regulatory / your own data\n" "- **Choosing a model** β€” what's in the catalog\n" "- **Training data** β€” what the adapters learned from\n\n" f"For anything else, email **{CONTACT_EMAIL}**." ) QUICK_QUESTIONS = [ "What can I do here?", "How do I get premium access?", "Can I get a model for my own domain or data?", "Which model should I choose?", "What data are the models trained on?", ] def guide_answer(message: str) -> str: text = message.lower() scores = {} for name, topic in TOPICS.items(): hits = sum(1 for kw in topic["keywords"] if kw in text) if hits: scores[name] = hits if not scores: return MENU best = max(scores, key=scores.get) return TOPICS[best]["answer"]