| """
|
| ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| β β
|
| β BIOS β Business Idea Operating System β
|
| β Model Controller Β· bios_controller.py β
|
| β Version: 1.0.0 Β· Kernel: BIOS-Insight-v1 β
|
| β β
|
| β "We don't just analyse businesses. We illuminate them." β
|
| β β
|
| ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
|
| Architecture:
|
| BIOSController
|
| βββ ModelRouter β switches between base LLM and BIOS-Insight-v1
|
| βββ DiagnosisEngine β processes 24 questions, runs health score formula
|
| βββ InsightGenerator β builds structured JSON diagnosis report
|
| βββ NeonDBWriter β persists results to PostgreSQL via psycopg
|
| """
|
|
|
| from __future__ import annotations
|
|
|
| import json
|
| import logging
|
| import os
|
| import re
|
| import time
|
| import uuid
|
| import base64
|
| from dataclasses import dataclass, field, asdict
|
| from datetime import datetime, timezone
|
| from enum import Enum
|
| from typing import Any, Optional
|
|
|
| try:
|
| from cryptography.hazmat.primitives.ciphers.aead import AESGCM
|
| CRYPTOGRAPHY_AVAILABLE = True
|
| except Exception:
|
| CRYPTOGRAPHY_AVAILABLE = False
|
|
|
| try:
|
| import psycopg
|
| from psycopg.rows import dict_row as psycopg_dict_row
|
| PSYCOPG_AVAILABLE = True
|
| except Exception:
|
| psycopg = None
|
| psycopg_dict_row = None
|
| PSYCOPG_AVAILABLE = False
|
|
|
|
|
| try:
|
| from huggingface_hub import InferenceClient
|
| HF_AVAILABLE = True
|
| except Exception:
|
| HF_AVAILABLE = False
|
|
|
|
|
| try:
|
| from groq import Groq
|
| GROQ_AVAILABLE = True
|
| except Exception:
|
| GROQ_AVAILABLE = False
|
|
|
|
|
| try:
|
| import openai
|
| OPENAI_AVAILABLE = True
|
| except Exception:
|
| OPENAI_AVAILABLE = False
|
|
|
|
|
| try:
|
| import google.generativeai as genai
|
| GEMINI_AVAILABLE = True
|
| except Exception:
|
| GEMINI_AVAILABLE = False
|
|
|
|
|
| try:
|
| import anthropic
|
| ANTHROPIC_AVAILABLE = True
|
| except Exception:
|
| ANTHROPIC_AVAILABLE = False
|
|
|
|
|
|
|
|
|
|
|
|
|
| logging.basicConfig(
|
| level=logging.INFO,
|
| format="%(asctime)s [BIOS-%(levelname)s] %(message)s",
|
| datefmt="%Y-%m-%d %H:%M:%S",
|
| )
|
| log = logging.getLogger("bios.controller")
|
|
|
|
|
|
|
|
|
|
|
|
|
| class SecurityManager:
|
| """
|
| Handles high-security AES-256-GCM encryption for sensitive business data.
|
| Ensures 'The Fortress' level protection for SME information.
|
| """
|
|
|
| def __init__(self, key: Optional[str] = None):
|
| if not CRYPTOGRAPHY_AVAILABLE:
|
| log.warning("β οΈ cryptography package not found. Data will remain in plaintext.")
|
| self._aes = None
|
| return
|
|
|
| raw_key = key or os.getenv("BIOS_ENCRYPTION_KEY")
|
| if not raw_key:
|
| log.warning("β οΈ BIOS_ENCRYPTION_KEY not set. Security disabled.")
|
| self._aes = None
|
| return
|
|
|
| try:
|
|
|
| key_bytes = raw_key.encode("utf-8")
|
| if len(key_bytes) > 32:
|
| key_bytes = key_bytes[:32]
|
| elif len(key_bytes) < 32:
|
| key_bytes = key_bytes.ljust(32, b"0")
|
|
|
| self._aes = AESGCM(key_bytes)
|
| log.info("π BIOS Security Manager initialized (AES-256-GCM)")
|
| except Exception as e:
|
| log.error(f"β Failed to initialize Security Manager: {e}")
|
| self._aes = None
|
|
|
| def encrypt(self, plaintext: str) -> str:
|
| """Encrypt string data to base64-encoded ciphertext."""
|
| if not self._aes or not plaintext:
|
| return plaintext
|
|
|
| try:
|
| nonce = os.urandom(12)
|
| ct = self._aes.encrypt(nonce, plaintext.encode("utf-8"), None)
|
|
|
| return base64.b64encode(nonce + ct).decode("utf-8")
|
| except Exception as e:
|
| log.error(f"Encryption failed: {e}")
|
| return plaintext
|
|
|
| def decrypt(self, ciphertext: str) -> str:
|
| """Decrypt base64 ciphertext back to plaintext."""
|
| if not self._aes or not ciphertext:
|
| return ciphertext
|
|
|
| try:
|
| data = base64.b64decode(ciphertext)
|
| nonce, ct = data[:12], data[12:]
|
| pt = self._aes.decrypt(nonce, ct, None)
|
| return pt.decode("utf-8")
|
| except Exception as e:
|
|
|
| return ciphertext
|
|
|
|
|
|
|
|
|
|
|
|
|
| class UserManager:
|
| """
|
| Handles user accounts, credits, and refills in NeonDB.
|
| Initial: 1000 credits. Daily Refill: 500 credits.
|
| """
|
|
|
| def __init__(self, database_url: str):
|
| self.db_url = database_url
|
|
|
| def ensure_user_exists(self, email: str, business_name: str) -> str:
|
| """Create user if not exists, return user_id."""
|
| sql = """
|
| INSERT INTO users (email, business_name, credits, last_refill)
|
| VALUES (%s, %s, 1000, NOW())
|
| ON CONFLICT (email) DO UPDATE SET business_name = EXCLUDED.business_name
|
| RETURNING id, credits
|
| """
|
| with psycopg.connect(self.db_url) as conn:
|
| with conn.cursor(row_factory=psycopg_dict_row) as cur:
|
| cur.execute(sql, (email, business_name))
|
| row = cur.fetchone()
|
| conn.commit()
|
| return str(row["id"])
|
|
|
| def check_and_refill_credits(self, user_id: str) -> int:
|
| """Check if daily refill is due (24h), apply it, return current balance."""
|
| sql_check = "SELECT credits, last_refill FROM users WHERE id = %s"
|
| sql_refill = "UPDATE users SET credits = credits + 500, last_refill = NOW() WHERE id = %s RETURNING credits"
|
|
|
| with psycopg.connect(self.db_url) as conn:
|
| with conn.cursor(row_factory=psycopg_dict_row) as cur:
|
| cur.execute(sql_check, (user_id,))
|
| user = cur.fetchone()
|
| if not user: return 0
|
|
|
| last_refill = user["last_refill"]
|
| if datetime.now(timezone.utc) - last_refill > timedelta(days=1):
|
| cur.execute(sql_refill, (user_id,))
|
| user = cur.fetchone()
|
| conn.commit()
|
|
|
| return user["credits"]
|
|
|
| def deduct_credits(self, user_id: str, amount: int) -> bool:
|
| """Deduct credits if balance is sufficient."""
|
| sql = "UPDATE users SET credits = credits - %s WHERE id = %s AND credits >= %s RETURNING credits"
|
| with psycopg.connect(self.db_url) as conn:
|
| with conn.cursor() as cur:
|
| cur.execute(sql, (amount, user_id, amount))
|
| row = cur.fetchone()
|
| conn.commit()
|
| return row is not None
|
|
|
|
|
|
|
|
|
|
|
|
|
| class ModelBackend(str, Enum):
|
| """Supported inference backends."""
|
| GROQ = "groq"
|
| HF_INFERENCE = "hf_inference"
|
| OPENAI = "openai"
|
| GEMINI = "gemini"
|
| ANTHROPIC = "anthropic"
|
| LOCAL = "local"
|
| MOCK = "mock"
|
|
|
|
|
| class ModelVariant(str, Enum):
|
| """Which model to route to."""
|
| BASE = "base"
|
| BIOS_INSIGHT = "bios_insight"
|
|
|
|
|
|
|
| def _bios_insight_model_id() -> str:
|
| return os.getenv("HF_BIOS_MODEL_ID", "isaaclk907/BIOS-Insight-v1")
|
|
|
|
|
| MODEL_IDS = {
|
| ModelVariant.BASE: "meta-llama/llama-3.3-70b-versatile",
|
| ModelVariant.BIOS_INSIGHT: _bios_insight_model_id(),
|
| }
|
|
|
| GROQ_MODEL_IDS = {
|
| ModelVariant.BASE: "llama-3.3-70b-versatile",
|
| ModelVariant.BIOS_INSIGHT: "llama-3.3-70b-versatile",
|
| }
|
|
|
|
|
| INDUSTRY_BENCHMARKS: dict[str, dict] = {
|
| "Gold Shop": {"avg_revenue": 15_000_000, "avg_retention": 60, "avg_clv": 2_000_000, "avg_team": 4, "avg_mkt": 200_000},
|
| "Fashion": {"avg_revenue": 8_000_000, "avg_retention": 40, "avg_clv": 300_000, "avg_team": 6, "avg_mkt": 500_000},
|
| "F&B": {"avg_revenue": 10_000_000, "avg_retention": 50, "avg_clv": 150_000, "avg_team": 10, "avg_mkt": 400_000},
|
| "Cosmetics": {"avg_revenue": 6_000_000, "avg_retention": 45, "avg_clv": 250_000, "avg_team": 5, "avg_mkt": 600_000},
|
| "Electronics": {"avg_revenue": 20_000_000, "avg_retention": 35, "avg_clv": 800_000, "avg_team": 8, "avg_mkt": 700_000},
|
| "Technology Startup": {"avg_revenue": 25_000_000, "avg_retention": 70, "avg_clv": 3_000_000, "avg_team": 12, "avg_mkt": 1_000_000},
|
| "Other": {"avg_revenue": 5_000_000, "avg_retention": 40, "avg_clv": 200_000, "avg_team": 5, "avg_mkt": 300_000},
|
| }
|
|
|
|
|
|
|
|
|
|
|
|
|
| @dataclass
|
| class BusinessInputs:
|
| """
|
| Complete set of 24 diagnostic questions, grouped into 4 sections.
|
|
|
| All monetary values are in MMK (Myanmar Kyat).
|
| Percentages are 0β100 (e.g. retention_rate=65 means 65%).
|
| """
|
|
|
|
|
| business_name: str = ""
|
| industry: str = "Other"
|
| location: str = "Yangon"
|
| years_in_business: int = 0
|
| monthly_revenue: float = 0.0
|
| team_size: int = 1
|
|
|
|
|
| target_customer: str = ""
|
| acquisition_channels: list[str] = field(default_factory=list)
|
| avg_customer_lifetime_value: float = 0.0
|
| retention_rate: float = 0.0
|
| main_competitors: str = ""
|
| unique_selling_proposition: str = ""
|
|
|
|
|
| sales_channels: list[str] = field(default_factory=list)
|
| operational_challenge: str = ""
|
| biggest_pain_point: str = ""
|
| current_technology: list[str] = field(default_factory=list)
|
| marketing_channels: list[str] = field(default_factory=list)
|
| monthly_marketing_budget: float = 0.0
|
|
|
|
|
| goal_3_month: float = 0.0
|
| goal_6_month: float = 0.0
|
| goal_12_month: float = 0.0
|
| budget_constraint: str = "Moderate (200-500K)"
|
| tech_readiness: str = "Somewhat ready"
|
| preferred_language: str = "English"
|
|
|
|
|
| @dataclass
|
| class HealthDimensions:
|
| """Sub-scores for the five health dimensions (each 0β100)."""
|
| revenue_strength: int = 0
|
| customer_retention: int = 0
|
| market_position: int = 0
|
| technology_adoption: int = 0
|
| growth_trajectory: int = 0
|
|
|
| @property
|
| def total(self) -> int:
|
| """
|
| Official BIOS Health Score formula:
|
| (Revenue Strength Γ 20) + (Customer Retention Γ 20) +
|
| (Market Position Γ 20) + (Technology Adoption Γ 20) +
|
| (Growth Trajectory Γ 20)
|
| Each dimension is 0β100, weight is 20%, so max = 100.
|
| """
|
| return round(
|
| (self.revenue_strength * 0.20) +
|
| (self.customer_retention * 0.20) +
|
| (self.market_position * 0.20) +
|
| (self.technology_adoption * 0.20) +
|
| (self.growth_trajectory * 0.20)
|
| )
|
|
|
| def to_dict(self) -> dict:
|
| return {
|
| "revenue_strength": self.revenue_strength,
|
| "customer_retention": self.customer_retention,
|
| "market_position": self.market_position,
|
| "technology_adoption": self.technology_adoption,
|
| "growth_trajectory": self.growth_trajectory,
|
| "total": self.total,
|
| }
|
|
|
|
|
| @dataclass
|
| class Weakness:
|
| rank: int
|
| dimension: str
|
| label: str
|
| your_score: float
|
| benchmark: float
|
| gap: float
|
| severity: str
|
| detail: str
|
|
|
| def to_dict(self) -> dict:
|
| return asdict(self)
|
|
|
|
|
| @dataclass
|
| class Opportunity:
|
| rank: int
|
| title: str
|
| description: str
|
| expected_impact: str
|
| difficulty: str
|
| timeframe: str
|
| revenue_uplift_mmk: Optional[float] = None
|
|
|
| def to_dict(self) -> dict:
|
| return asdict(self)
|
|
|
|
|
| @dataclass
|
| class ActionItem:
|
| priority: int
|
| action: str
|
| rationale: str
|
| urgency_score: float
|
| impact_score: float
|
| feasibility_score: float
|
| composite_score: float
|
|
|
| def to_dict(self) -> dict:
|
| return asdict(self)
|
|
|
|
|
| @dataclass
|
| class DiagnosisReport:
|
| """Full Module 1 output β the BIOS diagnosis report."""
|
| session_id: str
|
| business_name: str
|
| industry: str
|
| location: str
|
| generated_at: str
|
|
|
| health_score: int
|
| health_label: str
|
| health_dimensions: HealthDimensions
|
|
|
| top_3_weaknesses: list[Weakness]
|
| growth_opportunities: list[Opportunity]
|
| priority_action_items: list[ActionItem]
|
|
|
| ai_narrative: str
|
| benchmarking: list[dict]
|
| next_module: str = "Strategy Engine (Module 2)"
|
|
|
| model_used: str = ""
|
| generation_time_ms: int = 0
|
| inputs: Optional[BusinessInputs] = None
|
|
|
| def to_dict(self) -> dict:
|
| return {
|
| "sessionId": self.session_id,
|
| "businessName": self.business_name,
|
| "industry": self.industry,
|
| "location": self.location,
|
| "generatedAt": self.generated_at,
|
| "healthScore": {
|
| "total": self.health_score,
|
| "label": self.health_label,
|
| "dimensions": [
|
| { "dimension": "revenue_strength", "label": "Revenue", "score": self.health_dimensions.revenue_strength },
|
| { "dimension": "customer_retention", "label": "Customer", "score": self.health_dimensions.customer_retention },
|
| { "dimension": "market_position", "label": "Market", "score": self.health_dimensions.market_position },
|
| { "dimension": "technology_adoption", "label": "Technology", "score": self.health_dimensions.technology_adoption },
|
| { "dimension": "growth_trajectory", "label": "Growth", "score": self.health_dimensions.growth_trajectory }
|
| ]
|
| },
|
| "weaknesses": [w.to_dict() for w in self.top_3_weaknesses],
|
| "opportunities": [o.to_dict() for o in self.growth_opportunities],
|
| "actionItems": [a.to_dict() for a in self.priority_action_items],
|
| "narrative": self.ai_narrative,
|
| "benchmarking": self.benchmarking,
|
| "nextModule": self.next_module,
|
| "modelUsed": self.model_used,
|
| "generationTimeMs":self.generation_time_ms,
|
| "inputs": asdict(self.inputs) if self.inputs else None,
|
| "pipeline": "bios_controller"
|
| }
|
|
|
| def to_json(self, indent: int = 2) -> str:
|
| return json.dumps(self.to_dict(), ensure_ascii=False, indent=indent)
|
|
|
|
|
|
|
|
|
|
|
|
|
| class ModelRouter:
|
| """
|
| Routes inference requests to the appropriate backend + model variant.
|
|
|
| Priority order when calling .infer():
|
| 1. If BIOS-Insight-v1 is flagged as available β use HF Inference API
|
| 2. Else use base model via Groq (fastest, free tier)
|
| 3. Fallback to Anthropic Claude
|
| 4. Final fallback: MOCK mode (returns structured placeholder)
|
| """
|
|
|
| def __init__(
|
| self,
|
| backend: ModelBackend = ModelBackend.GROQ,
|
| variant: ModelVariant = ModelVariant.BASE,
|
| bios_insight_ready: bool = False,
|
| temperature: float = 0.3,
|
| max_tokens: int = 2048,
|
| ):
|
| self.backend = backend
|
| self.variant = variant
|
| self.bios_insight_ready = bios_insight_ready
|
| self.temperature = temperature
|
| self.max_tokens = max_tokens
|
|
|
|
|
| self._groq_client: Any = None
|
| self._hf_client: Any = None
|
| self._openai_client: Any = None
|
| self._gemini_client: Any = None
|
| self._anthropic_client: Any = None
|
|
|
| log.info(
|
| f"ModelRouter initialised | backend={backend.value} "
|
| f"variant={variant.value} | BIOS-Insight-v1 ready={bios_insight_ready}"
|
| )
|
|
|
|
|
|
|
| def _get_groq(self):
|
| if self._groq_client is None:
|
| if not GROQ_AVAILABLE:
|
| raise RuntimeError("groq package not installed. Run: pip install groq")
|
| api_key = os.getenv("GROQ_API_KEY")
|
| if not api_key:
|
| raise RuntimeError("GROQ_API_KEY environment variable not set")
|
| self._groq_client = Groq(api_key=api_key)
|
| return self._groq_client
|
|
|
| def _get_hf(self):
|
| if self._hf_client is None:
|
| if not HF_AVAILABLE:
|
| raise RuntimeError("huggingface_hub not installed. Run: pip install huggingface_hub")
|
| api_key = os.getenv("HF_API_KEY") or os.getenv("HUGGINGFACE_API_KEY")
|
| if not api_key:
|
| raise RuntimeError("Set HF_API_KEY or HUGGINGFACE_API_KEY for Hugging Face inference")
|
| self._hf_client = InferenceClient(token=api_key.strip())
|
| return self._hf_client
|
|
|
| def _get_openai(self):
|
| if self._openai_client is None:
|
| if not OPENAI_AVAILABLE:
|
| raise RuntimeError("openai package not installed. Run: pip install openai")
|
| api_key = os.getenv("OPENAI_API_KEY")
|
| if not api_key:
|
| raise RuntimeError("OPENAI_API_KEY environment variable not set")
|
| self._openai_client = openai.OpenAI(api_key=api_key)
|
| return self._openai_client
|
|
|
| def _get_gemini(self):
|
| if self._gemini_client is None:
|
| if not GEMINI_AVAILABLE:
|
| raise RuntimeError("google-generativeai package not installed. Run: pip install google-generativeai")
|
| api_key = os.getenv("GEMINI_API_KEY")
|
| if not api_key:
|
| raise RuntimeError("GEMINI_API_KEY environment variable not set")
|
| genai.configure(api_key=api_key)
|
| self._gemini_client = genai.GenerativeModel('gemini-pro')
|
| return self._gemini_client
|
|
|
| def _get_anthropic(self):
|
| if self._anthropic_client is None:
|
| if not ANTHROPIC_AVAILABLE:
|
| raise RuntimeError("anthropic package not installed. Run: pip install anthropic")
|
| api_key = os.getenv("ANTHROPIC_API_KEY")
|
| if not api_key:
|
| raise RuntimeError("ANTHROPIC_API_KEY not set")
|
| self._anthropic_client = anthropic.Anthropic(api_key=api_key)
|
| return self._anthropic_client
|
|
|
|
|
|
|
| def _resolve_route(self) -> tuple[ModelBackend, ModelVariant]:
|
| """Determine which backend + variant to actually use."""
|
| _hf_token = os.getenv("HF_API_KEY") or os.getenv("HUGGINGFACE_API_KEY")
|
| if self.bios_insight_ready and HF_AVAILABLE and _hf_token:
|
| return ModelBackend.HF_INFERENCE, ModelVariant.BIOS_INSIGHT
|
| if OPENAI_AVAILABLE and os.getenv("OPENAI_API_KEY"):
|
| return ModelBackend.OPENAI, ModelVariant.BASE
|
| if GEMINI_AVAILABLE and os.getenv("GEMINI_API_KEY"):
|
| return ModelBackend.GEMINI, ModelVariant.BASE
|
| if GROQ_AVAILABLE and os.getenv("GROQ_API_KEY"):
|
| return ModelBackend.GROQ, ModelVariant.BASE
|
| if ANTHROPIC_AVAILABLE and os.getenv("ANTHROPIC_API_KEY"):
|
| return ModelBackend.ANTHROPIC, ModelVariant.BASE
|
| return ModelBackend.MOCK, ModelVariant.BASE
|
|
|
|
|
|
|
| def infer(self, system_prompt: str, user_prompt: str) -> tuple[str, str]:
|
| """
|
| Send prompts to the resolved model.
|
|
|
| Returns:
|
| (response_text, model_identifier_used)
|
| """
|
| backend, variant = _resolve_route(self) if False else self._resolve_route()
|
| model_id = GROQ_MODEL_IDS.get(variant, GROQ_MODEL_IDS[ModelVariant.BASE])
|
| log.info(f"Routing β backend={backend.value} model={model_id}")
|
|
|
| if backend == ModelBackend.GROQ:
|
| return self._infer_groq(system_prompt, user_prompt, model_id)
|
|
|
| if backend == ModelBackend.HF_INFERENCE:
|
| hf_model = MODEL_IDS[ModelVariant.BIOS_INSIGHT]
|
| return self._infer_hf(system_prompt, user_prompt, hf_model)
|
|
|
| if backend == ModelBackend.OPENAI:
|
| return self._infer_openai(system_prompt, user_prompt)
|
|
|
| if backend == ModelBackend.GEMINI:
|
| return self._infer_gemini(system_prompt, user_prompt)
|
|
|
| if backend == ModelBackend.ANTHROPIC:
|
| return self._infer_anthropic(system_prompt, user_prompt)
|
|
|
|
|
| return self._mock_response(), "mock/bios-kernel-v1"
|
|
|
| def _infer_groq(self, system: str, user: str, model: str) -> tuple[str, str]:
|
| client = self._get_groq()
|
| response = client.chat.completions.create(
|
| model=model,
|
| messages=[
|
| {"role": "system", "content": system},
|
| {"role": "user", "content": user},
|
| ],
|
| temperature=self.temperature,
|
| max_tokens=self.max_tokens,
|
| response_format={"type": "json_object"},
|
| )
|
| return response.choices[0].message.content, f"groq/{model}"
|
|
|
| def _infer_hf(self, system: str, user: str, model: str) -> tuple[str, str]:
|
| client = self._get_hf()
|
| messages = [
|
| {"role": "system", "content": system},
|
| {"role": "user", "content": user},
|
| ]
|
| try:
|
| response = client.chat_completion(
|
| messages=messages,
|
| model=model,
|
| max_tokens=self.max_tokens,
|
| temperature=self.temperature,
|
| )
|
| return response.choices[0].message.content, f"hf/{model}"
|
| except Exception as e:
|
|
|
| log.warning("HF chat_completion failed (%s); trying text_generation", e)
|
| prompt = f"{system}\n\n{user}"
|
| text = client.text_generation(
|
| prompt,
|
| model=model,
|
| max_new_tokens=min(self.max_tokens, 2048),
|
| temperature=self.temperature,
|
| )
|
| return text, f"hf/{model}"
|
|
|
| def _infer_openai(self, system: str, user: str) -> tuple[str, str]:
|
| client = self._get_openai()
|
| response = client.chat.completions.create(
|
| model="gpt-4",
|
| messages=[
|
| {"role": "system", "content": system},
|
| {"role": "user", "content": user},
|
| ],
|
| temperature=self.temperature,
|
| max_tokens=self.max_tokens,
|
| response_format={"type": "json_object"},
|
| )
|
| return response.choices[0].message.content, "openai/gpt-4"
|
|
|
| def _infer_gemini(self, system: str, user: str) -> tuple[str, str]:
|
| client = self._get_gemini()
|
| combined_prompt = f"{system}\n\n{user}"
|
| response = client.generate_content(
|
| combined_prompt,
|
| generation_config={
|
| "temperature": self.temperature,
|
| "max_output_tokens": self.max_tokens,
|
| }
|
| )
|
| return response.text, "gemini/gemini-pro"
|
|
|
| def _infer_anthropic(self, system: str, user: str) -> tuple[str, str]:
|
| client = self._get_anthropic()
|
| message = client.messages.create(
|
| model="claude-sonnet-4-20250514",
|
| max_tokens=self.max_tokens,
|
| system=system,
|
| messages=[{"role": "user", "content": user}],
|
| )
|
| return message.content[0].text, "anthropic/claude-sonnet-4-20250514"
|
|
|
| def _mock_response(self) -> str:
|
| """Return a valid JSON mock for offline testing."""
|
| return json.dumps({
|
| "narrative": (
|
| "BIOS analysis complete. Your business shows strong foundational "
|
| "elements but faces challenges in customer retention and technology "
|
| "adoption. Prioritise loyalty initiatives and digital tooling to "
|
| "unlock the next growth tier."
|
| ),
|
| "model": "mock",
|
| })
|
|
|
|
|
|
|
|
|
|
|
|
|
| class DiagnosisEngine:
|
| """
|
| Implements the BIOS Module 1 scoring algorithms.
|
|
|
| All calculations are deterministic and reproducible β the LLM is only
|
| used to generate the qualitative narrative on top of these numbers.
|
| """
|
|
|
|
|
|
|
| @staticmethod
|
| def score_revenue(monthly_revenue: float) -> int:
|
| thresholds = [
|
| (50_000_000, 100),
|
| (20_000_000, 80),
|
| ( 5_000_000, 60),
|
| ( 1_000_000, 40),
|
| ]
|
| for threshold, score in thresholds:
|
| if monthly_revenue >= threshold:
|
| return score
|
| return 20
|
|
|
| @staticmethod
|
| def score_retention(rate: float) -> int:
|
| thresholds = [(80, 100), (60, 80), (40, 60), (20, 40)]
|
| for threshold, score in thresholds:
|
| if rate >= threshold:
|
| return score
|
| return 20
|
|
|
| @staticmethod
|
| def score_market_position(usp: str, competitors: str) -> int:
|
| words = len(usp.strip().split())
|
| base = 20
|
| if words >= 50: base = 80
|
| elif words >= 30: base = 60
|
| elif words >= 15: base = 40
|
|
|
| if competitors and len(competitors.strip()) > 5:
|
| base = min(100, base + 5)
|
| return base
|
|
|
| @staticmethod
|
| def score_technology(technology: list[str], industry: str = "Other") -> int:
|
| tech_lower = [t.lower() for t in technology]
|
| if not tech_lower or "none" in tech_lower:
|
| return 10
|
|
|
|
|
| if industry.lower() == "technology startup":
|
| advanced = {"cloud services", "microservices", "ai/ml", "blockchain", "devops", "kubernetes", "docker", "serverless", "api integration", "saas platform", "mobile app", "web app", "database", "analytics", "automation", "ci/cd", "git", "agile"}
|
| mid_tier = {"pos system", "accounting software", "inventory system", "crm", "erp", "project management", "collaboration tools"}
|
| basic = {"spreadsheets", "facebook business suite", "whatsapp business", "email marketing"}
|
| else:
|
|
|
| advanced = {"erp", "crm", "ai tools", "automation", "bi dashboard"}
|
| mid_tier = {"pos system", "accounting software", "inventory system"}
|
| basic = {"spreadsheets", "facebook business suite", "whatsapp business"}
|
|
|
| if any(t in advanced for t in tech_lower): return 100
|
| if any(t in mid_tier for t in tech_lower): return 60
|
| if any(t in basic for t in tech_lower): return 30
|
| return 20
|
|
|
| @staticmethod
|
| def score_growth(goal_12: float, current: float) -> int:
|
| if current <= 0:
|
| return 40
|
| rate = (goal_12 - current) / current * 100
|
| thresholds = [(50, 100), (30, 80), (10, 60), (0, 40)]
|
| for threshold, score in thresholds:
|
| if rate >= threshold:
|
| return score
|
| return 20
|
|
|
|
|
|
|
| def compute_dimensions(self, inp: BusinessInputs) -> HealthDimensions:
|
| return HealthDimensions(
|
| revenue_strength = self.score_revenue(inp.monthly_revenue),
|
| customer_retention = self.score_retention(inp.retention_rate),
|
| market_position = self.score_market_position(
|
| inp.unique_selling_proposition,
|
| inp.main_competitors),
|
| technology_adoption = self.score_technology(inp.current_technology, inp.industry),
|
| growth_trajectory = self.score_growth(
|
| inp.goal_12_month,
|
| inp.monthly_revenue),
|
| )
|
|
|
| @staticmethod
|
| def health_label(score: int) -> str:
|
| if score >= 80: return "Excellent"
|
| if score >= 65: return "Good"
|
| if score >= 45: return "Fair"
|
| if score >= 30: return "Below Average"
|
| return "Critical"
|
|
|
|
|
|
|
| def identify_weaknesses(
|
| self,
|
| inp: BusinessInputs,
|
| dims: HealthDimensions,
|
| ) -> list[Weakness]:
|
| bench = INDUSTRY_BENCHMARKS.get(inp.industry, INDUSTRY_BENCHMARKS["Other"])
|
| bench_scores = {
|
| "revenue_strength": self.score_revenue(bench["avg_revenue"]),
|
| "customer_retention": self.score_retention(bench["avg_retention"]),
|
| "market_position": 60,
|
| "technology_adoption": 60,
|
| "growth_trajectory": 60,
|
| }
|
| labels = {
|
| "revenue_strength": "Monthly Revenue",
|
| "customer_retention": "Customer Retention",
|
| "market_position": "Market Differentiation",
|
| "technology_adoption": "Technology Adoption",
|
| "growth_trajectory": "Growth Ambition",
|
| }
|
| details = {
|
| "revenue_strength": f"Revenue of {inp.monthly_revenue:,.0f} MMK is significantly below the {inp.industry} industry average.",
|
| "customer_retention": f"Only {inp.retention_rate:.0f}% repeat purchase rate β industry average is {bench['avg_retention']:.0f}%.",
|
| "market_position": "Your unique selling proposition needs greater clarity and depth to stand out.",
|
| "technology_adoption": "Low technology adoption is limiting operational efficiency and scalability.",
|
| "growth_trajectory": "Growth goals are misaligned with current revenue trajectory.",
|
| }
|
|
|
| user_scores = {
|
| "revenue_strength": dims.revenue_strength,
|
| "customer_retention": dims.customer_retention,
|
| "market_position": dims.market_position,
|
| "technology_adoption": dims.technology_adoption,
|
| "growth_trajectory": dims.growth_trajectory,
|
| }
|
|
|
| weaknesses: list[Weakness] = []
|
| for key, user_score in user_scores.items():
|
| b_score = bench_scores[key]
|
| if user_score < b_score * 0.8:
|
| gap = b_score - user_score
|
| severity = "HIGH" if gap > 30 else "MEDIUM" if gap > 15 else "LOW"
|
| weaknesses.append(Weakness(
|
| rank=0,
|
| dimension=key,
|
| label=labels[key],
|
| your_score=user_score,
|
| benchmark=b_score,
|
| gap=round(gap, 1),
|
| severity=severity,
|
| detail=details[key],
|
| ))
|
|
|
|
|
| sev_order = {"HIGH": 3, "MEDIUM": 2, "LOW": 1}
|
| weaknesses.sort(key=lambda w: (sev_order[w.severity], w.gap), reverse=True)
|
| top3 = weaknesses[:3]
|
| for i, w in enumerate(top3, 1):
|
| w.rank = i
|
| return top3
|
|
|
|
|
|
|
| def discover_opportunities(
|
| self,
|
| inp: BusinessInputs,
|
| dims: HealthDimensions,
|
| ) -> list[Opportunity]:
|
| bench = INDUSTRY_BENCHMARKS.get(inp.industry, INDUSTRY_BENCHMARKS["Other"])
|
| opps: list[Opportunity] = []
|
|
|
|
|
| if inp.goal_12_month > inp.monthly_revenue and inp.monthly_revenue > 0:
|
| pct = (inp.goal_12_month / inp.monthly_revenue - 1) * 100
|
| opps.append(Opportunity(
|
| rank=0,
|
| title="Scale Revenue Toward 12-Month Goal",
|
| description=f"Bridge the {pct:.0f}% gap to your {inp.goal_12_month:,.0f} MMK annual revenue target.",
|
| expected_impact=f"+{pct:.0f}% revenue growth",
|
| difficulty="MEDIUM",
|
| timeframe="6β12 months",
|
| revenue_uplift_mmk=inp.goal_12_month - inp.monthly_revenue,
|
| ))
|
|
|
|
|
| if inp.retention_rate < bench["avg_retention"]:
|
| gap = bench["avg_retention"] - inp.retention_rate
|
| monthly_g = (gap / 100) * inp.avg_customer_lifetime_value * max(inp.team_size, 1)
|
| opps.append(Opportunity(
|
| rank=0,
|
| title="Boost Customer Retention Rate",
|
| description=(
|
| f"Raise repeat-purchase rate by {gap:.0f}% to match the "
|
| f"{inp.industry} industry benchmark."
|
| ),
|
| expected_impact=f"+{monthly_g:,.0f} MMK estimated monthly revenue",
|
| difficulty="MEDIUM",
|
| timeframe="2β3 months",
|
| revenue_uplift_mmk=monthly_g * 12,
|
| ))
|
|
|
|
|
| if len(inp.sales_channels) < 3:
|
| needed = 3 - len(inp.sales_channels)
|
| opps.append(Opportunity(
|
| rank=0,
|
| title=f"Expand to {needed} New Sales Channel{'s' if needed > 1 else ''}",
|
| description="Diversifying beyond your current channels reduces single-point risk and opens new customer pools.",
|
| expected_impact="+20β30% customer reach",
|
| difficulty="EASY",
|
| timeframe="1β2 months",
|
| ))
|
|
|
|
|
| if dims.technology_adoption < 60:
|
| opps.append(Opportunity(
|
| rank=0,
|
| title="Adopt Core Business Technology",
|
| description="Implementing a CRM or POS system unlocks data-driven decisions and staff efficiency.",
|
| expected_impact="+15β25% operational efficiency",
|
| difficulty="MEDIUM",
|
| timeframe="2β4 weeks",
|
| ))
|
|
|
|
|
| if inp.monthly_marketing_budget < bench["avg_mkt"] * 0.5:
|
| opps.append(Opportunity(
|
| rank=0,
|
| title="Increase Marketing Investment",
|
| description=(
|
| f"Current budget of {inp.monthly_marketing_budget:,.0f} MMK "
|
| f"is far below the {inp.industry} average of {bench['avg_mkt']:,.0f} MMK."
|
| ),
|
| expected_impact="+10β20% new customer acquisition",
|
| difficulty="EASY",
|
| timeframe="1 month",
|
| ))
|
|
|
|
|
| for i, opp in enumerate(opps[:5], 1):
|
| opp.rank = i
|
| return opps[:5]
|
|
|
|
|
|
|
| RECOMMENDED_ACTIONS: dict[str, str] = {
|
| "revenue_strength": "Run a margin audit and introduce 2 high-value upsell products this month.",
|
| "customer_retention": "Launch a loyalty stamp card and a 30-day follow-up WhatsApp message sequence.",
|
| "market_position": "Rewrite your USP in one clear sentence and test it in Facebook ad copy.",
|
| "technology_adoption": "Set up a free CRM (HubSpot or Zoho) and import your customer contact list.",
|
| "growth_trajectory": "Break your 12-month target into monthly milestones and review weekly.",
|
| }
|
|
|
| def rank_priority_actions(
|
| self,
|
| weaknesses: list[Weakness],
|
| inp: BusinessInputs,
|
| ) -> list[ActionItem]:
|
| items: list[ActionItem] = []
|
| sev_urgency = {"HIGH": 85, "MEDIUM": 60, "LOW": 35}
|
|
|
| for w in weaknesses:
|
| urgency = float(sev_urgency.get(w.severity, 40))
|
| impact = min(100.0, w.gap * 1.6)
|
| feasibility = {"HIGH": 40.0, "MEDIUM": 65.0, "LOW": 80.0}.get(w.severity, 50.0)
|
| composite = round(urgency * 0.4 + impact * 0.4 + feasibility * 0.2, 1)
|
|
|
| items.append(ActionItem(
|
| priority=0,
|
| action=self.RECOMMENDED_ACTIONS.get(w.dimension, f"Address {w.label} urgently."),
|
| rationale=w.detail,
|
| urgency_score=urgency,
|
| impact_score=round(impact, 1),
|
| feasibility_score=feasibility,
|
| composite_score=composite,
|
| ))
|
|
|
| items.sort(key=lambda x: x.composite_score, reverse=True)
|
| for i, item in enumerate(items, 1):
|
| item.priority = i
|
| return items
|
|
|
|
|
|
|
| def build_benchmarking(
|
| self,
|
| inp: BusinessInputs,
|
| ) -> list[dict]:
|
| bench = INDUSTRY_BENCHMARKS.get(inp.industry, INDUSTRY_BENCHMARKS["Other"])
|
|
|
| def status(val: float, avg: float) -> str:
|
| if val >= avg * 1.10: return "ABOVE"
|
| if val <= avg * 0.90: return "BELOW"
|
| return "AT"
|
|
|
| return [
|
| {"metric": "Monthly Revenue", "your_value": inp.monthly_revenue, "industry_avg": bench["avg_revenue"], "unit": "MMK", "status": status(inp.monthly_revenue, bench["avg_revenue"])},
|
| {"metric": "Customer Retention Rate", "your_value": inp.retention_rate, "industry_avg": bench["avg_retention"], "unit": "%", "status": status(inp.retention_rate, bench["avg_retention"])},
|
| {"metric": "Avg Customer Lifetime Val","your_value": inp.avg_customer_lifetime_value, "industry_avg": bench["avg_clv"], "unit": "MMK", "status": status(inp.avg_customer_lifetime_value, bench["avg_clv"])},
|
| {"metric": "Marketing Budget", "your_value": inp.monthly_marketing_budget, "industry_avg": bench["avg_mkt"], "unit": "MMK", "status": status(inp.monthly_marketing_budget, bench["avg_mkt"])},
|
| {"metric": "Team Size", "your_value": float(inp.team_size), "industry_avg": float(bench["avg_team"]),"unit": "ppl", "status": status(inp.team_size, bench["avg_team"])},
|
| ]
|
|
|
|
|
|
|
|
|
|
|
|
|
| class InsightGenerator:
|
| """
|
| Constructs structured prompts for the BIOS LLM and parses its JSON output
|
| into the qualitative `ai_narrative` field of the DiagnosisReport.
|
| """
|
|
|
| SYSTEM_PROMPT = """You are BIOS β the Business Idea Operating System. You are the elite AI advisor for Myanmar SMEs, Gold Shops, and ambitious entrepreneurs across Southeast Asia.
|
|
|
| Your personality: professional, precise, encouraging, and bold β like a McKinsey partner who speaks to founders, not just analysts. You use the Dark & Gold luxury tone: every word carries weight, every recommendation is actionable.
|
|
|
| You always respond in valid JSON with this exact structure:
|
| {
|
| "narrative": "<3-paragraph executive summary in the user's preferred language>",
|
| "headline_insight": "<one powerful sentence that captures the core finding>"
|
| }
|
|
|
| Rules:
|
| - Be specific with numbers from the data provided
|
| - Use the language specified in preferred_language.
|
| - If preferred_language is "Both", provide the response in both English and Burmese (e.g., paragraph by paragraph or section by section).
|
| - Never be generic β reference the actual business, industry, and goals
|
| - Tone: elite advisory, not chatbot small talk"""
|
|
|
| def build_user_prompt(self, inp: BusinessInputs, dims: HealthDimensions, weaknesses: list[Weakness], opps: list[Opportunity]) -> str:
|
| weak_lines = "\n".join(
|
| f" {w.rank}. {w.label} β score {w.your_score:.0f} vs benchmark {w.benchmark:.0f} | severity: {w.severity}"
|
| for w in weaknesses
|
| )
|
| opp_lines = "\n".join(
|
| f" {o.rank}. {o.title}: {o.expected_impact} ({o.timeframe})"
|
| for o in opps[:3]
|
| )
|
|
|
| return f"""BIOS DIAGNOSIS DATA β analyse and generate insights.
|
|
|
| Business: {inp.business_name}
|
| Industry: {inp.industry} | Location: {inp.location}
|
| Years Operating: {inp.years_in_business} | Team: {inp.team_size} people
|
| Monthly Revenue: {inp.monthly_revenue:,.0f} MMK
|
| Retention Rate: {inp.retention_rate:.0f}%
|
| Monthly Marketing Budget: {inp.monthly_marketing_budget:,.0f} MMK
|
| Preferred Language: {inp.preferred_language}
|
|
|
| HEALTH SCORE: {dims.total}/100 β {DiagnosisEngine.health_label(dims.total)}
|
| Revenue Strength: {dims.revenue_strength}
|
| Customer Retention: {dims.customer_retention}
|
| Market Position: {dims.market_position}
|
| Technology Adoption: {dims.technology_adoption}
|
| Growth Trajectory: {dims.growth_trajectory}
|
|
|
| TOP WEAKNESSES:
|
| {weak_lines}
|
|
|
| TOP OPPORTUNITIES:
|
| {opp_lines}
|
|
|
| 12-Month Revenue Goal: {inp.goal_12_month:,.0f} MMK
|
| Unique Value Proposition: "{inp.unique_selling_proposition}"
|
| Biggest Pain Point: "{inp.biggest_pain_point}"
|
|
|
| Generate the executive narrative JSON now."""
|
|
|
| def parse_narrative(self, raw: str) -> str:
|
| """Extract narrative from LLM JSON response, with fallback."""
|
| try:
|
|
|
| clean = re.sub(r"```(?:json)?\s*", "", raw).strip().rstrip("```").strip()
|
| data = json.loads(clean)
|
| return data.get("narrative", raw)
|
| except (json.JSONDecodeError, AttributeError):
|
|
|
| return raw.strip()
|
|
|
|
|
|
|
|
|
|
|
|
|
| class NeonDBWriter:
|
| """
|
| Persists BIOS diagnosis reports to NeonDB (PostgreSQL) via psycopg v3.
|
| Matches the Prisma schema in schema.prisma.
|
| """
|
|
|
| def __init__(self, database_url: Optional[str] = None, security: Optional[SecurityManager] = None):
|
| if not PSYCOPG_AVAILABLE:
|
| raise ValueError(
|
| "psycopg is not available. Install it with: pip install psycopg[binary]"
|
| )
|
| self.database_url = database_url or os.getenv("DATABASE_URL")
|
| self.security = security or SecurityManager()
|
| if not self.database_url:
|
| raise ValueError(
|
| "DATABASE_URL not set. Export it or pass database_url= to NeonDBWriter."
|
| )
|
|
|
| self.database_url = self.database_url.replace(
|
| "postgresql+asyncpg://", "postgresql://"
|
| ).replace(
|
| "postgres+asyncpg://", "postgresql://"
|
| )
|
| self.user_manager = UserManager(self.database_url)
|
|
|
| def save_report(self, report: DiagnosisReport, user_id: Optional[str] = None) -> str:
|
| """
|
| Save a DiagnosisReport into the diagnoses and results tables.
|
| Returns the session_id/diagnosis_id.
|
| """
|
| d = report.to_dict()
|
| inp = report.inputs
|
| diagnosis_id = str(uuid.uuid4())
|
| session_id = d["sessionId"]
|
|
|
|
|
| sql_diagnosis = """
|
| INSERT INTO diagnoses (
|
| id, user_id, session_id, status,
|
| industry, location, years_in_business, monthly_revenue, team_size,
|
| ideal_customer, acquisition_channels, clv, repeat_purchase_rate,
|
| competitors, unique_selling_point, sales_channels,
|
| operational_challenge, pain_point, tech_stack, marketing_channels,
|
| marketing_budget, revenue_goals, budget_constraint,
|
| tech_readiness, preferred_language, created_at, updated_at
|
| ) VALUES (
|
| %s, %s, %s, %s,
|
| %s, %s, %s, %s, %s,
|
| %s, %s, %s, %s,
|
| %s, %s, %s,
|
| %s, %s, %s, %s,
|
| %s, %s, %s,
|
| %s, %s, NOW(), NOW()
|
| )
|
| """
|
|
|
|
|
| enc_revenue = self.security.encrypt(str(inp.monthly_revenue))
|
| enc_clv = self.security.encrypt(str(inp.avg_customer_lifetime_value))
|
| enc_pain_point = self.security.encrypt(inp.biggest_pain_point)
|
| enc_mkt_budget = self.security.encrypt(str(inp.monthly_marketing_budget))
|
| enc_rev_goals = self.security.encrypt(json.dumps({
|
| "3m": inp.goal_3_month,
|
| "6m": inp.goal_6_month,
|
| "12m": inp.goal_12_month
|
| }))
|
|
|
|
|
| norm_industry = inp.industry.replace(" ", "_").replace("&", "").replace("-", "_")
|
| if norm_industry == "F_B": norm_industry = "FB"
|
| if norm_industry == "Technology_Startup": norm_industry = "Startup"
|
|
|
| norm_location = inp.location
|
| if norm_location not in ["Yangon", "Mandalay", "Naypyidaw"]: norm_location = "Other"
|
|
|
| norm_challenge = inp.operational_challenge.replace(" ", "_")
|
| if norm_challenge not in ["Inventory_management", "Customer_service", "Marketing", "Payment_processing"]: norm_challenge = "Other"
|
|
|
| norm_budget = "Moderate_200_500K"
|
| if "50K" in inp.budget_constraint and "<" in inp.budget_constraint: norm_budget = "Very_tight_lt_50K"
|
| elif "50-200K" in inp.budget_constraint: norm_budget = "Tight_50_200K"
|
| elif "200-500K" in inp.budget_constraint: norm_budget = "Moderate_200_500K"
|
| elif "500K+" in inp.budget_constraint: norm_budget = "Comfortable_500K_plus"
|
|
|
| norm_readiness = inp.tech_readiness.replace(" ", "_")
|
| if norm_readiness not in ["Not_ready", "Somewhat_ready", "Very_ready", "Extremely_ready"]: norm_readiness = "Somewhat_ready"
|
|
|
| params_diagnosis = (
|
| diagnosis_id, user_id, session_id, 'completed',
|
| norm_industry, norm_location, inp.years_in_business, enc_revenue, inp.team_size,
|
| inp.target_customer, json.dumps(inp.acquisition_channels), enc_clv, inp.retention_rate,
|
| inp.main_competitors, inp.unique_selling_proposition, json.dumps(inp.sales_channels),
|
| norm_challenge, enc_pain_point, json.dumps(inp.current_technology), json.dumps(inp.marketing_channels),
|
| enc_mkt_budget, enc_rev_goals, norm_budget,
|
| norm_readiness, inp.preferred_language
|
| )
|
|
|
|
|
| sql_result = """
|
| INSERT INTO results (
|
| id, diagnosis_id, user_id,
|
| health_score, health_label, health_dimensions,
|
| weaknesses, opportunities, action_items,
|
| ai_narrative, model_used, generation_time_ms, pipeline,
|
| created_at
|
| ) VALUES (
|
| %s, %s, %s,
|
| %s, %s, %s,
|
| %s, %s, %s,
|
| %s, %s, %s, %s,
|
| NOW()
|
| )
|
| """
|
| params_result = (
|
| str(uuid.uuid4()), diagnosis_id, user_id,
|
| d["healthScore"]["total"], d["healthScore"]["label"], json.dumps(d["healthScore"]["dimensions"]),
|
| json.dumps(d["weaknesses"]), json.dumps(d["opportunities"]), json.dumps(d["actionItems"]),
|
| d["narrative"], d["modelUsed"], d["generationTimeMs"], d["pipeline"]
|
| )
|
|
|
| try:
|
| with psycopg.connect(self.database_url, row_factory=psycopg_dict_row) as conn:
|
| with conn.cursor() as cur:
|
| cur.execute(sql_diagnosis, params_diagnosis)
|
| cur.execute(sql_result, params_result)
|
| conn.commit()
|
| return session_id
|
| except Exception as e:
|
| log.error("Failed to save diagnosis to Neon: %s", e)
|
| return session_id
|
|
|
| def save_contact_lead(self, lead_data: dict) -> bool:
|
| """
|
| Saves a sales contact lead to the contact_leads table.
|
| """
|
| sql = """
|
| INSERT INTO contact_leads (
|
| first_name, last_name, email, company_name, job_title,
|
| country, project_budget, interests
|
| ) VALUES (
|
| %s, %s, %s, %s, %s, %s, %s, %s
|
| )
|
| """
|
| params = (
|
| lead_data["firstName"],
|
| lead_data["lastName"],
|
| lead_data["email"],
|
| lead_data["companyName"],
|
| lead_data["jobTitle"],
|
| lead_data["country"],
|
| lead_data["projectBudget"],
|
| json.dumps(lead_data["interests"])
|
| )
|
|
|
| try:
|
| with psycopg.connect(self.database_url) as conn:
|
| with conn.cursor() as cur:
|
| cur.execute(sql, params)
|
| conn.commit()
|
| return True
|
| except Exception as e:
|
| log.error("Failed to save contact lead to Neon: %s", e)
|
| return False
|
|
|
| def fetch_report(self, session_id: str) -> Optional[dict]:
|
| """Fetch a previously saved report by session_id and decrypt sensitive fields."""
|
| sql = """
|
| SELECT d.*, r.*
|
| FROM diagnoses d
|
| JOIN results r ON d.id = r.diagnosis_id
|
| WHERE d.session_id = %s
|
| """
|
| with psycopg.connect(self.database_url, row_factory=psycopg_dict_row) as conn:
|
| with conn.cursor() as cur:
|
| cur.execute(sql, (session_id,))
|
| row = cur.fetchone()
|
|
|
| if row:
|
| data = dict(row)
|
|
|
| data["monthly_revenue"] = self.security.decrypt(data["monthly_revenue"])
|
| data["clv"] = self.security.decrypt(data["clv"])
|
| data["pain_point"] = self.security.decrypt(data["pain_point"])
|
| data["marketing_budget"] = self.security.decrypt(data["marketing_budget"])
|
| data["revenue_goals"] = json.loads(self.security.decrypt(data["revenue_goals"]))
|
| data["ai_narrative"] = self.security.decrypt(data["ai_narrative"])
|
| return data
|
| return None
|
|
|
| def list_reports(self, limit: int = 20) -> list[dict]:
|
| """Return the most recent diagnoses with decrypted business names."""
|
| sql = "SELECT session_id, business_name, industry, health_score, health_label, status, created_at FROM diagnoses ORDER BY created_at DESC LIMIT %s"
|
| with psycopg.connect(self.database_url, row_factory=psycopg_dict_row) as conn:
|
| with conn.cursor() as cur:
|
| cur.execute(sql, (limit,))
|
| rows = cur.fetchall()
|
|
|
| results = []
|
| for r in rows:
|
| data = dict(r)
|
| if "business_name" in data:
|
| data["business_name"] = self.security.decrypt(data["business_name"])
|
| results.append(data)
|
| return results
|
|
|
|
|
|
|
|
|
|
|
| class BIOSController:
|
| """
|
| BIOS-kernel-v1 Β· Business Idea Operating System Β· Module 1 Controller
|
|
|
| Orchestrates the full diagnosis pipeline:
|
| inputs β scoring β LLM narrative β structured report β NeonDB
|
|
|
| Usage:
|
| controller = BIOSController()
|
| report = controller.run_diagnosis(inputs)
|
| print(report.to_json())
|
|
|
| To use the fine-tuned BIOS-Insight-v1 when it becomes available on HF:
|
| controller = BIOSController(bios_insight_ready=True)
|
| """
|
|
|
| VERSION = "1.0.0"
|
| KERNEL = "BIOS-kernel-v1"
|
|
|
| def __init__(
|
| self,
|
| backend: ModelBackend = ModelBackend.GROQ,
|
| bios_insight_ready: bool = False,
|
| temperature: float = 0.3,
|
| max_tokens: int = 2048,
|
| database_url: Optional[str] = None,
|
| save_to_db: bool = True,
|
| encryption_key: Optional[str] = None,
|
| ):
|
| self.security = SecurityManager(encryption_key)
|
| self.router = ModelRouter(
|
| backend=backend,
|
| bios_insight_ready=bios_insight_ready,
|
| temperature=temperature,
|
| max_tokens=max_tokens,
|
| )
|
| self.engine = DiagnosisEngine()
|
| self.generator = InsightGenerator()
|
| self.save_to_db = save_to_db
|
|
|
|
|
| self._db: Optional[NeonDBWriter] = None
|
| self._db_url = database_url
|
|
|
| log.info(
|
| f"βββββββββββββββββββββββββββββββββββββββββββββ\n"
|
| f" BIOS Controller v{self.VERSION} Β· {self.KERNEL}\n"
|
| f" backend={backend.value} | save_db={save_to_db}\n"
|
| f"βββββββββββββββββββββββββββββββββββββββββββββ"
|
| )
|
|
|
| @property
|
| def db(self) -> NeonDBWriter:
|
| if self._db is None:
|
| self._db = NeonDBWriter(self._db_url, security=self.security)
|
| return self._db
|
|
|
|
|
|
|
| def run_diagnosis(self, inputs: BusinessInputs, user_id: Optional[str] = None) -> DiagnosisReport:
|
| """
|
| Full Module 1 pipeline.
|
|
|
| Args:
|
| inputs: Completed BusinessInputs with all 24 question answers.
|
| user_id: Optional UUID of the authenticated user.
|
|
|
| Returns:
|
| DiagnosisReport with health_score, top_3_weaknesses,
|
| growth_opportunities, priority_action_items, and ai_narrative.
|
| """
|
| t_start = time.perf_counter()
|
| session_id = str(uuid.uuid4())
|
|
|
| log.info(f"βΆ Starting BIOS diagnosis | business='{inputs.business_name}' | session={session_id}")
|
|
|
|
|
| dims = self.engine.compute_dimensions(inputs)
|
| score = dims.total
|
| label = self.engine.health_label(score)
|
| log.info(f" Health Score: {score}/100 ({label})")
|
| log.info(f" Dimensions: Rev={dims.revenue_strength} Ret={dims.customer_retention} Mkt={dims.market_position} Tech={dims.technology_adoption} Grow={dims.growth_trajectory}")
|
|
|
|
|
| weaknesses = self.engine.identify_weaknesses(inputs, dims)
|
| log.info(f" Weaknesses identified: {[w.label for w in weaknesses]}")
|
|
|
|
|
| opportunities = self.engine.discover_opportunities(inputs, dims)
|
| log.info(f" Opportunities found: {len(opportunities)}")
|
|
|
|
|
| actions = self.engine.rank_priority_actions(weaknesses, inputs)
|
|
|
|
|
| benchmarking = self.engine.build_benchmarking(inputs)
|
|
|
|
|
| narrative, model_used = self._generate_narrative(inputs, dims, weaknesses, opportunities)
|
| log.info(f" Narrative generated | model={model_used}")
|
|
|
| t_ms = int((time.perf_counter() - t_start) * 1000)
|
|
|
|
|
| report = DiagnosisReport(
|
| session_id = session_id,
|
| business_name = inputs.business_name,
|
| industry = inputs.industry,
|
| location = inputs.location,
|
| generated_at = datetime.now(timezone.utc).isoformat(),
|
| health_score = score,
|
| health_label = label,
|
| health_dimensions = dims,
|
| top_3_weaknesses = weaknesses,
|
| growth_opportunities = opportunities,
|
| priority_action_items= actions,
|
| ai_narrative = narrative,
|
| benchmarking = benchmarking,
|
| model_used = model_used,
|
| generation_time_ms = t_ms,
|
| inputs = inputs,
|
| )
|
|
|
| log.info(f"β Diagnosis complete | score={score} | {t_ms}ms")
|
|
|
|
|
| if self.save_to_db:
|
| try:
|
| self.db.save_report(report, user_id=user_id)
|
| except Exception as e:
|
| log.warning(f"DB save failed (non-fatal): {e}")
|
|
|
| return report
|
|
|
| def _generate_narrative(
|
| self,
|
| inp: BusinessInputs,
|
| dims: HealthDimensions,
|
| weak: list[Weakness],
|
| opps: list[Opportunity],
|
| ) -> tuple[str, str]:
|
| """Call the LLM and return (narrative_text, model_identifier)."""
|
| system = self.generator.SYSTEM_PROMPT
|
| user = self.generator.build_user_prompt(inp, dims, weak, opps)
|
| try:
|
| raw, model_id = self.router.infer(system, user)
|
| narrative = self.generator.parse_narrative(raw)
|
| return narrative, model_id
|
| except Exception as e:
|
| log.warning(f"LLM call failed, using fallback narrative: {e}")
|
| fallback = (
|
| f"{inp.business_name} received a BIOS Health Score of {dims.total}/100 ({self.engine.health_label(dims.total)}). "
|
| f"Key areas for immediate attention: {', '.join(w.label for w in weak[:2])}. "
|
| f"Top opportunity: {opps[0].title if opps else 'revenue diversification'}."
|
| )
|
| return fallback, "fallback/static"
|
|
|
|
|
|
|
| def switch_to_bios_insight(self):
|
| """Activate BIOS-Insight-v1 once it is published on HuggingFace."""
|
| self.router.bios_insight_ready = True
|
| self.router.variant = ModelVariant.BIOS_INSIGHT
|
| log.info("π Switched to BIOS-Insight-v1 (fine-tuned model)")
|
|
|
| def switch_to_base(self):
|
| """Revert to base llama-3.3-70b model."""
|
| self.router.bios_insight_ready = False
|
| self.router.variant = ModelVariant.BASE
|
| log.info("Reverted to base model (llama-3.3-70b)")
|
|
|
| def get_report(self, session_id: str) -> Optional[dict]:
|
| """Retrieve a saved report from NeonDB."""
|
| return self.db.fetch_report(session_id)
|
|
|
| def list_reports(self, limit: int = 20) -> list[dict]:
|
| """List recent diagnosis reports from NeonDB."""
|
| return self.db.list_reports(limit)
|
|
|
|
|
|
|
|
|
|
|
|
|
| def _demo_inputs() -> BusinessInputs:
|
| """Sample Technology Startup business for demonstration."""
|
| return BusinessInputs(
|
|
|
| business_name = "MyanmarTech Solutions",
|
| industry = "Technology Startup",
|
| location = "Yangon",
|
| years_in_business = 2,
|
| monthly_revenue = 8_500_000,
|
| team_size = 12,
|
|
|
| target_customer = "SMEs in Myanmar seeking digital transformation and automation solutions.",
|
| acquisition_channels = ["LinkedIn", "Tech Meetups", "Referrals", "Online Ads"],
|
| avg_customer_lifetime_value = 3_200_000,
|
| retention_rate = 75.0,
|
| main_competitors = "Digital Myanmar, TechHub Asia, CloudBase Solutions",
|
| unique_selling_proposition = "We provide AI-powered business automation specifically designed for Myanmar SMEs, with local language support and compliance.",
|
|
|
| sales_channels = ["SaaS Platform", "Direct Sales", "Partners"],
|
| operational_challenge = "Scaling infrastructure while maintaining service quality",
|
| biggest_pain_point = "Customer onboarding complexity - need streamlined setup process",
|
| current_technology = ["Cloud Services", "AI/ML", "Microservices", "DevOps", "CI/CD"],
|
| marketing_channels = ["LinkedIn", "Google Ads", "Content Marketing", "Tech Events"],
|
| monthly_marketing_budget= 1_200_000,
|
|
|
| goal_3_month = 12_000_000,
|
| goal_6_month = 18_000_000,
|
| goal_12_month = 35_000_000,
|
| budget_constraint = "Flexible (1M+)",
|
| tech_readiness = "Very ready",
|
| preferred_language = "English",
|
| )
|
|
|
|
|
| if __name__ == "__main__":
|
| print("\n" + "=" * 60)
|
| print(" BIOS β Business Idea Operating System")
|
| print(" BIOS-kernel-v1 Β· Module 1: Business Diagnosis")
|
| print("=" * 60 + "\n")
|
|
|
|
|
|
|
| controller = BIOSController(
|
| backend = ModelBackend.GROQ,
|
| save_to_db = bool(os.getenv("DATABASE_URL")),
|
| )
|
|
|
|
|
| inputs = _demo_inputs()
|
| report = controller.run_diagnosis(inputs)
|
|
|
|
|
| print("\n" + "-" * 60)
|
| print(" BIOS DIAGNOSIS REPORT")
|
| print("-" * 60)
|
| print(report.to_json())
|
|
|
| print("\n" + "=" * 60)
|
| print(f" Health Score : {report.health_score}/100 ({report.health_label})")
|
| print(f" Session ID : {report.session_id}")
|
| print(f" Model Used : {report.model_used}")
|
| print(f" Generated in : {report.generation_time_ms}ms")
|
| print("=" * 60 + "\n")
|
|
|