vtdung23 commited on
Commit
2541529
·
1 Parent(s): f31c75b
app.tex ADDED
@@ -0,0 +1,516 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ % ============================================
2
+ % CHƯƠNG: XÂY DỰNG VÀ TRIỂN KHAI ỨNG DỤNG
3
+ % ============================================
4
+ \setlength{\parindent}{0pt}
5
+
6
+ \section{Xây dựng và Triển khai Ứng dụng}
7
+
8
+ Chương này trình bày chi tiết về kiến trúc hệ thống, giao diện người dùng và quy trình triển khai ứng dụng dự đoán đánh giá sản phẩm từ bình luận tiếng Việt.
9
+
10
+ % ============================================
11
+ % PHẦN 1: KIẾN TRÚC HỆ THỐNG
12
+ % ============================================
13
+ \subsection{Kiến trúc Hệ thống}
14
+
15
+ Hệ thống được thiết kế theo mô hình \textbf{Client-Server} với kiến trúc phân lớp (Layered Architecture), đảm bảo tính module hóa và dễ dàng bảo trì.
16
+
17
+ \subsubsection{Tổng quan Kiến trúc}
18
+
19
+ Hệ thống bao gồm 4 lớp chính:
20
+
21
+ \begin{itemize}
22
+ \item \textbf{Frontend Layer}: Giao diện người dùng được xây dựng bằng HTML/CSS (TailwindCSS) và JavaScript, sử dụng Jinja2 Template Engine để render động.
23
+ \item \textbf{API Layer}: FastAPI Backend xử lý các HTTP request thông qua RESTful API endpoints.
24
+ \item \textbf{Service Layer}: Các service xử lý business logic bao gồm Authentication Service, ML Prediction Service và Visualization Service.
25
+ \item \textbf{Data Layer}: SQLAlchemy ORM kết nối với cơ sở dữ liệu SQLite (development) hoặc PostgreSQL (production).
26
+ \end{itemize}
27
+
28
+ \begin{figure}[H]
29
+ \centering
30
+ \includegraphics[width=0.9\textwidth]{images/kien_truc_he_thong.png}
31
+ \caption{Sơ đồ kiến trúc tổng quan của hệ thống}
32
+ \label{fig:kien_truc_he_thong}
33
+ \end{figure}
34
+
35
+ \subsubsection{Frontend - Giao diện Người dùng}
36
+
37
+ Frontend được xây dựng với các công nghệ:
38
+
39
+ \begin{itemize}
40
+ \item \textbf{Jinja2 Templates}: Engine template của Python, tích hợp chặt chẽ với FastAPI để render các trang HTML động.
41
+ \item \textbf{TailwindCSS}: Framework CSS utility-first giúp xây dựng giao diện responsive và hiện đại.
42
+ \item \textbf{JavaScript (Fetch API)}: Xử lý các AJAX request để giao tiếp bất đồng bộ với Backend.
43
+ \item \textbf{Chart.js}: Thư viện visualize để hiển thị biểu đồ phân bố rating.
44
+ \end{itemize}
45
+
46
+ Khi người dùng thực hiện thao tác (ví dụ: nhập comment và nhấn "Predict"), JavaScript sẽ gửi HTTP POST request đến Backend API, nhận response JSON và cập nhật giao diện mà không cần reload trang.
47
+
48
+ \subsubsection{Backend - FastAPI Server}
49
+
50
+ Backend được xây dựng trên framework \textbf{FastAPI} với Python, có các đặc điểm nổi bật:
51
+
52
+ \begin{itemize}
53
+ \item \textbf{High Performance}: Xây dựng trên Starlette và Pydantic, FastAPI là một trong những framework Python nhanh nhất.
54
+ \item \textbf{Auto Documentation}: Tự động sinh Swagger UI (/docs) và ReDoc (/redoc) cho API documentation.
55
+ \item \textbf{Type Hints}: Sử dụng Python type hints để validation và serialization tự động.
56
+ \end{itemize}
57
+
58
+ Cấu trúc Router của Backend:
59
+
60
+ \vietnameselst
61
+ \begin{lstlisting}[language=Python]
62
+ # main.py - Khoi tao FastAPI Application
63
+ from fastapi import FastAPI
64
+ from app.routers import auth, prediction, dashboard
65
+
66
+ app = FastAPI(
67
+ title="Vietnamese Product Rating Prediction API",
68
+ description="ML-powered sentiment analysis for Vietnamese reviews",
69
+ version="1.0.0"
70
+ )
71
+
72
+ # Dang ky cac Router
73
+ app.include_router(auth.router, prefix="/api/auth", tags=["Authentication"])
74
+ app.include_router(prediction.router, prefix="/api/predict", tags=["Prediction"])
75
+ app.include_router(dashboard.router, tags=["Dashboard"])
76
+ \end{lstlisting}
77
+
78
+ \subsubsection{Cơ chế Lazy Loading của Model}
79
+
80
+ Một trong những tối ưu quan trọng nhất của hệ thống là cơ chế \textbf{Lazy Loading} cho ML Model. Thay vì load model ngay khi khởi động server (có thể mất 30-60 giây với model PhoBERT ~500MB), model chỉ được load vào RAM khi có request đầu tiên.
81
+
82
+ \vietnameselst
83
+ \begin{lstlisting}[language=Python]
84
+ class MLPredictionService:
85
+ """ML Service voi co che Lazy Loading"""
86
+
87
+ def __init__(self):
88
+ # Chi khoi tao cac bien, KHONG load model
89
+ self.model = None
90
+ self.tokenizer = None
91
+ self.model_loaded = False
92
+
93
+ # Dinh nghia Repo ID chua model tren Hugging Face
94
+ self.MODEL_REPO_ID = "vtdung23/my-phobert-models"
95
+ self.MODEL_FILENAME = "best_phoBER.pth"
96
+
97
+ print("ML Service initialized (Model se load khi co request dau tien)")
98
+
99
+ def _load_model(self):
100
+ """Load model chi khi can thiet (lazy loading)"""
101
+ if self.model_loaded:
102
+ return # Da load roi, khong can load lai
103
+
104
+ print("Dang load ML model (first request)...")
105
+
106
+ # Import cac thu vien nang chi khi can
107
+ import torch
108
+ from transformers import AutoTokenizer, RobertaForSequenceClassification
109
+ from huggingface_hub import hf_hub_download
110
+
111
+ # Tai file weights tu Hugging Face Hub
112
+ model_path = hf_hub_download(
113
+ repo_id=self.MODEL_REPO_ID,
114
+ filename=self.MODEL_FILENAME,
115
+ repo_type="model"
116
+ )
117
+
118
+ # Load tokenizer va model
119
+ self.tokenizer = AutoTokenizer.from_pretrained("vinai/phobert-base")
120
+ self.model = RobertaForSequenceClassification.from_pretrained(
121
+ "vinai/phobert-base",
122
+ num_labels=5
123
+ )
124
+
125
+ # Load trained weights
126
+ state_dict = torch.load(model_path, map_location="cpu")
127
+ self.model.load_state_dict(state_dict)
128
+ self.model.eval()
129
+
130
+ self.model_loaded = True
131
+ print("Model loaded thanh cong!")
132
+
133
+ def predict_single(self, text: str):
134
+ """Du doan rating cho 1 comment"""
135
+ self._load_model() # Dam bao model da duoc load
136
+ # ... logic du doan ...
137
+ \end{lstlisting}
138
+
139
+ \textbf{Lợi ích của Lazy Loading:}
140
+ \begin{itemize}
141
+ \item \textbf{Khởi động nhanh}: Server start trong vài giây thay vì phải chờ load model.
142
+ \item \textbf{Tiết kiệm RAM}: Trên các nền tảng miễn phí (Hugging Face Spaces, Render), RAM bị giới hạn. Model chỉ chiếm RAM khi thực sự cần thiết.
143
+ \item \textbf{Cold Start Optimization}: Phù hợp với serverless hoặc container-based deployment.
144
+ \end{itemize}
145
+
146
+ \subsubsection{Luồng Dữ liệu (Data Flow)}
147
+
148
+ Sơ đồ dưới đây mô tả luồng đi của dữ liệu khi người dùng thực hiện dự đoán:
149
+
150
+ \begin{figure}[H]
151
+ \centering
152
+ \includegraphics[width=0.95\textwidth]{images/data_flow.png}
153
+ \caption{Sơ đồ luồng dữ liệu của hệ thống dự đoán}
154
+ \label{fig:data_flow}
155
+ \end{figure}
156
+
157
+ \textbf{Mô tả luồng dữ liệu:}
158
+
159
+ \begin{enumerate}
160
+ \item \textbf{User Input}: Người dùng nhập comment tiếng Việt vào form trên Dashboard.
161
+ \item \textbf{HTTP Request}: JavaScript gửi POST request đến endpoint \texttt{/api/predict/single} với JSON body chứa comment.
162
+ \item \textbf{Authentication}: Middleware kiểm tra JWT token trong header để xác thực người dùng.
163
+ \item \textbf{Prediction Router}: Router nhận request, validate input bằng Pydantic schema.
164
+ \item \textbf{ML Service}:
165
+ \begin{itemize}
166
+ \item Lazy load model nếu chưa được load.
167
+ \item Tiền xử lý văn bản (word tokenization với Underthesea).
168
+ \item Tokenize với PhoBERT tokenizer.
169
+ \item Inference với model PhoBERT fine-tuned.
170
+ \item Trả về rating (1-5 sao) và confidence score.
171
+ \end{itemize}
172
+ \item \textbf{Save History}: Lưu kết quả dự đoán vào database để theo dõi lịch sử.
173
+ \item \textbf{Response}: Trả về JSON response với rating, confidence, highlighted keywords.
174
+ \item \textbf{UI Update}: JavaScript nhận response và cập nhật giao diện hiển thị kết quả.
175
+ \end{enumerate}
176
+
177
+ % ============================================
178
+ % PHẦN 2: GIAO DIỆN VÀ CHỨC NĂNG
179
+ % ============================================
180
+ \subsection{Giao diện và Chức năng}
181
+
182
+ \subsubsection{Màn hình Đăng nhập và Đăng ký}
183
+
184
+ Hệ thống yêu cầu người dùng đăng nhập trước khi sử dụng các tính năng dự đoán. Việc này giúp:
185
+ \begin{itemize}
186
+ \item Theo dõi lịch sử dự đoán của từng người dùng.
187
+ \item Bảo vệ API endpoints khỏi các truy cập trái phép.
188
+ \item Phân quyền và quản lý người dùng trong tương lai.
189
+ \end{itemize}
190
+
191
+ Xác thực được thực hiện bằng \textbf{JWT (JSON Web Token)} với thuật toán HS256 và mật khẩu được hash bằng \textbf{bcrypt}.
192
+
193
+ \subsubsection{Màn hình Dashboard - Giao diện Chính}
194
+
195
+ Dashboard là màn hình chính của ứng dụng, nơi người dùng thực hiện các thao tác dự đoán. Giao diện được thiết kế theo phong cách hiện đại với TailwindCSS, hỗ trợ cả Light Mode và Dark Mode.
196
+
197
+ \begin{figure}[H]
198
+ \centering
199
+ \includegraphics[width=0.9\textwidth]{images/giao_dien_chinh.png}
200
+ \caption{Màn hình Dashboard - Giao diện chính của ứng dụng}
201
+ \label{fig:giao_dien_chinh}
202
+ \end{figure}
203
+
204
+ \textbf{Các thành phần chính của Dashboard:}
205
+
206
+ \begin{itemize}
207
+ \item \textbf{Navigation Bar}: Hiển thị tên người dùng và nút Logout.
208
+ \item \textbf{Welcome Section}: Giới thiệu các tính năng chính của ứng dụng.
209
+ \item \textbf{Tab Input Mode}: Cho phép chuyển đổi giữa "Single Comment" và "Upload CSV".
210
+ \item \textbf{Input Area}: Vùng nhập liệu comment hoặc upload file CSV.
211
+ \item \textbf{Result Section}: Hiển thị kết quả dự đoán với các visualization.
212
+ \end{itemize}
213
+
214
+ \subsubsection{Chức năng Dự đoán Đơn lẻ (Single Prediction)}
215
+
216
+ Đây là chức năng cơ bản nhất, cho phép người dùng nhập một comment tiếng Việt và nhận kết quả dự đoán.
217
+
218
+ \textbf{Quy trình sử dụng:}
219
+ \begin{enumerate}
220
+ \item Chọn tab "Single Comment".
221
+ \item Nhập comment tiếng Việt vào textarea.
222
+ \item (Tùy chọn) Bật checkbox "Bao gồm giải thích AI" để nhận word importance.
223
+ \item Nhấn nút "Predict Rating".
224
+ \item Xem kết quả hiển thị bên dưới.
225
+ \end{enumerate}
226
+
227
+ \begin{figure}[H]
228
+ \centering
229
+ \includegraphics[width=0.85\textwidth]{images/ket_qua_du_doan.png}
230
+ \caption{Kết quả dự đoán với Rating, Confidence và Keyword Highlighting}
231
+ \label{fig:ket_qua_du_doan}
232
+ \end{figure}
233
+
234
+ \textbf{Thông tin hiển thị trong kết quả:}
235
+ \begin{itemize}
236
+ \item \textbf{Predicted Rating}: Số sao dự đoán từ 1-5, hiển thị dạng số và icon sao.
237
+ \item \textbf{Confidence Score}: Độ tin cậy của dự đoán (0-100\%).
238
+ \item \textbf{Highlighted Comment}: Comment gốc với các keyword tích cực (xanh) và tiêu cực (đỏ) được highlight.
239
+ \item \textbf{Keywords Found}: Danh sách các keyword tích cực/tiêu cực được phát hiện.
240
+ \item \textbf{AI Explanation} (nếu bật): Biểu đồ word importance thể hiện ảnh hưởng của từng từ đến kết quả.
241
+ \end{itemize}
242
+
243
+ \subsubsection{Chức năng Dự đoán Hàng loạt (Batch Prediction)}
244
+
245
+ Tính năng này cho phép upload file CSV chứa nhiều comment để dự đoán đồng thời, phù hợp cho việc phân tích dữ liệu lớn.
246
+
247
+ \textbf{Yêu cầu file CSV:}
248
+ \begin{lstlisting}[language=Python]
249
+ Comment
250
+ "San pham rat tot, dong goi can than"
251
+ "Chat luong kem, khong nhu mo ta"
252
+ "Giao hang nhanh, san pham on"
253
+ "Rat hai long voi san pham nay"
254
+ \end{lstlisting}
255
+
256
+ \textbf{Kết quả Batch Prediction bao gồm:}
257
+
258
+ \begin{itemize}
259
+ \item \textbf{Rating Distribution Chart}: Biểu đồ tròn/cột thể hiện phân bố số lượng comment theo từng mức rating.
260
+ \item \textbf{Word Cloud}: Đám mây từ khóa phổ biến trong các comment, kích thước từ tỷ lệ với tần suất xuất hiện.
261
+ \item \textbf{N-gram Analysis}: Phân tích các cụm từ phổ biến (unigrams, bigrams, trigrams).
262
+ \item \textbf{Keyword Frequency}: Thống kê tần suất xuất hiện của các keyword tích cực và tiêu cực.
263
+ \item \textbf{Results Table}: Bảng chi tiết kết quả dự đoán cho từng comment.
264
+ \item \textbf{Export Options}: Xuất kết quả ra file CSV hoặc PDF report.
265
+ \end{itemize}
266
+
267
+ \begin{figure}[H]
268
+ \centering
269
+ \includegraphics[width=0.9\textwidth]{images/batch_result.png}
270
+ \caption{Kết quả Batch Prediction với biểu đồ và Word Cloud}
271
+ \label{fig:batch_result}
272
+ \end{figure}
273
+
274
+ \subsubsection{Các Tính năng Nâng cao}
275
+
276
+ \textbf{1. Keyword Highlighting:}
277
+
278
+ Hệ thống tự động nhận diện và highlight các từ khóa tích cực/tiêu cực trong comment:
279
+
280
+ \vietnameselst
281
+ \begin{lstlisting}[language=Python]
282
+ class KeywordAnalyzer:
283
+ def __init__(self):
284
+ # Tu khoa tich cuc
285
+ self.positive_words = [
286
+ 'tot', 'dep', 'tuyet voi', 'xuat sac', 'hoan hao',
287
+ 'chat luong', 'nhanh', 'hai long', 'ung', 'de thuong'
288
+ ]
289
+ # Tu khoa tieu cuc
290
+ self.negative_words = [
291
+ 'te', 'xau', 'kem', 'that vong', 'loi', 'hong',
292
+ 'cham', 'gia', 'dat', 'khong dang'
293
+ ]
294
+
295
+ def analyze(self, text: str) -> Dict:
296
+ """Phan tich text va tra ve cac keyword tim thay"""
297
+ found_positive = [w for w in self.positive_words if w in text.lower()]
298
+ found_negative = [w for w in self.negative_words if w in text.lower()]
299
+ return {
300
+ 'positive_keywords': found_positive,
301
+ 'negative_keywords': found_negative
302
+ }
303
+ \end{lstlisting}
304
+
305
+ \textbf{2. N-gram Analysis:}
306
+
307
+ Phân tích các cụm từ phổ biến giúp hiểu rõ hơn về nội dung các review:
308
+ \begin{itemize}
309
+ \item \textbf{Unigrams} (1 từ): "tốt", "đẹp", "nhanh"
310
+ \item \textbf{Bigrams} (2 từ): "giao hàng", "chất lượng", "đóng gói"
311
+ \item \textbf{Trigrams} (3 từ): "rất hài lòng", "giao hàng nhanh", "đúng như mô tả"
312
+ \end{itemize}
313
+
314
+ \textbf{3. Word Importance Explanation:}
315
+
316
+ Khi bật tùy chọn "AI Explanation", hệ thống sẽ hiển thị mức độ ảnh hưởng của từng từ đến kết quả dự đoán, giúp người dùng hiểu tại sao model đưa ra kết quả như vậy.
317
+
318
+ \subsubsection{Trải nghiệm Người dùng (UX)}
319
+
320
+ Giao diện được thiết kế với các nguyên tắc UX hiện đại:
321
+
322
+ \begin{itemize}
323
+ \item \textbf{Responsive Design}: Tự động điều chỉnh layout trên mọi kích thước màn hình (desktop, tablet, mobile).
324
+ \item \textbf{Loading States}: Hiển thị skeleton loading khi đang xử lý request, giúp người dùng biết hệ thống đang hoạt động.
325
+ \item \textbf{Real-time Feedback}: Kết quả hiển thị ngay trên trang mà không cần reload.
326
+ \item \textbf{Dark Mode Support}: Hỗ trợ chế độ tối để giảm mỏi mắt khi làm việc lâu.
327
+ \item \textbf{Error Handling}: Thông báo lỗi rõ ràng khi có vấn đề xảy ra.
328
+ \end{itemize}
329
+
330
+ % ============================================
331
+ % PHẦN 3: TRIỂN KHAI (DEPLOYMENT)
332
+ % ============================================
333
+ \subsection{Triển khai Ứng dụng (Deployment)}
334
+
335
+ Ứng dụng được thiết kế để có thể triển khai trên nhiều môi trường khác nhau, từ local development đến các nền tảng cloud.
336
+
337
+ \subsubsection{Triển khai trên Cloud - Hugging Face Spaces}
338
+
339
+ \textbf{Hugging Face Spaces} là nền tảng hosting miễn phí cho các ứng dụng Machine Learning, được chọn vì các lý do:
340
+
341
+ \begin{itemize}
342
+ \item \textbf{Miễn phí}: Cung cấp CPU với 16GB RAM miễn phí, đủ để chạy model PhoBERT.
343
+ \item \textbf{Docker Support}: Hỗ trợ Docker SDK, cho phép deploy các ứng dụng phức tạp.
344
+ \item \textbf{Git-based Deployment}: Deploy bằng git push, dễ dàng cập nhật.
345
+ \item \textbf{Integrated với Hugging Face Hub}: Dễ dàng tải model từ Hub.
346
+ \end{itemize}
347
+
348
+ \textbf{Cấu hình Dockerfile cho Hugging Face Spaces:}
349
+
350
+ \begin{lstlisting}[language=Python]
351
+ # Dockerfile for Hugging Face Spaces
352
+ FROM python:3.10-slim
353
+
354
+ # Cai dat font cho WordCloud
355
+ RUN apt-get update && apt-get install -y \
356
+ fonts-dejavu fonts-dejavu-core build-essential gcc \
357
+ && rm -rf /var/lib/apt/lists/*
358
+
359
+ # Tao non-root user (bat buoc tren HF Spaces)
360
+ RUN useradd -m -u 1000 user
361
+ WORKDIR /app
362
+
363
+ # Cai dat dependencies
364
+ COPY --chown=user:user requirements.txt .
365
+ RUN pip install --no-cache-dir -r requirements.txt
366
+
367
+ # Copy source code
368
+ COPY --chown=user:user . .
369
+
370
+ # Tao thu muc can thiet
371
+ RUN mkdir -p /app/app/static/uploads/wordclouds && \
372
+ mkdir -p /app/app/database && \
373
+ chmod -R 777 /app/app/static/uploads
374
+
375
+ USER user
376
+ EXPOSE 7860
377
+
378
+ # Start FastAPI (port 7860 bat buoc tren HF Spaces)
379
+ CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "7860"]
380
+ \end{lstlisting}
381
+
382
+ \textbf{Biến môi trường cần thiết:}
383
+ \begin{itemize}
384
+ \item \texttt{DATABASE\_URL}: Connection string đến PostgreSQL database.
385
+ \item \texttt{SECRET\_KEY}: Key bí mật để mã hóa JWT token.
386
+ \end{itemize}
387
+
388
+ \textbf{Link Demo ứng dụng:}
389
+
390
+ Ứng dụng hiện đang hoạt động tại: \url{https://huggingface.co/spaces/vtdung23/RatingPrediction}
391
+
392
+ \subsubsection{Triển khai Local - Cài đặt trên Máy Cá nhân}
393
+
394
+ Hướng dẫn từng bước để chạy ứng dụng trên máy tính cá nhân:
395
+
396
+ \textbf{Yêu cầu hệ thống:}
397
+ \begin{itemize}
398
+ \item Python 3.10 trở lên
399
+ \item Git (để clone repository)
400
+ \item RAM tối thiểu 8GB (khuyến nghị 16GB cho model PhoBERT)
401
+ \item Dung lượng ổ cứng trống: 3GB (cho dependencies và model)
402
+ \end{itemize}
403
+
404
+ \textbf{Bước 1: Clone Project từ Git}
405
+
406
+ \begin{lstlisting}[language=bash]
407
+ # Clone repository
408
+ git clone https://github.com/your-username/rating-prediction.git
409
+
410
+ # Di chuyen vao thu muc project
411
+ cd rating-prediction
412
+ \end{lstlisting}
413
+
414
+ \textbf{Bước 2: Tạo và Kích hoạt Môi trường ảo}
415
+
416
+ \vietnameselst
417
+ \begin{lstlisting}[language=bash]
418
+ # Option A: Su dung Conda (khuyen nghi)
419
+ conda create -p ./env python=3.10 -y
420
+ conda activate ./env
421
+
422
+ # Option B: Su dung venv
423
+ python -m venv env
424
+
425
+ # Kich hoat tren Windows:
426
+ env\Scripts\activate
427
+
428
+ # Kich hoat tren Linux/Mac:
429
+ source env/bin/activate
430
+ \end{lstlisting}
431
+
432
+ \textbf{Bước 3: Cài đặt Thư viện}
433
+
434
+ \begin{lstlisting}[language=bash]
435
+ # Cai dat tat ca dependencies tu requirements.txt
436
+ pip install -r requirements.txt
437
+
438
+ # Qua trinh nay co the mat 5-10 phut
439
+ # tuy thuoc vao toc do mang (can tai PyTorch, Transformers)
440
+ \end{lstlisting}
441
+
442
+ \textbf{Bước 4: Chạy Ứng dụng}
443
+
444
+ \begin{lstlisting}[language=bash]
445
+ # Chay server development
446
+ python main.py
447
+
448
+ # Hoac su dung uvicorn truc tiep
449
+ uvicorn main:app --host 0.0.0.0 --port 8000 --reload
450
+ \end{lstlisting}
451
+
452
+ \textbf{Bước 5: Truy cập Ứng dụng}
453
+
454
+ Sau khi server khởi động thành công, mở trình duyệt và truy cập:
455
+
456
+ \begin{itemize}
457
+ \item \textbf{Dashboard}: \url{http://localhost:8000}
458
+ \item \textbf{Swagger API Docs}: \url{http://localhost:8000/docs}
459
+ \item \textbf{ReDoc}: \url{http://localhost:8000/redoc}
460
+ \end{itemize}
461
+
462
+ \textbf{Lưu ý quan trọng:}
463
+ \begin{itemize}
464
+ \item Lần đầu tiên thực hiện dự đoán, hệ thống sẽ tự động tải model PhoBERT từ Hugging Face Hub (~500MB). Quá trình này có thể mất vài phút tùy tốc độ mạng.
465
+ \item Đảm bảo máy tính có đủ RAM trống (ít nhất 4GB) khi model được load.
466
+ \item Trên Windows, nếu gặp lỗi với thư viện \texttt{underthesea}, cần cài đặt Visual C++ Build Tools.
467
+ \end{itemize}
468
+
469
+ \subsubsection{So sánh các Phương pháp Triển khai}
470
+
471
+ \begin{table}[H]
472
+ \centering
473
+ \begin{tabular}{|l|c|c|}
474
+ \hline
475
+ \textbf{Tiêu chí} & \textbf{Hugging Face Spaces} & \textbf{Local} \\
476
+ \hline
477
+ Chi phí & Miễn phí (CPU 16GB) & Miễn phí \\
478
+ \hline
479
+ Cấu hình & Docker required & Chỉ cần Python \\
480
+ \hline
481
+ Truy cập & Public URL & localhost only \\
482
+ \hline
483
+ Uptime & 24/7 (auto sleep) & Khi máy bật \\
484
+ \hline
485
+ Phù hợp & Demo, Production & Development, Testing \\
486
+ \hline
487
+ \end{tabular}
488
+ \caption{So sánh các phương pháp triển khai}
489
+ \label{tab:deploy_comparison}
490
+ \end{table}
491
+
492
+ \subsubsection{Cấu trúc Thư mục Project}
493
+
494
+ \begin{lstlisting}[language=bash]
495
+ RatingPrediction/
496
+ |-- main.py # Entry point FastAPI
497
+ |-- requirements.txt # Python dependencies
498
+ |-- Dockerfile # Docker configuration
499
+ |-- app/
500
+ | |-- config.py # Cau hinh ung dung
501
+ | |-- database.py # Database connection
502
+ | |-- models.py # SQLAlchemy models
503
+ | |-- schemas.py # Pydantic schemas
504
+ | |-- routers/
505
+ | | |-- auth.py # Authentication endpoints
506
+ | | |-- prediction.py # Prediction endpoints
507
+ | | |-- dashboard.py # Dashboard pages
508
+ | |-- services/
509
+ | | |-- auth_service.py # JWT & password handling
510
+ | | |-- ml_service.py # ML prediction logic
511
+ | | |-- visualization_service.py # Charts, WordCloud
512
+ | |-- templates/ # Jinja2 HTML templates
513
+ | |-- static/ # CSS, JS, uploaded files
514
+ \end{lstlisting}
515
+
516
+ Với cấu trúc module hóa này, việc bảo trì và mở rộng ứng dụng trở nên dễ dàng. Mỗi thành phần có trách nhiệm riêng biệt, tuân theo nguyên tắc Single Responsibility Principle.
app/database/rating_prediction.db CHANGED
Binary files a/app/database/rating_prediction.db and b/app/database/rating_prediction.db differ
 
app/services/__pycache__/ml_service.cpython-313.pyc CHANGED
Binary files a/app/services/__pycache__/ml_service.cpython-313.pyc and b/app/services/__pycache__/ml_service.cpython-313.pyc differ
 
app/services/report_service.py CHANGED
@@ -31,25 +31,95 @@ class ReportService:
31
 
32
  def __init__(self):
33
  self.styles = getSampleStyleSheet()
34
- self._setup_custom_styles()
35
  self._setup_fonts()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
36
 
37
  def _setup_fonts(self):
38
  """Setup fonts for Vietnamese character support"""
 
 
 
39
  try:
40
- # Try to use DejaVu font which supports Vietnamese characters
41
- pdfmetrics.registerFont(TTFont('DejaVu', '/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf'))
42
- # Register bold variant
43
- pdfmetrics.registerFont(TTFont('DejaVuBold', '/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf'))
 
 
 
 
 
 
 
 
44
  except Exception as e:
45
- # If fonts not found, continue with default fonts
46
- print(f"Warning: Could not load Vietnamese fonts: {e}")
 
 
47
 
48
  def _setup_custom_styles(self):
49
  """Setup custom paragraph styles"""
50
- # Use DejaVu font for Vietnamese support, fallback to Helvetica
51
- font_name = 'DejaVu'
52
- font_name_bold = 'DejaVuBold'
53
 
54
  self.styles.add(ParagraphStyle(
55
  name='CustomTitle',
 
31
 
32
  def __init__(self):
33
  self.styles = getSampleStyleSheet()
 
34
  self._setup_fonts()
35
+ self._setup_custom_styles()
36
+
37
+ def _get_font_path(self):
38
+ """Get font path based on OS"""
39
+ import platform
40
+ import os
41
+
42
+ system = platform.system()
43
+
44
+ # Define possible font paths for different OS
45
+ font_paths = {
46
+ 'Linux': [
47
+ '/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf',
48
+ '/usr/share/fonts/TTF/DejaVuSans.ttf',
49
+ ],
50
+ 'Windows': [
51
+ 'C:/Windows/Fonts/arial.ttf',
52
+ 'C:/Windows/Fonts/segoeui.ttf',
53
+ 'C:/Windows/Fonts/tahoma.ttf',
54
+ ],
55
+ 'Darwin': [ # macOS
56
+ '/Library/Fonts/Arial.ttf',
57
+ '/System/Library/Fonts/Helvetica.ttc',
58
+ ]
59
+ }
60
+
61
+ font_bold_paths = {
62
+ 'Linux': [
63
+ '/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf',
64
+ '/usr/share/fonts/TTF/DejaVuSans-Bold.ttf',
65
+ ],
66
+ 'Windows': [
67
+ 'C:/Windows/Fonts/arialbd.ttf',
68
+ 'C:/Windows/Fonts/segoeuib.ttf',
69
+ 'C:/Windows/Fonts/tahomabd.ttf',
70
+ ],
71
+ 'Darwin': [
72
+ '/Library/Fonts/Arial Bold.ttf',
73
+ ]
74
+ }
75
+
76
+ paths = font_paths.get(system, font_paths['Linux'])
77
+ bold_paths = font_bold_paths.get(system, font_bold_paths['Linux'])
78
+
79
+ font_path = None
80
+ font_bold_path = None
81
+
82
+ for path in paths:
83
+ if os.path.exists(path):
84
+ font_path = path
85
+ break
86
+
87
+ for path in bold_paths:
88
+ if os.path.exists(path):
89
+ font_bold_path = path
90
+ break
91
+
92
+ return font_path, font_bold_path
93
 
94
  def _setup_fonts(self):
95
  """Setup fonts for Vietnamese character support"""
96
+ self.font_name = 'Helvetica'
97
+ self.font_name_bold = 'Helvetica-Bold'
98
+
99
  try:
100
+ font_path, font_bold_path = self._get_font_path()
101
+
102
+ if font_path:
103
+ pdfmetrics.registerFont(TTFont('CustomFont', font_path))
104
+ self.font_name = 'CustomFont'
105
+ print(f"✅ Loaded font: {font_path}")
106
+
107
+ if font_bold_path:
108
+ pdfmetrics.registerFont(TTFont('CustomFontBold', font_bold_path))
109
+ self.font_name_bold = 'CustomFontBold'
110
+ print(f"✅ Loaded bold font: {font_bold_path}")
111
+
112
  except Exception as e:
113
+ # If fonts not found, use default Helvetica
114
+ print(f"⚠️ Using default fonts (Helvetica): {e}")
115
+ self.font_name = 'Helvetica'
116
+ self.font_name_bold = 'Helvetica-Bold'
117
 
118
  def _setup_custom_styles(self):
119
  """Setup custom paragraph styles"""
120
+ # Use dynamically loaded fonts
121
+ font_name = self.font_name
122
+ font_name_bold = self.font_name_bold
123
 
124
  self.styles.add(ParagraphStyle(
125
  name='CustomTitle',