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
```sql
-- 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
```json
{
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"token_type": "bearer"
}
```
### POST /api/predict/single
```json
{
"predicted_rating": 5,
"confidence_score": 0.92,
"comment": "SαΊ£n phαΊ©m rαΊ₯t tα»‘t..."
}
```
### POST /api/predict/batch
```json
{
"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)