Giới thiệu dự án
Sự thay đổi trong lối sống sau đại dịch COVID-19 đã thúc đẩy làn sóng tự nấu ăn tại nhà gia tăng hơn 45% trong giới trẻ và các hộ gia đình đô thị. Tuy nhiên, người dùng hiện đại thường xuyên gặp phải tình trạng quá tải thông tin, thiếu ý tưởng thực đơn hằng ngày ("hôm nay ăn gì?") và gặp khó khăn trong việc cân bằng dinh dưỡng. Các nền tảng chia sẻ công thức nấu ăn truyền thống hoặc các nhóm mạng xã hội đại trà (Facebook, YouTube) bộc lộ nhiều hạn chế: nội dung phân tán, thiếu tính tương tác chuyên sâu hai chiều và không có cơ chế hỗ trợ tức thì khi người dùng gặp thắc mắc trong quá trình vào bếp.
Đồ án tốt nghiệp ngành Công nghệ Phần mềm tại Trường Đại học Công nghệ Thông tin – ĐHQG TP.HCM (UIT) thực hiện bởi nhóm sinh viên Lê Nhị Khang và Võ Đoàn Minh Hiếu, dưới sự hướng dẫn của TS. Huỳnh Ngọc Tín, đã nghiên cứu và phát triển thành công giải pháp: "Xây dựng ứng dụng chia sẻ công thức nấu ăn tích hợp chatbot" (Building a food recipe sharing application with a built-in chatbot).
+------------------------------------------+
| ỨNG DỤNG DI ĐỘNG (FLUTTER) |
| Social Feed | Recipes | Rasa Chatbot |
+--------------------+---------------------+
|
HTTPS REST | Webhook Socket
v
+--------------------+ +------------+-------------+ +--------------------+
| CHATBOT SERVER |<---->| BACKEND API SERVER |<---->| DATABASE CLUSTER |
| Rasa NLU Core | | Node.js / Express.js | | MongoDB Atlas |
+--------------------+ +--------------------------+ +--------------------+
Mục tiêu của dự án
- Xây dựng nền tảng mạng xã hội chuyên biệt cho ẩm thực: Cung cấp đầy đủ các tính năng chia sẻ bài viết, đăng tải công thức nấu ăn chi tiết từng bước, đánh giá (ratings), tương tác (like, comment, cook reaction) và theo dõi đầu bếp (follow system).
- Tích hợp trợ lý ảo thông minh (Conversational AI Chatbot): Ứng dụng framework xử lý ngôn ngữ tự nhiên (NLU) Rasa để nhận diện ý định (Intent Classification) và trích xuất thực thể (Entity Extraction), hỗ trợ giải đáp thắc mắc về công thức, giá trị calo/dinh dưỡng và gợi ý món ăn theo nguyên liệu có sẵn.
- Chuẩn hóa dữ liệu ẩm thực: Tích hợp và cấu trúc hóa tập dữ liệu phong phú từ Edamam API và Cooky, phân loại theo ẩm thực vùng miền (Cuisines), loại món (DishTypes), mục đích dinh dưỡng (SpecialGoals) và phương pháp chế biến (CookMethods).
- Tối ưu hóa trải nghiệm người dùng đa nền tảng: Đảm bảo hiệu năng mượt mà trên thiết bị di động với kiến trúc quản lý trạng thái BLoC, thời gian phản hồi giao diện đạt chuẩn 60 FPS.
Phạm vi và giới hạn hệ thống
- Phạm vi nghiên cứu: Tập trung vào người dùng cá nhân yêu thích nấu ăn tại Việt Nam, xử lý ngôn ngữ tự nhiên tiếng Việt cho các tác vụ hỏi đáp công thức, nguyên liệu và thông tin sản phẩm nhà bếp liên quan.
- Giới hạn kỹ thuật: Chưa tích hợp thanh toán trực tiếp cho sản phẩm nhà bếp (chỉ hỗ trợ danh mục địa điểm mua sắm
salesLocation), chatbot tập trung xử lý hội thoại dạng slot-filling định hướng tác vụ cụ thể thay vì sinh văn bản mở (Open-domain LLM).
Phân tích và thiết kế giải pháp
Phân tích hiện trạng
Khảo sát thực tế các nền tảng chia sẻ nấu ăn hiện có tại thị trường Việt Nam cho thấy rõ các khoảng trống công nghệ:
| Tiêu chí phân tích |
Cookpad |
Cooky |
Ứng dụng đề xuất trong đồ án |
| Tính năng Mạng xã hội |
Cơ bản (bình luận, thả tim) |
Hạn chế (thiên về thương mại thực phẩm) |
Toàn diện (Feed, Follow, Post Reactions, Nested Comments) |
| Trợ lý ảo AI / Chatbot |
❌ Không hỗ trợ |
❌ Không hỗ trợ |
✅ Tích hợp Rasa NLU Framework |
| Gợi ý món ăn thông minh |
Tìm kiếm từ khóa tĩnh |
Bộ lọc danh mục cố định |
Hội thoại động theo nguyên liệu & mục tiêu sức khỏe |
| Cấu trúc dữ liệu dinh dưỡng |
Tự do, không chuẩn hóa |
Chuẩn hóa theo pack nguyên liệu |
Cấu trúc NoSQL đa chiều (Calo, Servings, Steps, Units) |
| Trải nghiệm ứng dụng di động |
Native App |
Native / Hybrid |
Flutter Multi-platform + BLoC State Pattern |
Áp dụng phương pháp phân loại yêu cầu MoSCoW:
- Must have: Xác thực JWT, CRUD công thức/bài viết, tương tác xã hội (like/comment/follow), Chatbot tìm món theo nguyên liệu/chế độ ăn.
- Should have: Phân loại đa tầng (Cuisine, MenuType, SpecialGoal), upload đa phương tiện (hình ảnh, video hướng dẫn).
- Could have: Quản lý gợi ý sản phẩm dụng cụ nhà bếp (
Products Collection), tính toán tự động định lượng nguyên liệu theo số khẩu phần (servings).
- Won't have (lần này): Thanh toán trực tuyến in-app (In-app purchase) và tính năng livestreaming nấu ăn.
Thiết kế hệ thống
Hệ thống được thiết kế theo mô hình 3 lớp (3-Tier Architecture) phân tách rõ ràng trách nhiệm giữa Tầng Trình diễn (Presentation Layer), Tầng Nghiệp vụ (Business Logic Layer) và Tầng Dữ liệu (Data Layer).
+-------------------------------------------------------------------------+
| PRESENTATION LAYER: FLUTTER MOBILE APP |
| [UI Screens] <---> [BLoC / State Events] <---> [Repository API] |
+------------------------------------+------------------------------------+
| JSON / HTTPS REST
+------------------------------------v------------------------------------+
| BUSINESS LOGIC LAYER: NODE.JS & EXPRESS |
| [Auth Middleware] -> [Controllers] -> [Services Layer] -> [Mongoose] |
| ^ |
| | Webhook API |
| [Rasa Core & NLU Engine] |
+------------------------------------+------------------------------------+
| ODM Queries
+------------------------------------v------------------------------------+
| DATA LAYER: MONGODB NO-SQL |
| Collections: Users, Recipes, Posts, Comments, Products, Metadata |
+-------------------------------------------------------------------------+
Technology Stack
- Mobile Client: Flutter SDK 3.0+, Dart 2.17+, BLoC Pattern (
flutter_bloc), Dio HTTP client, SharedPreferences.
- Backend Server: Node.js v16.14 LTS, Express.js v4.18, JSON Web Token (JWT), Bcrypt.js, Mongoose ODM v6.3.
- Chatbot Engine: Rasa Open Source 3.1, Rasa SDK 3.1 (Python 3.8), Spacy / Underthesea Tokenizer tiếng Việt.
- Cơ sở dữ liệu: MongoDB Atlas 5.0 (NoSQL Document Database).
Thiết kế cơ sở dữ liệu MongoDB (Document Schemas)
Hệ thống quản lý dữ liệu linh hoạt thông qua các Mongoose Models chính:
// Schema Công thức nấu ăn (Recipe Schema)
const RecipeSchema = new mongoose.Schema({
creatorId: { type: mongoose.Schema.Types.ObjectId, ref: 'Users', required: true, index: true },
name: { type: String, required: true, trim: true, text: true },
description: { type: String, default: '' },
photoUrls: [{ type: String }],
videoUrl: { type: String, default: null },
servings: { type: Number, required: true, min: 1 },
totalTime: { type: Number, required: true }, // Tính bằng phút
level: { type: String, enum: ['Dễ', 'Trung bình', 'Khó'], default: 'Dễ' },
ingredients: [{
name: { type: String, required: true },
typeId: { type: mongoose.Schema.Types.ObjectId, ref: 'IngredientTypes' },
unitId: { type: mongoose.Schema.Types.ObjectId, ref: 'Units' },
quantity: { type: Number, required: true }
}],
steps: [{
stepOrder: { type: Number },
content: { type: String, required: true },
photoUrls: [{ type: String }]
}],
cuisineId: { type: mongoose.Schema.Types.ObjectId, ref: 'Cuisines' },
dishTypeId: { type: mongoose.Schema.Types.ObjectId, ref: 'DishTypes' },
specialGoals: [{ type: mongoose.Schema.Types.ObjectId, ref: 'SpecialGoals' }],
totalView: { type: Number, default: 0 }
}, { timestamps: true });
Thiết kế API Endpoints tiêu biểu
POST /api/v1/auth/register & POST /api/v1/auth/login: Xác thực người dùng, cấp phát token JWT.
GET /api/v1/recipes/feed?page=1&limit=10: Lấy danh sách công thức phân trang, tối ưu qua cursor-based query.
POST /api/v1/recipes: Tạo mới công thức kèm upload danh sách hình ảnh các bước chế biến.
POST /api/v1/posts/:id/reactions: Gửi tương tác phản ứng (thích, yêu thích, v.v.).
POST /api/v1/chatbot/query: Cổng tiếp nhận câu hỏi của người dùng và chuyển tiếp tới Rasa Webhook.
Implementation và kết quả
Development Process
Quá trình phát triển áp dụng mô hình Agile Scrum với chu kỳ Sprint 2 tuần, kéo dài trong 16 tuần:
- Sprint 1 - 2: Khảo sát nghiệp vụ, thiết kế Data Schema MongoDB, cấu hình kiến trúc Express.js Server.
- Sprint 3 - 5: Xây dựng UI Mobile App với Flutter (Auth, Home Feed, Recipe Creator) và áp dụng BLoC.
- Sprint 6 - 7: Xây dựng tập dữ liệu huấn luyện NLU, cấu hình Pipeline và huấn luyện Rasa Chatbot.
- Sprint 8: Tích hợp Webhook giữa Rasa - Node.js Server - Flutter Client, kiểm thử hệ thống và tối ưu hóa hiệu năng.
Xử lý trạng thái phía Mobile với BLoC Pattern
// RecipeBloc: Quản lý trạng thái nạp dữ liệu công thức nấu ăn
class RecipeBloc extends Bloc<RecipeEvent, RecipeState> {
final RecipeRepository repository;
RecipeBloc({required this.repository}) : super(RecipeInitialState()) {
on<FetchRecipesEvent>((event, emit) async {
emit(RecipeLoadingState());
try {
final recipes = await repository.getRecipes(
page: event.page,
cuisineId: event.cuisineId
);
emit(RecipeLoadedState(recipes: recipes, hasReachedMax: recipes.length < 10));
} catch (error) {
emit(RecipeErrorState(message: error.toString()));
}
});
}
}
Xây dựng Pipeline NLU và Custom Action cho Chatbot
Cấu hình Pipeline trong tệp config.yml của Rasa kết hợp giữa featurizer và bộ phân loại DIET (Dual Intent and Entity Transformer):
language: "vi"
pipeline:
- name: WhitespaceTokenizer
- name: RegexFeaturizer
- name: LexicalSyntacticFeaturizer
- name: CountVectorsFeaturizer
analyzer: "char_wb"
min_ngram: 1
max_ngram: 4
- name: DIETClassifier
epochs: 100
constrain_similarities: true
- name: EntitySynonymMapper
Hành động tùy chỉnh (Custom Action) bằng Python để truy xuất công thức theo thực thể nguyên liệu người dùng cung cấp:
# actions.py: Rasa Custom Action tìm kiếm món ăn theo nguyên liệu
from rasa_sdk import Action, Tracker
from rasa_sdk.executor import CollectingDispatcher
import requests
class ActionSearchRecipeByIngredient(Action):
def name(self) -> str:
return "action_search_recipe_by_ingredient"
def run(self, dispatcher: CollectingDispatcher, tracker: Tracker, domain: dict) -> list:
ingredient = tracker.get_slot("ingredient")
if not ingredient:
dispatcher.utter_message(text="Bạn muốn tìm món ăn chế biến từ nguyên liệu nào ạ?")
return []
# Gọi API nội bộ của hệ sinh thái Node.js Backend
response = requests.get(f"http://localhost:5000/api/v1/recipes/search?ingredient={ingredient}")
if response.status_code == 200 and response.json().get("data"):
recipes = response.json()["data"][:3]
reply = f"Dưới đây là một số món ngon từ {ingredient}:\n"
for r in recipes:
reply += f"- {r['name']} ({r['totalTime']} phút, mức độ: {r['level']})\n"
dispatcher.utter_message(text=reply)
else:
dispatcher.utter_message(text=f"Tiếc quá, hiện hệ thống chưa có công thức nào nấu từ {ingredient}.")
return []
Testing và Validation
Hệ thống trải qua các giai đoạn kiểm thử đơn vị (Unit Test), kiểm thử tích hợp (Integration Test) và kiểm thử tải hệ thống:
+--------------------------------------------------------------------------+
| KẾT QUẢ TESTING VÀ PERFORMANCE BENCHMARK |
+--------------------------------------------------------------------------+
| Metric | Giá trị đạt được |
+------------------------------------------+-------------------------------+
| Unit Test Coverage (Backend API) | 84.6% |
| Unit Test Coverage (BLoC State Mobile) | 78.2% |
| API Latency (REST Endpoints) | 68ms (Trung bình tại 500 CCU) |
| Chatbot Intent Classification F1-Score | 92.4% (Tập test 350 mẫu) |
| Mobile UI Frame Render Rate | 59.8 FPS (Tiêu chuẩn 60 FPS) |
| Tỷ lệ lỗi phản hồi (Error Rate) | 0.04% tại 1,000 requests/phút |
+------------------------------------------+-------------------------------+
- Kiểm thử khả năng chịu tải: Sử dụng công cụ Apache JMeter giả lập 500 người dùng đồng thời (Concurrency Users - CCU) gửi request lấy dữ liệu bài viết. Cơ sở dữ liệu MongoDB được lập chỉ mục (
compound indexes trên {cuisineId: 1, createdAt: -1}) giúp thời gian phản hồi duy trì ổn định dưới 100ms.
- Kiểm thử Chatbot: Tập dữ liệu NLU được kiểm thử chéo 5-fold cross validation, đạt độ chính xác phát hiện ý định (Intent Accuracy) trên 91.5% đối với các nhóm câu hỏi về nguyên liệu, thời gian nấu và đề xuất thực đơn giảm cân.
Đổi mới và đóng góp
- Tích hợp hội thoại thông minh trực tiếp vào mạng xã hội ẩm thực: Thay vì chỉ dùng thanh tìm kiếm từ khóa cứng nhắc, giải pháp chatbot NLU giúp giảm thời gian tìm kiếm ý tưởng món ăn từ 4.5 phút xuống dưới 15 giây qua cơ chế hỏi đáp tự nhiên.
- Kiến trúc dữ liệu dạng NoSQL tối ưu hóa cho công thức nấu ăn: Thiết kế cấu trúc các bước thực hiện (
steps) lồng ghép mảng hình ảnh và nguyên liệu chi tiết theo từng đơn vị chuẩn (Units Collection), giúp giải quyết triệt để việc sai lệch tỷ lệ gia vị khi nấu.
- Mô hình kiến trúc module hóa linh hoạt: Sự tách biệt giữa Node.js API và Rasa AI Action Server giúp hệ thống có khả năng mở rộng (Scale-out) độc lập khi lưu lượng truy cập chatbot tăng đột biến mà không gây nghẽn dịch vụ mạng xã hội chính.
Ứng dụng thực tế và triển khai
Kịch bản sử dụng thực tế (Use Cases)
- Kịch bản 1: Giải quyết vấn đề "Tủ lạnh còn gì nấu nấy": Người dùng nhập tin nhắn vào chatbot: "Nhà mình còn trứng và cà chua thì làm được món gì nhanh?" Chatbot tự động bóc tách thực thể
trứng, cà chua, gọi Action tìm kiếm trong cơ sở dữ liệu và trả về danh sách công thức tương ứng kèm thời gian chế biến dưới 15 phút.
- Kịch bản 2: Chia sẻ trải nghiệm nấu ăn theo cộng đồng: Người dùng đăng tải công thức "Bò sốt vang chuẩn vị", đính kèm ảnh từng bước. Người theo dõi có thể nhấn nút "Đã nấu món này" (
RecipeCooks), bình luận ảnh thành phẩm và chấm điểm đánh giá (Ratings).
Hướng dẫn triển khai hệ thống (Deployment Setup)
1. Yêu cầu môi trường phần cứng và phần mềm
- Máy chủ Backend: Ubuntu 20.04 LTS, RAM 4GB, 2 vCPU.
- Môi trường: Node.js v16+, Python 3.8, Docker & Docker-Compose.
2. Khởi chạy hệ thống bằng Docker Compose
version: '3.8'
services:
backend-server:
build: ./server
ports:
- "5000:5000"
environment:
- PORT=5000
- MONGO_URI=mongodb+srv://admin:secret@cluster0.mongodb.net/FoodApp?retryWrites=true
- JWT_SECRET=super_secret_jwt_key_2022
- RASA_ENDPOINT=http://rasa-server:5005/webhooks/rest/webhook
depends_on:
- rasa-server
rasa-server:
build: ./chatbot
ports:
- "5005:5005"
command: rasa run --enable-api --cors "*"
# Khởi chạy toàn bộ hệ thống
docker-compose up -d --build
Hạn chế và hướng phát triển
- Hạn chế kỹ thuật hiện tại:
- Tập dữ liệu mẫu tiếng Việt của chatbot chủ yếu được xây dựng thủ công (khoảng 1,200 câu mẫu), dẫn đến khả năng hiểu sai ngữ nghĩa đối với các câu hỏi phức tạp hoặc từ ngữ địa phương đặc thù.
- Ứng dụng chưa hỗ trợ chức năng nhận diện hình ảnh nguyên liệu qua camera (Computer Vision).
- Hướng phát triển tiếp theo:
- Tích hợp các mô hình ngôn ngữ lớn (LLM) thông qua cơ chế RAG (Retrieval-Augmented Generation) để nâng cao khả năng đối thoại tự nhiên và tư vấn dinh dưỡng chuyên sâu.
- Phát triển tính năng Computer Vision: Tự động nhận diện nguyên liệu thực phẩm trong tủ lạnh qua camera điện thoại và gợi ý ngay công thức nấu ăn phù hợp.
- Tích hợp sàn thương mại điện tử liên kết (Affiliate E-commerce) cho phép người dùng đặt mua nguyên liệu trực tiếp từ các chuỗi siêu thị.
Đối tượng hưởng lợi
- Sinh viên & Người học CNTT: Tiếp cận một đồ án thực tế hoàn chỉnh, hiểu sâu cách tích hợp Flutter BLoC với Backend RESTful API và mô hình AI Chatbot Rasa.
- Lập trình viên Mobile / AI: Cung cấp kiến trúc tham chiếu mẫu (Reference Architecture) trong việc kết hợp ứng dụng đa nền tảng với hệ thống xử lý ngôn ngữ tự nhiên tiếng Việt.
- Người dùng nội trợ & Giới trẻ: Sở hữu công cụ hữu ích hỗ trợ lên thực đơn nhanh chóng, giải tỏa áp lực nấu nướng và kết nối cùng cộng đồng yêu ẩm thực.
- Chuyên gia ẩm thực & Food Creators: Có nền tảng chuyên biệt để chia sẻ công thức chuẩn hóa, xây dựng thương hiệu cá nhân và tiếp cận đúng đối tượng mục tiêu.
Câu hỏi thường gặp
1. Ứng dụng Flutter cần cấu hình tối thiểu như thế nào để vận hành mượt mà?
Khách hàng có thể chạy ứng dụng trên thiết bị Android từ phiên bản 6.0 (Marshmallow - API level 23) hoặc iOS từ phiên bản 12.0 trở lên. Nhờ việc tối ưu cây Widget và sử dụng BLoC quản lý trạng thái, ứng dụng chỉ tiêu tốn khoảng 85MB - 120MB RAM khi chạy các tác vụ duyệt feed video và hình ảnh.
2. Làm thế nào để mở rộng (Scale) hệ thống Rasa Chatbot khi có nhiều người dùng đồng thời?
Rasa Core và Action Server được đóng gói thành các microservices độc lập. Khi lượng truy cập tăng cao, ta có thể triển khai hệ thống trên Kubernetes Cluster, sử dụng Horizontal Pod Autoscaler (HPA) để tự động tăng số lượng Pods của Rasa và sử dụng Redis làm Message Broker trung gian.
3. Hệ thống đảm bảo an toàn và bảo mật dữ liệu người dùng như thế nào?
Toàn bộ mật khẩu người dùng được băm (hash) bằng thuật toán bcrypt với muối (salt rounds) cấp 10. Mọi request nhạy cảm từ Mobile Client gửi lên đều bắt buộc đính kèm JWT qua Authorization Header, kết hợp cơ chế kiểm soát truy cập phân quyền người dùng (Role-Based Access Control) tại các Express Middleware.
4. Dữ liệu công thức nấu ăn được chuẩn hóa như thế nào giữa các hệ đo lường?
Hệ thống sử dụng bảng Units Collection để định nghĩa các đơn vị chuẩn (Gram, Kilogram, Muỗng cà phê, Chén, v.v.). Khi người dùng thay đổi số lượng khẩu phần (servings), hệ thống tự động nhân tỷ lệ tương ứng theo công thức:
$$\text{Khối lượng thực tế} = \frac{\text{Định lượng gốc}}{\text{Khẩu phần gốc}} \times \text{Khẩu phần mong muốn}$$
5. Chi phí vận hành máy chủ ước tính cho quy mô 10,000 người dùng hoạt động hàng ngày (DAU) là bao nhiêu?
Với kiến trúc Docker container tối ưu, hệ thống chỉ cần 1 máy chủ VPS (4 vCPU, 8GB RAM) trị giá khoảng $40 - $60/tháng kết hợp cùng gói MongoDB Atlas Shared/Dedicated khoảng $30/tháng và Cloudinary/AWS S3 để lưu trữ media ($20/tháng), tổng chi phí hạ tầng ước tính dưới $120/tháng.
Kết luận
Đồ án tốt nghiệp "Xây dựng ứng dụng chia sẻ công thức nấu ăn tích hợp chatbot" của sinh viên Lê Nhị Khang và Võ Đoàn Minh Hiếu (Trường Đại học Công nghệ Thông tin - ĐHQG TP.HCM) đã giải quyết trọn vẹn bài toán kết nối cộng đồng ẩm thực và hỗ trợ nấu nướng thông minh. Bằng sự kết hợp chặt chẽ giữa framework đa nền tảng Flutter, nền tảng backend Node.js/Express, cơ sở dữ liệu MongoDB và công nghệ NLU tiên tiến từ Rasa, dự án không chỉ đáp ứng xuất sắc các tiêu chuẩn kỹ thuật của một khóa luận kỹ sư phần mềm mà còn sở hữu tiềm năng ứng dụng thực tiễn cao trong đời sống số hóa hiện đại.