Spaces:
Sleeping
Sleeping
| # ============================================================ | |
| # FILE: app/api.py | |
| # PURPOSE: Acts as the central "loader" for all heavy AI objects. | |
| # Streamlit reruns the entire script on every user action, | |
| # so we use @st.cache_resource to load models ONCE and | |
| # reuse the same object for the entire app session. | |
| # ============================================================ | |
| import os # Standard library: used to build file paths safely | |
| import sys # Standard library: used to modify Python's module search path | |
| import streamlit as st # Streamlit: the web framework powering the entire UI | |
| # βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| # PATH SETUP BLOCK | |
| # Problem: This file lives inside app/ but our source code lives | |
| # in src/ (one level up). Python won't find src/ unless | |
| # we manually tell it where to look. | |
| # βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| # Get the absolute path of THIS file (e.g., /home/user/project/app/api.py) | |
| current_dir = os.path.dirname(os.path.abspath(__file__)) | |
| # Go one level UP from app/ to reach the project root (e.g., /home/user/project/) | |
| project_root = os.path.abspath(os.path.join(current_dir, "../")) | |
| # Only add the project root to sys.path if it isn't already there. | |
| # sys.path is the list of directories Python searches when you do "import X". | |
| if project_root not in sys.path: | |
| sys.path.append(project_root) | |
| # βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| # IMPORTS β now safe because project_root is on sys.path | |
| # βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| # Import our main chatbot class from src/chatbot/groq_bot.py | |
| from src.chatbot.groq_bot import MindGuardChatbot | |
| # Import our SHAP explainability class from src/explainability/shap_explainer.py | |
| from src.explainability.shap_explainer import MindGuardSHAPExplainer | |
| # βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| # CACHED LOADER: MindGuard Chatbot | |
| # βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| # <-- This decorator is the KEY. It tells Streamlit: | |
| # "Run this function only ONCE. After that, return the | |
| # same object every time instead of rebuilding it." | |
| # Without this, the bot would reload on every keypress. | |
| def get_mindguard_bot(): | |
| """ | |
| Instantiates the MindGuardChatbot and keeps it alive in memory. | |
| This loads: | |
| - The Groq LLM connection | |
| - The Whisper audio transcription model | |
| - The SQLite database connection | |
| All of these are expensive to create, so we create them once. | |
| """ | |
| return MindGuardChatbot() # Create and return a new bot instance | |
| # βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| # CACHED LOADER: SHAP Explainer | |
| # βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| # Same caching strategy as above β critical here because | |
| # MindGuardSHAPExplainer loads a full XLM-RoBERTa model | |
| # (~1.1GB weights) which takes ~10-15 seconds to load. | |
| # Caching means that cost is paid only once at startup. | |
| def get_shap_explainer(): | |
| """ | |
| Instantiates the MindGuardSHAPExplainer and keeps it alive in memory. | |
| This loads: | |
| - XLMRobertaTokenizer (converts text to token IDs) | |
| - XLMRobertaForSequenceClassification (the 35-emotion neural network) | |
| - shap.Explainer (the Game Theory math engine wrapped around the model) | |
| All three are heavy objects β caching is non-negotiable for a smooth UX. | |
| """ | |
| return MindGuardSHAPExplainer() # Create and return a new explainer instance |