> ## Documentation Index
> Fetch the complete documentation index at: https://cseakdeniz.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Implementation

> Technology stack, code structure, and key components

## Technology Stack

<CardGroup cols={2}>
  <Card title="Backend" icon="python" color="#3776AB">
    FastAPI with async support
  </Card>

  <Card title="Database" icon="database" color="#47A248">
    MongoDB with Motor async driver
  </Card>

  <Card title="AI/ML" icon="brain" color="#4285F4">
    Google Gemini 2.5 Flash
  </Card>

  <Card title="Classification" icon="robot" color="#FF6F00">
    Ollama (Qwen2 7B)
  </Card>
</CardGroup>

<Accordion title="Full Technology List" icon="list" defaultOpen>
  | Category | Technology | Purpose |
  | - | - | - |
  | **Backend Framework** | FastAPI | High-performance async API |
  | **Database** | MongoDB + Motor | Flexible schema, async driver |
  | **AI/ML** | Google Gemini 2.5 Flash | Chat generation, image parsing |
  | **AI/ML** | Ollama (Qwen2 7B) | Local intent classification |
  | **String Matching** | TheFuzz | Fuzzy keyword matching |
  | **WhatsApp** | WPPConnect | WhatsApp Web automation |
  | **Scheduler** | APScheduler | Data pipeline cron jobs |
</Accordion>

***

## Key Components

<Tabs>
  <Tab title="Intent Classifier" icon="brain">
    **Location**: `backend/app/llm_engine/classifier.py`

    Combines **Strategy** and **Factory** patterns:

    ```python theme={null}
    CLASSIFIER_MAP = {
        "ollama": _create_ollama_classifier,
        "fuzzy": _create_fuzzy_classifier,
        "hybrid": _create_hybrid_classifier,
    }

    def get_classifier() -> IntentClassifier:
        method = settings.CLASSIFICATION_METHOD
        factory_fn = CLASSIFIER_MAP.get(method)
        return factory_fn()
    ```

    <Tip>
      Configure via `.env`: `CLASSIFICATION_METHOD=hybrid`
    </Tip>
  </Tab>

  <Tab title="Context Strategies" icon="arrows-split-up-and-left">
    **Location**: `backend/app/strategies/context_strategies.py`

    Each strategy encapsulates data fetching + LLM formatting:

    ```python theme={null}
    class DiningStrategy(ContextStrategy):
        async def fetch(self, query: str) -> str:
            raw_menus = await fetch_dining_data_raw()
            return self._format_for_llm(raw_menus)
    ```

    | Strategy | Data Source |
    | - | - |
    | `DiningStrategy` | MongoDB menus collection |
    | `AnnouncementStrategy` | MongoDB announcements |
    | `GeneralStrategy` | No database (fallback) |
  </Tab>

  <Tab title="MongoDB Singleton" icon="database">
    **Location**: `backend/app/db/mongo.py`

    Thread-safe singleton with lazy initialization:

    ```python theme={null}
    class MongoDB:
        def __init__(self):
            self._client = None
            self._initialized = False
        
        @property
        def client(self):
            if self._client is None:
                raise RuntimeError("Not connected")
            return self._client

    db = MongoDB()  # Global singleton
    ```

    <Warning>
      Always call `connect_to_mongo()` in app startup event!
    </Warning>
  </Tab>

  <Tab title="Data Pipeline" icon="arrows-rotate">
    **Location**: `data-pipeline/`

    | Job | Schedule | Action |
    | - | - | - |
    | **Menu Sync** | Daily 8:00 | Scrape → Gemini Vision → MongoDB |
    | **Announcement Sync** | Hourly | Scrape → Parse → MongoDB |

    ```python theme={null}
    # Menu extraction with Gemini Vision
    image_bytes = download_menu_image()
    json_menu = await gemini_client.parse_image(image_bytes)
    await db.menus.insert_one(json_menu)
    ```
  </Tab>
</Tabs>

***

## Configuration

<Tabs>
  <Tab title="Environment Variables" icon="gear">
    ```env theme={null}
    # Database
    MONGO_CONNECTION_STRING=mongodb://localhost:27017
    MONGO_DB_NAME=chatbot

    # AI Services
    GEMINI_API_KEY=your_api_key
    OLLAMA_BASE_URL=http://localhost:11434
    OLLAMA_MODEL=qwen2:7b

    # Classification
    CLASSIFICATION_METHOD=hybrid
    FUZZY_THRESHOLD=80
    ```
  </Tab>

  <Tab title="Pydantic Settings" icon="python">
    ```python theme={null}
    from pydantic_settings import BaseSettings

    class Settings(BaseSettings):
        MONGO_CONNECTION_STRING: str
        GEMINI_API_KEY: str
        CLASSIFICATION_METHOD: Literal["ollama", "fuzzy", "hybrid"] = "hybrid"
        
        model_config = SettingsConfigDict(env_file=".env")

    settings = Settings()
    ```
  </Tab>
</Tabs>

***

## Running the Project

<Steps>
  <Step title="Clone & Setup">
    ```bash theme={null}
    git clone https://github.com/Akdeniz-CSE-Students/csebot_documentation/.git
    cd ChatbotForCse
    cp .env.example .env  # Configure your API keys
    ```
  </Step>

  <Step title="Start Backend">
    ```bash theme={null}
    cd backend
    pip install -r requirements.txt
    uvicorn main:app --reload
    ```
  </Step>

  <Step title="Start WhatsApp Client">
    ```bash theme={null}
    cd whatsapp
    npm install
    npm start  # First run requires QR scan
    ```
  </Step>

  <Step title="Start Data Pipeline (Optional)">
    ```bash theme={null}
    cd data-pipeline
    pip install -r requirements.txt
    python jobs/run_scheduler.py
    ```
  </Step>
</Steps>

***

## Testing

<Accordion title="Running Tests" icon="flask-vial">
  ```bash theme={null}
  # Run classifier tests
  cd backend
  pytest test_classifier.py -v
  ```

  **Mock injection example:**

  ```python theme={null}
  def test_hybrid_fallback():
      reset_classifier()  # Reset singleton
      
      classifier = get_classifier()
      result = await classifier.classify("test message")
      
      assert result in ["dining", "announcement", "general"]
  ```
</Accordion>

<Note>
  The `reset_classifier()` function allows injecting mock classifiers for testing.
</Note>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.