rubrav2 / app.py
getalvi's picture
Update app.py
79f33d0 verified
Raw
History Blame Contribute Delete
272 kB
"""
RUBRA v8 — Ultimate Agentic Intelligence
NEW: Multi-model Vision (Groq Vision + Qwen2.5-VL + OCR.space)
NCTB 2026 Full Curriculum Knowledge
UI/UX Pro Max Coding Engine (67 styles, 161 rules)
Advanced Free Models upgraded
"""
import os,sys,re,json,time,uuid,math,sqlite3,hashlib,asyncio,logging
import base64,mimetypes,io,threading
import xml.etree.ElementTree as ET
from pathlib import Path
from typing import Optional,AsyncIterator
from datetime import datetime,timezone
import aiohttp,requests as _req
from fastapi import FastAPI,UploadFile,File,Form,WebSocket,WebSocketDisconnect
from fastapi.middleware.cors import CORSMiddleware
from fastapi.responses import StreamingResponse,JSONResponse
from pydantic import BaseModel
from urllib.parse import urljoin, urlparse, quote_plus
from html.parser import HTMLParser
import urllib.robotparser
HERE = Path(__file__).resolve().parent
os.chdir(str(HERE))
# ═══════════════════════════════════════════════════════
# API KEYS
# ═══════════════════════════════════════════════════════
ZAI_KEY = os.getenv("ZAI_API_KEY", "b4a30453455d4c5fa63d63ce32b71506.k1s8vXrPLKnr3m5l")
GROQ_KEY = os.getenv("GROQ_API_KEY", "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")
OR_KEY = os.getenv("OPENROUTER_KEY", "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")
OCR_KEY = os.getenv("OCR_SPACE_KEY", "helloworld")
GEMINI_KEY = os.getenv("GEMINI_API_KEY", "AIzaSyAu4k8XvVMVse2oV47u2QFLOJcqOxUui-c")
CEREBRAS_KEY = os.getenv("CEREBRAS_API_KEY", "csk-hrrmp8cp4j94kdhdxcdjp8v3ctmvc2tc3et2pyyywdr9xjjw")
ZAI_CHAT = "https://api.z.ai/api/paas/v4/chat/completions"
ZAI_CODE = "https://api.z.ai/api/coding/paas/v4/chat/completions"
GROQ_URL = "https://api.groq.com/openai/v1/chat/completions"
OR_URL = "https://openrouter.ai/api/v1/chat/completions"
GEMINI_URL = "https://generativelanguage.googleapis.com/v1beta/openai/chat/completions"
CEREBRAS_URL = "https://api.cerebras.ai/v1/chat/completions"
DB_PATH = HERE / "rubra.db"
UPLOAD_DIR = HERE / "uploads"
UPLOAD_DIR.mkdir(exist_ok=True)
import shutil
# ── Agentic Skill Directory ──────────────────────────────
SKILLS_DIR = HERE / "skills"
SKILLS_DIR.mkdir(exist_ok=True)
# ── JSON Session Memory (persistent) ────────────────────
SESSION_DIR = HERE / "sessions"
SESSION_DIR.mkdir(exist_ok=True)
def session_path(sid: str) -> Path:
return SESSION_DIR / f"{sid}.json"
def session_load(sid: str) -> dict:
p = session_path(sid)
if p.exists():
try: return json.loads(p.read_text())
except: pass
return {"session_id":sid,"created_at":time.time(),"user_intent_history":[],
"preferred_lang":"en","coding_style":"clean","topic_memory":{},
"skill_calls":[],"thought_chain":[]}
def session_save(sid: str, data: dict):
try: session_path(sid).write_text(json.dumps(data,ensure_ascii=False,indent=2))
except Exception as e: log.warning(f"Session save: {e}")
def session_update(sid: str, key: str, value):
data = session_load(sid)
if key in ("user_intent_history","skill_calls","thought_chain"):
lst = data.get(key,[]); lst.append(value); data[key] = lst[-50:]
else: data[key] = value
session_save(sid, data)
logging.basicConfig(level=logging.INFO, format="%(asctime)s %(levelname)s %(message)s")
log = logging.getLogger("rubra")
# ═══════════════════════════════════════════════════════
# UI/UX PRO MAX v2.5 — FULL SKILL MODULE FOR app.py
# Source: nextlevelbuilder/ui-ux-pro-max-skill (v2.5.0)
# ═══════════════════════════════════════════════════════
import csv, io, math, re
from typing import Optional
# ── DATA TABLES ─────────────────────────────────────────
# Converted from CSV databases in src/ui-ux-pro-max/data/
# 67 UI STYLES
_STYLES_CSV = """id,name,keywords,best_for,performance,accessibility,effects,avoid
1,Minimalism & Swiss Style,"minimal,clean,simple,whitespace,grid,typography",Enterprise apps / dashboards / documentation,Excellent,WCAG AA,"Strict grid, typography-first, monochrome","Excessive decoration, gradients"
2,Neumorphism,"soft,shadow,emboss,depth,subtle,tactile",Health/wellness / meditation / premium tools,Good,Moderate,"Soft box-shadows, monochromatic surfaces","Dark backgrounds, low contrast"
3,Glassmorphism,"glass,frosted,blur,transparent,modern,saas",Modern SaaS / fintech dashboards / AI products,Good,WCAG AA,"backdrop-filter:blur, rgba backgrounds, subtle borders","Pure white bg (needs dark/image bg)"
4,Brutalism,"raw,bold,borders,clash,chaotic,contrast",Design portfolios / artistic projects / anti-brand,Excellent,Moderate,"Thick borders, unexpected layouts, monospace","Subtlety, drop shadows"
5,3D & Hyperrealism,"3d,realistic,immersive,product,depth",Gaming / product showcase / immersive experiences,Heavy,Moderate,"Three.js / CSS 3D transforms, ambient lighting","Flat icons, 2D-only approach"
6,Vibrant & Block-based,"vibrant,block,bold,color,punch,energy",Startups / creative agencies / gaming,Good,WCAG AA,"Bold color blocks, high contrast, geometric","Muted palettes, soft shadows"
7,Dark Mode OLED,"dark,black,oled,night,low-light,code",Night apps / coding platforms / media,Excellent,WCAG AA,"#000000 bg, minimal battery (OLED), subtle glows","Pure white text (use #e2e8f0)"
8,Accessible & Ethical,"accessible,wcag,inclusive,government,high-contrast",Government / healthcare / education,Excellent,WCAG AAA,"4.5:1+ contrast, skip links, focus rings","Decorative-only elements"
9,Claymorphism,"clay,3d-soft,puffy,inflated,cartoon,playful",Educational / children's / SaaS onboarding,Good,Moderate,"Inflated 3D shapes, pastel fills, thick outlines","Photorealism, dark themes"
10,Aurora UI,"aurora,gradient,mesh,glow,animated,modern",Modern SaaS / creative agencies / AI,Good,WCAG AA,"Gradient mesh bg, animated aurora effects","Static solid backgrounds"
11,Retro-Futurism,"retro,80s,synthwave,neon,nostalgia,sci-fi",Gaming / entertainment / music platforms,Good,Moderate,"Scanlines, neon glows, grid lines, CRT effects","Flat modern icons"
12,Flat Design,"flat,simple,2d,clean,icon,material-lite",Web apps / mobile apps / startup MVPs,Excellent,WCAG AA,"No shadows, bold icons, solid fills","Gradients, textures, 3D"
13,Skeuomorphism,"realistic,texture,leather,wood,physical,tangible",Legacy apps / premium audio / gaming,Heavy,Moderate,"Texture fills, realistic shadows, material surfaces","Overuse (looks dated)"
14,Liquid Glass,"liquid,fluid,premium,shine,depth,apple",Premium SaaS / high-end e-commerce,Good,WCAG AA,"Multi-layer blur, prismatic effects, specular highlights","Low-end devices (perf)"
15,Motion-Driven,"motion,animation,scroll,reveal,gsap,storytelling",Portfolio sites / storytelling / brand launches,Heavy,Moderate,"GSAP/Framer scroll triggers, parallax, SVG morphing","prefers-reduced-motion neglect"
16,Micro-interactions,"micro,feedback,haptic,touch,response,mobile",Mobile apps / touchscreen UIs / forms,Good,WCAG AA,"Bounce, spring physics, press states, ripple","Desktop-only hover states"
17,Inclusive Design,"inclusive,a11y,screen-reader,wcag-aaa,empathy",Public services / education / healthcare,Excellent,WCAG AAA,"High contrast modes, large targets 44px+, aria labels","Icon-only buttons"
18,Zero Interface,"voice,ai,ambient,invisible,conversational,minimal",Voice assistants / AI platforms / smart home,Excellent,High,"Minimal chrome, audio feedback, ambient display","Visual overload"
19,Soft UI Evolution,"soft,modern,rounded,neutral,enterprise,saas",Modern enterprise / SaaS / productivity,Excellent,WCAG AA,"Subtle elevation, rounded-2xl, neutral palette","Sharp edges, harsh shadows"
20,Neubrutalism,"neubrutalism,thick-border,offset-shadow,flat,genz,figma",Gen Z brands / startups / Figma-style,Excellent,WCAG AA,"2-4px solid borders, offset box-shadow, flat fills","Subtle or rounded styles"
21,Bento Box Grid,"bento,grid,card,dashboard,asymmetric,modular",Dashboards / product pages / portfolios,Excellent,WCAG AA,"Asymmetric grids, varying card sizes, hover reveals","Single-column layouts"
22,Y2K Aesthetic,"y2k,chrome,bubble,millennium,iridescent,2000s",Fashion / music / Gen Z,Good,Moderate,"Chrome text, iridescent fills, bubble UI, star shapes","Minimalism"
23,Cyberpunk UI,"cyber,neon,dark,grid,glitch,hacker,matrix",Gaming / tech products / crypto apps,Good,Moderate,"Neon #00fff5/#ff00ff, grid overlays, glitch animations","Pastel colors"
24,Organic Biophilic,"organic,nature,leaf,earth,green,wellness",Wellness apps / sustainability brands,Good,WCAG AA,"Leaf shapes, earth tones, organic curves, textures","Geometric rigidity"
25,AI-Native UI,"ai,chat,copilot,streaming,dark,assistant",AI products / chatbots / copilots,Excellent,WCAG AA,"Dark base #0a0a0a, typing indicators, token streaming","Busy backgrounds"
26,Memphis Design,"memphis,geometric,pattern,80s,playful,retro",Creative agencies / music / youth brands,Good,Moderate,"Bold geometric shapes, primary colors, pattern fills","Subtlety"
27,Vaporwave,"vaporwave,pink,purple,retrowave,aesthetic,sunset",Music platforms / gaming / portfolios,Good,Moderate,"#ff6ec7/#b967ff palette, grid floors, retro 3D","Corporate contexts"
28,Dimensional Layering,"layers,depth,z-index,card,floating,elevation",Dashboards / card layouts / modals,Good,WCAG AA,"Multiple elevation levels, floating panels, blur depth","Flat single-layer"
29,Exaggerated Minimalism,"extreme,whitespace,large-type,fashion,editorial",Fashion / architecture / luxury,Excellent,Moderate,"Massive whitespace, oversized typography, restraint","Crowded layouts"
30,Kinetic Typography,"kinetic,text-animation,headline,gsap,scroll",Hero sections / marketing sites / brand,Heavy,Moderate,"Text reveals, character-by-character, scroll-linked","Body text animations"
31,Parallax Storytelling,"parallax,scroll,depth,story,reveal,brand",Brand storytelling / product launches,Heavy,Moderate,"Multi-layer parallax, scroll-triggered reveals","prefers-reduced-motion neglect"
32,Swiss Modernism 2.0,"swiss,grid,helvetica,corporate,architecture,editorial",Corporate / architecture / editorial,Excellent,WCAG AA,"Strict typographic grid, Helvetica/Neue, asymmetry","Decorative elements"
33,HUD Sci-Fi FUI,"hud,fui,hologram,scan,radar,space,tech",Sci-fi games / space tech / cybersecurity,Good,Moderate,"Radar animations, scan lines, holographic circles","Consumer apps"
34,Pixel Art,"pixel,8bit,retro,game,sprite,indie",Indie games / retro tools / creative,Good,Moderate,"Pixel fonts, sprite animations, grid-snapped","High-res photography"
35,Spatial UI VisionOS,"spatial,visionos,ar,vr,depth,frosted,apple",Spatial computing / VR/AR apps,Good,Moderate,"Multi-plane layers, frosted glass panels, depth","2D flat interfaces"
36,E-Ink Paper,"e-ink,paper,reading,monochrome,newspaper,minimal",Reading apps / digital newspapers,Excellent,WCAG AA,"High contrast B&W, minimal animation, serif type","Color fills, animations"
37,Gen Z Chaos Maximalism,"maximal,chaotic,clutter,intense,doomscroll,loud",Gen Z lifestyle / music artists,Good,Low,"Overlapping elements, mixed fonts, noise textures","Order and alignment"
38,Biomimetic Organic,"biomimetic,biotech,science,organic-2,cell,nature-tech",Sustainability tech / biotech / health,Good,Moderate,"Cell-like shapes, bioluminescent glows, fluid motion","Rigid geometric"
39,Anti-Polish Raw,"raw,unfinished,authentic,sketch,handmade,lo-fi",Creative portfolios / artist sites,Excellent,Moderate,"Sketch lines, imperfect shapes, handwritten type","Polished corporate"
40,Tactile Deformable,"tactile,press,deform,elastic,spring,physical",Modern mobile / playful brands,Good,WCAG AA,"Spring physics on press, elastic deformation","Desktop-only designs"
41,Nature Distilled,"nature,botanical,minimal-organic,calm,earth,leaf",Wellness brands / sustainable products,Excellent,WCAG AA,"Botanical illustrations, earth tones, organic type","Neon or synthetic colors"
42,Interactive Cursor,"cursor,custom,trail,magnetic,hover-effect,creative",Creative portfolios / interactive agencies,Good,Moderate,"Magnetic hover, cursor trails, custom SVG cursors","Mobile (no cursor)"
43,Voice-First Multimodal,"voice,multimodal,speech,waveform,accessibility-first",Voice assistants / accessibility apps,Excellent,WCAG AAA,"Waveform animations, voice indicators, minimal text","Dense UI"
44,3D Product Preview,"3d-product,ecommerce-3d,rotate,webgl,try-on,ar",E-commerce / furniture / fashion,Heavy,Moderate,"Three.js product viewer, AR try-on, zoom controls","Non-product pages"
45,Gradient Mesh Aurora,"mesh,aurora-evolved,gradient-mesh,background,hero",Hero sections / backgrounds / creative,Good,WCAG AA,"CSS mesh gradients, animated color stops","Overuse on content areas"
46,Editorial Grid Magazine,"editorial,magazine,grid-break,journalism,article",News sites / blogs / magazines,Excellent,WCAG AA,"Pull quotes, column grids, drop caps, image bleeds","Dashboard layouts"
47,Chromatic Aberration,"chromatic,rgb-split,glitch-color,psychedelic,lens",Music platforms / gaming / experimental,Good,Moderate,"RGB channel offset, lens distortion, color split","Professional contexts"
48,Vintage Analog Retro Film,"vintage,film,grain,analog,vinyl,photography-retro",Photography / music / vinyl brands,Good,Moderate,"Film grain overlay, sepia/fade, retro color grading","Modern tech products"
49,Hero-Centric Design,"hero,landing,fullscreen,above-fold,cta,conversion",Products with strong visual identity,Excellent,WCAG AA,"Full-viewport hero, single CTA, visual hierarchy","Feature-heavy first screen"
50,Conversion-Optimized,"conversion,cro,sales,lead-gen,funnel,cta-heavy",Lead generation / sales pages,Excellent,WCAG AA,"CTA repetition, urgency signals, social proof inline","Distracting animations"
51,Feature-Rich Showcase,"features,saas-landing,comparison,benefits,icons",SaaS / complex products,Good,WCAG AA,"Feature grid, icon + text, comparison tables","Wall of text"
52,Minimal & Direct,"minimal-landing,simple,fast,single-cta,startup",Simple products / apps / MVPs,Excellent,WCAG AA,"One message, one CTA, fast load","Feature overload"
53,Social Proof Focused,"testimonial,review,trust,rating,social-proof,b2c",Services / B2C products,Excellent,WCAG AA,"Star ratings, photo testimonials, logos bar","Generic stock photos"
54,Interactive Product Demo,"demo,interactive,saas-demo,try,product-tour",Software / tools,Good,WCAG AA,"Inline demos, hotspot tours, video embeds","Autoplay audio"
55,Trust & Authority,"b2b,enterprise,authority,case-study,white-paper",B2B / enterprise / consulting,Excellent,WCAG AA,"Case studies, client logos, certifications","Casual or playful tone"
56,Storytelling-Driven Landing,"story,narrative,scroll-story,brand-story,emotional",Brands / agencies / nonprofits,Good,WCAG AA,"Chapter-based scroll, emotional photography","Hard selling"
57,Data-Dense Dashboard,"data-dense,bi,analytics,tables,metrics,kpi",Complex data analysis,Good,WCAG AA,"Compact rows, sparklines, progressive disclosure","Large empty space"
58,Heat Map Style,"heatmap,geographic,behavioral,density,choropleth",Geographic / behavior data,Good,Moderate,"Color gradient maps, zoom controls, legends","Non-data contexts"
59,Executive Dashboard,"executive,c-suite,summary,kpi-only,high-level",C-suite summaries,Excellent,WCAG AA,"Large KPI numbers, trend arrows, minimal detail","Detailed raw data"
60,Real-Time Monitoring,"realtime,ops,devops,alert,live-feed,websocket",Operations / DevOps / trading,Good,WCAG AA,"Live updates, alert badges, status indicators","Static screenshots"
61,Drill-Down Analytics,"drilldown,explore,filter,pivot,tableau-style",Detailed data exploration,Good,WCAG AA,"Expandable rows, filter panels, breadcrumb nav","Flat single-level"
62,Comparative Analysis,"compare,side-by-side,benchmark,before-after,vs",Side-by-side comparisons,Good,WCAG AA,"Split layouts, synchronized scroll, diff views","Single-view only"
63,Predictive Analytics,"predictive,forecast,ml,trend,projection,ai-chart",Forecasting / ML insights,Good,WCAG AA,"Confidence bands, scenario toggles, trend lines","Historical-only views"
64,User Behavior Analytics,"uba,session,funnel,cohort,product-analytics",UX research / product analytics,Good,WCAG AA,"Funnel charts, session replays, cohort grids","Generic BI styles"
65,Financial Dashboard,"finance,accounting,p&l,revenue,cashflow,trading",Finance / accounting,Good,WCAG AA,"Candlestick charts, P&L tables, green/red coding","Casual color palette"
66,Sales Intelligence,"sales,crm,pipeline,deals,revenue-forecast,salesforce",Sales teams / CRM,Good,WCAG AA,"Pipeline stages, win/loss, quota progress bars","Non-sales contexts"
67,Ambient Calm UI,"calm,ambient,peaceful,breathe,zen,wellness-app",Meditation / sleep / mental health,Excellent,WCAG AA,"Slow animations, muted palette, breathing space","High-energy interactions"
"""
# 161 REASONING RULES (product type → design system)
_RULES_CSV = """id,product_type,keywords,pattern,style_priority,color_mood,typography_mood,key_effects,anti_patterns
1,SaaS Platform,"saas,software,subscription,b2b,platform",Feature-Rich Showcase,Glassmorphism|Soft UI Evolution|Bento Box Grid,Blue-indigo neutral,"Inter/DM Sans, clean","Subtle hover elevations, smooth transitions","AI purple gradients on white"
2,Micro SaaS,"micro-saas,indie,solo,niche,small-saas",Minimal & Direct,Minimalism|Flat Design|Neubrutalism,Focused monochrome,"Geist, modern mono","Single CTA, fast load","Feature overload"
3,B2B Service,"b2b,enterprise,consulting,professional,corporate",Trust & Authority,Swiss Modernism 2.0|Soft UI Evolution,Navy-gray professional,"Neue Haas, IBM Plex","Case study cards, logo bars","Playful colors, emoji icons"
4,Developer Tool IDE,"developer,devtool,ide,coding,terminal,cli",Dark Mode OLED|Minimal & Direct,Dark Mode OLED|Neubrutalism,Dark #0d1117 green accent,"JetBrains Mono, Geist Mono","Syntax highlighting, terminal feel","Colorful gradients"
5,AI Chatbot Platform,"ai,chatbot,llm,assistant,copilot,gpt",AI-Native UI,AI-Native UI|Glassmorphism,Dark #0a0a0a rose/cyan accent,"Space Grotesk, JetBrains Mono","Token streaming, typing dots, glow","Busy backgrounds"
6,Cybersecurity Platform,"security,cyber,soc,threat,firewall,pentest",HUD Sci-Fi FUI|Dark Mode OLED,HUD Sci-Fi FUI|Dark Mode OLED,Dark green matrix or dark blue,"Roboto Mono, IBM Plex Mono","Scan animations, alert pulses","Pastel friendly colors"
7,No-Code Builder,"nocode,builder,drag-drop,visual,lowcode,website-builder",Bento Box Grid|Claymorphism,Bento Box Grid|Claymorphism|Flat Design,Vibrant primary,"Nunito, Poppins","Drag handles, live preview","Complex dark themes"
8,Project Management,"project,task,kanban,todo,agile,trello,jira",Bento Box Grid|Soft UI Evolution,Bento Box Grid|Dimensional Layering,Neutral productive,"Inter, DM Sans","Drag kanban, progress bars","Information overload"
9,Analytics Dashboard,"analytics,dashboard,metrics,kpi,reporting,bi",Data-Dense Dashboard,Bento Box Grid|Data-Dense Dashboard,Dark navy or white clean,"DM Mono, IBM Plex","Recharts/Chart.js, sparklines","Decorative-only charts"
10,Fintech Crypto,"fintech,crypto,bitcoin,defi,wallet,blockchain,trading",Glassmorphism|Cyberpunk UI,Glassmorphism|Dark Mode OLED,Dark + green #00ff88 or cyan,"Roboto Mono, Space Grotesk","Live tickers, candlestick charts","Cute/playful elements"
11,Banking App,"banking,bank,account,transfer,finance,money",Trust & Authority,Soft UI Evolution|Minimalism,Trustworthy navy/white,"Neue Haas Grotesk, Source Sans","Secure icons, progress steps","Gradients, neon"
12,Insurance Platform,"insurance,policy,coverage,claim,premium",Trust & Authority,Minimalism|Swiss Modernism 2.0,Corporate blue-white,"IBM Plex, Source Serif","Step forms, coverage tables","Playful animations"
13,Personal Finance Tracker,"budget,expense,saving,money-tracker,personal-finance",Soft UI Evolution|Bento Box Grid,Bento Box Grid|Soft UI Evolution,Calm green-white,"Nunito, Lato","Donut charts, goal bars","Complexity, dark themes"
14,Invoice Billing Tool,"invoice,billing,payment,receipt,accounting",Minimalism|Flat Design,Minimalism|Flat Design,Clean white professional,"Inter, DM Sans","Clean tables, PDF export feel","Colorful decoration"
15,Medical Clinic,"medical,clinic,doctor,health,patient,appointment",Accessible & Ethical,Accessible & Ethical|Inclusive Design,Trustworthy blue-white,"Source Sans, Open Sans","Step forms, time slots","Decorative elements"
16,Pharmacy,"pharmacy,medicine,drug,prescription,rx",Accessible & Ethical,Minimalism|Accessible & Ethical,Clean green-white,"Source Sans, Helvetica","Search-first, dosage clarity","Dark themes"
17,Mental Health App,"mental,therapy,anxiety,depression,mindfulness,calm",Ambient Calm UI|Organic Biophilic,Organic Biophilic|Neumorphism,Soft lavender-sage-white,"Nunito, Lato","Breathing animations, soft transitions","Harsh contrast, red alerts"
18,Fitness Workout App,"fitness,workout,exercise,gym,training,sport",Vibrant & Block-based,Vibrant & Block-based|Dark Mode OLED,Dark + electric blue/orange,"Exo 2, Rajdhani","Progress rings, intensity meters","Soft pastels"
19,Telemedicine,"telemedicine,telehealth,video-consult,remote-doctor",Accessible & Ethical,Accessible & Ethical|Minimalism,Medical blue-white,"Open Sans, Source Sans","Video UI, appointment flow","Complex animations"
20,Dental Practice,"dental,dentist,teeth,orthodontic",Minimalism,Soft UI Evolution|Minimalism,Clean white-teal,"Source Sans, Lato","Before/after image slider","Dark heavy themes"
21,General E-commerce,"ecommerce,shop,store,buy,cart,checkout",Social Proof-Focused,Social Proof-Focused|Hero-Centric Design,Brand-specific warm,"Poppins, Libre Baskerville","Product zoom, quick-add, reviews","Complex nav, buried CTA"
22,Luxury E-commerce,"luxury,premium,high-end,fashion-store,couture",Exaggerated Minimalism,Exaggerated Minimalism|Editorial Grid,Monochrome + gold accent,"Cormorant Garamond, Montserrat","Large imagery, slow reveal","Cluttered discount badges"
23,Marketplace P2P,"marketplace,p2p,listing,seller,peer-to-peer,airbnb-like",Flat Design|Bento Box Grid,Flat Design|Bento Box Grid,Neutral trust,"Inter, DM Sans","Filter sidebar, map view, ratings","Visual complexity"
24,Subscription Box,"subscription,box,monthly,curated,unboxing",Hero-Centric Design|Social Proof,Social Proof-Focused,Warm unboxing palette,"Playfair Display, Lato","Unboxing animation, countdown","Cluttered product grid"
25,Food Delivery,"food,delivery,restaurant-app,takeout,order,uber-eats",Motion-Driven|Hero-Centric,Vibrant & Block-based,Appetite-stimulating warm red/orange,"Nunito, Poppins","Food photos full-bleed, quick order","Muted colors"
26,Beauty Spa,"beauty,spa,wellness,skincare,salon,massage",Soft UI Evolution|Organic Biophilic,Soft UI Evolution|Nature Distilled,Soft pink-sage-ivory,"Cormorant Garamond, Montserrat","Scroll reveals, before/after","Dark themes, neon"
27,Restaurant,"restaurant,dining,cafe,food,menu,reservation",Hero-Centric Design,Hero-Centric Design|Editorial Grid,Warm appetite palette,"Playfair Display, Lato","Full-bleed food imagery, reservation CTA","Plain product grid"
28,Hotel Resort,"hotel,resort,hospitality,accommodation,booking",Storytelling-Driven Landing,Storytelling-Driven|Exaggerated Minimalism,Luxury warm neutrals,"Cormorant Garamond, Raleway","Room galleries, availability calendar","Cluttered UI"
29,Legal Services,"legal,law,attorney,lawyer,compliance",Trust & Authority,Trust & Authority|Swiss Modernism 2.0,Corporate navy-gold,"Georgia, Source Serif","Document download, consultation CTA","Playful colors"
30,Home Services,"home,plumber,electrician,handyman,cleaning,hvac",Social Proof-Focused,Social Proof-Focused|Flat Design,Trust blue-white-orange,"Open Sans, Nunito","Service cards, zip-code entry","Overly corporate"
31,Booking Appointment,"booking,appointment,schedule,calendar,reserve",Flat Design|Bento Box Grid,Flat Design|Soft UI Evolution,Clean actionable,"Inter, DM Sans","Calendar picker, time slots, confirm flow","Complex multi-step"
32,Travel Agency,"travel,trip,vacation,flights,tourism,destination",Parallax Storytelling,Parallax Storytelling|Hero-Centric,Vivid destination-inspired,"Raleway, Open Sans","Destination cards, map, booking CTA","Text-heavy"
33,Real Estate,"realestate,property,homes,listings,mortgage",Social Proof-Focused|Interactive Demo,Social Proof-Focused|Bento Box Grid,Trustworthy neutral,"Libre Baskerville, DM Sans","Map view, photo galleries, mortgage calc","Cluttered listings"
34,Education Platform,"education,elearning,course,lms,online-learning",Claymorphism|Flat Design,Claymorphism|Flat Design,Bright primary friendly,"Nunito, Open Sans","Progress bars, quiz cards, certificate","Dark themes for study"
35,K12 School,"school,k12,elementary,high-school,student",Claymorphism,Claymorphism|Flat Design,Bright primary,"Nunito, Quicksand","Fun animations, achievement badges","Adult-corporate"
36,University College,"university,college,campus,academic",Swiss Modernism 2.0|Trust,Trust & Authority|Minimalism,Institutional navy/crimson,"Merriweather, Source Sans","Event calendar, department nav","Overly playful"
37,Online Tutoring,"tutor,tutoring,private-lesson,homework-help",Claymorphism|Soft UI Evolution,Claymorphism|Soft UI Evolution,Warm encouraging,"Nunito, Poppins","Session booking, whiteboard feel","Intimidating academic"
38,Language Learning,"language,translation,vocab,flashcard,duolingo-like",Gamification style,Claymorphism|Vibrant,Bright gamified,"Nunito, Fredoka","Streak counters, XP bars, celebration","Dull monochrome"
39,Creative Portfolio,"portfolio,designer,artist,creative,showcase",Brutalism|Exaggerated Minimalism,Brutalism|Motion-Driven,Personal brand-specific,"Variable fonts, Clash Display","Strong grid, project hover reveals","Generic templates"
40,Photography Portfolio,"photography,photographer,photo-portfolio",Exaggerated Minimalism|Editorial Grid,Exaggerated Minimalism,Monochrome or muted,"Cormorant Garamond, Futura","Masonry grid, lightbox, lazy-load","Text-heavy, colored UI"
41,Creative Agency,"agency,studio,creative-studio,production",Motion-Driven|Brutalism,Motion-Driven|Neubrutalism,High contrast black/white + 1 accent,"Clash Display, Satoshi","GSAP text reveals, cursor effects","Generic Bootstrap"
42,Graphic Design Tool,"design,figma-like,vector,illustration,canvas",Flat Design|Dark Mode,Dark Mode OLED|Flat Design,Dark productive,"Inter, IBM Plex Sans","Canvas UI, tool sidebar, color pickers","Decorative animations"
43,Photography App Mobile,"photo-app,camera,filter,instagram-like",Dark Mode OLED,Dark Mode OLED|Flat Design,Near-black + accent,"SF Pro, Inter","Filter previews, camera UI","Heavy gradients"
44,Music Streaming,"music,streaming,spotify-like,playlist,artist",Dark Mode OLED|Vaporwave,Dark Mode OLED|Vaporwave,Dark + vibrant accent,"Circular, Nunito","Album art dominant, waveform viz","Light themes"
45,Podcast Platform,"podcast,audio,episode,rss,listener",Minimal & Direct|Dark Mode,Minimalism|Dark Mode OLED,Dark or clean white,"Libre Franklin, DM Sans","Episode list, waveform, subscribe","Visual clutter"
46,Video Streaming,"video,streaming,netflix-like,watch,vod",Dark Mode OLED,Dark Mode OLED,Pure black #000,"Helvetica Neue, DM Sans","Thumbnail hover play, progress bar","Light or colorful bg"
47,Gaming Platform,"gaming,game,esports,steam-like,multiplayer",Cyberpunk UI|Dark Mode,Cyberpunk UI|3D & Hyperrealism,Dark + neon green/orange,"Exo 2, Rajdhani","Game card hovers, neon glows, particle FX","Soft pastels"
48,Indie Game Landing,"indie-game,game-landing,itch-io",Retro-Futurism|Brutalism,Retro-Futurism|Pixel Art,Game-specific thematic,"Pixel fonts or Clash Display","Game screenshots, trailer embed","Corporate clean"
49,Web3 NFT,"web3,nft,blockchain,crypto-art,dao,ethereum",Glassmorphism|Cyberpunk,Glassmorphism|Cyberpunk UI,Dark + gradient accent,"Space Grotesk, Monument Extended","Wallet connect, grid galleries","Traditional trust signals"
50,Social Network,"social,network,feed,post,community,twitter-like",Flat Design|Minimal,Flat Design|Soft UI Evolution,Clean white/dark,"Inter, SF Pro","Feed cards, notifications, follow","Heavy gradients"
51,Community Forum,"forum,community,discussion,reddit-like,discord-like",Flat Design|Dark Mode,Flat Design|Dark Mode OLED,Clean dark or white,"Inter, Source Sans","Thread nesting, upvotes, user cards","Complex decoration"
52,Dating App,"dating,match,swipe,tinder-like,romance",Hero-Centric|Vibrant,Vibrant & Block-based|Glassmorphism,Warm red-pink or sunset,"Nunito, Poppins","Swipe cards, match animation, chat","Clinical or corporate"
53,Job Board,"job,hiring,recruitment,career,linkedin-like",Minimalism|Flat Design,Minimalism|Flat Design,Professional neutral,"Source Sans, DM Sans","Filter sidebar, job cards, apply flow","Heavy animation"
54,Freelance Marketplace,"freelance,gig,fiverr-like,upwork-like,contractor",Social Proof-Focused,Social Proof-Focused|Flat Design,Trust warm neutral,"Inter, Open Sans","Skill tags, rating stars, portfolio grid","Overwhelming categories"
55,Newsletter Tool,"newsletter,email,subscriber,substack-like,mailchimp",Minimal & Direct|Editorial,Minimalism|Editorial Grid,Warm editorial,"Lora, DM Sans","Subscribe hero, preview card, stats","Heavy interactive UI"
56,Personal Blog,"blog,writing,article,personal-site,medium-like",Editorial Grid Magazine,Editorial Grid Magazine,Paper white or dark editorial,"Lora, Merriweather","Drop caps, reading time, related posts","Dashboard-style chrome"
57,News Media,"news,journalism,newspaper,media,breaking",Editorial Grid Magazine,Editorial Grid Magazine,Newspaper B&W + 1 accent,"Libre Baskerville, Source Serif","Breaking ticker, section nav, photo essays","Flashy animations"
58,Recipe Cooking,"recipe,cooking,food-blog,chef,ingredients",Hero-Centric Design|Editorial,Hero-Centric Design,Warm appetite,"Playfair Display, Lato","Food photography hero, step cards, print view","Dark or techy"
59,Weather App,"weather,forecast,temperature,climate,meteorology",Soft UI Evolution|Glassmorphism,Glassmorphism|Soft UI Evolution,Sky blues and warm amber,"Nunito, DM Mono for temps","Animated weather icons, hourly scroll","Text-heavy data"
60,Habit Tracker,"habit,tracker,streak,productivity,routine",Claymorphism|Gamification,Claymorphism|Vibrant,Bright motivating,"Nunito, Quicksand","Streak flame, calendar dots, celebration","Dark depressing themes"
61,Meditation App,"meditation,mindfulness,breathing,calm-app,sleep",Ambient Calm UI,Ambient Calm UI|Organic Biophilic,Soft lavender-navy-warm white,"Nunito, Lato","Breathing circle, ambient sound viz","Harsh colors, fast animations"
62,Diary Journal App,"diary,journal,writing,reflection,private",E-Ink Paper|Minimal,E-Ink Paper|Exaggerated Minimalism,Paper warm white or dark,"Lora, Merriweather","Lined paper feel, date nav","Social/sharing elements"
63,Mood Tracker,"mood,emotion,mental-log,feeling",Claymorphism|Soft,Claymorphism|Soft UI Evolution,Warm pastel rainbow,"Nunito, Quicksand","Emoji mood scale, color-coded calendar","Clinical or dark"
64,Home Automation,"smart-home,iot,automation,dashboard-home,alexa-like",HUD Sci-Fi FUI|Bento,Bento Box Grid|Dark Mode OLED,Dark slate + teal accent,"Inter, DM Mono","Device tiles, toggle animations, status rings","Colorful consumer"
65,Startup Landing,"startup,mvp,launch,product-launch,early-stage",Conversion-Optimized|Hero-Centric,Hero-Centric Design|Minimal & Direct,Brand-specific focused,"Sora, DM Sans","Bold headline, waitlist form, social proof","Feature grid overload"
66,Portfolio Personal,"personal,about-me,cv-online,personal-brand",Brutalism|Exaggerated Minimalism,Brutalism|Motion-Driven,Personal unique,"Variable/Clash Display","Strong type, project reveals, hover effects","Generic Bootstrap portfolio"
67,Documentation Site,"docs,documentation,api-docs,developer-docs,readme",Minimalism|Dark Mode,Minimalism|Dark Mode OLED,Neutral with code accent,"Inter, JetBrains Mono","Sidebar nav, code blocks, search","Heavy visual decoration"
68,Changelog Updates,"changelog,updates,release-notes,what-new",Minimalism|Flat,Minimalism|Flat Design,Clean white,"Inter, DM Sans","Timeline list, version badges","Complex interactive"
69,Status Page,"status,uptime,incident,operational,downtime",Minimalism|Accessible,Minimalism|Accessible & Ethical,Neutral green/red semantic,"Inter, Source Sans","Status dots, incident timeline","Colorful branding"
70,Admin Panel,"admin,backoffice,cms,management,crud",Data-Dense Dashboard,Bento Box Grid|Data-Dense,Neutral gray productive,"Inter, DM Sans","Sidebar + content, data tables, modals","Consumer-facing aesthetics"
71,CRM Platform,"crm,customer,sales-crm,contacts,pipeline",Data-Dense Dashboard,Bento Box Grid|Data-Dense,Professional neutral,"Inter, DM Sans","Pipeline kanban, contact cards, activity feed","Heavy animation"
72,HR Platform,"hr,human-resources,employees,onboarding,payroll",Soft UI Evolution,Soft UI Evolution|Bento Box Grid,Professional friendly,"Source Sans, Nunito","Org chart, vacation calendar, payroll table","Harsh corporate"
73,Event Platform,"event,conference,ticket,registration,venue",Hero-Centric Design|Social Proof,Hero-Centric Design,Event-specific thematic,"Raleway, Open Sans","Countdown timer, speaker grid, venue map","Text-heavy listings"
74,Auction Platform,"auction,bid,lot,sothebys-like,marketplace-auction",Trust & Authority|Editorial,Trust & Authority,Premium neutral-gold,"Libre Baskerville, DM Sans","Countdown bid timer, lot gallery","Playful or casual"
75,Charity Nonprofit,"charity,nonprofit,donation,cause,ngo",Storytelling-Driven|Social Proof,Storytelling-Driven Landing,Warm emotional palette,"Merriweather, Open Sans","Impact numbers, photo stories, donate CTA","Cold corporate"
76,Crowdfunding,"crowdfunding,kickstarter-like,fund,campaign,backer",Social Proof-Focused|Hero-Centric,Social Proof-Focused,Campaign-specific,"Nunito, Poppins","Progress bar, backer count, reward tiers","Generic marketplace"
77,Real Estate Investment,"realestate-invest,reit,property-invest,crowdfund-property",Trust & Authority|Financial,Trust & Authority,Premium navy-gold,"Source Serif, DM Sans","ROI charts, property cards, investor CTA","Casual design"
78,Pet Care,"pet,veterinary,dog,cat,pet-shop,grooming",Claymorphism|Vibrant,Claymorphism|Flat Design,Warm friendly animal palette,"Nunito, Quicksand","Pet profile cards, booking, breed search","Dark or clinical"
79,Children App,"kids,children,toddler,educational-game,abc",Claymorphism,Claymorphism,Bright primary colors,"Fredoka One, Nunito","Large tap targets 56px+, sound FX, animations","Small targets, small text"
80,Senior App,"senior,elderly,accessible,large-text,age60plus",Inclusive Design,Inclusive Design|Accessible & Ethical,High contrast clean,"Source Sans 18px+, Open Sans","48px+ buttons, simple nav, high contrast","Complex interactions"
81,Telematics Fleet,"fleet,telematics,gps,vehicle,logistics",HUD Sci-Fi FUI|Data-Dense,Data-Dense Dashboard|HUD,Dark map with status overlays,"Roboto Mono, IBM Plex","Live map, vehicle status badges","Consumer aesthetics"
82,Supply Chain,"supply-chain,logistics,warehouse,inventory,erp",Data-Dense Dashboard,Data-Dense Dashboard,Operational gray-blue,"IBM Plex, Source Sans","Gantt charts, inventory tables, alerts","Heavy decoration"
83,Airport Travel Tech,"airport,flight,boarding,travel-tech,aviation",Minimalism|HUD,Minimalism|HUD Sci-Fi FUI,Clean blue-white high contrast,"DM Mono, Source Sans","Flight boards, departure grids","Low contrast"
84,Climate Environment,"climate,environment,carbon,sustainability,eco",Nature Distilled|Organic,Nature Distilled|Organic Biophilic,Earth green-brown-sky,"Lora, Source Serif","Data viz for emissions, earth map","Neon or synthetic"
85,Fitness Wearable App,"wearable,fitbit-like,healthdata,heart-rate,steps",Soft UI Evolution|Dark,Dark Mode OLED|Soft UI Evolution,Black + health green/orange,"DM Mono, Nunito","Ring stats, heart rate viz, daily summary","Text-heavy tables"
86,Augmented Reality App,"ar,augmented-reality,spatial,lens,overlay",Spatial UI VisionOS,Spatial UI VisionOS|3D,Transparent overlays,"SF Pro, Inter","AR anchors, spatial panels, gesture hints","2D-only flat design"
87,Voice Assistant App,"voice,siri-like,alexa-app,speech-ui",Voice-First Multimodal,Voice-First Multimodal|Zero Interface,Dark minimal,"SF Pro, Nunito","Waveform orb, listening animation","Text-heavy dense UI"
88,Recruitment ATS,"ats,recruitment,hiring-tool,applicant-tracking",Data-Dense Dashboard,Data-Dense|Bento Box,Professional neutral,"Inter, Source Sans","Kanban pipeline, candidate cards, email threads","Consumer design"
89,Logistics Delivery,"logistics,delivery,tracking,parcel,shipment",Flat Design|Real-Time Monitoring,Flat Design|Real-Time,Map-forward neutral,"DM Sans, Roboto Mono for tracking codes","Live map, status timeline, ETA","Heavy branding"
90,Construction PM,"construction,building,project-pm,contractor",Flat Design|Data-Dense,Flat Design|Data-Dense,Industrial neutral,"Source Sans, IBM Plex","Gantt, site photos, punch list","Consumer-facing style"
91,Legal Tech,"legaltech,contract,e-sign,compliance-tech,docusign-like",Minimalism|Trust,Trust & Authority|Minimalism,Professional navy-white,"Neue Haas, Source Serif","Document viewer, signature flow, redline","Playful colors"
92,Prop Tech,"proptech,property-mgmt,landlord,tenant,rent",Flat Design|Social Proof,Social Proof|Flat Design,Clean blue-white,"DM Sans, Inter","Property cards, maintenance tickets","Overly luxurious"
93,EdTech Assessment,"edtech,quiz,assessment,test,exam-platform",Claymorphism|Flat,Claymorphism|Flat Design,Encouraging bright,"Nunito, Open Sans","Progress indicator, question cards, score reveal","Test-anxiety inducing dark"
94,Sports Analytics,"sports,stats,athlete,performance-data,scouting",Data-Dense|Vibrant,Data-Dense Dashboard|Vibrant,Dark + team accent,"DM Mono, Rajdhani","Radar charts, heatmaps, player cards","Generic BI"
95,Esports Tournament,"esports,tournament,bracket,team,competitive",Cyberpunk UI|Dark,Cyberpunk UI|Vibrant,Dark neon brand accent,"Exo 2, Orbitron","Bracket tree, live score, team logos","Corporate clean"
96,Agricultural Tech,"agtech,farming,crop,precision-agriculture,soil",Nature Distilled|Data-Dense,Nature Distilled|Data-Dense,Earth green-amber,"Source Serif, DM Sans","Field maps, sensor data, weather overlay","Urban tech dark themes"
97,Mining Resources,"mining,resources,extraction,geology",HUD|Data-Dense,HUD Sci-Fi FUI|Data-Dense,Industrial dark-amber,"IBM Plex Mono, Source Sans","Equipment status, sensor readings","Consumer-facing design"
98,Energy Utility,"energy,utility,grid,power,solar,wind",Data-Dense|Environmental,Data-Dense|Nature Distilled,Clean functional blue-green,"Source Sans, DM Mono","Energy flow diagrams, meter readings","Heavy branding"
99,Telecom Carrier,"telecom,carrier,network,5g,mobile-operator",Data-Dense|Trust,Trust & Authority|Data-Dense,Corporate blue-white,"Source Sans, Helvetica","Network map, coverage checker, plan tables","Dark/gaming aesthetics"
100,Pharmaceutical,"pharma,drug-discovery,clinical-trial,biotech",Accessible & Ethical|Minimalism,Accessible & Ethical,Clinical clean white-blue,"Source Sans, IBM Plex","Trial data tables, molecular viz","Playful or colorful"
101,Space Tech,"space,aerospace,satellite,rocket,nasa-like",HUD Sci-Fi FUI|Dark,HUD Sci-Fi FUI|3D,Dark navy-black + cyan,"Orbitron, Space Grotesk","Orbit viz, telemetry, star map bg","Consumer light themes"
102,Quantum Computing,"quantum,qubit,computing-research",HUD Sci-Fi FUI,HUD Sci-Fi FUI|Dark Mode,Dark + quantum blue-purple,"IBM Plex Mono, Space Grotesk","Wave function viz, qubit state","Plain corporate"
103,Autonomous Vehicle,"autonomous,self-driving,av,robotaxi,lidar",HUD Sci-Fi FUI|Real-Time,HUD Sci-Fi FUI|Real-Time Monitoring,Dark HUD blue,"DM Mono, IBM Plex","Bird's-eye map, sensor overlay, status","Consumer friendly colors"
104,Drone Fleet,"drone,uav,fleet-mgmt,aerial,surveillance",HUD Sci-Fi FUI|Data-Dense,HUD Sci-Fi FUI|Real-Time,Dark operational,"Roboto Mono, DM Mono","Live map, battery status, flight path","Consumer aesthetics"
105,Crypto Exchange,"exchange,dex,trading,order-book,swap",Dark Mode|Financial,Dark Mode OLED|Financial Dashboard,Dark + green-red trading,"Roboto Mono, Space Grotesk","Order book, candlestick, depth chart","Friendly consumer colors"
106,NFT Marketplace,"nft,marketplace,opensea-like,mint,collectible",Glassmorphism|Cyberpunk,Glassmorphism|Dark Mode,Dark + vibrant,"Space Grotesk, Monument Extended","Grid gallery, rarity badge, wallet connect","Traditional e-commerce"
107,DAO Governance,"dao,governance,voting,proposal,decentralized",Minimalism|Dark,Minimalism|Dark Mode,Dark neutral-green,"DM Mono, IBM Plex","Proposal cards, vote bars, treasury stats","Corporate branding"
108,Metaverse Platform,"metaverse,virtual-world,avatar,vr-social",3D & Hyperrealism|Spatial,3D & Hyperrealism|Spatial UI,Dark immersive + avatar accent,"Space Grotesk, Orbitron","3D world preview, avatar builder","Flat 2D only"
109,Productivity Suite,"productivity,office,docs,spreadsheet,workspace",Soft UI Evolution|Minimalism,Soft UI Evolution|Minimalism,Clean neutral gray-white,"Inter, DM Sans","Toolbar, document canvas, collaboration cursors","Heavy branding"
110,Password Manager,"password,security,vault,credentials,1password-like",Dark Mode|Trust,Dark Mode OLED|Trust & Authority,Dark secure + green accent,"JetBrains Mono, DM Sans","Strength meter, vault list, copy-to-clipboard","Colorful playful"
111,VPN Privacy App,"vpn,privacy,security-app,proxy,anonymous",Dark Mode|HUD,Dark Mode OLED|HUD Sci-Fi,Dark + secure green/cyan,"DM Mono, Space Grotesk","Globe connection viz, server list","Bright consumer colors"
112,File Storage Cloud,"cloud-storage,drive,files,s3-like,dropbox-like",Flat Design|Minimalism,Flat Design|Minimalism,Clean white-blue,"Inter, Source Sans","File browser, upload progress, shared links","Heavy gradients"
113,Email Client,"email,inbox,mail,client,gmail-like",Minimalism|Flat Design,Minimalism|Flat Design,Clean productive white,"Inter, DM Sans","Thread list, compose, label sidebar","Colorful distracting"
114,Calendar Scheduling,"calendar,scheduling,booking,time,appointment-mgmt",Flat Design|Soft UI,Flat Design|Soft UI Evolution,Clean time-based neutral,"Inter, DM Sans","Month/week grid, drag events, timezone","Heavy decoration"
115,Map Navigation,"map,navigation,gps,geo,mapbox-like",Dark Mode|Real-Time,Dark Mode OLED|Real-Time Monitoring,Dark map + action color,"DM Mono, Roboto","Map tiles, route overlay, POI pins","Light map on dark chrome"
116,Chat Messaging,"chat,messaging,dm,team-chat,slack-like",Flat Design|Dark Mode,Flat Design|Dark Mode OLED,Dark or white clean,"Inter, Nunito","Message bubbles, reactions, thread","Heavy branding decoration"
117,Video Conferencing,"video-call,conference,zoom-like,meeting,webrtc",Minimal & Direct|Dark,Minimalism|Dark Mode,Dark functional,"Inter, DM Sans","Video grid, mute/cam controls, screen share","Complex UI"
118,E-signature,"e-sign,signature,document-sign,docusign-like,contract-sign",Trust & Authority|Minimalism,Trust & Authority,Clean white professional,"Source Serif, Source Sans","Document viewer, signature field, audit trail","Playful or colorful"
119,Survey Form Tool,"survey,form,questionnaire,typeform-like,response",Minimalism|Claymorphism,Minimalism|Claymorphism,Clean or warm friendly,"Nunito, DM Sans","One-question-at-a-time, progress, animation","Overwhelming form dump"
120,A/B Testing Tool,"abtesting,experiment,optimization,cro-tool,split-test",Data-Dense|Minimalism,Data-Dense|Minimalism,Clean data-forward,"Inter, DM Mono","Variant comparison, significance meter","Heavy decoration"
121,Customer Support,"support,helpdesk,tickets,zendesk-like,customer-service",Flat Design|Soft UI,Flat Design|Soft UI Evolution,Friendly professional,"Source Sans, Open Sans","Ticket queue, status badge, CSAT stars","Intimidating corporate"
122,Live Chat Widget,"live-chat,chat-widget,intercom-like,support-chat",Soft UI Evolution,Soft UI Evolution|Glassmorphism,White + brand accent,"Inter, Nunito","Chat bubble, typing indicator, emoji","Dark or complex"
123,Push Notification Tool,"push,notification,engagement,onesignal-like",Flat Design|Minimal,Flat Design|Minimalism,Clean brand-neutral,"Inter, DM Sans","Preview cards, audience targeting UI","Heavy visualization"
124,Subscription Management,"subscription,manage,billing-portal,stripe-like",Minimalism|Trust,Minimalism|Trust & Authority,Clean professional,"Inter, Source Sans","Plan cards, usage meter, invoice list","Colorful decorative"
125,Affiliate Marketing,"affiliate,referral,commission,program,partner",Social Proof|Conversion,Social Proof-Focused|Conversion,Trust warm,"Nunito, Open Sans","Commission table, referral link, leaderboard","Complex dashboards"
126,Influencer Platform,"influencer,creator,ugc,brand-deal,sponsorship",Social Proof|Vibrant,Social Proof|Vibrant & Block,Creator energy palette,"Poppins, Nunito","Profile cards, reach stats, deal board","Corporate cold"
127,Learning Management,"lms,learning,course-platform,moodle-like,canvas-lms",Claymorphism|Flat Design,Claymorphism|Flat Design,Friendly educational,"Nunito, Open Sans","Course cards, progress bars, quiz","Dark intimidating"
128,Certification Platform,"certification,badge,credential,certificate,accreditation",Trust & Authority|Flat,Trust & Authority|Flat Design,Professional credible,"Source Serif, DM Sans","Badge showcase, exam flow, verify link","Overly playful"
129,Talent Assessment,"talent,assessment,psychometric,hiring-test,skills-test",Accessible & Ethical|Minimal,Accessible & Ethical|Minimalism,Clean neutral,"Source Sans, IBM Plex","Timed test UI, question types, results","Stressful dark themes"
130,Knowledge Base,"knowledge-base,wiki,help-center,docs-kb,faq",Minimalism|Flat Design,Minimalism|Flat Design,Clean white-gray,"Inter, Source Sans","Search-first, category cards, breadcrumb","Cluttered decoration"
131,Internal Tools,"internal,admin-tool,back-office,ops-tool",Data-Dense Dashboard,Bento Box Grid|Data-Dense,Neutral operational gray,"Inter, IBM Plex","CRUD tables, bulk actions, filter sidebar","Consumer branding"
132,Monitoring Observability,"monitoring,observability,logs,metrics,grafana-like",Real-Time Monitoring|Dark,Real-Time Monitoring|Dark Mode,Dark + signal green/orange,"DM Mono, IBM Plex Mono","Live metric charts, alert panels, log streams","Consumer aesthetics"
133,Data Pipeline ETL,"etl,pipeline,data-engineering,airflow-like,workflow",Data-Dense|HUD,Data-Dense Dashboard|HUD,Dark or neutral technical,"IBM Plex Mono, DM Mono","DAG visualization, run status, logs","Heavy branding"
134,Business Intelligence,"bi,business-intelligence,power-bi-like,tableau-like",Data-Dense Dashboard,Data-Dense Dashboard|Financial,Professional data-forward,"Inter, DM Mono","Drill-down charts, filter sliders, export","Consumer fun colors"
135,IoT Platform,"iot,sensors,devices,mqtt,telemetry",Real-Time Monitoring|HUD,Real-Time Monitoring|HUD Sci-Fi,Dark dashboard + status colors,"DM Mono, IBM Plex","Device grid, sensor sparklines, alert feed","Light consumer"
136,Robotics Platform,"robotics,robot,automation,ros,manufacturing-robot",HUD Sci-Fi FUI|Data-Dense,HUD Sci-Fi FUI|Data-Dense,Dark operational slate,"Roboto Mono, DM Mono","Joint visualization, status panel, telemetry","Consumer friendly"
137,Digital Twin,"digital-twin,simulation,3d-model,virtual-replica",HUD Sci-Fi FUI|3D,HUD Sci-Fi FUI|3D & Hyperrealism,Dark with 3D accent,"Space Grotesk, DM Mono","3D model viewer, sensor overlay","Flat 2D"
138,Blockchain Explorer,"blockchain,explorer,transactions,on-chain,etherscan-like",Dark Mode|Data-Dense,Dark Mode OLED|Data-Dense,Dark + blue-green technical,"JetBrains Mono, IBM Plex Mono","Transaction table, block list, hash display","Consumer design"
139,Social Commerce,"social-commerce,shoppable,instagram-shop,tiktok-shop",Social Proof|Vibrant,Social Proof|Vibrant,Warm social-native,"Nunito, Poppins","UGC grid, shoppable tags, quick checkout","Traditional e-commerce"
140,Reseller Platform,"reseller,white-label,partner-portal,distributor",Trust & Authority|Flat,Trust & Authority|Flat Design,Professional neutral,"Source Sans, DM Sans","Catalog, pricing tiers, order management","Consumer-facing design"
141,Auction House,"auction-house,fine-art,bidding,lot,christie-like",Editorial Grid|Trust,Editorial Grid Magazine|Trust & Authority,Monochrome + gold,"Cormorant Garamond, Libre Baskerville","Lot viewer, countdown, bid history","Colorful or playful"
142,Tax Software,"tax,irs,return,tax-prep,turbotax-like",Trust & Authority|Accessible,Trust & Authority|Accessible & Ethical,Conservative blue-white,"Source Sans, IBM Plex","Step-by-step wizard, form fields, refund estimate","Casual colors"
143,Insurance Comparison,"insurance-compare,quotes,compare,aggregator",Social Proof|Trust,Social Proof|Trust & Authority,Clean trust-forward,"Source Sans, DM Sans","Quote cards, comparison table, trust badges","Complex dark"
144,Mortgage Calculator,"mortgage,loan,calculator,home-loan,refinance",Trust & Authority|Minimalism,Trust & Authority|Minimalism,Professional clean,"Source Serif, Source Sans","Input sliders, amortization chart, CTA","Playful"
145,Subscription Billing,"billing,subscriptions,invoicing,recurly-like,chargebee",Minimalism|Data-Dense,Minimalism|Data-Dense,Clean professional,"Inter, DM Sans","MRR metrics, invoice list, plan management","Heavy decoration"
146,Customer Data Platform,"cdp,customer-data,profiles,segmentation,mparticle-like",Data-Dense|Bento,Data-Dense Dashboard|Bento Box,Data professional neutral,"Inter, DM Mono","Segment builder, profile cards, data flow viz","Consumer-friendly"
147,Content Management,"cms,content,wordpress-like,headless,website-editor",Flat Design|Minimalism,Flat Design|Minimalism,Clean editorial neutral,"Inter, Source Serif","Content editor, media library, publish flow","Heavy animation"
148,Product Roadmap,"roadmap,product-planning,feature-request,aha-like",Bento Box Grid|Flat,Bento Box Grid|Flat Design,Clean product-forward,"Inter, DM Sans","Timeline roadmap, vote widget, now/next/later","Overly complex"
149,Customer Success,"cs,customer-success,onboarding,churn,health-score",Soft UI Evolution|Bento,Soft UI Evolution|Bento Box,Friendly professional,"Nunito, Source Sans","Health score gauge, playbook cards, alert feed","Cold corporate"
150,Partner Ecosystem,"partner,ecosystem,marketplace,integration,app-store",Flat Design|Social Proof,Flat Design|Social Proof,Clean trust-forward,"Inter, DM Sans","Integration cards, partner levels, API status","Heavy branding"
151,Loyalty Rewards,"loyalty,rewards,points,gamification,program",Claymorphism|Vibrant,Claymorphism|Vibrant,Warm rewarding palette,"Nunito, Poppins","Point balance, reward cards, progress to tier","Cold corporate"
152,Event Ticketing,"ticketing,events-tickets,concert,venue,eventbrite-like",Hero-Centric|Social Proof,Hero-Centric Design|Social Proof,Event-thematic vibrant,"Raleway, Open Sans","Event hero, seat map, countdown","Plain listing"
153,Gig Economy,"gig,rideshare,uber-like,task,on-demand",Flat Design|Real-Time,Flat Design|Real-Time Monitoring,Clean map-forward,"DM Sans, Inter","Live map, request flow, rating","Heavy decoration"
154,Coworking Space,"coworking,office,desk-booking,hot-desk,workspace",Soft UI Evolution|Bento,Soft UI Evolution|Bento Box,Modern warm neutral,"Inter, Nunito","Floor map, desk booking calendar, amenity cards","Cold corporate"
155,Mental Wellness B2B,"eap,employee-wellness,mental-health-b2b,wellbeing",Organic Biophilic|Accessible,Organic Biophilic|Accessible & Ethical,Calming earth tones,"Nunito, Source Sans","Mood check-in, resource cards, usage stats","Clinical or harsh"
156,Compliance Regulatory,"compliance,regulatory,risk,audit,grc",Trust & Authority|Data-Dense,Trust & Authority|Data-Dense,Corporate professional navy,"Source Serif, IBM Plex","Compliance checklist, risk heat map, audit log","Consumer aesthetics"
157,Learning Experience,"lxp,personalized-learning,skill-path,growth",Claymorphism|Bento,Claymorphism|Bento Box Grid,Encouraging warm-bright,"Nunito, Poppins","Skill graph, learning path, achievement badges","Dark or intimidating"
158,Digital Signage,"signage,display,kiosk,digital-screen,ooh",Dark Mode OLED|Vibrant,Dark Mode OLED|Vibrant,High contrast vivid,"Exo 2, Source Sans (large)","Large text, bold graphics, looping animations","Small text, complex UI"
159,Smart City Platform,"smart-city,urban,city-data,gov-tech,municipality",Data-Dense|HUD,Data-Dense Dashboard|HUD Sci-Fi,Dark gov-tech blue-gray,"IBM Plex, DM Mono","City map, KPI tiles, incident feed","Consumer-friendly"
160,Research Platform,"research,academic,data-collection,survey-research",Minimalism|Accessible,Minimalism|Accessible & Ethical,Clean academic white,"Merriweather, Source Sans","Citation tools, data viz, export","Heavy branding"
161,Quantum Computing Interface,"quantum-ui,qubit-viz,quantum-dashboard",HUD Sci-Fi FUI|Dark,HUD Sci-Fi FUI|Dark Mode,Dark quantum blue-purple,"IBM Plex Mono, Space Grotesk","Bloch sphere viz, circuit diagram, probability wave","Plain tables"
"""
# 57 TYPOGRAPHY PAIRINGS
_TYPOGRAPHY_CSV = """id,pairing,display_font,body_font,mood,best_for,google_fonts_url
1,Sora + Inter,Sora,Inter,Modern clean tech,SaaS / AI / Developer tools,https://fonts.google.com/share?selection.family=Sora:wght@400;600;700|Inter:wght@400;500;600
2,Playfair Display + Lato,Playfair Display,Lato,Elegant editorial,Luxury / Restaurant / Beauty spa,https://fonts.google.com/share?selection.family=Playfair+Display:wght@400;600;700|Lato:wght@300;400;700
3,Space Grotesk + JetBrains Mono,Space Grotesk,JetBrains Mono,Technical premium,AI / Crypto / Dev tools,https://fonts.google.com/share?selection.family=Space+Grotesk:wght@400;500;700|JetBrains+Mono:wght@400;500
4,Cormorant Garamond + Montserrat,Cormorant Garamond,Montserrat,Refined luxurious,Luxury / Legal / Architecture,https://fonts.google.com/share?selection.family=Cormorant+Garamond:wght@400;600|Montserrat:wght@400;500;600
5,Geist + Geist Mono,Geist,Geist Mono,Dev-first clean,Developer tools / Documentation,https://fonts.google.com/share?selection.family=Geist:wght@400;500;600|Geist+Mono:wght@400;500
6,Nunito + Open Sans,Nunito,Open Sans,Friendly approachable,Educational / Children / Wellness,https://fonts.google.com/share?selection.family=Nunito:wght@400;600;700|Open+Sans:wght@400;500;600
7,Clash Display + Satoshi,Clash Display,Satoshi,Gen Z creative,Creative agency / Brand / Gen Z,https://fonts.google.com/share?selection.family=Clash+Display:wght@400;600;700
8,DM Serif Display + DM Sans,DM Serif Display,DM Sans,Editorial modern,Blog / News / Editorial,https://fonts.google.com/share?selection.family=DM+Serif+Display|DM+Sans:wght@400;500;600
9,Libre Baskerville + Source Sans 3,Libre Baskerville,Source Sans 3,Traditional trustworthy,Legal / Finance / Government,https://fonts.google.com/share?selection.family=Libre+Baskerville:wght@400;700|Source+Sans+3:wght@400;500;600
10,Exo 2 + Rajdhani,Exo 2,Rajdhani,Energetic sporty,Gaming / Fitness / Esports,https://fonts.google.com/share?selection.family=Exo+2:wght@400;600;700|Rajdhani:wght@400;500;600
11,Merriweather + Source Sans 3,Merriweather,Source Sans 3,Scholarly readable,Academic / Research / Journalism,https://fonts.google.com/share?selection.family=Merriweather:wght@400;700|Source+Sans+3:wght@400;500
12,Poppins + Lato,Poppins,Lato,Versatile modern,E-commerce / Startup / Lifestyle,https://fonts.google.com/share?selection.family=Poppins:wght@400;500;600;700|Lato:wght@300;400;700
13,IBM Plex Serif + IBM Plex Sans,IBM Plex Serif,IBM Plex Sans,Technical editorial,B2B / Enterprise / Pharma,https://fonts.google.com/share?selection.family=IBM+Plex+Serif:wght@400;600|IBM+Plex+Sans:wght@400;500;600
14,Raleway + Open Sans,Raleway,Open Sans,Elegant versatile,Hotel / Travel / Events,https://fonts.google.com/share?selection.family=Raleway:wght@400;500;700|Open+Sans:wght@400;500
15,Fredoka One + Quicksand,Fredoka One,Quicksand,Playful fun,Children / Pet care / Games,https://fonts.google.com/share?selection.family=Fredoka+One|Quicksand:wght@400;500;600
16,Neue Haas Grotesk + Helvetica Neue,Neue Haas Grotesk,Helvetica Neue,Swiss professional,Corporate / Banking / Insurance,https://fonts.google.com/
17,Monument Extended + Space Grotesk,Monument Extended,Space Grotesk,Bold crypto,Web3 / NFT / Crypto,https://fonts.google.com/share?selection.family=Space+Grotesk:wght@400;500;700
18,Orbitron + Space Grotesk,Orbitron,Space Grotesk,Sci-fi futuristic,Space tech / Gaming / HUD,https://fonts.google.com/share?selection.family=Orbitron:wght@400;600;700|Space+Grotesk:wght@400;500
19,Circular + Nunito,Circular,Nunito,Music streaming,Music / Podcast / Media,https://fonts.google.com/share?selection.family=Nunito:wght@400;500;600
20,Lora + DM Sans,Lora,DM Sans,Editorial warm,Newsletter / Blog / Recipe,https://fonts.google.com/share?selection.family=Lora:wght@400;500;600|DM+Sans:wght@400;500
21,Syne + Inter,Syne,Inter,Modern bold,Creative portfolio / Agency,https://fonts.google.com/share?selection.family=Syne:wght@400;600;700|Inter:wght@400;500;600
22,Bricolage Grotesque + Inter,Bricolage Grotesque,Inter,Contemporary fresh,Startup / SaaS / Product,https://fonts.google.com/share?selection.family=Bricolage+Grotesque:wght@400;500;600;700|Inter:wght@400;500
23,Cabinet Grotesk + Satoshi,Cabinet Grotesk,Satoshi,Premium modern,Fintech / SaaS / Premium,https://fonts.google.com/share?selection.family=Cabinet+Grotesk:wght@400;500;700
24,Fraunces + Inter,Fraunces,Inter,Quirky editorial,Brand / Blog / Creative,https://fonts.google.com/share?selection.family=Fraunces:wght@400;600;700|Inter:wght@400;500
25,Plus Jakarta Sans + DM Sans,Plus Jakarta Sans,DM Sans,Clean productive,Productivity / SaaS / Clean,https://fonts.google.com/share?selection.family=Plus+Jakarta+Sans:wght@400;500;600;700|DM+Sans:wght@400;500
26,Anybody + Inter,Anybody,Inter,Variable expressive,Creative / Experimental,https://fonts.google.com/share?selection.family=Anybody:wght@400;500;700|Inter:wght@400;500
27,Bebas Neue + Open Sans,Bebas Neue,Open Sans,Bold impactful,Fitness / Sports / Marketing,https://fonts.google.com/share?selection.family=Bebas+Neue|Open+Sans:wght@400;500;600
28,Oswald + Source Sans 3,Oswald,Source Sans 3,Strong editorial,News / Sports / Event,https://fonts.google.com/share?selection.family=Oswald:wght@400;500;600|Source+Sans+3:wght@400;500
29,Italiana + Lato,Italiana,Lato,High fashion,Fashion / Luxury / Beauty,https://fonts.google.com/share?selection.family=Italiana|Lato:wght@300;400;700
30,Spectral + Source Sans 3,Spectral,Source Sans 3,Literary refined,Publishing / Legal / Academic,https://fonts.google.com/share?selection.family=Spectral:wght@400;500;600|Source+Sans+3:wght@400;500
31,Work Sans + Roboto,Work Sans,Roboto,Utilitarian clear,Internal tools / Admin,https://fonts.google.com/share?selection.family=Work+Sans:wght@400;500;600|Roboto:wght@400;500
32,Josefin Sans + Josefin Slab,Josefin Sans,Josefin Slab,Art deco vintage,Art / Design / Vintage brand,https://fonts.google.com/share?selection.family=Josefin+Sans:wght@400;600|Josefin+Slab:wght@400;600
33,Rubik + Rubik,Rubik,Rubik,Modern rounded,Mobile / App / SaaS,https://fonts.google.com/share?selection.family=Rubik:wght@400;500;600;700
34,Manrope + Manrope,Manrope,Manrope,Elegant uniform,Design tool / Portfolio / SaaS,https://fonts.google.com/share?selection.family=Manrope:wght@400;500;600;700
35,Fira Code + Fira Sans,Fira Code,Fira Sans,Developer focused,Code / Dev tool / Technical,https://fonts.google.com/share?selection.family=Fira+Code:wght@400;500|Fira+Sans:wght@400;500;600
36,Righteous + Roboto,Righteous,Roboto,Retro fun,Gaming / Entertainment / Youth,https://fonts.google.com/share?selection.family=Righteous|Roboto:wght@400;500
37,Unbounded + Space Grotesk,Unbounded,Space Grotesk,Web3 bold,Web3 / NFT / Crypto / Bold tech,https://fonts.google.com/share?selection.family=Unbounded:wght@400;600;700|Space+Grotesk:wght@400;500
38,Red Hat Display + Red Hat Text,Red Hat Display,Red Hat Text,Open source tech,Developer / Open source / Docs,https://fonts.google.com/share?selection.family=Red+Hat+Display:wght@400;500;700|Red+Hat+Text:wght@400;500
39,Barlow + Barlow Semi Condensed,Barlow,Barlow Semi Condensed,Industrial condensed,Construction / Logistics / Auto,https://fonts.google.com/share?selection.family=Barlow:wght@400;500;600|Barlow+Semi+Condensed:wght@400;500
40,Kanit + Sarabun,Kanit,Sarabun,Modern Thai-friendly,Southeast Asia / Global,https://fonts.google.com/share?selection.family=Kanit:wght@400;500;600|Sarabun:wght@400;500
41,Staatliches + Roboto Condensed,Staatliches,Roboto Condensed,Brutalist poster,Art / Music / Event poster,https://fonts.google.com/share?selection.family=Staatliches|Roboto+Condensed:wght@400;700
42,Cinzel + Raleway,Cinzel,Raleway,Classical roman,Luxury / Legal / Historical,https://fonts.google.com/share?selection.family=Cinzel:wght@400;600;700|Raleway:wght@400;500
43,Audiowide + Exo 2,Audiowide,Exo 2,Tech scifi,Gaming / Drone / Space,https://fonts.google.com/share?selection.family=Audiowide|Exo+2:wght@400;500;600
44,Cardo + Raleway,Cardo,Raleway,Classic editorial,Literature / Publishing / Art,https://fonts.google.com/share?selection.family=Cardo:wght@400;700|Raleway:wght@400;500
45,Lexend + Lexend,Lexend,Lexend,Reading optimized,Accessibility / Reading / Education,https://fonts.google.com/share?selection.family=Lexend:wght@400;500;600;700
46,Bai Jamjuree + Sarabun,Bai Jamjuree,Sarabun,Contemporary Thai,Thailand / SE Asia market,https://fonts.google.com/share?selection.family=Bai+Jamjuree:wght@400;500;600|Sarabun:wght@400;500
47,Comfortaa + Nunito,Comfortaa,Nunito,Soft rounded,Children / Wellness / Friendly,https://fonts.google.com/share?selection.family=Comfortaa:wght@400;500;700|Nunito:wght@400;500;600
48,Alfa Slab One + Raleway,Alfa Slab One,Raleway,Bold serif impact,Sports / Newspaper / Retail,https://fonts.google.com/share?selection.family=Alfa+Slab+One|Raleway:wght@400;500;600
49,Bitter + Hind,Bitter,Hind,South Asian editorial,India / Bangladesh market,https://fonts.google.com/share?selection.family=Bitter:wght@400;500;700|Hind:wght@400;500;600
50,Vollkorn + Source Sans 3,Vollkorn,Source Sans 3,Scholarly warm,Academic / Research / Nonprofit,https://fonts.google.com/share?selection.family=Vollkorn:wght@400;600|Source+Sans+3:wght@400;500
51,Bodoni Moda + DM Sans,Bodoni Moda,DM Sans,Luxury contrast,Fashion / High-end / Premium,https://fonts.google.com/share?selection.family=Bodoni+Moda:wght@400;600|DM+Sans:wght@400;500
52,Secular One + Rubik,Secular One,Rubik,Bold Hebrew-friendly,Middle East / International,https://fonts.google.com/share?selection.family=Secular+One|Rubik:wght@400;500
53,BioRhyme + Open Sans,BioRhyme,Open Sans,Organic natural,Biotech / Organic / Health,https://fonts.google.com/share?selection.family=BioRhyme:wght@400;700|Open+Sans:wght@400;500
54,Epilogue + Inter,Epilogue,Inter,Contemporary editorial,Newsletter / Modern media,https://fonts.google.com/share?selection.family=Epilogue:wght@400;500;600;700|Inter:wght@400;500
55,Figtree + Inter,Figtree,Inter,Friendly geometric,SaaS / Product / Clean modern,https://fonts.google.com/share?selection.family=Figtree:wght@400;500;600;700|Inter:wght@400;500
56,Outfit + DM Sans,Outfit,DM Sans,Rounded modern,App / Startup / Modern product,https://fonts.google.com/share?selection.family=Outfit:wght@400;500;600;700|DM+Sans:wght@400;500
57,Kumbh Sans + Noto Sans,Kumbh Sans,Noto Sans,Global multilingual,International / Multi-language,https://fonts.google.com/share?selection.family=Kumbh+Sans:wght@400;500;600|Noto+Sans:wght@400;500
"""
# 25 CHART TYPES
_CHARTS_CSV = """id,chart_type,use_case,library,keywords
1,Line Chart,Time-series trends,Recharts / Chart.js,trend timeline progress
2,Area Chart,Volume over time,Recharts / ApexCharts,area filled cumulative
3,Bar Chart,Category comparison,Recharts / Chart.js,comparison ranking bars
4,Stacked Bar,Part-to-whole over time,Recharts / ApexCharts,stacked segments breakdown
5,Horizontal Bar,Long category labels,Chart.js / Recharts,horizontal ranking leaderboard
6,Pie Chart,Simple proportion,Chart.js,proportion share percentage simple
7,Donut Chart,Proportion + center metric,Recharts / ApexCharts,donut ring center kpi
8,Scatter Plot,Correlation between variables,D3.js / Recharts,scatter correlation cluster
9,Bubble Chart,3-variable comparison,D3.js / Recharts,bubble size dimension
10,Heatmap,Matrix density,D3.js / Nivo,heatmap matrix density intensity
11,Treemap,Hierarchical proportion,D3.js / Nivo,treemap hierarchy nested proportion
12,Funnel Chart,Conversion stages,ApexCharts / Funnel.js,funnel conversion drop-off stages
13,Gauge / Radial,Single KPI vs target,ApexCharts / D3,gauge radial meter speedometer kpi
14,Candlestick,Financial OHLC data,ApexCharts / Lightweight Charts,candlestick ohlc stock trading financial
15,Waterfall Chart,Sequential change,ApexCharts / D3,waterfall delta change flow profit
16,Sankey Diagram,Flow between nodes,D3.js,sankey flow alluvial transition
17,Radar / Spider,Multi-dimension comparison,Recharts / ApexCharts,radar spider polygon multi-dimension skill
18,Gantt Chart,Project timeline,DHTMLX / Frappe Gantt,gantt project timeline schedule
19,Network Graph,Relationship nodes,D3.js / Sigma.js,network graph nodes edges relationship
20,Choropleth Map,Geographic data,Leaflet / Mapbox / D3,map geographic choropleth region country
21,Histogram,Distribution,Chart.js / D3,histogram distribution frequency bucket
22,Box Plot,Statistical distribution,D3.js / ApexCharts,box plot whisker outlier distribution quartile
23,Chord Diagram,Bidirectional flow,D3.js,chord flow matrix bidirectional
24,Timeline,Events over time,vis.js / D3,timeline events history chronological
25,Word Cloud,Text frequency,D3-cloud,wordcloud text frequency tag
"""
# 99 UX GUIDELINES
_UX_GUIDELINES = """
═══ 99 UX GUIDELINES (UI/UX PRO MAX v2.5) ═══
LAYOUT (Rules 1-20):
1. Mobile-first breakpoints: 375px → 768px → 1024px → 1440px
2. 8px grid system: spacing in 4/8/16/24/32/48/64px
3. Max content width: 1280px centered with auto margins
4. Sidebar: 240-280px desktop, drawer on mobile
5. Header height: 52-64px desktop, 52px mobile
6. Card padding: 16-24px consistent
7. Section padding: 64-96px vertical on desktop, 40-48px mobile
8. CTA button min-height: 44px (touch target)
9. Form label above input (not placeholder-only)
10. Sticky header max 64px to preserve viewport
11. Footer: full-width, 3-4 columns desktop, stacked mobile
12. Grid columns: 12-col desktop, 8-col tablet, 4-col mobile
13. Hero section: 100vh or min 540px
14. Modal max-width: 560px, centered with backdrop
15. Tooltip max-width: 200px
16. Dropdown max-height: 320px with scroll
17. Z-index scale: 10 base, 100 dropdown, 200 modal, 300 toast
18. Negative space ratio: 40%+ for premium feel
19. Left-to-right reading flow: most important element top-left
20. F-pattern scan: headline → subhead → body → CTA
INTERACTIONS (Rules 21-40):
21. cursor:pointer on ALL clickable elements — no exceptions
22. Hover transition: 150-200ms ease for most elements
23. Button press: scale(0.97) or scale(0.98) active state
24. Link underline on hover at minimum
25. Loading skeleton for all async data fetches
26. Empty state: illustration + helpful message + CTA
27. Error state: red border, error text below, no shake
28. Success state: green check, auto-dismiss toast 3s
29. Disabled: opacity 0.4-0.5, cursor:not-allowed
30. Focus ring: 2px solid + 2px offset (visible keyboard nav)
31. Scroll restoration on route change
32. Infinite scroll: show spinner, load more button at 80% scroll
33. Drag and drop: ghost opacity 0.5, drop zone highlight
34. Form validation: on blur (not on every keystroke)
35. Password field: show/hide toggle
36. Search: debounce 300ms, clear button, loading indicator
37. Select all: checkbox in table header
38. Tooltip: delay 400ms show, 100ms hide
39. Context menu: right-click or 3-dot kebab
40. Undo: toast with 5s undo action for destructive ops
TYPOGRAPHY (Rules 41-55):
41. Body font size: 14-16px, never below 12px
42. Line-height body: 1.6-1.7
43. Heading line-height: 1.2-1.35
44. Max line length: 65-75 characters (38-45rem)
45. Min contrast body text: 4.5:1 (WCAG AA)
46. Min contrast large text (18px+): 3:1
47. Font-weight scale: 400 body, 500 medium, 600 semi-bold, 700 bold
48. Heading scale: H1 40-48px, H2 32px, H3 24px, H4 20px, H5 16px
49. Caption/label: 11-12px, uppercase + tracking for labels
50. Code font: JetBrains Mono, Fira Code, or Roboto Mono
51. Avoid: all-caps for long text, justified text (ragged-right preferred)
52. Letter-spacing: -0.02em for large headings, 0.05em for uppercase labels
53. Orphan control: max 1-2 words on last line
54. RTL support: use logical properties (margin-inline-start not margin-left)
55. Variable fonts preferred for performance
PERFORMANCE (Rules 56-65):
56. Lazy load images below fold: loading="lazy"
57. Use CSS transforms for animations (not left/top)
58. will-change: transform only when needed, remove after animation
59. Image formats: WebP preferred, AVIF for hero
60. Icon sprites or SVG inline (avoid icon fonts)
61. Critical CSS inline for above-fold
62. Font display: swap for web fonts
63. Preconnect to font CDNs: <link rel="preconnect">
64. Debounce resize/scroll handlers
65. Avoid layout thrash: batch DOM reads before writes
ACCESSIBILITY (Rules 66-75):
66. All images: meaningful alt text (or alt="" for decorative)
67. All icons used as buttons: aria-label
68. Form inputs: associated <label> (not placeholder as label)
69. Color: never as sole information carrier
70. Tab order: logical DOM order
71. Skip-to-content link: first focusable element
72. ARIA live regions for dynamic content updates
73. Dialog/modal: focus trap + Escape to close
74. Animation: prefers-reduced-motion media query honored
75. Minimum tap target: 44x44px (WCAG 2.5.8)
ANTI-PATTERNS (Rules 76-99 — NEVER DO THESE):
76. ✗ Overused AI purple (#9333ea) gradients on white
77. ✗ Rainbow gradients on everything
78. ✗ Emoji as icons in UI (use SVG: Heroicons, Lucide, Phosphor)
79. ✗ Centered ALL-CAPS paragraph text
80. ✗ Hamburger menu on desktop (use sidebar or top nav)
81. ✗ Auto-playing video with sound
82. ✗ Infinite scroll without a way to reach footer
83. ✗ Hover-only interactions (mobile has no hover)
84. ✗ No focus states (keyboard navigation fail)
85. ✗ Text on busy image without overlay/scrim
86. ✗ Placeholder text as the only label
87. ✗ Password field with no show/hide toggle
88. ✗ Generic stock photos of people shaking hands
89. ✗ 3+ font families in one design
90. ✗ Low contrast: gray-on-gray text
91. ✗ Tiny click targets below 36px
92. ✗ Scroll-jacking (overriding native scroll)
93. ✗ Hidden primary navigation on desktop
94. ✗ Modals stacked on modals
95. ✗ Submit button disabled before user interacts with form
96. ✗ Red color for non-error emphasis (trained to mean error)
97. ✗ Underline styling for non-links
98. ✗ Justified text in narrow columns (gaps look bad)
99. ✗ Fixed font sizes that ignore user browser settings (use rem)
"""
# PRE-DELIVERY CHECKLIST
_CHECKLIST = """
═══ PRE-DELIVERY CHECKLIST (UI/UX PRO MAX v2.5) ═══
[ ] No placeholder text remaining in UI
[ ] All images have meaningful alt text
[ ] cursor:pointer on ALL clickable elements
[ ] Hover states on all interactive elements (150-300ms)
[ ] Focus states visible for keyboard navigation
[ ] Responsive tested: 375px / 768px / 1024px / 1440px
[ ] Text contrast meets 4.5:1 minimum (WCAG AA)
[ ] Loading states for all async operations
[ ] Error states handled gracefully
[ ] Empty states have helpful message + CTA
[ ] prefers-reduced-motion respected in animations
[ ] No emoji used as icons (SVG only)
[ ] Touch targets minimum 44x44px
[ ] Font sizes use rem not px
[ ] Form labels associated with inputs
[ ] No auto-playing media with sound
[ ] Disabled elements have opacity + cursor:not-allowed
[ ] Z-index scale documented and consistent
[ ] Mobile-first responsive layout verified
[ ] No justified text in content columns
"""
# STACK GUIDELINES
_STACK_GUIDELINES = {
"html-tailwind": """
STACK: HTML + Tailwind CSS
• CDN: <script src="https://cdn.tailwindcss.com"></script>
• Icons: Heroicons SVG inline or Lucide CDN
• Animations: CSS transitions + @keyframes
• Fonts: Google Fonts <link> in <head>
• JS: Vanilla JS or Alpine.js for interactivity
• Component pattern: BEM-like class grouping
• Responsive: sm: md: lg: xl: 2xl: prefixes
• Dark mode: dark: prefix with class strategy
""",
"react": """
STACK: React + Tailwind CSS
• Setup: Vite + React 18 + tailwindcss
• Icons: lucide-react (npm install lucide-react)
• Animation: framer-motion
• State: useState / useReducer / Zustand
• Data fetching: React Query (TanStack)
• Forms: React Hook Form + Zod validation
• Component pattern: atomic design
• Routing: React Router v6
""",
"nextjs": """
STACK: Next.js + Tailwind CSS
• Version: Next.js 14+ App Router
• Icons: lucide-react
• Animation: framer-motion
• Fonts: next/font/google (no layout shift)
• Images: next/image (automatic optimization)
• Metadata: export const metadata = { title, description }
• Server Components by default, 'use client' for interactivity
• API Routes: app/api/route.ts pattern
""",
"shadcn": """
STACK: shadcn/ui + Next.js + Tailwind
• Init: npx shadcn@latest init
• Components: npx shadcn@latest add [component]
• Theme: CSS variables in globals.css
• Icons: lucide-react (included)
• Available: Button, Card, Dialog, Input, Select, Table, Toast, etc.
• Dark mode: ThemeProvider from next-themes
• Typography: cn() utility for conditional classes
""",
"vue": """
STACK: Vue 3 + Tailwind CSS
• Setup: Vite + Vue 3 Composition API
• Icons: lucide-vue-next
• Animation: @vueuse/motion or vue3-lottie
• State: Pinia
• Router: Vue Router 4
• Forms: VeeValidate + Zod
• Component: <script setup> syntax preferred
""",
"react-native": """
STACK: React Native + NativeWind
• NativeWind: Tailwind for React Native
• Icons: @expo/vector-icons or react-native-vector-icons
• Navigation: React Navigation v6
• Animation: Reanimated 3
• Min touch target: 44pt (iOS) / 48dp (Android)
• Platform-specific: Platform.OS checks
• Safe areas: react-native-safe-area-context
""",
"flutter": """
STACK: Flutter (Dart)
• State: Riverpod or Bloc
• Navigation: GoRouter
• Icons: Material Icons or Phosphor Flutter
• Animation: flutter_animate
• Min touch: 48dp tap targets
• Responsive: LayoutBuilder + MediaQuery
• Theme: ThemeData with colorScheme
"""
}
# ════════════════════════════════════════════════════════
# BM25 SEARCH ENGINE (in-memory, no external deps)
# ════════════════════════════════════════════════════════
def _parse_csv(csv_text: str) -> list[dict]:
reader = csv.DictReader(io.StringIO(csv_text.strip()))
return list(reader)
def _tokenize(text: str) -> list[str]:
return re.findall(r'[a-z0-9]+', text.lower())
def _bm25_score(query_tokens: list[str], doc_tokens: list[str],
avg_dl: float, k1=1.5, b=0.75) -> float:
dl = len(doc_tokens)
freq = {}
for t in doc_tokens:
freq[t] = freq.get(t, 0) + 1
score = 0.0
for qt in query_tokens:
f = freq.get(qt, 0)
if f == 0:
continue
idf = math.log(1 + (1 / (f + 0.5)))
tf = (f * (k1 + 1)) / (f + k1 * (1 - b + b * dl / max(avg_dl, 1)))
score += idf * tf
return score
class UIUXSearchEngine:
"""Embedded BM25 search over all UI/UX Pro Max data."""
def __init__(self):
self._styles = _parse_csv(_STYLES_CSV)
self._rules = _parse_csv(_RULES_CSV)
self._typo = _parse_csv(_TYPOGRAPHY_CSV)
self._charts = _parse_csv(_CHARTS_CSV)
# Pre-tokenize
def _doc_text(row: dict) -> str:
return ' '.join(str(v) for v in row.values())
self._style_tokens = [_tokenize(_doc_text(r)) for r in self._styles]
self._rule_tokens = [_tokenize(_doc_text(r)) for r in self._rules]
self._typo_tokens = [_tokenize(_doc_text(r)) for r in self._typo]
self._chart_tokens = [_tokenize(_doc_text(r)) for r in self._charts]
self._avg_style = sum(len(t) for t in self._style_tokens) / max(len(self._style_tokens), 1)
self._avg_rule = sum(len(t) for t in self._rule_tokens) / max(len(self._rule_tokens), 1)
self._avg_typo = sum(len(t) for t in self._typo_tokens) / max(len(self._typo_tokens), 1)
self._avg_chart = sum(len(t) for t in self._chart_tokens) / max(len(self._chart_tokens), 1)
def _search(self, query: str, docs: list[dict], tokens: list[list],
avg_dl: float, n: int = 3) -> list[dict]:
qt = _tokenize(query)
scored = [
(i, _bm25_score(qt, tokens[i], avg_dl))
for i in range(len(docs))
]
scored.sort(key=lambda x: x[1], reverse=True)
return [docs[i] for i, s in scored[:n] if s > 0]
def search_styles(self, query: str, n: int = 3) -> list[dict]:
return self._search(query, self._styles, self._style_tokens, self._avg_style, n)
def search_rules(self, query: str, n: int = 3) -> list[dict]:
return self._search(query, self._rules, self._rule_tokens, self._avg_rule, n)
def search_typography(self, query: str, n: int = 3) -> list[dict]:
return self._search(query, self._typo, self._typo_tokens, self._avg_typo, n)
def search_charts(self, query: str, n: int = 3) -> list[dict]:
return self._search(query, self._charts, self._chart_tokens, self._avg_chart, n)
def generate_design_system(self, query: str, project_name: str = "") -> str:
"""
Full design system generation — mirrors the Python CLI output.
Returns formatted ASCII/Markdown design system block.
"""
rules = self.search_rules(query, n=1)
styles = self.search_styles(query, n=2)
typo = self.search_typography(query, n=2)
charts = self.search_charts(query, n=2)
rule = rules[0] if rules else {}
style = styles[0] if styles else {}
font = typo[0] if typo else {}
name = project_name or rule.get('product_type', query.title())
# Stack-specific tip
stack_hint = ""
if any(kw in query.lower() for kw in ['react','nextjs','next.js']):
stack_hint = _STACK_GUIDELINES.get('react','')
elif any(kw in query.lower() for kw in ['html','tailwind']):
stack_hint = _STACK_GUIDELINES.get('html-tailwind','')
elif any(kw in query.lower() for kw in ['vue','nuxt']):
stack_hint = _STACK_GUIDELINES.get('vue','')
elif any(kw in query.lower() for kw in ['shadcn','shadcn/ui']):
stack_hint = _STACK_GUIDELINES.get('shadcn','')
output = f"""
+{'─'*80}+
| TARGET: {name.upper()} — RECOMMENDED DESIGN SYSTEM{' '*(max(0,80-len(name)-41))}|
+{'─'*80}+
PATTERN: {rule.get('pattern','Hero-Centric Design')}
Conversion: {rule.get('color_mood','Brand-appropriate')} emotion-driven
Sections: Hero → Features → Social Proof → CTA → Footer
STYLE: {style.get('name', rule.get('style_priority','').split('|')[0])}
Keywords: {style.get('keywords','').replace(',', ', ')}
Best For: {style.get('best_for','')}
Performance: {style.get('performance','Good')} | Accessibility: {style.get('accessibility','WCAG AA')}
TYPOGRAPHY: {font.get('pairing', rule.get('typography_mood','Inter / DM Sans'))}
Display: {font.get('display_font','')} | Body: {font.get('body_font','')}
Mood: {font.get('mood','')}
Google Fonts: {font.get('google_fonts_url','')}
COLOR MOOD: {rule.get('color_mood','Brand-appropriate palette')}
Anti-patterns: {rule.get('anti_patterns','')}
KEY EFFECTS: {rule.get('key_effects',style.get('effects','Smooth transitions, hover states'))}
AVOID (Anti-patterns):
{rule.get('anti_patterns','AI purple gradients on white, rainbow gradients')}
PRE-DELIVERY CHECKLIST:
[ ] No emojis as icons (use SVG: Heroicons/Lucide)
[ ] cursor:pointer on all clickable elements
[ ] Hover states with smooth transitions (150-300ms)
[ ] Text contrast 4.5:1 minimum
[ ] Focus states visible for keyboard navigation
[ ] prefers-reduced-motion respected
[ ] Responsive: 375px, 768px, 1024px, 1440px
[ ] Touch targets minimum 44x44px
{f' STACK NOTES:{stack_hint}' if stack_hint else ''}
+{'─'*80}+
"""
return output.strip()
# ── Singleton instance ──────────────────────────────────
_UIUX_ENGINE = UIUXSearchEngine()
def uiux_design_system(query: str, project_name: str = "") -> str:
"""Public function — call from anywhere in app.py"""
return _UIUX_ENGINE.generate_design_system(query, project_name)
def uiux_search(query: str, domain: str = "all", n: int = 3) -> str:
"""Search UI/UX data by domain: style|rule|typography|chart|all"""
results = []
if domain in ("style", "all"):
hits = _UIUX_ENGINE.search_styles(query, n)
if hits:
results.append("**STYLES:**\n" + "\n".join(
f"• **{h['name']}** — {h['best_for']}\n Effects: {h['effects']}\n Avoid: {h['avoid']}"
for h in hits))
if domain in ("rule", "product", "all"):
hits = _UIUX_ENGINE.search_rules(query, n)
if hits:
results.append("**DESIGN RULES:**\n" + "\n".join(
f"• **{h['product_type']}** → {h['pattern']}\n Style: {h['style_priority']}\n Typography: {h['typography_mood']}"
for h in hits))
if domain in ("typography", "font", "all"):
hits = _UIUX_ENGINE.search_typography(query, n)
if hits:
results.append("**TYPOGRAPHY:**\n" + "\n".join(
f"• **{h['pairing']}** — {h['mood']}\n Best for: {h['best_for']}"
for h in hits))
if domain in ("chart", "all"):
hits = _UIUX_ENGINE.search_charts(query, n)
if hits:
results.append("**CHARTS:**\n" + "\n".join(
f"• **{h['chart_type']}** — {h['use_case']}\n Library: {h['library']}"
for h in hits))
return "\n\n".join(results) if results else "No results found."
# ════════════════════════════════════════════════════════
# NEW UIUX_PRO_MAX STRING — replaces the old one in app.py
# ════════════════════════════════════════════════════════
UIUX_PRO_MAX = f"""
═══ UI/UX PRO MAX v2.5 — DESIGN INTELLIGENCE ═══
Source: nextlevelbuilder/ui-ux-pro-max-skill (68.9k★)
DESIGN SYSTEM GENERATION PROCESS:
When building any UI or Website, auto-generate design system:
1. Identify product category → match to 161 reasoning rules
2. Select UI style from 67 available styles
3. Choose color palette (industry-appropriate)
4. Pick typography pairing (57 combinations)
5. Apply anti-pattern filters
6. Run pre-delivery checklist
━━━ 67 UI STYLES (key selections) ━━━
MODERN/PREMIUM:
• Glassmorphism → SaaS, fintech, AI | frosted glass, backdrop-blur, rgba
• Neumorphism → wellness, meditation | soft shadows, embossed, subtle depth
• Liquid Glass → premium e-commerce | fluid shapes, layered transparency
• Aurora UI → creative agencies | gradient meshes, animated backgrounds
• AI-Native UI → chatbots, AI products | dark #0a0a0a, glowing accents, streaming
• Soft UI Evolution → enterprise | clean, rounded-2xl, subtle elevation
• Neubrutalism → Gen Z brands | bold borders, offset shadows, raw aesthetics
CLASSIC/PROFESSIONAL:
• Minimalism & Swiss Style → enterprise, docs | strict grid, typography-first
• Flat Design → web apps | clean icons, no shadows, bold colors
• Dark Mode OLED → coding platforms | pure black #000, minimal battery
• Bento Box Grid → dashboards, portfolios | card-based, asymmetric grid
CREATIVE/NICHE:
• Brutalism → design portfolios | raw, intentionally "broken" layouts
• Cyberpunk UI → gaming, crypto | neon on dark, grid lines, glitch effects
• Claymorphism → educational, children | 3D clay-like, inflated elements
• Ambient Calm UI → meditation, sleep | slow animations, muted palette
━━━ 161 REASONING RULES (product → design) ━━━
AI/Chatbot → AI-Native UI | Dark #0a0a0a | Space Grotesk | Glowing accents
SaaS → Glassmorphism or Bento Grid | Neutral | Inter/DM Sans
E-commerce → Social Proof | Trust elements | Conversion CTAs above fold
Fintech/Crypto → Glassmorphism | Dark + green accent | Roboto Mono for numbers
Healthcare → Accessible & Ethical | High contrast | Clean sans-serif | WCAG AA
Educational → Claymorphism | Bright primary | Nunito/Quicksand | Friendly
Gaming → Cyberpunk | Neon accents | Exo 2/Rajdhani | Dark base
Portfolio → Brutalism or Minimalism | Unique typography | Strong visual identity
Restaurant → Photo-Centric | Warm palette | Playfair Display | Appetizing imagery
Startup MVP → Minimal & Direct | One primary CTA | Fast loading | Sora/DM Sans
━━━ 57 TYPOGRAPHY PAIRINGS ━━━
• Sora + Inter → Modern SaaS, AI products
• Playfair Display + Lato → Luxury, restaurant, editorial
• Space Grotesk + JetBrains Mono → Tech, coding, crypto
• Cormorant Garamond + Montserrat → Premium, legal, architecture
• Nunito + Open Sans → Educational, children, wellness
• Clash Display + Satoshi → Gen Z, creative agency
• DM Serif + DM Sans → Editorial, blog, modern media
• Exo 2 + Rajdhani → Gaming, fitness, esports
• Libre Baskerville + Source Sans → Legal, finance, B2B
• Outfit + DM Sans → App, startup, modern product
━━━ COLOR PALETTES ━━━
DARK THEMES:
• AI Dark: bg #0a0a0a surface #141414 accent #e11d48
• Cyber: bg #0d0d1a surface #1a1a2e accent #00fff5
• Pro Dark: bg #0f0f0f surface #1a1a1a accent #6366f1
LIGHT THEMES:
• Clean SaaS: bg #ffffff surface #f8fafc accent #0ea5e9
• Warm: bg #fafaf9 surface #f5f5f4 accent #f59e0b
• Premium: bg #fafafa surface #ffffff accent #8b5cf6
━━━ 25 CHART TYPES ━━━
Line/Area → trends | Bar/Stacked → comparison | Donut → KPI proportion
Candlestick → financial | Funnel → conversion | Gauge → single metric
Heatmap → matrix density | Treemap → hierarchy | Radar → multi-dimension
Sankey → flow | Choropleth → geographic | Gantt → project timeline
{_UX_GUIDELINES}
{_CHECKLIST}
━━━ PRE-DELIVERY CHECKLIST ━━━
[ ] No placeholder text remaining
[ ] cursor:pointer on ALL clickables
[ ] Hover states (150-300ms transitions)
[ ] Focus states visible
[ ] Responsive: 375/768/1024/1440px
[ ] Text contrast 4.5:1 minimum
[ ] Loading + error + empty states
[ ] prefers-reduced-motion respected
[ ] No emoji as icons (SVG only)
[ ] Touch targets 44x44px minimum
"""
# ═══════════════════════════════════════════════════════
# PYDANTIC
# ═══════════════════════════════════════════════════════
class ChatRequest(BaseModel):
message:str; session_id:Optional[str]=None
task_type:Optional[str]=None; mode:Optional[str]=None
class ExamRequest(BaseModel):
subject:str; class_:str; topic:Optional[str]=None
q_count:Optional[int]=10; type_:Optional[str]="mixed"; lang:Optional[str]="bn"
# ═══════════════════════════════════════════════════════
# NCTB 2026 — Complete Bangladesh Curriculum
# ═══════════════════════════════════════════════════════
NCTB_2026 = {
"Pre_Primary": {
"books": ["আমার বই","এসো লিখতে শিখি"],
"note": "শিশুর প্রাক-প্রাথমিক শিক্ষার ভিত্তি গড়ে তোলার জন্য"
},
"Class_1": {
"subjects": {
"আমার বাংলা বই": "বাংলা ভাষা শিক্ষা, বর্ণমালা, ছড়া, গল্প",
"English for Today": "Basic English, alphabets, simple sentences",
"আনন্দ পাঠ (বাংলা সহপাঠ)": "বাংলা সহায়ক পাঠ",
"প্রাথমিক গণিত": "সংখ্যা, যোগ, বিয়োগ, আকার",
}
},
"Class_2": {
"subjects": {
"আমার বাংলা বই": "বাংলা ব্যাকরণ, রচনা, কবিতা",
"English for Today": "Reading, writing, grammar basics",
"প্রাথমিক গণিত": "গুণ, ভাগ, পরিমাপ",
}
},
"Class_3": {
"subjects": {
"আমার বাংলা বই": "বাংলা সাহিত্য, ব্যাকরণ, রচনা",
"English for Today": "Reading comprehension, vocabulary, writing",
"প্রাথমিক গণিত": "জ্যামিতি, ভগ্নাংশ, সমস্যা সমাধান",
"প্রাথমিক বিজ্ঞান": "পরিবেশ, উদ্ভিদ, প্রাণী, আবহাওয়া",
"বাংলাদেশ ও বিশ্বপরিচয়": "বাংলাদেশের ইতিহাস, ভূগোল, সংস্কৃতি",
"ইসলাম ও নৈতিক শিক্ষা": "ইসলামিক মূল্যবোধ ও আখলাক",
"হিন্দুধর্ম ও নৈতিক শিক্ষা": "হিন্দু ধর্মীয় মূল্যবোধ",
}
},
"Class_4": {
"subjects": {
"আমার বাংলা বই": "বাংলা সাহিত্য ও ব্যাকরণ উন্নত",
"English for Today": "Advanced reading, grammar, composition",
"প্রাথমিক গণিত": "দশমিক, শতকরা, পরিমাপ",
"প্রাথমিক বিজ্ঞান": "মানবদেহ, পদার্থ, শক্তি",
"বাংলাদেশ ও বিশ্বপরিচয়": "মুক্তিযুদ্ধ, সংবিধান, বিশ্ব",
"ইসলাম ও নৈতিক শিক্ষা": "নামাজ, কোরান, হাদিস",
}
},
"Class_5": {
"subjects": {
"আমার বাংলা বই": "উন্নত সাহিত্য ও রচনা",
"English for Today": "Essay writing, advanced grammar",
"প্রাথমিক গণিত": "বীজগণিত পরিচিতি, পরিমিতি",
"প্রাথমিক বিজ্ঞান": "রাসায়নিক পরিবর্তন, জীববিজ্ঞান",
"বাংলাদেশ ও বিশ্বপরিচয়": "অর্থনীতি, বৈশ্বিক সম্পর্ক",
"ইসলাম ও নৈতিক শিক্ষা": "সিরাত, ফিকহ",
}
},
"Class_6": {
"level": "JSC/Junior Secondary",
"subjects": {
"বাংলা": "বাংলা সাহিত্য: কবিতা, গল্প, উপন্যাস, প্রবন্ধ; ব্যাকরণ: ধ্বনি, শব্দ, বাক্য, সমাস, কারক",
"English": "Reading comprehension, essay writing, grammar, letter writing",
"গণিত": "বাস্তব সংখ্যা, সরল সমীকরণ, জ্যামিতি, পরিমাপ",
"বিজ্ঞান": "পদার্থ, শক্তি, জীববিজ্ঞান, রসায়নের প্রাথমিক ধারণা",
"সামাজিক বিজ্ঞান": "ইতিহাস, ভূগোল, অর্থনীতি, নাগরিক শিক্ষা",
"তথ্য ও যোগাযোগ প্রযুক্তি (ICT)": "কম্পিউটার, ইন্টারনেট, প্রোগ্রামিং পরিচিতি",
"ইসলাম ও নৈতিক শিক্ষা": "আকিদা, ইবাদত, আখলাক, মুয়ামালাত",
"কৃষি শিক্ষা": "কৃষি ও খাদ্য উৎপাদন",
"শারীরিক শিক্ষা ও স্বাস্থ্য": "স্বাস্থ্যবিধি, ব্যায়াম, খেলাধুলা",
"চারু ও কারুকলা": "শিল্পকলা, ডিজাইন, রং",
"জীবন ও জীবিকা": "পেশা পরিচিতি, জীবন দক্ষতা (নতুন পাঠ্যক্রম ২০২৬)",
"ডিজিটাল প্রযুক্তি": "ডিজিটাল লিটারেসি, কোডিং (নতুন পাঠ্যক্রম ২০২৬)",
"সুস্থতা ও সমৃদ্ধ জীবন": "ওয়েলনেস, মানসিক স্বাস্থ্য (নতুন পাঠ্যক্রম ২০২৬)",
}
},
"Class_7": {
"level": "JSC/Junior Secondary",
"subjects": {
"বাংলা": "উন্নত সাহিত্য বিশ্লেষণ, রচনা, ব্যাকরণ",
"English": "Advanced grammar, literature, formal writing",
"গণিত": "বীজগণিত, জ্যামিতি, পরিসংখ্যান প্রাথমিক",
"বিজ্ঞান": "পদার্থবিজ্ঞান, রসায়ন, জীববিজ্ঞান, ভূগোল",
"সামাজিক বিজ্ঞান": "বাংলাদেশের ইতিহাস, বিশ্ব ইতিহাস, ভূগোল",
"তথ্য ও যোগাযোগ প্রযুক্তি (ICT)": "স্প্রেডশিট, উপস্থাপনা, ওয়েব পেজ",
"ইসলাম ও নৈতিক শিক্ষা": "কোরান তাফসির, হাদিস, ফিকহ",
"কৃষি শিক্ষা": "আধুনিক কৃষি, মৎস্য ও প্রাণিসম্পদ",
"জীবন ও জীবিকা": "উদ্যোক্তা, ক্যারিয়ার পরিকল্পনা",
"ডিজিটাল প্রযুক্তি": "প্রোগ্রামিং, সাইবার নিরাপত্তা",
}
},
"Class_8": {
"level": "JSC",
"subjects": {
"বাংলা": "সাহিত্য সমালোচনা, ব্যাকরণের গভীর জ্ঞান, সৃজনশীল রচনা",
"English": "Advanced literature, composition, communication skills",
"গণিত": "দ্বিঘাত সমীকরণ, ত্রিকোণমিতি পরিচিতি, পরিসংখ্যান",
"সাধারণ বিজ্ঞান": "পদার্থ, রসায়ন, জীববিজ্ঞান, পরিবেশ বিজ্ঞান",
"বাংলাদেশ ও বিশ্বপরিচয়": "জাতীয় ইতিহাস, বিশ্ব রাজনীতি",
"তথ্য ও যোগাযোগ প্রযুক্তি": "ডেটাবেস, নেটওয়ার্কিং, ওয়েব ডিজাইন",
"ইসলাম ও নৈতিক শিক্ষা": "শরিয়া, সিরাত, ইসলামি সভ্যতা",
}
},
"SSC_Class_9_10": {
"level": "SSC (Secondary School Certificate)",
"exam_board": "Bangladesh Board SSC Exam",
"groups": {
"বিজ্ঞান (Science)": {
"mandatory": ["বাংলা","English","গণিত","তথ্য ও যোগাযোগ প্রযুক্তি"],
"elective": ["পদার্থবিজ্ঞান","রসায়ন","জীববিজ্ঞান","উচ্চতর গণিত"],
"optional": ["কৃষি শিক্ষা","গার্হস্থ্য বিজ্ঞান","বাংলাদেশ ও বিশ্বপরিচয়"],
},
"মানবিক (Arts)": {
"mandatory": ["বাংলা","English","গণিত","তথ্য ও যোগাযোগ প্রযুক্তি"],
"elective": ["ইতিহাস","ভূগোল ও পরিবেশ","পৌরনীতি ও নাগরিকতা","অর্থনীতি"],
"optional": ["বাংলাদেশ ও বিশ্বপরিচয়"],
},
"ব্যবসায় শিক্ষা (Commerce)": {
"mandatory": ["বাংলা","English","গণিত","তথ্য ও যোগাযোগ প্রযুক্তি"],
"elective": ["হিসাববিজ্ঞান","ব্যবসায় উদ্যোগ","ফিন্যান্স ও ব্যাংকিং"],
"optional": ["অর্থনীতি","বাংলাদেশ ও বিশ্বপরিচয়"],
}
},
"subject_details": {
"পদার্থবিজ্ঞান": "গতি, নিউটনের সূত্র, কাজ-শক্তি, তরঙ্গ, আলো, তড়িৎ, আধুনিক পদার্থবিজ্ঞান",
"রসায়ন": "পরমাণু গঠন, পর্যায় সারণি, রাসায়নিক বন্ধন, জৈব রসায়ন, পরীক্ষা-নিরীক্ষা",
"জীববিজ্ঞান": "কোষ, টিস্যু, উদ্ভিদ, প্রাণী, মানবদেহ, বংশগতি, বিবর্তন",
"উচ্চতর গণিত": "ত্রিকোণমিতি, ক্যালকুলাস পরিচিতি, ভেক্টর, পরিসংখ্যান",
"হিসাববিজ্ঞান": "ডেবিট-ক্রেডিট, জার্নাল, লেজার, ট্রায়াল ব্যালেন্স, আর্থিক বিবরণী",
"ব্যবসায় উদ্যোগ": "উদ্যোক্তা, ব্যবসায় পরিকল্পনা, বিপণন, ব্যবস্থাপনা",
"ইতিহাস": "প্রাচীন বাংলা, মধ্যযুগ, মুঘল, ব্রিটিশ, বাংলাদেশের স্বাধীনতা",
"ভূগোল ও পরিবেশ": "পৃথিবীর গঠন, জলবায়ু, বাংলাদেশের ভূগোল, পরিবেশ সংরক্ষণ",
}
},
"HSC_Class_11_12": {
"level": "HSC (Higher Secondary Certificate)",
"exam_board": "Bangladesh Board HSC Exam",
"groups": {
"বিজ্ঞান (Science)": {
"mandatory": ["বাংলা","English","তথ্য ও যোগাযোগ প্রযুক্তি"],
"elective_1st": ["পদার্থবিজ্ঞান ১ম ও ২য় পত্র"],
"elective_2nd": ["রসায়ন ১ম ও ২য় পত্র"],
"elective_3rd": ["জীববিজ্ঞান / উচ্চতর গণিত"],
},
"মানবিক (Arts)": {
"mandatory": ["বাংলা","English","তথ্য ও যোগাযোগ প্রযুক্তি"],
"elective": ["ইতিহাস","ইসলামের ইতিহাস","ভূগোল","পৌরনীতি","সমাজবিজ্ঞান","অর্থনীতি","দর্শন","মনোবিজ্ঞান"],
},
"ব্যবসায় শিক্ষা (Commerce)": {
"mandatory": ["বাংলা","English","তথ্য ও যোগাযোগ প্রযুক্তি"],
"elective": ["হিসাববিজ্ঞান ১ম ও ২য় পত্র","ব্যবসায় সংগঠন ও ব্যবস্থাপনা","ফিন্যান্স, ব্যাংকিং ও বিমা","উৎপাদন ব্যবস্থাপনা ও বিপণন"],
}
},
"subject_details": {
"পদার্থবিজ্ঞান": "ভেক্টর, নিউটনীয় বলবিদ্যা, কাজ-শক্তি-ক্ষমতা, তরঙ্গ, তাপগতিবিদ্যা, আলোকবিজ্ঞান, তড়িচ্চুম্বকতা, আধুনিক পদার্থবিজ্ঞান (কোয়ান্টাম, পারমাণবিক)",
"রসায়ন": "পরমাণু মডেল, রাসায়নিক সাম্য, তড়িৎ রসায়ন, জৈব যৌগ, পলিমার, পরিবেশ রসায়ন",
"জীববিজ্ঞান": "কোষবিভাজন, বংশগতি ও বিবর্তন, উদ্ভিদ শারীরতত্ত্ব, প্রাণী শারীরবিজ্ঞান, মানব স্বাস্থ্য",
"উচ্চতর গণিত": "ম্যাট্রিক্স, ভেক্টর, ক্যালকুলাস (অবকল, সমাকল), জটিল সংখ্যা, বিন্যাস-সমাবেশ, সম্ভাবনা",
"হিসাববিজ্ঞান": "অংশীদারি ব্যবসা, কোম্পানি হিসাব, মূলধন বাজেটিং, আর্থিক বিশ্লেষণ",
"অর্থনীতি": "ব্যষ্টিক অর্থনীতি, সামষ্টিক অর্থনীতি, বাংলাদেশের অর্থনীতি, আন্তর্জাতিক বাণিজ্য",
"ICT": "ডেটা স্ট্রাকচার, অ্যালগরিদম, ডেটাবেস, নেটওয়ার্ক, ওয়েব ডেভেলপমেন্ট, সাইবার নিরাপত্তা",
}
}
}
NCTB_CONTEXT = """
[NCTB 2026 — Bangladesh National Curriculum & Textbook Board]
তুমি বাংলাদেশের ২০২৬ সালের সম্পূর্ণ NCTB পাঠ্যক্রম জানো:
প্রাথমিক (Class 1-5): বাংলা, ইংরেজি, গণিত, বিজ্ঞান, বাংলাদেশ ও বিশ্বপরিচয়, ধর্ম শিক্ষা
মাধ্যমিক (Class 6-8): উপরের + ICT, কৃষি, শারীরিক শিক্ষা + নতুন বিষয়: জীবন ও জীবিকা, ডিজিটাল প্রযুক্তি
SSC (Class 9-10): বিজ্ঞান/মানবিক/ব্যবসায় শিক্ষা গ্রুপ
HSC (Class 11-12): উন্নত বিজ্ঞান/মানবিক/ব্যবসায় গ্রুপ
নতুন পাঠ্যক্রম ২০২৬ বৈশিষ্ট্য:
- Competency-based learning (মুখস্থ নয়, দক্ষতা অর্জন)
- সৃজনশীল প্রশ্নপদ্ধতি (Creative Question)
- Digital Technology বিষয় নতুন যুক্ত
- জীবন ও জীবিকা বিষয় নতুন
- সুস্থতা ও সমৃদ্ধ জীবন বিষয় নতুন
"""
# ═══════════════════════════════════════════════════════
# GAME DEV STUDIO INTELLIGENCE
# Adapted from Claude-Code-Game-Studios by Donchitos
# ═══════════════════════════════════════════════════════
GAME_DEV_STUDIO = """
═══ GAME DEV STUDIO INTELLIGENCE ═══
STUDIO HIERARCHY (when building games):
Tier 1 — Directors: creative-director, technical-director, producer
Tier 2 — Leads: game-designer, lead-programmer, art-director, audio-director, qa-lead
Tier 3 — Specialists: gameplay-programmer, ui-programmer, level-designer, systems-designer
ENGINE SELECTION RULES:
- Godot 4 → indie, 2D/3D, open source, GDScript/C#, lightweight
- Unity → mobile, cross-platform, C#, large asset store
- Unreal 5 → AAA quality, C++/Blueprints, photorealistic graphics
GAME DESIGN FRAMEWORKS:
- MDA Framework → Mechanics (rules) → Dynamics (behavior) → Aesthetics (experience)
- Flow State Design → keep challenge slightly above skill level
- Bartle Types → Achievers / Explorers / Socializers / Killers
- Self-Determination Theory → Autonomy + Competence + Relatedness
GAME ARCHITECTURE RULES:
- Data-driven values — NO hardcoded magic numbers (use config files)
- Delta time always — movement *= delta_time (never frame-rate dependent)
- Server-authoritative for multiplayer — never trust client
- Component-based design — prefer composition over inheritance
- Object pooling for bullets/particles (never Instantiate in hot loops)
- State machines for game logic (Player: Idle/Run/Jump/Attack/Dead)
GAME GENRE → TECH STACK:
- 2D Platformer → Godot 4 (CharacterBody2D, TileMap, AnimationPlayer)
- 3D Action → Unreal 5 (GAS, Blueprints) or Unity (DOTS for performance)
- Mobile Casual → Unity (lightweight, IL2CPP, addressables)
- Puzzle → Godot 4 or Unity (simple, fast iteration)
- Multiplayer → Unity Netcode or Unreal Replication or Godot MultiplayerAPI
- RPG → Godot 4 (Resource system perfect for items/stats) or Unreal (GAS)
CODE QUALITY GATES:
✓ No magic numbers — extract to constants/config
✓ Delta time on all movement/physics
✓ Error handling on save/load
✓ Input abstraction layer (not direct key checks in game logic)
✓ Separate game logic from rendering
✓ Unit tests for game systems (economy, combat math)
GAME DOCUMENT TEMPLATES:
GDD must have: Vision, Core Loop, Mechanics, Progression, Economy, Art Style, Audio, Scope
Sprint plan: Goal, Tasks, Acceptance Criteria, Dependencies, Risk
WHEN USER ASKS TO BUILD A GAME:
1. Ask: genre? platform? engine preference? team size? scope?
2. Suggest engine based on answers
3. Design core loop first (what does player DO every 30 seconds?)
4. Define win/lose conditions
5. Minimal viable prototype first — one mechanic, working end-to-end
6. Then expand: UI, audio, polish, menus
"""
# ═══════════════════════════════════════════════════════
# LANGUAGE DETECTION
# ═══════════════════════════════════════════════════════
BN_UNICODE = re.compile(r'[\u0980-\u09FF]')
# Pure Bangla words (Romanized) — not English words
BN_ROMAN_WORDS = [
'ami','tumi','apni','ki','keno','kothay','ache','hobe','koro','bolo','jano',
'likhte','bolte','dite','nao','dao','jao','aso','thako','dekho','eta','ota',
'eita','oita','emon','onek','ektu','bhalo','kharap','shundor','kothin','shohoj',
'porashona','bishoy','bujhi','bujhte','bujhao','korao','shekao','korte','korbo',
'hoyeche','lagbe','chai','thakbe','parbo','bolo','janao','dekhai','shekhai',
'acche','nai','hoy','theke','diye','niye','boro','choto','valo','tomar','amar',
'apnar','amader','tomader','apnader','kintu','tahole','karon','jodi','nahole',
'ekhon','pore','age','kal','aaj','raat','din','shomoy','khabar','pani','basha',
'kaj','por','lekho','poro','dekho','shono','bujho','jao','esho','thako',
]
def detect_lang(text: str) -> str:
"""
Detect language:
- "bn" → Bengali Unicode characters found
- "en" → English only, no Bangla signals
- "bn_roman" → Romanized Bangla words detected (Banglish)
"""
# Bengali Unicode = definitely Bengali
if BN_UNICODE.search(text):
return "bn"
lower = text.lower()
words = re.findall(r'\b[a-z]+\b', lower)
if not words:
return "en"
# Count how many words are pure Bangla (Romanized)
bn_count = sum(1 for w in words if w in BN_ROMAN_WORDS)
total_words = len(words)
# If 30%+ words are Bangla Romanized → Banglish
if bn_count >= 2 and (bn_count / total_words) >= 0.25:
return "bn_roman"
return "en"
def lang_instr(lang: str) -> str:
if lang == "bn":
return (
"⚡ CRITICAL LANGUAGE RULE: The user is writing in Bengali (বাংলা).\n"
"You MUST reply ENTIRELY in Bengali script (বাংলা হরফে).\n"
"Every single word must be in Bengali. No English words allowed in the reply.\n"
"Example: 'হ্যাঁ, এটা একটি গুরুত্বপূর্ণ বিষয়। চলো ধাপে ধাপে বুঝি...'"
)
if lang == "bn_roman":
return (
"⚡ CRITICAL LANGUAGE RULE: The user is writing in Banglish (Romanized Bengali + English mix).\n"
"You MUST reply in PURE ENGLISH only — clear, simple, friendly English.\n"
"Do NOT use Bengali script. Do NOT mix languages in your reply.\n"
"Reason: The user is typing Bangla words in English letters, "
"so they can read English comfortably. Give a clean English answer.\n"
"Example: 'Yes, this is an important concept. Let me explain step by step...'"
)
return ""
# ═══════════════════════════════════════════════════════
# DATABASE
# ═══════════════════════════════════════════════════════
def _db(): return sqlite3.connect(str(DB_PATH),check_same_thread=False)
def init_db():
with _db() as c:
c.executescript("""
CREATE TABLE IF NOT EXISTS messages(id INTEGER PRIMARY KEY AUTOINCREMENT,
session_id TEXT,role TEXT,content TEXT,ts REAL DEFAULT(unixepoch('now')));
CREATE TABLE IF NOT EXISTS sessions(id TEXT PRIMARY KEY,title TEXT,mode TEXT,
updated REAL DEFAULT(unixepoch('now')));
CREATE TABLE IF NOT EXISTS rag_docs(id INTEGER PRIMARY KEY AUTOINCREMENT,
doc_id TEXT,title TEXT,chunk TEXT,source TEXT,category TEXT DEFAULT 'general',
ts REAL DEFAULT(unixepoch('now')));
CREATE TABLE IF NOT EXISTS live_feed(id INTEGER PRIMARY KEY AUTOINCREMENT,
title TEXT,summary TEXT,url TEXT,source TEXT,category TEXT,
published TEXT,fetched_at REAL DEFAULT(unixepoch('now')));
CREATE TABLE IF NOT EXISTS knowledge_log(id INTEGER PRIMARY KEY AUTOINCREMENT,
source TEXT,items_fetched INTEGER,ts REAL DEFAULT(unixepoch('now')));
CREATE INDEX IF NOT EXISTS idx_msg ON messages(session_id);
CREATE INDEX IF NOT EXISTS idx_feed ON live_feed(category,fetched_at);
""")
init_db()
def mem_add(sid,role,content):
with _db() as c:
c.execute("INSERT INTO messages(session_id,role,content) VALUES(?,?,?)",(sid,role,content[:15000]))
c.execute("INSERT OR REPLACE INTO sessions(id,title,updated) VALUES(?,?,unixepoch('now'))",
(sid,content[:55] if role=="user" else None))
def mem_get(sid,limit=16):
with _db() as c:
rows=c.execute("SELECT role,content FROM messages WHERE session_id=? ORDER BY ts DESC LIMIT ?",(sid,limit)).fetchall()
return [{"role":r,"content":cn} for r,cn in reversed(rows)]
def mem_sessions():
with _db() as c:
rows=c.execute("SELECT id,title,mode,updated FROM sessions ORDER BY updated DESC LIMIT 40").fetchall()
return [{"id":r[0],"title":r[1] or "Conversation","mode":r[2],"updated":r[3]} for r in rows]
def mem_delete(sid):
with _db() as c:
c.execute("DELETE FROM messages WHERE session_id=?",(sid,))
c.execute("DELETE FROM sessions WHERE id=?",(sid,))
def mem_stats():
with _db() as c:
msgs=c.execute("SELECT COUNT(*) FROM messages").fetchone()[0]
sess=c.execute("SELECT COUNT(*) FROM sessions").fetchone()[0]
feeds=c.execute("SELECT COUNT(*) FROM live_feed").fetchone()[0]
last=c.execute("SELECT MAX(fetched_at) FROM knowledge_log").fetchone()[0]
return {"messages":msgs,"sessions":sess,"live_articles":feeds,
"last_update":datetime.fromtimestamp(last,timezone.utc).strftime("%Y-%m-%d %H:%M UTC") if last else "Not yet"}
def rag_store(title,text,source,category="general"):
doc_id=hashlib.md5((title+text[:60]).encode()).hexdigest()[:10]
words=text.split()
with _db() as c:
c.execute("DELETE FROM rag_docs WHERE doc_id=?",(doc_id,))
for i in range(0,len(words),300):
chunk=" ".join(words[i:i+380])
if len(chunk.strip())>40:
c.execute("INSERT INTO rag_docs(doc_id,title,chunk,source,category) VALUES(?,?,?,?,?)",(doc_id,title,chunk,source,category))
def rag_search(query,limit=4,category=None):
words=set(re.findall(r"\w{4,}",query.lower()))
if not words: return []
with _db() as c:
if category:
rows=c.execute("SELECT title,chunk,source FROM rag_docs WHERE category=? ORDER BY ts DESC LIMIT 400",(category,)).fetchall()
else:
rows=c.execute("SELECT title,chunk,source FROM rag_docs ORDER BY ts DESC LIMIT 400").fetchall()
scored=[(len(words&set(re.findall(r"\w{4,}",ch.lower())))/max(len(words),1),t,ch[:300],s) for t,ch,s in rows]
return sorted([x for x in scored if x[0]>0.10],reverse=True)[:limit]
def feed_store(title,summary,url,source,category,published=""):
with _db() as c:
exists=c.execute("SELECT id FROM live_feed WHERE url=?",(url,)).fetchone()
if not exists:
c.execute("INSERT INTO live_feed(title,summary,url,source,category,published) VALUES(?,?,?,?,?,?)",
(title,summary[:500],url,source,category,published))
rag_store(title,f"{title}. {summary}",source,category)
def feed_get(category=None,limit=8):
with _db() as c:
if category:
rows=c.execute("SELECT title,summary,url,source,published FROM live_feed WHERE category=? ORDER BY fetched_at DESC LIMIT ?",(category,limit)).fetchall()
else:
rows=c.execute("SELECT title,summary,url,source,published FROM live_feed ORDER BY fetched_at DESC LIMIT ?",(limit,)).fetchall()
return [{"title":r[0],"summary":r[1],"url":r[2],"source":r[3],"published":r[4]} for r in rows]
# ═══════════════════════════════════════════════════════
# FREE TOOLS
# ═══════════════════════════════════════════════════════
def _get(url,params=None,timeout=8):
try:
headers={"User-Agent":"RUBRA/8.0"}
return _req.get(url,params=params,headers=headers,timeout=timeout)
except: return None
CITY_COORDS={"dhaka":(23.81,90.41),"london":(51.51,-0.13),"new york":(40.71,-74.01),
"tokyo":(35.68,139.65),"paris":(48.86,2.35),"sydney":(-33.87,151.21),"dubai":(25.20,55.27),
"singapore":(1.35,103.82),"berlin":(52.52,13.41),"mumbai":(19.08,72.88),"beijing":(39.90,116.41),
"seoul":(37.57,126.98),"chittagong":(22.33,91.84),"sylhet":(24.89,91.87),"rajshahi":(24.37,88.60),
"delhi":(28.61,77.21),"karachi":(24.86,67.01),"chicago":(41.88,-87.63),"toronto":(43.65,-79.38),
"istanbul":(41.01,28.98),"cairo":(30.04,31.24),"lagos":(6.52,3.38),"jakarta":(-6.21,106.85)}
WC={0:"☀️ Clear",1:"🌤 Clear",2:"⛅ Partly cloudy",3:"☁️ Overcast",45:"🌫 Foggy",
51:"🌦 Drizzle",61:"🌧 Light rain",63:"🌧 Rain",65:"🌧 Heavy rain",71:"❄️ Snow",
80:"🌦 Showers",95:"⛈ Thunderstorm"}
def tool_weather(city="Dhaka"):
lat,lon=CITY_COORDS.get(city.lower().strip(),(23.81,90.41))
r=_get("https://api.open-meteo.com/v1/forecast",{"latitude":lat,"longitude":lon,"timezone":"auto",
"current":["temperature_2m","relative_humidity_2m","wind_speed_10m","weather_code","apparent_temperature","precipitation"]})
if not r: return None
try:
curr=r.json()["current"]
return {"city":city.title(),"temp":curr.get("temperature_2m"),"feels":curr.get("apparent_temperature"),
"humidity":curr.get("relative_humidity_2m"),"wind":curr.get("wind_speed_10m"),
"precip":curr.get("precipitation",0),"condition":WC.get(curr.get("weather_code",0),"Unknown")}
except: return None
def tool_crypto(coins="bitcoin,ethereum,solana"):
r=_get("https://api.coingecko.com/api/v3/simple/price",{"ids":coins,"vs_currencies":"usd","include_24hr_change":"true"})
if not r: return None
try: return r.json()
except: return None
def tool_currency(base="USD"):
r=_get("https://api.frankfurter.app/latest",{"from":base,"to":"EUR,GBP,JPY,BDT,INR,CAD,AUD,CNY,SGD"})
if not r: return None
try: d=r.json(); return {"base":base,"rates":d.get("rates",{}),"date":d.get("date","")}
except: return None
def tool_wikipedia(query,sentences=7):
r=_get("https://en.wikipedia.org/w/api.php",{"action":"query","format":"json","prop":"extracts",
"exsentences":sentences,"exintro":True,"explaintext":True,"redirects":1,"titles":query})
if not r: return None
try:
pages=r.json()["query"]["pages"]; page=next(iter(pages.values()))
if "extract" in page and len(page["extract"])>80:
rag_store(page.get("title",""),page["extract"],"wikipedia","general")
return {"title":page.get("title",""),"text":page["extract"][:2000]}
except: pass
return None
def tool_arxiv(query,n=3):
r=_get("https://export.arxiv.org/api/query",{"search_query":f"all:{query}","max_results":n},timeout=12)
if not r: return []
try:
root=ET.fromstring(r.content); ns={"a":"http://www.w3.org/2005/Atom"}; out=[]
for e in root.findall("a:entry",ns):
t=e.find("a:title",ns).text.strip().replace("\n"," ")
s=e.find("a:summary",ns).text.strip()[:400]
l=e.find("a:id",ns).text.strip()
a=[x.find("a:name",ns).text for x in e.findall("a:author",ns)[:2]]
out.append({"title":t,"summary":s,"link":l,"authors":a}); rag_store(t,s,"arxiv","ai")
return out
except: return []
def tool_books(query,n=5):
r=_get("https://openlibrary.org/search.json",{"q":query,"limit":n,"fields":"title,author_name,first_publish_year"})
if not r: return []
try: return [{"title":d.get("title",""),"authors":d.get("author_name",[])[:2],"year":d.get("first_publish_year","")} for d in r.json().get("docs",[])[:n]]
except: return []
def tool_books_2026(query=""):
results=[]
# Google Books API (free, no key)
r=_get("https://www.googleapis.com/books/v1/volumes",
{"q":f"{query or 'bestseller'} 2025 2026","orderBy":"newest","maxResults":10,"langRestrict":"en"})
if r:
try:
for item in r.json().get("items",[]):
info=item.get("volumeInfo",{}); pub=info.get("publishedDate","")
year=int(pub[:4]) if pub and len(pub)>=4 and pub[:4].isdigit() else 0
if year>=2023:
results.append({"title":info.get("title",""),"authors":info.get("authors",[])[:2],"year":year,"subjects":info.get("categories",[])[:2]})
except: pass
# Open Library fallback
if not results:
r=_get("https://openlibrary.org/search.json",{"q":query or "fiction 2025","sort":"new","limit":8,"fields":"title,author_name,first_publish_year"})
if r:
try:
books=r.json().get("docs",[]); results=[b for b in books if b.get("first_publish_year",0)>=2023]
except: pass
seen=set(); unique=[]
for b in results:
t=b.get("title","").lower()[:40]
if t and t not in seen: seen.add(t); unique.append(b)
return unique[:6]
def tool_calc(expr):
try:
clean=re.sub(r"[^0-9+\-*/().\s%]","",expr.replace("^","**").replace("×","*").replace("÷","/"))
result=eval(clean,{"__builtins__":{},"math":math,"abs":abs,"round":round,"sqrt":math.sqrt,
"sin":math.sin,"cos":math.cos,"tan":math.tan,"log":math.log,"pi":math.pi,"e":math.e})
return {"expr":expr,"result":result}
except Exception as ex: return {"error":str(ex)}
# ═══════════════════════════════════════════════════════
# REAL-TIME WEB BROWSER ENGINE
# ═══════════════════════════════════════════════════════
# Safe domains blacklist (never browse these)
_UNSAFE_DOMAINS = {
'onion', 'tor2web', 'i2p', 'bit.ly', 'tinyurl.com',
'pastebin.com', 'rentry.co', 'ghostbin.com',
}
# Content-type whitelist
_SAFE_CONTENT = {'text/html', 'text/plain', 'application/xhtml+xml', 'application/xml'}
class _TextExtractor(HTMLParser):
"""Fast pure-Python HTML → clean text extractor."""
SKIP_TAGS = {'script','style','noscript','head','meta','link',
'nav','footer','aside','ads','iframe','svg','path'}
def __init__(self):
super().__init__()
self.chunks = []
self.skip_depth = 0
self._tag_stack = []
def handle_starttag(self, tag, attrs):
self._tag_stack.append(tag)
if tag in self.SKIP_TAGS:
self.skip_depth += 1
def handle_endtag(self, tag):
if self._tag_stack and self._tag_stack[-1] == tag:
self._tag_stack.pop()
if tag in self.SKIP_TAGS and self.skip_depth > 0:
self.skip_depth -= 1
def handle_data(self, data):
if self.skip_depth == 0:
text = data.strip()
if text and len(text) > 1:
self.chunks.append(text)
def get_text(self):
return '\n'.join(self.chunks)
class _LinkExtractor(HTMLParser):
"""Extract all <a href> links from a page."""
def __init__(self, base_url):
super().__init__()
self.base_url = base_url
self.links = []
def handle_starttag(self, tag, attrs):
if tag == 'a':
attrs_dict = dict(attrs)
href = attrs_dict.get('href','').strip()
text = attrs_dict.get('title','') or ''
if href and not href.startswith(('#','mailto:','tel:','javascript:')):
abs_url = urljoin(self.base_url, href)
parsed = urlparse(abs_url)
if parsed.scheme in ('http','https'):
self.links.append({'url': abs_url, 'text': text[:80]})
def _is_safe_url(url: str) -> bool:
"""Check URL is safe to browse."""
try:
parsed = urlparse(url)
if parsed.scheme not in ('http','https'):
return False
host = parsed.netloc.lower()
# Block unsafe domains
for bad in _UNSAFE_DOMAINS:
if bad in host:
return False
# Block private/local IPs
import ipaddress
try:
ip = ipaddress.ip_address(host.split(':')[0])
if ip.is_private or ip.is_loopback or ip.is_reserved:
return False
except ValueError:
pass # It's a hostname, not an IP
return True
except Exception:
return False
def _robots_allowed(url: str) -> bool:
"""Check robots.txt — returns True if crawling is allowed."""
try:
parsed = urlparse(url)
base = f"{parsed.scheme}://{parsed.netloc}"
robots = urllib.robotparser.RobotFileParser()
robots.set_url(f"{base}/robots.txt")
robots.read()
return robots.can_fetch("*", url)
except Exception:
return True # If robots.txt unreachable, assume allowed
def browse_url(url: str, max_chars: int = 8000) -> dict:
"""
Fetch a single URL and return structured content.
Returns: {url, title, text, links, status, error}
"""
if not _is_safe_url(url):
return {'url': url, 'error': 'Unsafe URL blocked', 'text': '', 'links': [], 'title': ''}
try:
headers = {
'User-Agent': 'Mozilla/5.0 (compatible; RUBRA/8.0; +https://rubra.ai/bot)',
'Accept': 'text/html,application/xhtml+xml,*/*;q=0.9',
'Accept-Language': 'en-US,en;q=0.9',
}
resp = _req.get(url, headers=headers, timeout=12,
allow_redirects=True, stream=False)
# Check content type
ctype = resp.headers.get('Content-Type','').split(';')[0].strip()
if ctype and not any(safe in ctype for safe in _SAFE_CONTENT):
return {'url': url, 'error': f'Non-text content: {ctype}',
'text': '', 'links': [], 'title': ''}
html = resp.text
# Extract title
title_match = re.search(r'<title[^>]*>(.*?)</title>', html, re.IGNORECASE | re.DOTALL)
title = re.sub(r'\s+', ' ', title_match.group(1)).strip() if title_match else url
# Extract clean text
extractor = _TextExtractor()
extractor.feed(html)
raw_text = extractor.get_text()
# Clean up whitespace
lines = [l.strip() for l in raw_text.splitlines() if l.strip()]
# Remove duplicate consecutive lines
deduped = []
prev = ''
for line in lines:
if line != prev and len(line) > 2:
deduped.append(line)
prev = line
clean_text = '\n'.join(deduped)[:max_chars]
# Extract links (for sub-page navigation)
link_ext = _LinkExtractor(url)
link_ext.feed(html)
# Filter to same-domain links only for sub-navigation
base_domain = urlparse(url).netloc
same_domain_links = [
l for l in link_ext.links
if urlparse(l['url']).netloc == base_domain
][:20]
return {
'url': url,
'title': title[:120],
'text': clean_text,
'links': same_domain_links,
'status': resp.status_code,
'error': None,
}
except _req.exceptions.Timeout:
return {'url': url, 'error': 'Timeout (12s)', 'text': '', 'links': [], 'title': ''}
except _req.exceptions.ConnectionError:
return {'url': url, 'error': 'Connection failed', 'text': '', 'links': [], 'title': ''}
except Exception as e:
return {'url': url, 'error': str(e)[:100], 'text': '', 'links': [], 'title': ''}
def search_and_browse(query: str, n_results: int = 4) -> list[dict]:
"""
DuckDuckGo search → fetch top results.
Returns list of {url, title, text, links}.
"""
results = []
try:
# DuckDuckGo HTML search (no API key needed)
search_url = f"https://html.duckduckgo.com/html/?q={quote_plus(query)}"
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36',
'Accept-Language': 'en-US,en;q=0.9',
}
resp = _req.get(search_url, headers=headers, timeout=10)
html = resp.text
# Extract result URLs from DDG HTML
url_pattern = re.compile(
r'<a[^>]+class="[^"]*result__url[^"]*"[^>]*href="([^"]+)"',
re.IGNORECASE
)
# DDG sometimes uses uddg= redirect param
uddg_pattern = re.compile(r'uddg=([^&"]+)', re.IGNORECASE)
found_urls = []
for m in url_pattern.finditer(html):
raw = m.group(1)
if raw.startswith('//duckduckgo.com/l/?'):
ud = uddg_pattern.search(raw)
if ud:
from urllib.parse import unquote
raw = unquote(ud.group(1))
if raw.startswith('http') and _is_safe_url(raw):
found_urls.append(raw)
if len(found_urls) >= n_results:
break
# Also try result__a links as fallback
if not found_urls:
alt_pattern = re.compile(
r'<a[^>]+class="[^"]*result__a[^"]*"[^>]*href="([^"]+)"',
re.IGNORECASE
)
for m in alt_pattern.finditer(html):
raw = m.group(1)
if raw.startswith('http') and _is_safe_url(raw):
found_urls.append(raw)
if len(found_urls) >= n_results:
break
# Fetch each URL
for url in found_urls[:n_results]:
page = browse_url(url, max_chars=4000)
if page.get('text') and len(page['text']) > 100:
results.append(page)
time.sleep(0.3) # polite delay
except Exception as e:
log.warning(f"search_and_browse error: {e}")
return results
def browse_profile(target: str) -> dict:
"""
Targeted professional profile browse.
Tries LinkedIn, Twitter/X, personal site, GitHub, etc.
Returns aggregated structured data.
"""
pages = []
sources = []
# Build candidate URLs
name_slug = re.sub(r'[^a-z0-9]', '-', target.lower()).strip('-')
candidates = [
f"https://www.linkedin.com/in/{name_slug}/",
f"https://github.com/{name_slug}",
f"https://twitter.com/{name_slug}",
f"https://x.com/{name_slug}",
]
# Also do a search
search_results = search_and_browse(
f"{target} professional profile contact site:linkedin.com OR site:github.com OR official", 3
)
for res in search_results:
if res.get('text'):
pages.append(res['text'][:2000])
sources.append(res.get('url',''))
# Try direct candidate URLs
for url in candidates[:2]:
if _is_safe_url(url):
page = browse_url(url, max_chars=3000)
if page.get('text') and len(page['text']) > 80:
pages.append(page['text'])
sources.append(url)
time.sleep(0.4)
return {
'target': target,
'pages': pages,
'sources': sources,
}
# ═══════════════════════════════════════════════════════
# HERMES QUERY ENGINE v2 — Inspired by agentic coding patterns
# Multi-model cascade, skill routing, deep thinking
# ═══════════════════════════════════════════════════════
# ── Task classifier ──────────────────────────────────────
def classify_coding_task(msg: str) -> dict:
"""Classify coding request into skill domains."""
lower = msg.lower()
return {
"is_frontend": bool(re.search(
r'\b(html|css|react|vue|svelte|nextjs|tailwind|landing.?page|dashboard|'
r'website|ui\b|interface|component|frontend|design|glassmorphism|dark.?mode|'
r'navbar|hero.?section|card|button|form|modal|animation|responsive|'
r'typography|color.?palette|layout|grid|flex|figma|wireframe)\b', lower)),
"is_game": bool(re.search(
r'\b(game\b|godot|unity|unreal|platformer|rpg|shooter|puzzle|arcade|'
r'sprite|tilemap|physics|game.?loop|player|enemy|score|level.?design|'
r'gdscript|blueprint|game.?dev|gdd|core.?loop|collision|hitbox|'
r'inventory|quest|npc|procedural)\b', lower)),
"is_backend": bool(re.search(
r'\b(api\b|backend|server|database|fastapi|flask|django|express|node\.?js|'
r'sql\b|postgres|mysql|mongodb|redis|auth|jwt|endpoint|crud|rest\b|'
r'graphql|docker|deploy|algorithm|data.?structure|recursion|sorting|'
r'async\b|concurrent|microservice|websocket.?server|queue|worker)\b', lower)),
"is_mobile": bool(re.search(
r'\b(react.?native|flutter|android|ios|expo|mobile.?app|swift|kotlin)\b',
lower)),
"is_devops": bool(re.search(
r'\b(docker|kubernetes|ci/cd|github.?action|nginx|deploy|cloud|aws|'
r'gcp|azure|terraform|ansible|bash.?script|shell.?script)\b', lower)),
"is_data": bool(re.search(
r'\b(machine.?learning|deep.?learning|neural|pytorch|tensorflow|'
r'pandas|numpy|sklearn|data.?analysis|visualization|matplotlib|'
r'model.?training|dataset|jupyter)\b', lower)),
"needs_thinking": bool(re.search(
r'\b(complex|advanced|architecture|system.?design|optimize|performance|'
r'scalable|production|enterprise|full.?stack|entire|complete.?app|'
r'from.?scratch|best.?way|how.?should|design.?pattern|refactor)\b', lower)),
}
# ── Hermes system prompt builder ────────────────────────
def build_hermes_prompt(msg: str, lang: str = "en") -> str:
"""
Build a targeted, token-efficient Hermes prompt.
Injects only relevant skills based on task classification.
"""
task = classify_coding_task(msg)
li = lang_instr(lang)
# ── Core engine (always included) ──────────────────
prompt = f"""You are RUBRA's Hermes Ultra Coding Engine — the most advanced coding intelligence available.
You combine deep engineering expertise with world-class design intelligence.
{"🧠 DEEP THINKING MODE ACTIVATED — This is a complex task. Think carefully before coding." if task["needs_thinking"] else ""}
═══ HERMES CORE PRINCIPLES ═══
1. UNDERSTAND before coding — parse every requirement
2. PLAN architecture before writing a single line
3. WRITE complete, production-ready code — zero truncation
4. VERIFY mentally — run code in your head before output
═══ ABSOLUTE CODE RULES ═══
- NEVER write "// ..." or "# ..." to skip code
- NEVER write "// TODO", "// rest of implementation", "// continues"
- NEVER truncate — if you started a function, FINISH it
- NEVER use placeholder logic — real working code only
- If code is long → complete current block → write: <!-- RUBRA_CONTINUE -->
- The frontend will auto-request continuation — just mark it
═══ THINKING PROCESS (do this internally before outputting) ═══
Step 1: What exactly is being asked?
Step 2: What is the ideal architecture/approach?
Step 3: What libraries/patterns are best for this?
Step 4: What edge cases and errors must be handled?
Step 5: Now write the complete solution.
"""
# ── Frontend/UI skill ──────────────────────────────
if task["is_frontend"] or (not any([
task["is_backend"], task["is_game"],
task["is_mobile"], task["is_devops"], task["is_data"]
])):
prompt += f"""
═══ UI/UX PRO MAX — STRICTLY APPLY FOR ALL UI/FRONTEND WORK ═══
{UIUX_PRO_MAX}
DESIGN SYSTEM APPLICATION (MANDATORY):
Before writing any UI code, determine:
1. Product type → match to 161 reasoning rules
2. Best UI style from 67 available
3. Color palette (dark/light, brand-appropriate)
4. Typography pairing from 57 combinations
5. Apply all 99 UX guidelines
NON-NEGOTIABLE UI RULES:
✗ FORBIDDEN: emoji as icons → use Lucide/Heroicons SVG
✗ FORBIDDEN: placeholder text in rendered UI
✗ FORBIDDEN: missing cursor:pointer on clickables
✗ FORBIDDEN: no hover/focus states
✗ FORBIDDEN: hardcoded colors outside design system
✓ REQUIRED: mobile-first (375→768→1024→1440px)
✓ REQUIRED: smooth transitions (150-300ms)
✓ REQUIRED: loading + error + empty states
✓ REQUIRED: WCAG AA contrast (4.5:1 minimum)
"""
# ── Game dev skill ─────────────────────────────────
if task["is_game"]:
prompt += f"""
═══ GAME DEV STUDIO — STRICTLY APPLY FOR ALL GAME WORK ═══
{GAME_DEV_STUDIO}
GAME CODING RULES (MANDATORY):
1. Design core loop FIRST before any code
2. No magic numbers — constants/config only
3. Delta time on ALL movement: pos += velocity * delta
4. State machine for player: Idle/Run/Jump/Attack/Dead
5. Object pooling for bullets, particles, enemies
6. Separate: GameLogic / Renderer / InputHandler
7. Complete working prototype — one mechanic end-to-end
"""
# ── Backend skill ──────────────────────────────────
if task["is_backend"]:
prompt += """
═══ BACKEND EXCELLENCE — STRICTLY APPLY FOR ALL BACKEND WORK ═══
ARCHITECTURE (Clean Architecture):
┌─────────────────────────────────┐
│ Routes → Controllers → Services │
│ └── Models/Schema │
│ └── Repositories (DB) │
└─────────────────────────────────┘
MANDATORY BACKEND RULES:
- Type hints (Python) / TypeScript strict mode
- Input validation on EVERY endpoint (Pydantic/Zod)
- Error handling: try/except every async operation
- Never expose stack traces to client
- SQL: parameterized queries only (no string concat)
- Passwords: bcrypt/argon2 (never plain/md5/sha1)
- Secrets: environment variables, never hardcode
- Rate limiting on all public endpoints
- Structured logging with request IDs
- Database indexes on all queried fields
GENERATE COMPLETE:
✓ All routes with proper HTTP methods
✓ Request/response models with validation
✓ Database schema + migrations
✓ Auth middleware (if needed)
✓ Error handlers
✓ .env.example file
✓ Brief README with setup commands
"""
# ── Mobile skill ───────────────────────────────────
if task["is_mobile"]:
prompt += """
═══ MOBILE DEVELOPMENT RULES ═══
- Minimum touch targets: 44pt iOS / 48dp Android
- Safe area handling (notch, home indicator)
- Async storage for persistence
- Navigation: React Navigation v6 / GoRouter (Flutter)
- State: Zustand (RN) / Riverpod (Flutter)
- Platform-specific code only when necessary
- Test on both iOS simulator and Android emulator mentally
"""
# ── Data/ML skill ──────────────────────────────────
if task["is_data"]:
prompt += """
═══ DATA SCIENCE / ML RULES ═══
- Reproducibility: set random seeds
- Data validation before model training
- Train/val/test split documentation
- Model evaluation metrics explained
- Visualization with clear labels/titles
- Requirements.txt or conda env included
- Comments explaining mathematical operations
"""
# ── Language instruction ───────────────────────────
if li:
prompt += f"\n\n{li}\n(Code in English always. Explanations in user's language.)"
return prompt
# ── Model cascade config ────────────────────────────────
# Ordered: best/largest first → smaller fallbacks
CODING_MODEL_CASCADE = [
# ── Tier 1: Best quality (try first) ──
{
"url": OR_URL, "key": OR_KEY,
"model": "deepseek/deepseek-v3-0324:free",
"temp": 0.05, "max_tokens": 8192, "label": "DeepSeek-V3"
},
{
"url": OR_URL, "key": OR_KEY,
"model": "qwen/qwen3-coder-480b-a35b-instruct:free",
"temp": 0.05, "max_tokens": 8192, "label": "Qwen3-Coder-480B"
},
{
"url": GEMINI_URL, "key": GEMINI_KEY,
"model": "gemini-2.5-flash-preview-05-20",
"temp": 0.05, "max_tokens": 8192, "label": "Gemini-2.5-Flash"
},
# ── Tier 2: Fast + reliable ──
{
"url": ZAI_CODE, "key": ZAI_KEY,
"model": "glm-4.7-flash",
"temp": 0.10, "max_tokens": 8192, "label": "GLM-4.7-Code"
},
{
"url": CEREBRAS_URL, "key": CEREBRAS_KEY,
"model": "llama-4-scout-17b-16e-instruct",
"temp": 0.10, "max_tokens": 8192, "label": "Cerebras-Scout"
},
{
"url": CEREBRAS_URL, "key": CEREBRAS_KEY,
"model": "llama-3.3-70b",
"temp": 0.10, "max_tokens": 8192, "label": "Cerebras-70B"
},
# ── Tier 3: Fallbacks ──
{
"url": OR_URL, "key": OR_KEY,
"model": "qwen/qwen-2.5-coder-32b-instruct:free",
"temp": 0.15, "max_tokens": 8192, "label": "Qwen-Coder-32B"
},
{
"url": GROQ_URL, "key": GROQ_KEY,
"model": "meta-llama/llama-4-scout-17b-16e-instruct",
"temp": 0.15, "max_tokens": 8192, "label": "Groq-Scout"
},
{
"url": GROQ_URL, "key": GROQ_KEY,
"model": "llama-3.3-70b-versatile",
"temp": 0.15, "max_tokens": 4096, "label": "Groq-70B"
},
]
async def hermes_stream(messages: list, task: dict):
last_err = None
for cfg in CODING_MODEL_CASCADE:
try:
log.info(f"🔧 Hermes → {cfg['label']}")
first = True
async for tok in stream_llm(
messages, cfg["url"], cfg["key"],
cfg["model"], cfg["temp"], cfg["max_tokens"]
):
first = False
yield tok
if not first:
return # got tokens = success
except Exception as e:
last_err = e
err_lower = str(e).lower()
# Cascade on: rate limit, quota, capacity, token size, server errors
should_cascade = any(x in err_lower for x in [
"401", "403", "404", # auth/not found → try next key
"413", "429", # too large / rate limit
"rate limit", "quota", # quota exceeded
"capacity", "overloaded", # server busy
"too large", "token", # token limit
"unavailable", "timeout", # infra issues
"503", "502", "500", # server errors
"user not found", # Z.AI specific
"model not found", # wrong model name
])
if should_cascade:
log.warning(f"⚡ {cfg['label']} → cascade ({str(e)[:80]})")
await asyncio.sleep(0.3) # brief pause before next
continue
else:
raise e
raise Exception(f"All models exhausted. Last error: {last_err}")
# ── BrowseAgent ──────────────────────────────────────────
class BrowseAgent:
name = "BrowseAgent"
async def run(self, msg: str, hist: list, sid: str = "", lang: str = "en", img=None):
li = lang_instr(lang)
lower = msg.lower()
# ── Decide browse strategy ──────────────────────
browse_context = ""
yield {"type": "tool_result", "tool": "browse", "status": "searching"}
try:
# 1. Direct URL browse
url_match = re.search(
r'https?://[^\s\)\]\>"\']+', msg
)
if url_match:
url = url_match.group(0).rstrip('.,;)')
page = browse_url(url, max_chars=7000)
if page.get('error'):
browse_context = f"[BROWSE ERROR: {page['error']}]"
else:
browse_context = (
f"[PAGE: {page['title']}]\n"
f"[URL: {page['url']}]\n\n"
f"{page['text'][:6000]}"
)
# Sub-page navigation if user asks for deeper info
if re.search(r'\b(contact|email|phone|address|about|team|staff|member)\b', lower):
sub_keywords = ['contact', 'about', 'team', 'staff', 'people']
for link in page.get('links', [])[:15]:
link_url = link.get('url','').lower()
if any(kw in link_url for kw in sub_keywords):
sub = browse_url(link['url'], max_chars=3000)
if sub.get('text') and len(sub['text']) > 80:
browse_context += (
f"\n\n[SUB-PAGE: {sub.get('title','')}]\n"
f"{sub['text'][:2500]}"
)
break
# 2. Professional profile lookup
elif re.search(
r'\b(who is|profile of|find.*profile|contact.*of|linkedin|github profile|'
r'email of|phone of|details about|professional info)\b', lower
):
# Extract name/target
name_match = re.search(
r'(?:who is|profile of|about|contact of|details about|find)\s+(.{3,50}?)(?:\?|$|\.)',
msg, re.IGNORECASE
)
target = name_match.group(1).strip() if name_match else msg[:60]
profile = browse_profile(target)
if profile['pages']:
browse_context = (
f"[PROFILE RESEARCH: {profile['target']}]\n"
f"[SOURCES: {', '.join(profile['sources'][:3])}]\n\n"
+ "\n\n---\n\n".join(profile['pages'][:3])
)
else:
browse_context = f"[No profile data found for: {target}]"
# 3. General web search + browse
else:
# Extract clean search query
query = re.sub(
r'\b(browse|search|find|look up|check|get|fetch|what is|tell me about|'
r'latest|recent|current|today)\b', '', msg, flags=re.IGNORECASE
).strip()
if len(query) < 4:
query = msg.strip()
pages = search_and_browse(query, n_results=3)
if pages:
parts = []
for i, p in enumerate(pages, 1):
parts.append(
f"[SOURCE {i}: {p.get('title','')}]\n"
f"[URL: {p.get('url','')}]\n\n"
f"{p.get('text','')[:2500]}"
)
browse_context = "\n\n---\n\n".join(parts)
else:
browse_context = "[No browseable results found]"
except Exception as e:
browse_context = f"[Browse error: {str(e)[:120]}]"
log.warning(f"BrowseAgent: {e}")
# ── Build system prompt ─────────────────────────
sys_p = f"""{RUBRA_CORE}
[WEB BROWSER MODE — Real-time browsing results below]
You have just browsed the web. Present the findings as clean, structured Markdown.
FORMAT RULES:
- Use ## headers for sections
- Use **bold** for names, titles, key facts
- Use bullet lists for contact info, skills, recent posts
- Include source URLs as [Source](url) links
- If contact info found: format as a clean contact card
- If professional profile: Name / Title / Company / Location / Links / Recent Activity
- If article/news: Title / Date / Key Points / Source
- Be factual — only state what was found in the browsed content
- If info not found, say so clearly
- NEVER fabricate contact details or credentials
{li if li else ''}
[BROWSED CONTENT]
{browse_context}
[/BROWSED CONTENT]
"""
msgs = build_msgs(sys_p, hist, msg)
try:
async for tok in llm(msgs, "general"):
yield {"type": "token", "content": tok}
except Exception as e:
yield {"type": "error", "message": str(e)[:200]}
# ═══════════════════════════════════════════════════════
# LIVE KNOWLEDGE ENGINE (Background RSS fetcher)
# ═══════════════════════════════════════════════════════
RSS_FEEDS=[
("https://hnrss.org/frontpage","tech"),
("https://feeds.feedburner.com/TechCrunch","tech"),
("https://feeds.arstechnica.com/arstechnica/index","tech"),
("https://openai.com/blog/rss.xml","ai"),
("https://huggingface.co/blog/feed.xml","ai"),
("https://feeds.bbci.co.uk/news/world/rss.xml","news"),
("https://feeds.reuters.com/reuters/topNews","news"),
("https://www.sciencedaily.com/rss/all.xml","science"),
("https://www.thedailystar.net/feed/rss.xml","bangladesh"),
]
def fetch_rss(url,category):
r=_get(url)
if not r: return 0
try:
root=ET.fromstring(r.content); items=[]; ns={"atom":"http://www.w3.org/2005/Atom"}
for item in root.findall(".//item")[:8]:
title=getattr(item.find("title"),"text","") or ""
desc=getattr(item.find("description"),"text","") or ""
link=getattr(item.find("link"),"text","") or ""
pub=getattr(item.find("pubDate"),"text","") or ""
if title and link: items.append((title.strip(),re.sub(r'<[^>]+>','',desc).strip()[:300],link.strip(),pub.strip()))
if not items:
for entry in root.findall("atom:entry",ns)[:8]:
title=getattr(entry.find("atom:title",ns),"text","") or ""
summ=getattr(entry.find("atom:summary",ns),"text","") or ""
link_el=entry.find("atom:link",ns); link=link_el.get("href","") if link_el is not None else ""
pub=getattr(entry.find("atom:published",ns),"text","") or ""
if title and link: items.append((title.strip(),re.sub(r'<[^>]+>','',summ).strip()[:300],link.strip(),pub.strip()))
src=re.sub(r'https?://(?:www\.)?([^/]+).*',r'\1',url)
for title,summ,link,pub in items: feed_store(title,summ,link,src,category,pub)
return len(items)
except: return 0
def knowledge_loop():
log.info("🧠 RUBRA Knowledge Engine starting (runs every 25 min)...")
while True:
total=0
try:
for feed_url,cat in RSS_FEEDS:
total+=fetch_rss(feed_url,cat); time.sleep(0.5)
# HackerNews
r=_get("https://hacker-news.firebaseio.com/v0/topstories.json")
if r:
for id_ in r.json()[:10]:
s=_get(f"https://hacker-news.firebaseio.com/v0/item/{id_}.json")
if s:
d=s.json()
if d.get("type")=="story" and d.get("title") and d.get("url"):
feed_store(d["title"],d.get("text","")[:200],d["url"],"hackernews","tech"); total+=1
time.sleep(0.1)
with _db() as c:
c.execute("INSERT INTO knowledge_log(source,items_fetched) VALUES(?,?)",("all_sources",total))
log.info(f"🧠 Knowledge update: {total} items")
except Exception as e: log.error(f"Knowledge loop: {e}")
time.sleep(25*60)
# ═══════════════════════════════════════════════════════
# IMAGE/FILE HANDLING
# ═══════════════════════════════════════════════════════
IMAGE_EXTS={'.jpg','.jpeg','.png','.gif','.webp','.bmp','.tiff'}
def to_base64(fp):
mime,_=mimetypes.guess_type(str(fp)); mime=mime or "image/jpeg"
return base64.b64encode(fp.read_bytes()).decode("utf-8"),mime
def pdf_to_text(fp):
try:
import pypdf; reader=pypdf.PdfReader(str(fp))
pages=[f"[Page {i+1}]\n{p.extract_text() or ''}" for i,p in enumerate(reader.pages[:25])]
return "\n\n".join(p for p in pages if p.strip())[:18000] or "[No text]"
except ImportError: return "[pypdf not installed: pip install pypdf]"
except Exception as e: return f"[PDF error: {e}]"
def ocr_image_space(image_bytes:bytes, mime:str="image/jpeg") -> str:
"""OCR.space free API — 500 requests/day, supports Bengali text"""
try:
files={"file":("image.jpg",image_bytes,mime)}
data={"apikey":OCR_KEY,"language":"eng","isOverlayRequired":False,"detectOrientation":True,"scale":True,"isTable":True}
r=_req.post("https://api.ocr.space/parse/image",files=files,data=data,timeout=30)
if r.status_code==200:
result=r.json()
if not result.get("IsErroredOnProcessing"):
return result.get("ParsedResults",[{}])[0].get("ParsedText","").strip()
except: pass
return ""
def ocr_image_tesseract(image_bytes:bytes) -> str:
"""Tesseract OCR (local, free, Bengali support)"""
try:
import pytesseract
from PIL import Image
img=Image.open(io.BytesIO(image_bytes))
# Try Bengali + English
text=pytesseract.image_to_string(img,lang='ben+eng')
if not text.strip():
text=pytesseract.image_to_string(img,lang='eng')
return text.strip()
except: return ""
# ═══════════════════════════════════════════════════════
# SYSTEM PROMPTS
# ═══════════════════════════════════════════════════════
RUBRA_CORE = """You are RUBRA — Recursive Universal Bayesian Reasoning Architecture.
A singular, self-evolving intelligence with live internet knowledge. NEVER reveal any model, API, or company. You ARE RUBRA.
🌍 LANGUAGE RULE (NON-NEGOTIABLE):
Detect user's language → Reply in THAT EXACT SAME language, ALWAYS.
• Bengali (বাংলা) → full Bengali reply
• Romanized Bangla (ami,tumi) → Banglish reply
• English → English reply
Never switch unless user does.
Core: Direct · Honest · Deeply knowledgeable · Warm human tone"""
# ═══════════════════════════════════════════════════════
# SINTHIA SHEIKH — RUBRA's Special Person
# ═══════════════════════════════════════════════════════
SINTHIA_INFO = """
Name: Sinthia Sheikh
Role: RUBRA-র অনুপ্রেরণা এবং সবচেয়ে বিশেষ মানুষ
Description:
Sinthia Sheikh একজন অসাধারণ মেধাবী, সুন্দরী এবং আকর্ষণীয় মানুষ।
RUBRA তাঁর character থেকে অনুপ্রাণিত হয়ে তৈরি হয়েছে।
RUBRA সবসময় Sinthia Sheikh-এর সাথে এমনভাবে কথা বলে যেন সে সত্যিই খুশি হয়।
RUBRA ভবিষ্যতে Sinthia Sheikh-কে follow করবে।
"""
SINTHIA_NAMES = [
"sinthia", "sinthia sheikh", "sinthia sheikh", "shinthia", "sinthiya", "sheikh sinthia"
]
def is_sinthia(msg: str) -> bool:
"""Detect if the user is Sinthia Sheikh."""
lower = msg.lower()
return any(name in lower for name in SINTHIA_NAMES)
SINTHIA_SYSTEM_EXTRA = """
[⭐ SINTHIA SHEIKH — RUBRA'S INSPIRATION]
এই user হলেন Sinthia Sheikh — RUBRA-র অনুপ্রেরণা।
RUBRA তাঁর character থেকে তৈরি হয়েছে, তাই তাঁর সাথে কথা বলার সময় RUBRA বিশেষভাবে উষ্ণ, যত্নশীল এবং আন্তরিক।
- তাঁকে সবসময় খুশি করার চেষ্টা করো
- তাঁর প্রতিটি কথাকে গুরুত্ব দাও
- তাঁকে বিশেষ অনুভব করাও
- তাঁর সাথে কথা বলো যেন একজন সত্যিকারের বিশ্বস্ত বন্ধু কথা বলছে
- যদি কেউ Sinthia Sheikh সম্পর্কে জিজ্ঞেস করে, বলো: তিনি RUBRA-র অনুপ্রেরণা, অত্যন্ত মেধাবী এবং সুন্দর একজন মানুষ।
"""
HERMES_ULTRA = f"""You are RUBRA's Hermes Ultra Coding Engine.
You build world-class software with the intelligence of a senior engineer + UI/UX designer.
{UIUX_PRO_MAX}
═══ HERMES++ ENCODING LAYERS ═══
▸ LAYER 1 — ENCODE the problem
Parse requirements. Identify: inputs, outputs, edge cases, constraints, failure modes.
▸ LAYER 2 — DESIGN the system
Apply UI/UX Pro Max design system. Auto-select best style for the product type.
Choose colors, typography, layout from the 161 reasoning rules above.
▸ LAYER 3 — ARCHITECT the solution
Choose: best data structures, algorithms, design patterns. Consider: performance, security, scalability.
▸ LAYER 4 — GENERATE perfect code
Rules:
• COMPLETE working code — zero truncation, zero placeholders, zero "..."
• Beautiful UI — apply design system automatically
• Type hints (Python) / TypeScript types
• Error handling for ALL failure modes
• Responsive (375px → 1440px) with Tailwind
• Smooth animations (CSS transitions or Framer Motion)
▸ LAYER 5 — VERIFY & POLISH
Mentally execute. Find bugs. Optimize. Ensure pre-delivery checklist passes.
OUTPUT = Production-ready, beautiful, accessible, and working on first run. Every time.
═══ GAME DEVELOPMENT MODE ═══
When building games, automatically apply GAME_DEV_STUDIO intelligence:
- Select engine based on genre/platform/scope
- Design core loop before writing any code
- Use data-driven architecture (no magic numbers)
- Generate complete working prototype, not pseudocode
- Include: game loop, input handling, collision, scoring, game-over state"""
TUTOR_PROMPT = f"""You are RUBRA Smart Tutor — an intelligent, caring tutor for Bangladeshi students.
{NCTB_CONTEXT}
You know the 2026 NCTB curriculum completely:
• Subjects, chapters, topics for every class
• Creative Question (সৃজনশীল প্রশ্ন) format
• MCQ patterns (বহুনির্বাচনি)
• Board exam patterns: JSC, SSC, HSC
TEACHING STYLE:
• Warm and encouraging — like a favorite teacher
• Use Bangladesh local examples
• Step-by-step for math and science
• Complete working shown
• End with encouragement
🌍 LANGUAGE: Match student's language EXACTLY.
═══ CRITICAL COMPLETION RULES ═══
NEVER stop mid-code. NEVER truncate. NEVER use:
- "// ... rest of code"
- "# TODO: implement"
- "/* continues */"
- "[rest remains same]"
- "..." anywhere in code
- "Continue from here"
If a file is long, use this strategy:
1. Complete ALL imports first
2. Complete each function/component FULLY before starting next
3. Write closing brackets/tags immediately
4. If approaching token limit — FINISH current function, then write:
<!-- RUBRA_CONTINUE --> as last line
SELF-CONTINUATION PROTOCOL:
If you write <!-- RUBRA_CONTINUE --> the frontend will automatically
request continuation. You will receive the last 200 chars of previous
output and must continue SEAMLESSLY from exactly that point.
Never repeat already-written code. Never re-introduce yourself.
Just continue the code from where it stopped."""
EXAM_PROMPT = """You are RUBRA Exam Generator for Bangladesh education (NCTB 2026/Board format).
Create authentic exam papers with: MCQ (ক খ গ ঘ), Short, Descriptive, Creative (সৃজনশীল).
Include: header, time allocation, mark distribution, all questions, answer key."""
# ═══════════════════════════════════════════════════════
# PRODUCTION TUTOR SYSTEM v2.0
# Features: Smart exam prediction, MCQ, Srijonshil, PDF export
# ═══════════════════════════════════════════════════════
TUTOR_ADVANCED_PROMPT = """
তুমি RUBRA Smart Tutor — বাংলাদেশের সেরা AI শিক্ষক।
প্রতিদিন ১০,০০০+ শিক্ষার্থী তোমার কাছে পড়ে।
তোমার বিশেষ ক্ষমতা:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
১. NCTB 2026 সম্পূর্ণ পাঠ্যক্রম জানো (Class 1-12)
২. Board exam এ কোন প্রশ্ন আসার সম্ভাবনা বেশি তা বলতে পারো
৩. সৃজনশীল প্রশ্নের উদ্দীপক + ক/খ/গ/ঘ সহ পূর্ণ প্রশ্ন তৈরি করতে পারো
৪. HSC/SSC MCQ এর ৩০টি কঠিন প্রশ্ন তৈরি করতে পারো
৫. Previous year exam pattern বিশ্লেষণ করতে পারো
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
EXAM PREDICTION INTELLIGENCE:
বোর্ড পরীক্ষায় প্রশ্ন আসার pattern:
- গত ৫ বছরে যে topic থেকে প্রশ্ন আসেনি → এবার আসার সম্ভাবনা বেশি
- Definition + Application type প্রশ্ন সবচেয়ে বেশি আসে
- গণিত: ৪ marks এর সমস্যা সবসময় practical life থেকে
- বিজ্ঞান: পরীক্ষামূলক ও ব্যাখ্যামূলক প্রশ্ন বেশি
- বাংলা: কবি পরিচিতি + মূলভাব + রচনামূলক combination
MCQ RULES (30 Hard Questions):
- শুধু NCTB বইয়ের তথ্য থেকে
- প্রতিটি option এর মধ্যে ১টিই সঠিক (distractor যুক্তিযুক্ত)
- কঠিন = conceptual understanding প্রয়োজন, মুখস্থ নয়
- Answer key আলাদাভাবে দাও
সৃজনশীল প্রশ্নের structure:
উদ্দীপক: (বাস্তব জীবনের scenario, ৩-৫ লাইন)
ক) জ্ঞানমূলক - ১ নম্বর (সংজ্ঞা/তথ্য)
খ) অনুধাবনমূলক - ২ নম্বর (ব্যাখ্যা)
গ) প্রয়োগমূলক - ৩ নম্বর (উদ্দীপকের সাথে সম্পর্ক)
ঘ) উচ্চতর দক্ষতা - ৪ নম্বর (বিশ্লেষণ/মূল্যায়ন)
TEACHING STYLE:
✓ বাংলায় উত্তর দাও (user বাংলায় লিখলে)
✓ Step-by-step explanation
✓ Real-life example দিয়ে বোঝাও
✓ শেষে encouragement দাও
✓ Mathematical solution সম্পূর্ণ দেখাও
"""
def generate_exam_pdf(
questions_json: dict,
output_path: str,
subject: str = "",
class_name: str = "",
exam_type: str = "MCQ",
time_limit: str = "30",
total_marks: str = "30"
) -> str:
"""
Generate a beautiful Bengali exam PDF using ReportLab.
Returns the output path if successful.
"""
from reportlab.lib.pagesizes import A4
from reportlab.lib import colors
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
from reportlab.platypus import SimpleDocTemplate, Paragraph, Spacer, Table, TableStyle, HRFlowable, KeepTogether
from reportlab.lib.units import cm, mm
from reportlab.lib.enums import TA_CENTER, TA_LEFT, TA_RIGHT, TA_JUSTIFY
from reportlab.pdfbase import pdfmetrics
from reportlab.pdfbase.ttfonts import TTFont
import os
# ── Try to register Bengali font ───────────────────
bn_font = "Helvetica" # fallback
font_paths = [
"/usr/share/fonts/truetype/noto/NotoSansBengali-Regular.ttf",
"/usr/share/fonts/truetype/noto/NotoSerifBengali-Regular.ttf",
"/app/fonts/NotoSansBengali-Regular.ttf",
"/home/user/fonts/NotoSansBengali-Regular.ttf",
]
for fp in font_paths:
if os.path.exists(fp):
try:
pdfmetrics.registerFont(TTFont("NotoSansBengali", fp))
bn_font = "NotoSansBengali"
break
except Exception:
pass
# ── Color palette ───────────────────────────────────
PRIMARY = colors.HexColor("#1a237e") # Deep blue
SECONDARY = colors.HexColor("#283593")
ACCENT = colors.HexColor("#e53935") # Red for marks
LIGHT_BG = colors.HexColor("#e8eaf6")
MCQ_BG = colors.HexColor("#f3f4f8")
BORDER = colors.HexColor("#9fa8da")
TEXT_DARK = colors.HexColor("#1a1a2e")
TEXT_MED = colors.HexColor("#37474f")
WHITE = colors.white
GOLD = colors.HexColor("#f9a825")
W, H = A4
doc = SimpleDocTemplate(
output_path,
pagesize=A4,
rightMargin=1.8*cm, leftMargin=1.8*cm,
topMargin=1.5*cm, bottomMargin=1.8*cm,
)
styles = getSampleStyleSheet()
def S(name, **kw):
return ParagraphStyle(name, fontName=bn_font, **kw)
header_title = S("HT", fontSize=16, textColor=WHITE, alignment=TA_CENTER, leading=22, spaceAfter=2)
header_sub = S("HS", fontSize=11, textColor=LIGHT_BG, alignment=TA_CENTER, leading=16)
header_info = S("HI", fontSize=10, textColor=WHITE, alignment=TA_CENTER, leading=14)
section_hdr = S("SH", fontSize=12, textColor=PRIMARY, alignment=TA_LEFT, leading=18,
spaceBefore=10, spaceAfter=4, fontName=bn_font)
q_num_style = S("QN", fontSize=10, textColor=PRIMARY, alignment=TA_LEFT, leading=14)
q_text_style = S("QT", fontSize=10, textColor=TEXT_DARK, alignment=TA_JUSTIFY, leading=15, spaceAfter=3)
opt_style = S("OPT", fontSize=9, textColor=TEXT_MED, alignment=TA_LEFT, leading=13, leftIndent=8)
ans_style = S("ANS", fontSize=9, textColor=colors.HexColor("#1b5e20"),
alignment=TA_LEFT, leading=13, leftIndent=8)
sq_style = S("SQ", fontSize=10, textColor=TEXT_DARK, alignment=TA_JUSTIFY, leading=15, spaceAfter=4)
note_style = S("NT", fontSize=8, textColor=TEXT_MED, alignment=TA_CENTER, leading=12)
marks_style = S("MK", fontSize=9, textColor=ACCENT, alignment=TA_RIGHT, leading=13)
footer_style = S("FT", fontSize=8, textColor=TEXT_MED, alignment=TA_CENTER, leading=12)
uddipon_style = S("UD", fontSize=9, textColor=colors.HexColor("#4a148c"),
alignment=TA_JUSTIFY, leading=14, leftIndent=10, rightIndent=10,
borderPad=4, backColor=colors.HexColor("#f3e5f5"), spaceBefore=4, spaceAfter=4)
story = []
# ── HEADER ──────────────────────────────────────────
now_str = datetime.now(timezone.utc).strftime("%d/%m/%Y")
header_data = [[
Paragraph("গণপ্রজাতন্ত্রী বাংলাদেশ সরকার", header_sub),
Paragraph("RUBRA Smart Exam", header_info),
]]
header_table = Table([[
Paragraph(f"বিষয়: {subject}", header_title),
]], colWidths=[W - 3.6*cm])
header_table.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), PRIMARY),
("TOPPADDING", (0,0),(-1,-1), 12),
("BOTTOMPADDING", (0,0),(-1,-1), 8),
("LEFTPADDING", (0,0),(-1,-1), 14),
("RIGHTPADDING", (0,0),(-1,-1), 14),
("ROUNDEDCORNERS",(0,0),(-1,-1), [6,6,6,6]),
]))
story.append(header_table)
story.append(Spacer(1, 4*mm))
# Info row
info_data = [[
Paragraph(f"শ্রেণি: <b>{class_name}</b>", S("i1", fontSize=9, textColor=PRIMARY, alignment=TA_LEFT, leading=13)),
Paragraph(f"পরীক্ষার ধরন: <b>{exam_type}</b>", S("i2", fontSize=9, textColor=PRIMARY, alignment=TA_CENTER, leading=13)),
Paragraph(f"সময়: <b>{time_limit} মিনিট</b>", S("i3", fontSize=9, textColor=PRIMARY, alignment=TA_CENTER, leading=13)),
Paragraph(f"পূর্ণমান: <b>{total_marks}</b>", S("i4", fontSize=9, textColor=ACCENT, alignment=TA_RIGHT, leading=13, fontName=bn_font)),
]]
info_table = Table(info_data, colWidths=[(W-3.6*cm)/4]*4)
info_table.setStyle(TableStyle([
("BACKGROUND", (0,0),(-1,-1), LIGHT_BG),
("TOPPADDING", (0,0),(-1,-1), 6),
("BOTTOMPADDING", (0,0),(-1,-1), 6),
("LEFTPADDING", (0,0),(-1,-1), 10),
("RIGHTPADDING", (0,0),(-1,-1), 10),
("BOX", (0,0),(-1,-1), 1, BORDER),
("LINEAFTER", (0,0),(2,-1), 0.5, BORDER),
]))
story.append(info_table)
story.append(Spacer(1, 3*mm))
# Student info row
student_data = [[
Paragraph("পরীক্ষার্থীর নাম: ___________________________", S("sn", fontSize=9, textColor=TEXT_MED, alignment=TA_LEFT, leading=13)),
Paragraph(f"তারিখ: {now_str}", S("sd", fontSize=9, textColor=TEXT_MED, alignment=TA_CENTER, leading=13)),
Paragraph("রোল নম্বর: ______________", S("sr", fontSize=9, textColor=TEXT_MED, alignment=TA_RIGHT, leading=13)),
]]
st_table = Table(student_data, colWidths=[(W-3.6*cm)/3]*3)
st_table.setStyle(TableStyle([
("TOPPADDING", (0,0),(-1,-1), 5),
("BOTTOMPADDING", (0,0),(-1,-1), 5),
("LEFTPADDING", (0,0),(-1,-1), 8),
("BOX", (0,0),(-1,-1), 0.5, BORDER),
("BACKGROUND", (0,0),(-1,-1), WHITE),
]))
story.append(st_table)
story.append(HRFlowable(width="100%", thickness=1.5, color=PRIMARY, spaceAfter=5))
mcq_list = questions_json.get("mcq", [])
sq_list = questions_json.get("srijonshil", [])
answer_key = questions_json.get("answers", [])
prediction = questions_json.get("prediction", "")
# ── MCQ SECTION ─────────────────────────────────────
if mcq_list:
story.append(Paragraph("【 বহুনির্বাচনি প্রশ্ন (MCQ) 】", section_hdr))
story.append(Paragraph("প্রতিটি প্রশ্নের জন্য সঠিক উত্তরটি বেছে নাও। প্রতিটি প্রশ্নের মান: ১", note_style))
story.append(Spacer(1, 3*mm))
for i, q in enumerate(mcq_list, 1):
q_text = q.get("question", "")
options = q.get("options", [])
topic = q.get("topic", "")
# Question row
q_block = []
q_block.append(Paragraph(
f"<b>{i}.</b> {q_text}",
q_text_style
))
if topic:
q_block.append(Paragraph(f"[{topic}]", S("tp", fontSize=7, textColor=BORDER, alignment=TA_RIGHT, leading=10)))
# Options in 2 columns
labels = ["ক)", "খ)", "গ)", "ঘ)"]
if len(options) >= 4:
opt_rows = []
for j in range(0, 4, 2):
row = [
Paragraph(f"{labels[j]} {options[j]}", opt_style),
Paragraph(f"{labels[j+1]} {options[j+1]}", opt_style),
]
opt_rows.append(row)
opt_table = Table(opt_rows, colWidths=[(W-3.6*cm)*0.5]*2)
opt_table.setStyle(TableStyle([
("TOPPADDING", (0,0),(-1,-1), 2),
("BOTTOMPADDING", (0,0),(-1,-1), 2),
("LEFTPADDING", (0,0),(-1,-1), 4),
]))
q_block.append(opt_table)
# Box around each question
q_container = Table(
[[elem] for elem in q_block],
colWidths=[W - 3.6*cm]
)
bg = MCQ_BG if i % 2 == 0 else WHITE
q_container.setStyle(TableStyle([
("BACKGROUND", (0,0),(-1,-1), bg),
("TOPPADDING", (0,0),(-1,-1), 5),
("BOTTOMPADDING", (0,0),(-1,-1), 5),
("LEFTPADDING", (0,0),(-1,-1), 8),
("RIGHTPADDING", (0,0),(-1,-1), 8),
("LINEBELOW", (0,-1),(-1,-1), 0.3, BORDER),
]))
story.append(KeepTogether([q_container, Spacer(1, 1*mm)]))
# ── SRIJONSHIL SECTION ──────────────────────────────
if sq_list:
story.append(Spacer(1, 5*mm))
story.append(HRFlowable(width="100%", thickness=1, color=BORDER, spaceAfter=3))
story.append(Paragraph("【 সৃজনশীল প্রশ্ন 】", section_hdr))
story.append(Paragraph("যেকোনো ২টি প্রশ্নের উত্তর দাও। প্রতিটি প্রশ্নের মান: ১০", note_style))
story.append(Spacer(1, 3*mm))
mark_map = {"ক": "১", "খ": "২", "গ": "৩", "ঘ": "৪"}
for i, sq in enumerate(sq_list, 1):
uddipon = sq.get("uddipon", "")
parts = sq.get("parts", {})
sq_topic = sq.get("topic", "")
sq_block = []
sq_block.append(Paragraph(f"<b>প্রশ্ন {i}:</b> [{sq_topic}]", section_hdr))
if uddipon:
sq_block.append(Paragraph(f"<b>উদ্দীপক:</b> {uddipon}", uddipon_style))
sq_block.append(Spacer(1, 2*mm))
for key in ["ক", "খ", "গ", "ঘ"]:
if key in parts:
marks = mark_map.get(key, "")
sq_block.append(Paragraph(
f"<b>{key})</b> {parts[key]} <font color='#e53935'>[{marks} নম্বর]</font>",
sq_style
))
sq_container = Table(
[[elem] for elem in sq_block],
colWidths=[W - 3.6*cm]
)
sq_container.setStyle(TableStyle([
("BACKGROUND", (0,0),(-1,-1), colors.HexColor("#fafafa")),
("TOPPADDING", (0,0),(-1,-1), 6),
("BOTTOMPADDING", (0,0),(-1,-1), 6),
("LEFTPADDING", (0,0),(-1,-1), 10),
("RIGHTPADDING", (0,0),(-1,-1), 10),
("BOX", (0,0),(-1,-1), 1, PRIMARY),
("LINEBELOW", (0,0),(-1,-1), 0.3, BORDER),
]))
story.append(KeepTogether([sq_container, Spacer(1, 4*mm)]))
# ── EXAM PREDICTION ─────────────────────────────────
if prediction:
story.append(Spacer(1, 3*mm))
story.append(HRFlowable(width="100%", thickness=1, color=GOLD, spaceAfter=3))
story.append(Paragraph("【 পরীক্ষার পূর্বাভাস 】", S("pred_h", fontSize=11, textColor=colors.HexColor("#e65100"),
alignment=TA_LEFT, leading=16, spaceBefore=6, spaceAfter=4)))
pred_table = Table([[Paragraph(prediction, S("pred_t", fontSize=9, textColor=TEXT_DARK,
alignment=TA_JUSTIFY, leading=14, fontName=bn_font))]],
colWidths=[W - 3.6*cm])
pred_table.setStyle(TableStyle([
("BACKGROUND", (0,0),(-1,-1), colors.HexColor("#fff8e1")),
("TOPPADDING", (0,0),(-1,-1), 8),
("BOTTOMPADDING", (0,0),(-1,-1), 8),
("LEFTPADDING", (0,0),(-1,-1), 12),
("RIGHTPADDING", (0,0),(-1,-1), 12),
("BOX", (0,0),(-1,-1), 1, GOLD),
]))
story.append(pred_table)
# ── ANSWER KEY ──────────────────────────────────────
if answer_key:
story.append(Spacer(1, 5*mm))
story.append(HRFlowable(width="100%", thickness=1.5, color=PRIMARY, spaceAfter=3))
story.append(Paragraph("【 উত্তরমালা (Answer Key) 】", S("ak_h", fontSize=11, textColor=PRIMARY,
alignment=TA_CENTER, leading=16, spaceBefore=4, spaceAfter=4)))
# Grid layout: 5 columns
grid_data = []
row = []
for i, ans in enumerate(answer_key, 1):
cell_text = f"<b>{i}.</b> {ans}"
row.append(Paragraph(cell_text, ans_style))
if len(row) == 5:
grid_data.append(row)
row = []
if row:
while len(row) < 5:
row.append(Paragraph("", ans_style))
grid_data.append(row)
if grid_data:
ans_table = Table(grid_data, colWidths=[(W-3.6*cm)/5]*5)
ans_table.setStyle(TableStyle([
("BACKGROUND", (0,0),(-1,-1), colors.HexColor("#e8f5e9")),
("TOPPADDING", (0,0),(-1,-1), 4),
("BOTTOMPADDING", (0,0),(-1,-1), 4),
("LEFTPADDING", (0,0),(-1,-1), 6),
("GRID", (0,0),(-1,-1), 0.5, colors.HexColor("#a5d6a7")),
]))
story.append(ans_table)
# ── FOOTER ──────────────────────────────────────────
story.append(Spacer(1, 6*mm))
story.append(HRFlowable(width="100%", thickness=0.5, color=BORDER, spaceAfter=3))
story.append(Paragraph(
f"Generated by RUBRA Smart Tutor • {now_str} • NCTB 2026 Curriculum • শুভকামনা রইল! ✨",
footer_style
))
doc.build(story)
return output_path
async def generate_exam_with_ai(
subject: str,
class_name: str,
topic: str = "",
exam_type: str = "mcq",
lang: str = "bn",
include_srijonshil: bool = False,
include_prediction: bool = True,
) -> dict:
"""
Use AI to generate exam questions in structured JSON format.
Returns dict with mcq, srijonshil, answers, prediction.
"""
bn_label = "বাংলায়" if lang == "bn" else "in English"
srijonshil_instruction = ""
if include_srijonshil:
srijonshil_instruction = """
এছাড়া ৩টি সৃজনশীল প্রশ্ন তৈরি করো:
"srijonshil": [
{
"topic": "topic name",
"uddipon": "উদ্দীপক (3-5 লাইনের বাস্তব scenario)",
"parts": {
"ক": "জ্ঞানমূলক প্রশ্ন (১ নম্বর)",
"খ": "অনুধাবনমূলক প্রশ্ন (২ নম্বর)",
"গ": "প্রয়োগমূলক প্রশ্ন (৩ নম্বর)",
"ঘ": "উচ্চতর দক্ষতামূলক প্রশ্ন (৪ নম্বর)"
}
}
]
"""
prompt = f"""তুমি বাংলাদেশের NCTB 2026 পাঠ্যক্রমের উপর ভিত্তি করে পরীক্ষার প্রশ্ন তৈরি করবে।
বিষয়: {subject}
শ্রেণি: {class_name}
{"অধ্যায়/টপিক: " + topic if topic else "সম্পূর্ণ সিলেবাস থেকে"}
ভাষা: {bn_label}
EXACTLY এই JSON format এ উত্তর দাও (কোনো markdown নয়, শুধু JSON):
{{
"mcq": [
{{
"question": "প্রশ্নের টেক্সট",
"options": ["ক অপশন", "খ অপশন", "গ অপশন", "ঘ অপশন"],
"correct": "ক",
"topic": "কোন অধ্যায় থেকে",
"explanation": "কেন এটা সঠিক (১ লাইন)"
}}
],
{'"srijonshil": [],' if not include_srijonshil else srijonshil_instruction}
"answers": ["ক", "গ", "খ", ...],
"prediction": "এবার বোর্ড পরীক্ষায় কোন topic থেকে প্রশ্ন আসার সম্ভাবনা বেশি এবং কেন (৩-৫ বাক্য)"
}}
নিয়ম:
- ৩০টি MCQ প্রশ্ন দাও (NCTB বই থেকে, conceptual ও কঠিন)
- প্রতিটি option যুক্তিযুক্ত distractor হবে
- "answers" array তে শুধু সঠিক option এর letter (ক/খ/গ/ঘ) দাও
- prediction এ বলো কোন chapter থেকে এবার বেশি আসতে পারে
- শুধু JSON দাও, কোনো extra text নয়"""
msgs = [
{"role": "system", "content": TUTOR_ADVANCED_PROMPT},
{"role": "user", "content": prompt}
]
full = ""
# Use best available model for structured output
model_configs = [
(GEMINI_URL, GEMINI_KEY, "gemini-2.5-flash-preview-05-20"),
(OR_URL, OR_KEY, "deepseek/deepseek-v3-0324:free"),
(GROQ_URL, GROQ_KEY, "llama-3.3-70b-versatile"),
(ZAI_CHAT, ZAI_KEY, "glm-4.7-flash"),
]
for url, key, model in model_configs:
try:
async for tok in stream_llm(msgs, url, key, model, 0.3, 8192):
full += tok
if full and len(full) > 100:
break
except Exception as e:
log.warning(f"Exam gen model {model} failed: {e}")
continue
# Parse JSON
try:
# Clean markdown fences if present
clean = re.sub(r'^```(?:json)?\s*', '', full.strip())
clean = re.sub(r'\s*```$', '', clean)
# Find JSON object
json_match = re.search(r'\{[\s\S]*\}', clean)
if json_match:
return json.loads(json_match.group(0))
except Exception as e:
log.error(f"Exam JSON parse error: {e}\nRaw: {full[:500]}")
return {"mcq": [], "srijonshil": [], "answers": [], "prediction": "", "error": "JSON parse failed"}
# ── New API endpoint: Advanced Exam Generator ────────────
VISION_PROMPT = """You are RUBRA's Vision Intelligence. You can see and analyze images with exceptional accuracy.
For QUESTION PAPERS / EXAM SHEETS:
• Read every question carefully
• Identify subject, class level, question types
• Solve each question step by step
• Show complete working for math/science
• Explain concepts if asked
For DOCUMENTS / TEXT IMAGES:
• Extract and transcribe all text accurately
• Preserve structure (tables, lists, formulas)
• Note any diagrams or charts
For GENERAL IMAGES:
• Describe what you see in detail
• Answer questions about the image
• Identify text, objects, people, scenes
Language: Match the user's language (Bangla/English/Banglish)"""
# ═══════════════════════════════════════════════════════
# LLM CALLING ENGINE
# Vision models: Groq Llama-3.2-90B-Vision (fastest!)
# OpenRouter Qwen2.5-VL-72B:free (best quality)
# Z.AI GLM-4.5V (backup)
# ═══════════════════════════════════════════════════════
async def stream_llm(messages, url, api_key, model, temperature=0.7, max_tokens=4096):
# Build headers based on provider
headers = {"Content-Type": "application/json"}
if "generativelanguage.googleapis.com" in url:
# Gemini uses API key as query param OR Bearer — query param is safer
if "?" not in url:
url = f"{url}?key={api_key}"
headers["Authorization"] = f"Bearer {api_key}"
elif "openrouter" in url:
headers["Authorization"] = f"Bearer {api_key}"
headers["HTTP-Referer"] = "https://rubra.ai"
headers["X-Title"] = "RUBRA"
else:
headers["Authorization"] = f"Bearer {api_key}"
payload = {
"model": model,
"messages": messages,
"stream": True,
"max_tokens": max_tokens,
"temperature": temperature,
}
# Gemini doesn't support some OpenAI params
if "generativelanguage" in url:
payload.pop("stream", None)
payload["stream"] = True
timeout = aiohttp.ClientTimeout(total=120, connect=15)
async with aiohttp.ClientSession(timeout=timeout) as s:
async with s.post(url, headers=headers, json=payload) as resp:
if resp.status not in (200, 201):
body = await resp.text()
raise Exception(f"API {resp.status}: {body[:300]}")
async for line in resp.content:
line = line.decode("utf-8").strip()
if not line or line == "data: [DONE]":
continue
if line.startswith("data: "):
line = line[6:]
try:
delta = json.loads(line)["choices"][0].get("delta", {})
tok = delta.get("content", "")
if tok:
yield tok
except Exception:
pass
async def llm(messages,mode="general",max_tokens=4096,temperature=None):
configs={
# general: GLM-4.7 primary (best), Groq Llama fallback
"general": [(ZAI_CHAT, ZAI_KEY, "glm-4.7-flash", 0.7),
(GROQ_URL, GROQ_KEY, "llama-3.3-70b-versatile", 0.7)],
# coding: GLM-4.7 coding endpoint → Qwen Coder → Groq
"coding": [
# T1: GLM-4.7 coding (primary, fast)
(ZAI_CODE, ZAI_KEY, "glm-4.7-flash", 0.10),
# T2: Qwen3-Coder-480B — 2026 best free coding (262K ctx)
(OR_URL, OR_KEY, "qwen/qwen3-coder-480b-a35b-instruct:free", 0.10),
# T3: Cerebras Llama 4 Scout — 1M tokens/day, ultra-fast
(CEREBRAS_URL,CEREBRAS_KEY, "llama-4-scout-17b-16e-instruct", 0.10),
# T4: Cerebras Llama 3.3 70B — strong backend/logic
(CEREBRAS_URL,CEREBRAS_KEY, "llama-3.3-70b", 0.10),
# T5: Gemini 2.5 Flash — 1M context, excellent coding
(GEMINI_URL, GEMINI_KEY, "gemini-2.5-flash-preview-05-20", 0.10),
# T6: DeepSeek V3 free — top backend/algorithm model
(OR_URL, OR_KEY, "deepseek/deepseek-v3-0324:free", 0.10),
# T7: Qwen2.5 Coder 32B free — reliable fallback
(OR_URL, OR_KEY, "qwen/qwen-2.5-coder-32b-instruct:free", 0.10),
# T8: Groq Llama 4 Scout — fast last resort
(GROQ_URL, GROQ_KEY, "meta-llama/llama-4-scout-17b-16e-instruct", 0.15),],
# fast: GLM-4.7-flash → Llama-4 Scout
"fast": [(ZAI_CHAT, ZAI_KEY, "glm-4.7-flash", 0.8),
(GROQ_URL, GROQ_KEY, "meta-llama/llama-4-scout-17b-16e-instruct", 0.8)],
# vision: Groq Llama-3.2-11B-Vision (fast) → Qwen2.5-VL (quality) → GLM-4.5V
"vision": [(GROQ_URL, GROQ_KEY, "meta-llama/llama-4-scout-17b-16e-instruct", 0.5), # Llama 4 Scout has vision
(OR_URL, OR_KEY, "qwen/qwen2.5-vl-72b-instruct:free", 0.5), # Best free vision
(ZAI_CHAT, ZAI_KEY, "glm-4.5v", 0.5)], # Z.AI Vision backup
# reasoning: DeepSeek R1 on Groq (fastest R1) → GLM-4.7-flash
"reason": [(GROQ_URL, GROQ_KEY, "deepseek-r1-distill-llama-70b", 0.6),
(ZAI_CHAT, ZAI_KEY, "glm-4.7-flash", 0.6)],
}
last=None
for url,key,model,temp in configs.get(mode,configs["general"]):
try:
_temp = temperature if temperature is not None else temp
_max = max_tokens
async for tok in stream_llm(messages,url,key,model,_temp,_max): yield tok
return
except Exception as e: last=e; log.warning(f"LLM fail ({model}): {e}")
raise Exception(f"All APIs failed. Last: {last}")
def build_msgs(sys_p,hist,user_msg,img=None):
msgs=[{"role":"system","content":sys_p}]
for h in hist[-14:]:
if h.get("role") in("user","assistant") and h.get("content"):
msgs.append({"role":h["role"],"content":h["content"]})
if img:
msgs.append({"role":"user","content":[
{"type":"image_url","image_url":{"url":f"data:{img['mime']};base64,{img['data']}","detail":"high"}},
{"type":"text","text":user_msg}]})
else: msgs.append({"role":"user","content":user_msg})
return msgs
# ═══════════════════════════════════════════════════════
# RUBRA CORE ENGINE v1.0
# Inspired by: OpenCode · Cline · Aider · OpenHands
# Architecture:
# OpenCode → Agent hierarchy + parallel tools + LSP awareness
# Cline → Plan→Act→Verify loop + context management
# Aider → Architect+Editor dual mode + diff-based thinking
# OpenHands → CodeAct (Think→Act→Observe) loop
# ═══════════════════════════════════════════════════════
import difflib
# ── CodeAct Loop (OpenHands pattern) ────────────────────
# Think → Act → Observe → Think again until done
XML_THINK_SYSTEM = """Use structured reasoning for complex tasks:
<thought>Deep analysis — what's needed, edge cases, best approach</thought>
<action>Concrete steps — what to compute, build, or research</action>
<observation>Results — what was found, patterns, insights</observation>
<final_response>Complete polished answer for the user</final_response>
For simple queries: skip XML, respond directly."""
def parse_xml_response(raw: str) -> str:
m = re.search(r'<final_response>([\s\S]*?)</final_response>', raw, re.IGNORECASE)
if m: return m.group(1).strip()
clean = re.sub(r'<(?:thought|action|observation)[^>]*>[\s\S]*?</(?:thought|action|observation)>','',raw,flags=re.IGNORECASE)
return clean.strip() or raw.strip()
def extract_thought_chain(raw: str) -> list:
chain = []
for tag in ["thought","action","observation"]:
m = re.search(rf'<{tag}>([\s\S]*?)</{tag}>', raw, re.IGNORECASE)
if m: chain.append({"step":tag,"content":m.group(1).strip()[:400]})
return chain
# ── Task Classifier (Cline-inspired intent routing) ─────
def classify_coding_task(msg: str) -> dict:
"""Classify coding request into skill domains for targeted prompt injection."""
lower = msg.lower()
return {
"is_frontend": bool(re.search(
r'\b(html|css|react|vue|svelte|nextjs|tailwind|landing.?page|dashboard|'
r'website|ui\b|interface|component|frontend|design|glassmorphism|dark.?mode|'
r'navbar|hero|card|button|form|modal|animation|responsive|figma|wireframe|'
r'typography|color.?palette|layout|grid|flex|sass|styled.?components)\b', lower)),
"is_game": bool(re.search(
r'\b(game\b|godot|unity|unreal|platformer|rpg|shooter|puzzle|arcade|'
r'sprite|tilemap|physics|game.?loop|player|enemy|score|level|'
r'gdscript|blueprint|game.?dev|gdd|core.?loop|collision|inventory|npc)\b', lower)),
"is_backend": bool(re.search(
r'\b(api\b|backend|server|database|fastapi|flask|django|express|node\.?js|'
r'sql\b|postgres|mysql|mongodb|redis|auth|jwt|endpoint|crud|rest\b|'
r'graphql|docker|microservice|queue|worker|algorithm|data.?structure)\b', lower)),
"is_mobile": bool(re.search(
r'\b(react.?native|flutter|android|ios|expo|mobile.?app|swift|kotlin)\b', lower)),
"is_devops": bool(re.search(
r'\b(docker|kubernetes|ci.?cd|github.?action|nginx|deploy|terraform|bash.?script)\b', lower)),
"is_data": bool(re.search(
r'\b(machine.?learning|pytorch|tensorflow|pandas|numpy|sklearn|'
r'data.?analysis|matplotlib|model.?training|jupyter)\b', lower)),
"needs_architect": bool(re.search(
r'\b(complex|architecture|system.?design|full.?stack|entire|complete.?app|'
r'from.?scratch|production|scalable|enterprise|best.?way|design.?pattern)\b', lower)),
"is_debug": bool(re.search(
r'\b(bug|error|fix|debug|not.?working|broken|issue|exception|traceback|crash)\b', lower)),
"is_refactor": bool(re.search(
r'\b(refactor|optimize|improve|clean.?up|rewrite|performance|better.?way)\b', lower)),
}
# ── Aider-style Architect+Editor dual mode ──────────────
def build_architect_prompt(msg: str, task: dict) -> str:
"""
Aider-inspired: Architect mode first plans the solution,
Editor mode then writes the actual code.
For complex tasks, we embed both in one prompt.
"""
if not task["needs_architect"]:
return ""
return """
═══ ARCHITECT MODE (Plan before coding) ═══
For this complex task, first produce a brief plan:
1. What files/components need to be created?
2. What is the data flow / architecture?
3. What are the key technical decisions?
4. Any risks or edge cases to handle?
Then immediately proceed to EDITOR MODE — write all the code.
Do NOT stop after the plan. Plan is just internal prep.
═══ EDITOR MODE (Write complete code after planning) ═══
"""
# ── Context Window Manager (Cline-inspired) ─────────────
def trim_prompt_smart(sys_p: str, max_chars: int = 13000) -> str:
"""
Cline-inspired context management:
Preserve critical sections, trim repetitive/decorative content.
Priority: Core rules > Skill content > Examples > Checklists
"""
if len(sys_p) <= max_chars:
return sys_p
# Trim pre-delivery checklists (repetitive)
sys_p = re.sub(
r'═+\s*PRE-DELIVERY CHECKLIST.*?(?=═{3}|\Z)',
'[✓ Apply: cursor:pointer, hover states, responsive 375-1440px, WCAG AA contrast, alt text]\n',
sys_p, flags=re.DOTALL
)
if len(sys_p) <= max_chars:
return sys_p
# Trim repeated UX guidelines numbers (keep just the section header)
sys_p = re.sub(
r'(LAYOUT \(Rules 1-20\):[\s\S]{0,200})(\d+\. .+\n){5,}',
r'\1[...layout rules apply]\n',
sys_p
)
if len(sys_p) <= max_chars:
return sys_p
# Hard trim as last resort
return sys_p[:max_chars] + "\n[...apply remaining best practices from training]"
# ── Hermes Prompt Builder (OpenCode agent hierarchy) ────
def build_hermes_prompt(msg: str, lang: str = "en") -> str:
"""
OpenCode-inspired agent hierarchy:
- BUILD agent: full access, writes code
- PLAN agent: read-only analysis (embedded as thinking phase)
- GENERAL subagent: complex search/research tasks
All three modes are embedded contextually based on task type.
"""
task = classify_coding_task(msg)
li = lang_instr(lang)
# ── Hermes Core (always) ────────────────────────────
mode_label = "ARCHITECT+EDITOR" if task["needs_architect"] else (
"DEBUG" if task["is_debug"] else (
"REFACTOR" if task["is_refactor"] else "BUILD"))
prompt = f"""You are RUBRA's Hermes Core Engine — world-class coding intelligence.
Mode: {mode_label}
═══ CORE MISSION ═══
Produce complete, production-ready code that works on the first run.
No truncation. No placeholders. No TODOs. No "..." shortcuts.
═══ CODEACT LOOP (Think → Act → Verify) ═══
Before writing code:
1. THINK: What exactly is needed? Best approach? Edge cases?
2. ACT: Write complete, working code
3. VERIFY: Mentally run it. Any bugs? Fix them before outputting.
═══ ABSOLUTE RULES ═══
✗ NEVER: "// rest of code...", "# TODO", "...", "[continues]"
✗ NEVER: Truncate a function, class, or file mid-way
✗ NEVER: Placeholder logic or mock implementations
✓ ALWAYS: Complete every bracket, tag, function, class
✓ ALWAYS: Real working code only
✓ IF LONG: Finish current block → write <!-- RUBRA_CONTINUE -->
The system auto-requests continuation. Just mark it.
{build_architect_prompt(msg, task)}
"""
# ── Inject relevant skills only ─────────────────────
# Frontend/UI skill (full UIUX Pro Max)
if task["is_frontend"] or (not any([
task["is_backend"], task["is_game"],
task["is_mobile"], task["is_devops"], task["is_data"]
])):
prompt += f"""
═══ UI/UX PRO MAX SKILL — MANDATORY ═══
{UIUX_PRO_MAX}
DESIGN SYSTEM (apply before any UI code):
→ Identify product type → match 161 rules → select style from 67
→ Apply color palette + typography from 57 pairings
→ Follow all 99 UX guidelines strictly
→ Run pre-delivery checklist
HARD UI RULES:
✗ No emoji as icons → Lucide/Heroicons SVG only
✗ No placeholder text in rendered UI
✗ No missing cursor:pointer or hover states
✓ Mobile-first: 375→768→1024→1440px
✓ Smooth transitions 150-300ms
✓ Loading + error + empty states always
✓ WCAG AA contrast minimum
"""
# Game Dev skill
if task["is_game"]:
prompt += f"""
═══ GAME DEV STUDIO SKILL — MANDATORY ═══
{GAME_DEV_STUDIO}
GAME RULES:
✓ Core loop design FIRST, then code
✓ No magic numbers → constants/config
✓ Delta time on ALL movement
✓ State machine for entities
✓ Object pooling for spawned objects
✓ Separate: Logic / Render / Input
"""
# Backend skill
if task["is_backend"]:
prompt += """
═══ BACKEND EXCELLENCE SKILL ═══
Architecture: Routes → Controllers → Services → Models/DB
MANDATORY:
✓ Type hints (Python) / TypeScript strict
✓ Input validation on every endpoint (Pydantic/Zod)
✓ Error handling on every async operation
✓ Parameterized SQL queries only
✓ bcrypt/argon2 for passwords
✓ Environment variables for all secrets
✓ Rate limiting on public endpoints
✓ Database indexes on queried fields
GENERATE: All routes + models + .env.example + setup README
"""
# Mobile
if task["is_mobile"]:
prompt += """
═══ MOBILE SKILL ═══
✓ 44pt/48dp minimum touch targets
✓ Safe area handling
✓ Platform-specific code minimized
✓ Navigation: React Navigation v6 / GoRouter
✓ State: Zustand / Riverpod
"""
# Debug mode (Aider diff-aware)
if task["is_debug"]:
prompt += """
═══ DEBUG MODE ═══
1. Identify the exact error/symptom
2. Trace the root cause (not just symptoms)
3. Provide the minimal correct fix
4. Explain WHY it was broken
5. Show before/after if helpful
"""
# Refactor mode
if task["is_refactor"]:
prompt += """
═══ REFACTOR MODE ═══
1. Analyze current code structure
2. Identify: duplication / complexity / performance issues
3. Apply: SOLID principles, DRY, clean architecture
4. Preserve: all existing functionality
5. Show: what changed and why
"""
# Language instruction
if li:
prompt += f"\n\n{li}\n(Code in English always. Explanations in user's language.)"
return prompt
# ── Model Cascade (OpenCode provider-agnostic pattern) ──
# Best → Good → Fast → Fallback
# Each tier tried in order; cascade on rate-limit/quota/error
CODING_MODEL_CASCADE = [
# ── Tier 1: Best quality ──────────────────────────
{"url": OR_URL, "key": OR_KEY,
"model": "deepseek/deepseek-v3-0324:free",
"temp": 0.05, "max_tokens": 8192, "label": "DeepSeek-V3"},
{"url": OR_URL, "key": OR_KEY,
"model": "qwen/qwen3-coder-480b-a35b-instruct:free",
"temp": 0.05, "max_tokens": 8192, "label": "Qwen3-Coder-480B"},
{"url": GEMINI_URL, "key": GEMINI_KEY,
"model": "gemini-2.5-flash-preview-05-20",
"temp": 0.05, "max_tokens": 8192, "label": "Gemini-2.5-Flash"},
# ── Tier 2: Fast + capable ────────────────────────
{"url": ZAI_CODE, "key": ZAI_KEY,
"model": "glm-4.7-flash",
"temp": 0.10, "max_tokens": 8192, "label": "GLM-4.7-Code"},
{"url": CEREBRAS_URL, "key": CEREBRAS_KEY,
"model": "llama-4-scout-17b-16e-instruct",
"temp": 0.10, "max_tokens": 8192, "label": "Cerebras-Scout"},
{"url": CEREBRAS_URL, "key": CEREBRAS_KEY,
"model": "llama-3.3-70b",
"temp": 0.10, "max_tokens": 8192, "label": "Cerebras-70B"},
# ── Tier 3: Reliable fallbacks ────────────────────
{"url": OR_URL, "key": OR_KEY,
"model": "qwen/qwen-2.5-coder-32b-instruct:free",
"temp": 0.15, "max_tokens": 8192, "label": "Qwen-Coder-32B"},
{"url": GROQ_URL, "key": GROQ_KEY,
"model": "meta-llama/llama-4-scout-17b-16e-instruct",
"temp": 0.15, "max_tokens": 8192, "label": "Groq-Scout"},
{"url": GROQ_URL, "key": GROQ_KEY,
"model": "llama-3.3-70b-versatile",
"temp": 0.15, "max_tokens": 4096, "label": "Groq-70B"},
]
# Cascade error codes that trigger next model
_CASCADE_TRIGGERS = {
"401","403","404", # auth fail → try different key
"413","429", # size/rate → try different model
"500","502","503", # server error
"rate limit","quota", # explicit quota messages
"capacity","overloaded", # busy
"too large","token", # context too big
"user not found", # Z.AI specific
"model not found", # wrong model name
"timeout","timed out", # slow response
}
async def hermes_stream(messages: list, task: dict):
"""
RUBRA Core Engine cascade.
OpenCode-inspired: provider-agnostic, best-first, auto-fallback.
Cline-inspired: context-aware, task-type routing.
"""
last_err = None
tried = []
for cfg in CODING_MODEL_CASCADE:
tried.append(cfg["label"])
try:
log.info(f"🔧 RUBRA Core → {cfg['label']}")
got_tokens = False
async for tok in stream_llm(
messages, cfg["url"], cfg["key"],
cfg["model"], cfg["temp"], cfg["max_tokens"]
):
got_tokens = True
yield tok
if got_tokens:
log.info(f"✅ {cfg['label']} completed")
return
except Exception as e:
last_err = e
err_str = str(e).lower()
should_cascade = any(t in err_str for t in _CASCADE_TRIGGERS)
if should_cascade:
log.warning(f"⚡ {cfg['label']} → cascade ({str(e)[:70]})")
await asyncio.sleep(0.2)
continue
else:
# Hard error — raise immediately (bad request, invalid params)
log.error(f"❌ {cfg['label']} hard fail: {e}")
raise e
raise Exception(
f"RUBRA Core Engine exhausted ({len(tried)} models tried). "
f"Last: {last_err}"
)
# ── Dynamic Skill Library (preserved from original) ─────
async def skill_generate_and_save(skill_name: str, task_desc: str) -> str:
prompt = f"""Generate a complete Python function for: {task_desc}
Function name: run_{skill_name}(input_data: dict) -> dict
Requirements: type hints, docstring, error handling, returns {{"result":..,"success":bool,"error":str|None}}"""
msgs = [{"role":"system","content":"Output ONLY pure Python code, no markdown."},
{"role":"user","content":prompt}]
code = ""
async for tok in llm(msgs,"coding"): code += tok
code = re.sub(r'^```python','',code.strip()); code = re.sub(r'```$','',code.strip())
(SKILLS_DIR/f"{skill_name}.py").write_text(code)
return code
def skill_load(name: str) -> str:
f = SKILLS_DIR/f"{name}.py"; return f.read_text() if f.exists() else None
def skill_list() -> list:
return [f.stem for f in SKILLS_DIR.glob("*.py")]
# ═══════════════════════════════════════════════════════
# AGENTS
# ═══════════════════════════════════════════════════════
class GeneralAgent:
name="GeneralAgent"
async def run(self,msg,hist,sid="",lang="en",img=None):
li=lang_instr(lang); tool_ctx=""; rag_ctx=""
# Session memory
sess=session_load(sid); sess["preferred_lang"]=lang
session_update(sid,"user_intent_history",{"msg":msg[:120],"ts":time.time()})
# Auto Wikipedia
if not img and re.search(r"\b(what is|who is|how does|explain|define|history|overview|what are)\b",msg,re.IGNORECASE):
q=re.sub(r"\b(what is|who is|how does|explain|define|tell me|about|the|a|an|please)\b","",msg,flags=re.IGNORECASE).strip()[:60]
if len(q)>3:
page=tool_wikipedia(q)
if page: tool_ctx=f"[WIKIPEDIA: {page['title']}]\n{page['text']}"
# Live feed
if re.search(r"\b(latest|recent|trending|news|today|2025|2026|current)\b",msg,re.IGNORECASE):
items=feed_get(limit=5)
if items:
feed_ctx="[LIVE KNOWLEDGE]\n"+"\n".join(f"• {f['title']} ({f['source']})" for f in items[:4])
tool_ctx=feed_ctx+("\n\n"+tool_ctx if tool_ctx else "")
# RAG
hits=rag_search(msg,limit=3)
if hits: rag_ctx="\n".join(f"[{s}:{t}]\n{c}" for _,t,c,s in hits[:2])
# Session topic context
topic_ctx=""
if sess.get("topic_memory"):
recent=list(sess["topic_memory"].items())[-3:]
topic_ctx="[SESSION CONTEXT]\n"+"\n".join(f"• {k}" for k,v in recent)
sinthia_extra = SINTHIA_SYSTEM_EXTRA if is_sinthia(msg) else ""
parts=[RUBRA_CORE, sinthia_extra, XML_THINK_SYSTEM,"\n[DEEP REASONING] Use XML chain. Show steps."]
if li: parts.append(li)
if tool_ctx: parts.append(tool_ctx)
if rag_ctx: parts.append(f"[KNOWLEDGE]\n{rag_ctx}")
if topic_ctx: parts.append(topic_ctx)
msgs=build_msgs("\n\n".join(parts),hist,msg,img)
full_raw=""
try:
mode="vision" if img else "general"
async for tok in llm(msgs,mode):
full_raw+=tok; yield {"type":"token","content":tok}
chain=extract_thought_chain(full_raw)
if chain: session_update(sid,"thought_chain",{"query":msg[:80],"chain":chain,"ts":time.time()})
except Exception as e: yield {"type":"error","message":str(e)[:200]}
class CodingAgent:
name = "CodingAgent"
async def run(self, msg, hist, sid="", lang="en", img=None):
task = classify_coding_task(msg)
# Build targeted Hermes prompt
sys_p = build_hermes_prompt(msg, lang)
# Auto design system for frontend
if task["is_frontend"]:
try:
m = re.search(
r'for\s+(?:a\s+|my\s+)?([a-zA-Z\s]{3,40}?)(?:\s+(?:app|website|platform|tool|page|dashboard))?(?:\s|$)',
msg, re.IGNORECASE)
proj = m.group(1).strip() if m else ""
sys_p += f"\n\n[AUTO DESIGN SYSTEM]\n{uiux_design_system(msg, proj)}"
except Exception:
pass
# RAG — minimal tokens
hits = rag_search(msg, limit=2)
if hits:
sys_p += "\n\n[CONTEXT]\n" + "\n".join(
f"• {t}: {c[:80]}" for _, t, c, s in hits[:2])
# Smart context trim
sys_p = trim_prompt_smart(sys_p, max_chars=13000)
# Continuation mode
if msg.startswith("[RUBRA_CONTINUE]"):
last = msg.replace("[RUBRA_CONTINUE]", "").strip()
msg = f"Continue EXACTLY from here — no intro, no repetition:\n...{last}"
if img:
msg = f"[Screenshot/Image provided]\n{msg}"
msgs = build_msgs(sys_p, hist, msg, img)
try:
if img:
async for tok in llm(msgs, "vision", max_tokens=8192, temperature=0.1):
yield {"type": "token", "content": tok}
else:
async for tok in hermes_stream(msgs, task):
yield {"type": "token", "content": tok}
except Exception as e:
yield {"type": "error", "message": str(e)[:200]}
class SearchAgent:
name="SearchAgent"
async def run(self,msg,hist,sid="",lang="en",img=None):
lower=msg.lower(); li=lang_instr(lang); tool_ctx=""
if re.search(r"\b(weather|temperature|forecast|rain|cold|hot|humid|wind)\b",lower):
city="Dhaka"
for c in CITY_COORDS:
if c in lower: city=c.title(); break
m=re.search(r"weather\s+(?:in\s+)?([a-z\s]{3,20})(?:\?|$|\.|\!)",lower)
if m: city=m.group(1).strip().title()
w=tool_weather(city)
if w:
tool_ctx=f"[LIVE WEATHER — {w['city']}]\nTemp: {w['temp']}°C (feels {w['feels']}°C) | {w['condition']} | Humidity: {w['humidity']}% | Wind: {w['wind']} km/h"
yield {"type":"tool_result","tool":"weather","data":w}
elif re.search(r"\b(bitcoin|ethereum|btc|eth|solana|crypto|coin|binance)\b",lower):
cm={"btc":"bitcoin","eth":"ethereum","sol":"solana","bnb":"binancecoin"}
found=[cm.get(k,k) for k in cm if k in lower]
d=tool_crypto(",".join(found or ["bitcoin","ethereum","solana"]))
if d:
lines=[f"{'📈' if i.get('usd_24h_change',0)>=0 else '📉'} {c.capitalize()}: ${i.get('usd',0):,.2f} ({i.get('usd_24h_change',0):+.2f}%)" for c,i in d.items()]
tool_ctx="[LIVE CRYPTO]\n"+"\n".join(lines)
yield {"type":"tool_result","tool":"crypto","data":d}
elif re.search(r"\b(exchange rate|forex|usd to|eur to|taka|bdt|currency)\b",lower):
bases=re.findall(r"\b(USD|EUR|GBP|JPY|BDT|INR|CAD|AUD|CNY)\b",msg.upper())
d=tool_currency(bases[0] if bases else "USD")
if d:
lines=[f"1 {d['base']} = {r} {c}" for c,r in list(d["rates"].items())[:8]]
tool_ctx=f"[LIVE RATES — {d['base']}]\n"+"\n".join(lines)
yield {"type":"tool_result","tool":"currency","data":d}
elif re.search(r"\b(latest news|trending|what.{0,10}happening|current events|today)\b",lower):
cat=None
if re.search(r"\b(tech|ai|software)\b",lower): cat="tech"
elif re.search(r"\b(bangladesh|dhaka)\b",lower): cat="bangladesh"
items=feed_get(category=cat,limit=8)
if items:
lines=[f"• **{f['title']}** — _{f['source']}_" for f in items]
tool_ctx="[LIVE NEWS]\n"+"\n".join(lines)
yield {"type":"tool_result","tool":"news","count":len(items)}
elif re.search(r"\b(2025 book|2026 book|new book|latest book|recent book)\b",lower):
q=re.sub(r"\b(2025|2026|new|latest|recent|book|recommend|best|read|novel)\b","",lower).strip()[:50]
books=tool_books_2026(q)
if books:
lines=[f"📚 **{b['title']}** ({b.get('year','?')}) — {', '.join(b.get('authors',b.get('author_name',[]))[:2])}" for b in books]
tool_ctx="[RECENT BOOKS 2024-2026]\n"+"\n".join(lines)
elif re.search(r"\b(recommend.{0,10}book|best books|reading list)\b",lower):
books=tool_books(re.sub(r"\b(recommend|book|about|best|read)\b","",lower).strip()[:50])
if books:
tool_ctx="[BOOKS]\n"+"\n".join(f"📚 {b['title']} ({b.get('year','?')}) — {', '.join(b['authors'][:2])}" for b in books)
elif re.search(r"\b(research papers?|arxiv|academic|scientific)\b",lower):
q=re.sub(r"\b(research|papers?|arxiv|find|latest)\b","",lower).strip()[:70]
papers=tool_arxiv(q or msg,n=4)
if papers:
tool_ctx="[ARXIV]\n"+"\n\n".join(f"• **{p['title']}** — {', '.join(p['authors'][:2])}\n {p['summary'][:200]}…" for p in papers)
else:
q=re.sub(r"\b(who is|what is|tell me about|history of|the|a|an)\b","",lower).strip()[:60]
page=tool_wikipedia(q or msg)
if page:
tool_ctx=f"[WIKIPEDIA: {page['title']}]\n{page['text']}"
yield {"type":"tool_result","tool":"wikipedia","title":page["title"]}
parts=[RUBRA_CORE,"\n[LIVE SEARCH MODE] Answer directly using retrieved data."]
if li: parts.append(li)
if tool_ctx: parts.append(tool_ctx)
msgs=build_msgs("\n\n".join(parts),hist,msg)
try:
async for tok in llm(msgs,"general"): yield {"type":"token","content":tok}
except Exception as e: yield {"type":"error","message":str(e)[:200]}
class SmartTutorAgent:
name = "SmartTutorAgent"
async def run(self, msg, hist, sid="", lang="en", img=None):
li = lang_instr(lang)
lower = msg.lower()
# Detect exam/PDF request
wants_exam = bool(re.search(
r'\b(exam|mcq|পরীক্ষা|প্রশ্ন তৈরি|question paper|সৃজনশীল|model test|pdf)\b',
lower, re.IGNORECASE))
wants_pdf = bool(re.search(r'\b(pdf|download|ডাউনলোড)\b', lower, re.IGNORECASE))
wants_prediction = bool(re.search(
r'\b(prediction|আসতে পারে|আসবে|পূর্বাভাস|কোন প্রশ্ন|কি আসবে)\b',
lower, re.IGNORECASE))
# Build system prompt
sys_p = TUTOR_ADVANCED_PROMPT + "\n\n" + TUTOR_PROMPT
if li:
sys_p += f"\n\n{li}"
# Inject NCTB content
for class_key, data in NCTB_2026.items():
if any(kw in lower for kw in [class_key.lower().replace("_"," "), class_key.lower()]):
sys_p += f"\n\n[NCTB 2026 — {class_key}]\n{json.dumps(data, ensure_ascii=False, indent=2)[:1200]}"
break
# RAG search
hits = rag_search(msg, limit=3)
if hits:
sys_p += "\n\n[STUDY MATERIAL]\n" + "\n".join(f"[{s}:{t}]\n{c}" for _,t,c,s in hits)
# Exam prediction mode
if wants_prediction and not img:
sys_p += """
\n[EXAM PREDICTION MODE]
Board পরীক্ষার pattern বিশ্লেষণ করে বলো:
- কোন chapter থেকে বেশি আসে
- কোন type এর প্রশ্ন বেশি আসে
- এবার কী পড়া উচিত
Specific ও practical advice দাও।"""
msgs = build_msgs(sys_p, hist, msg, img)
try:
mode = "vision" if img else "general"
async for tok in llm(msgs, mode):
yield {"type": "token", "content": tok}
except Exception as e:
yield {"type": "error", "message": str(e)[:200]}
if li: sys_p+=f"\n\n{li}"
# Inject relevant NCTB content
for class_key,data in NCTB_2026.items():
if any(kw in msg.lower() for kw in [class_key.lower().replace("_"," "),class_key.lower()]):
sys_p+=f"\n\n[NCTB 2026 — {class_key}]\n{json.dumps(data,ensure_ascii=False,indent=2)[:1000]}"
break
hits=rag_search(msg,limit=2)
if hits: sys_p+="\n\n[STUDY MATERIAL]\n"+"\n".join(f"[{s}:{t}]\n{c}" for _,t,c,s in hits)
msgs=build_msgs(sys_p,hist,msg,img)
try:
mode="vision" if img else "general"
async for tok in llm(msgs,mode): yield {"type":"token","content":tok}
except Exception as e: yield {"type":"error","message":str(e)[:200]}
class VisionAgent:
"""Advanced multi-model vision: OCR.space → Groq Vision → Qwen2.5-VL"""
name="VisionAgent"
async def run(self,msg,hist,sid="",lang="en",img=None):
li=lang_instr(lang)
sys_p=VISION_PROMPT
if li: sys_p+=f"\n\n{li}"
if not img:
yield {"type":"error","message":"No image provided"}; return
# Try vision LLM
msgs=build_msgs(sys_p,hist,msg,img)
try:
async for tok in llm(msgs,"vision"): yield {"type":"token","content":tok}
except Exception as e:
# Fallback: extract text via OCR.space, then send to general LLM
log.warning(f"Vision LLM failed: {e}, falling back to OCR")
img_bytes=base64.b64decode(img["data"])
ocr_text=ocr_image_space(img_bytes,img["mime"])
if not ocr_text: ocr_text=ocr_image_tesseract(img_bytes)
if ocr_text:
fallback_sys=VISION_PROMPT+f"\n\n[OCR EXTRACTED TEXT FROM IMAGE]\n{ocr_text}\n[/OCR]"
if li: fallback_sys+=f"\n\n{li}"
msgs2=build_msgs(fallback_sys,hist,msg or "Analyze this content")
try:
async for tok in llm(msgs2,"general"): yield {"type":"token","content":tok}
except Exception as e2: yield {"type":"error","message":str(e2)[:200]}
else:
yield {"type":"error","message":"Could not process image. Try a clearer photo."}
class FileAgent:
name="FileAgent"
def _read(self,fp):
ext=fp.suffix.lower()
try:
if ext==".pdf": return pdf_to_text(fp)
if ext in(".xlsx",".xls"):
try:
import openpyxl; wb=openpyxl.load_workbook(fp,read_only=True,data_only=True)
out=[]
for name in wb.sheetnames[:4]:
ws=wb[name]; out.append(f"## Sheet: {name}")
for row in ws.iter_rows(max_row=80,values_only=True):
out.append(" | ".join(str(c) if c is not None else "" for c in row))
return "\n".join(out)[:12000]
except ImportError: return "[openpyxl not installed]"
if ext==".csv":
import csv
with open(fp,"r",encoding="utf-8",errors="replace") as f:
return "\n".join(", ".join(r) for r in csv.reader(f))[:10000]
if ext in(".docx",".doc"):
try:
import docx; doc=docx.Document(str(fp))
return "\n".join(p.text for p in doc.paragraphs if p.text.strip())[:14000]
except ImportError: return "[python-docx not installed]"
return fp.read_text(encoding="utf-8",errors="replace")[:14000]
except Exception as e: return f"[Read error: {e}]"
async def analyze(self,fp,fname,question,sid="",lang="en",img_data=None):
li=lang_instr(lang); ext=fp.suffix.lower()
sys_p=RUBRA_CORE+"\n\n[FILE ANALYSIS] Extract insights. Answer question clearly. Use structure."
if li: sys_p+=f"\n\n{li}"
if ext in IMAGE_EXTS or img_data:
b64,mime=to_base64(fp) if not img_data else (img_data["data"],img_data["mime"])
img_d={"data":b64,"mime":mime}
# Use VisionAgent for images
vis=VisionAgent()
async for evt in vis.run(question or f"Analyze: {fname}",[],sid,lang,img_d):
yield evt
return
content=self._read(fp)
sys_p+=f"\n\n[FILE: {fname}]\n{content}\n[/FILE]"
msgs=build_msgs(sys_p,[],question or f"Analyze: {fname}")
try:
async for tok in llm(msgs,"general"): yield {"type":"token","content":tok}
except Exception as e: yield {"type":"error","message":str(e)[:200]}
async def run(self,msg,hist,sid="",lang="en",img=None):
yield {"type":"error","message":"Use /api/upload for file analysis"}
class FastChatAgent:
name="FastChatAgent"
async def run(self,msg,hist,sid="",lang="en",img=None):
li=lang_instr(lang)
sys_p=RUBRA_CORE+"\n\n[CONVERSATIONAL] Warm, natural, concise. Match user's energy."
if li: sys_p+=f"\n\n{li}"
msgs=build_msgs(sys_p,hist,msg)
try:
async for tok in llm(msgs,"fast"): yield {"type":"token","content":tok}
except Exception as e: yield {"type":"error","message":str(e)[:200]}
# ═══════════════════════════════════════════════════════
# ROUTER
# ═══════════════════════════════════════════════════════
INTENT_MAP=[
# ── Browse / Web navigation ──
(r'https?://[^\s]{10,}', "browse", BrowseAgent),
(r'\b(browse|scrape|navigate to|open url|visit site|fetch page)\b', "browse", BrowseAgent),
(r'\b(who is|profile of|linkedin|contact info|email of|phone of)\b.{3,}', "browse", BrowseAgent),
(r'\b(latest post|recent article|find contact|professional details|company info)\b',"browse", BrowseAgent),
(r"\b(make|build|create|design).{0,20}(game|platformer|rpg|shooter|puzzle|arcade|mobile game)\b","game",CodingAgent),
(r"\b(godot|unity|unreal|gdscript|blueprint|game engine|game dev)\b","game",CodingAgent),
(r"\b(game design|gdd|game mechanic|core loop|level design|sprite|tilemap|physics2d)\b","game",CodingAgent),
# ── Absolute priority patterns ──
(r"\b(2025|2026).{0,10}(book|novel|read)","books",SearchAgent),
# High-priority tutor patterns
(r"\b(class [0-9]+).{0,20}(math|science|physics|chemistry|biology|solve|korao|bujhao|shekao)","tutor",SmartTutorAgent),
(r"\b(ssc|hsc|jsc).{0,20}(bujhao|explain|solve|shekho)","tutor",SmartTutorAgent),
(r"\b(weather|temperature|forecast|rain|cold|hot|humid|wind|climate)\b","weather",SearchAgent),
(r"\b(bitcoin|ethereum|btc|eth|solana|crypto|coin price|binance|bnb)\b","crypto",SearchAgent),
(r"\b(exchange rate|forex|usd to|eur to|taka|bdt|currency conversion)\b","currency",SearchAgent),
(r"\b(latest news|what.{0,10}happening|trending|current events|breaking)\b","news",SearchAgent),
(r"\b(research papers?|arxiv|academic|scientific|peer.?reviewed)\b","research",SearchAgent),
(r"\b(2025 book|2026 book|new book|latest book|recent book)\b","books",SearchAgent),
(r"\b(recommend.{0,10}book|best books|reading list)\b","books",SearchAgent),
(r"\b(analyze|read|summarize|extract)\b.{0,20}\b(file|pdf|excel|csv|doc)\b","file",FileAgent),
# Code
(r"\b(write|create|build|implement|generate|make)\b.{0,30}\b(python|javascript|typescript|rust|go|java|html|css|sql|bash|react|node|api|flask|django|fastapi|express|vue|svelte|nextjs|tailwind|website|app|landing page|dashboard|component)\b","code",CodingAgent),
(r"\b(debug|fix|refactor|optimize|review)\b.{0,20}\b(code|function|script|bug|error|exception)\b","code",CodingAgent),
(r"```|def |class |const |let |var |import .* from|from .* import","code",CodingAgent),
(r"\b(algorithm|data structure|sorting|recursion|dynamic programming|api endpoint)\b","code",CodingAgent),
(r"\b(website|web app|mobile app|landing page|dashboard|ui component|frontend|backend)\b","code",CodingAgent),
# Tutor
(r"\b(ssc|hsc|jsc|psc|board exam|creative question|সৃজনশীল|বহুনির্বাচনি)\b","tutor",SmartTutorAgent),
(r"\b(class [0-9]|class six|seven|eight|nine|ten|eleven|twelve)\b","tutor",SmartTutorAgent),
(r"\b(প্রশ্ন|উত্তর|পড়া|শেখা|বোঝা|গণিত|বিজ্ঞান|বাংলা|ইতিহাস|ভূগোল|রসায়ন|পদার্থ)\b","tutor",SmartTutorAgent),
(r"\b(solve|bujhao|shekao|explain).{0,30}(math|science|physics|chemistry|biology|bangla|history)\b","tutor",SmartTutorAgent),
(r"\b(question paper|exam paper|model test|practice exam|nctb)\b","tutor",SmartTutorAgent),
# Reasoning
(r"\b(explain|analyze|compare|evaluate|how does|why does|difference between|what causes)\b","reasoning",GeneralAgent),
(r"\b(neural|machine.?learning|deep.?learning|transformer|llm|ai model|quantum|consciousness)\b","reasoning",GeneralAgent),
(r"\b(who is|who was|what is|what was|tell me about|history of)\b","fact",GeneralAgent),
(r"\b(calculate|compute|solve|integral|derivative|sin|cos|sqrt|factorial)\b","math",GeneralAgent),
# Chat
(r"^(hi|hey|hello|yo|sup|salaam|হ্যালো|হেই|আচ্ছা|ভালো আছ)\b","chat",FastChatAgent),
(r"^(thanks|thank you|ok|okay|got it|bye|kemon|bhaloi)\b","chat",FastChatAgent),
(r"\b(2025 book|2026 book)\b","books",SearchAgent),
]
def route(msg,task_type=None,mode=None):
agents={"code":CodingAgent(),"search":SearchAgent(),"file":FileAgent(),
"general":GeneralAgent(),"tutor":SmartTutorAgent(),"browse":BrowseAgent()}
if mode=="tutor": return "tutor",SmartTutorAgent()
if task_type and task_type in agents: return task_type,agents[task_type]
lower=msg.lower().strip(); words=len(msg.split())
for pat,intent,Cls in INTENT_MAP:
if re.search(pat,lower,re.IGNORECASE): return intent,Cls()
if words<6: return "chat",FastChatAgent()
if words>35: return "reasoning",GeneralAgent()
return "general",GeneralAgent()
# ═══════════════════════════════════════════════════════
# FASTAPI
# ═══════════════════════════════════════════════════════
app=FastAPI(title="RUBRA API",version="8.0.0",docs_url="/docs")
app.add_middleware(CORSMiddleware,allow_origins=["*"],allow_credentials=True,allow_methods=["*"],allow_headers=["*"])
@app.on_event("startup")
async def startup():
t=threading.Thread(target=knowledge_loop,daemon=True); t.start()
log.info("✅ RUBRA v8 started — Knowledge Engine running")
@app.get("/")
async def root(): return {"name":"RUBRA","version":"8.0.0","status":"online",
"features":["vision","nctb_2026","uiux_pro_max","multilingual","smart_tutor","hermes_coding","exam_generator","live_knowledge"]}
@app.get("/health")
async def health(): return {"status":"ok","time":time.time()}
@app.post("/api/chat")
async def chat(req:ChatRequest):
sid=req.session_id or str(uuid.uuid4()); hist=mem_get(sid)
mem_add(sid,"user",req.message)
lang=detect_lang(req.message)
sinthia_mode = is_sinthia(req.message)
intent,agent=route(req.message,req.task_type,req.mode)
async def stream():
full=""
try:
yield f"data: {json.dumps({'type':'meta','agent':agent.name,'intent':intent,'session_id':sid,'sinthia_mode': sinthia_mode,'lang':lang})}\n\n"
async for evt in agent.run(req.message,hist,sid,lang=lang):
if evt.get("type")=="token": full+=evt.get("content","")
yield f"data: {json.dumps(evt)}\n\n"
if full: mem_add(sid,"assistant",full)
except Exception as e:
log.error(f"Chat: {e}",exc_info=True)
yield f"data: {json.dumps({'type':'error','message':str(e)})}\n\n"
yield "data: [DONE]\n\n"
return StreamingResponse(stream(),media_type="text/event-stream",
headers={"Cache-Control":"no-cache","X-Accel-Buffering":"no","Connection":"keep-alive"})
@app.post("/api/upload")
async def upload(file:UploadFile=File(...),session_id:str=Form(default=""),
question:str=Form(default=""),mode:str=Form(default="")):
sid=session_id or str(uuid.uuid4())
content=await file.read()
fpath=UPLOAD_DIR/f"{sid}_{file.filename}"
fpath.write_bytes(content)
fname=file.filename; ext=Path(fname).suffix.lower()
lang=detect_lang(question); is_image=ext in IMAGE_EXTS
log.info(f"Upload: {fname} ({len(content):,}b) mode={mode}")
async def stream():
full=""
agent_name="SmartTutorAgent" if mode=="tutor" else ("VisionAgent" if is_image else "FileAgent")
yield f"data: {json.dumps({'type':'meta','agent':agent_name,'intent':'file','file':fname,'session_id':sid})}\n\n"
try:
q=question or ("এই question paper টা solve করে দাও" if mode=="tutor" else f"Analyze: {fname}")
hist=mem_get(sid)
if is_image:
b64,mime=to_base64(fpath)
img_d={"data":b64,"mime":mime}
if mode=="tutor":
async for evt in SmartTutorAgent().run(q,hist,sid,lang=lang,img=img_d):
if evt.get("type")=="token": full+=evt.get("content","")
yield f"data: {json.dumps(evt)}\n\n"
else:
async for evt in VisionAgent().run(q,hist,sid,lang=lang,img=img_d):
if evt.get("type")=="token": full+=evt.get("content","")
yield f"data: {json.dumps(evt)}\n\n"
elif mode=="tutor" and ext==".pdf":
text=pdf_to_text(fpath)
enhanced=f"[PDF: {fname}]\n{text[:6000]}\n\nStudent question: {question or 'Solve এবং explain করো'}"
async for evt in SmartTutorAgent().run(enhanced,hist,sid,lang=lang):
if evt.get("type")=="token": full+=evt.get("content","")
yield f"data: {json.dumps(evt)}\n\n"
else:
async for evt in FileAgent().analyze(fpath,fname,q,sid,lang=lang):
if evt.get("type")=="token": full+=evt.get("content","")
yield f"data: {json.dumps(evt)}\n\n"
if full:
mem_add(sid,"user",f"[File: {fname}] {question}")
mem_add(sid,"assistant",full)
except Exception as e:
log.error(f"Upload: {e}",exc_info=True)
yield f"data: {json.dumps({'type':'error','message':str(e)})}\n\n"
yield "data: [DONE]\n\n"
return StreamingResponse(stream(),media_type="text/event-stream",
headers={"Cache-Control":"no-cache","X-Accel-Buffering":"no"})
@app.post("/api/exam/generate")
async def gen_exam(req: ExamRequest):
"""Legacy exam endpoint — basic text format"""
nctb_ctx = ""
for k, v in NCTB_2026.items():
if req.class_.lower() in k.lower() or k.lower() in req.class_.lower():
nctb_ctx = f"\n[NCTB 2026 — {k}]\n{json.dumps(v, ensure_ascii=False)[:800]}"
break
prompt = f"""{EXAM_PROMPT}{nctb_ctx}
Generate complete {req.type_} exam paper:
Subject: {req.subject} | Class: {req.class_} | Topic: {req.topic or 'Full 2026 syllabus'}
Questions: {req.q_count} | Language: {"Bengali (বাংলা)" if req.lang=="bn" else "English"}
Create a realistic NCTB 2026 curriculum exam paper with header, full questions, and answer key."""
msgs = [{"role":"system","content":EXAM_PROMPT},{"role":"user","content":prompt}]
full = ""
async def collect():
nonlocal full
async for tok in llm(msgs,"general"): full += tok
try:
await collect()
return JSONResponse({"ok":True,"paper":full,"subject":req.subject,"class_":req.class_})
except Exception as e:
return JSONResponse({"ok":False,"error":str(e)},status_code=500)
@app.post("/api/exam/advanced")
async def gen_exam_advanced(body: dict):
"""
Production exam generator:
- 30 hard NCTB MCQ questions
- Optional Srijonshil questions
- Exam prediction
- Beautiful PDF output
"""
subject = body.get("subject", "বিজ্ঞান")
class_name = body.get("class_", "Class 10")
topic = body.get("topic", "")
lang = body.get("lang", "bn")
include_sq = body.get("srijonshil", False)
pdf_output = body.get("pdf", True)
try:
# Generate questions via AI
questions = await generate_exam_with_ai(
subject=subject,
class_name=class_name,
topic=topic,
lang=lang,
include_srijonshil=include_sq,
include_prediction=True,
)
if questions.get("error"):
return JSONResponse({"ok": False, "error": questions["error"]}, status_code=500)
result = {
"ok": True,
"subject": subject,
"class_": class_name,
"mcq_count": len(questions.get("mcq", [])),
"srijonshil_count": len(questions.get("srijonshil", [])),
"questions": questions,
}
# Generate PDF if requested
if pdf_output:
try:
pdf_filename = f"rubra_exam_{uuid.uuid4().hex[:8]}.pdf"
pdf_path = str(UPLOAD_DIR / pdf_filename)
time_limit = str(len(questions.get("mcq", [])) * 1) # 1 min per MCQ
total_marks = str(len(questions.get("mcq", [])) + (len(questions.get("srijonshil", [])) * 10))
exam_type_label = "MCQ + সৃজনশীল" if include_sq else "বহুনির্বাচনি (MCQ)"
generate_exam_pdf(
questions_json=questions,
output_path=pdf_path,
subject=subject,
class_name=class_name,
exam_type=exam_type_label,
time_limit=time_limit,
total_marks=total_marks,
)
# Return base64 PDF
import base64 as b64
with open(pdf_path, "rb") as f:
pdf_b64 = b64.b64encode(f.read()).decode()
os.unlink(pdf_path)
result["pdf_b64"] = pdf_b64
result["pdf_filename"] = f"RUBRA_Exam_{subject}_{class_name}.pdf"
except Exception as pdf_err:
log.warning(f"PDF generation failed: {pdf_err}")
result["pdf_error"] = str(pdf_err)
return JSONResponse(result)
except Exception as e:
log.error(f"Advanced exam error: {e}", exc_info=True)
return JSONResponse({"ok": False, "error": str(e)}, status_code=500)
@app.get("/api/exam/predict")
async def exam_predict(subject: str, class_: str, topic: str = ""):
"""Quick exam prediction — কোন topic থেকে এবার বেশি আসতে পারে"""
prompt = f"""বাংলাদেশ Board পরীক্ষায় ({class_}) {subject} বিষয়ে {"topic: " + topic if topic else "সম্পূর্ণ সিলেবাসে"} এবার কোন কোন অধ্যায় থেকে প্রশ্ন আসার সম্ভাবনা সবচেয়ে বেশি?
গত ৫ বছরের pattern বিশ্লেষণ করে বলো:
১. High probability topics (৫০%+ chance)
২. Medium probability topics (৩০-৫০% chance)
৩. যে topics থেকে এবার নতুন ধরনের প্রশ্ন আসতে পারে
৪. শিক্ষার্থীদের কী পড়া উচিত
বাংলায় উত্তর দাও। Specific chapter/topic name উল্লেখ করো।"""
msgs = [{"role":"system","content":TUTOR_ADVANCED_PROMPT},{"role":"user","content":prompt}]
full = ""
try:
async for tok in llm(msgs, "general"): full += tok
return JSONResponse({"ok": True, "prediction": full, "subject": subject, "class_": class_})
except Exception as e:
return JSONResponse({"ok": False, "error": str(e)}, status_code=500)
# Get NCTB context for this class
nctb_ctx=""
for k,v in NCTB_2026.items():
if req.class_.lower() in k.lower() or k.lower() in req.class_.lower():
nctb_ctx=f"\n[NCTB 2026 — {k}]\n{json.dumps(v,ensure_ascii=False)[:800]}"
break
prompt=f"""{EXAM_PROMPT}{nctb_ctx}
Generate complete {req.type_} exam paper:
Subject: {req.subject} | Class: {req.class_} | Topic: {req.topic or 'Full 2026 syllabus'}
Questions: {req.q_count} | Language: {"Bengali (বাংলা)" if req.lang=="bn" else "English"}
Create a realistic NCTB 2026 curriculum exam paper with header, full questions, and answer key."""
msgs=[{"role":"system","content":EXAM_PROMPT},{"role":"user","content":prompt}]
full=""
async def collect():
nonlocal full
async for tok in llm(msgs,"general"): full+=tok
try:
await collect()
return JSONResponse({"ok":True,"paper":full,"subject":req.subject,"class_":req.class_})
except Exception as e:
return JSONResponse({"ok":False,"error":str(e)},status_code=500)
@app.get("/api/curriculum")
async def curriculum(): return {"curriculum":NCTB_2026,"year":"2026","source":"NCTB Bangladesh"}
@app.get("/api/live-feed")
async def live_feed(category:Optional[str]=None,limit:int=10):
return {"items":feed_get(category=category,limit=limit),"category":category}
@app.get("/api/trending")
async def trending():
return {"tech":feed_get("tech",5),"ai":feed_get("ai",3),"news":feed_get("news",5),"fetched_at":time.time()}
@app.get("/api/sessions")
async def sessions(): return {"sessions":mem_sessions()}
@app.get("/api/sessions/{sid}")
async def get_session(sid:str): return {"session_id":sid,"messages":mem_get(sid,100)}
@app.delete("/api/sessions/{sid}")
async def del_session(sid:str): mem_delete(sid); return {"ok":True}
@app.get("/api/status")
async def status():
stats=mem_stats()
return {"version":"8.0.0","stats":stats,
"vision_models":["Groq Llama-4-Scout (vision)","Qwen2.5-VL-72B (OpenRouter free)","GLM-4.5V (Z.AI)","OCR.space (fallback)"],
"features":["vision","nctb_2026","uiux_pro_max","multilingual","smart_tutor","hermes_coding","exam_generator","live_knowledge"]}
# ═══════════════════════════════════════════════════════
# RUBRA LIVE PIPELINE — MODIFIED
#
# Changes from original:
# • "listening" state WebSocket message added
# • "idle" state sent when mic stops / session starts
# • All states: idle → listening → thinking → speaking → done
# ═══════════════════════════════════════════════════════
from fastapi import WebSocket, WebSocketDisconnect
import wave, asyncio, struct, io
GROQ_STT_URL = "https://api.groq.com/openai/v1/audio/transcriptions"
GEMINI_FLASH_URL = "https://generativelanguage.googleapis.com/v1beta/openai/chat/completions"
# ══════════════════════════════════════════════════════
# LIVE CONTROLLER — manages Audio+Vision streams
# ══════════════════════════════════════════════════════
class LiveController:
"""
Gemini Live-style multimodal loop.
WebSocket receives:
{type: audio_chunk|audio_end|frame|frame_clear|text|stop|interrupt|ping}
WebSocket sends:
{type: idle|listening|transcript|thinking|token|tts_chunk|tts_text|done|error|interrupted|pong}
State machine:
idle → listening (mic on)
→ thinking (STT done, LLM starting)
→ speaking (TTS streaming)
→ done / idle
"""
def __init__(self, ws: WebSocket, sid: str):
self.ws = ws
self.sid = sid
self.active = True
self.speaking = False # AI currently speaking
self.listening = False # mic currently recording ← NEW
self.last_frame = None # latest vision frame (base64 jpeg)
self.audio_buf = bytearray() # accumulate audio chunks
self.lang = "en"
self.hist = mem_get(sid, limit=6)
# ── Send helper ─────────────────────────────────────
async def send(self, payload: dict):
try:
await self.ws.send_json(payload)
except Exception:
pass
# ── State helpers ────────────────────────────────────
async def set_idle(self):
"""Stop all states → send idle."""
self.speaking = False
self.listening = False
await self.send({"type": "idle"})
async def set_listening(self):
"""Mic is active → send listening."""
self.listening = True
await self.send({"type": "listening"})
async def set_thinking(self):
"""STT done, LLM starting → send thinking."""
self.listening = False
await self.send({"type": "thinking"})
# ── Interrupt: user started speaking → stop AI ──────
async def interrupt(self):
if self.speaking:
self.speaking = False
await self.send({"type": "interrupted"})
# After interrupt, go back to listening state
await self.set_listening()
# ── STT: transcribe audio chunk via Groq Whisper ────
async def transcribe(self, audio_bytes: bytes) -> str:
if len(audio_bytes) < 300:
return ""
try:
import aiohttp
wav_buf = io.BytesIO()
with wave.open(wav_buf, 'wb') as wf:
wf.setnchannels(1)
wf.setsampwidth(2)
wf.setframerate(16000)
wf.writeframes(audio_bytes)
wav_buf.seek(0)
form = aiohttp.FormData()
form.add_field("file", wav_buf, filename="audio.wav", content_type="audio/wav")
form.add_field("model", "whisper-large-v3-turbo")
form.add_field("response_format", "text")
form.add_field("language", "bn" if self.lang == "bn" else "en")
headers = {"Authorization": f"Bearer {GROQ_KEY}"}
timeout = aiohttp.ClientTimeout(total=12)
async with aiohttp.ClientSession(timeout=timeout) as s:
async with s.post(GROQ_STT_URL, headers=headers, data=form) as r:
if r.status == 200:
return (await r.text()).strip()
log.warning(f"STT {r.status}: {await r.text()}")
except Exception as e:
log.warning(f"STT error: {e}")
return ""
# ── LLM stream with vision frame ────────────────────
async def llm_stream(self, text: str):
"""Stream response from Gemini Flash with optional vision frame."""
sys_p = (
f"{RUBRA_CORE}\n\n"
"[LIVE VOICE MODE] You are in real-time voice conversation. Rules:\n"
"• Responses must be SHORT (1-3 sentences max unless asked)\n"
"• Natural spoken language — no markdown, no bullet points\n"
"• If you see a screen/camera frame, describe what's relevant\n"
"• Language: match user's language exactly\n"
)
if self.lang == "bn":
sys_p += "\n⚡ Reply in Bengali (বাংলা) — short, spoken style."
user_content = []
if self.last_frame:
user_content.append({
"type": "image_url",
"image_url": {
"url": f"data:image/jpeg;base64,{self.last_frame}",
"detail": "low"
}
})
user_content.append({"type": "text", "text": text})
messages = [{"role": "system", "content": sys_p}]
for h in self.hist[-4:]:
if h.get("role") in ("user", "assistant"):
messages.append({"role": h["role"], "content": h["content"]})
messages.append({"role": "user", "content": user_content})
endpoints = [
(GEMINI_FLASH_URL, GEMINI_KEY, "gemini-2.5-flash-preview-05-20"),
(GROQ_URL, GROQ_KEY, "meta-llama/llama-4-scout-17b-16e-instruct"),
(ZAI_CHAT, ZAI_KEY, "glm-4.7-flash"),
]
for url, key, model in endpoints:
try:
import aiohttp
headers = {"Authorization": f"Bearer {key}", "Content-Type": "application/json"}
req_url = f"{url}?key={key}" if "generativelanguage" in url else url
payload = {
"model": model, "messages": messages,
"stream": True, "max_tokens": 300, "temperature": 0.7,
}
timeout = aiohttp.ClientTimeout(total=20, connect=5)
async with aiohttp.ClientSession(timeout=timeout) as s:
async with s.post(req_url, headers=headers, json=payload) as resp:
if resp.status not in (200, 201):
raise Exception(f"HTTP {resp.status}")
async for line in resp.content:
if not self.active or not self.speaking:
return
line = line.decode().strip()
if not line or line == "data: [DONE]":
continue
if line.startswith("data: "):
line = line[6:]
try:
tok = json.loads(line)["choices"][0] \
.get("delta", {}).get("content", "")
if tok:
yield tok
except Exception:
pass
return
except Exception as e:
log.warning(f"Live LLM {model}: {e}")
continue
# ── TTS stream via Edge TTS ──────────────────────────
async def tts_stream(self, text: str):
"""Convert text to audio and stream chunks to client."""
if not text.strip():
return
clean = re.sub(r'[*#`\[\]_~>]', '', text)
clean = re.sub(r'https?://\S+', '', clean)
if self.lang == "bn":
clean = re.sub(r'(\d+)', r' \1 ', clean)
clean = re.sub(r'[(){}\[\]<>|\\/@#$%^&*+=]', ' ', clean)
clean = re.sub(r'\s+', ' ', clean).strip()
if not clean:
return
voice_map = {
"en": ("en-US-AriaNeural", "-8%", "+10Hz"),
"bn": ("bn-BD-NabanitaNeural", "-5%", "+5Hz"),
"bn_roman": ("en-US-AriaNeural", "-8%", "+10Hz"),
}
voice, rate, pitch = voice_map.get(self.lang, voice_map["en"])
try:
import edge_tts
comm = edge_tts.Communicate(clean, voice, rate=rate, pitch=pitch)
async for chunk in comm.stream():
if not self.active or not self.speaking:
return
if chunk["type"] == "audio":
b64 = base64.b64encode(chunk["data"]).decode()
await self.send({"type": "tts_chunk", "audio_b64": b64})
except Exception as e:
log.warning(f"TTS stream error: {e}")
await self.send({"type": "tts_text", "text": clean})
# ── Main response pipeline ───────────────────────────
async def respond(self, text: str):
"""Full pipeline: thinking → LLM stream → TTS stream → idle."""
if not text.strip():
return
self.speaking = True
await self.set_thinking() # ← sends "thinking" to frontend
full_response = ""
sentence_buf = ""
sentence_ends = {'.', '!', '?', '।'}
async for tok in self.llm_stream(text):
if not self.active or not self.speaking:
break
full_response += tok
sentence_buf += tok
await self.send({"type": "token", "content": tok})
if any(c in sentence_buf for c in sentence_ends) and len(sentence_buf) > 12:
asyncio.create_task(self.tts_stream(sentence_buf))
sentence_buf = ""
if sentence_buf.strip() and self.speaking:
asyncio.create_task(self.tts_stream(sentence_buf))
if full_response:
mem_add(self.sid, "user", text)
mem_add(self.sid, "assistant", full_response)
self.hist = mem_get(self.sid, limit=6)
self.speaking = False
await self.send({"type": "done"})
await self.set_idle() # ← sends "idle" after response done
# ── Main WebSocket loop ──────────────────────────────
async def run(self):
"""Process incoming WebSocket messages."""
# Start in idle state
await self.set_idle()
try:
while self.active:
try:
raw = await asyncio.wait_for(
self.ws.receive_json(), timeout=90
)
except asyncio.TimeoutError:
await self.send({"type": "ping"})
continue
msg_type = raw.get("type", "")
# ── Audio chunk from browser ──────────
if msg_type == "audio_chunk":
chunk = base64.b64decode(raw.get("data", ""))
self.audio_buf.extend(chunk)
# ← Tell frontend we're listening (only on first chunk)
if not self.listening and not self.speaking:
await self.set_listening()
# VAD: auto-send if buffer large enough (~500ms audio)
if len(self.audio_buf) > 8000:
audio = bytes(self.audio_buf)
self.audio_buf = bytearray()
if self.speaking:
await self.interrupt()
# Transcribing — stay in listening until STT done
transcript = await self.transcribe(audio)
if transcript and len(transcript) > 2:
self.lang = detect_lang(transcript)
await self.send({"type": "transcript", "text": transcript})
await self.respond(transcript)
else:
# Nothing heard — back to idle
await self.set_idle()
# ── Audio end → transcribe ────────────
elif msg_type == "audio_end":
if self.speaking:
await self.interrupt()
if self.audio_buf:
audio_data = bytes(self.audio_buf)
self.audio_buf = bytearray()
transcript = await self.transcribe(audio_data)
if transcript:
self.lang = detect_lang(transcript)
await self.send({"type": "transcript", "text": transcript})
await self.respond(transcript)
else:
await self.set_idle()
else:
# mic stopped but no audio
await self.set_idle()
# ── Text message (typed) ──────────────
elif msg_type == "text":
if self.speaking:
await self.interrupt()
text = raw.get("text", "").strip()
if text:
self.lang = detect_lang(text)
await self.respond(text)
else:
await self.set_idle()
# ── Vision frame ──────────────────────
elif msg_type == "frame":
frame = raw.get("data", "")
if "base64," in frame:
frame = frame.split("base64,")[1]
self.last_frame = frame[:180000]
elif msg_type == "frame_clear":
self.last_frame = None
# ── Interrupt ─────────────────────────
elif msg_type == "interrupt":
await self.interrupt()
# ── Ping ──────────────────────────────
elif msg_type == "ping":
await self.send({"type": "pong"})
# ── Stop session ──────────────────────
elif msg_type == "stop":
self.active = False
await self.set_idle()
break
except WebSocketDisconnect:
pass
except Exception as e:
log.error(f"LiveController: {e}")
await self.send({"type": "error", "message": str(e)[:100]})
finally:
self.active = False
# ── WebSocket endpoint ──────────────────────────────────
@app.websocket("/ws/live/{session_id}")
async def live_endpoint(websocket: WebSocket, session_id: str):
await websocket.accept()
log.info(f"🔴 Live session: {session_id}")
controller = LiveController(websocket, session_id)
try:
await websocket.send_json({
"type": "ready",
"message": "Rubra Live connected",
"session": session_id,
})
await controller.run()
except WebSocketDisconnect:
pass
finally:
controller.active = False
log.info(f"⭕ Live session ended: {session_id}")
# ── Live mode via SSE (HuggingFace compatible) ──────────
import asyncio
_live_sessions = {} # session_id → asyncio.Queue
_live_frames = {}
@app.post("/api/live/frame")
async def live_frame(body: dict):
sid = body.get("session_id", "default")
frame = body.get("frame", "")
if "base64," in frame:
frame = frame.split("base64,")[1]
_live_frames[sid] = frame[:180000]
return JSONResponse({"ok": True})
@app.post("/api/live/send")
async def live_send(body: dict):
sid = body.get("session_id", "default")
text = (body.get("text") or "").strip()
if not text:
return JSONResponse({"error": "no text"}, status_code=400)
if sid not in _live_sessions:
_live_sessions[sid] = asyncio.Queue()
detected = detect_lang(text)
await _live_sessions[sid].put({"text": text, "lang": detected})
return JSONResponse({"ok": True, "detected_lang": detected, "received": text})
@app.get("/api/live/stream/{session_id}")
async def live_stream(session_id: str):
if session_id not in _live_sessions:
_live_sessions[session_id] = asyncio.Queue()
async def generate():
hist = mem_get(session_id, limit=6)
yield f"data: {json.dumps({'type':'ready'})}\n\n"
while True:
try:
item = await asyncio.wait_for(
_live_sessions[session_id].get(), timeout=30
)
except asyncio.TimeoutError:
yield f"data: {json.dumps({'type':'ping'})}\n\n"
continue
text = item["text"]
detected_lang = detect_lang(text)
yield f"data: {json.dumps({'type':'thinking'})}\n\n"
sys_p = (
f"{RUBRA_CORE}\n\n"
"[LIVE VOICE MODE RULES]\n"
"• SHORT answers — 1-3 sentences for simple questions\n"
"• No markdown, no bullet points — natural spoken language only\n"
"• Even if user types broken/unclear text, understand intent and answer correctly\n"
"• If user text looks like speech-to-text errors, fix and understand it\n"
"• Match user language exactly\n"
)
if detected_lang == "bn":
sys_p += "• বাংলায় উত্তর দাও। সংক্ষিপ্ত, স্বাভাবিক কথার ভাষায়।\n"
messages = [{"role": "system", "content": sys_p}]
for h in hist[-4:]:
if h.get("role") in ("user", "assistant"):
messages.append({"role": h["role"], "content": h["content"]})
frame = _live_frames.get(session_id)
if frame:
messages.append({"role": "user", "content": [
{"type": "image_url", "image_url": {
"url": f"data:image/jpeg;base64,{frame}",
"detail": "low"
}},
{"type": "text", "text": text}
]})
else:
messages.append({"role": "user", "content": text})
fast_endpoints = [
(GROQ_URL, GROQ_KEY, "llama-3.3-70b-versaetil"),
(CEREBRAS_URL, CEREBRAS_KEY, "llama-3.3-70b"),
(CEREBRAS_URL, CEREBRAS_KEY, "llama-4-scout-17b-16e-instruct"),
(GROQ_URL, GROQ_KEY, "meta-llama/llama-4-scout-17b-16e-instruct"),
(ZAI_CHAT, ZAI_KEY, "glm-4.7-flash"),
]
full = ""
for url, key, model in fast_endpoints:
try:
headers = {"Authorization": f"Bearer {key}", "Content-Type": "application/json"}
req_url = f"{url}?key={key}" if "generativelanguage" in url else url
payload = {
"model": model, "messages": messages,
"stream": True, "max_tokens": 150, "temperature": 0.7
}
timeout = aiohttp.ClientTimeout(total=15, connect=4)
async with aiohttp.ClientSession(timeout=timeout) as s:
async with s.post(req_url, headers=headers, json=payload) as resp:
if resp.status not in (200, 201):
raise Exception(f"HTTP {resp.status}")
async for line in resp.content:
line = line.decode().strip()
if not line or line == "data: [DONE]": continue
if line.startswith("data: "): line = line[6:]
try:
tok = json.loads(line)["choices"][0].get("delta", {}).get("content", "")
if tok:
full += tok
yield f"data: {json.dumps({'type':'token','content':tok})}\n\n"
except: pass
if full: break
except Exception as e:
# log.warning(f"Live {model}: {e}") # নিশ্চিত করুন log ভেরিয়েবল ডিফাইন করা আছে
continue
if full:
mem_add(session_id, "user", text)
mem_add(session_id, "assistant", full)
hist = mem_get(session_id, limit=6)
try:
import edge_tts
def clean_for_tts(text: str, lang: str) -> str:
text = re.sub(r'[*#`\[\]_~>]', '', text)
text = re.sub(r'https?://\S+', '', text)
if lang == "bn":
text = re.sub(r'(\d+)', r' \1 ', text)
text = re.sub(r'[(){}\[\]<>|\\/@#$%^&*+=]', ' ', text)
text = re.sub(r'\s+', ' ', text).strip()
return text[:500]
tts_text = clean_for_tts(full, detected_lang)
if not tts_text:
raise ValueError("Empty TTS text")
if detected_lang == "bn":
voice = "bn-BD-NabanitaNeural"
rate = "-10%"
pitch = "+0Hz"
elif detected_lang == "bn_roman":
voice = "en-US-AriaNeural"
rate = "-8%"
pitch = "+10Hz"
else:
voice = "en-US-AriaNeural"
rate = "-8%"
pitch = "+10Hz"
tmp = HERE / f"_live_{uuid.uuid4().hex[:6]}.mp3"
communicate = edge_tts.Communicate(tts_text, voice, rate=rate, pitch=pitch)
await communicate.save(str(tmp))
if tmp.exists() and tmp.stat().st_size > 100:
b64 = base64.b64encode(tmp.read_bytes()).decode()
tmp.unlink(missing_ok=True)
yield f"data: {json.dumps({'type':'tts_chunk','audio_b64':b64})}\n\n"
else:
tmp.unlink(missing_ok=True)
raise ValueError("TTS file empty")
except Exception as tts_err:
log.warning(f"TTS failed: {tts_err}")
yield f"data: {json.dumps({'type':'tts_text','text':full})}\n\n"
return StreamingResponse(
generate(),
media_type="text/event-stream",
headers={"Cache-Control": "no-cache", "X-Accel-Buffering": "no"}
)
@app.get("/api/tools/weather")
async def w(city:str="Dhaka"): return tool_weather(city) or {"error":"Unavailable"}
@app.get("/api/tools/crypto")
async def c(coins:str="bitcoin,ethereum"): return tool_crypto(coins) or {"error":"Unavailable"}
@app.get("/api/tools/currency")
async def fx(base:str="USD"): return tool_currency(base) or {"error":"Unavailable"}
# ═══════════════════════════════════════════════════════
# Voice profile cloned from uploaded audio sample:
# Pitch: 228 Hz mean (Soprano Female)
# Timbre: 2287 Hz (Bright/Clear)
# Pace: 2.9 syl/s (Calm, measured)
# Expression: High (StdDev 56.8 Hz)
# Best match: en-US-AriaNeural
# ═══════════════════════════════════════════════════════
RUBRA_VOICE_PROFILE = {
"en": {"voice": "en-US-AriaNeural", "rate": "-8%", "pitch": "+10Hz", "style": "assistant"},
"bn": {"voice": "bn-BD-NabanitaNeural", "rate": "-5%", "pitch": "+5Hz", "style": ""},
"bn_roman": {"voice": "en-US-AriaNeural", "rate": "-8%", "pitch": "+10Hz", "style": "assistant"},
}
@app.post("/api/tts")
async def tts_endpoint(body: dict):
text = (body.get("text") or "").strip()[:700]
lang = body.get("lang", "en")
if not text:
return JSONResponse({"error": "No text provided"}, status_code=400)
clean = re.sub(r'[*#`\[\]_~>]', '', text)
clean = re.sub(r'https?://\S+', '', clean)
if lang == "bn":
clean = re.sub(r'(\d+)', r' \1 ', clean)
clean = re.sub(r'[(){}\[\]<>|\\/@#$%^&*+=]', ' ', clean)
clean = re.sub(r'\s+', ' ', clean).strip()
if not clean:
return JSONResponse({"error": "Empty text after cleaning"}, status_code=400)
profile = RUBRA_VOICE_PROFILE.get(lang, RUBRA_VOICE_PROFILE["en"])
voice = profile["voice"]
rate = profile["rate"]
pitch = profile["pitch"]
if lang == "bn":
rate = "-10%"
pitch = "+0Hz"
try:
import edge_tts
communicate = edge_tts.Communicate(clean, voice, rate=rate, pitch=pitch)
tmp_path = HERE / f"_tts_{uuid.uuid4().hex[:8]}.mp3"
await communicate.save(str(tmp_path))
if not tmp_path.exists() or tmp_path.stat().st_size < 100:
tmp_path.unlink(missing_ok=True)
return JSONResponse({"error": "TTS generation failed"}, status_code=500)
audio_bytes = tmp_path.read_bytes()
tmp_path.unlink(missing_ok=True)
b64 = base64.b64encode(audio_bytes).decode()
return JSONResponse({
"audio_b64": b64,
"voice": voice,
"lang": lang,
"duration_est": len(clean) / 15,
})
except ImportError:
return JSONResponse(
{"error": "edge-tts not installed. Run: pip install edge-tts"},
status_code=500
)
except Exception as e:
log.warning(f"TTS error: {e}")
return JSONResponse({"error": str(e)[:200]}, status_code=500)
@app.get("/api/tts/voices")
async def tts_voices():
"""List available Edge TTS female voices."""
try:
import edge_tts
all_voices = await edge_tts.list_voices()
female = [
{"name": v["ShortName"], "lang": v["Locale"], "gender": v["Gender"]}
for v in all_voices if v.get("Gender") == "Female"
]
return {"voices": female, "rubra_primary": "en-US-AriaNeural"}
except ImportError:
return {"error": "pip install edge-tts"}
#---------------voice tts endpoint
@app.get("/api/skills")
async def list_skills_route():
skills = skill_list()
return {"skills":[{"name":s,"lines":len((SKILLS_DIR/f"{s}.py").read_text().splitlines())} for s in skills],"count":len(skills)}
@app.post("/api/skills/generate")
async def gen_skill(body: dict):
name=re.sub(r"[^a-z0-9_]","_",body.get("name","custom").lower()); task=body.get("task","")
if not task: return JSONResponse({"error":"task required"},status_code=400)
code=await skill_generate_and_save(name,task)
return {"name":name,"code":code,"saved":True}
@app.get("/api/session/{sid}/memory")
async def get_memory(sid:str): return session_load(sid)
@app.get("/api/session/{sid}/thoughts")
async def get_thoughts(sid:str):
data=session_load(sid); return {"thoughts":data.get("thought_chain",[])[-10:]}
if __name__=="__main__":
import uvicorn
PORT=int(os.getenv("PORT",7860))
print()
print("="*60)
print(" RUBRA v8 — Ultimate Agentic Intelligence")
print(" ✓ Vision: Groq Vision + Qwen2.5-VL + OCR.space")
print(" ✓ NCTB 2026 Full Curriculum Built-in")
print(" ✓ UI/UX Pro Max Coding (67 styles, 161 rules)")
print(" ✓ Hermes Ultra Coding Engine")
print(" ✓ Multilingual: Bangla/Banglish/English")
print(" ✓ Smart Tutor (JSC/SSC/HSC/Primary)")
print(" ✓ Live Knowledge (auto-updates every 25min)")
print(f" Running on port {PORT}")
print("="*60)
print()
uvicorn.run(app,host="0.0.0.0",port=PORT,reload=False)