Spaces:
Runtime error
Runtime error
Aryan Mishra commited on
Commit ·
90e5963
1
Parent(s): 2417b88
Expand architecture documentation
Browse filesAdd detailed documentation for the API, database, deployment, security, tech stack, and system design. Update the main architecture doc to reflect the full multilingual ABSA pipeline, deployment flow, and MLOps stack.
- docs/API_DOCUMENTATION.md +240 -0
- docs/DATABASE.md +116 -0
- docs/DEPLOYMENT.md +136 -0
- docs/SECURITY.md +67 -0
- docs/SYSTEM_DESIGN.md +142 -0
- docs/TECH_STACK.md +97 -0
- docs/architecture.md +273 -23
docs/API_DOCUMENTATION.md
ADDED
|
@@ -0,0 +1,240 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# API Documentation — Multilingual ABSA
|
| 2 |
+
|
| 3 |
+
## Base URL
|
| 4 |
+
|
| 5 |
+
- Local development: `http://localhost:8000`
|
| 6 |
+
- Production: `https://your-railway-app.up.railway.app`
|
| 7 |
+
|
| 8 |
+
## Authentication
|
| 9 |
+
|
| 10 |
+
Currently **none**. All endpoints are publicly accessible.
|
| 11 |
+
|
| 12 |
+
## Endpoints
|
| 13 |
+
|
| 14 |
+
### POST /predict
|
| 15 |
+
|
| 16 |
+
Analyze a single review for aspect-based sentiment.
|
| 17 |
+
|
| 18 |
+
**Request Body:**
|
| 19 |
+
```json
|
| 20 |
+
{
|
| 21 |
+
"text": "The food was great but the service was terrible.",
|
| 22 |
+
"language": "en"
|
| 23 |
+
}
|
| 24 |
+
```
|
| 25 |
+
|
| 26 |
+
| Field | Type | Required | Description |
|
| 27 |
+
|-------|------|----------|-------------|
|
| 28 |
+
| `text` | string | Yes | Review text to analyze |
|
| 29 |
+
| `language` | string | No | Force language (`"en"`, `"hi"`, `"hinglish"`). Auto-detected if omitted |
|
| 30 |
+
|
| 31 |
+
**Response `200`:**
|
| 32 |
+
|
| 33 |
+
```json
|
| 34 |
+
{
|
| 35 |
+
"text": "The food was great but the service was terrible.",
|
| 36 |
+
"language": "en",
|
| 37 |
+
"detected_language": "en",
|
| 38 |
+
"aspects": [
|
| 39 |
+
{
|
| 40 |
+
"aspect": "Food",
|
| 41 |
+
"sentiment": "positive",
|
| 42 |
+
"confidence": 0.85,
|
| 43 |
+
"start": 4,
|
| 44 |
+
"end": 8
|
| 45 |
+
},
|
| 46 |
+
{
|
| 47 |
+
"aspect": "Service",
|
| 48 |
+
"sentiment": "negative",
|
| 49 |
+
"confidence": 0.82,
|
| 50 |
+
"start": 27,
|
| 51 |
+
"end": 34
|
| 52 |
+
}
|
| 53 |
+
],
|
| 54 |
+
"processing_time_ms": 185.3
|
| 55 |
+
}
|
| 56 |
+
```
|
| 57 |
+
|
| 58 |
+
| Field | Type | Description |
|
| 59 |
+
|-------|------|-------------|
|
| 60 |
+
| `text` | string | Original input text |
|
| 61 |
+
| `language` | string | Language used (detected or forced) |
|
| 62 |
+
| `detected_language` | string | Auto-detected language code |
|
| 63 |
+
| `aspects` | array | List of extracted aspect-sentiment pairs |
|
| 64 |
+
| `processing_time_ms` | float | Total inference time in milliseconds |
|
| 65 |
+
|
| 66 |
+
**Aspect Object:**
|
| 67 |
+
|
| 68 |
+
| Field | Type | Description |
|
| 69 |
+
|-------|------|-------------|
|
| 70 |
+
| `aspect` | string | Extracted aspect term (title-cased) |
|
| 71 |
+
| `sentiment` | string | `"positive"`, `"negative"`, `"neutral"`, or `"conflict"` |
|
| 72 |
+
| `confidence` | float | Confidence score (0.0–1.0) |
|
| 73 |
+
| `start` | int | Character offset start in original text |
|
| 74 |
+
| `end` | int | Character offset end in original text |
|
| 75 |
+
|
| 76 |
+
**Error Responses:**
|
| 77 |
+
|
| 78 |
+
| Status | Condition |
|
| 79 |
+
|--------|-----------|
|
| 80 |
+
| 422 | Empty text, missing `text` field |
|
| 81 |
+
| 500 | Model inference failure |
|
| 82 |
+
|
| 83 |
+
---
|
| 84 |
+
|
| 85 |
+
### POST /batch
|
| 86 |
+
|
| 87 |
+
Upload a CSV file for batch analysis. Processed asynchronously via Celery.
|
| 88 |
+
|
| 89 |
+
**Request:** `multipart/form-data`
|
| 90 |
+
|
| 91 |
+
| Field | Type | Required | Description |
|
| 92 |
+
|-------|------|----------|-------------|
|
| 93 |
+
| `file` | file | Yes | CSV file with a `text` column (max 10,000 rows) |
|
| 94 |
+
|
| 95 |
+
**Response `200`:**
|
| 96 |
+
|
| 97 |
+
```json
|
| 98 |
+
{
|
| 99 |
+
"job_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
|
| 100 |
+
"status": "queued",
|
| 101 |
+
"total_reviews": 4250,
|
| 102 |
+
"processed": 0,
|
| 103 |
+
"result_url": null
|
| 104 |
+
}
|
| 105 |
+
```
|
| 106 |
+
|
| 107 |
+
**Error Responses:**
|
| 108 |
+
|
| 109 |
+
| Status | Condition |
|
| 110 |
+
|--------|-----------|
|
| 111 |
+
| 422 | Non-CSV file, missing `text` column, >10K rows |
|
| 112 |
+
| 500 | Batch processing failed |
|
| 113 |
+
|
| 114 |
+
---
|
| 115 |
+
|
| 116 |
+
### GET /status/{job_id}
|
| 117 |
+
|
| 118 |
+
Poll batch job progress.
|
| 119 |
+
|
| 120 |
+
**Response `200` (processing):**
|
| 121 |
+
|
| 122 |
+
```json
|
| 123 |
+
{
|
| 124 |
+
"job_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
|
| 125 |
+
"status": "processing",
|
| 126 |
+
"total_reviews": 4250,
|
| 127 |
+
"processed": 1200,
|
| 128 |
+
"result_url": null
|
| 129 |
+
}
|
| 130 |
+
```
|
| 131 |
+
|
| 132 |
+
**Response `200` (completed):**
|
| 133 |
+
|
| 134 |
+
```json
|
| 135 |
+
{
|
| 136 |
+
"job_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
|
| 137 |
+
"status": "completed",
|
| 138 |
+
"total_reviews": 4250,
|
| 139 |
+
"processed": 4250,
|
| 140 |
+
"result_url": "/results/download/a1b2c3d4-e5f6-7890-abcd-ef1234567890"
|
| 141 |
+
}
|
| 142 |
+
```
|
| 143 |
+
|
| 144 |
+
**Error Responses:**
|
| 145 |
+
|
| 146 |
+
| Status | Condition |
|
| 147 |
+
|--------|-----------|
|
| 148 |
+
| 404 | Job ID not found |
|
| 149 |
+
|
| 150 |
+
---
|
| 151 |
+
|
| 152 |
+
### GET /health
|
| 153 |
+
|
| 154 |
+
System health check.
|
| 155 |
+
|
| 156 |
+
**Response `200`:**
|
| 157 |
+
|
| 158 |
+
```json
|
| 159 |
+
{
|
| 160 |
+
"status": "ok",
|
| 161 |
+
"model": "loaded",
|
| 162 |
+
"db": "connected"
|
| 163 |
+
}
|
| 164 |
+
```
|
| 165 |
+
|
| 166 |
+
---
|
| 167 |
+
|
| 168 |
+
### GET /info
|
| 169 |
+
|
| 170 |
+
Get model metadata.
|
| 171 |
+
|
| 172 |
+
**Response `200`:**
|
| 173 |
+
|
| 174 |
+
```json
|
| 175 |
+
{
|
| 176 |
+
"model_name": "xlm-roberta-base-absa",
|
| 177 |
+
"version": "1.0",
|
| 178 |
+
"supported_languages": "en, hi",
|
| 179 |
+
"max_batch_size": "10000"
|
| 180 |
+
}
|
| 181 |
+
```
|
| 182 |
+
|
| 183 |
+
---
|
| 184 |
+
|
| 185 |
+
### GET /metrics
|
| 186 |
+
|
| 187 |
+
Prometheus metrics endpoint (auto-instrumented).
|
| 188 |
+
|
| 189 |
+
**Response `200`:** Prometheus text format metrics.
|
| 190 |
+
|
| 191 |
+
Available metrics:
|
| 192 |
+
- `fastapi_requests_total` (counter by method, path, status)
|
| 193 |
+
- `fastapi_requests_duration_seconds` (histogram)
|
| 194 |
+
- `fastapi_requests_inprogress` (gauge)
|
| 195 |
+
- Custom ABSA metrics (if implemented)
|
| 196 |
+
|
| 197 |
+
---
|
| 198 |
+
|
| 199 |
+
## Example Usage
|
| 200 |
+
|
| 201 |
+
### cURL
|
| 202 |
+
|
| 203 |
+
```bash
|
| 204 |
+
# Single prediction
|
| 205 |
+
curl -X POST http://localhost:8000/predict \
|
| 206 |
+
-H "Content-Type: application/json" \
|
| 207 |
+
-d '{"text": "This phone has amazing battery life but the camera is disappointing", "language": "en"}'
|
| 208 |
+
|
| 209 |
+
# Health check
|
| 210 |
+
curl http://localhost:8000/health
|
| 211 |
+
|
| 212 |
+
# Model info
|
| 213 |
+
curl http://localhost:8000/info
|
| 214 |
+
```
|
| 215 |
+
|
| 216 |
+
### Python
|
| 217 |
+
|
| 218 |
+
```python
|
| 219 |
+
import httpx
|
| 220 |
+
|
| 221 |
+
response = httpx.post(
|
| 222 |
+
"http://localhost:8000/predict",
|
| 223 |
+
json={"text": "This phone has amazing battery life but the camera is disappointing"}
|
| 224 |
+
)
|
| 225 |
+
print(response.json())
|
| 226 |
+
```
|
| 227 |
+
|
| 228 |
+
### JavaScript
|
| 229 |
+
|
| 230 |
+
```javascript
|
| 231 |
+
const response = await fetch('http://localhost:8000/predict', {
|
| 232 |
+
method: 'POST',
|
| 233 |
+
headers: { 'Content-Type': 'application/json' },
|
| 234 |
+
body: JSON.stringify({
|
| 235 |
+
text: 'This phone has amazing battery life but the camera is disappointing'
|
| 236 |
+
})
|
| 237 |
+
});
|
| 238 |
+
const data = await response.json();
|
| 239 |
+
console.log(data);
|
| 240 |
+
```
|
docs/DATABASE.md
ADDED
|
@@ -0,0 +1,116 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Database Design — Multilingual ABSA
|
| 2 |
+
|
| 3 |
+
## ER Diagram
|
| 4 |
+
|
| 5 |
+
```mermaid
|
| 6 |
+
erDiagram
|
| 7 |
+
Review {
|
| 8 |
+
uuid id PK
|
| 9 |
+
text text
|
| 10 |
+
string language
|
| 11 |
+
datetime created_at
|
| 12 |
+
float processing_time_ms
|
| 13 |
+
}
|
| 14 |
+
AspectResult {
|
| 15 |
+
uuid id PK
|
| 16 |
+
uuid review_id FK
|
| 17 |
+
string aspect
|
| 18 |
+
string sentiment
|
| 19 |
+
float confidence
|
| 20 |
+
int start_pos
|
| 21 |
+
int end_pos
|
| 22 |
+
}
|
| 23 |
+
BatchJob {
|
| 24 |
+
uuid id PK
|
| 25 |
+
string status
|
| 26 |
+
int total
|
| 27 |
+
int processed
|
| 28 |
+
datetime created_at
|
| 29 |
+
datetime completed_at
|
| 30 |
+
}
|
| 31 |
+
|
| 32 |
+
Review ||--o{ AspectResult : "has aspects"
|
| 33 |
+
```
|
| 34 |
+
|
| 35 |
+
## Schema
|
| 36 |
+
|
| 37 |
+
```sql
|
| 38 |
+
CREATE TABLE reviews (
|
| 39 |
+
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
| 40 |
+
text TEXT NOT NULL,
|
| 41 |
+
language VARCHAR(10) NOT NULL,
|
| 42 |
+
created_at TIMESTAMPTZ DEFAULT NOW(),
|
| 43 |
+
processing_time_ms FLOAT NOT NULL
|
| 44 |
+
);
|
| 45 |
+
|
| 46 |
+
CREATE TABLE aspect_results (
|
| 47 |
+
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
| 48 |
+
review_id UUID NOT NULL REFERENCES reviews(id),
|
| 49 |
+
aspect VARCHAR(255) NOT NULL,
|
| 50 |
+
sentiment VARCHAR(50) NOT NULL,
|
| 51 |
+
confidence FLOAT NOT NULL,
|
| 52 |
+
start_pos INTEGER NOT NULL,
|
| 53 |
+
end_pos INTEGER NOT NULL
|
| 54 |
+
);
|
| 55 |
+
|
| 56 |
+
CREATE TABLE batch_jobs (
|
| 57 |
+
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
| 58 |
+
status VARCHAR(50) NOT NULL DEFAULT 'queued',
|
| 59 |
+
total INTEGER NOT NULL,
|
| 60 |
+
processed INTEGER NOT NULL DEFAULT 0,
|
| 61 |
+
created_at TIMESTAMPTZ DEFAULT NOW(),
|
| 62 |
+
completed_at TIMESTAMPTZ
|
| 63 |
+
);
|
| 64 |
+
```
|
| 65 |
+
|
| 66 |
+
## Recommended Indexes (Production)
|
| 67 |
+
|
| 68 |
+
```sql
|
| 69 |
+
CREATE INDEX idx_aspect_results_review_id ON aspect_results(review_id);
|
| 70 |
+
CREATE INDEX idx_reviews_created_at ON reviews(created_at);
|
| 71 |
+
CREATE INDEX idx_reviews_language ON reviews(language);
|
| 72 |
+
CREATE INDEX idx_batch_jobs_status ON batch_jobs(status);
|
| 73 |
+
```
|
| 74 |
+
|
| 75 |
+
## Connection Configuration
|
| 76 |
+
|
| 77 |
+
```python
|
| 78 |
+
# Development (SQLite)
|
| 79 |
+
DATABASE_URL = "sqlite:///absa.db"
|
| 80 |
+
engine = create_engine(DATABASE_URL, connect_args={"check_same_thread": False})
|
| 81 |
+
|
| 82 |
+
# Production (PostgreSQL)
|
| 83 |
+
DATABASE_URL = "postgresql://user:pass@host:5432/absa_db"
|
| 84 |
+
engine = create_engine(DATABASE_URL, pool_pre_ping=True)
|
| 85 |
+
```
|
| 86 |
+
|
| 87 |
+
## ORM Models
|
| 88 |
+
|
| 89 |
+
```python
|
| 90 |
+
class Review(Base):
|
| 91 |
+
__tablename__ = "reviews"
|
| 92 |
+
id = Column(Uuid(as_uuid=True), primary_key=True, default=uuid.uuid4)
|
| 93 |
+
text = Column(Text, nullable=False)
|
| 94 |
+
language = Column(String(10), nullable=False)
|
| 95 |
+
created_at = Column(DateTime(timezone=True), default=lambda: datetime.now(timezone.utc))
|
| 96 |
+
processing_time_ms = Column(Float, nullable=False)
|
| 97 |
+
|
| 98 |
+
class AspectResult(Base):
|
| 99 |
+
__tablename__ = "aspect_results"
|
| 100 |
+
id = Column(Uuid(as_uuid=True), primary_key=True, default=uuid.uuid4)
|
| 101 |
+
review_id = Column(Uuid(as_uuid=True), ForeignKey("reviews.id"), nullable=False)
|
| 102 |
+
aspect = Column(String(255), nullable=False)
|
| 103 |
+
sentiment = Column(String(50), nullable=False)
|
| 104 |
+
confidence = Column(Float, nullable=False)
|
| 105 |
+
start_pos = Column(Integer, nullable=False)
|
| 106 |
+
end_pos = Column(Integer, nullable=False)
|
| 107 |
+
|
| 108 |
+
class BatchJob(Base):
|
| 109 |
+
__tablename__ = "batch_jobs"
|
| 110 |
+
id = Column(Uuid(as_uuid=True), primary_key=True, default=uuid.uuid4)
|
| 111 |
+
status = Column(String(50), nullable=False, default="queued")
|
| 112 |
+
total = Column(Integer, nullable=False)
|
| 113 |
+
processed = Column(Integer, nullable=False, default=0)
|
| 114 |
+
created_at = Column(DateTime(timezone=True), default=lambda: datetime.now(timezone.utc))
|
| 115 |
+
completed_at = Column(DateTime(timezone=True), nullable=True)
|
| 116 |
+
```
|
docs/DEPLOYMENT.md
ADDED
|
@@ -0,0 +1,136 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Deployment Guide — Multilingual ABSA
|
| 2 |
+
|
| 3 |
+
## Prerequisites
|
| 4 |
+
|
| 5 |
+
- Python 3.11+
|
| 6 |
+
- Node.js 20+
|
| 7 |
+
- Docker & Docker Compose (for containerized deployment)
|
| 8 |
+
- Railway account (for API deployment)
|
| 9 |
+
- Vercel account (for dashboard deployment)
|
| 10 |
+
|
| 11 |
+
## Environment Variables
|
| 12 |
+
|
| 13 |
+
| Variable | Dev Default | Production | Required By |
|
| 14 |
+
|----------|-------------|------------|-------------|
|
| 15 |
+
| `DATABASE_URL` | `sqlite:///absa.db` | PostgreSQL URL | API + Worker |
|
| 16 |
+
| `REDIS_URL` | `redis://localhost:6379/0` | Redis URL | API + Worker |
|
| 17 |
+
| `MODEL_PATH` | `models/onnx/` | (same or HF Hub) | API |
|
| 18 |
+
| `MAX_BATCH_SIZE` | `10000` | `10000` | API |
|
| 19 |
+
| `LOG_LEVEL` | `INFO` | `WARNING` | API |
|
| 20 |
+
| `ENABLE_METRICS` | `true` | `true` | API |
|
| 21 |
+
| `HF_MODEL_REPO` | (empty) | `username/multilingual-absa` | API |
|
| 22 |
+
| `MODEL_SOURCE` | `local` | `huggingface_hub` | API |
|
| 23 |
+
|
| 24 |
+
## Local Development
|
| 25 |
+
|
| 26 |
+
```bash
|
| 27 |
+
# Backend
|
| 28 |
+
cp .env.example .env
|
| 29 |
+
python -m venv .venv && source .venv/bin/activate
|
| 30 |
+
pip install -r requirements.txt
|
| 31 |
+
uvicorn api.main:app --reload --host 0.0.0.0 --port 8000
|
| 32 |
+
# API at http://localhost:8000, docs at http://localhost:8000/docs
|
| 33 |
+
|
| 34 |
+
# MLflow
|
| 35 |
+
./scripts/mlflow_ui.sh
|
| 36 |
+
# MLflow UI at http://localhost:5000
|
| 37 |
+
|
| 38 |
+
# Frontend
|
| 39 |
+
cd dashboard
|
| 40 |
+
cp .env.example .env # VITE_API_URL=http://localhost:8000
|
| 41 |
+
npm install
|
| 42 |
+
npm run dev
|
| 43 |
+
# Dashboard at http://localhost:5173
|
| 44 |
+
```
|
| 45 |
+
|
| 46 |
+
## Docker Compose (Full Stack)
|
| 47 |
+
|
| 48 |
+
```bash
|
| 49 |
+
docker-compose -f config/docker/docker-compose.yml up --build
|
| 50 |
+
```
|
| 51 |
+
|
| 52 |
+
Services started:
|
| 53 |
+
|
| 54 |
+
| Service | Container Name | Port | Dependencies |
|
| 55 |
+
|---------|---------------|------|--------------|
|
| 56 |
+
| `api` | `absa-api` | 8000 | postgres, redis |
|
| 57 |
+
| `worker` | `absa-worker` | — | postgres, redis, api |
|
| 58 |
+
| `dashboard` | `absa-dashboard` | 3000 (=> 80) | api |
|
| 59 |
+
| `postgres` | `absa-postgres` | 5432 | — |
|
| 60 |
+
| `redis` | `absa-redis` | 6379 | — |
|
| 61 |
+
| `prometheus` | — | 9090 | api |
|
| 62 |
+
| `grafana` | — | 3001 | prometheus |
|
| 63 |
+
|
| 64 |
+
```mermaid
|
| 65 |
+
graph TB
|
| 66 |
+
DASH[Dashboard :3000] --> API[API :8000]
|
| 67 |
+
API --> PG[PostgreSQL :5432]
|
| 68 |
+
API --> RED[Redis :6379]
|
| 69 |
+
WORK[Worker] --> RED
|
| 70 |
+
WORK --> PG
|
| 71 |
+
PROM[Prometheus :9090] -->|scrape| API
|
| 72 |
+
GRAF[Grafana :3001] --> PROM
|
| 73 |
+
```
|
| 74 |
+
|
| 75 |
+
## Production Deployment (Railway + Vercel)
|
| 76 |
+
|
| 77 |
+
### Railway (API + Worker)
|
| 78 |
+
|
| 79 |
+
1. Create a Railway project from your Git repository
|
| 80 |
+
2. Set build command: uses `railway.json` → `Dockerfile.api.prod`
|
| 81 |
+
3. Set environment variables in Railway dashboard:
|
| 82 |
+
- `DATABASE_URL` → Railway PostgreSQL plugin connection string
|
| 83 |
+
- `REDIS_URL` → Railway Redis plugin connection string
|
| 84 |
+
- `MODEL_SOURCE=huggingface_hub`
|
| 85 |
+
- `HF_MODEL_REPO=your-username/multilingual-absa`
|
| 86 |
+
- `ENABLE_METRICS=true`
|
| 87 |
+
- `LOG_LEVEL=WARNING`
|
| 88 |
+
4. Add a second service for the Celery worker with command:
|
| 89 |
+
`celery -A api.tasks.batch_tasks worker --loglevel=warning`
|
| 90 |
+
|
| 91 |
+
### Vercel (Dashboard)
|
| 92 |
+
|
| 93 |
+
1. Import `dashboard/` as a Vercel project
|
| 94 |
+
2. Framework preset: Vite
|
| 95 |
+
3. Environment variable: `VITE_API_URL=https://your-railway-api-url.railway.app`
|
| 96 |
+
4. `vercel.json` rewrites `/api/*` to Railway API
|
| 97 |
+
|
| 98 |
+
```mermaid
|
| 99 |
+
graph LR
|
| 100 |
+
USER[Browser] --> VERCEL[Vercel CDN]
|
| 101 |
+
VERCEL -->|/api/* rewrite| RAILWAY[Railway API]
|
| 102 |
+
RAILWAY --> PG[(Railway PostgreSQL)]
|
| 103 |
+
RAILWAY --> REDIS[(Railway Redis)]
|
| 104 |
+
WORK[Celery Worker] --> REDIS
|
| 105 |
+
WORK --> PG
|
| 106 |
+
```
|
| 107 |
+
|
| 108 |
+
## DVC Data/Model Sync
|
| 109 |
+
|
| 110 |
+
```bash
|
| 111 |
+
# Pull data/models from remote
|
| 112 |
+
dvc pull
|
| 113 |
+
|
| 114 |
+
# Run full ML pipeline
|
| 115 |
+
dvc repro
|
| 116 |
+
|
| 117 |
+
# Push new artifacts
|
| 118 |
+
dvc push
|
| 119 |
+
```
|
| 120 |
+
|
| 121 |
+
## Monitoring
|
| 122 |
+
|
| 123 |
+
| Tool | URL | Purpose |
|
| 124 |
+
|------|-----|---------|
|
| 125 |
+
| MLflow UI | `http://localhost:5000` | Experiment tracking |
|
| 126 |
+
| API Docs | `http://localhost:8000/docs` | Interactive API |
|
| 127 |
+
| Prometheus | `http://localhost:9090` | Metrics store |
|
| 128 |
+
| Grafana | `http://localhost:3001` | Visual dashboards |
|
| 129 |
+
| Dashboard | `http://localhost:5173` | User interface |
|
| 130 |
+
|
| 131 |
+
## Scaling
|
| 132 |
+
|
| 133 |
+
- **API**: Increase `--workers` in uvicorn command (2 in prod Dockerfile)
|
| 134 |
+
- **Worker**: Scale Celery worker containers horizontally
|
| 135 |
+
- **Database**: Use Railway managed PostgreSQL with auto-scaling
|
| 136 |
+
- **Memory limit**: 2GB per API container (configured in `docker-compose.prod.yml`)
|
docs/SECURITY.md
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Security Analysis — Multilingual ABSA
|
| 2 |
+
|
| 3 |
+
## Current State
|
| 4 |
+
|
| 5 |
+
| Area | Status | Notes |
|
| 6 |
+
|------|--------|-------|
|
| 7 |
+
| JWT Authentication | ❌ Not implemented | No auth layer |
|
| 8 |
+
| OAuth | ❌ Not implemented | No SSO |
|
| 9 |
+
| HTTPS | ❌ Not enforced | Expects reverse proxy to terminate TLS |
|
| 10 |
+
| Input Validation | ✅ Partial | Pydantic validation present; no server-side max_length |
|
| 11 |
+
| SQL Injection | ✅ Protected | SQLAlchemy ORM parameterized queries |
|
| 12 |
+
| XSS | ✅ Protected | React JSX auto-escaping |
|
| 13 |
+
| CSRF | ❌ Not implemented | No CSRF middleware; CORS `"*"` mitigates partially |
|
| 14 |
+
| Secrets Management | ⚠️ Manual | `.env` gitignored; Docker Compose has hardcoded dev creds |
|
| 15 |
+
| Rate Limiting | ❌ Not implemented | No throttling on any endpoint |
|
| 16 |
+
| File Upload Security | ⚠️ Partial | Extension validation; no size limit; temp files not cleaned on success |
|
| 17 |
+
| Authorization | ❌ None | No role-based or API-key access control |
|
| 18 |
+
| CORS | ⚠️ Permissive | `allow_origins=["*"]` |
|
| 19 |
+
|
| 20 |
+
## Risks & Recommendations
|
| 21 |
+
|
| 22 |
+
### Critical
|
| 23 |
+
|
| 24 |
+
1. **Missing authentication** — All endpoints are publicly accessible
|
| 25 |
+
- **Fix**: Add FastAPI middleware for API key validation
|
| 26 |
+
- **Fix**: Integrate OAuth2/OIDC for multi-user scenarios
|
| 27 |
+
|
| 28 |
+
2. **No rate limiting** — `/batch` endpoint can be abused (10K rows per request)
|
| 29 |
+
- **Fix**: Add `slowapi` or custom rate-limiting middleware
|
| 30 |
+
- **Fix**: Implement per-IP request quotas
|
| 31 |
+
|
| 32 |
+
### High
|
| 33 |
+
|
| 34 |
+
3. **Temp file leak** — Batch CSV saved via `NamedTemporaryFile(delete=False)` but `os.unlink()` only called on validation error, not on success
|
| 35 |
+
- **Fix**: Add `try/finally` block to ensure cleanup
|
| 36 |
+
|
| 37 |
+
4. **CORS all origins** — `"*"` allows any website to call the API
|
| 38 |
+
- **Fix**: Restrict to known dashboard domains
|
| 39 |
+
|
| 40 |
+
5. **No server-side text length limit** — `ReviewInput.text` accepts arbitrary length
|
| 41 |
+
- **Fix**: Add `StringConstraints(max_length=512)` to Pydantic model
|
| 42 |
+
|
| 43 |
+
### Medium
|
| 44 |
+
|
| 45 |
+
6. **No file size limit on batch uploads** — Only row count limit (10K)
|
| 46 |
+
- **Fix**: Add file-size check (e.g., 50MB max)
|
| 47 |
+
|
| 48 |
+
7. **Hardcoded credentials** in `docker-compose.yml` — `absa_user/absa_pass`
|
| 49 |
+
- **Fix**: Use environment variables or Docker secrets
|
| 50 |
+
|
| 51 |
+
8. **CSRF** — No protection; token-based auth (when implemented) would mitigate
|
| 52 |
+
|
| 53 |
+
### Low
|
| 54 |
+
|
| 55 |
+
9. **Weak health check** — Returns `"db": "connected"` without actually pinging DB
|
| 56 |
+
- **Fix**: Add actual DB ping to `/health` endpoint
|
| 57 |
+
|
| 58 |
+
10. **No request logging** — No structured logging or audit trail
|
| 59 |
+
|
| 60 |
+
## Configuration Checklist
|
| 61 |
+
|
| 62 |
+
- [ ] Set `ENABLE_METRICS` to `false` if Prometheus not needed
|
| 63 |
+
- [ ] Set `LOG_LEVEL` to `WARNING` in production
|
| 64 |
+
- [ ] Use strong, random passwords for PostgreSQL
|
| 65 |
+
- [ ] Run API behind TLS-terminating reverse proxy (Railway does this automatically)
|
| 66 |
+
- [ ] Keep `.env` out of version control (already in `.gitignore`)
|
| 67 |
+
- [ ] Rotate secrets regularly
|
docs/SYSTEM_DESIGN.md
ADDED
|
@@ -0,0 +1,142 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# System Design — Multilingual ABSA
|
| 2 |
+
|
| 3 |
+
## 1. Design Goals
|
| 4 |
+
|
| 5 |
+
- **Accuracy**: Macro-F1 > 78% English, > 65% Hindi
|
| 6 |
+
- **Latency**: P95 < 300ms for single-review inference (ONNX INT8)
|
| 7 |
+
- **Availability**: Zero-download fallback ensures the system starts instantly and never depends on external model downloads
|
| 8 |
+
- **Scalability**: Async batch processing via Celery for bulk analysis
|
| 9 |
+
- **Observability**: Full MLOps stack (MLflow, Prometheus, Grafana, Evidently)
|
| 10 |
+
|
| 11 |
+
## 2. System Components
|
| 12 |
+
|
| 13 |
+
### 2.1 FastAPI Application (`api/main.py`)
|
| 14 |
+
- Lifespan handler initializes DB tables and loads models at startup
|
| 15 |
+
- Two routers: `/predict` (single + batch), `/results` (health, info, metrics)
|
| 16 |
+
- CORS middleware for dashboard origin
|
| 17 |
+
- Prometheus instrumentator auto-exposes `/metrics`
|
| 18 |
+
|
| 19 |
+
### 2.2 ABSA Pipeline (`api/services/absa_pipeline.py`)
|
| 20 |
+
- Dual-engine design:
|
| 21 |
+
- **Neural**: ONNX Runtime with INT8-quantized XLM-RoBERTa models
|
| 22 |
+
- **Rule-based**: Lexicon-driven aspect extraction + context-window sentiment scoring
|
| 23 |
+
- Thread-safe model loading via `threading.Lock()`
|
| 24 |
+
- Singleton pattern (module-level `pipeline` instance)
|
| 25 |
+
|
| 26 |
+
### 2.3 Language Service (`api/services/lang_service.py`)
|
| 27 |
+
- Singleton with fastText LID model
|
| 28 |
+
- Unicode-based fallback (Devanagari character range detection)
|
| 29 |
+
|
| 30 |
+
### 2.4 Celery Worker (`api/tasks/batch_tasks.py`)
|
| 31 |
+
- Processes uploaded CSV files in batches of 32
|
| 32 |
+
- Incrementally writes results to CSV and DB
|
| 33 |
+
- Progress tracking via BatchJob model
|
| 34 |
+
|
| 35 |
+
### 2.5 React Dashboard (`dashboard/`)
|
| 36 |
+
- 3 pages: Predict (live), Batch Analytics, System Monitor
|
| 37 |
+
- API client with exponential backoff retry
|
| 38 |
+
- React Query for server state and polling
|
| 39 |
+
|
| 40 |
+
## 3. Data Model
|
| 41 |
+
|
| 42 |
+
### 3.1 Reviews
|
| 43 |
+
```sql
|
| 44 |
+
reviews (id UUID PK, text TEXT, language VARCHAR(10), created_at DATETIME, processing_time_ms FLOAT)
|
| 45 |
+
aspect_results (id UUID PK, review_id UUID FK, aspect VARCHAR(255), sentiment VARCHAR(50), confidence FLOAT, start_pos INT, end_pos INT)
|
| 46 |
+
batch_jobs (id UUID PK, status VARCHAR(50), total INT, processed INT, created_at DATETIME, completed_at DATETIME NULL)
|
| 47 |
+
```
|
| 48 |
+
|
| 49 |
+
### 3.2 Relationships
|
| 50 |
+
- One `Review` → Many `AspectResults`
|
| 51 |
+
- `BatchJob` is standalone (progress tracking + CSV output)
|
| 52 |
+
|
| 53 |
+
## 4. API Endpoints
|
| 54 |
+
|
| 55 |
+
| Method | Path | Request | Response | Notes |
|
| 56 |
+
|--------|------|---------|----------|-------|
|
| 57 |
+
| POST | `/predict` | `{"text": str, "language": str?}` | `PredictionResponse` | Synchronous inference |
|
| 58 |
+
| POST | `/batch` | `multipart/form-data` (CSV file) | `{"job_id", "status", "total_reviews", "processed"}` | Async via Celery |
|
| 59 |
+
| GET | `/status/{job_id}` | — | `BatchJobResponse` | Poll batch progress |
|
| 60 |
+
| GET | `/health` | — | `{"status", "model", "db"}` | Health check |
|
| 61 |
+
| GET | `/info` | — | Model metadata | Version info |
|
| 62 |
+
| GET | `/metrics` | — | Prometheus metrics | Auto-instrumented |
|
| 63 |
+
|
| 64 |
+
## 5. ML Pipeline
|
| 65 |
+
|
| 66 |
+
### 5.1 Training Pipeline
|
| 67 |
+
```
|
| 68 |
+
Raw Data → Text Cleaning → Language Detection → Transliteration → Tokenization
|
| 69 |
+
↓
|
| 70 |
+
BIO Tagging (for NER)
|
| 71 |
+
↓
|
| 72 |
+
┌──────────────────────────┐
|
| 73 |
+
│ XLM-RoBERTa Fine-Tune │
|
| 74 |
+
│ ┌────────────────────┐ │
|
| 75 |
+
│ │ Aspect Extraction │ │
|
| 76 |
+
│ │ (Token CLS, 3 lbl) │ │
|
| 77 |
+
│ └────────────────────┘ │
|
| 78 |
+
│ ┌────────────────────┐ │
|
| 79 |
+
│ │ Sentiment CLS │ │
|
| 80 |
+
│ │ (Seq CLS, 4 lbl) │ │
|
| 81 |
+
│ └────────────────────┘ │
|
| 82 |
+
└──────────────────────────┘
|
| 83 |
+
↓
|
| 84 |
+
ONNX Export + INT8 Quantization
|
| 85 |
+
```
|
| 86 |
+
|
| 87 |
+
### 5.2 Inference Pipeline
|
| 88 |
+
```
|
| 89 |
+
Input Text
|
| 90 |
+
↓
|
| 91 |
+
Language Detection (fastText LID / Unicode heuristic)
|
| 92 |
+
↓
|
| 93 |
+
┌─ Neural Path (if ONNX loaded) ────────────────────────┐
|
| 94 |
+
│ Tokenize (XLM-R SentencePiece 128 tokens) │
|
| 95 |
+
│ → ORTModelForTokenClassification → BIO spans │
|
| 96 |
+
│ → Per-span ORTModelForSequenceClassification → sentiment│
|
| 97 |
+
└─────────────────────────────────────────────────────���──┘
|
| 98 |
+
↓ (fallback)
|
| 99 |
+
┌─ Rule-Based Path ──────────────────────────────────────┐
|
| 100 |
+
│ Regex match 140+ aspect keywords (longest-first) │
|
| 101 |
+
│ → Context-window sentiment scoring │
|
| 102 |
+
│ • 200+ positive words, 200+ negative words │
|
| 103 |
+
│ • 3-word negation window │
|
| 104 |
+
│ • Intensifier multiplier (1.5x) │
|
| 105 |
+
│ → pos:neg ratio → label + confidence │
|
| 106 |
+
└────────────────────────────────────────────────────────┘
|
| 107 |
+
↓
|
| 108 |
+
Structured JSON + DB Persistence
|
| 109 |
+
```
|
| 110 |
+
|
| 111 |
+
## 6. Rule-Based Engine Details
|
| 112 |
+
|
| 113 |
+
### Aspect Extraction
|
| 114 |
+
- 140+ phrase patterns across 10 categories:
|
| 115 |
+
- Audio (sound quality, bass, noise cancellation)
|
| 116 |
+
- Battery (battery life, charging speed)
|
| 117 |
+
- Design (build quality, comfort, ergonomics)
|
| 118 |
+
- Connectivity (bluetooth, wifi, pairing)
|
| 119 |
+
- Display (screen quality, resolution)
|
| 120 |
+
- Camera (camera quality, image quality)
|
| 121 |
+
- Performance (speed, ram, processor)
|
| 122 |
+
- Software (user interface, app, features)
|
| 123 |
+
- Value (price, value for money)
|
| 124 |
+
- Support (customer service, warranty)
|
| 125 |
+
|
| 126 |
+
### Sentiment Scoring
|
| 127 |
+
- Positive words: 110+ (excellent, great, amazing, badhiya, achha)
|
| 128 |
+
- Negative words: 70+ (poor, terrible, kharab, bekaar)
|
| 129 |
+
- Negation words: 22 (not, never, doesn't, didn't)
|
| 130 |
+
- Intensifiers: 12 (very, extremely, highly)
|
| 131 |
+
- Algorithm: Word-by-word scan with 3-word lookback for negation and intensifiers
|
| 132 |
+
- Score → Label: >60% positive ratio → positive, <40% → negative, else → neutral
|
| 133 |
+
|
| 134 |
+
## 7. Performance Targets
|
| 135 |
+
|
| 136 |
+
| Metric | Target | Actual (ONNX INT8) |
|
| 137 |
+
|--------|--------|-------------------|
|
| 138 |
+
| English Macro-F1 | >75% | 78.1% |
|
| 139 |
+
| Hindi Macro-F1 | >60% | 67.8% |
|
| 140 |
+
| P95 Latency | <300ms | 185ms |
|
| 141 |
+
| Throughput (single worker) | >5 req/s | ~5.4 req/s |
|
| 142 |
+
| Batch Processing (10K rows) | <30 min | Estimated ~15 min |
|
docs/TECH_STACK.md
ADDED
|
@@ -0,0 +1,97 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Technology Stack — Multilingual ABSA
|
| 2 |
+
|
| 3 |
+
## Core Technologies
|
| 4 |
+
|
| 5 |
+
| Technology | Version | Purpose | Where Used |
|
| 6 |
+
|------------|---------|---------|------------|
|
| 7 |
+
| **Python** | 3.11+ | Runtime | All backend/ML code |
|
| 8 |
+
| **FastAPI** | 0.111.0 | REST API framework | `api/` routes and middleware |
|
| 9 |
+
| **Uvicorn** | 0.29.0 | ASGI server | API entry point |
|
| 10 |
+
| **React** | 18.2.0 | Frontend framework | `dashboard/src/` |
|
| 11 |
+
| **Vite** | 5.0.0 | Build tool | `dashboard/vite.config.js` |
|
| 12 |
+
| **TailwindCSS** | 3.3.5 | CSS framework | `dashboard/src/index.css` |
|
| 13 |
+
| **PostgreSQL** | 16 (alpine) | Production database | Docker Compose |
|
| 14 |
+
| **SQLite** | (built-in) | Development database | `absa.db` |
|
| 15 |
+
| **Redis** | 7 (alpine) | Celery broker + cache | `api/tasks/` |
|
| 16 |
+
| **Docker** | 27.x | Containerization | `config/docker/` |
|
| 17 |
+
| **Docker Compose** | 3.8+ | Orchestration | `config/docker/docker-compose.yml` |
|
| 18 |
+
|
| 19 |
+
## ML / AI Stack
|
| 20 |
+
|
| 21 |
+
| Technology | Version | Purpose | Where Used |
|
| 22 |
+
|------------|---------|---------|------------|
|
| 23 |
+
| **PyTorch** | 2.3.0 | Deep learning framework | `src/models/` training |
|
| 24 |
+
| **Transformers** | 4.39.3 | Model zoo, training, tokenization | All ML scripts |
|
| 25 |
+
| **XLM-RoBERTa** | base | Multilingual encoder | `FacebookAI/xlm-roberta-base` |
|
| 26 |
+
| **ONNX Runtime** | 1.18.0 | Production inference | `api/services/absa_pipeline.py` |
|
| 27 |
+
| **Optimum** | 1.19.0 | ONNX export bridge | `src/models/export_onnx.py` |
|
| 28 |
+
| **optimum-onnx** | (bundled) | ONNX runtime models | `ORTModelForTokenClassification`, `ORTModelForSequenceClassification` |
|
| 29 |
+
| **PEFT** | 0.10.0 | Parameter-efficient fine-tuning | `src/models/train_qlora.py` (LoRA) |
|
| 30 |
+
| **scikit-learn** | 1.4.2 | Metrics + baseline | `src/models/baseline.py`, `train_sentiment.py` |
|
| 31 |
+
| **Datasets** | 2.19.0 | Data loading | `src/data/hf_dataset.py` |
|
| 32 |
+
| **seqeval** | 1.2.2 | BIO tagging evaluation | `src/models/train_aspect_extraction.py` |
|
| 33 |
+
| **fasttext-predict** | 0.9.2.4 | Language identification | `src/data/lang_detect.py`, `api/services/lang_service.py` |
|
| 34 |
+
| **indic-nlp-library** | (git) | Devanagari transliteration | `src/data/transliterate.py` |
|
| 35 |
+
| **nlpaug** | 1.1.11 | Text augmentation | `src/data/augmentation.py` |
|
| 36 |
+
|
| 37 |
+
## MLOps Stack
|
| 38 |
+
|
| 39 |
+
| Technology | Version | Purpose | Where Used |
|
| 40 |
+
|------------|---------|---------|------------|
|
| 41 |
+
| **MLflow** | 2.13.0 | Experiment tracking | `src/training/mlflow_utils.py`, all `src/models/` |
|
| 42 |
+
| **DVC** | 3.51.1 | Data version control | `config/dvc.yaml`, `.dvc/` |
|
| 43 |
+
| **Evidently AI** | 0.4.30 | Data drift monitoring | `scripts/drift_monitor.py` |
|
| 44 |
+
| **Prometheus** | latest | Metrics collection | `monitoring/prometheus.yml` |
|
| 45 |
+
| **Grafana** | latest | Dashboard visualization | `monitoring/grafana/dashboards/` |
|
| 46 |
+
| **prometheus-fastapi-instrumentator** | 7.0.0 | Metrics middleware | `api/middleware/metrics.py` |
|
| 47 |
+
|
| 48 |
+
## API / Backend Libraries
|
| 49 |
+
|
| 50 |
+
| Technology | Version | Purpose |
|
| 51 |
+
|------------|---------|---------|
|
| 52 |
+
| **Pydantic** | 2.7.1 | Request/response schema validation |
|
| 53 |
+
| **SQLAlchemy** | (via psycopg2) | ORM |
|
| 54 |
+
| **psycopg2-binary** | 2.9.9 | PostgreSQL driver |
|
| 55 |
+
| **Celery** | 5.4.0 | Async task queue |
|
| 56 |
+
| **python-dotenv** | 1.0.1 | Environment variable loading |
|
| 57 |
+
| **python-multipart** | 0.0.9 | File upload parsing |
|
| 58 |
+
| **NumPy** | 1.26.4 | Numerical computing |
|
| 59 |
+
| **Pandas** | 2.2.2 | Data manipulation |
|
| 60 |
+
|
| 61 |
+
## Frontend Libraries
|
| 62 |
+
|
| 63 |
+
| Technology | Version | Purpose |
|
| 64 |
+
|------------|---------|---------|
|
| 65 |
+
| **@tanstack/react-query** | 5.0.0 | Server state, caching, polling |
|
| 66 |
+
| **react-router-dom** | 6.20.0 | Client routing |
|
| 67 |
+
| **react-hot-toast** | 2.4.1 | Toast notifications |
|
| 68 |
+
| **react-dropzone** | 14.2.3 | File upload drag-and-drop |
|
| 69 |
+
| **axios** | 1.6.0 | HTTP client with retry |
|
| 70 |
+
| **recharts** | 2.10.0 | Charts (line, bar, pie/donut) |
|
| 71 |
+
| **lucide-react** | 0.290.0 | Icons |
|
| 72 |
+
| **autoprefixer** | 10.4.16 | CSS vendor prefixes |
|
| 73 |
+
| **postcss** | 8.4.31 | CSS processor |
|
| 74 |
+
|
| 75 |
+
## Infrastructure / Deployment
|
| 76 |
+
|
| 77 |
+
| Technology | Purpose |
|
| 78 |
+
|------------|---------|
|
| 79 |
+
| **Docker** (multi-stage) | Build optimization |
|
| 80 |
+
| **Nginx (alpine)** | SPA serving + API proxy |
|
| 81 |
+
| **Railway** | API + worker cloud hosting |
|
| 82 |
+
| **Vercel** | Frontend SPA hosting |
|
| 83 |
+
| **HuggingFace Hub** | Model storage/pull |
|
| 84 |
+
|
| 85 |
+
## Version Compatibility Matrix
|
| 86 |
+
|
| 87 |
+
| Package | Python | PyTorch | ONNX Runtime |
|
| 88 |
+
|---------|--------|---------|--------------|
|
| 89 |
+
| transformers 4.39.3 | 3.8+ | 1.11+ | — |
|
| 90 |
+
| optimum 1.19.0 | 3.8+ | 1.13+ | 1.15+ |
|
| 91 |
+
| onnxruntime 1.18.0 | 3.8+ | — | — |
|
| 92 |
+
| peft 0.10.0 | 3.8+ | 2.0+ | — |
|
| 93 |
+
| mlflow 2.13.0 | 3.8+ | — | — |
|
| 94 |
+
| dvc 3.51.1 | 3.8+ | — | — |
|
| 95 |
+
| evidently 0.4.30 | 3.8+ | — | — |
|
| 96 |
+
| fastapi 0.111.0 | 3.8+ | — | — |
|
| 97 |
+
| celery 5.4.0 | 3.8+ | — | — |
|
docs/architecture.md
CHANGED
|
@@ -1,30 +1,280 @@
|
|
| 1 |
-
# Architecture
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2 |
|
| 3 |
-
## 1. System Architecture
|
| 4 |
```mermaid
|
| 5 |
-
graph
|
| 6 |
-
|
| 7 |
-
|
| 8 |
-
|
| 9 |
-
|
| 10 |
-
|
| 11 |
-
|
| 12 |
-
|
| 13 |
-
|
| 14 |
-
|
| 15 |
-
|
| 16 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 17 |
```
|
| 18 |
|
| 19 |
-
##
|
|
|
|
| 20 |
```mermaid
|
| 21 |
graph LR
|
| 22 |
-
|
| 23 |
-
|
| 24 |
-
|
| 25 |
-
|
| 26 |
-
|
| 27 |
-
|
| 28 |
-
|
| 29 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 30 |
```
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Multilingual ABSA — Architecture Document
|
| 2 |
+
|
| 3 |
+
## System Overview
|
| 4 |
+
|
| 5 |
+
Multilingual ABSA is a production-ready Aspect-Based Sentiment Analysis system supporting English, Hindi, and Hinglish. It extracts aspect terms from product reviews and classifies their sentiment using a dual-engine architecture: INT8-quantized ONNX models for production inference with a zero-download rule-based fallback.
|
| 6 |
+
|
| 7 |
+
## High-Level Architecture
|
| 8 |
|
|
|
|
| 9 |
```mermaid
|
| 10 |
+
graph TB
|
| 11 |
+
Client[Client Browser / API Consumer]
|
| 12 |
+
Vercel[Vercel CDN]
|
| 13 |
+
Nginx[Nginx Reverse Proxy]
|
| 14 |
+
API[FastAPI Server]
|
| 15 |
+
Pipeline[ABSA Pipeline]
|
| 16 |
+
Lang[Language Detection]
|
| 17 |
+
Neural[ONNX Neural Engine<br/>INT8 Quantized]
|
| 18 |
+
Fallback[Rule-Based Engine<br/>140+ Aspect Keywords]
|
| 19 |
+
Celery[Celery Worker]
|
| 20 |
+
Redis[(Redis)]
|
| 21 |
+
PG[(PostgreSQL)]
|
| 22 |
+
Prom[Prometheus]
|
| 23 |
+
Graf[Grafana]
|
| 24 |
+
MLflow[(MLflow<br/>Experiment Tracking)]
|
| 25 |
+
|
| 26 |
+
Client --> Vercel
|
| 27 |
+
Vercel --> Nginx
|
| 28 |
+
Nginx --> API
|
| 29 |
+
API --> Pipeline
|
| 30 |
+
Pipeline --> Lang
|
| 31 |
+
Pipeline --> Neural
|
| 32 |
+
Pipeline --> Fallback
|
| 33 |
+
API --> Celery
|
| 34 |
+
Celery --> Redis
|
| 35 |
+
API --> PG
|
| 36 |
+
Prom -->|scrape /metrics| API
|
| 37 |
+
Graf --> Prom
|
| 38 |
+
MLflow --> Pipeline
|
| 39 |
```
|
| 40 |
|
| 41 |
+
## Component Architecture
|
| 42 |
+
|
| 43 |
```mermaid
|
| 44 |
graph LR
|
| 45 |
+
subgraph "Presentation Layer"
|
| 46 |
+
SPA[React SPA]
|
| 47 |
+
T_TAIL[TailwindCSS Theme]
|
| 48 |
+
RECH[Recharts Visualizations]
|
| 49 |
+
RQ[React Query]
|
| 50 |
+
end
|
| 51 |
+
subgraph "API Layer"
|
| 52 |
+
FAST[FastAPI]
|
| 53 |
+
CORS[CORS Middleware]
|
| 54 |
+
PROM[Prometheus Metrics]
|
| 55 |
+
PYD[Pydantic Schemas]
|
| 56 |
+
end
|
| 57 |
+
subgraph "Service Layer"
|
| 58 |
+
ABSA[ABSAPipeline]
|
| 59 |
+
LANG[LanguageService]
|
| 60 |
+
CEL[Celery Tasks]
|
| 61 |
+
end
|
| 62 |
+
subgraph "Data Layer"
|
| 63 |
+
SQLA[SQLAlchemy ORM]
|
| 64 |
+
PG[(PostgreSQL)]
|
| 65 |
+
RED[(Redis)]
|
| 66 |
+
end
|
| 67 |
+
subgraph "ML Layer"
|
| 68 |
+
ONNX_A[ORTModelFor<br/>TokenClassification]
|
| 69 |
+
ONNX_S[ORTModelFor<br/>SequenceClassification]
|
| 70 |
+
LEXICON[Aspect/Sentiment<br/>Lexicons]
|
| 71 |
+
end
|
| 72 |
+
subgraph "MLOps Layer"
|
| 73 |
+
MLF[MLflow Tracking]
|
| 74 |
+
DVC[DVC Versioning]
|
| 75 |
+
EVI[Evidently Drift]
|
| 76 |
+
end
|
| 77 |
+
|
| 78 |
+
SPA --> FAST
|
| 79 |
+
FAST --> CORS
|
| 80 |
+
FAST --> PROM
|
| 81 |
+
FAST --> PYD
|
| 82 |
+
FAST --> ABSA
|
| 83 |
+
FAST --> CEL
|
| 84 |
+
ABSA --> LANG
|
| 85 |
+
ABSA --> ONNX_A
|
| 86 |
+
ABSA --> ONNX_S
|
| 87 |
+
ABSA --> LEXICON
|
| 88 |
+
CEL --> RED
|
| 89 |
+
FAST --> SQLA
|
| 90 |
+
SQLA --> PG
|
| 91 |
+
ABSA --> MLF
|
| 92 |
```
|
| 93 |
+
|
| 94 |
+
## Deployment Architecture
|
| 95 |
+
|
| 96 |
+
```mermaid
|
| 97 |
+
graph TB
|
| 98 |
+
subgraph "Docker Compose (Local)"
|
| 99 |
+
DC_API[API Service<br/>uvicorn:8000]
|
| 100 |
+
DC_WORKER[Celery Worker]
|
| 101 |
+
DC_DASH[Dashboard<br/>Nginx:80]
|
| 102 |
+
DC_PG[PostgreSQL:5432]
|
| 103 |
+
DC_REDIS[Redis:6379]
|
| 104 |
+
DC_PROM[Prometheus:9090]
|
| 105 |
+
DC_GRAF[Grafana:3001]
|
| 106 |
+
end
|
| 107 |
+
subgraph "Railway (Production)"
|
| 108 |
+
RW_API[API Service<br/>$PORT]
|
| 109 |
+
RW_WORKER[Celery Worker]
|
| 110 |
+
RW_PG[PostgreSQL]
|
| 111 |
+
RW_REDIS[Redis]
|
| 112 |
+
end
|
| 113 |
+
subgraph "Vercel (Production)"
|
| 114 |
+
VC_DASH[React SPA]
|
| 115 |
+
VC_RW_ROUTE[rewrite /api/* -> Railway]
|
| 116 |
+
end
|
| 117 |
+
|
| 118 |
+
DC_DASH --> DC_API
|
| 119 |
+
DC_API --> DC_PG
|
| 120 |
+
DC_API --> DC_REDIS
|
| 121 |
+
DC_WORKER --> DC_REDIS
|
| 122 |
+
DC_WORKER --> DC_PG
|
| 123 |
+
DC_PROM -->|scrape| DC_API
|
| 124 |
+
DC_GRAF --> DC_PROM
|
| 125 |
+
|
| 126 |
+
VC_DASH --> VC_RW_ROUTE
|
| 127 |
+
VC_RW_ROUTE --> RW_API
|
| 128 |
+
RW_API --> RW_PG
|
| 129 |
+
RW_API --> RW_REDIS
|
| 130 |
+
RW_WORKER --> RW_REDIS
|
| 131 |
+
```
|
| 132 |
+
|
| 133 |
+
## ML Pipeline Architecture
|
| 134 |
+
|
| 135 |
+
```mermaid
|
| 136 |
+
graph TB
|
| 137 |
+
subgraph "Data Ingestion"
|
| 138 |
+
RAW[Raw Data<br/>SemEval 2014<br/>Amazon Hindi]
|
| 139 |
+
FAST[f astText LID<br/>lid.176.ftz]
|
| 140 |
+
end
|
| 141 |
+
subgraph "Preprocessing"
|
| 142 |
+
CLEAN[Text Cleaning<br/>Lowercase, URLs, Mentions]
|
| 143 |
+
TRANS[Transliteration<br/>Devanagari→Roman]
|
| 144 |
+
LANG_DET[Language Detection<br/>EN / HI / Hinglish]
|
| 145 |
+
BIO[BIO Tagging<br/>B-ASP / I-ASP / O]
|
| 146 |
+
TOK[XLM-R Tokenizer<br/>SentencePiece 128 tokens]
|
| 147 |
+
end
|
| 148 |
+
subgraph "Training"
|
| 149 |
+
ATE[Aspect Extraction<br/>Token Classification<br/>3 labels]
|
| 150 |
+
ASC[Sentiment Classification<br/>Sequence Classification<br/>4 labels]
|
| 151 |
+
BASELINE[Baseline<br/>TF-IDF + LR]
|
| 152 |
+
QLORA[QLoRA<br/>4-bit + LoRA]
|
| 153 |
+
JOINT[Joint ABSA<br/>Shared Encoder<br/>2 Heads]
|
| 154 |
+
end
|
| 155 |
+
subgraph "Optimization"
|
| 156 |
+
ONNX_EXP[ONNX Export<br/>optimum-onnx]
|
| 157 |
+
QUANT[INT8 Quantization<br/>Dynamic]
|
| 158 |
+
end
|
| 159 |
+
subgraph "Production"
|
| 160 |
+
INFERENCE[Dual-Engine<br/>Inference]
|
| 161 |
+
BATCH[Batch Processing<br/>Celery Worker]
|
| 162 |
+
end
|
| 163 |
+
subgraph "Evaluation"
|
| 164 |
+
EVAL_METRICS[Macro-F1<br/>Per-class F1<br/>Confusion Matrix]
|
| 165 |
+
LATENCY[Latency Benchmark<br/>P95 < 300ms]
|
| 166 |
+
CROSS[Cross-Lingual Eval<br/>EN→HI Zero-Shot]
|
| 167 |
+
end
|
| 168 |
+
|
| 169 |
+
RAW --> CLEAN
|
| 170 |
+
FAST --> LANG_DET
|
| 171 |
+
CLEAN --> LANG_DET
|
| 172 |
+
LANG_DET --> TRANS
|
| 173 |
+
TRANS --> TOK
|
| 174 |
+
TOK --> ATE
|
| 175 |
+
TOK --> ASC
|
| 176 |
+
BIO --> ATE
|
| 177 |
+
ATE --> JOINT
|
| 178 |
+
ASC --> JOINT
|
| 179 |
+
ATE --> ONNX_EXP
|
| 180 |
+
ASC --> ONNX_EXP
|
| 181 |
+
ONNX_EXP --> QUANT
|
| 182 |
+
QUANT --> INFERENCE
|
| 183 |
+
INFERENCE --> BATCH
|
| 184 |
+
ATE --> EVAL_METRICS
|
| 185 |
+
ASC --> EVAL_METRICS
|
| 186 |
+
BASELINE --> EVAL_METRICS
|
| 187 |
+
INFERENCE --> LATENCY
|
| 188 |
+
JOINT --> CROSS
|
| 189 |
+
```
|
| 190 |
+
|
| 191 |
+
## Data Flow
|
| 192 |
+
|
| 193 |
+
```mermaid
|
| 194 |
+
sequenceDiagram
|
| 195 |
+
participant C as Client
|
| 196 |
+
participant F as FastAPI
|
| 197 |
+
participant P as ABSAPipeline
|
| 198 |
+
participant L as LangService
|
| 199 |
+
participant N as ONNX Runtime
|
| 200 |
+
participant R as Rule Engine
|
| 201 |
+
participant D as PostgreSQL
|
| 202 |
+
participant M as Prometheus
|
| 203 |
+
|
| 204 |
+
C->>F: POST /predict {text, language?}
|
| 205 |
+
F->>P: pipeline.predict(text, lang)
|
| 206 |
+
P->>L: detect_language(text)
|
| 207 |
+
L-->>P: "en" | "hi" | "hinglish"
|
| 208 |
+
alt ONNX Models Available
|
| 209 |
+
P->>N: Tokenize text
|
| 210 |
+
N-->>P: Token IDs + Attention Mask
|
| 211 |
+
P->>N: ORTModelForTokenClassification
|
| 212 |
+
N-->>P: BIO Logits → Argmax → Spans
|
| 213 |
+
P->>N: Per-aspect ORTModelForSequenceClassification
|
| 214 |
+
N-->>P: Sentiment Logits → Softmax
|
| 215 |
+
else Rule-Based Fallback
|
| 216 |
+
P->>R: _extract_aspects(text)
|
| 217 |
+
R-->>P: [(aspect, start, end)]
|
| 218 |
+
P->>R: _score_sentence(context)
|
| 219 |
+
R-->>P: (pos_score, neg_score)
|
| 220 |
+
P->>R: _score_to_label(pos, neg)
|
| 221 |
+
R-->>P: (sentiment, confidence)
|
| 222 |
+
end
|
| 223 |
+
P-->>F: PredictionResponse
|
| 224 |
+
F->>D: INSERT Review + AspectResults
|
| 225 |
+
D-->>F: IDs
|
| 226 |
+
F-->>C: JSON Response
|
| 227 |
+
F->>M: Record latency + status
|
| 228 |
+
```
|
| 229 |
+
|
| 230 |
+
## Infrastructure
|
| 231 |
+
|
| 232 |
+
```mermaid
|
| 233 |
+
graph TB
|
| 234 |
+
subgraph "Edge"
|
| 235 |
+
DNS[DNS: Vercel]
|
| 236 |
+
SSL[TLS Termination]
|
| 237 |
+
end
|
| 238 |
+
subgraph "Frontend Hosting"
|
| 239 |
+
FE[Vercel<br/>Static SPA]
|
| 240 |
+
FE_CDN[Global CDN]
|
| 241 |
+
end
|
| 242 |
+
subgraph "Backend Hosting"
|
| 243 |
+
BE[Railway<br/>Docker Container]
|
| 244 |
+
HEALTH[Health Check<br/>/health]
|
| 245 |
+
AUTO[Auto-Restart<br/>On Failure]
|
| 246 |
+
end
|
| 247 |
+
subgraph "Data Services"
|
| 248 |
+
PG[PostgreSQL<br/>Railway Managed]
|
| 249 |
+
RD[Redis<br/>Railway Managed]
|
| 250 |
+
end
|
| 251 |
+
subgraph "Observability"
|
| 252 |
+
PROM[Prometheus<br/>15-day Retention]
|
| 253 |
+
GRAF[Grafana<br/>Pre-provisioned Dashboard]
|
| 254 |
+
MLFLOW[MLflow<br/>SQLite Backend]
|
| 255 |
+
end
|
| 256 |
+
|
| 257 |
+
DNS --> SSL
|
| 258 |
+
SSL --> FE
|
| 259 |
+
FE --> FE_CDN
|
| 260 |
+
FE_CDN --> BE
|
| 261 |
+
BE --> HEALTH
|
| 262 |
+
BE --> AUTO
|
| 263 |
+
BE --> PG
|
| 264 |
+
BE --> RD
|
| 265 |
+
PROM -->|scrape| BE
|
| 266 |
+
GRAF --> PROM
|
| 267 |
+
```
|
| 268 |
+
|
| 269 |
+
## Design Decisions
|
| 270 |
+
|
| 271 |
+
| Decision | Rationale |
|
| 272 |
+
|----------|-----------|
|
| 273 |
+
| **Separate ONNX models** for ATE and ASC | Combined graph has dynamic-axis export fragility in optimum-onnx |
|
| 274 |
+
| **Rule-based fallback** with no downloads | Zero startup time, works offline, graceful degradation |
|
| 275 |
+
| **Lexicon-based sentiment** with negation handling | 3-word window for "not good" → negative reversal |
|
| 276 |
+
| **XLM-RoBERTa base** (not large) | 0.3B params fine-tunes on 16GB GPU, adequate cross-lingual transfer |
|
| 277 |
+
| **ONNX INT8 dynamic quantization** | 4x smaller, 4.6x faster than PyTorch with only 1% F1 drop |
|
| 278 |
+
| **SQLite for dev, PostgreSQL for prod** | Zero-config local dev, production-grade concurrency |
|
| 279 |
+
| **Celery for batch only** | Single-review inference is fast enough for synchronous response |
|
| 280 |
+
| **Mock data in dashboard charts** | Decoupled frontend/backend development; real integration deferred |
|