Predict_Rating / ARCHITECTURE.md
vtdung23's picture
Upload folder using huggingface_hub
c09e844 verified

πŸ—οΈ System Architecture

High-Level Architecture

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                         FRONTEND                            β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”     β”‚
β”‚  β”‚   Login/     β”‚  β”‚   Dashboard  β”‚  β”‚   Register   β”‚     β”‚
β”‚  β”‚  Register    β”‚  β”‚   (Jinja2)   β”‚  β”‚    Page      β”‚     β”‚
β”‚  β”‚  (Jinja2)    β”‚  β”‚ + TailwindCSSβ”‚  β”‚  (Jinja2)    β”‚     β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜     β”‚
β”‚         β”‚                  β”‚                  β”‚             β”‚
β”‚         β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜             β”‚
β”‚                            β”‚                                β”‚
β”‚                   JavaScript (Fetch API)                    β”‚
β”‚                     + Chart.js for viz                      β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”‚β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                             β”‚
                             β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                    FASTAPI BACKEND                          β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”     β”‚
β”‚  β”‚                  API ROUTERS                      β”‚     β”‚
β”‚  β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”       β”‚     β”‚
β”‚  β”‚  β”‚   Auth   β”‚  β”‚Predictionβ”‚  β”‚Dashboard β”‚       β”‚     β”‚
β”‚  β”‚  β”‚  Router  β”‚  β”‚  Router  β”‚  β”‚  Router  β”‚       β”‚     β”‚
β”‚  β”‚  β”‚ /api/authβ”‚  β”‚/api/pred β”‚  β”‚  /pages  β”‚       β”‚     β”‚
β”‚  β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜       β”‚     β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜     β”‚
β”‚                            β”‚                                β”‚
β”‚                            β–Ό                                β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”     β”‚
β”‚  β”‚                   SERVICES                        β”‚     β”‚
β”‚  β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”             β”‚     β”‚
β”‚  β”‚  β”‚     Auth     β”‚  β”‚      ML      β”‚             β”‚     β”‚
β”‚  β”‚  β”‚   Service    β”‚  β”‚   Service    β”‚             β”‚     β”‚
β”‚  β”‚  β”‚(JWT, bcrypt) β”‚  β”‚  (Model)     β”‚             β”‚     β”‚
β”‚  β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜             β”‚     β”‚
β”‚  β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”           β”‚     β”‚
β”‚  β”‚  β”‚   Visualization Service          β”‚           β”‚     β”‚
β”‚  β”‚  β”‚  (WordCloud, Charts)             β”‚           β”‚     β”‚
β”‚  β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜           β”‚     β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜     β”‚
β”‚                            β”‚                                β”‚
β”‚                            β–Ό                                β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”     β”‚
β”‚  β”‚              DATA LAYER                           β”‚     β”‚
β”‚  β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”         β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”               β”‚     β”‚
β”‚  β”‚  β”‚ SQLAlchemyβ”‚        β”‚ Pydantic β”‚               β”‚     β”‚
β”‚  β”‚  β”‚  Models   β”‚        β”‚ Schemas  β”‚               β”‚     β”‚
β”‚  β”‚  β”‚(ORM Layer)β”‚        β”‚(Validation)              β”‚     β”‚
β”‚  β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜         β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜               β”‚     β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜     β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”‚β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                             β”‚
                             β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                      DATABASE                               β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”        β”‚
β”‚  β”‚    Users Table       β”‚  β”‚ PredictionHistory    β”‚        β”‚
β”‚  β”‚  - id (PK)           β”‚  β”‚  - id (PK)           β”‚        β”‚
β”‚  β”‚  - username          β”‚  β”‚  - user_id (FK)      β”‚        β”‚
β”‚  β”‚  - email             β”‚  β”‚  - product_name      β”‚        β”‚
β”‚  β”‚  - hashed_password   β”‚  β”‚  - comment           β”‚        β”‚
β”‚  β”‚  - created_at        β”‚  β”‚  - predicted_rating  β”‚        β”‚
β”‚  β”‚                      β”‚  β”‚  - confidence_score  β”‚        β”‚
β”‚  β”‚                      β”‚  β”‚  - created_at        β”‚        β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜        β”‚
β”‚                SQLite Database                              β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Request Flow Examples

1️⃣ User Login Flow

User enters credentials
        β”‚
        β–Ό
[Login.html]
        β”‚
        β–Ό
POST /api/auth/login
        β”‚
        β–Ό
[Auth Router]
        β”‚
        β–Ό
[Auth Service] ──► Verify password (bcrypt)
        β”‚          Generate JWT token
        β–Ό
[Database] ──► Query User table
        β”‚
        β–Ό
Return JWT token to frontend
        β”‚
        β–Ό
Store token in localStorage
        β”‚
        β–Ό
Redirect to /dashboard

2️⃣ Single Prediction Flow

User enters comment
        β”‚
        β–Ό
[Dashboard.html]
        β”‚
        β–Ό
POST /api/predict/single
(with JWT token in header)
        β”‚
        β–Ό
[Prediction Router]
        β”‚
        β–Ό
[Auth Service] ──► Verify JWT token
        β”‚
        β–Ό
[ML Service] ──► predict_single(comment)
        β”‚         (DUMMY: return random rating)
        β–Ό
[Database] ──► Save to PredictionHistory
        β”‚
        β–Ό
Return {rating, confidence}
        β”‚
        β–Ό
Display result in UI

3️⃣ Batch CSV Prediction Flow

User uploads CSV file
        β”‚
        β–Ό
[Dashboard.html]
        β”‚
        β–Ό
POST /api/predict/batch
(multipart/form-data)
        β”‚
        β–Ό
[Prediction Router]
        β”‚
        β–Ό
Parse CSV ──► Extract comments
        β”‚
        β–Ό
[ML Service] ──► predict_batch(comments)
        β”‚         For each comment:
        β”‚         predict_single()
        β–Ό
[Visualization Service]
        β”‚
        β”œβ”€β”€β–Ί generate_wordcloud()
        β”‚    Save PNG to /static/uploads/
        β”‚
        └──► calculate_rating_distribution()
             Count 1⭐, 2⭐, 3⭐, 4⭐, 5⭐
        β”‚
        β–Ό
[Database] ──► Save all predictions
        β”‚
        β–Ό
Return:
- wordcloud_url
- rating_distribution
- results array
        β”‚
        β–Ό
[Dashboard.html]
        β”‚
        β”œβ”€β”€β–Ί Render Chart.js bar chart
        β”œβ”€β”€β–Ί Display word cloud image
        β”œβ”€β”€β–Ί Populate results table
        └──► Enable CSV download

Technology Stack Details

Backend

FastAPI (0.104.1)
β”œβ”€β”€ Auto-generates Swagger UI (/docs)
β”œβ”€β”€ Automatic data validation (Pydantic)
β”œβ”€β”€ Async support
└── Built-in dependency injection

SQLAlchemy (2.0.23)
β”œβ”€β”€ ORM for database operations
β”œβ”€β”€ Models: User, PredictionHistory
└── Automatic table creation

JWT Authentication
β”œβ”€β”€ python-jose for token generation
β”œβ”€β”€ passlib[bcrypt] for password hashing
└── OAuth2PasswordBearer for token validation

Frontend

Jinja2 Templates
β”œβ”€β”€ Server-side rendering
β”œβ”€β”€ Template inheritance (base.html)
└── Context variables from backend

TailwindCSS (CDN)
β”œβ”€β”€ Utility-first CSS framework
β”œβ”€β”€ Responsive design
└── Custom animations

Chart.js (CDN)
β”œβ”€β”€ Interactive bar charts
└── Rating distribution visualization

JavaScript (Vanilla)
β”œβ”€β”€ Fetch API for HTTP requests
β”œβ”€β”€ LocalStorage for JWT token
└── Dynamic DOM manipulation

Visualization

WordCloud (1.9.3)
β”œβ”€β”€ Generate word cloud images
β”œβ”€β”€ Vietnamese stopwords support
└── Save to PNG files

Matplotlib (3.8.2)
β”œβ”€β”€ Render word cloud to image
└── Non-GUI backend (Agg)

File Responsibilities

Backend Files

File Purpose
main.py FastAPI app initialization, router inclusion
config.py Configuration (SECRET_KEY, products list)
database.py SQLAlchemy engine, session management
models.py Database table definitions (User, PredictionHistory)
schemas.py Pydantic models for request/response validation

Router Files

File Purpose
routers/auth.py Register, login, get current user
routers/prediction.py Single/batch prediction, history
routers/dashboard.py Serve HTML pages (login, register, dashboard)

Service Files

File Purpose
services/auth_service.py JWT generation, password hashing, token validation
services/ml_service.py ML model wrapper, prediction logic (DUMMY)
services/visualization_service.py WordCloud generation, chart data

Frontend Files

File Purpose
templates/base.html Base layout with navigation, CDN imports
templates/login.html Login form with JWT handling
templates/register.html Registration form
templates/dashboard.html Main interface (product select, predictions, viz)

Security Features

  1. Password Hashing: bcrypt with salt
  2. JWT Tokens: Signed with SECRET_KEY (HS256)
  3. Token Expiration: 24 hours
  4. Protected Routes: Dependency injection (get_current_user)
  5. CORS: Configured for security
  6. Input Validation: Pydantic schemas

Database Schema

-- Users Table
CREATE TABLE users (
    id INTEGER PRIMARY KEY,
    username VARCHAR(50) UNIQUE NOT NULL,
    email VARCHAR(100) UNIQUE NOT NULL,
    hashed_password VARCHAR(255) NOT NULL,
    created_at DATETIME DEFAULT CURRENT_TIMESTAMP
);

-- PredictionHistory Table
CREATE TABLE prediction_history (
    id INTEGER PRIMARY KEY,
    user_id INTEGER NOT NULL,
    product_name VARCHAR(200) NOT NULL,
    comment TEXT NOT NULL,
    predicted_rating INTEGER NOT NULL,
    confidence_score FLOAT,
    prediction_type VARCHAR(20) DEFAULT 'single',
    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
    FOREIGN KEY (user_id) REFERENCES users(id)
);

API Response Examples

POST /api/auth/login

{
  "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
  "token_type": "bearer"
}

POST /api/predict/single

{
  "predicted_rating": 5,
  "confidence_score": 0.92,
  "comment": "SαΊ£n phαΊ©m rαΊ₯t tα»‘t..."
}

POST /api/predict/batch

{
  "total_predictions": 20,
  "rating_distribution": {
    "1": 2,
    "2": 3,
    "3": 5,
    "4": 6,
    "5": 4
  },
  "wordcloud_url": "/static/uploads/wordclouds/wordcloud_20241125_143022.png",
  "results": [
    {
      "Comment": "SαΊ£n phαΊ©m tα»‘t",
      "Predicted_Rating": 5,
      "Confidence": 0.95
    }
  ],
  "csv_download_url": "/api/predict/download/1/1700924622.123"
}

Deployment Checklist

Before production:

  • Change SECRET_KEY in config.py
  • Set reload=False in uvicorn
  • Configure CORS properly
  • Use PostgreSQL instead of SQLite
  • Add environment variables (.env file)
  • Set up HTTPS
  • Add rate limiting
  • Configure logging
  • Add error monitoring
  • Set up backup strategy

This architecture provides: βœ… Separation of Concerns βœ… Scalability (easy to add features) βœ… Maintainability (clear file structure) βœ… Security (JWT, password hashing) βœ… Documentation (auto-generated Swagger) βœ… Testing (clear API endpoints)