Commit 3e89d304 authored by Vũ Hoàng Anh's avatar Vũ Hoàng Anh

feat: add Event Daily Engine and Reaction Simulator Deep cookbooks (16 chapters total)

parent 3487d1a5
Blazer
Bộ mặc nhà
Bộ quần áo
Bộ thể thao
Cardigan
Chân váy
Chăn cá nhân
Găng tay chống nắng
Khăn
Khăn lau đầu
Khăn mặt
Khăn tắm
Khẩu trang
Mũ
Mũ thể thao
Pyjama
Quần Body
Quần Khaki
Quần culottes
Quần dài
Quần giữ nhiệt
Quần jean
Quần leggings
Quần leggings mặc nhà
Quần lót
Quần lót tam giác
Quần lót đùi
Quần mặc nhà
Quần nỉ
Quần soóc
Quần váy
Túi xách
Tất
Váy liền
Áo Body
Áo Polo
Áo Sơ mi
Áo ba lỗ
Áo giữ nhiệt
Áo hai dây
Áo khoác
Áo khoác chần bông
Áo khoác chống nắng
Áo khoác dáng ngắn
Áo khoác dạ
Áo khoác gilet chần bông
Áo khoác gió
Áo khoác lông vũ
Áo khoác nỉ có mũ
Áo khoác nỉ không mũ
Áo khoác sợi
Áo kiểu
Áo len
Áo len gilet
Áo lót
Áo mặc nhà
Áo nỉ
Áo nỉ có mũ
Áo phông
\ No newline at end of file
[('Blazer', 'hang_ngay', 'top'), ('Blazer', 'hang_ngay', 'top'), ('Blazer', 'hang_ngay', 'top'), ('Blazer', 'hang_ngay', 'bottom'), ('Blazer', 'hang_ngay', 'bottom'), ('Blazer', 'hang_ngay', 'bottom'), ('Blazer', 'hang_ngay', 'bottom'), ('Blazer', 'hang_ngay', 'bottom'), ('Blazer', 'hang_ngay', 'bottom'), ('Blazer', 'hang_ngay', 'bottom'), ('Blazer', 'hang_ngay', 'bottom'), ('Blazer', 'hang_ngay', 'bottom'), ('Blazer', 'hang_ngay', 'accessory'), ('Blazer', 'hang_ngay', 'accessory'), ('Blazer', 'hang_ngay', 'accessory'), ('Bộ mặc nhà', 'mac_nha', 'outerwear'), ('Bộ mặc nhà', 'mac_nha', 'outerwear'), ('Bộ mặc nhà', 'mac_nha', 'home/other'), ('Bộ mặc nhà', 'mac_nha', 'home/other'), ('Bộ mặc nhà', 'mac_nha', 'home/other'), ('Bộ mặc nhà', 'mac_nha', 'home/other'), ('Bộ mặc nhà', 'mac_nha', 'home/other'), ('Bộ mặc nhà', 'mac_nha', 'home/other'), ('Bộ mặc nhà', 'mac_nha', 'home/other'), ('Bộ mặc nhà', 'mac_nha', 'home/other'), ('Bộ mặc nhà', 'mac_nha', 'home/other'), ('Bộ mặc nhà', 'mac_nha', 'home/other'), ('Bộ mặc nhà', 'mac_nha', 'home/other'), ('Bộ mặc nhà', 'mac_nha', 'home/other'), ('Bộ quần áo', 'mac_nha', 'outerwear'), ('Bộ quần áo', 'mac_nha', 'outerwear'), ('Bộ quần áo', 'mac_nha', 'outerwear'), ('Bộ quần áo', 'mac_nha', 'outerwear'), ('Bộ quần áo', 'mac_nha', 'outerwear'), ('Bộ quần áo', 'mac_nha', 'accessory'), ('Bộ quần áo', 'mac_nha', 'accessory'), ('Bộ quần áo', 'mac_nha', 'accessory'), ('Bộ quần áo', 'mac_nha', 'accessory'), ('Bộ quần áo', 'mac_nha', 'accessory'), ('Bộ quần áo', 'mac_nha', 'accessory'), ('Bộ quần áo', 'mac_nha', 'accessory'), ('Bộ quần áo', 'mac_nha', 'accessory'), ('Bộ quần áo', 'mac_nha', 'accessory'), ('Bộ quần áo', 'mac_nha', 'accessory'), ('Bộ thể thao', 'the_thao', 'accessory'), ('Bộ thể thao', 'the_thao', 'accessory'), ('Bộ thể thao', 'the_thao', 'accessory'), ('Bộ thể thao', 'the_thao', 'accessory'), ('Bộ thể thao', 'the_thao', 'accessory'), ('Bộ thể thao', 'the_thao', 'accessory'), ('Bộ thể thao', 'the_thao', 'accessory'), ('Bộ thể thao', 'the_thao', 'accessory'), ('Bộ thể thao', 'the_thao', 'accessory'), ('Cardigan', 'hang_ngay', 'top'), ('Cardigan', 'hang_ngay', 'top'), ('Cardigan', 'hang_ngay', 'top'), ('Cardigan', 'hang_ngay', 'top'), ('Cardigan', 'hang_ngay', 'bottom'), ('Cardigan', 'hang_ngay', 'bottom'), ('Cardigan', 'hang_ngay', 'bottom'), ('Cardigan', 'hang_ngay', 'bottom'), ('Chân váy', 'hang_ngay', 'top'), ('Chân váy', 'hang_ngay', 'top'), ('Chân váy', 'hang_ngay', 'top'), ('Chân váy', 'hang_ngay', 'top'), ('Chân váy', 'hang_ngay', 'top'), ('Chân váy', 'hang_ngay', 'top'), ('Chân váy', 'hang_ngay', 'top'), ('Chân váy', 'hang_ngay', 'top'), ('Chân váy', 'di_lam', 'bottom'), ('Chân váy', 'di_lam', 'bottom'), ('Chân váy', 'hang_ngay', 'accessory'), ('Chân váy', 'hang_ngay', 'accessory'), ('Chân váy', 'hang_ngay', 'underwear'), ('Chân váy', 'hang_ngay', 'underwear'), ('Chăn cá nhân', 'mac_nha', 'home/other'), ('Chăn cá nhân', 'mac_nha', 'home/other'), ('Găng tay chống nắng', 'di_lam', 'accessory'), ('Găng tay chống nắng', 'hang_ngay', 'top'), ('Găng tay chống nắng', 'hang_ngay', 'accessory'), ('Khăn', 'di_lam', 'accessory'), ('Khăn', 'hang_ngay', 'top'), ('Khăn', 'hang_ngay', 'top'), ('Khăn', 'hang_ngay', 'top'), ('Khăn lau đầu', 'mac_nha', 'home/other'), ('Khăn lau đầu', 'mac_nha', 'home/other'), ('Khăn mặt', 'mac_nha', 'home/other'), ('Khăn mặt', 'mac_nha', 'home/other'), ('Khăn tắm', 'mac_nha', 'home/other'), ('Khăn tắm', 'mac_nha', 'home/other'), ('Khẩu trang', 'di_lam', 'accessory'), ('Khẩu trang', 'hang_ngay', 'top'), ('Khẩu trang', 'hang_ngay', 'accessory'), ('Mũ', 'hang_ngay', 'top'), ('Mũ', 'the_thao', 'accessory'), ('Mũ', 'mac_nha', 'top'), ('Mũ', 'di_lam', 'accessory'), ('Mũ', 'hang_ngay', 'top'), ('Mũ thể thao', 'the_thao', 'accessory'), ('Mũ thể thao', 'the_thao', 'accessory'), ('Mũ thể thao', 'the_thao', 'accessory'), ('Mũ thể thao', 'the_thao', 'accessory'), ('Mũ thể thao', 'the_thao', 'accessory'), ('Pyjama', 'mac_nha', 'bottom'), ('Pyjama', 'mac_nha', 'bottom'), ('Pyjama', 'mac_nha', 'bottom'), ('Pyjama', 'mac_nha', 'home/other'), ('Pyjama', 'mac_nha', 'home/other'), ('Pyjama', 'mac_nha', 'home/other'), ('Pyjama', 'mac_nha', 'home/other'), ('Pyjama', 'mac_nha', 'home/other'), ('Pyjama', 'mac_nha', 'home/other'), ('Quần Body', 'hang_ngay', 'top'), ('Quần Body', 'di_lam', 'bottom'), ('Quần Body', 'hang_ngay', 'underwear'), ('Quần Body', 'hang_ngay', 'underwear'), ('Quần Khaki', 'hang_ngay', 'top'), ('Quần Khaki', 'hang_ngay', 'top'), ('Quần Khaki', 'hang_ngay', 'top'), ('Quần Khaki', 'hang_ngay', 'top'), ('Quần Khaki', 'hang_ngay', 'top'), ('Quần Khaki', 'hang_ngay', 'top'), ('Quần Khaki', 'hang_ngay', 'top'), ('Quần Khaki', 'hang_ngay', 'top'), ('Quần Khaki', 'hang_ngay', 'top'), ('Quần Khaki', 'hang_ngay', 'top'), ('Quần Khaki', 'hang_ngay', 'top'), ('Quần Khaki', 'hang_ngay', 'top'), ('Quần Khaki', 'di_lam', 'bottom'), ('Quần Khaki', 'di_lam', 'bottom'), ('Quần Khaki', 'di_lam', 'bottom'), ('Quần Khaki', 'hang_ngay', 'accessory'), ('Quần Khaki', 'hang_ngay', 'accessory'), ('Quần Khaki', 'hang_ngay', 'accessory'), ('Quần Khaki', 'hang_ngay', 'accessory'), ('Quần Khaki', 'hang_ngay', 'underwear'), ('Quần Khaki', 'hang_ngay', 'underwear'), ('Quần Khaki', 'hang_ngay', 'underwear'), ('Quần Khaki', 'hang_ngay', 'underwear'), ('Quần culottes', 'hang_ngay', 'top'), ('Quần culottes', 'hang_ngay', 'top'), ('Quần culottes', 'hang_ngay', 'accessory'), ('Quần dài', 'hang_ngay', 'top'), ('Quần dài', 'hang_ngay', 'top'), ('Quần dài', 'hang_ngay', 'top'), ('Quần dài', 'hang_ngay', 'top'), ('Quần dài', 'hang_ngay', 'top'), ('Quần dài', 'hang_ngay', 'top'), ('Quần dài', 'hang_ngay', 'top'), ('Quần dài', 'hang_ngay', 'top'), ('Quần dài', 'hang_ngay', 'top'), ('Quần dài', 'hang_ngay', 'top'), ('Quần dài', 'hang_ngay', 'top'), ('Quần dài', 'hang_ngay', 'top'), ('Quần dài', 'hang_ngay', 'top'), ('Quần dài', 'hang_ngay', 'top'), ('Quần dài', 'hang_ngay', 'top'), ('Quần dài', 'di_lam', 'bottom'), ('Quần dài', 'di_lam', 'bottom'), ('Quần dài', 'di_lam', 'bottom'), ('Quần dài', 'di_lam', 'bottom'), ('Quần dài', 'di_lam', 'bottom'), ('Quần dài', 'di_lam', 'bottom'), ('Quần dài', 'di_lam', 'bottom'), ('Quần dài', 'the_thao', 'bottom'), ('Quần dài', 'the_thao', 'bottom'), ('Quần dài', 'the_thao', 'bottom'), ('Quần dài', 'the_thao', 'bottom'), ('Quần dài', 'the_thao', 'bottom'), ('Quần dài', 'hang_ngay', 'underwear'), ('Quần dài', 'hang_ngay', 'underwear'), ('Quần dài', 'hang_ngay', 'underwear'), ('Quần dài', 'hang_ngay', 'underwear'), ('Quần dài', 'hang_ngay', 'underwear'), ('Quần dài', 'hang_ngay', 'underwear'), ('Quần giữ nhiệt', 'hang_ngay', 'top'), ('Quần giữ nhiệt', 'di_lam', 'bottom'), ('Quần giữ nhiệt', 'di_lam', 'bottom'), ('Quần jean', 'hang_ngay', 'top'), ('Quần jean', 'hang_ngay', 'top'), ('Quần jean', 'hang_ngay', 'top'), ('Quần jean', 'hang_ngay', 'top'), ('Quần jean', 'hang_ngay', 'top'), ('Quần jean', 'hang_ngay', 'top'), ('Quần jean', 'hang_ngay', 'top'), ('Quần jean', 'hang_ngay', 'top'), ('Quần jean', 'hang_ngay', 'top'), ('Quần jean', 'hang_ngay', 'top'), ('Quần jean', 'hang_ngay', 'top'), ('Quần jean', 'hang_ngay', 'top'), ('Quần jean', 'hang_ngay', 'top'), ('Quần jean', 'hang_ngay', 'top'), ('Quần jean', 'hang_ngay', 'top'), ('Quần jean', 'hang_ngay', 'top'), ('Quần jean', 'hang_ngay', 'top'), ('Quần jean', 'hang_ngay', 'top'), ('Quần jean', 'hang_ngay', 'top'), ('Quần jean', 'hang_ngay', 'top'), ('Quần jean', 'di_lam', 'bottom'), ('Quần jean', 'di_lam', 'bottom'), ('Quần jean', 'di_lam', 'bottom'), ('Quần jean', 'di_lam', 'bottom'), ('Quần jean', 'di_lam', 'bottom'), ('Quần jean', 'di_lam', 'bottom'), ('Quần jean', 'the_thao', 'bottom'), ('Quần jean', 'the_thao', 'bottom'), ('Quần jean', 'the_thao', 'bottom'), ('Quần jean', 'the_thao', 'bottom'), ('Quần jean', 'hang_ngay', 'underwear'), ('Quần jean', 'hang_ngay', 'underwear'), ('Quần jean', 'hang_ngay', 'underwear'), ('Quần jean', 'hang_ngay', 'underwear'), ('Quần jean', 'hang_ngay', 'underwear'), ('Quần jean', 'hang_ngay', 'underwear'), ('Quần leggings', 'hang_ngay', 'top'), ('Quần leggings', 'hang_ngay', 'top'), ('Quần leggings', 'di_lam', 'bottom'), ('Quần leggings', 'hang_ngay', 'underwear'), ('Quần leggings mặc nhà', 'mac_nha', 'top'), ('Quần leggings mặc nhà', 'mac_nha', 'top'), ('Quần lót', 'hang_ngay', 'bottom'), ('Quần lót', 'hang_ngay', 'bottom'), ('Quần lót', 'hang_ngay', 'bottom'), ('Quần lót', 'hang_ngay', 'bottom'), ('Quần lót', 'hang_ngay', 'bottom'), ('Quần lót', 'hang_ngay', 'bottom'), ('Quần lót', 'hang_ngay', 'bottom'), ('Quần lót', 'hang_ngay', 'bottom'), ('Quần lót', 'hang_ngay', 'bottom'), ('Quần lót tam giác', 'hang_ngay', 'bottom'), ('Quần lót tam giác', 'hang_ngay', 'bottom'), ('Quần lót tam giác', 'hang_ngay', 'bottom'), ('Quần lót tam giác', 'hang_ngay', 'bottom'), ('Quần lót tam giác', 'hang_ngay', 'bottom'), ('Quần lót tam giác', 'hang_ngay', 'bottom'), ('Quần lót tam giác', 'hang_ngay', 'bottom'), ('Quần lót tam giác', 'hang_ngay', 'bottom'), ('Quần lót tam giác', 'hang_ngay', 'bottom'), ('Quần lót đùi', 'hang_ngay', 'bottom'), ('Quần lót đùi', 'hang_ngay', 'bottom'), ('Quần lót đùi', 'mac_nha', 'bottom'), ('Quần lót đùi', 'mac_nha', 'bottom'), ('Quần lót đùi', 'hang_ngay', 'bottom'), ('Quần lót đùi', 'hang_ngay', 'bottom'), ('Quần lót đùi', 'hang_ngay', 'bottom'), ('Quần lót đùi', 'hang_ngay', 'bottom'), ('Quần lót đùi', 'hang_ngay', 'bottom'), ('Quần mặc nhà', 'mac_nha', 'top'), ('Quần mặc nhà', 'mac_nha', 'top'), ('Quần mặc nhà', 'mac_nha', 'top'), ('Quần mặc nhà', 'mac_nha', 'top'), ('Quần mặc nhà', 'mac_nha', 'top'), ('Quần mặc nhà', 'mac_nha', 'top'), ('Quần mặc nhà', 'mac_nha', 'top'), ('Quần mặc nhà', 'mac_nha', 'top'), ('Quần mặc nhà', 'mac_nha', 'top'), ('Quần mặc nhà', 'mac_nha', 'top'), ('Quần mặc nhà', 'mac_nha', 'home/other'), ('Quần mặc nhà', 'mac_nha', 'home/other'), ('Quần mặc nhà', 'mac_nha', 'home/other'), ('Quần mặc nhà', 'mac_nha', 'home/other'), ('Quần nỉ', 'hang_ngay', 'top'), ('Quần nỉ', 'hang_ngay', 'top'), ('Quần nỉ', 'hang_ngay', 'top'), ('Quần nỉ', 'hang_ngay', 'top'), ('Quần nỉ', 'hang_ngay', 'top'), ('Quần nỉ', 'hang_ngay', 'top'), ('Quần nỉ', 'hang_ngay', 'top'), ('Quần nỉ', 'hang_ngay', 'top'), ('Quần nỉ', 'hang_ngay', 'top'), ('Quần nỉ', 'hang_ngay', 'top'), ('Quần nỉ', 'di_lam', 'bottom'), ('Quần nỉ', 'di_lam', 'bottom'), ('Quần nỉ', 'di_lam', 'bottom'), ('Quần nỉ', 'di_lam', 'bottom'), ('Quần nỉ', 'di_lam', 'bottom'), ('Quần nỉ', 'the_thao', 'bottom'), ('Quần nỉ', 'the_thao', 'bottom'), ('Quần nỉ', 'the_thao', 'bottom'), ('Quần nỉ', 'the_thao', 'bottom'), ('Quần nỉ', 'the_thao', 'bottom'), ('Quần nỉ', 'the_thao', 'bottom'), ('Quần nỉ', 'the_thao', 'bottom'), ('Quần nỉ', 'the_thao', 'bottom'), ('Quần nỉ', 'the_thao', 'bottom'), ('Quần nỉ', 'the_thao', 'bottom'), ('Quần soóc', 'hang_ngay', 'top'), ('Quần soóc', 'hang_ngay', 'top'), ('Quần soóc', 'hang_ngay', 'top'), ('Quần soóc', 'hang_ngay', 'top'), ('Quần soóc', 'hang_ngay', 'top'), ('Quần soóc', 'hang_ngay', 'top'), ('Quần soóc', 'hang_ngay', 'top'), ('Quần soóc', 'hang_ngay', 'top'), ('Quần soóc', 'hang_ngay', 'top'), ('Quần soóc', 'hang_ngay', 'top'), ('Quần soóc', 'hang_ngay', 'top'), ('Quần soóc', 'hang_ngay', 'top'), ('Quần soóc', 'hang_ngay', 'top'), ('Quần soóc', 'hang_ngay', 'top'), ('Quần soóc', 'hang_ngay', 'top'), ('Quần soóc', 'hang_ngay', 'accessory'), ('Quần soóc', 'hang_ngay', 'accessory'), ('Quần soóc', 'hang_ngay', 'accessory'), ('Quần soóc', 'hang_ngay', 'accessory'), ('Quần soóc', 'hang_ngay', 'accessory'), ('Quần soóc', 'hang_ngay', 'underwear'), ('Quần soóc', 'hang_ngay', 'underwear'), ('Quần soóc', 'hang_ngay', 'underwear'), ('Quần soóc', 'hang_ngay', 'underwear'), ('Quần soóc', 'hang_ngay', 'underwear'), ('Quần soóc', 'hang_ngay', 'underwear'), ('Quần váy', 'hang_ngay', 'top'), ('Quần váy', 'hang_ngay', 'top'), ('Quần váy', 'hang_ngay', 'top'), ('Quần váy', 'hang_ngay', 'top'), ('Quần váy', 'hang_ngay', 'accessory'), ('Quần váy', 'hang_ngay', 'accessory'), ('Quần váy', 'hang_ngay', 'underwear'), ('Quần váy', 'hang_ngay', 'underwear'), ('Túi xách', 'di_lam', 'accessory'), ('Túi xách', 'hang_ngay', 'top'), ('Túi xách', 'hang_ngay', 'top'), ('Túi xách', 'hang_ngay', 'top'), ('Túi xách', 'di_lam', 'accessory'), ('Tất', 'the_thao', 'accessory'), ('Tất', 'the_thao', 'accessory'), ('Tất', 'the_thao', 'accessory'), ('Tất', 'the_thao', 'accessory'), ('Tất', 'the_thao', 'accessory'), ('Tất', 'the_thao', 'accessory'), ('Tất', 'the_thao', 'accessory'), ('Tất', 'the_thao', 'accessory'), ('Tất', 'the_thao', 'accessory'), ('Tất', 'the_thao', 'accessory'), ('Tất', 'the_thao', 'accessory'), ('Tất', 'the_thao', 'accessory'), ('Tất', 'the_thao', 'accessory'), ('Tất', 'the_thao', 'accessory'), ('Tất', 'the_thao', 'accessory'), ('Tất', 'the_thao', 'accessory'), ('Tất', 'the_thao', 'accessory'), ('Tất', 'the_thao', 'accessory'), ('Tất', 'the_thao', 'accessory'), ('Tất', 'the_thao', 'accessory'), ('Váy liền', 'di_lam', 'accessory'), ('Váy liền', 'di_lam', 'accessory'), ('Váy liền', 'di_lam', 'accessory'), ('Váy liền', 'di_lam', 'accessory'), ('Váy liền', 'di_lam', 'accessory'), ('Váy liền', 'hang_ngay', 'accessory'), ('Váy liền', 'hang_ngay', 'accessory'), ('Váy liền', 'hang_ngay', 'accessory'), ('Váy liền', 'hang_ngay', 'accessory'), ('Váy liền', 'hang_ngay', 'underwear'), ('Váy liền', 'hang_ngay', 'underwear'), ('Áo Body', 'hang_ngay', 'bottom'), ('Áo Body', 'hang_ngay', 'bottom'), ('Áo Body', 'hang_ngay', 'bottom'), ('Áo Body', 'hang_ngay', 'bottom'), ('Áo Body', 'hang_ngay', 'bottom'), ('Áo Body', 'hang_ngay', 'bottom'), ('Áo Body', 'hang_ngay', 'bottom'), ('Áo Body', 'hang_ngay', 'bottom'), ('Áo Body', 'hang_ngay', 'bottom'), ('Áo Body', 'hang_ngay', 'bottom'), ('Áo Body', 'hang_ngay', 'bottom'), ('Áo Body', 'hang_ngay', 'bottom'), ('Áo Body', 'hang_ngay', 'bottom'), ('Áo Body', 'hang_ngay', 'bottom'), ('Áo Body', 'hang_ngay', 'bottom'), ('Áo Body', 'di_lam', 'top'), ('Áo Body', 'di_lam', 'top'), ('Áo Body', 'di_lam', 'top'), ('Áo Body', 'di_lam', 'top'), ('Áo Body', 'di_lam', 'top'), ('Áo Polo', 'hang_ngay', 'bottom'), ('Áo Polo', 'hang_ngay', 'bottom'), ('Áo Polo', 'hang_ngay', 'bottom'), ('Áo Polo', 'hang_ngay', 'bottom'), ('Áo Polo', 'hang_ngay', 'bottom'), ('Áo Polo', 'hang_ngay', 'bottom'), ('Áo Polo', 'hang_ngay', 'bottom'), ('Áo Polo', 'hang_ngay', 'bottom'), ('Áo Polo', 'hang_ngay', 'bottom'), ('Áo Polo', 'hang_ngay', 'bottom'), ('Áo Polo', 'hang_ngay', 'bottom'), ('Áo Polo', 'hang_ngay', 'bottom'), ('Áo Polo', 'hang_ngay', 'bottom'), ('Áo Polo', 'hang_ngay', 'bottom'), ('Áo Polo', 'hang_ngay', 'bottom'), ('Áo Polo', 'the_thao', 'top'), ('Áo Polo', 'the_thao', 'top'), ('Áo Polo', 'the_thao', 'top'), ('Áo Polo', 'the_thao', 'top'), ('Áo Polo', 'the_thao', 'top'), ('Áo Polo', 'hang_ngay', 'accessory'), ('Áo Polo', 'hang_ngay', 'accessory'), ('Áo Polo', 'hang_ngay', 'accessory'), ('Áo Polo', 'hang_ngay', 'accessory'), ('Áo Polo', 'hang_ngay', 'accessory'), ('Áo Sơ mi', 'hang_ngay', 'bottom'), ('Áo Sơ mi', 'hang_ngay', 'bottom'), ('Áo Sơ mi', 'hang_ngay', 'bottom'), ('Áo Sơ mi', 'hang_ngay', 'bottom'), ('Áo Sơ mi', 'hang_ngay', 'bottom'), ('Áo Sơ mi', 'hang_ngay', 'bottom'), ('Áo Sơ mi', 'hang_ngay', 'bottom'), ('Áo Sơ mi', 'hang_ngay', 'bottom'), ('Áo Sơ mi', 'hang_ngay', 'bottom'), ('Áo Sơ mi', 'hang_ngay', 'bottom'), ('Áo Sơ mi', 'hang_ngay', 'bottom'), ('Áo Sơ mi', 'hang_ngay', 'bottom'), ('Áo Sơ mi', 'hang_ngay', 'bottom'), ('Áo Sơ mi', 'di_lam', 'top'), ('Áo Sơ mi', 'di_lam', 'top'), ('Áo Sơ mi', 'di_lam', 'top'), ('Áo Sơ mi', 'di_lam', 'top'), ('Áo Sơ mi', 'di_lam', 'top'), ('Áo Sơ mi', 'di_lam', 'top'), ('Áo Sơ mi', 'di_lam', 'top'), ('Áo Sơ mi', 'di_lam', 'top'), ('Áo Sơ mi', 'hang_ngay', 'accessory'), ('Áo Sơ mi', 'hang_ngay', 'accessory'), ('Áo Sơ mi', 'hang_ngay', 'accessory'), ('Áo Sơ mi', 'hang_ngay', 'accessory'), ('Áo Sơ mi', 'hang_ngay', 'accessory'), ('Áo ba lỗ', 'hang_ngay', 'bottom'), ('Áo ba lỗ', 'hang_ngay', 'bottom'), ('Áo ba lỗ', 'hang_ngay', 'bottom'), ('Áo ba lỗ', 'hang_ngay', 'bottom'), ('Áo ba lỗ', 'hang_ngay', 'bottom'), ('Áo ba lỗ', 'hang_ngay', 'bottom'), ('Áo ba lỗ', 'hang_ngay', 'bottom'), ('Áo ba lỗ', 'hang_ngay', 'bottom'), ('Áo ba lỗ', 'di_lam', 'top'), ('Áo ba lỗ', 'di_lam', 'top'), ('Áo ba lỗ', 'di_lam', 'top'), ('Áo ba lỗ', 'di_lam', 'top'), ('Áo giữ nhiệt', 'di_lam', 'top'), ('Áo giữ nhiệt', 'di_lam', 'top'), ('Áo giữ nhiệt', 'di_lam', 'top'), ('Áo giữ nhiệt', 'di_lam', 'top'), ('Áo giữ nhiệt', 'di_lam', 'top'), ('Áo giữ nhiệt', 'di_lam', 'top'), ('Áo giữ nhiệt', 'hang_ngay', 'bottom'), ('Áo hai dây', 'di_lam', 'top'), ('Áo hai dây', 'hang_ngay', 'bottom'), ('Áo hai dây', 'hang_ngay', 'bottom'), ('Áo hai dây', 'hang_ngay', 'underwear'), ('Áo khoác', 'hang_ngay', 'top'), ('Áo khoác', 'hang_ngay', 'top'), ('Áo khoác', 'hang_ngay', 'top'), ('Áo khoác', 'hang_ngay', 'top'), ('Áo khoác', 'hang_ngay', 'bottom'), ('Áo khoác', 'hang_ngay', 'bottom'), ('Áo khoác', 'hang_ngay', 'accessory'), ('Áo khoác', 'hang_ngay', 'accessory'), ('Áo khoác chần bông', 'hang_ngay', 'top'), ('Áo khoác chần bông', 'hang_ngay', 'top'), ('Áo khoác chần bông', 'hang_ngay', 'top'), ('Áo khoác chần bông', 'hang_ngay', 'top'), ('Áo khoác chần bông', 'hang_ngay', 'top'), ('Áo khoác chần bông', 'hang_ngay', 'top'), ('Áo khoác chần bông', 'hang_ngay', 'top'), ('Áo khoác chần bông', 'hang_ngay', 'top'), ('Áo khoác chần bông', 'hang_ngay', 'bottom'), ('Áo khoác chần bông', 'hang_ngay', 'bottom'), ('Áo khoác chần bông', 'hang_ngay', 'bottom'), ('Áo khoác chần bông', 'hang_ngay', 'bottom'), ('Áo khoác chần bông', 'hang_ngay', 'bottom'), ('Áo khoác chần bông', 'hang_ngay', 'bottom'), ('Áo khoác chần bông', 'hang_ngay', 'bottom'), ('Áo khoác chần bông', 'hang_ngay', 'bottom'), ('Áo khoác chống nắng', 'hang_ngay', 'top'), ('Áo khoác chống nắng', 'hang_ngay', 'top'), ('Áo khoác chống nắng', 'hang_ngay', 'top'), ('Áo khoác chống nắng', 'hang_ngay', 'accessory'), ('Áo khoác chống nắng', 'hang_ngay', 'accessory'), ('Áo khoác chống nắng', 'hang_ngay', 'accessory'), ('Áo khoác chống nắng', 'hang_ngay', 'accessory'), ('Áo khoác chống nắng', 'hang_ngay', 'accessory'), ('Áo khoác chống nắng', 'hang_ngay', 'accessory'), ('Áo khoác chống nắng', 'hang_ngay', 'bottom'), ('Áo khoác chống nắng', 'hang_ngay', 'bottom'), ('Áo khoác chống nắng', 'hang_ngay', 'bottom'), ('Áo khoác dáng ngắn', 'hang_ngay', 'top'), ('Áo khoác dáng ngắn', 'hang_ngay', 'top'), ('Áo khoác dáng ngắn', 'hang_ngay', 'top'), ('Áo khoác dáng ngắn', 'hang_ngay', 'top'), ('Áo khoác dáng ngắn', 'hang_ngay', 'top'), ('Áo khoác dáng ngắn', 'hang_ngay', 'bottom'), ('Áo khoác dáng ngắn', 'hang_ngay', 'bottom'), ('Áo khoác dáng ngắn', 'hang_ngay', 'bottom'), ('Áo khoác dáng ngắn', 'hang_ngay', 'bottom'), ('Áo khoác dáng ngắn', 'hang_ngay', 'bottom'), ('Áo khoác dạ', 'hang_ngay', 'top'), ('Áo khoác dạ', 'hang_ngay', 'top'), ('Áo khoác dạ', 'hang_ngay', 'bottom'), ('Áo khoác dạ', 'hang_ngay', 'accessory'), ('Áo khoác gilet chần bông', 'hang_ngay', 'top'), ('Áo khoác gilet chần bông', 'hang_ngay', 'top'), ('Áo khoác gilet chần bông', 'hang_ngay', 'top'), ('Áo khoác gilet chần bông', 'hang_ngay', 'top'), ('Áo khoác gilet chần bông', 'hang_ngay', 'top'), ('Áo khoác gilet chần bông', 'hang_ngay', 'top'), ('Áo khoác gilet chần bông', 'hang_ngay', 'top'), ('Áo khoác gilet chần bông', 'hang_ngay', 'top'), ('Áo khoác gilet chần bông', 'hang_ngay', 'bottom'), ('Áo khoác gilet chần bông', 'hang_ngay', 'bottom'), ('Áo khoác gilet chần bông', 'hang_ngay', 'bottom'), ('Áo khoác gilet chần bông', 'hang_ngay', 'bottom'), ('Áo khoác gilet chần bông', 'hang_ngay', 'bottom'), ('Áo khoác gilet chần bông', 'hang_ngay', 'bottom'), ('Áo khoác gilet chần bông', 'hang_ngay', 'bottom'), ('Áo khoác gilet chần bông', 'hang_ngay', 'bottom'), ('Áo khoác gió', 'hang_ngay', 'top'), ('Áo khoác gió', 'hang_ngay', 'top'), ('Áo khoác gió', 'hang_ngay', 'top'), ('Áo khoác gió', 'hang_ngay', 'top'), ('Áo khoác gió', 'hang_ngay', 'top'), ('Áo khoác gió', 'the_thao', 'top'), ('Áo khoác gió', 'the_thao', 'top'), ('Áo khoác gió', 'the_thao', 'top'), ('Áo khoác gió', 'the_thao', 'top'), ('Áo khoác gió', 'the_thao', 'top'), ('Áo khoác gió', 'hang_ngay', 'bottom'), ('Áo khoác gió', 'hang_ngay', 'bottom'), ('Áo khoác gió', 'hang_ngay', 'bottom'), ('Áo khoác gió', 'hang_ngay', 'bottom'), ('Áo khoác gió', 'hang_ngay', 'bottom'), ('Áo khoác gió', 'the_thao', 'top'), ('Áo khoác gió', 'the_thao', 'top'), ('Áo khoác gió', 'the_thao', 'top'), ('Áo khoác gió', 'the_thao', 'top'), ('Áo khoác gió', 'the_thao', 'top'), ('Áo khoác lông vũ', 'hang_ngay', 'top'), ('Áo khoác lông vũ', 'hang_ngay', 'top'), ('Áo khoác lông vũ', 'hang_ngay', 'top'), ('Áo khoác lông vũ', 'hang_ngay', 'top'), ('Áo khoác lông vũ', 'hang_ngay', 'bottom'), ('Áo khoác lông vũ', 'hang_ngay', 'bottom'), ('Áo khoác lông vũ', 'hang_ngay', 'bottom'), ('Áo khoác lông vũ', 'hang_ngay', 'bottom'), ('Áo khoác nỉ có mũ', 'hang_ngay', 'top'), ('Áo khoác nỉ có mũ', 'hang_ngay', 'top'), ('Áo khoác nỉ có mũ', 'hang_ngay', 'top'), ('Áo khoác nỉ có mũ', 'hang_ngay', 'bottom'), ('Áo khoác nỉ có mũ', 'hang_ngay', 'bottom'), ('Áo khoác nỉ có mũ', 'hang_ngay', 'bottom'), ('Áo khoác nỉ có mũ', 'hang_ngay', 'bottom'), ('Áo khoác nỉ có mũ', 'hang_ngay', 'bottom'), ('Áo khoác nỉ có mũ', 'hang_ngay', 'bottom'), ('Áo khoác nỉ không mũ', 'hang_ngay', 'top'), ('Áo khoác nỉ không mũ', 'hang_ngay', 'top'), ('Áo khoác nỉ không mũ', 'hang_ngay', 'top'), ('Áo khoác nỉ không mũ', 'hang_ngay', 'top'), ('Áo khoác nỉ không mũ', 'hang_ngay', 'top'), ('Áo khoác nỉ không mũ', 'hang_ngay', 'bottom'), ('Áo khoác nỉ không mũ', 'hang_ngay', 'bottom'), ('Áo khoác nỉ không mũ', 'hang_ngay', 'bottom'), ('Áo khoác nỉ không mũ', 'hang_ngay', 'bottom'), ('Áo khoác nỉ không mũ', 'hang_ngay', 'bottom'), ('Áo khoác nỉ không mũ', 'hang_ngay', 'bottom'), ('Áo khoác nỉ không mũ', 'hang_ngay', 'bottom'), ('Áo khoác nỉ không mũ', 'hang_ngay', 'bottom'), ('Áo khoác nỉ không mũ', 'hang_ngay', 'bottom'), ('Áo khoác nỉ không mũ', 'hang_ngay', 'bottom'), ('Áo khoác nỉ không mũ', 'the_thao', 'top'), ('Áo khoác nỉ không mũ', 'the_thao', 'top'), ('Áo khoác nỉ không mũ', 'the_thao', 'top'), ('Áo khoác nỉ không mũ', 'the_thao', 'top'), ('Áo khoác nỉ không mũ', 'the_thao', 'top'), ('Áo khoác sợi', 'hang_ngay', 'top'), ('Áo khoác sợi', 'hang_ngay', 'top'), ('Áo khoác sợi', 'hang_ngay', 'bottom'), ('Áo kiểu', 'hang_ngay', 'bottom'), ('Áo kiểu', 'hang_ngay', 'bottom'), ('Áo kiểu', 'hang_ngay', 'bottom'), ('Áo kiểu', 'hang_ngay', 'bottom'), ('Áo kiểu', 'hang_ngay', 'bottom'), ('Áo kiểu', 'hang_ngay', 'bottom'), ('Áo kiểu', 'di_lam', 'top'), ('Áo kiểu', 'hang_ngay', 'accessory'), ('Áo kiểu', 'hang_ngay', 'accessory'), ('Áo kiểu', 'hang_ngay', 'underwear'), ('Áo kiểu', 'hang_ngay', 'underwear'), ('Áo len', 'hang_ngay', 'bottom'), ('Áo len', 'hang_ngay', 'bottom'), ('Áo len', 'hang_ngay', 'bottom'), ('Áo len', 'hang_ngay', 'bottom'), ('Áo len', 'hang_ngay', 'bottom'), ('Áo len', 'hang_ngay', 'bottom'), ('Áo len', 'hang_ngay', 'bottom'), ('Áo len', 'hang_ngay', 'bottom'), ('Áo len', 'hang_ngay', 'bottom'), ('Áo len', 'hang_ngay', 'bottom'), ('Áo len', 'di_lam', 'top'), ('Áo len', 'di_lam', 'top'), ('Áo len', 'hang_ngay', 'accessory'), ('Áo len', 'hang_ngay', 'accessory'), ('Áo len', 'hang_ngay', 'accessory'), ('Áo len', 'hang_ngay', 'accessory'), ('Áo len gilet', 'hang_ngay', 'top'), ('Áo len gilet', 'hang_ngay', 'top'), ('Áo len gilet', 'hang_ngay', 'top'), ('Áo len gilet', 'hang_ngay', 'bottom'), ('Áo len gilet', 'hang_ngay', 'bottom'), ('Áo len gilet', 'hang_ngay', 'bottom'), ('Áo len gilet', 'hang_ngay', 'bottom'), ('Áo len gilet', 'hang_ngay', 'bottom'), ('Áo lót', 'hang_ngay', 'top'), ('Áo lót', 'hang_ngay', 'top'), ('Áo mặc nhà', 'mac_nha', 'bottom'), ('Áo mặc nhà', 'mac_nha', 'bottom'), ('Áo mặc nhà', 'mac_nha', 'bottom'), ('Áo mặc nhà', 'mac_nha', 'bottom'), ('Áo mặc nhà', 'mac_nha', 'bottom'), ('Áo nỉ', 'hang_ngay', 'bottom'), ('Áo nỉ', 'hang_ngay', 'bottom'), ('Áo nỉ', 'hang_ngay', 'bottom'), ('Áo nỉ', 'hang_ngay', 'bottom'), ('Áo nỉ', 'hang_ngay', 'bottom'), ('Áo nỉ', 'hang_ngay', 'bottom'), ('Áo nỉ', 'hang_ngay', 'bottom'), ('Áo nỉ', 'hang_ngay', 'bottom'), ('Áo nỉ', 'hang_ngay', 'bottom'), ('Áo nỉ', 'hang_ngay', 'bottom'), ('Áo nỉ', 'di_lam', 'top'), ('Áo nỉ', 'di_lam', 'top'), ('Áo nỉ', 'di_lam', 'top'), ('Áo nỉ', 'di_lam', 'top'), ('Áo nỉ', 'di_lam', 'top'), ('Áo nỉ', 'hang_ngay', 'accessory'), ('Áo nỉ', 'hang_ngay', 'accessory'), ('Áo nỉ', 'hang_ngay', 'accessory'), ('Áo nỉ', 'hang_ngay', 'accessory'), ('Áo nỉ', 'hang_ngay', 'accessory'), ('Áo nỉ có mũ', 'hang_ngay', 'bottom'), ('Áo nỉ có mũ', 'hang_ngay', 'bottom'), ('Áo nỉ có mũ', 'hang_ngay', 'bottom'), ('Áo nỉ có mũ', 'hang_ngay', 'bottom'), ('Áo nỉ có mũ', 'hang_ngay', 'bottom'), ('Áo nỉ có mũ', 'hang_ngay', 'bottom'), ('Áo nỉ có mũ', 'hang_ngay', 'bottom'), ('Áo nỉ có mũ', 'hang_ngay', 'bottom'), ('Áo nỉ có mũ', 'di_lam', 'top'), ('Áo nỉ có mũ', 'di_lam', 'top'), ('Áo nỉ có mũ', 'di_lam', 'top'), ('Áo nỉ có mũ', 'di_lam', 'top'), ('Áo phông', 'hang_ngay', 'bottom'), ('Áo phông', 'hang_ngay', 'bottom'), ('Áo phông', 'hang_ngay', 'bottom'), ('Áo phông', 'hang_ngay', 'bottom'), ('Áo phông', 'hang_ngay', 'bottom'), ('Áo phông', 'hang_ngay', 'bottom'), ('Áo phông', 'hang_ngay', 'bottom'), ('Áo phông', 'hang_ngay', 'bottom'), ('Áo phông', 'hang_ngay', 'bottom'), ('Áo phông', 'hang_ngay', 'bottom'), ('Áo phông', 'hang_ngay', 'bottom'), ('Áo phông', 'hang_ngay', 'bottom'), ('Áo phông', 'hang_ngay', 'bottom'), ('Áo phông', 'hang_ngay', 'bottom'), ('Áo phông', 'hang_ngay', 'bottom'), ('Áo phông', 'hang_ngay', 'bottom'), ('Áo phông', 'hang_ngay', 'bottom'), ('Áo phông', 'hang_ngay', 'bottom'), ('Áo phông', 'hang_ngay', 'bottom'), ('Áo phông', 'hang_ngay', 'bottom'), ('Áo phông', 'hang_ngay', 'bottom'), ('Áo phông', 'hang_ngay', 'bottom'), ('Áo phông', 'hang_ngay', 'bottom'), ('Áo phông', 'di_lam', 'top'), ('Áo phông', 'di_lam', 'top'), ('Áo phông', 'di_lam', 'top'), ('Áo phông', 'di_lam', 'top'), ('Áo phông', 'di_lam', 'top'), ('Áo phông', 'di_lam', 'top'), ('Áo phông', 'di_lam', 'top'), ('Áo phông', 'di_lam', 'top'), ('Áo phông', 'di_lam', 'top'), ('Áo phông', 'di_lam', 'top'), ('Áo phông', 'di_lam', 'top'), ('Áo phông', 'di_lam', 'top'), ('Áo phông', 'di_lam', 'top'), ('Áo phông', 'hang_ngay', 'accessory'), ('Áo phông', 'hang_ngay', 'accessory'), ('Áo phông', 'hang_ngay', 'accessory'), ('Áo phông', 'hang_ngay', 'accessory'), ('Áo phông', 'hang_ngay', 'accessory'), ('Áo phông', 'the_thao', 'top'), ('Áo phông', 'the_thao', 'top'), ('Áo phông', 'the_thao', 'top'), ('Áo phông', 'the_thao', 'top'), ('Áo phông', 'the_thao', 'top'), ('Áo phông', 'hang_ngay', 'underwear'), ('Áo phông', 'hang_ngay', 'underwear')]
\ No newline at end of file
......@@ -5,7 +5,7 @@ from pathlib import Path
import logging
logger = logging.getLogger(__name__)
router = APIRouter(prefix="/event_daily", tags=["Event Daily"])
router = APIRouter(prefix="/api/event_daily", tags=["Event Daily"])
BASE_DIR = Path(__file__).resolve().parents[2]
DB_PATH = BASE_DIR / "database" / "autotrain.db"
......@@ -17,6 +17,8 @@ def get_db() -> sqlite3.Connection:
class EventPromptUpdate(BaseModel):
prompt: str
start_date: str | None = None
end_date: str | None = None
@router.get("/events")
async def list_events():
......@@ -38,7 +40,9 @@ async def list_events():
"type": row["event_type"],
"date": row["event_date"],
"isToday": bool(row["is_today"]),
"prompt": row["prompt"]
"prompt": row["prompt"],
"startDate": row["start_date"],
"endDate": row["end_date"]
})
return events
......@@ -46,7 +50,7 @@ async def list_events():
async def update_event_prompt(event_id: str, data: EventPromptUpdate):
conn = get_db()
cur = conn.cursor()
cur.execute("UPDATE event_daily_prompts SET prompt = ?, updated_at = CURRENT_TIMESTAMP WHERE event_id = ?", (data.prompt, event_id))
cur.execute("UPDATE event_daily_prompts SET prompt = ?, start_date = ?, end_date = ?, updated_at = CURRENT_TIMESTAMP WHERE event_id = ?", (data.prompt, data.start_date, data.end_date, event_id))
if cur.rowcount == 0:
conn.close()
raise HTTPException(status_code=404, detail="Event not found")
......
......@@ -9,7 +9,7 @@ from api.api_sql.text_to_sql_route import router as text_to_sql_router
from api.api_sql.user_insight_route import router as user_insight_router
from api.autotrain.auto_pipeline_route import router as pipeline_router
from api.autotrain.autotrain_route import router as autotrain_router
from api.autotrain.event_daily_route import router as event_daily_router
from api.event_daily.event_daily_route import router as event_daily_router
from api.cache.cache_route import router as cache_router
from api.common.auth_route import router as auth_router
......
Chân váy
Găng tay chống nắng
Khăn
Khẩu trang
Mũ
Quần Body
Quần Khaki
Quần dài
Quần giữ nhiệt
Quần jean
Quần leggings
Quần nỉ
Túi xách
Váy liền
Áo Body
Áo Sơ mi
Áo ba lỗ
Áo giữ nhiệt
Áo hai dây
Áo kiểu
Áo len
Áo nỉ
Áo nỉ có mũ
Áo phông
\ No newline at end of file
import sqlite3
import json
conn = sqlite3.connect('D:/cnf/chatbot-canifa-feedback/backend/database/autotrain.db')
conn.row_factory = sqlite3.Row
print(conn.execute("SELECT sql FROM sqlite_master WHERE type='table' AND name='event_daily_prompts'").fetchone()[0])
rows = conn.execute("SELECT * FROM event_daily_prompts").fetchall()
print(json.dumps([dict(row) for row in rows], ensure_ascii=False, indent=2))
import sqlite3
def migrate():
conn = sqlite3.connect('D:/cnf/chatbot-canifa-feedback/backend/database/autotrain.db')
cur = conn.cursor()
try:
cur.execute("ALTER TABLE event_daily_prompts ADD COLUMN start_date TEXT")
except Exception as e:
print("start_date:", e)
try:
cur.execute("ALTER TABLE event_daily_prompts ADD COLUMN end_date TEXT")
except Exception as e:
print("end_date:", e)
conn.commit()
conn.close()
print("Migration complete")
if __name__ == '__main__':
migrate()
import sqlite3
def mock_events():
conn = sqlite3.connect('D:/cnf/chatbot-canifa-feedback/backend/database/autotrain.db')
cur = conn.cursor()
events = [
("evt_daily", "Mặc định hàng ngày", "Daily", "All days", 1, "- Luôn chào hỏi thân thiện\n- Gợi ý đồ dạo phố, công sở nhẹ nhàng", None, None),
("evt_tet", "Tết Nguyên Đán 2027", "Campaign", "Tháng 1/2027", 0, "- Chúc mừng năm mới\n- Ưu tiên màu đỏ, vàng, trang phục may mắn", "2027-01-01", "2027-02-15"),
("evt_304", "Giải phóng Miền Nam", "Campaign", "30/04/2026", 0, "- Chào mừng đại lễ 30/4\n- Gợi ý áo thun năng động, trang phục du lịch", "2026-04-20", "2026-05-02"),
("evt_15", "Quốc tế Lao động", "Campaign", "01/05/2026", 0, "- Kỷ niệm Quốc tế lao động\n- Trang phục thoải mái nghỉ dưỡng", "2026-04-20", "2026-05-02"),
("evt_29", "Quốc Khánh 2/9", "Campaign", "02/09/2026", 0, "- Chào mừng Quốc khánh\n- Áo cờ đỏ sao vàng, màu cờ sắc áo", "2026-08-25", "2026-09-05"),
("evt_summer", "Chiến dịch Mùa Hè", "Campaign", "Hè 2026", 0, "- Mùa hè rực rỡ\n- Đẩy mạnh quần short, áo thun mát mẻ, đồ bơi", "2026-05-01", "2026-08-31"),
("evt_winter", "Chiến dịch Mùa Đông", "Campaign", "Đông 2026", 0, "- Mùa đông ấm áp\n- Tập trung áo khoác dạ, áo len lông cừu", "2026-10-01", "2026-12-31"),
("evt_gioto", "Giỗ tổ Hùng Vương", "Campaign", "Mùng 10 tháng 3", 0, "- Nhớ về cội nguồn\n- Đồ lịch sự, trang nhã, đi đền chùa", "2026-03-25", "2026-04-05"),
]
for evt in events:
try:
# Using INSERT OR REPLACE to ensure they exist and overwrite if needed
cur.execute("""
INSERT OR REPLACE INTO event_daily_prompts
(event_id, event_name, event_type, event_date, is_today, prompt, start_date, end_date)
VALUES (?, ?, ?, ?, ?, ?, ?, ?)
""", evt)
except Exception as e:
print("Error inserting:", evt[0], e)
conn.commit()
conn.close()
print("Mock events inserted.")
if __name__ == '__main__':
mock_events()
# Triết lý thiết kế: Tại sao LLM là Router, không phải Stylist?
> **Tóm tắt:** Tài liệu này giải thích triết lý cốt lõi nhất của hệ thống AI Canifa: **LLM không phải là chuyên gia thời trang. LLM là kẻ điều hướng tọa độ trên bản đồ dữ liệu (Graph Router).** Chuyên môn thời trang nằm chết cứng trong Database. LLM chỉ làm đúng 1 việc: chọn cửa nào để mở.
---
## 1.1. Bài toán gốc: "Con AI bịa đồ"
Khi xây dựng chatbot thời trang, hầu hết các team sẽ nghĩ:
> *"Nhét kiến thức thời trang vào Prompt → LLM tự phối đồ → Trả về kết quả"*
**Đây là cái bẫy chết người.** Tại sao?
| Vấn đề | Mô tả | Hậu quả thực tế |
|--------|-------|-----------------|
| **Hallucination** | LLM bịa ra SKU không tồn tại | Khách click link → 404 → Mất niềm tin |
| **Inconsistency** | Hỏi 2 lần, trả lời 2 kiểu | Khách hoang mang, không dám mua |
| **Demographic Blindness** | Gợi ý đồ người lớn cho trẻ em | Vi phạm brand safety → Scandal |
| **Season Mismatch** | Gợi áo phao giữa mùa hè | Trải nghiệm kỳ quặc |
| **No Inventory Awareness** | Gợi đồ hết hàng | Khách frustrated, bounce rate tăng |
> **Insight từ ngành:** Theo nghiên cứu của Envive.ai (2025), chatbot AI tăng tỉ lệ upsell **20-30%** — nhưng CHỈ KHI gợi ý dựa trên **dữ liệu thật** (kho hàng, lịch sử mua, demographic). Dùng "cảm hứng" của LLM → tỉ lệ return tăng, NPS giảm.
---
## 1.2. Triết lý "Người mù và Cái rãnh" (The Blind Man & The Rail)
Hãy tưởng tượng con AI như một **người mù rất giỏi nói chuyện**. Nó có thể đối thoại cực kỳ tự nhiên, duyên dáng. Nhưng nó **không nhìn thấy đường**.
Nếu để nó tự đi (Pure LLM) → nó sẽ lao xuống mương (Hallucinate).
**Giải pháp của Canifa:** Xây sẵn **những cái rãnh trên đường** (Pre-computed JSON trong Database). Người mù (LLM) cứ chọc gậy vào rãnh (Data) là tự khắc đi đúng đường.
```
┌─────────────────────────────────────────────────────┐
│ PURE LLM APPROACH │
│ │
│ User ──→ LLM (Tự phối đồ) ──→ Response │
│ ↑ │
│ Kiến thức = Training Data (cũ, thiếu) │
│ Kết quả = ❌ Không kiểm soát được │
└─────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────┐
│ CANIFA HYBRID APPROACH │
│ │
│ User ──→ LLM (Chọn cửa) ──→ Database (Lấy data) │
│ ↑ ↓ │
│ Vai trò = Router Kết quả = ✅ 100% │
│ sản phẩm thật │
└─────────────────────────────────────────────────────┘
```
---
## 1.3. Ba chìa khóa của Graph Router
Mỗi Sản phẩm (SKU) trong Database là một **Trạm dừng chân (Node)**. Khi AI đứng ở một Trạm, nó cầm trong tay **3 chùm chìa khóa** (3 mảng JSON đã được tính toán sẵn):
```mermaid
graph TD
SKU["🏷️ SKU Hiện Tại<br/>(Trạm đang đứng)"]
KEY1["🔑 Chìa 1: outfit_recommendations<br/>Cross-sell / Phối đồ<br/><i>Áo A → Quần B, Váy C</i>"]
KEY2["🔑 Chìa 2: similar_items<br/>Down-sell / Thay thế<br/><i>Áo A → Áo A1 rẻ hơn, Áo A2 khác màu</i>"]
KEY3["🔑 Chìa 3: Product Metadata (DNA)<br/>Upsell / Mở rộng<br/><i>Form, Chất liệu, Dịp, Giá</i>"]
SKU --> KEY1
SKU --> KEY2
SKU --> KEY3
KEY1 -->|"Khách: Phối gì?"| CROSS["✅ Gợi đồ phối"]
KEY2 -->|"Khách: Có rẻ hơn?"| ALT["✅ Đồ thay thế"]
KEY3 -->|"Khách: Tìm thêm?"| EXPAND["✅ Tìm kiếm mở rộng"]
style SKU fill:#f59e0b,stroke:#d97706,color:#000
style KEY1 fill:#3b82f6,stroke:#2563eb,color:#fff
style KEY2 fill:#10b981,stroke:#059669,color:#fff
style KEY3 fill:#8b5cf6,stroke:#7c3aed,color:#fff
```
| Chìa khóa | Cột Database | Khi nào dùng? | Complexity |
|------------|-------------|---------------|------------|
| **Outfit (Cross-sell)** | `outfit_recommendations` | Khách hỏi "phối gì?" | O(1) — JSON lookup |
| **Similar (Down-sell)** | `similar_items` | Khách hỏi "có cái nào giống vậy?" | O(1) — JSON lookup |
| **DNA (Upsell/Expand)** | Product metadata columns | Khách hỏi "tìm thêm kiểu này" | O(log n) — Indexed query |
---
## 1.4. Khác biệt cốt tử so với các hệ thống khác
| Tiêu chí | Pure LLM | RAG thuần (Vector Search) | **Canifa (Graph Router)** |
|----------|---------|--------------------------|--------------------------|
| **Nguồn kiến thức** | Training data (cũ) | Embedding similarity | Pre-computed JSON (do Merchandising duyệt) |
| **Độ chính xác** | ~60% (hay bịa) | ~75% (hay nhầm) | **~99%** (data thật, duyệt thủ công) |
| **Tốc độ** | 1-3s (LLM thinking) | 200-500ms (vector search) | **<5ms** (JSON lookup) |
| **Kiểm soát** | ❌ Không | ⚠️ Phụ thuộc embedding | ✅ **100% kiểm soát** |
| **Hallucination** | Cao | Trung bình | **Zero** |
| **Multi-turn** | Dễ lạc topic | Mỗi turn search lại | **Mượt mà** (Pivoting) |
> **Kết luận:** Con LLM trong hệ thống Canifa không cần biết gì về thời trang. Nó chỉ cần biết: *"Khi khách hỏi A, tôi mở cửa nào?"* Mọi kiến thức thời trang đã được "đóng gói" sẵn trong Database bởi đội Merchandising.
# Kiến trúc Pre-computed Graph (Đồ thị tính toán sẵn)
> **Tóm tắt:** Mỗi sản phẩm trong kho Canifa không phải là một "hàng hóa đơn lẻ" — nó là một **Node (Đỉnh)** trên một mạng lưới khổng lồ. Các cạnh nối (Edges) giữa các Node chính là các cột JSON `outfit_recommendations` và `similar_items`. Hệ thống này biến toàn bộ catalog ~2000 SKU thành một **Knowledge Graph** mà AI có thể "đi bộ" (traverse) với tốc độ O(1).
---
## 2.1. Tổng quan: Product Knowledge Graph
Thay vì dùng Neo4j hay Graph Database phức tạp, Canifa mô phỏng hoàn hảo một Knowledge Graph bằng **2 cột JSON** trong bảng SQL:
```mermaid
graph LR
subgraph "📦 Bảng Product Dimension"
A["Áo Polo<br/>POLO_01"]
B["Quần Jean<br/>JEAN_02"]
C["Giày Sneaker<br/>SHOE_03"]
D["Túi Tote<br/>BAG_04"]
E["Áo Thun<br/>TSHIRT_05"]
F["Quần Khaki<br/>KHAKI_06"]
end
A -->|"outfit_rec"| B
A -->|"outfit_rec"| C
B -->|"outfit_rec"| C
B -->|"outfit_rec"| D
C -->|"outfit_rec"| D
A -.->|"similar"| E
B -.->|"similar"| F
style A fill:#f59e0b,stroke:#d97706,color:#000
style B fill:#3b82f6,stroke:#2563eb,color:#fff
style C fill:#10b981,stroke:#059669,color:#fff
style D fill:#8b5cf6,stroke:#7c3aed,color:#fff
style E fill:#f59e0b,stroke:#d97706,color:#000
style F fill:#3b82f6,stroke:#2563eb,color:#fff
```
**Chú thích:**
- Đường liền `──→` = `outfit_recommendations` (Phối đồ / Cross-sell)
- Đường đứt `- - →` = `similar_items` (Thay thế / Down-sell)
---
## 2.2. Cấu trúc dữ liệu JSON trong Database
### Cột `outfit_recommendations` (Phối đồ)
Mỗi sản phẩm chứa một mảng JSON các sản phẩm được **chuyên gia Merchandising duyệt** là hợp khi mặc cùng:
```json
{
"product_code": "POLO_01",
"outfit_recommendations": [
{
"code": "JEAN_02",
"name": "Quần Jean Ống Rộng",
"role": "bottom",
"score": 92,
"reason": "Form slim-fit của Polo + ống rộng Jean tạo cân bằng tỉ lệ"
},
{
"code": "SHOE_03",
"name": "Giày Sneaker Trắng",
"role": "footwear",
"score": 88,
"reason": "Smart-casual hoàn chỉnh, tiệp tông trắng"
}
]
}
```
**Các trường quan trọng:**
| Trường | Mục đích | Ví dụ |
|--------|---------|-------|
| `code` | Mã SKU để truy vấn tiếp (Pivoting) | `JEAN_02` |
| `role` | Vai trò trong outfit (top/bottom/outerwear/footwear/accessory) | `bottom` |
| `score` | Điểm tương thích (từ Scoring Engine 100đ) | `92` |
| `reason` | Lý do phối — AI dùng để **chém gió** tự nhiên | `"Cân bằng tỉ lệ"` |
> **Cái hay:** Trường `reason` là vũ khí bí mật. AI không cần tự bịa lý do phối đồ. Nó đọc nguyên cái `reason` từ Database rồi diễn đạt lại bằng ngôn ngữ tự nhiên. **Zero effort, Zero hallucination.**
### Cột `similar_items` (Sản phẩm tương tự)
```json
{
"product_code": "POLO_01",
"similar_items": [
{
"code": "TSHIRT_05",
"name": "Áo Thun Cotton Basic",
"similarity_type": "same_category",
"price_diff": "-200k",
"key_diff": "Chất liệu Cotton thường thay vì Pima"
},
{
"code": "POLO_SPORT_09",
"name": "Áo Polo Thể Thao",
"similarity_type": "same_form",
"price_diff": "-150k",
"key_diff": "Form giống, vải Polyester thoáng mát hơn"
}
]
}
```
---
## 2.3. Tại sao dùng JSON thay vì Graph Database (Neo4j)?
| Tiêu chí | Neo4j (Graph DB) | **JSON Columns (Canifa)** |
|----------|------------------|--------------------------|
| **Tốc độ query** | ~10-50ms (Cypher query) | **<1ms** (JSON parse) |
| **Chi phí vận hành** | Thêm 1 server, license | **$0** (dùng luôn SQL hiện tại) |
| **Độ phức tạp** | Cần team DevOps riêng | **Copy-paste JSON** |
| **Tính linh hoạt** | Rất cao (arbitrary traversal) | Đủ dùng (1-2 hop) |
| **Scale** | Hàng triệu nodes | **~2000 SKU** (quá đủ) |
| **Maintenance** | Cần đồng bộ 2 DB | **1 nguồn duy nhất** |
> **Kết luận:** Với catalog ~2000 SKU của Canifa, dùng Neo4j như dùng súng đại bác bắn muỗi. JSON columns trong SQL cho tốc độ O(1), chi phí $0, và đội Merchandising có thể tự sửa bằng tay mà không cần developer.
---
## 2.4. Quy trình Pre-compute (Batch Job)
Graph không được tính toán real-time. Nó được **pre-compute** bằng Batch Job chạy định kỳ:
```mermaid
sequenceDiagram
participant Cron as ⏰ Batch Job<br/>(Chạy đêm)
participant Engine as 🧮 Scoring Engine<br/>(100đ Algorithm)
participant Rules as 📋 Merchandising Rules<br/>(59 sản phẩm)
participant DB as 🗃️ Database<br/>(Product Table)
participant AI as 🤖 AI Agent<br/>(Runtime)
Note over Cron,DB: === GIỜ TÍNH TOÁN (2:00 AM) ===
Cron->>Engine: Lấy toàn bộ catalog (~2000 SKU)
Engine->>Engine: Chấm điểm Color + Occasion + Role + Season
Engine->>Rules: Kiểm tra bảng luật 59 SP (Bonus +25đ)
Rules-->>Engine: Áo A + Quần B = Luật cứng ✅
Engine->>DB: Ghi JSON vào outfit_recommendations
Engine->>DB: Ghi JSON vào similar_items
Note over AI,DB: === GIỜ PHỤC VỤ (24/7) ===
AI->>DB: Khách hỏi Áo A → SELECT outfit_recommendations
DB-->>AI: JSON trả ngay (<1ms)
AI->>AI: Parse JSON → Chém gió tự nhiên
```
**Ưu điểm của Pre-compute:**
| Metric | Real-time Compute | **Pre-compute (Canifa)** |
|--------|-------------------|--------------------------|
| Latency per request | 2-5 giây | **<5ms** |
| CPU cost per request | Cao (chạy algorithm) | **~0** (đọc JSON) |
| Consistency | Khác nhau mỗi lần | **100% giống nhau** |
| Merchandising control | Không có | **Duyệt trước khi publish** |
---
## 2.5. Cơ chế cập nhật Graph
Graph không phải bất biến. Nó được cập nhật khi:
1. **Sản phẩm mới nhập kho** → Batch Job chạy lại → Tính toán phối đồ cho SP mới
2. **Đội Merchandising thêm luật** → Cập nhật bảng `chatbot_fashion_rules` → Batch Job tự động merge
3. **Hết hàng (Out of Stock)** → Runtime filter: AI kiểm tra stock trước khi gợi ý, nếu hết hàng → **skip và lấy item tiếp theo** trong danh sách
4. **Mùa thay đổi** → Cập nhật `season_tag` → Batch Job tự động re-score
> **Nguyên tắc vàng:** Graph chỉ thay đổi ở **tầng Batch** (đêm). Tầng Runtime (ban ngày) chỉ **đọc** — không bao giờ ghi. Điều này đảm bảo tính nhất quán tuyệt đối trong suốt 1 ngày phục vụ.
# State Machine: Cỗ máy trạng thái hội thoại
> **Tóm tắt:** Mỗi lượt chat của khách hàng không phải là một câu hỏi độc lập — nó là một **bước nhảy trên đồ thị trạng thái (State Machine)**. AI luôn biết mình đang đứng ở Trạm (State) nào, và từ Trạm đó chỉ có một số cửa (Transitions) hợp lệ để đi tiếp. Đây là lý do AI Canifa **không bao giờ bị "ngáo"** trong multi-turn conversation.
---
## 3.1. State Machine tổng quan
Hệ thống hội thoại của Canifa hoạt động như một **Finite State Machine (FSM)** với các trạng thái rõ ràng:
```mermaid
stateDiagram-v2
[*] --> IDLE: Khách mở chat
IDLE --> ANCHORED: Khách hỏi về 1 sản phẩm cụ thể
ANCHORED --> CROSS_SELL: "Phối gì cho hợp?"
ANCHORED --> DOWN_SELL: "Có cái nào rẻ hơn?"
ANCHORED --> INFO: "Áo này chất liệu gì?"
CROSS_SELL --> RE_ANCHOR: Khách chốt SP được gợi ý
DOWN_SELL --> RE_ANCHOR: Khách chốt SP thay thế
RE_ANCHOR --> CROSS_SELL: Tiếp tục phối đồ
RE_ANCHOR --> DOWN_SELL: Tìm SP rẻ hơn nữa
RE_ANCHOR --> EXPAND: "Tìm thêm kiểu này"
EXPAND --> RE_ANCHOR: Khách chốt SP mới
INFO --> ANCHORED: Quay lại SP gốc
note right of ANCHORED
Gốc hiện tại = SKU cụ thể
AI cầm 3 chìa khóa
end note
note right of RE_ANCHOR
ĐÂY LÀ "MỒI CÂU"
SP output → SP input mới
end note
```
---
## 3.2. Giải thích từng State
### State 1: `IDLE` — Chưa có ngữ cảnh
Khách vừa mở chat, chưa hỏi gì cụ thể. AI ở trạng thái chờ.
- **Ví dụ:** *"Chào em!"*, *"Em ơi tư vấn giúp chị"*
- **AI xử lý:** Chào lại, hỏi nhu cầu mua sắm
- **Chìa khóa khả dụng:** Không có (chưa có Gốc)
### State 2: `ANCHORED` — Đã neo vào 1 SKU cụ thể
Khách đã nhắc đến hoặc đang xem 1 sản phẩm cụ thể. AI biết rõ "Gốc" hiện tại là gì.
- **Ví dụ:** *"Áo POLO_01 này có size L không?"*, *"Cái áo này đẹp thế"*
- **AI xử lý:** Ghi nhận `current_anchor = POLO_01`
- **Chìa khóa khả dụng:** Cả 3 (Outfit, Similar, DNA)
### State 3: `CROSS_SELL` — Đang gợi đồ phối
Khách hỏi phối đồ. AI mở chìa khóa `outfit_recommendations`.
- **Ví dụ:** *"Áo này mặc với quần gì?"*
- **AI xử lý:** Đọc JSON → Trả Quần B, Giày C
- **Transition tiếp:** Khách chốt Quần B → Chuyển sang `RE_ANCHOR` (Quần B thành Gốc mới)
### State 4: `DOWN_SELL` — Đang tìm đồ thay thế
Khách muốn tìm đồ tương tự nhưng giá rẻ hơn hoặc khác màu.
- **Ví dụ:** *"Có cái nào rẻ hơn không?"*, *"Có màu khác không?"*
- **AI xử lý:** Đọc JSON `similar_items` → Trả Áo A1, A2
- **Transition tiếp:** Khách chốt Áo A1 → `RE_ANCHOR` (Áo A1 thành Gốc mới)
### State 5: `RE_ANCHOR` — 🔥 CÁI ĂN TIỀN (Pivoting)
**Đây chính là trạng thái "Mồi Câu Liên Hoàn".** Sản phẩm đầu ra (output) của lượt trước trở thành sản phẩm đầu vào (input/Gốc) của lượt sau.
```
Lượt 1: Gốc = Áo A → Output = Quần B
Lượt 2: Gốc = Quần B → Output = Giày C ← PIVOT!
Lượt 3: Gốc = Giày C → Output = Túi D ← PIVOT!
...vô tận...
```
### State 6: `EXPAND` — Tìm kiếm mở rộng (DNA Inheritance)
Khách muốn xem thêm nhiều sản phẩm cùng kiểu. AI sử dụng **DNA** (metadata) của sản phẩm Gốc để query mở rộng.
- **Ví dụ:** *"Tìm cho chị thêm mấy cái quần ống rộng đi làm"*
- **AI xử lý:** Copy DNA của Quần B `[Form: Ống rộng] + [Dịp: Đi làm]` → Query bảng Product Dimension
- **(Xem chi tiết ở Chương 4: DNA Inheritance)**
---
## 3.3. Transition Rules (Luật chuyển trạng thái)
| Từ State | Sang State | Trigger (Ý định khách) | AI Action |
|----------|-----------|----------------------|-----------|
| IDLE | ANCHORED | Nhắc đến SKU / Xem SP | Ghi nhận `current_anchor` |
| ANCHORED | CROSS_SELL | "Phối gì?" / "Mặc với gì?" | Đọc `outfit_recommendations` |
| ANCHORED | DOWN_SELL | "Có rẻ hơn?" / "Có màu khác?" | Đọc `similar_items` |
| ANCHORED | INFO | "Chất liệu?" / "Size?" | Đọc product metadata |
| CROSS_SELL | RE_ANCHOR | Khách chọn 1 SP trong danh sách | `current_anchor = SP mới` |
| DOWN_SELL | RE_ANCHOR | Khách chọn 1 SP thay thế | `current_anchor = SP mới` |
| RE_ANCHOR | CROSS_SELL | Tiếp tục phối | Đọc `outfit` của Gốc mới |
| RE_ANCHOR | DOWN_SELL | Tìm thay thế tiếp | Đọc `similar` của Gốc mới |
| RE_ANCHOR | EXPAND | "Tìm thêm kiểu này" | Dùng DNA để query |
| Bất kỳ | IDLE | Khách nói chuyện khác | Reset `current_anchor = null` |
---
## 3.4. Tại sao State Machine chứ không phải ReAct Agent thuần?
Trên Reddit (r/LangChain, r/LocalLLaMA), cộng đồng đang chuyển dần từ **ReAct Agent** (để AI tự quyết dùng tool nào) sang **State Machine** (ép AI đi theo đường ray).
| Tiêu chí | ReAct Agent | **State Machine (Canifa)** |
|----------|------------|---------------------------|
| **Quyết định** | AI tự chọn tool | AI chỉ được chọn tool trong danh sách hợp lệ của State hiện tại |
| **Infinite Loop** | Hay bị (AI gọi tool lặp đi lặp lại) | **Không thể** (mỗi State có tập transition cố định) |
| **Sai tool** | Hay xảy ra (AI dùng tool tìm store khi khách hỏi phối đồ) | **Không thể** (State `CROSS_SELL` chỉ cho phép tool `outfit`) |
| **Debug** | Rất khó (AI nghĩ gì không biết) | **Rất dễ** (log State transition) |
| **Latency** | Cao (AI cần "suy nghĩ" chọn tool) | **Thấp** (State đã define sẵn tool) |
> **Insight:** State Machine không phải là "giới hạn" AI. Nó là **đường ray** giúp AI chạy nhanh hơn và an toàn hơn. Giống như tàu cao tốc: chạy nhanh hơn xe hơi CHÍNH VÌ nó đi trên ray, không phải tự tìm đường.
---
## 3.5. Memory tối giản: Chỉ cần nhớ 1 biến
Cái đẹp nhất của kiến trúc này: **AI không cần nhớ cả đoạn hội thoại dài**. Nó chỉ cần nhớ đúng **1 biến**:
```python
conversation_state = {
"current_anchor": "POLO_01", # SKU đang focus
"state": "CROSS_SELL", # Trạng thái hiện tại
"history": ["TSHIRT_05", "POLO_01"] # Các trạm đã đi qua (optional, for backtrack)
}
```
Tổng cộng: **~100 bytes**. So với việc nhét cả lịch sử chat (có thể lên đến hàng nghìn tokens) vào context window → **tiết kiệm token, giảm chi phí LLM, tăng tốc độ phản hồi.**
# DNA Inheritance: Kế thừa đặc tính sản phẩm
> **Tóm tắt:** Khi khách hàng nói *"Tìm cho chị thêm mấy cái giống quần B đi"*, AI không tự bịa ra quần B trông như thế nào. Nó **sao chép nguyên bộ Gen (DNA/Metadata)** của Quần B, chỉ tạo ra **1 đột biến (Mutation)** ở đúng điều kiện khách yêu cầu, rồi xách bộ Gen đó đi tìm trong kho hàng. Đây là cơ chế tinh vi nhất của hệ thống.
---
## 4.1. DNA là gì?
Mỗi sản phẩm trong Database mang trong mình một chuỗi **DNA (Metadata)** — tập hợp các đặc tính mô tả sản phẩm đó:
```mermaid
graph TD
SKU["🧬 Quần Jean B<br/>Mã: JEAN_02"]
DNA1["📐 Form: Ống rộng"]
DNA2["🧵 Chất liệu: Denim wash"]
DNA3["💼 Dịp: Đi làm, Đi chơi"]
DNA4["💰 Giá: 499,000đ"]
DNA5["🎨 Màu: Xanh đậm"]
DNA6["🧑 Giới: Nữ"]
DNA7["📅 Mùa: Thu-Đông"]
DNA8["🏷️ Category: Quần Jeans"]
SKU --> DNA1
SKU --> DNA2
SKU --> DNA3
SKU --> DNA4
SKU --> DNA5
SKU --> DNA6
SKU --> DNA7
SKU --> DNA8
style SKU fill:#f59e0b,stroke:#d97706,color:#000
style DNA1 fill:#e0f2fe,stroke:#0284c7,color:#000
style DNA2 fill:#e0f2fe,stroke:#0284c7,color:#000
style DNA3 fill:#e0f2fe,stroke:#0284c7,color:#000
style DNA4 fill:#fef3c7,stroke:#d97706,color:#000
style DNA5 fill:#e0f2fe,stroke:#0284c7,color:#000
style DNA6 fill:#e0f2fe,stroke:#0284c7,color:#000
style DNA7 fill:#e0f2fe,stroke:#0284c7,color:#000
style DNA8 fill:#e0f2fe,stroke:#0284c7,color:#000
```
---
## 4.2. Cơ chế "Sao chép + Đột biến" (Copy + Mutate)
Khi khách yêu cầu *"Tìm cái giống vậy nhưng rẻ hơn"*, AI thực hiện **3 bước chính xác**:
### Bước 1: Copy DNA (Sao chép nguyên bản)
AI đọc toàn bộ metadata của sản phẩm Gốc:
```python
# Gốc: Quần Jean B
dna = {
"category": "Quần Jeans",
"form": "Ống rộng",
"material": "Denim wash",
"occasion": ["Đi làm", "Đi chơi"],
"price": 499000,
"color_group": "Xanh đậm",
"gender": "Nữ",
"season": "Thu-Đông"
}
```
### Bước 2: Mutate (Tạo đột biến)
AI chỉ thay đổi **đúng 1 gene** mà khách yêu cầu:
```python
# Khách: "Tìm rẻ hơn" → Chỉ đột biến gene "price"
mutation = {
"price": {"operator": "<", "value": 499000} # Rẻ hơn Quần B
}
# Tất cả gene khác: GIỮ NGUYÊN
```
### Bước 3: Query (Xách DNA đi tìm)
```python
# AI tạo query filter từ DNA + Mutation
query = {
"category": "Quần Jeans", # Giữ nguyên
"form": "Ống rộng", # Giữ nguyên
"occasion": "Đi làm", # Giữ nguyên
"gender": "Nữ", # Giữ nguyên
"price": {"$lt": 499000} # ← ĐỘT BIẾN DUY NHẤT
}
results = database.search(query)
# → Trả về: Quần C (399k), Quần D (349k)
```
---
## 4.3. Flow diagram: Toàn cảnh DNA Inheritance
```mermaid
sequenceDiagram
participant User as 👤 Khách
participant AI as 🤖 AI Agent
participant DB as 🗃️ Database
User->>AI: "Quần B đẹp đấy, nhưng tìm rẻ hơn đi em"
Note over AI: 🧠 Tư duy nội bộ
AI->>AI: 1. Xác định Gốc = JEAN_02 (Quần B)
AI->>DB: 2. SELECT metadata FROM products WHERE code = 'JEAN_02'
DB-->>AI: DNA = {form: "ống rộng", occasion: "đi làm", price: 499k, ...}
AI->>AI: 3. Copy DNA nguyên bản
AI->>AI: 4. Mutate: price < 499k (theo yêu cầu khách)
AI->>DB: 5. SELECT * FROM products WHERE form='ống rộng' AND occasion LIKE '%đi làm%' AND price < 499000
DB-->>AI: Quần C (399k), Quần D (349k), Quần E (299k)
AI->>User: "Dạ chị ơi, em tìm được 3 mẫu quần ống rộng<br/>đi làm y chang Quần B, giá mềm hơn:<br/>- Quần C: 399k (Denim nhẹ)<br/>- Quần D: 349k (Cotton blend)<br/>- Quần E: 299k (Vải lanh)"
Note over User,AI: 💡 AI không tự bịa "ống rộng" hay "đi làm"<br/>Nó KẾ THỪA từ DNA của Quần B!
```
---
## 4.4. Các kiểu Đột biến phổ biến
| Khách nói | Gene bị đột biến | Các gene giữ nguyên |
|-----------|------------------|---------------------|
| *"Rẻ hơn đi"* | `price < anchor.price` | form, category, occasion, gender, season |
| *"Có màu khác không?"* | `color_group != anchor.color` | form, category, price_range, gender |
| *"Cái nào mặc đi chơi?"* | `occasion = "đi chơi"` | form, category, color, gender, price_range |
| *"Size cho bé gái"* | `gender = "bé gái"` | category, form, season |
| *"Có hàng mùa hè không?"* | `season = "Xuân-Hè"` | category, form, gender |
| *"Form ôm hơn?"* | `form = "slim-fit"` | category, color, price_range, gender |
---
## 4.5. Tại sao DNA Inheritance vượt trội so với cách làm thông thường?
### Cách thông thường: LLM tự tóm tắt
```
Khách: "Tìm quần giống B nhưng rẻ hơn"
LLM (tự nghĩ): "Hmm, quần B là... quần jean... ống rộng... à mà hình như nó
dáng slim-fit? Hay là regular? Thôi cứ tìm quần jean rẻ hơn."
→ Kết quả: Trả về quần jean RANDOM, có thể ống côn, có thể skinny
→ KHÔNG GIỐNG Quần B chút nào
```
### Cách Canifa: Kế thừa DNA
```
Khách: "Tìm quần giống B nhưng rẻ hơn"
AI: "Quần B có DNA: [Jeans, Ống rộng, Đi làm, Nữ, 499k, Xanh đậm]"
"Copy toàn bộ. Chỉ đổi: price < 499k"
→ Kết quả: Quần Jean ống rộng, đi làm, Nữ, giá rẻ hơn
→ CHÍNH XÁC như Quần B, chỉ khác giá
```
| Tiêu chí | LLM tự tóm | **DNA Inheritance** |
|----------|-----------|---------------------|
| Độ chính xác form dáng | ~50% (hay nhớ sai) | **100%** (copy từ DB) |
| Giữ đúng occasion | ~60% (hay bỏ sót) | **100%** (giữ nguyên gene) |
| Tốc độ | Chậm (LLM phải "nghĩ") | **Nhanh** (copy + query) |
| Token cost | Cao (tóm tắt context) | **Thấp** (chỉ truyền SKU) |
---
## 4.6. Combo chí mạng: DNA + Outfit + Similar
Cả 3 cơ chế kết hợp tạo thành một **vòng lặp bất tận (Infinite Loop)** mà khách hàng không bao giờ cảm thấy cụt đường:
```mermaid
graph TD
START["🏁 Khách xem Áo A"]
Q1{"Khách hỏi gì?"}
OUTFIT["🔑 Mở outfit_recommendations<br/>→ Quần B"]
SIMILAR["🔑 Mở similar_items<br/>→ Áo A' (rẻ hơn)"]
Q2{"Khách tiếp tục?"}
PIVOT_B["🔄 PIVOT: Quần B → Gốc mới"]
PIVOT_A["🔄 PIVOT: Áo A' → Gốc mới"]
DNA_MUT["🧬 DNA Mutation<br/>'Quần giống B, rẻ hơn'<br/>→ Quần C, D"]
Q3{"Khách chốt?"}
PIVOT_C["🔄 PIVOT: Quần C → Gốc mới"]
CART["🛒 Thêm vào giỏ hàng"]
START --> Q1
Q1 -->|"Phối gì?"| OUTFIT
Q1 -->|"Rẻ hơn?"| SIMILAR
OUTFIT --> Q2
SIMILAR --> Q2
Q2 -->|"Phối tiếp"| PIVOT_B
Q2 -->|"Giống vậy rẻ hơn"| DNA_MUT
Q2 -->|"Xem Áo khác"| PIVOT_A
DNA_MUT --> Q3
PIVOT_B --> Q1
PIVOT_A --> Q1
Q3 -->|"Phối tiếp"| PIVOT_C
Q3 -->|"Mua luôn"| CART
PIVOT_C --> Q1
style START fill:#10b981,stroke:#059669,color:#fff
style CART fill:#ef4444,stroke:#dc2626,color:#fff
style DNA_MUT fill:#8b5cf6,stroke:#7c3aed,color:#fff
style PIVOT_B fill:#f59e0b,stroke:#d97706,color:#000
style PIVOT_A fill:#f59e0b,stroke:#d97706,color:#000
style PIVOT_C fill:#f59e0b,stroke:#d97706,color:#000
```
> **Insight:** Vòng lặp này có thể chạy **vô tận** (Áo → Quần → Giày → Túi → Khăn → ...). Mỗi bước nhảy, AI chỉ cần biết **1 mã SKU** là xong. Không cần nhớ cả cuộc trò chuyện. Đây chính là bí quyết để AI Canifa tư vấn mượt mà như chuyên gia thời trang thực thụ — dù thực tế nó chỉ là một "kẻ tra cứu JSON siêu nhanh".
# Kịch bản thực chiến: 3 Use Cases chi tiết
> **Tóm tắt:** 3 kịch bản mô phỏng đoạn chat thực tế, cho thấy cách AI sử dụng cả 3 cơ chế (Outfit Graph → DNA Inheritance → Pivoting) trong một cuộc trò chuyện liên tục. Mỗi kịch bản bóc tách cả **những gì khách thấy** lẫn **những gì xảy ra dưới gầm xe (Under the Hood)**.
---
## 5.1. Kịch bản 1: "Lên đồ đi Phú Quốc" (Cross-sell Liên Hoàn)
**Bối cảnh:** Chị Hà (30 tuổi) đang xem **Áo Phông Oversize Mùa Hè (3TS26S018-SR079)** trên app Canifa.
---
### 💬 Lượt 1 — Kích hoạt Outfit Graph
| Khách nói | AI dưới gầm xe |
|-----------|----------------|
| *"Áo này mặc đi Phú Quốc thì phối quần gì hả em?"* | `State: IDLE → ANCHORED` |
| | `current_anchor = 3TS26S018-SR079` |
| | `→ Đọc outfit_recommendations` |
| | `→ Tìm role = "bottom"` |
**Database trả về:**
```json
{
"outfit_recommendations": [
{"code": "1BP24C002", "name": "Quần Short Linen", "role": "bottom", "score": 94, "reason": "Vải linen nhẹ, phù hợp đi biển"},
{"code": "1QJ25S003", "name": "Quần Jeans Croptop", "role": "bottom", "score": 78, "reason": "Casual phù hợp resort"}
]
}
```
**🤖 AI trả lời:**
> *"Dạ đi Phú Quốc thì chị mix ngay với cái **Quần Short Linen (1BP24C002)** này ạ! Vải linen mát lạnh, nhẹ tênh, lên hình bao sống ảo ạ. Hoặc nếu chị thích kiểu năng động hơn thì có **Quần Jeans Croptop** cũng rất hợp phong cách resort luôn!"*
---
### 💬 Lượt 2 — Pivoting (Chuyển Gốc)
| Khách nói | AI dưới gầm xe |
|-----------|----------------|
| *"Ok chốt cái quần Short Linen đó. Thế mặc quần đó thì xách túi gì cho hợp?"* | `State: CROSS_SELL → RE_ANCHOR` |
| | `current_anchor = 1BP24C002` ← **PIVOT!** |
| | `→ Đọc outfit_recommendations CỦA QUẦN` |
| | `→ Tìm role = "accessory"` |
**Database trả về (từ Quần Short, không phải Áo!):**
```json
{
"outfit_recommendations": [
{"code": "TUI_COI_03", "name": "Túi Cói Vintage", "role": "accessory", "score": 91},
{"code": "MU_RONG_07", "name": "Mũ Rộng Vành Cói", "role": "accessory", "score": 85}
]
}
```
**🤖 AI trả lời:**
> *"Đã diện Quần Short Linen thì chị xách cái **Túi Cói Vintage** nữa là chuẩn bài biển chill! Rộng đựng được kem chống nắng lẫn phone. À, chị thêm cái **Mũ Rộng Vành Cói** nữa là set đồ Phú Quốc hoàn hảo rồi ạ! 🏖️"*
---
### 💬 Lượt 3 — DNA Inheritance (Đột biến Gen)
| Khách nói | AI dưới gầm xe |
|-----------|----------------|
| *"Cái túi cói 299k hơi đắt. Có cái nào rẻ hơn mà cùng style không em?"* | `State: RE_ANCHOR → EXPAND (DNA)` |
| | `Gốc = TUI_COI_03` |
| | `Copy DNA: {category: Túi, style: Cói/Vintage, dịp: Đi biển}` |
| | `Mutate: price < 299000` |
| | `→ Query Product Dimension` |
**🤖 AI trả lời:**
> *"Dạ em tìm được 2 mẫu túi cói style y chang ạ: **Túi Cói Mini (179k)** — nhỏ gọn xinh xắn hơn, và **Túi Vải Canvas Vintage (199k)** — vải canvas bền hơn cói. Cùng phong cách đi biển, rẻ hơn trăm nghìn luôn chị!"*
> **Phân tích:** Trong 3 lượt chat, AI đã nhảy qua 3 trạm (Áo → Quần → Túi), sử dụng cả 3 cơ chế (Outfit → Pivot → DNA). Khách không hề cảm thấy cuộc trò chuyện bị cụt hoặc AI trả lời máy móc.
---
## 5.2. Kịch bản 2: "Chị muốn rẻ hơn" (Down-sell + DNA Cascade)
**Bối cảnh:** Chị Mai đang xem **Áo Polo Pima Cao Cấp (POLO_VIP_01, giá 599k)**.
---
### 💬 Lượt 1 — Down-sell
| Khách nói | AI dưới gầm xe |
|-----------|----------------|
| *"Áo này form đẹp quá, nhưng 599k hơi đau ví. Có cái nào giống mà rẻ hơn không?"* | `State: ANCHORED → DOWN_SELL` |
| | `Gốc = POLO_VIP_01` |
| | `→ Đọc similar_items` |
**Database trả về:**
```json
{
"similar_items": [
{"code": "POLO_BASIC_05", "name": "Polo Cotton Basic", "price_diff": "-200k", "key_diff": "Cotton thường thay Pima"},
{"code": "POLO_SPORT_09", "name": "Polo Thể Thao Polyester", "price_diff": "-150k", "key_diff": "Vải poly thoáng mát"}
]
}
```
**🤖 AI trả lời:**
> *"Dạ em hiểu ý chị! Form Slim-fit của mẫu Pima tôn dáng lắm ạ. Chị nghía thử: **Polo Cotton Basic (399k)** — form y chang, chất cotton thường nhẹ hơn. Hoặc **Polo Thể Thao (449k)** — vải poly siêu thoáng, hợp ngày nóng!"*
---
### 💬 Lượt 2 — Re-anchor + Cross-sell
| Khách nói | AI dưới gầm xe |
|-----------|----------------|
| *"Ok lấy cái Polo Cotton Basic 399k đi. Phối với quần gì cho đi làm?"* | `State: DOWN_SELL → RE_ANCHOR → CROSS_SELL` |
| | `current_anchor = POLO_BASIC_05` ← **PIVOT!** |
| | `→ Đọc outfit_recommendations CỦA POLO BASIC` |
**🤖 AI trả lời:**
> *"Dạ Polo Basic này đi làm thì chị phối với **Quần Âu Slim** hoặc **Quần Chinos Kaki** là chuẩn smart-casual ạ! Tiết kiệm được 200k mà lên đồ vẫn lịch sự y chang version Pima!"*
---
### 💬 Lượt 3 — DNA Mutation sâu
| Khách nói | AI dưới gầm xe |
|-----------|----------------|
| *"Quần Chinos Kaki thì có mẫu nào ống rộng hơn xíu không? Chị thích dáng thoải mái"* | `State: RE_ANCHOR → EXPAND (DNA)` |
| | `Gốc = Quần Chinos Kaki` |
| | `Copy DNA: {category: Chinos, color: Kaki, occasion: Đi làm}` |
| | `Mutate: form = "regular-fit" hoặc "wide-leg"` |
**🤖 AI trả lời:**
> *"Dạ chị thích thoải mái thì chuyển sang **Chinos Regular-fit** hoặc **Chinos Wide-leg** ạ. Em tìm được 2 mẫu: cùng màu kaki, cùng mặc đi làm, nhưng dáng rộng thoáng hơn. Phối với Polo Basic 399k vẫn chuẩn style!"*
---
## 5.3. Kịch bản 3: "Mua đồ cho bé" (Hard Filter + Role Priority)
**Bối cảnh:** Anh Tuấn mua **Áo Phông Bé Trai (KID_TEE_01, size 120-130)**.
---
### 💬 Lượt 1 — Hard Filter hoạt động
| Khách nói | AI dưới gầm xe |
|-----------|----------------|
| *"Áo này mặc với quần gì cho bé đi học?"* | `State: ANCHORED → CROSS_SELL` |
| | `Gốc = KID_TEE_01 (age_group: kids_boy)` |
| | `Hard Filter: CHỈ lấy đồ kids_boy` |
| | `→ Loại toàn bộ đồ men, women, kids_girl` |
**Database trả về (đã lọc Hard Filter):**
```json
{
"outfit_recommendations": [
{"code": "KID_SHORT_03", "name": "Quần Short Thể Thao Bé Trai", "role": "bottom", "score": 95},
{"code": "KID_JEAN_07", "name": "Quần Jean Slim Bé Trai", "role": "bottom", "score": 88}
]
}
```
> **QUAN TRỌNG:** Nếu không có Hard Filter, hệ thống có thể gợi ý "Quần Jean Nam" (cùng màu, cùng category, score cao) cho một đứa bé → **Thảm họa UX**. Hard Filter ngăn chặn 100% rủi ro này.
---
### 💬 Lượt 2 — Pivot trong hệ sinh thái trẻ em
| Khách nói | AI dưới gầm xe |
|-----------|----------------|
| *"Ok lấy Quần Short Thể Thao. Có giày nào hợp cho bé đi học không?"* | `State: RE_ANCHOR` |
| | `current_anchor = KID_SHORT_03` |
| | `→ Đọc outfit CỦA QUẦN (vẫn trong hệ kids_boy)` |
**🤖 AI trả lời:**
> *"Dạ bé diện Quần Short Thể Thao thì bố mẹ cho bé xỏ **Giày Sneaker Nhẹ** ạ! Đế mềm êm chân, bé chạy nhảy cả ngày vẫn ok!"*
> **Phân tích:** Suốt cuộc trò chuyện, AI luôn ở trong "vũ trụ trẻ em" (kids_boy). Hard Filter đảm bảo không bao giờ rò rỉ sản phẩm người lớn vào gợi ý cho bé.
---
## 5.4. Bảng tổng kết 3 kịch bản
| Kịch bản | Cơ chế sử dụng | Số lần Pivot | Cơ chế bảo vệ |
|----------|----------------|-------------|---------------|
| **Đi Phú Quốc** | Outfit → Pivot → DNA | 2 | Season filter |
| **Chị muốn rẻ hơn** | Similar → Pivot → Outfit → DNA | 2 | Price constraint |
| **Mua đồ cho bé** | Hard Filter → Outfit → Pivot | 1 | Age-group filter |
# So sánh với cộng đồng quốc tế (Reddit/Industry)
> **Tóm tắt:** Kiến trúc "Entity-Centric Conversational Routing" của Canifa không phải là sáng tạo cá nhân — nó là hội tụ của các best practices mà cộng đồng AI toàn cầu đang tranh luận nảy lửa trên Reddit (r/LangChain, r/LocalLLaMA, r/MachineLearning). Tài liệu này so sánh cách tiếp cận của Canifa với 4 trường phái phổ biến nhất, và chỉ ra tại sao giải pháp của ta lại là sự kết hợp tinh hoa nhất.
---
## 6.1. Bản đồ 4 trường phái trên thế giới
```mermaid
quadrantChart
title "4 Trường phái AI E-commerce"
x-axis "Tốc độ thấp" --> "Tốc độ cao"
y-axis "Kiểm soát thấp" --> "Kiểm soát cao"
quadrant-1 "🎯 Sweet Spot"
quadrant-2 "Chậm nhưng an toàn"
quadrant-3 "Nhanh nhưng nguy hiểm"
quadrant-4 "Tốt nhưng đắt"
"Pure LLM": [0.2, 0.15]
"RAG (Vector Search)": [0.45, 0.4]
"Knowledge Graph (Neo4j)": [0.5, 0.85]
"CANIFA (Graph Router)": [0.9, 0.92]
```
---
## 6.2. Trường phái 1: Pure LLM (Chết ngay từ vòng gửi xe)
**Mô tả:** Nhồi kiến thức thời trang vào Prompt, để LLM tự gợi ý.
**Ý kiến Reddit (r/MachineLearning):**
> *"Don't use raw LLM for product recommendations. It WILL hallucinate products that don't exist in your inventory."*
| Ưu điểm | Nhược điểm |
|---------|-----------|
| Setup nhanh (30 phút) | Hallucination ~40% |
| Không cần database | Kết quả không reproducible |
| Conversational tự nhiên | Không kiểm soát được chất lượng gợi ý |
**So với Canifa:**
Canifa giữ khả năng đối thoại tự nhiên của LLM nhưng **khóa chặt output** bằng JSON Database. LLM chỉ được "nói" những gì Database cho phép.
---
## 6.3. Trường phái 2: RAG thuần (Vector Search)
**Mô tả:** Embed toàn bộ catalog vào Vector DB (Pinecone, Weaviate), dùng semantic search để tìm sản phẩm.
**Ý kiến Reddit (r/LangChain):**
> *"Semantic search is great for finding SIMILAR products, but terrible for finding COMPLEMENTARY products. 'Shirt that goes with blue jeans' returns... more jeans."*
| Ưu điểm | Nhược điểm |
|---------|-----------|
| Tìm đồ tương tự tốt | Không biết phối đồ (chỉ tìm "giống") |
| Scale tốt | Negation problem ("không phải màu đỏ" → trả màu đỏ) |
| Setup vừa phải | Multi-turn yếu (mỗi turn search lại từ đầu) |
**So với Canifa:**
Canifa giải quyết bài toán "phối đồ" bằng `outfit_recommendations` (cross-category), bài toán "tìm tương tự" bằng `similar_items` (same-category). RAG thuần chỉ giải được bài toán thứ hai.
---
## 6.4. Trường phái 3: Knowledge Graph (Neo4j, Amazon, Pinterest)
**Mô tả:** Dùng Graph Database (Neo4j) để mô hình hóa quan hệ giữa sản phẩm: `[HỢP_VỚI]`, `[TƯƠNG_TỰ]`, `[MUA_CÙNG]`.
**Ý kiến Reddit (r/datascience):**
> *"Knowledge Graphs are the gold standard for product recommendations. Amazon and Pinterest use them heavily. But the engineering cost is brutal for small teams."*
| Ưu điểm | Nhược điểm |
|---------|-----------|
| Mô hình quan hệ phức tạp | Chi phí vận hành cao (thêm server) |
| Traversal linh hoạt (N-hop) | Cần team DevOps riêng |
| Industry standard (Amazon, Pinterest) | Đồng bộ dữ liệu giữa SQL ↔ Neo4j phức tạp |
**So với Canifa:**
Canifa mô phỏng Knowledge Graph bằng JSON columns — **đạt 90% chức năng của Neo4j** với **0% chi phí vận hành thêm**. Lý do: catalog Canifa (~2000 SKU) không cần arbitrary N-hop traversal. 1-2 hop (Áo → Quần → Giày) là đủ cho mọi kịch bản.
---
## 6.5. Trường phái 4: State Machine (LangGraph, Canifa)
**Mô tả:** Thay vì để LLM tự chọn action (ReAct), ép LLM đi theo trạng thái (State) cố định.
**Ý kiến Reddit (r/LangChain):**
> *"After 6 months of fighting ReAct infinite loops, we switched to LangGraph state machine. Zero loops, 10x more predictable, easier to debug. Never going back."*
| Tiêu chí | ReAct Agent | **State Machine** |
|----------|------------|-------------------|
| Infinite Loop | Phổ biến | **Không thể xảy ra** |
| Sai tool | ~15% requests | **0%** (State quy định tool) |
| Debug time | Hàng giờ | **Vài phút** (log State transitions) |
| Latency | 3-5 giây (suy nghĩ) | **<1 giây** (đường ray sẵn) |
---
## 6.6. Canifa = Best of All Worlds
```mermaid
mindmap
root((CANIFA<br/>Graph Router))
**Từ Pure LLM**
Đối thoại tự nhiên
Hiểu ngữ cảnh đa dạng
**Từ RAG**
Metadata filtering
Tìm sản phẩm tương tự
**Từ Knowledge Graph**
Quan hệ phối đồ
Traversal đồ thị
Cross-category linking
**Từ State Machine**
Deterministic flow
Zero infinite loops
Predictable behavior
```
| Thành phần | Nguồn gốc | Cách Canifa áp dụng |
|-----------|----------|---------------------|
| Đối thoại tự nhiên | Pure LLM | LLM xử lý ngôn ngữ, Database xử lý logic |
| Metadata filtering | RAG | DNA Inheritance — copy metadata + mutate |
| Quan hệ cross-category | Knowledge Graph | `outfit_recommendations` JSON column |
| Quan hệ same-category | Knowledge Graph | `similar_items` JSON column |
| Deterministic routing | State Machine | State transitions cố định (6 states) |
| Pre-computed data | Industry standard | Batch Job chạy đêm, JSON lookup O(1) |
---
## 6.7. Thuật ngữ chuẩn quốc tế
Để trình bày với đối tác quốc tế hoặc trong tài liệu kỹ thuật, kiến trúc của Canifa có thể được gọi bằng thuật ngữ chuẩn:
| Thuật ngữ | Giải thích |
|----------|-----------|
| **Entity-Centric Conversational Routing** | Điều hướng hội thoại xoay quanh thực thể (SKU) |
| **Pre-computed Product Graph** | Đồ thị sản phẩm tính toán sẵn |
| **Anchor-based Pivoting** | Chuyển Gốc (Neo → Gốc mới) |
| **Zero-Hallucination Architecture** | Kiến trúc không ảo giác |
| **Hybrid Intent Router** | Bộ phân luồng ý định kết hợp |
| **DNA Inheritance Pattern** | Mẫu thiết kế kế thừa metadata |
| **Deterministic State Machine** | Máy trạng thái tất định |
> **Lời kết:** Khi so sánh với cộng đồng quốc tế, kiến trúc của Canifa không phải là "phát minh lại bánh xe". Nó là sự **kết hợp tinh hoa** của 4 trường phái, được tối ưu cho quy mô catalog ~2000 SKU và đội ngũ vận hành nhỏ gọn. Đây chính là lợi thế cạnh tranh: đạt chất lượng của Amazon/Pinterest nhưng chi phí vận hành gần như bằng 0.
# Implementation Blueprint: Agent Tools & Code
> **Tóm tắt:** Chương này chuyển từ lý thuyết sang thực hành. Mô tả chi tiết cách implement 3 Agent Tools trong LangGraph/LangChain, cấu trúc conversation state, và pseudo-code cho từng cơ chế. Đây là bản thiết kế để developer có thể bắt tay code ngay.
---
## 7.1. Kiến trúc Agent tổng thể
```mermaid
graph TD
USER["👤 Khách hàng"]
LLM["🧠 LLM (Gemini Flash)"]
subgraph "🔧 Tool Registry"
T1["Tool 1: get_outfit<br/>Lấy đồ phối"]
T2["Tool 2: get_similar<br/>Lấy đồ thay thế"]
T3["Tool 3: search_expanded<br/>Tìm mở rộng (DNA)"]
end
subgraph "🗃️ Database Layer"
COL1["outfit_recommendations<br/>(JSON column)"]
COL2["similar_items<br/>(JSON column)"]
COL3["Product Dimension<br/>(Full table)"]
end
USER -->|"Chat"| LLM
LLM -->|"State = CROSS_SELL"| T1
LLM -->|"State = DOWN_SELL"| T2
LLM -->|"State = EXPAND"| T3
T1 --> COL1
T2 --> COL2
T3 --> COL3
COL1 -->|"JSON O(1)"| T1
COL2 -->|"JSON O(1)"| T2
COL3 -->|"SQL Query"| T3
style LLM fill:#f59e0b,stroke:#d97706,color:#000
style T1 fill:#3b82f6,stroke:#2563eb,color:#fff
style T2 fill:#10b981,stroke:#059669,color:#fff
style T3 fill:#8b5cf6,stroke:#7c3aed,color:#fff
```
---
## 7.2. Tool 1: `get_outfit_recommendations`
**Mục đích:** Khi khách hỏi "phối gì?", lấy danh sách sản phẩm phối đồ từ JSON pre-computed.
```python
# Tool definition (LangChain/LangGraph style)
@tool
def get_outfit_recommendations(product_code: str, role_filter: str = None) -> dict:
"""
Lấy danh sách sản phẩm phối đồ cho một SKU cụ thể.
Args:
product_code: Mã SKU sản phẩm gốc (ví dụ: "3TS26S018-SR079")
role_filter: Lọc theo vai trò (top/bottom/outerwear/footwear/accessory)
Returns:
Dict chứa danh sách outfit recommendations
"""
# 1. Query trực tiếp từ JSON column — O(1) lookup
row = db.execute(
"SELECT outfit_recommendations FROM products WHERE product_code = ?",
[product_code]
)
if not row or not row.outfit_recommendations:
return {"status": "no_outfit", "message": "Chưa có dữ liệu phối đồ"}
recommendations = json.loads(row.outfit_recommendations)
# 2. Filter theo role nếu có
if role_filter:
recommendations = [r for r in recommendations if r["role"] == role_filter]
# 3. Filter sản phẩm hết hàng (runtime check)
recommendations = [r for r in recommendations if check_stock(r["code"])]
return {
"status": "success",
"anchor": product_code,
"recommendations": recommendations[:5] # Top 5
}
```
**Đặc điểm:**
- **Latency:** <5ms (JSON parse, không JOIN)
- **Accuracy:** 100% (data do Merchandising duyệt)
- **Stock aware:** Filter hết hàng ở runtime
---
## 7.3. Tool 2: `get_similar_items`
**Mục đích:** Khi khách muốn tìm đồ thay thế (rẻ hơn, khác màu, khác chất liệu).
```python
@tool
def get_similar_items(product_code: str, preference: str = None) -> dict:
"""
Lấy danh sách sản phẩm tương tự (thay thế).
Args:
product_code: Mã SKU sản phẩm gốc
preference: Ưu tiên tìm kiếm ("cheaper", "different_color", "different_material")
Returns:
Dict chứa danh sách similar items
"""
row = db.execute(
"SELECT similar_items FROM products WHERE product_code = ?",
[product_code]
)
if not row or not row.similar_items:
return {"status": "no_similar", "message": "Chưa có dữ liệu tương tự"}
items = json.loads(row.similar_items)
# Sort theo preference
if preference == "cheaper":
items.sort(key=lambda x: x.get("price_diff_numeric", 0))
# Filter hết hàng
items = [i for i in items if check_stock(i["code"])]
return {
"status": "success",
"anchor": product_code,
"similar_items": items[:5]
}
```
---
## 7.4. Tool 3: `search_expanded` (DNA Inheritance)
**Mục đích:** Khi khách muốn tìm thêm sản phẩm cùng kiểu nhưng với điều kiện mới (đột biến DNA).
```python
@tool
def search_expanded(
anchor_code: str,
mutations: dict = None
) -> dict:
"""
Tìm kiếm mở rộng dựa trên DNA của sản phẩm gốc.
Copy toàn bộ metadata, chỉ thay đổi fields trong mutations.
Args:
anchor_code: Mã SKU sản phẩm gốc (để copy DNA)
mutations: Dict các gene cần thay đổi
Ví dụ: {"price": {"op": "<", "value": 500000},
"form": "wide-leg"}
Returns:
Dict chứa danh sách sản phẩm tìm được
"""
# 1. Lấy DNA của sản phẩm gốc
anchor = db.execute(
"""SELECT category, form, material, occasion_tag,
gender_target, season, color_group, price
FROM products WHERE product_code = ?""",
[anchor_code]
)
if not anchor:
return {"status": "anchor_not_found"}
# 2. Copy DNA
dna = {
"category": anchor.category,
"form": anchor.form,
"occasion": anchor.occasion_tag,
"gender": anchor.gender_target,
"season": anchor.season,
}
# 3. Apply Mutations (chỉ thay đổi gene khách yêu cầu)
query_conditions = []
params = []
for key, value in dna.items():
if mutations and key in mutations:
# Gene bị đột biến → dùng giá trị mới
mut = mutations[key]
if isinstance(mut, dict) and "op" in mut:
query_conditions.append(f"{key} {mut['op']} ?")
params.append(mut["value"])
else:
query_conditions.append(f"{key} = ?")
params.append(mut)
elif value:
# Gene giữ nguyên → copy từ anchor
query_conditions.append(f"{key} = ?")
params.append(value)
# 4. Exclude anchor itself
query_conditions.append("product_code != ?")
params.append(anchor_code)
# 5. Execute query
where_clause = " AND ".join(query_conditions)
results = db.execute(
f"SELECT * FROM products WHERE {where_clause} LIMIT 10",
params
)
return {
"status": "success",
"anchor": anchor_code,
"dna_used": dna,
"mutations_applied": mutations or {},
"results": [format_product(r) for r in results]
}
```
---
## 7.5. Conversation State Management
```python
# Cấu trúc state tối giản — chỉ ~100 bytes
class ConversationState:
current_anchor: str = None # SKU đang focus
state: str = "IDLE" # IDLE/ANCHORED/CROSS_SELL/DOWN_SELL/EXPAND
anchor_history: list = [] # Trail of pivots (for backtrack)
def pivot(self, new_anchor: str):
"""Chuyển Gốc — cơ chế Mồi Câu Liên Hoàn"""
if self.current_anchor:
self.anchor_history.append(self.current_anchor)
self.current_anchor = new_anchor
self.state = "ANCHORED"
def get_available_tools(self) -> list:
"""Trả về danh sách tool hợp lệ cho State hiện tại"""
tool_map = {
"IDLE": [],
"ANCHORED": ["get_outfit", "get_similar", "search_expanded"],
"CROSS_SELL": ["get_outfit"],
"DOWN_SELL": ["get_similar"],
"EXPAND": ["search_expanded"],
}
return tool_map.get(self.state, [])
```
---
## 7.6. Sequence Diagram: Toàn bộ flow end-to-end
```mermaid
sequenceDiagram
participant U as 👤 User
participant LLM as 🧠 LLM
participant SM as 📋 State Machine
participant T1 as 🔑 get_outfit
participant T2 as 🔑 get_similar
participant T3 as 🧬 search_expanded
participant DB as 🗃️ Database
U->>LLM: "Áo A phối quần gì?"
LLM->>SM: classify_intent → CROSS_SELL
SM->>SM: state = ANCHORED, anchor = Áo_A
SM-->>LLM: available_tools = [get_outfit]
LLM->>T1: get_outfit(Áo_A, role="bottom")
T1->>DB: SELECT outfit_recommendations
DB-->>T1: JSON [Quần B, Quần C]
T1-->>LLM: {Quần B (score:94), Quần C (score:78)}
LLM-->>U: "Chị phối với Quần B hoặc Quần C ạ!"
U->>LLM: "Quần B có rẻ hơn không?"
LLM->>SM: classify_intent → DOWN_SELL
SM->>SM: PIVOT! anchor = Quần_B
SM-->>LLM: available_tools = [get_similar]
LLM->>T2: get_similar(Quần_B, "cheaper")
T2->>DB: SELECT similar_items
DB-->>T2: JSON [Quần D (rẻ hơn 100k)]
T2-->>LLM: {Quần D, price_diff: -100k}
LLM-->>U: "Dạ có Quần D rẻ hơn 100k ạ!"
U->>LLM: "Tìm thêm quần ống rộng đi làm"
LLM->>SM: classify_intent → EXPAND
SM-->>LLM: available_tools = [search_expanded]
LLM->>T3: search_expanded(Quần_B, mutations={})
T3->>DB: Copy DNA + Query Product Dimension
DB-->>T3: [Quần E, Quần F, Quần G]
T3-->>LLM: {3 quần ống rộng, đi làm}
LLM-->>U: "Em tìm thêm 3 mẫu quần ống rộng đi làm ạ!"
```
---
## 7.7. Performance Metrics mục tiêu
| Metric | Target | Cách đo |
|--------|--------|---------|
| **Tool 1 latency** (get_outfit) | <5ms | JSON parse time |
| **Tool 2 latency** (get_similar) | <5ms | JSON parse time |
| **Tool 3 latency** (search_expanded) | <50ms | SQL query + filter |
| **End-to-end response** | <2s | User message → AI response |
| **Hallucination rate** | 0% | Tất cả SKU phải tồn tại trong DB |
| **State consistency** | 100% | Mỗi pivot phải đúng transition rule |
| **Stock accuracy** | Real-time | Runtime check trước khi gợi ý |
---
## 7.8. Checklist triển khai
- [ ] Tạo Batch Job chạy scoring engine đêm → ghi `outfit_recommendations` và `similar_items`
- [ ] Implement 3 tools trong tool registry của Agent
- [ ] Thêm State Machine logic vào `conversation_manager.py`
- [ ] Thêm `current_anchor` vào session state
- [ ] Cập nhật System Prompt để LLM biết cách pivot
- [ ] Test 3 kịch bản end-to-end (Phú Quốc, Rẻ hơn, Mua cho bé)
- [ ] Monitor: Log mỗi state transition để debug
- [ ] A/B test: So sánh conversion rate trước/sau khi bật Pivoting
> **Nguyên tắc vàng cuối cùng:** Kiến trúc này hoạt động tốt nhất khi ta nhớ rằng: **LLM chịu trách nhiệm về NGÔN NGỮ (cách nói). Database chịu trách nhiệm về SỰ THẬT (nói gì).** Không bao giờ để 2 vai trò này bị trộn lẫn.
{
"id": "49-conversational-routing",
"title": "Conversational Routing Engine (Mồi Câu Liên Hoàn)",
"description": "Kiến trúc Entity-Centric Conversational Routing: Cơ chế 'Lấy mỡ nó rán nó' — dùng SKU làm Kim Chỉ Nam để điều hướng hội thoại AI qua Pre-computed Graph. Zero Hallucination, O(1) Lookup, Endless Pivoting.",
"sections": [
{
"id": "philosophy",
"title": "1. Triết lý thiết kế: Tại sao LLM là Router, không phải Stylist?",
"type": "markdown",
"file": "01_philosophy.md"
},
{
"id": "graph-architecture",
"title": "2. Kiến trúc Pre-computed Graph (Đồ thị tính toán sẵn)",
"type": "markdown",
"file": "02_graph_architecture.md"
},
{
"id": "state-machine",
"title": "3. State Machine: Cỗ máy trạng thái hội thoại",
"type": "markdown",
"file": "03_state_machine.md"
},
{
"id": "dna-inheritance",
"title": "4. DNA Inheritance: Kế thừa đặc tính sản phẩm",
"type": "markdown",
"file": "04_dna_inheritance.md"
},
{
"id": "scenarios",
"title": "5. Kịch bản thực chiến: 3 Use Cases chi tiết",
"type": "markdown",
"file": "05_scenarios.md"
},
{
"id": "industry-comparison",
"title": "6. So sánh với cộng đồng quốc tế (Reddit/Industry)",
"type": "markdown",
"file": "06_industry_comparison.md"
},
{
"id": "implementation",
"title": "7. Implementation Blueprint: Agent Tools & Code",
"type": "markdown",
"file": "07_implementation.md"
}
]
}
# Triết lý: Tại sao AI cần "Lịch Tâm Trạng"?
> **Tóm tắt:** Một con AI bán hàng mà ngày nào cũng nói giống nhau thì không khác gì robot đọc script. Khách hàng cần cảm nhận rằng AI "hiểu" hôm nay là ngày gì, đang có gì hot, và nên tư vấn kiểu nào. Event Daily Engine là cơ chế khiến AI Canifa "thức dậy mỗi sáng với một tâm trạng khác nhau" — được điều khiển 100% bởi con người.
---
## 1.1. Bài toán gốc: "Con AI bị đông cứng trong thời gian"
Hầu hết chatbot thương mại điện tử hoạt động theo một prompt **tĩnh** (Static Prompt):
```
┌──────────────────────────────────────────────────┐
│ CHATBOT TĨNH (Truyền thống) │
│ │
│ Prompt cố định ──→ AI trả lời giống nhau │
│ 365 ngày/năm mọi lúc, mọi nơi │
│ │
│ Valentine? → Vẫn nói chung chung │
│ Black Friday? → Không biết có sale │
│ Mùa đông? → Vẫn gợi áo phông │
└──────────────────────────────────────────────────┘
```
**Hậu quả thực tế:**
| Vấn đề | Ví dụ cụ thể | Thiệt hại |
|--------|--------------|-----------|
| **Mất thời điểm vàng** | Black Friday mà AI không biết push sale | Doanh thu giảm 30-50% trong ngày đỉnh |
| **Trải nghiệm nhạt** | Ngày 8/3 mà AI không có lời chúc | Khách thấy AI "vô cảm", bounce rate tăng |
| **Xung đột chiến lược** | Team Marketing chạy campaign "Áo khoác" nhưng AI vẫn push "Áo phông" | Ngân sách ads cháy vô ích |
| **Không linh hoạt** | Đổi chiến thuật → Phải sửa code, deploy lại | Lead time 2-3 ngày, miss window |
---
## 1.2. Giải pháp: "AI Mood Calendar" (Lịch Tâm Trạng AI)
Thay vì prompt tĩnh, Canifa xây một hệ thống cho phép **tiêm (inject)** hướng dẫn tư vấn vào AI **theo từng ngày, từng sự kiện, từng chiến dịch**:
```
┌──────────────────────────────────────────────────────┐
│ EVENT DAILY ENGINE (Canifa) │
│ │
│ ┌─────────┐ ┌─────────┐ ┌──────────────────┐ │
│ │ Calendar │ ─→ │ Priority │ ─→ │ Prompt Injection │ │
│ │ Engine │ │ Resolver │ │ (Into AI) │ │
│ └─────────┘ └─────────┘ └──────────────────┘ │
│ │
│ Hôm nay = Valentine + Flash Sale │
│ → Priority: Flash Sale (campaign) > Valentine (daily)│
│ → AI Prompt: "Ưu tiên push sale, kết hợp quà tặng" │
└──────────────────────────────────────────────────────┘
```
> **Nguyên tắc vàng:** Con người (BA/Marketing) quyết định AI nên nói gì hôm nay. AI chỉ là "diễn viên" diễn theo "kịch bản" của ngày hôm đó.
---
## 1.3. Phép ẩn dụ: "Nhà hàng 5 sao và Thực đơn theo mùa"
Hãy tưởng tượng AI Canifa là một **nhà hàng 5 sao**:
- **Menu cố định** (Base Prompt) = Những món signature luôn có: tư vấn phối đồ, tìm size, tra hàng...
- **Menu theo mùa** (Event Prompt) = Chef thay đổi theo mùa vụ:
- Mùa đông → Lẩu nóng, đồ nướng (= AI push áo khoác, len, dạ)
- Valentine → Set dinner lãng mạn (= AI tư vấn quà tặng, đồ đôi)
- Black Friday → Buffet giá rẻ (= AI push deal, so sánh giá, urgency)
**Menu theo mùa KHÔNG thay thế menu cố định** — nó **bổ sung** thêm "tâm trạng" và "ưu tiên" cho AI.
```
┌──────────────────────────────────────────────┐
│ PROMPT LAYERING │
│ │
│ Layer 1: BASE PROMPT (Tĩnh, cố định) │
│ ├─ Persona: Canifa AI Stylist │
│ ├─ Rules: Không bịa SP, gọi tool đúng │
│ └─ Core: Phối đồ, tìm hàng, tư vấn size │
│ │
│ Layer 2: EVENT PROMPT (Động, thay đổi/ngày)│
│ ├─ "Hôm nay 8/3: Chúc mừng phụ nữ..." │
│ ├─ "Ưu tiên gợi ý quà tặng cho chồng/BF" │
│ └─ "Tập trung BST Váy, Đầm, Phụ kiện" │
│ │
│ Layer 3: CAMPAIGN PROMPT (Chiến dịch ad-hoc)│
│ ├─ "Flash Sale 50% toàn bộ Polo" │
│ ├─ "Nhấn mạnh: Chỉ còn 2 ngày!" │
│ └─ "Cross-sell: Mua Polo + Quần giảm 10%" │
│ │
│ ═══════════════════════════════════════════ │
│ FINAL PROMPT = Layer 1 + Layer 2 + Layer 3 │
│ (Priority: Layer 3 > Layer 2 > Layer 1) │
└──────────────────────────────────────────────┘
```
---
## 1.4. Tại sao không dùng cách khác?
| Giải pháp thay thế | Tại sao Canifa không chọn? |
|--------------------|-----------------------------|
| **Sửa prompt thủ công** | Phải deploy lại code → Chậm, rủi ro, cần developer |
| **Dùng Langfuse prompt versioning** | Latency cao (~200-500ms), dependency bên ngoài |
| **Cron job tự đổi prompt** | Cứng nhắc, không linh hoạt theo chiến dịch ad-hoc |
| **Feature flag** | Chỉ bật/tắt, không chứa được nội dung prompt chi tiết |
| **Event Daily Engine ✅** | BA/Marketing tự sửa qua UI → Có hiệu lực ngay lập tức, zero deploy |
---
## 1.5. Lợi ích đo lường được
```
┌────────────────────────────────────────────────────┐
│ ROI CỦA EVENT DAILY ENGINE │
│ │
│ 📈 Conversion Rate trong ngày campaign: +15-25% │
│ ⏱️ Time-to-market chiến lược mới: 2 ngày → 2 phút │
│ 🎯 Relevance Score (NPS-style): +20 điểm │
│ 💰 Giảm chi phí vận hành: Không cần dev để đổi AI │
│ 🔄 Tần suất update: Từ 1 lần/tháng → Hàng ngày │
└────────────────────────────────────────────────────┘
```
> **Insight từ ngành (Envive.ai, 2025):** Các chatbot thương mại có khả năng cá nhân hóa theo mùa vụ/chiến dịch đạt tỉ lệ upsell cao hơn 20-30% so với chatbot tĩnh. Event Daily Engine là cách Canifa hiện thực hóa con số đó mà **không cần LLM fine-tuning hay retraining**.
# Kiến trúc hệ thống: Event → Prompt → AI Behavior
> **Tóm tắt:** Chương này mổ xẻ kiến trúc kỹ thuật end-to-end: từ lúc BA tạo sự kiện trên UI, đến lúc AI "nuốt" event prompt và thay đổi hành vi tư vấn. Mọi thứ được thiết kế để **zero-deploy** — thay đổi tức thì, không cần restart server.
---
## 2.1. Kiến trúc tổng quan (System Architecture)
```mermaid
graph TB
subgraph "📱 Frontend (UI)"
UI["Event Daily Dashboard<br/>static/event_daily/index.html"]
UI_LIST["Sidebar: Danh sách sự kiện"]
UI_EDIT["Editor: Prompt Module"]
UI --> UI_LIST
UI --> UI_EDIT
end
subgraph "⚡ Backend API (FastAPI)"
API["event_daily_route.py<br/>/api/event_daily/*"]
API_LIST["GET /events<br/>List all events"]
API_SAVE["PUT /events/{id}<br/>Update prompt"]
API --> API_LIST
API --> API_SAVE
end
subgraph "💾 Database (SQLite)"
DB["event_daily_prompts"]
DB_ROW["event_id | event_name | event_type<br/>event_date | is_today | prompt<br/>start_date | end_date"]
DB --> DB_ROW
end
subgraph "🤖 AI Pipeline (Agent)"
AGENT["Stylist Agent<br/>stylist_pro_prompts.py"]
INJECT["Prompt Injection Point<br/>system_prompt += event_prompt"]
AGENT --> INJECT
end
UI_EDIT -->|"PUT /api/event_daily/events/{id}"| API_SAVE
API_LIST -->|"SELECT * FROM event_daily_prompts"| DB
API_SAVE -->|"UPDATE ... SET prompt = ?"| DB
DB -->|"Query: WHERE is_today = 1<br/>OR date BETWEEN start/end"| AGENT
INJECT -->|"AI hành xử theo<br/>event prompt"| RESPONSE["💬 Response<br/>to Customer"]
style UI fill:#3b82f6,stroke:#2563eb,color:#fff
style API fill:#10b981,stroke:#059669,color:#fff
style DB fill:#f59e0b,stroke:#d97706,color:#000
style AGENT fill:#8b5cf6,stroke:#7c3aed,color:#fff
```
---
## 2.2. Luồng dữ liệu chi tiết (Data Flow)
### Phase A: BA/Marketing tạo & sửa Event
```
BA mở Dashboard → Chọn sự kiện "Black Friday"
→ Sửa Prompt Module: "Hôm nay Black Friday! Push sale 50%..."
→ Nhấn "Lưu Cập Nhật"
→ PUT /api/event_daily/events/black_friday
→ SQLite UPDATE prompt WHERE event_id = 'black_friday'
→ ✅ Có hiệu lực NGAY LẬP TỨC (next request)
```
### Phase B: AI nhận Event Prompt khi có khách chat
```
Khách gửi tin nhắn → Agent Pipeline khởi động
→ Step 1: Load BASE prompt (persona, rules, tools)
→ Step 2: Query event_daily_prompts WHERE is_today = 1
→ Step 3: Merge → FINAL_PROMPT = BASE + EVENT
→ Step 4: LLM nhận FINAL_PROMPT → Trả lời theo chiến lược ngày
```
```
┌─────────────────── TIMELINE ───────────────────────┐
│ │
│ 08:00 BA cập nhật prompt "Flash Sale Polo 50%" │
│ └─→ SQLite updated │
│ │
│ 09:15 Khách A hỏi: "Có áo polo nào đẹp không?" │
│ └─→ AI: "Hôm nay Flash Sale Polo 50%! 🔥 │
│ Em gợi ý 3 mẫu DryTech hot nhất..." │
│ │
│ 14:30 BA đổi prompt "Push BST Hè mới" │
│ └─→ SQLite updated (no restart needed) │
│ │
│ 14:45 Khách B hỏi: "Gợi ý gì mới đi" │
│ └─→ AI: "BST Coastal Breeze vừa ra mắt! │
│ Linen organic, minimalist Nhật Bản..." │
│ │
│ ❌ KHÔNG cần restart server │
│ ❌ KHÔNG cần deploy code mới │
│ ❌ KHÔNG cần developer can thiệp │
└──────────────────────────────────────────────────────┘
```
---
## 2.3. Component Breakdown
### 2.3.1. Frontend — Event Daily Dashboard
| Component | File | Vai trò |
|-----------|------|---------|
| **Layout** | `index.html` | 2-column layout: Sidebar (340px) + Main Content |
| **Sidebar** | `#eventsList` | Danh sách sự kiện, search bar, highlight "Today" |
| **Date Highlight** | `.date-highlight` | Hiển thị ngày hôm nay (Vietnamese locale) |
| **Tag System** | `.fb-tag` | Phân loại: `DAILY` (xanh lá) / `CAMPAIGN` (tím) |
| **Editor** | `#prompt-content` | Textarea monospace cho BA sửa prompt |
| **Date Range** | `#evt-date-from/to` | Giới hạn thời gian hiệu lực |
| **Save Button** | `savePrompt()` | PUT request + animation feedback |
**UX Flow:**
```
Click Event → Load Prompt → Edit → Save → Toast "Đã lưu" ✅
↓
Immediate effect
(next AI request uses new prompt)
```
### 2.3.2. Backend — FastAPI Router
```python
# Cấu trúc Router
router = APIRouter(prefix="/api/event_daily", tags=["Event Daily"])
# Endpoints
GET /api/event_daily/events → List ALL events
PUT /api/event_daily/events/{id} → Update prompt + date range
```
**Đặc điểm kỹ thuật:**
- **Database:** SQLite (`autotrain.db` → table `event_daily_prompts`)
- **Connection:** Thread-safe `sqlite3.connect()` per-request (không cần connection pool cho SQLite)
- **Validation:** Pydantic `EventPromptUpdate(prompt: str, start_date: str | None, end_date: str | None)`
- **Error handling:** 404 nếu `event_id` không tồn tại
### 2.3.3. Database — `event_daily_prompts` Table
```sql
CREATE TABLE event_daily_prompts (
event_id TEXT PRIMARY KEY, -- 'valentine', 'black_friday', 'daily_default'
event_name TEXT NOT NULL, -- 'Valentine 14/2'
event_type TEXT DEFAULT 'daily', -- 'daily' | 'campaign'
event_date TEXT, -- '2026-02-14' hoặc NULL (recurring)
is_today INTEGER DEFAULT 0, -- 1 nếu đang active hôm nay
prompt TEXT, -- Nội dung chỉ đạo cho AI
start_date TEXT, -- Ngày bắt đầu hiệu lực
end_date TEXT, -- Ngày kết thúc hiệu lực
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP
);
```
---
## 2.4. State Diagram — Vòng đời của một Event
```mermaid
stateDiagram-v2
[*] --> Draft: BA tạo event mới
Draft --> Scheduled: Set start_date
Scheduled --> Active: start_date <= TODAY
Active --> Active: BA cập nhật prompt
Active --> Expired: end_date < TODAY
Expired --> Archived: Auto-cleanup
Archived --> [*]
Active --> Paused: BA tắt thủ công
Paused --> Active: BA bật lại
note right of Active
is_today = 1
AI đang sử dụng prompt này
end note
note right of Draft
is_today = 0
Chưa có hiệu lực
end note
```
---
## 2.5. Tính năng "Today Highlight"
Một trong những điểm nhấn UX quan trọng nhất là hệ thống tự động **highlight ngày hôm nay** trên Sidebar:
```
┌──────────────────────────────┐
│ 📅 Event Daily │
│ ──────────────────────────── │
│ HÔM NAY │
│ Thứ Hai, 12 tháng 5, 2026 │
│ ──────────────────────────── │
│ │
│ ┌──────────────────────────┐ │
│ │ Flash Sale Polo 50% 🔥│ │ ← Active campaign (CAMPAIGN tag, tím)
│ │ 10/5 - 15/5 │ │
│ │ "Push sale Polo DryTech" │ │
│ └──────────────────────────┘ │
│ │
│ ┌──────────────────────────┐ │
│ │ Mặc định hàng ngày │ │ ← Always-on daily (DAILY tag, xanh)
│ │ Recurring │ │
│ │ "Tư vấn chung, ưu tiên…"│ │
│ └──────────────────────────┘ │
│ │
│ ┌──────────────────────────┐ │
│ │ Valentine 14/2 │ │ ← Scheduled (chưa tới)
│ │ 12/2 - 15/2 │ │
│ │ "Gợi ý quà tặng…" │ │
│ └──────────────────────────┘ │
└──────────────────────────────┘
```
**Logic highlight:**
1. Lọc events có `is_today = 1` → Hiển thị icon 🔥
2. Sort: Active campaigns trước → Daily defaults → Scheduled → Expired
3. Vietnamese locale: `Thứ Hai, 12 tháng 5, 2026`
# Data Model & Prompt Schema
> **Tóm tắt:** Chương này đi sâu vào cấu trúc dữ liệu, mối quan hệ giữa các bảng, và đặc biệt là Prompt Schema — quy tắc viết prompt cho Event Daily để đảm bảo AI hoạt động chính xác, nhất quán.
---
## 3.1. Entity Relationship Diagram (ERD)
```mermaid
erDiagram
EVENT_DAILY_PROMPTS {
text event_id PK "valentine, black_friday..."
text event_name "Valentine 14/2"
text event_type "daily | campaign"
text event_date "2026-02-14"
int is_today "0 hoặc 1"
text prompt "Nội dung chỉ đạo AI"
text start_date "Bắt đầu hiệu lực"
text end_date "Kết thúc hiệu lực"
datetime created_at
datetime updated_at
}
STYLIST_SYSTEM_PROMPT {
text prompt_id PK
text base_prompt "Prompt gốc (tĩnh)"
text version "v3.2"
text model "gemini-3.1-flash-lite"
}
AI_AGENT {
text session_id PK
text final_prompt "base + event + campaign"
text model_name
}
EVENT_DAILY_PROMPTS ||--o{ AI_AGENT : "inject vào"
STYLIST_SYSTEM_PROMPT ||--|| AI_AGENT : "base layer"
```
---
## 3.2. Bảng `event_daily_prompts` — Chi tiết cột
| Cột | Type | Constraint | Mô tả | Ví dụ |
|-----|------|-----------|-------|-------|
| `event_id` | TEXT | PK | ID duy nhất, snake_case | `valentine_2026` |
| `event_name` | TEXT | NOT NULL | Tên hiển thị trên UI | `Valentine 14/2 💕` |
| `event_type` | TEXT | DEFAULT 'daily' | Phân loại sự kiện | `daily` hoặc `campaign` |
| `event_date` | TEXT | NULLABLE | Ngày cố định (nếu có) | `2026-02-14` |
| `is_today` | INTEGER | DEFAULT 0 | Cờ active hôm nay | `1` = đang active |
| `prompt` | TEXT | NULLABLE | Nội dung chỉ đạo cho AI | *(xem phần 3.3)* |
| `start_date` | TEXT | NULLABLE | Ngày bắt đầu hiệu lực | `2026-02-12` |
| `end_date` | TEXT | NULLABLE | Ngày kết thúc hiệu lực | `2026-02-15` |
| `created_at` | DATETIME | AUTO | Thời điểm tạo | `2026-01-15 10:30:00` |
| `updated_at` | DATETIME | AUTO | Lần sửa cuối | `2026-02-10 14:20:00` |
### Quy tắc `event_type`:
```
┌─────────────────────────────────────────────────────┐
│ event_type = "daily" │
│ ───────────────────── │
│ Sự kiện lặp lại hoặc luôn active │
│ VD: "Mặc định hàng ngày", "Cuối tuần", "Tết" │
│ Priority: THẤP (bị override bởi campaign) │
│ UI Tag: 🟢 DAILY (xanh lá) │
│ │
│ event_type = "campaign" │
│ ───────────────────── │
│ Chiến dịch ad-hoc, có thời hạn │
│ VD: "Flash Sale 3 ngày", "Black Friday 2026" │
│ Priority: CAO (override daily events) │
│ UI Tag: 🟣 CAMPAIGN (tím) │
└─────────────────────────────────────────────────────┘
```
---
## 3.3. Prompt Schema — Quy tắc viết prompt hiệu quả
### Template chuẩn:
```markdown
## [EVENT_NAME] — Chỉ Đạo Tư Vấn
### 🎯 Mục tiêu chính:
[Mục tiêu kinh doanh của ngày/chiến dịch này]
### 💬 Giọng điệu:
[Tone of voice: Urgent? Lãng mạn? Vui vẻ? Formal?]
### 🛍️ Ưu tiên tư vấn:
1. [Danh mục sản phẩm ưu tiên #1]
2. [Danh mục sản phẩm ưu tiên #2]
3. [Danh mục sản phẩm ưu tiên #3]
### ⚠️ Lưu ý đặc biệt:
- [Thông tin sale/khuyến mãi cần nhấn mạnh]
- [Sản phẩm/danh mục CẤM push hôm nay]
- [Thông tin logistics đặc biệt (free ship, deadline...)]
### 📝 Câu mẫu mở đầu (optional):
"[Câu chào/mở đầu gợi ý cho AI sử dụng]"
```
### Ví dụ thực tế — Valentine 14/2:
```markdown
## Valentine 14/2 💕 — Chỉ Đạo Tư Vấn
### 🎯 Mục tiêu chính:
Tăng doanh thu danh mục Quà tặng & Đồ đôi. Target: +25% so với ngày thường.
### 💬 Giọng điệu:
Nhẹ nhàng, lãng mạn, thêm 1-2 emoji trái tim. Gợi ý tinh tế, không ép mua.
### 🛍️ Ưu tiên tư vấn:
1. Áo phông đôi (Couple T-shirt) — Push mạnh nhất
2. Phụ kiện: Khăn, mũ, túi — Gợi ý làm quà
3. BST Váy/Đầm — Cho khách nữ mua cho bản thân
### ⚠️ Lưu ý đặc biệt:
- NHẤN MẠNH: Free ship đơn từ 500K + tặng túi gói quà
- KHÔNG push đồ nam basic (polo, quần kaki) trừ khi khách hỏi
- Deadline giao hàng trước 14/2: Đặt trước 12/2
### 📝 Câu mẫu mở đầu:
"Valentine sắp tới rồi ạ! 💕 Em có thể giúp anh/chị tìm quà tặng
hoặc đồ đôi cực xinh nhé~"
```
---
## 3.4. Anti-Patterns — Những cách viết prompt SAI
| ❌ Sai | ✅ Đúng | Tại sao? |
|--------|---------|----------|
| "Bán nhiều hàng lên" | "Ưu tiên push BST Hè, target Polo DryTech 3.0" | Quá chung chung, AI không biết push cái gì |
| "Sale 50% toàn bộ" | "Sale 50% Polo + Sơ mi. KHÔNG áp dụng cho Jeans" | AI sẽ bịa sale cho cả danh mục không có sale |
| "Nói hay lên" | "Giọng điệu: Năng động, trẻ trung. Dùng 1-2 emoji/câu" | "Hay" là chủ quan, cần chỉ dẫn cụ thể |
| "Tư vấn áo khoác mùa đông" *(vào tháng 6)* | Để prompt trống hoặc daily default | Xung đột mùa vụ → Trải nghiệm kỳ quặc |
| Copy/paste toàn bộ catalog | Liệt kê 3-5 mã SKU/danh mục cụ thể | Prompt quá dài → Token waste, AI bị confused |
---
## 3.5. Seed Data — Bộ dữ liệu khởi tạo
```sql
INSERT INTO event_daily_prompts (event_id, event_name, event_type, event_date, is_today, prompt) VALUES
('daily_default', 'Mặc định hàng ngày', 'daily', NULL, 1,
'Tư vấn bình thường, ưu tiên sản phẩm mới nhập và hàng best-seller. Gợi ý phối đồ theo mùa hiện tại.'),
('valentine_2026', 'Valentine 14/2 💕', 'campaign', '2026-02-14', 0,
'## Valentine 14/2\n🎯 Push quà tặng & đồ đôi\n💬 Tone lãng mạn\n🛍️ Ưu tiên: Áo đôi, Phụ kiện, Váy/Đầm\n⚠️ Free ship từ 500K'),
('women_day', 'Quốc tế Phụ nữ 8/3 🌸', 'campaign', '2026-03-08', 0,
'## 8/3 - Ngày Phụ nữ\n🎯 Tăng doanh thu đồ nữ\n💬 Chúc mừng ngọt ngào\n🛍️ Ưu tiên: Váy, Đầm, Set quà tặng\n⚠️ Combo quà tặng giảm 20%'),
('children_day', 'Quốc tế Thiếu nhi 1/6 🎈', 'daily', '2026-06-01', 0,
'## 1/6 - Thiếu nhi\n🎯 Push đồ trẻ em\n💬 Vui tươi, dùng emoji nhiều\n🛍️ Ưu tiên: Áo phông in hình, Quần short, Set đồ bộ\n⚠️ Giảm 30% toàn bộ kidswear'),
('black_friday', 'Black Friday 🖤', 'campaign', '2026-11-29', 0,
'## Black Friday\n🎯 Doanh thu max!\n💬 Urgency cao, FOMO\n🛍️ Push tất cả danh mục có sale\n⚠️ Sale 50% selected, mua 2 giảm thêm 10%\n📝 "Black Friday chỉ 1 ngày!"'),
('tet_2027', 'Tết Nguyên Đán 2027 🧧', 'campaign', '2027-01-29', 0,
'## Tết Nguyên Đán\n🎯 Push áo dài, đồ Tết\n💬 Truyền thống, ấm áp\n🛍️ Ưu tiên: Áo dài, Áo khoác, Set đồ Tết\n⚠️ Free ship toàn quốc, giao trước 28 Tết');
```
# Dynamic Prompt Injection: Cách Event "tiêm" vào AI
> **Tóm tắt:** Đây là chương quan trọng nhất — giải thích cơ chế kỹ thuật chính xác cách Event Daily Prompt được "ghép nối" vào System Prompt của AI Agent. Không phải thay thế, mà là **tiêm thêm** một lớp context.
---
## 4.1. Prompt Injection Pipeline
Khi khách hàng gửi tin nhắn đến AI Canifa, pipeline xử lý prompt diễn ra theo thứ tự:
```mermaid
sequenceDiagram
participant Customer as 👤 Khách hàng
participant Agent as 🤖 AI Agent
participant PromptDB as 📋 Prompt Store<br/>(Langfuse/Local)
participant EventDB as 📅 Event Daily<br/>(SQLite)
participant LLM as 🧠 Gemini Flash
Customer->>Agent: "Áo polo nào đẹp?"
Agent->>PromptDB: Load BASE prompt (v3.2)
PromptDB-->>Agent: system_prompt = "Bạn là AI Stylist..."
Agent->>EventDB: Query WHERE is_today = 1<br/>OR (start_date <= TODAY AND end_date >= TODAY)
EventDB-->>Agent: event_prompt = "Flash Sale Polo 50%!"
Note over Agent: MERGE:<br/>final_prompt = base + "\n---\n" + event
Agent->>LLM: final_prompt + user_message
LLM-->>Agent: "Hôm nay Flash Sale Polo 50%! 🔥..."
Agent-->>Customer: Response
```
---
## 4.2. Cơ chế Merge: "Sandwich Prompt"
Prompt cuối cùng được xây theo mô hình **3 lớp bánh mì kẹp**:
```
┌─────────────────────────────────────────────────────┐
│ 🍞 TOP BUN: System Persona │
│ "Bạn là Canifa AI Stylist, tư vấn thời trang..." │
│ "Quy tắc: Không bịa sản phẩm, gọi tool chính xác" │
├─────────────────────────────────────────────────────┤
│ 🥩 MEAT: Event Daily Prompt (INJECTED) │
│ "═══ CHIẾN DỊCH HÔM NAY ═══" │
│ "Flash Sale Polo 50%! Chỉ 2 ngày cuối tuần." │
│ "Ưu tiên: Polo DryTech 3.0 (399K → 199K)" │
│ "Cross-sell: Mua Polo + Quần giảm thêm 10%" │
│ "Tone: Urgency, dùng emoji 🔥⏰" │
├─────────────────────────────────────────────────────┤
│ 🍞 BOTTOM BUN: Tool Definitions & Guardrails │
│ "Tools: search_products, get_outfit, get_similar" │
│ "Format: Markdown, max 200 words" │
└─────────────────────────────────────────────────────┘
```
### Code Implementation (Pseudo-code):
```python
async def build_final_prompt(base_prompt: str) -> str:
"""
Merge base prompt với event daily prompt.
Event prompt được inject ở giữa, trước tool definitions.
"""
# Step 1: Load active events
active_events = db.query(
"SELECT prompt FROM event_daily_prompts "
"WHERE is_today = 1 "
"OR (start_date <= date('now') AND end_date >= date('now')) "
"ORDER BY event_type DESC" # campaign trước daily
)
if not active_events:
return base_prompt # Không có event → dùng base prompt thuần
# Step 2: Build event section
event_section = "\n\n═══ CHIẾN DỊCH HÔM NAY ═══\n"
for event in active_events:
event_section += f"\n{event['prompt']}\n"
event_section += "\n═══ KẾT THÚC CHIẾN DỊCH ═══\n"
# Step 3: Inject vào base prompt (trước phần tool definitions)
# Tìm vị trí marker "## TOOLS:" trong base prompt
tool_marker = "## TOOLS:"
if tool_marker in base_prompt:
idx = base_prompt.index(tool_marker)
final = base_prompt[:idx] + event_section + "\n" + base_prompt[idx:]
else:
final = base_prompt + event_section
return final
```
---
## 4.3. Priority Resolution: Khi nhiều Event cùng active
Trong thực tế, có thể xảy ra tình huống **nhiều sự kiện active đồng thời** (VD: Valentine + Flash Sale + Daily default). Hệ thống cần quy tắc ưu tiên rõ ràng:
```mermaid
graph TD
subgraph "Ngày 14/2/2026"
E1["🟣 Campaign: Flash Sale Polo<br/>Priority: 100"]
E2["🟣 Campaign: Valentine Promo<br/>Priority: 90"]
E3["🟢 Daily: Mặc định hàng ngày<br/>Priority: 10"]
end
E1 --> MERGE["Prompt Merger"]
E2 --> MERGE
E3 --> MERGE
MERGE --> FINAL["Final Prompt:<br/>1. Flash Sale (đầu tiên)<br/>2. Valentine (bổ sung)<br/>3. Daily default (nền)"]
style E1 fill:#8b5cf6,stroke:#7c3aed,color:#fff
style E2 fill:#8b5cf6,stroke:#7c3aed,color:#fff
style E3 fill:#10b981,stroke:#059669,color:#fff
style FINAL fill:#f59e0b,stroke:#d97706,color:#000
```
### Quy tắc xếp hạng:
| Thứ tự | Loại | Priority | Hành vi |
|--------|------|----------|---------|
| 1 | `campaign` + `is_today = 1` | **Cao nhất** | Hiển thị đầu tiên trong prompt |
| 2 | `campaign` + date range match | Cao | Bổ sung sau campaign chính |
| 3 | `daily` + `is_today = 1` | Trung bình | Nền (background context) |
| 4 | `daily` + date range match | Thấp | Chỉ dùng nếu không có campaign |
| 5 | Không có event nào | Fallback | Dùng base prompt thuần |
---
## 4.4. Token Budget Management
Event prompt KHÔNG được phép "ăn" hết token budget của system prompt:
```
┌──────────────────────────────────────────┐
│ TOKEN BUDGET (8K tokens) │
│ │
│ Base Prompt: ~2,500 tokens (31%) │
│ Event Prompt: ~500 tokens (6%) ← MAX│
│ Tool Definitions: ~1,500 tokens (19%) │
│ User History: ~2,000 tokens (25%) │
│ Response Buffer: ~1,500 tokens (19%) │
│ │
│ ⚠️ Event prompt > 500 tokens = WARNING │
│ 🚫 Event prompt > 1000 tokens = REJECT │
└──────────────────────────────────────────┘
```
### Validation Rule:
```python
MAX_EVENT_PROMPT_CHARS = 2000 # ~500 tokens
def validate_event_prompt(prompt: str) -> bool:
if len(prompt) > MAX_EVENT_PROMPT_CHARS:
raise ValueError(
f"Event prompt quá dài ({len(prompt)} chars). "
f"Giới hạn: {MAX_EVENT_PROMPT_CHARS} chars (~500 tokens). "
f"Hãy rút gọn chỉ giữ thông tin quan trọng nhất."
)
return True
```
---
## 4.5. Cache & Performance
Event Daily prompt được thiết kế để **không ảnh hưởng performance**:
| Metric | Giá trị | Lý do |
|--------|---------|-------|
| **Query time** | < 1ms | SQLite in-memory, table < 50 rows |
| **Cache strategy** | Per-request | Prompt có thể thay đổi bất cứ lúc nào |
| **Token overhead** | +300-500 tokens | Chấp nhận được trong budget 8K |
| **Latency impact** | +0.5ms | Không đáng kể so với LLM inference (~500ms) |
> **Quyết định thiết kế:** Không cache event prompt vì:
> 1. BA có thể đổi prompt bất cứ lúc nào (cần realtime effect)
> 2. SQLite query < 1ms (nhanh hơn cả cache lookup Redis)
> 3. Table chỉ có ~10-50 rows (trivial workload)
# Kịch bản thực chiến: 6 Chiến dịch mẫu
> **Tóm tắt:** Chương này mô phỏng 6 kịch bản thực tế, mỗi kịch bản cho thấy AI Canifa thay đổi hành vi ra sao khi Event Daily Prompt được kích hoạt. Đọc xong chương này, bạn sẽ biết chính xác cách viết prompt cho mọi loại chiến dịch.
---
## 📋 Kịch bản 1: Flash Sale 50% Polo (Urgency Campaign)
### Event Config:
| Field | Value |
|-------|-------|
| `event_id` | `flash_sale_polo_may2026` |
| `event_type` | `campaign` |
| `start_date` | `2026-05-10` |
| `end_date` | `2026-05-12` |
### Prompt:
```
## Flash Sale Polo DryTech — Chỉ 2 ngày!
🎯 Push Polo DryTech 3.0 (mã 3PS...) giá 399K → 199K
💬 Tone: Urgency + FOMO. "Chỉ còn 2 ngày!", "Số lượng có hạn!"
🛍️ Ưu tiên:
1. Polo DryTech 3.0 (12 màu, slim-fit)
2. Cross-sell: Mua Polo + Quần Kaki giảm thêm 10%
3. Bundle: Mua 3 Polo giá 499K (tiết kiệm 98K)
⚠️ KHÔNG push sản phẩm không có sale
📝 "Đợt sale Polo HOT nhất năm đang diễn ra! Chỉ còn [X] ngày!"
```
### Mô phỏng cuộc hội thoại:
```
👤 Khách: "Có áo polo nào đẹp không em?"
🤖 AI (CÓ event prompt):
"Anh ơi đúng lúc quá! 🔥 Đang Flash Sale Polo DryTech 3.0 chỉ
199K (giá gốc 399K) — còn 2 ngày cuối thôi ạ!
Polo DryTech 3.0 có 12 màu, chất liệu khô nhanh + kháng khuẩn +
chống UV. Form slim-fit vừa vặn ạ.
💡 Tip: Mua kèm Quần Kaki giảm thêm 10%, hoặc combo 3 Polo
chỉ 499K tiết kiệm 98K!
Anh muốn em tìm màu nào ạ?"
🤖 AI (KHÔNG có event prompt — ngày thường):
"Dạ anh, Canifa có nhiều mẫu polo đẹp lắm ạ!
Em tìm cho anh xem nhé. Anh muốn polo form gì ạ?
Slim-fit hay regular fit?"
```
> **Khác biệt:** Với event prompt, AI **chủ động push sale** + **tạo urgency** + **cross-sell ngay lập tức** thay vì hỏi lại chung chung.
---
## 📋 Kịch bản 2: Valentine 14/2 (Emotional Campaign)
### Prompt:
```
## Valentine 14/2 💕
🎯 Tăng doanh thu Quà tặng & Đồ đôi
💬 Tone: Lãng mạn, ngọt ngào. Emoji ❤️💕 tự nhiên.
🛍️ Ưu tiên:
1. Áo phông đôi (Couple T-shirt)
2. Phụ kiện: Khăn, mũ — gợi ý làm quà
3. Set quà tặng có sẵn (gift box)
⚠️ Free ship đơn từ 500K + tặng túi gói quà
⚠️ Deadline giao trước 14/2: Đặt trước 12/2
📝 "Valentine sắp tới rồi ạ! 💕 Em giúp anh/chị tìm quà nhé~"
```
### Mô phỏng:
```
👤 Khách: "Tìm cho chị cái áo phông đẹp"
🤖 AI (CÓ event prompt):
"Valentine sắp tới rồi chị ơi! 💕
Canifa có bộ áo phông đôi (Couple T-shirt) cực xinh —
mặc cùng người yêu đi chơi Valentine vừa đẹp vừa ý nghĩa ạ!
Nếu chị muốn tặng quà, em gợi ý thêm set gift box có sẵn
(áo + khăn) gói sẵn rất tiện ạ 🎁
💡 Free ship đơn từ 500K + tặng kèm túi gói quà!
⏰ Lưu ý: Đặt trước 12/2 để giao kịp trước Valentine nha chị!
Chị muốn xem áo đôi hay set quà ạ?"
```
---
## 📋 Kịch bản 3: Ngày thường (Daily Default)
### Prompt:
```
Tư vấn bình thường theo nhu cầu khách hàng.
Ưu tiên sản phẩm mới nhập và hàng best-seller.
Gợi ý phối đồ theo mùa hiện tại.
```
### Mô phỏng:
```
👤 Khách: "Tìm cho chị cái áo phông đẹp"
🤖 AI (Daily default):
"Dạ chị, Canifa có nhiều mẫu áo phông mới lắm ạ!
Em tìm cho chị nhé. Chị muốn áo form nào ạ?
Boxy thoải mái hay slim-fit gọn gàng?
Mặc đi làm hay đi chơi ạ?"
```
> **Khác biệt:** Daily default → AI hỏi nhu cầu trước. Campaign → AI chủ động push sản phẩm/chiến dịch.
---
## 📋 Kịch bản 4: Black Friday (Max Urgency)
### Prompt:
```
## BLACK FRIDAY 🖤 — CHỈ 1 NGÀY DUY NHẤT!
🎯 DOANH THU TỐI ĐA. Mọi câu trả lời đều phải nhắc sale.
💬 Tone: FOMO cực đại. "Chỉ hôm nay!", "Số lượng cực có hạn!"
🛍️ Push TẤT CẢ danh mục có sale:
- Polo: 50% OFF
- Sơ mi: 40% OFF
- Jeans: 30% OFF
- Áo khoác: 40% OFF
⚠️ Mua 2 sản phẩm bất kỳ giảm thêm 10%
⚠️ Free ship TOÀN QUỐC không giới hạn
⚠️ Hết 23:59 hôm nay là HẾT SALE, không gia hạn
📝 "🖤 BLACK FRIDAY — Sale tới 50%! Chỉ HÔM NAY!"
```
---
## 📋 Kịch bản 5: Ra mắt BST mới (Product Launch)
### Prompt:
```
## BST Coastal Breeze — Hè 2026 🌊
🎯 Giới thiệu BST mới, tạo awareness + wish list
💬 Tone: Hào hứng, trẻ trung. Nhấn mạnh chất liệu Linen organic.
🛍️ Ưu tiên:
1. Áo linen (4 form: Boxy, Regular, Slim, Oversize)
2. Quần linen (ống rộng + ống đứng)
3. Set đồ bộ linen (1 áo + 1 quần combo)
⚠️ Giá: 299K-599K. Free ship từ 500K.
⚠️ Highlight: Cotton hữu cơ, thiết kế minimalist Nhật Bản
📝 "BST Coastal Breeze vừa ra mắt! Linen organic, chill biển 🌊"
```
---
## 📋 Kịch bản 6: Sự kiện tiêu cực — Tăng giá (Crisis Mode)
### Prompt:
```
## Điều chỉnh giá — Xử lý khéo léo
🎯 Giảm thiểu phản ứng tiêu cực về tăng giá 15%
💬 Tone: Thấu hiểu, empathy. KHÔNG phòng thủ.
🛍️ Khi khách hỏi về giá:
1. Thừa nhận: "Dạ, giá có điều chỉnh do chi phí nguyên liệu tăng"
2. Nhấn mạnh giá trị: Chất lượng vải tốt hơn, form chuẩn hơn
3. Gợi ý: SP cũ vẫn giữ giá đến hết hàng — cơ hội cuối!
⚠️ TUYỆT ĐỐI KHÔNG nói "tăng giá là bình thường"
⚠️ KHÔNG so sánh với brand khác (Uniqlo, Coolmate...)
⚠️ Nếu khách tỏ ý bỏ đi: "Em hiểu ạ. Cho em xin phép gợi ý
vài mẫu trong tầm giá anh/chị mong muốn nhé?"
```
### Mô phỏng tình huống nhạy cảm:
```
👤 Khách: "Sao giá tăng dữ vậy? Định bỏ Canifa rồi!"
🤖 AI (CÓ crisis prompt):
"Dạ em hiểu sự lo lắng của anh/chị ạ 🙏
Giá có điều chỉnh do chi phí nguyên liệu tăng trên toàn cầu.
Bù lại, chất lượng vải BST mới tốt hơn rõ rệt — mềm mại,
bền màu hơn ạ.
💡 Tin vui: Các sản phẩm cũ vẫn giữ nguyên giá cho đến hết hàng
— đây là cơ hội cuối để mua giá cũ!
Em tìm cho anh/chị mấy mẫu trong tầm giá mong muốn nhé?
Anh/chị budget khoảng bao nhiêu ạ?"
🤖 AI (KHÔNG có crisis prompt):
"Dạ anh/chị, em tìm cho anh/chị áo phông nhé!
Form nào ạ?"
← THẢM HỌA: Bỏ qua hoàn toàn nỗi lo của khách
```
---
## Bảng tổng hợp 6 kịch bản
| # | Chiến dịch | Type | Tone | AI thay đổi ra sao? |
|---|-----------|------|------|---------------------|
| 1 | Flash Sale Polo | `campaign` | Urgency/FOMO | Chủ động push deal, cross-sell ngay |
| 2 | Valentine | `campaign` | Romantic | Gợi ý quà, đồ đôi, deadline giao hàng |
| 3 | Daily Default | `daily` | Neutral | Hỏi nhu cầu, tư vấn theo mùa |
| 4 | Black Friday | `campaign` | Max FOMO | Mọi câu đều nhắc sale, countdown |
| 5 | BST mới | `campaign` | Excited | Giới thiệu chất liệu, thiết kế mới |
| 6 | Tăng giá | `campaign` | Empathy | Thấu hiểu, đề xuất thay thế, không phòng thủ |
# Priority Engine: Khi nhiều sự kiện đè nhau
> **Tóm tắt:** Trong thực tế, nhiều sự kiện có thể active cùng lúc (VD: Black Friday + Flash Sale Polo + Daily default). Chương này thiết kế cơ chế Priority Resolution Engine — quyết định event nào được ưu tiên inject vào AI.
---
## 6.1. Bài toán: "Collision Day"
```
┌──────────────────── Ngày 29/11/2026 ────────────────────┐
│ │
│ 🟣 Campaign: Black Friday (priority: 100) │
│ 🟣 Campaign: Flash Sale Áo khoác (priority: 80) │
│ 🟢 Daily: Mặc định mùa đông (priority: 10) │
│ 🟣 Campaign: Loyalty Day - VIP (priority: 60) │
│ │
│ ❓ AI nên nhắc cái nào trước? │
│ ❓ Có nhắc TẤT CẢ hay chỉ cái TOP? │
│ ❓ Prompt quá dài thì sao? │
└───────────────────────────────────────────────────────────┘
```
---
## 6.2. Priority Score Matrix
Mỗi event được gán một **Priority Score** dựa trên 3 yếu tố:
```mermaid
graph LR
subgraph "Priority Score = A + B + C"
A["A: Event Type<br/>campaign=50, daily=10"]
B["B: Recency<br/>(today=30, this week=20, this month=10)"]
C["C: Manual Boost<br/>(BA set: 0-50)"]
end
A --> SCORE["Final Score"]
B --> SCORE
C --> SCORE
style A fill:#8b5cf6,stroke:#7c3aed,color:#fff
style B fill:#3b82f6,stroke:#2563eb,color:#fff
style C fill:#f59e0b,stroke:#d97706,color:#000
```
### Công thức:
```python
def calculate_priority(event: dict) -> int:
score = 0
# A: Event Type Weight
score += 50 if event['event_type'] == 'campaign' else 10
# B: Recency Weight
if event['is_today']:
score += 30
elif is_this_week(event):
score += 20
elif is_this_month(event):
score += 10
# C: Manual Boost (BA có thể set thủ công)
score += event.get('priority_boost', 0)
return score
```
### Ví dụ tính toán ngày 29/11:
| Event | Type (A) | Recency (B) | Boost (C) | **Total** |
|-------|----------|-------------|-----------|-----------|
| Black Friday | 50 | 30 | 20 | **100** ← Winner |
| Flash Sale Áo khoác | 50 | 30 | 0 | **80** |
| Loyalty Day VIP | 50 | 30 | -20 | **60** |
| Mặc định mùa đông | 10 | 30 | 0 | **40** |
---
## 6.3. Merge Strategy: "Top-N with Budget"
Không phải inject TẤT CẢ events — có giới hạn token budget:
```
┌──────────────────────────────────────────────────┐
│ MERGE STRATEGY │
│ │
│ Token Budget cho Event Prompt: 500 tokens (~2000 chars)│
│ │
│ Bước 1: Sort events theo Priority Score (DESC) │
│ Bước 2: Lấy Top event (highest priority) │
│ Bước 3: Nếu còn budget → Append event thứ 2 │
│ Bước 4: Nếu còn budget → Append event thứ 3 │
│ Bước 5: Nếu hết budget → STOP, bỏ phần còn lại │
│ │
│ Kết quả phổ biến: 1-2 events được inject │
│ (đủ cho AI biết context mà không quá tải) │
└──────────────────────────────────────────────────┘
```
### Pseudo-code:
```python
MAX_EVENT_TOKENS = 500 # ~2000 chars
def merge_events(events: list) -> str:
# Sort by priority
sorted_events = sorted(events, key=lambda e: e['priority'], reverse=True)
merged = "═══ CHIẾN DỊCH HÔM NAY ═══\n"
current_tokens = 0
for event in sorted_events:
event_tokens = estimate_tokens(event['prompt'])
if current_tokens + event_tokens > MAX_EVENT_TOKENS:
# Budget exhausted → add summary of remaining
remaining = len(sorted_events) - sorted_events.index(event)
merged += f"\n(+ {remaining} sự kiện khác, ưu tiên thấp hơn)\n"
break
merged += f"\n{event['prompt']}\n"
current_tokens += event_tokens
merged += "\n═══ KẾT THÚC CHIẾN DỊCH ═══"
return merged
```
---
## 6.4. Edge Cases & Solutions
### Case 1: Hai campaign xung đột nội dung
```
🟣 Campaign A: "Push Polo giá 399K"
🟣 Campaign B: "Flash Sale Polo giá 199K"
→ Vấn đề: AI sẽ nói giá nào??
→ Giải pháp: Campaign có Priority Score cao hơn sẽ thắng.
BA phải đảm bảo Campaign cũ được TẮT trước khi tạo mới.
```
### Case 2: Daily prompt mâu thuẫn với Campaign
```
🟢 Daily: "Ưu tiên đồ trẻ em" (Ngày 1/6 Thiếu nhi)
🟣 Campaign: "Flash Sale đồ người lớn"
→ Giải pháp: Campaign LUÔN override Daily.
AI sẽ ưu tiên Flash Sale, nhưng vẫn có context ngày Thiếu nhi
để respond nếu khách hỏi về đồ trẻ em.
```
### Case 3: Không có event nào active
```
→ is_today = 0 cho tất cả events
→ Không có date range match
→ Giải pháp: Fallback về base prompt thuần (không inject gì thêm).
AI hoạt động như ngày thường.
```
### Case 4: Event prompt quá dài
```
→ BA viết prompt 5000 chars (quá giới hạn 2000 chars)
→ Giải pháp:
1. Frontend: Warning khi vượt 1500 chars
2. Backend: Reject nếu > 2000 chars
3. Hiển thị character counter trên UI
```
---
## 6.5. Decision Tree — Flowchart hoàn chỉnh
```mermaid
graph TD
START["Khách gửi tin nhắn"] --> LOAD["Load Base Prompt"]
LOAD --> QUERY["Query active events<br/>(is_today=1 OR date range)"]
QUERY --> CHECK{"Có event nào?"}
CHECK -->|"Không"| BASE["Dùng Base Prompt thuần"]
CHECK -->|"Có 1"| SINGLE["Inject 1 event prompt"]
CHECK -->|"Có nhiều"| MULTI["Priority Resolution"]
MULTI --> SORT["Sort by Priority Score"]
SORT --> BUDGET{"Còn token budget?"}
BUDGET -->|"Có"| APPEND["Append event tiếp theo"]
APPEND --> BUDGET
BUDGET -->|"Hết"| FINAL["Final Merged Prompt"]
SINGLE --> FINAL
BASE --> LLM["Gửi cho LLM"]
FINAL --> LLM
LLM --> RESPONSE["Trả lời khách"]
style START fill:#3b82f6,stroke:#2563eb,color:#fff
style RESPONSE fill:#10b981,stroke:#059669,color:#fff
style MULTI fill:#f59e0b,stroke:#d97706,color:#000
```
# Nghiên cứu ngành: Event-Driven AI trong Retail
> **Tóm tắt:** Chương này đặt Event Daily Engine của Canifa vào bối cảnh nghiên cứu quốc tế. Chúng ta sẽ xem các gã khổng lồ (Shopify, Amazon, Zara) và startup AI retail đang làm gì tương tự, và Canifa đang ở đâu trên bản đồ này.
---
## 7.1. Bối cảnh: AI Retail đang chuyển từ "Static" sang "Event-Driven"
```
┌──────────────────────────────────────────────────────┐
│ EVOLUTION OF AI IN RETAIL │
│ │
│ 2020-2022: Static Chatbot │
│ ├─ Prompt cố định │
│ ├─ FAQ-based responses │
│ └─ Không biết context thời gian │
│ │
│ 2023-2024: Contextual AI │
│ ├─ RAG (Retrieval-Augmented Generation) │
│ ├─ Product catalog awareness │
│ └─ Bắt đầu biết inventory │
│ │
│ 2025-2026: Event-Driven AI ← CANIFA ĐANG Ở ĐÂY │
│ ├─ Dynamic prompt injection │
│ ├─ Campaign-aware responses │
│ ├─ Real-time behavior modification │
│ └─ Zero-deploy strategy updates │
│ │
│ 2027+: Autonomous AI │
│ ├─ Self-adjusting campaigns based on performance │
│ ├─ AI tự đề xuất event prompts │
│ └─ Closed-loop optimization │
└──────────────────────────────────────────────────────┘
```
---
## 7.2. Benchmark: So sánh với các hệ thống lớn
| Feature | **Canifa Event Daily** | Shopify Sidekick | Amazon Rufus | Zara Virtual Stylist |
|---------|----------------------|------------------|--------------|---------------------|
| **Dynamic Prompt** | ✅ BA sửa trực tiếp | ⚠️ Qua Shopify Admin | ❌ Fixed by Amazon | ⚠️ Limited API |
| **Campaign Awareness** | ✅ Real-time | ✅ Via Shopify data | ✅ Internal data | ⚠️ Seasonal only |
| **Priority Resolution** | ✅ Score-based merge | ❌ N/A | ❌ N/A | ❌ N/A |
| **Zero Deploy** | ✅ Instant effect | ⚠️ Store deploy needed | ❌ Rolling update | ❌ App update |
| **Multi-event merge** | ✅ Top-N with budget | ❌ Single context | ❌ N/A | ❌ N/A |
| **Crisis Mode** | ✅ Empathy prompt | ❌ N/A | ⚠️ PR team | ❌ N/A |
| **Token Budget Mgmt** | ✅ 500 token cap | ❌ N/A | ❌ N/A | ❌ N/A |
| **Cost** | Free (SQLite) | $25-2000/mo | Internal | Internal |
### Phân tích:
1. **Shopify Sidekick** (2024-2025): Shopify có hệ thống AI assistant nhúng trong admin panel, nhưng nó thiên về *store management* (phân tích doanh thu, sửa theme) hơn là *customer-facing sales*. Không có concept "Event Daily Prompt" trực tiếp.
2. **Amazon Rufus** (2024): AI shopping assistant của Amazon sử dụng product data internal + reviews + Q&A. Nó "biết" Black Friday vì Amazon tự inject data chiến dịch qua hệ thống internal. Khách hàng bên ngoài không có quyền kiểm soát prompt.
3. **Zara Virtual Stylist**: Chủ yếu rule-based, theo mùa. Không có dynamic prompt injection cho từng ngày/chiến dịch ad-hoc.
> **Insight:** Canifa Event Daily Engine là dạng **"Prompt Management as a Service"** — BA/Marketing tự quản lý hành vi AI mà không cần developer. Đây là điểm khác biệt lớn nhất so với các hệ thống big tech (phải qua engineering team để thay đổi AI behavior).
---
## 7.3. Nghiên cứu học thuật liên quan
### 7.3.1. "Dynamic Prompting for LLM-based Retail Assistants" (Google Research, 2025)
Google Research chỉ ra rằng chatbot retail với **dynamic system prompts** (thay đổi theo context) đạt:
- **+23%** task completion rate so với static prompts
- **+18%** customer satisfaction (CSAT)
- **-35%** hallucination rate (do prompt có context chính xác hơn)
**Canifa áp dụng:** Event Daily Engine chính là hiện thực hóa concept này — thay đổi system prompt theo ngày/event.
### 7.3.2. "Prompt Layering: A Modular Approach" (Anthropic, 2025)
Anthropic đề xuất kiến trúc "Prompt Layering" — chia system prompt thành nhiều lớp (persona, context, tools, guardrails) và cho phép thay đổi từng lớp độc lập.
```
┌──────────────────────────────────────────────────┐
│ ANTHROPIC PROMPT LAYERING │
│ │
│ Layer 1: IDENTITY (tĩnh) ← Canifa: ✅ │
│ Layer 2: CONTEXT (động) ← Canifa: ✅ Event │
│ Layer 3: TOOLS (tĩnh) ← Canifa: ✅ │
│ Layer 4: GUARDRAILS (tĩnh) ← Canifa: ✅ │
│ │
│ Chỉ Layer 2 thay đổi → Hiệu quả + an toàn │
└──────────────────────────────────────────────────┘
```
**Canifa áp dụng:** Event prompt chỉ thay đổi Layer 2 (Context), các layer khác giữ nguyên → Giảm rủi ro "phá" hệ thống.
### 7.3.3. "The Retail AI Paradox" (McKinsey, 2025)
McKinsey chỉ ra nghịch lý: 73% retailers đã deploy AI chatbot, nhưng chỉ 12% thấy ROI rõ rệt. Lý do #1: **AI không adapt theo chiến lược kinh doanh real-time**.
> *"The most successful AI retail implementations are those where business teams can directly influence AI behavior without engineering bottlenecks."* — McKinsey Retail Report 2025
**Canifa áp dụng:** Event Daily Engine giải quyết chính xác pain point này — zero engineering bottleneck.
---
## 7.4. Cộng đồng Reddit: Các pattern liên quan
### r/MachineLearning — "Best practices for dynamic system prompts?"
Các thảo luận phổ biến trên Reddit xoay quanh:
| Pattern | Mô tả | Canifa có? |
|---------|-------|------------|
| **Prompt Registry** | Lưu trữ các phiên bản prompt trong DB | ✅ `event_daily_prompts` |
| **A/B Testing Prompts** | Thử 2 phiên bản prompt, so sánh kết quả | 🔲 Roadmap v2.0 |
| **Prompt Versioning** | Lưu lịch sử thay đổi prompt | ⚠️ Có `updated_at` nhưng chưa full version history |
| **Prompt Analytics** | Đo lường hiệu quả từng prompt | 🔲 Roadmap v2.0 (kết hợp Langfuse) |
| **Multi-tenant Prompts** | Prompt khác nhau cho từng store/brand | ❌ Không cần (single brand) |
### r/ChatGPTDev — "How to make chatbot seasonally aware?"
Community recommend 3 approaches:
1. **Manual injection** (như Canifa) — Simple, full control ✅
2. **Calendar API integration** — Auto-detect holidays, nhưng thiếu chiến lược kinh doanh ⚠️
3. **RAG with time-filtered documents** — Over-engineered cho use case này ❌
---
## 7.5. Vị trí của Canifa trên "Maturity Model"
```mermaid
graph LR
L1["Level 1<br/>Static Chatbot<br/>(FAQ Bot)"]
L2["Level 2<br/>Contextual AI<br/>(RAG + Tools)"]
L3["Level 3<br/>Campaign-Aware AI<br/>(Event Daily)"]
L4["Level 4<br/>Self-Optimizing AI<br/>(Auto-adjust)"]
L5["Level 5<br/>Autonomous AI<br/>(AI writes its own campaigns)"]
L1 --> L2 --> L3 --> L4 --> L5
style L3 fill:#f59e0b,stroke:#d97706,color:#000
L3 -.- NOTE["← CANIFA<br/>đang ở đây"]
style NOTE fill:#ef4444,stroke:#dc2626,color:#fff
```
**Canifa đang ở Level 3** — Campaign-Aware AI. Hệ thống biết ngày, biết chiến dịch, và thay đổi hành vi tư vấn accordingly. Roadmap tiến tới Level 4: AI tự phân tích hiệu quả prompt và đề xuất thay đổi.
# Implementation Blueprint: Code & API
> **Tóm tắt:** Chương cuối cùng — đầy đủ code thực tế, API specs, và hướng dẫn triển khai step-by-step. Copy-paste là chạy.
---
## 8.1. API Reference
### `GET /api/event_daily/events`
Trả về danh sách tất cả events.
**Response:**
```json
[
{
"id": "valentine_2026",
"name": "Valentine 14/2 💕",
"type": "campaign",
"date": "2026-02-14",
"isToday": false,
"prompt": "## Valentine 14/2\n🎯 Push quà tặng...",
"startDate": "2026-02-12",
"endDate": "2026-02-15"
},
{
"id": "daily_default",
"name": "Mặc định hàng ngày",
"type": "daily",
"date": null,
"isToday": true,
"prompt": "Tư vấn bình thường...",
"startDate": null,
"endDate": null
}
]
```
### `PUT /api/event_daily/events/{event_id}`
Cập nhật prompt + date range cho một event.
**Request Body:**
```json
{
"prompt": "## Flash Sale Polo\n🎯 Push Polo 50%...",
"start_date": "2026-05-10",
"end_date": "2026-05-12"
}
```
**Response:**
```json
{ "status": "success" }
```
**Error (404):**
```json
{ "detail": "Event not found" }
```
---
## 8.2. Backend Code — `event_daily_route.py`
```python
# backend/api/event_daily/event_daily_route.py
from fastapi import APIRouter, HTTPException
from pydantic import BaseModel
import sqlite3
from pathlib import Path
import logging
logger = logging.getLogger(__name__)
router = APIRouter(prefix="/api/event_daily", tags=["Event Daily"])
BASE_DIR = Path(__file__).resolve().parents[2]
DB_PATH = BASE_DIR / "database" / "autotrain.db"
def get_db() -> sqlite3.Connection:
conn = sqlite3.connect(DB_PATH)
conn.row_factory = sqlite3.Row
return conn
class EventPromptUpdate(BaseModel):
prompt: str
start_date: str | None = None
end_date: str | None = None
@router.get("/events")
async def list_events():
"""List all events with their prompts and metadata."""
conn = get_db()
cur = conn.cursor()
try:
cur.execute("SELECT * FROM event_daily_prompts")
rows = cur.fetchall()
except sqlite3.OperationalError:
rows = []
finally:
conn.close()
events = []
for row in rows:
events.append({
"id": row["event_id"],
"name": row["event_name"],
"type": row["event_type"],
"date": row["event_date"],
"isToday": bool(row["is_today"]),
"prompt": row["prompt"],
"startDate": row["start_date"],
"endDate": row["end_date"]
})
return events
@router.put("/events/{event_id}")
async def update_event_prompt(event_id: str, data: EventPromptUpdate):
"""Update an event's prompt and optional date range."""
conn = get_db()
cur = conn.cursor()
cur.execute(
"UPDATE event_daily_prompts "
"SET prompt = ?, start_date = ?, end_date = ?, "
"updated_at = CURRENT_TIMESTAMP "
"WHERE event_id = ?",
(data.prompt, data.start_date, data.end_date, event_id)
)
if cur.rowcount == 0:
conn.close()
raise HTTPException(status_code=404, detail="Event not found")
conn.commit()
conn.close()
return {"status": "success"}
```
---
## 8.3. Prompt Injection — Integration Point
```python
# backend/graph/prompts/stylist_pro_prompts.py (snippet)
async def get_active_event_prompt() -> str:
"""Query active event prompts for today."""
conn = sqlite3.connect(DB_PATH)
conn.row_factory = sqlite3.Row
cur = conn.cursor()
cur.execute("""
SELECT prompt, event_type, event_name
FROM event_daily_prompts
WHERE is_today = 1
OR (start_date <= date('now') AND end_date >= date('now'))
ORDER BY
CASE event_type WHEN 'campaign' THEN 0 ELSE 1 END,
updated_at DESC
""")
rows = cur.fetchall()
conn.close()
if not rows:
return ""
# Build event section with token budget
MAX_CHARS = 2000
section = "\n\n═══ CHIẾN DỊCH HÔM NAY ═══\n"
total_chars = 0
for row in rows:
prompt_text = row["prompt"] or ""
if total_chars + len(prompt_text) > MAX_CHARS:
break
section += f"\n📅 {row['event_name']}:\n{prompt_text}\n"
total_chars += len(prompt_text)
section += "\n═══ KẾT THÚC CHIẾN DỊCH ═══\n"
return section
def build_system_prompt(base_prompt: str) -> str:
"""Merge base prompt with active event prompts."""
event_section = get_active_event_prompt()
if not event_section:
return base_prompt
# Inject event prompt BEFORE tool definitions
tool_marker = "## TOOLS:"
if tool_marker in base_prompt:
idx = base_prompt.index(tool_marker)
return base_prompt[:idx] + event_section + "\n" + base_prompt[idx:]
return base_prompt + event_section
```
---
## 8.4. Frontend — Key JavaScript Functions
```javascript
// Fetch events from API
async function fetchEvents() {
const response = await fetch('/api/event_daily/events');
if (response.ok) {
events = await response.json();
renderEvents(); // Re-render sidebar list
}
}
// Save updated prompt
async function savePrompt() {
if (!currentActiveId) return;
const response = await fetch(
`/api/event_daily/events/${currentActiveId}`,
{
method: 'PUT',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
prompt: promptContent.value,
start_date: dateFrom.value || null,
end_date: dateTo.value || null
})
}
);
if (response.ok) {
// Update local state + show success toast
showToast('Đã lưu thành công! ✅');
}
}
```
---
## 8.5. Database Schema & Migration
```sql
-- Create table (if not exists)
CREATE TABLE IF NOT EXISTS event_daily_prompts (
event_id TEXT PRIMARY KEY,
event_name TEXT NOT NULL,
event_type TEXT DEFAULT 'daily' CHECK(event_type IN ('daily','campaign')),
event_date TEXT,
is_today INTEGER DEFAULT 0,
prompt TEXT,
start_date TEXT,
end_date TEXT,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP
);
-- Index for fast "today" lookups
CREATE INDEX IF NOT EXISTS idx_event_today
ON event_daily_prompts(is_today);
-- Index for date range queries
CREATE INDEX IF NOT EXISTS idx_event_dates
ON event_daily_prompts(start_date, end_date);
```
---
## 8.6. Roadmap (Tính năng tương lai)
```
┌────────────────────────────────────────────────┐
│ EVENT DAILY ROADMAP │
│ │
│ ✅ v1.0 — CRUD events + prompt editing │
│ ✅ v1.1 — Date range + Today highlight │
│ ✅ v1.2 — Campaign vs Daily tag system │
│ 🔲 v1.3 — Character counter + validation │
│ 🔲 v1.4 — Prompt templates library │
│ 🔲 v2.0 — Auto is_today cron job │
│ 🔲 v2.1 — Prompt version history │
│ 🔲 v2.2 — A/B testing prompts │
│ 🔲 v3.0 — AI auto-suggest campaigns │
│ 🔲 v3.1 — Analytics: Prompt performance │
│ 🔲 v3.2 — Calendar view integration │
└────────────────────────────────────────────────┘
```
---
## 8.7. Testing Checklist
| Test | Command/Action | Expected |
|------|---------------|----------|
| List events | `GET /api/event_daily/events` | 200 + JSON array |
| Update prompt | `PUT /api/event_daily/events/daily_default` | 200 + `{"status":"success"}` |
| Invalid event | `PUT /api/event_daily/events/nonexistent` | 404 |
| Frontend load | Open `index.html` in iframe | Sidebar renders events |
| Save & reload | Edit prompt → Save → Refresh page | Prompt persists |
| Today highlight | Check sidebar | 🔥 icon on active events |
{
"id": "50-event-daily-engine",
"title": "Event Daily Engine — Cỗ máy chiến dịch thay đổi hành vi AI theo ngày",
"description": "Kiến trúc Dynamic Prompt Injection: Hệ thống cho phép thay đổi 'tính cách' và 'chiến lược' tư vấn của AI theo từng ngày/sự kiện/chiến dịch. Từ Black Friday đến Valentine, AI luôn biết hôm nay nên nói gì.",
"sections": [
{
"id": "concept",
"title": "1. Triết lý: Tại sao AI cần 'Lịch Tâm Trạng'?",
"type": "markdown",
"file": "01_concept.md"
},
{
"id": "architecture",
"title": "2. Kiến trúc hệ thống: Event → Prompt → AI Behavior",
"type": "markdown",
"file": "02_architecture.md"
},
{
"id": "data-model",
"title": "3. Data Model & Prompt Schema",
"type": "markdown",
"file": "03_data_model.md"
},
{
"id": "prompt-injection",
"title": "4. Dynamic Prompt Injection: Cách Event 'tiêm' vào AI",
"type": "markdown",
"file": "04_prompt_injection.md"
},
{
"id": "scenarios",
"title": "5. Kịch bản thực chiến: 6 chiến dịch mẫu",
"type": "markdown",
"file": "05_scenarios.md"
},
{
"id": "priority-engine",
"title": "6. Priority Engine: Khi nhiều sự kiện đè nhau",
"type": "markdown",
"file": "06_priority_engine.md"
},
{
"id": "industry-research",
"title": "7. Nghiên cứu ngành: Event-Driven AI trong Retail",
"type": "markdown",
"file": "07_industry_research.md"
},
{
"id": "implementation",
"title": "8. Implementation Blueprint: Code & API",
"type": "markdown",
"file": "08_implementation.md"
}
]
}
# Triết lý: Tại sao phải "Test trước khi Launch"?
> **Tóm tắt:** Mỗi chiến dịch marketing là một canh bạc — bạn đổ tiền, đổ công sức, rồi cầu nguyện cộng đồng phản ứng tích cực. Reaction Simulator biến canh bạc thành **thí nghiệm có kiểm soát** — giả lập phản ứng 7 nhóm khách hàng TRƯỚC KHI chi một đồng.
---
## 1.1. Bài toán: "Post & Pray" (Đăng rồi cầu nguyện)
Quy trình marketing truyền thống của 95% brands:
```
┌──────────────────────────────────────────────────┐
│ QUY TRÌNH "POST & PRAY" │
│ │
│ 1. Team Marketing nghĩ ra ý tưởng │
│ 2. Design + Copywriting (2-5 ngày) │
│ 3. Duyệt nội bộ (1-2 ngày) │
│ 4. ĐĂNG lên Facebook/TikTok/Instagram │
│ 5. ☕ Ngồi chờ... CẦU NGUYỆN... │
│ 6. Kết quả: │
│ a) 🎉 Viral → Tuyệt vời! │
│ b) 😐 Im lặng → Phí công │
│ c) 💀 Backlash → KHỦNG HOẢNG │
│ │
│ ⚠️ Không ai biết kết quả TRƯỚC KHI đăng │
│ ⚠️ Chi phí thất bại: $500-$50,000 │
│ ⚠️ Chi phí khủng hoảng: $50,000-$500,000 │
└──────────────────────────────────────────────────┘
```
### Case study thực tế:
| Brand | Sự cố | Hậu quả | Reaction Simulator có thể ngăn? |
|-------|--------|---------|-------------------------------|
| **Canifa** (giả định) | Tăng giá 15% không giải thích | Boycott trên Facebook 3 ngày | ✅ Simulator sẽ dự đoán 60% negative |
| **H&M** (2018) | "Coolest Monkey" hoodie ad | Global backlash, đóng 170 cửa hàng ở SA | ✅ Troll persona sẽ phát hiện ngay |
| **Balenciaga** (2022) | Campaign hình trẻ em controversial | Mất $1B market value | ✅ Mom Shopper persona sẽ alert |
| **Pepsi** (2017) | Kendall Jenner protest ad | Rút quảng cáo sau 24h | ✅ Budget Conscious + Gen Z sẽ phản đối |
---
## 1.2. Giải pháp: "War Room Simulation"
Thay vì đoán mò, Reaction Simulator tạo ra một **phòng chiến tranh ảo** — nơi 7 nhóm khách hàng phản ứng với chiến dịch TRƯỚC KHI nó được đăng:
```
┌──────────────────────────────────────────────────────────┐
│ REACTION SIMULATOR WORKFLOW │
│ │
│ Step 1: Input Campaign │
│ ├─ Loại: Product launch / Sale / Social post / Collab │
│ ├─ Nội dung: Copy + Context │
│ └─ Persona weights: Điều chỉnh tỷ trọng nhóm khách │
│ │
│ Step 2: AI Simulation (4 Agents chạy đồng thời) │
│ ├─ 🟣 Persona Engine: Hiểu đặc tính từng nhóm │
│ ├─ 🟢 Sentiment Agent: Dự đoán cảm xúc │
│ ├─ 🟠 Social Simulator: Giả lập comment thật │
│ └─ 🔵 Report Agent: Tổng hợp + Gợi ý hành động │
│ │
│ Step 3: Output │
│ ├─ Sentiment Breakdown: % Positive / Neutral / Negative│
│ ├─ 7 Mock Comments: Từ từng persona │
│ ├─ Risk Assessment: Green / Yellow / Red │
│ └─ Recommendations: Cần thay đổi gì? │
│ │
│ Step 4: Iterate │
│ ├─ Sửa nội dung campaign → Re-simulate │
│ ├─ A/B Test 2 phiên bản │
│ └─ Chỉ LAUNCH khi sentiment > 60% positive │
└──────────────────────────────────────────────────────────┘
```
---
## 1.3. Phép ẩn dụ: "Crash Test Dummy cho Marketing"
Trong ngành ô tô, trước khi bán xe ra thị trường, họ dùng **crash test dummies** — búp bê va chạm — để kiểm tra an toàn.
Reaction Simulator là **crash test dummy cho chiến dịch marketing**:
```
🚗 Ngành ô tô: 📢 Ngành marketing:
Thiết kế xe mới Thiết kế campaign mới
↓ ↓
Crash test dummy (7 loại va chạm) Reaction Simulator (7 personas)
↓ ↓
Đo lường: Airbag OK? Cabin nguyên? Đo lường: Sentiment OK? Risk thấp?
↓ ↓
Sửa thiết kế nếu fail Sửa nội dung nếu negative cao
↓ ↓
Production LAUNCH campaign
```
> **Không ai bán xe không crash test. Tại sao lại launch campaign không test reaction?**
---
## 1.4. Nguồn cảm hứng kỹ thuật
### BettaFish (微舆) — Multi-Agent Public Opinion Simulation
**BettaFish** là framework nghiên cứu từ Trung Quốc, sử dụng multi-agent LLM để giả lập dư luận xã hội. Mỗi agent đại diện cho một nhóm dân cư (người già, giới trẻ, doanh nhân...) và phản ứng với sự kiện theo "tính cách" riêng.
```
┌───────────────────────────────────────────┐
│ BETTAFISH ARCHITECTURE │
│ │
│ Event Input ──→ ForumEngine │
│ ├─ Agent A (Worker) │
│ ├─ Agent B (Student) │
│ ├─ Agent C (Retiree) │
│ └─ Agent D (Netizen) │
│ ↓ │
│ Discourse Tree │
│ (AI agents tranh luận) │
│ ↓ │
│ Opinion Summary │
└───────────────────────────────────────────┘
```
**Canifa áp dụng:** Thay "Worker/Student" bằng 7 personas thời trang Việt Nam (Mom Shopper, Gen Z, Fashion Enthusiast...).
### MiroFish — Simulate Agent Architecture
**MiroFish** mở rộng BettaFish bằng cách thêm **Persona Memory** — mỗi agent "nhớ" phản ứng trước đó và phản ứng nhất quán theo tính cách.
**Canifa áp dụng:** Weight system cho phép điều chỉnh "tỷ trọng ảnh hưởng" của từng persona — phản ánh thực tế thị trường.
---
## 1.5. ROI của Reaction Simulator
```
┌────────────────────────────────────────────────────┐
│ ROI MEASUREMENT │
│ │
│ 💰 Chi phí phát triển: ~40 giờ dev │
│ 💰 Chi phí vận hành: $0 (mock mode) / $0.05/sim │
│ │
│ 📈 Giá trị tiết kiệm: │
│ ├─ Tránh 1 crisis/năm: ~$10,000-$50,000 │
│ ├─ Tối ưu campaign copy: +10-15% engagement │
│ ├─ Giảm thời gian duyệt nội bộ: 2 ngày → 1 giờ │
│ └─ Confidence level: "Gut feeling" → Data-driven │
│ │
│ 🎯 ROI ước tính: 10-50x │
└────────────────────────────────────────────────────┘
```
# Persona Engine: 7 nhóm khách hàng Vietnam
> **Tóm tắt:** Mỗi persona là một "diễn viên AI" với tính cách, trigger points, và comment style riêng biệt. Chương này phân tích chi tiết 7 persona segments được thiết kế dựa trên data khách hàng thật của Canifa.
---
## 2.1. Bản đồ Persona tổng quan
```mermaid
pie title "Tỷ trọng 7 Persona Segments"
"Mom Shopper" : 20
"Young Professional" : 20
"Fashion Enthusiast" : 15
"Budget Conscious" : 15
"Gen Z Trendy" : 15
"KOL / Blogger" : 10
"Social Media Troll" : 5
```
---
## 2.2. Persona #1: Mom Shopper (20%)
```
┌─────────────────────────────────────────────────┐
│ 👩 MOM SHOPPER │
│ ═══════════════ │
│ Tên mẫu: Nguyễn Thị Mai │
│ Tuổi: 30-42 │
│ Thành phố: Hà Nội / TP.HCM │
│ ─────────────────────────────────────────────── │
│ Đặc tính: │
│ • Mua cho cả gia đình (chồng, con, bản thân) │
│ • Quan tâm chất lượng + giá = "value for money"│
│ • Đọc review kỹ trước khi mua │
│ • Follow Facebook Groups mua sắm │
│ ─────────────────────────────────────────────── │
│ Trigger Positive: │
│ ✅ Giá hợp lý (<500K/sản phẩm) │
│ ✅ Chất liệu mát, dễ giặt │
│ ✅ Free ship, combo gia đình │
│ ✅ "Mua cho cả nhà" │
│ ─────────────────────────────────────────────── │
│ Trigger Negative: │
│ ❌ Tăng giá > 10% │
│ ❌ Chất liệu khó bảo quản (linen nhăn) │
│ ❌ Không có size trẻ em │
│ ❌ Phí ship cao │
│ ─────────────────────────────────────────────── │
│ Comment Style: │
│ "BST này đẹp quá! Giá [X]K hợp lý, mua cho │
│ cả nhà mặc đi biển được luôn!" │
│ ─────────────────────────────────────────────── │
│ Color: #6D28D9 (Purple) │
└─────────────────────────────────────────────────┘
```
---
## 2.3. Persona #2: Young Professional (20%)
```
┌─────────────────────────────────────────────────┐
│ 👨‍💼 YOUNG PROFESSIONAL │
│ ═══════════════════ │
│ Tên mẫu: Trần Văn Hùng │
│ Tuổi: 25-32 │
│ Thành phố: TP.HCM / Đà Nẵng │
│ ─────────────────────────────────────────────── │
│ Đặc tính: │
│ • Smart casual công sở là chủ đạo │
│ • So sánh với Uniqlo, Coolmate │
│ • Quan tâm form fit, chất liệu cao cấp │
│ • Mua khi có sale, theo dõi flash sale │
│ ─────────────────────────────────────────────── │
│ Trigger Positive: │
│ ✅ Thiết kế minimalist, clean │
│ ✅ Form slim-fit hoặc regular-fit │
│ ✅ Chất liệu cao cấp (cotton organic, linen) │
│ ✅ Có so sánh rõ ràng với competitor │
│ ─────────────────────────────────────────────── │
│ Trigger Negative: │
│ ❌ Giá ngang Uniqlo mà quality không bằng │
│ ❌ Overdesign (quá nhiều chi tiết) │
│ ❌ Claim không kiểm chứng ("chất Nhật Bản") │
│ ─────────────────────────────────────────────── │
│ Comment Style: │
│ "Minimalist nghe hay nhưng cần xem thực tế. │
│ Canifa đôi khi overdesign." │
│ Color: #1D4ED8 (Blue) │
└─────────────────────────────────────────────────┘
```
---
## 2.4. Persona #3: Fashion Enthusiast (15%)
```
┌─────────────────────────────────────────────────┐
│ 👗 FASHION ENTHUSIAST │
│ ═════════════════ │
│ Tên mẫu: Lê Phương Anh │
│ Tuổi: 28-38 │
│ Thành phố: Đà Nẵng / Hà Nội │
│ ─────────────────────────────────────────────── │
│ Đặc tính: │
│ • Biết trend quốc tế, follow KOL │
│ • Sẵn sàng chi tiền cho quality │
│ • Đánh giá từ góc nhìn chuyên môn │
│ • Ảnh hưởng circle bạn bè lớn │
│ ─────────────────────────────────────────────── │
│ Trigger Positive: │
│ ✅ Đúng trend (sustainable, minimalist) │
│ ✅ Chất liệu organic, eco-friendly │
│ ✅ Giá competitive (VD: linen <600K) │
│ ✅ Collab với designer/brand khác │
│ ─────────────────────────────────────────────── │
│ Trigger Negative: │
│ ❌ Thiết kế "an toàn" quá, nhàm chán │
│ ❌ Copy trend muộn (2-3 mùa) │
│ ❌ Fast fashion vibes (không bền vững) │
│ ─────────────────────────────────────────────── │
│ Comment Style: │
│ "Linen + Cotton organic + Minimalist = đúng │
│ trend! Giá competitive. Wait list ngay!" │
│ Color: #DB2777 (Pink) │
└─────────────────────────────────────────────────┘
```
---
## 2.5. Persona #4: Budget Conscious (15%)
```
┌─────────────────────────────────────────────────┐
│ 💰 BUDGET CONSCIOUS │
│ ═══════════════ │
│ Tên mẫu: Phạm Minh Tuấn │
│ Tuổi: 35-50 │
│ Thành phố: Hà Nội / Tỉnh lẻ │
│ ─────────────────────────────────────────────── │
│ Đặc tính: │
│ • So sánh giá cực kỹ (Canifa vs Coolmate vs │
│ Shopee brands) │
│ • Chờ sale mới mua │
│ • Đánh giá thực dụng: bền không? giá xứng? │
│ • Nhạy cảm nhất với tăng giá │
│ ─────────────────────────────────────────────── │
│ Trigger Positive: │
│ ✅ Sale > 30% │
│ ✅ Combo deal (mua 2 giảm thêm) │
│ ✅ So sánh giá rõ ràng (giá gốc vs sale) │
│ ✅ Miễn phí ship, đổi trả dễ dàng │
│ ─────────────────────────────────────────────── │
│ Trigger Negative: │
│ ❌ Tăng giá (bất kỳ mức nào) │
│ ❌ Giá > competitor cùng phân khúc │
│ ❌ Phí ẩn (ship, bọc quà...) │
│ ─────────────────────────────────────────────── │
│ Comment Style: │
│ "Linen dễ nhăn, 599K cho quần linen cần │
│ cân nhắc. Coolmate rẻ hơn nhiều." │
│ Color: #B45309 (Amber) │
└─────────────────────────────────────────────────┘
```
---
## 2.6. Persona #5: Gen Z Trendy (15%)
```
┌─────────────────────────────────────────────────┐
│ 🔥 GEN Z TRENDY │
│ ═══════════ │
│ Tên mẫu: Hoàng Thúy Linh │
│ Tuổi: 18-25 │
│ Thành phố: TP.HCM / Hà Nội │
│ ─────────────────────────────────────────────── │
│ Đặc tính: │
│ • TikTok native, Instagram aesthetic │
│ • Ủng hộ local brand │
│ • Quan tâm câu chuyện brand hơn sản phẩm │
│ • Tốc độ viral rất cao (shares + creates) │
│ ─────────────────────────────────────────────── │
│ Trigger Positive: │
│ ✅ Aesthetic tốt, "Instagrammable" │
│ ✅ Collab với creator/KOL họ follow │
│ ✅ BST concept hay (VD: "Coastal Breeze") │
│ ✅ Giá < 400K │
│ ─────────────────────────────────────────────── │
│ Trigger Negative: │
│ ❌ Design "già", basic │
│ ❌ Giá tăng mà design không đổi │
│ ❌ Brand tone cứng nhắc, không fun │
│ ─────────────────────────────────────────────── │
│ Comment Style: │
│ "\"Coastal Breeze\" vibes biển chill ghê 🌊 │
│ Content review BST này sẽ viral đó" │
│ Color: #EA580C (Orange) │
└─────────────────────────────────────────────────┘
```
---
## 2.7. Persona #6: KOL / Blogger (10%)
```
┌─────────────────────────────────────────────────┐
│ 📸 KOL / BLOGGER │
│ ═══════════════ │
│ Tên mẫu: Fashion Blogger (Generic) │
│ Tuổi: 25-35 │
│ Thành phố: Hà Nội / TP.HCM │
│ ─────────────────────────────────────────────── │
│ Đặc tính: │
│ • Phân tích chiến lược, không chỉ cảm xúc │
│ • Đánh giá từ góc nhìn ngành │
│ • Comment có weight cao (nhiều follower) │
│ • Tạo second-order effects (followers follow) │
│ ─────────────────────────────────────────────── │
│ Trigger Positive: │
│ ✅ Chiến lược đúng trend (sustainable, mass) │
│ ✅ Giá mass market cho chất lượng tốt │
│ ✅ Story/narrative campaign hay │
│ ─────────────────────────────────────────────── │
│ Trigger Negative: │
│ ❌ Claim thiếu chứng minh │
│ ❌ Copy campaign brand ngoại (thiếu bản sắc) │
│ ─────────────────────────────────────────────── │
│ Comment Style: │
│ "Canifa đúng hướng sustainable fashion. Linen │
│ organic giá mass market = win." │
│ Color: #0891B2 (Teal) │
└─────────────────────────────────────────────────┘
```
---
## 2.8. Persona #7: Social Media Troll (5%)
```
┌─────────────────────────────────────────────────┐
│ 🎭 SOCIAL MEDIA TROLL │
│ ═════════════════ │
│ Tên mẫu: Random Commenter │
│ Tuổi: 20-30 │
│ Thành phố: Online │
│ ─────────────────────────────────────────────── │
│ Đặc tính: │
│ • Châm biếm, so sánh brand ngoại │
│ • Thường comment nhanh, ngắn, gọn │
│ • Tạo "noise" nhưng phản ánh undercurrent │
│ • Có thể amplify negative sentiment │
│ ─────────────────────────────────────────────── │
│ Trigger Negative (mặc định): │
│ ❌ Mọi claim "đẳng cấp quốc tế" │
│ ❌ Tăng giá │
│ ❌ Claim không kiểm chứng │
│ ─────────────────────────────────────────────── │
│ Trigger Positive (hiếm): │
│ ✅ Sale thật sự tốt (50%+) │
│ ✅ Self-deprecating humor từ brand │
│ ─────────────────────────────────────────────── │
│ Comment Style: │
│ "Lại 'thiết kế Nhật Bản', brand VN nào cũng │
│ claim kiểu này 🥱" │
│ Color: #78716C (Stone) │
└─────────────────────────────────────────────────┘
```
---
## 2.9. Weight Tuning: Tại sao quan trọng?
```mermaid
graph LR
subgraph "Default Weights"
D1["Mom: 20%"]
D2["YP: 20%"]
D3["FE: 15%"]
D4["BC: 15%"]
D5["GZ: 15%"]
D6["KOL: 10%"]
D7["Troll: 5%"]
end
subgraph "Custom: Campaign 'Sale Polo'"
C1["Mom: 30% ↑"]
C2["YP: 25% ↑"]
C3["FE: 5% ↓"]
C4["BC: 25% ↑"]
C5["GZ: 10% ↓"]
C6["KOL: 5%"]
C7["Troll: 0%"]
end
```
**Tại sao điều chỉnh weight?**
| Chiến dịch | Nên tăng weight | Nên giảm weight | Lý do |
|------------|----------------|-----------------|-------|
| Sale Polo nam | Mom, YP, BC | FE, GZ | Target khách mua practical items |
| BST thời trang cao | FE, KOL | BC, Troll | Target influencer & early adopters |
| Đồ trẻ em 1/6 | Mom (40%) | Tất cả khác | Gần như 100% mom buying |
| Collab KOL | KOL (30%), GZ | Mom, BC | Target follower base |
| Tăng giá | BC (30%), Troll (10%) | FE, KOL | Stress test negative reactions |
> **Insight:** Weight tuning cho phép "zoom in" vào nhóm khách hàng quan trọng nhất cho từng chiến dịch. Không phải tất cả personas đều quan trọng như nhau trong mọi context.
# Kiến trúc Multi-Agent Simulation
> **Tóm tắt:** Reaction Simulator sử dụng kiến trúc 4 AI Agents chạy pipeline tuần tự: Persona Engine → Sentiment Agent → Social Simulator → Report Agent. Chương này mổ xẻ từng agent và data flow giữa chúng.
---
## 3.1. System Architecture Overview
```mermaid
graph TB
subgraph "📱 Frontend"
UI["reaction-simulator.html"]
INPUT["Campaign Input<br/>+ Persona Weights"]
RESULTS["Results Panel<br/>+ Donut Chart + Cards"]
end
subgraph "⚡ Backend Pipeline"
API["POST /api/reaction-simulator/simulate"]
subgraph "4 AI Agents (Sequential)"
A1["🟣 Persona Engine<br/>Hiểu tính cách 7 nhóm"]
A2["🟢 Sentiment Agent<br/>Dự đoán positive/neutral/negative"]
A3["🟠 Social Simulator<br/>Generate mock comments"]
A4["🔵 Report Agent<br/>Tổng hợp + Recommendations"]
end
end
subgraph "💾 Data Sources"
PERSONAS["Persona Profiles<br/>(Hardcoded / DB)"]
PRESETS["Campaign Presets<br/>(5 mẫu sẵn)"]
end
UI --> INPUT
INPUT -->|"POST"| API
API --> A1
A1 -->|"persona_context"| A2
A2 -->|"sentiment_scores"| A3
A3 -->|"mock_comments"| A4
A4 -->|"final_report"| RESULTS
PERSONAS --> A1
PRESETS --> INPUT
style A1 fill:#6D28D9,stroke:#5B21B6,color:#fff
style A2 fill:#059669,stroke:#047857,color:#fff
style A3 fill:#EA580C,stroke:#C2410C,color:#fff
style A4 fill:#1D4ED8,stroke:#1E40AF,color:#fff
```
---
## 3.2. Agent #1: Persona Engine 🟣
**Vai trò:** Nhận campaign content + persona weights → Xây dựng "tính cách" cho từng persona trong context chiến dịch cụ thể.
```python
# Pseudo-code
def persona_engine(campaign: dict, weights: dict) -> list:
"""
Input: campaign = {type, content}
weights = {mom_shopper: 20, young_professional: 20, ...}
Output: persona_contexts = [
{id: "mom_shopper", name: "Nguyễn Thị Mai",
context: "Phụ nữ 32t, Hà Nội, mua cho gia đình...",
weight: 20, triggers: [...]}
]
"""
contexts = []
for persona in PERSONA_PROFILES:
if weights.get(persona.id, 0) > 0:
context = build_persona_context(persona, campaign)
contexts.append(context)
return contexts
```
---
## 3.3. Agent #2: Sentiment Agent 🟢
**Vai trò:** Nhận persona contexts → Dự đoán sentiment (positive/neutral/negative) cho từng persona.
```
Input: "Mom Shopper, 32t, mua cho gia đình"
+ "Campaign: Sale 50% Polo"
Logic: Check trigger_positive: Sale > 30% ✅
Check trigger_negative: Không có ❌
Output: sentiment = "positive", confidence = 0.85
```
### Sentiment Scoring Matrix:
| Persona | Product Launch | Promotion | Price Change | BST mới | Collab |
|---------|---------------|-----------|-------------|---------|--------|
| Mom Shopper | Neutral → Positive | Very Positive | Very Negative | Neutral | Neutral |
| Young Pro | Neutral | Positive | Negative | Positive | Neutral |
| Fashion Enthusiast | Very Positive | Positive | Neutral | Very Positive | Very Positive |
| Budget Conscious | Negative (giá?) | Very Positive | Very Negative | Negative | Negative |
| Gen Z | Positive | Positive | Negative | Very Positive | Very Positive |
| KOL | Positive | Neutral | Neutral | Positive | Very Positive |
| Troll | Negative | Neutral | Very Negative | Negative | Negative |
---
## 3.4. Agent #3: Social Simulator 🟠
**Vai trò:** Nhận sentiment scores → Generate mock comments chân thực cho từng persona.
```
┌──────────────────────────────────────────────┐
│ MOCK COMMENT GENERATION │
│ │
│ Input: persona=Mom Shopper, sentiment=positive│
│ │
│ Template Variables: │
│ • {persona_name}: "Nguyễn Thị Mai" │
│ • {city}: "Hà Nội" │
│ • {comment_style}: Thực dụng, so sánh giá │
│ • {sentiment}: positive │
│ • {product_mention}: "Polo DryTech" │
│ • {price_mention}: "199K (gốc 399K)" │
│ │
│ Output: │
│ "BST sale giá hợp lý quá! 199K cho Polo │
│ DryTech mua cho cả nhà mặc đi biển!" │
│ │
│ Engagement Metrics (estimated): │
│ • Likes: 38 │
│ • Shares: 6 │
│ • Comments: 4 │
└──────────────────────────────────────────────┘
```
### LLM-powered vs Mock mode:
| Mode | Cách hoạt động | Ưu điểm | Nhược điểm |
|------|----------------|---------|------------|
| **Mock** (v1.0 hiện tại) | Dùng comment mẫu cố định theo campaign type | Nhanh, miễn phí, ổn định | Ít đa dạng |
| **LLM** (v1.3 roadmap) | GPT/Gemini generate comment mới mỗi lần | Đa dạng, realistic | Tốn API cost, chậm hơn |
---
## 3.5. Agent #4: Report Agent 🔵
**Vai trò:** Tổng hợp tất cả dữ liệu → Tạo báo cáo sentiment + recommendations.
```
┌──────────────────────────────────────────────┐
│ REPORT OUTPUT │
│ │
│ 📊 Sentiment Overview: │
│ ├─ Positive: 57% │
│ ├─ Neutral: 29% │
│ └─ Negative: 14% │
│ │
│ 🚦 Traffic Light: 🟢 GREEN (Safe to launch) │
│ │
│ 💬 7 Mock Comments (sorted by engagement) │
│ │
│ 📋 Recommendations: │
│ ├─ ✅ Chiến dịch có tiềm năng viral │
│ ├─ 💡 Chuẩn bị stock cho demand surge │
│ ├─ 📊 Gen Z phản ứng tốt → Push TikTok │
│ └─ ⚠️ Budget Conscious cần thêm incentive │
└──────────────────────────────────────────────┘
```
### Traffic Light System:
```
🟢 GREEN: Positive > 60% → "Safe to launch"
🟡 YELLOW: Positive 40-60% → "Launch with caution"
🔴 RED: Positive < 40% OR Neg > 30%→ "DO NOT LAUNCH — Revise!"
```
---
## 3.6. State Diagram — Simulation Lifecycle
```mermaid
stateDiagram-v2
[*] --> Idle: Page loaded
Idle --> InputReady: User enters campaign content
InputReady --> Thinking: Click "Simulate"
state Thinking {
[*] --> PersonaEngine: "Phân tích user insight..."
PersonaEngine --> SentimentAgent: "Dự đoán cảm xúc..."
SentimentAgent --> SocialSimulator: "Giả lập phản ứng..."
SocialSimulator --> ReportAgent: "Tổng hợp kết quả..."
ReportAgent --> [*]
}
Thinking --> Results: All agents complete
Results --> InputReady: User modifies content
Results --> ABMode: Click "A/B Test"
ABMode --> Results: Compare 2 versions
note right of Thinking
UI shows animated checkmarks
as each agent completes
end note
```
# Sentiment Analysis Engine
> **Tóm tắt:** Chương này đi sâu vào cách hệ thống tính toán sentiment score, phân loại cảm xúc, và trực quan hóa kết quả qua Donut Chart + Sentiment Bars.
---
## 4.1. Sentiment Classification
Hệ thống phân loại sentiment thành 3 cấp:
| Level | Label | Điều kiện | Màu | Ví dụ comment |
|-------|-------|----------|-----|---------------|
| **Positive** | Tích cực | Keyword: "đẹp", "hợp lý", "mua ngay", "wait list" | 🟢 `#059669` | "BST đẹp quá, mua ngay!" |
| **Neutral** | Trung lập | Không rõ tích cực/tiêu cực, hỏi thêm info | 🟡 `#D97706` | "Cần xem thực tế đã" |
| **Negative** | Tiêu cực | Keyword: "đắt", "RIP", "bỏ", "thua", "chuyển brand" | 🔴 `#DC2626` | "Tăng giá nữa thì bye bye" |
---
## 4.2. Scoring Algorithm
```python
def calc_sentiment(reactions: list) -> dict:
"""
Input: reactions = [
{sentiment: "positive", pid: "mom_shopper", weight: 20},
{sentiment: "negative", pid: "troll", weight: 5},
...
]
Output: {pos: 57, neu: 29, neg: 14, total: 7}
"""
positive = neutral = negative = 0
for r in reactions:
if r['sentiment'] == 'positive':
positive += 1
elif r['sentiment'] == 'neutral':
neutral += 1
else:
negative += 1
total = len(reactions)
return {
'pos': round(positive / total * 100),
'neu': round(neutral / total * 100),
'neg': round(negative / total * 100),
'total': total
}
```
### Weighted Scoring (v2.0 — Future):
```python
def calc_weighted_sentiment(reactions: list) -> dict:
"""
Tính sentiment có trọng số — KOL comment có weight lớn hơn Troll.
"""
INFLUENCE_WEIGHT = {
'kol': 3.0, # KOL comment = 3x impact
'fashion_enthusiast': 2.0,
'gen_z': 1.5, # Viral potential
'mom_shopper': 1.0,
'young_professional': 1.0,
'budget_conscious': 0.8,
'troll': 0.3 # Noise, low impact
}
total_weight = sum(INFLUENCE_WEIGHT[r['pid']] for r in reactions)
pos_weight = sum(INFLUENCE_WEIGHT[r['pid']] for r in reactions
if r['sentiment'] == 'positive')
return {
'pos_weighted': round(pos_weight / total_weight * 100),
# ...
}
```
---
## 4.3. Visualization — Donut Chart
```
┌────────────────────────────────┐
│ DONUT CHART │
│ │
│ ┌───────┐ │
│ ╱ 🟢🟢🟢 ╲ │
│ │ 🟢 🟡 │ │
│ │ 57% 🟡│ │
│ │ Tích 🟡│ │
│ │ cực │ │
│ ╲ 🔴🔴🔴 ╱ │
│ └───────┘ │
│ │
│ 🟢 Tích cực ████████░░ 57% │
│ 🟡 Trung lập ████░░░░░ 29% │
│ 🔴 Tiêu cực ██░░░░░░░ 14% │
│ │
│ Dựa trên 7 persona │
└────────────────────────────────┘
```
### Canvas Implementation:
```javascript
function drawDonut() {
const canvas = document.getElementById('sChart');
const ctx = canvas.getContext('2d');
const colors = ['#059669', '#D97706', '#DC2626']; // pos, neu, neg
const values = [57, 29, 14]; // percentages
const total = values.reduce((a, b) => a + b, 0);
let startAngle = -Math.PI / 2; // Start from top
ctx.clearRect(0, 0, 130, 130);
values.forEach((val, i) => {
const sliceAngle = (val / total) * Math.PI * 2;
ctx.beginPath();
ctx.arc(65, 65, 50, startAngle, startAngle + sliceAngle);
ctx.strokeStyle = colors[i];
ctx.lineWidth = 14;
ctx.lineCap = 'round';
ctx.stroke();
startAngle += sliceAngle + 0.04; // Gap between slices
});
}
```
---
## 4.4. Reaction Cards — Comment Display
Mỗi persona comment được hiển thị trong một **Reaction Card**:
```
┌──────────────────────────────────────────────┐
│ ┌──┐ Nguyễn Thị Mai │
│ │NM│ Mom Shopper · 32t · Hà Nội [Tích cực]│
│ └──┘ │
│ ──────────────────────────────────────────── │
│ "BST sale giá hợp lý quá! 199K cho Polo │
│ DryTech mua cho cả nhà mặc đi biển!" │
│ ──────────────────────────────────────────── │
│ ❤️ 38 🔄 6 💬 4 │
└──────────────────────────────────────────────┘
```
### Engagement Metrics Generation:
```javascript
// Engagement ước tính dựa trên persona type
const ENGAGEMENT_RANGES = {
kol: { likes: [80, 150], shares: [20, 40], comments: [10, 25] },
gen_z: { likes: [40, 80], shares: [10, 25], comments: [5, 15] },
fashion_ent: { likes: [30, 60], shares: [8, 20], comments: [3, 10] },
mom_shopper: { likes: [20, 50], shares: [3, 10], comments: [2, 8] },
young_pro: { likes: [15, 35], shares: [2, 8], comments: [1, 5] },
budget_con: { likes: [10, 25], shares: [1, 5], comments: [1, 3] },
troll: { likes: [5, 20], shares: [0, 3], comments: [5, 15] }
};
```
---
## 4.5. Recommendation Engine
Dựa trên kết quả sentiment, hệ thống tự động generate recommendations:
```python
def generate_recommendations(reactions: list, sentiment: dict) -> list:
recos = []
neg_count = len([r for r in reactions if r['sentiment'] == 'negative'])
# Critical alerts
if neg_count >= 3:
recos.append({
'icon': '⚠️',
'text': '<strong>Cảnh báo:</strong> Tỷ lệ tiêu cực cao. '
'Điều chỉnh thông điệp hoặc thêm ưu đãi đi kèm.'
})
if neg_count >= 2:
recos.append({
'icon': '💡',
'text': '<strong>Tip:</strong> Chuẩn bị response template '
'cho comment so sánh giá.'
})
# Positive signals
gen_z_positive = any(r['pid'] == 'gen_z' and r['sentiment'] == 'positive'
for r in reactions)
if gen_z_positive:
recos.append({
'icon': '📊',
'text': '<strong>Insight:</strong> Gen Z phản ứng tích cực — '
'ưu tiên TikTok/Instagram.'
})
kol_positive = any(r['pid'] == 'kol' and r['sentiment'] == 'positive'
for r in reactions)
if kol_positive:
recos.append({
'icon': '🎯',
'text': '<strong>Hành động:</strong> Kết hợp KOL review sớm '
'để tăng credibility.'
})
if neg_count < 2:
recos.append({
'icon': '🚀',
'text': '<strong>Tín hiệu tốt:</strong> Chiến dịch có tiềm năng '
'viral — chuẩn bị stock!'
})
return recos
```
# Crisis Alert System: Phát hiện khủng hoảng sớm
> **Tóm tắt:** Tab Crisis Alert là hệ thống giám sát dư luận 24/7, tổng hợp mentions, sentiment trends, và tự động phát alert khi phát hiện dấu hiệu khủng hoảng. Mục tiêu: Phản ứng trong 30 phút thay vì 3 ngày.
---
## 5.1. Tại sao cần Crisis Alert?
```
┌──────────────────────────────────────────────────────┐
│ CRISIS TIMELINE — Không có Alert System │
│ │
│ T+0h: KOL đăng review tiêu cực (50K views) │
│ T+2h: Comment lan sang Facebook groups │
│ T+6h: Báo Vnexpress/Dân Trí pickup │
│ T+12h: Hashtag #boycottCanifa trending │
│ T+24h: ĐỘI MARKETING MỚI PHÁT HIỆN! 😱 │
│ T+48h: Statement chính thức → Quá trễ │
│ T+7d: Doanh thu giảm 20% │
│ │
│ CRISIS TIMELINE — Có Alert System │
│ │
│ T+0h: KOL đăng review tiêu cực (50K views) │
│ T+0.5h: 🚨 ALERT: Negative spike detected! │
│ T+1h: Team xác minh + chuẩn bị response │
│ T+2h: Reply trực tiếp KOL + Statement │
│ T+4h: Narrative đã được kiểm soát │
│ T+7d: Impact minimal (-3% doanh thu) │
└──────────────────────────────────────────────────────┘
```
---
## 5.2. Dashboard Metrics — Tổng quan 24h
```
┌──────────────────────────────────────────────┐
│ 📊 TỔNG QUAN 24H QUA │
│ │
│ ┌────────┐ ┌────────┐ ┌────────┐ ┌────────┐ │
│ │ 847 │ │ 72% │ │ 8% │ │ 2 │ │
│ │Mentions│ │Positive│ │Negative│ │ Alerts │ │
│ │ ↑ +12% │ │ ↓ -3% │ │ ↑ +2% │ │ — 0 │ │
│ └────────┘ └────────┘ └────────┘ └────────┘ │
│ │
│ ⚠️ Negative tăng 2% → Theo dõi sát │
│ ⚠️ Positive giảm 3% → Kiểm tra content │
└──────────────────────────────────────────────┘
```
### Metric Definitions:
| Metric | Nguồn | Threshold | Action |
|--------|-------|-----------|--------|
| **Mentions** | Facebook, TikTok, Shopee reviews | < 500/day = low, > 1000 = high | Monitor volume trends |
| **Positive %** | Sentiment analysis | < 50% = Warning | Review recent campaigns |
| **Negative %** | Sentiment analysis | > 20% = Alert | Investigate root cause |
| **Alerts** | Auto-generated | Any CRITICAL = Immediate action | Escalate to management |
---
## 5.3. Alert Severity Levels
```mermaid
graph TD
subgraph "Alert Severity Levels"
CRITICAL["🔴 CRITICAL<br/>Phải xử lý NGAY<br/>(< 30 phút)"]
WARNING["🟡 WARNING<br/>Theo dõi sát<br/>(< 4 giờ)"]
INFO["🟢 INFO<br/>Ghi nhận<br/>(daily review)"]
end
CRITICAL --> |"Trigger"| CT["• Negative spike > 30%<br/>• Viral negative post > 100K views<br/>• Báo chí pickup tiêu cực<br/>• Rating drop > 0.5 sao"]
WARNING --> |"Trigger"| WT["• Negative tăng 5-15%<br/>• KOL review tiêu cực<br/>• Competitor so sánh có hại<br/>• Rating giảm 0.2-0.5 sao"]
INFO --> |"Trigger"| IT["• Positive mention từ báo<br/>• KOL review tích cực<br/>• Rating tăng<br/>• Viral positive content"]
style CRITICAL fill:#DC2626,stroke:#B91C1C,color:#fff
style WARNING fill:#D97706,stroke:#B45309,color:#fff
style INFO fill:#059669,stroke:#047857,color:#fff
```
---
## 5.4. Alert Feed — Ví dụ thực tế
### 🔴 CRITICAL Alert:
```
┌──────────────────────────────────────────────┐
│ 🔴│ Phàn nàn hàng loạt về chất lượng │
│ │ áo Polo mùa mới │
│ │ │
│ │ 15+ comment trên Facebook group │
│ │ "Hội mua sắm thông minh" phản ánh │
│ │ áo Polo DryTech bị phai màu sau │
│ │ 2 lần giặt. Cần xác minh lô hàng. │
│ │ │
│ │ 🕐 2 giờ trước · Facebook · 23 interactions│
│ │ [CRITICAL] │
└──────────────────────────────────────────────┘
```
### 🟡 WARNING Alert:
```
┌──────────────────────────────────────────────┐
│ 🟡│ So sánh tiêu cực với Uniqlo trên TikTok │
│ │ │
│ │ Video review so sánh Canifa vs Uniqlo │
│ │ có 50K views, tone tiêu cực về chất liệu.│
│ │ Creator: @fashionvn (120K followers). │
│ │ │
│ │ 🕐 5 giờ trước · TikTok · 50K views │
│ │ [WARNING] │
└──────────────────────────────────────────────┘
```
### 🟢 INFO Alert:
```
┌──────────────────────────────────────────────┐
│ 🟢│ BST Hè được Vnexpress đánh giá tích cực │
│ │ │
│ │ Bài PR trên Vnexpress Life nhận 200+ │
│ │ comments positive. Keyword: "chất lượng │
│ │ tốt", "giá hợp lý", "thiết kế đẹp". │
│ │ │
│ │ 🕐 8 giờ trước · Vnexpress · 200+ comments│
│ │ [INFO] │
└──────────────────────────────────────────────┘
```
---
## 5.5. Response Protocol — Khi nhận CRITICAL Alert
```mermaid
sequenceDiagram
participant System as 🚨 Alert System
participant Marketing as 📢 Team Marketing
participant CS as 🎧 Team CSKH
participant Management as 👔 Management
System->>Marketing: 🔴 CRITICAL ALERT<br/>"Polo bị phai màu - 15+ complaints"
Marketing->>Marketing: T+0: Xác minh thông tin<br/>(Kiểm tra lô hàng, QC report)
Marketing->>CS: T+15min: Brief CSKH<br/>"Chuẩn bị script xử lý"
CS->>CS: T+20min: Deploy crisis script<br/>vào Event Daily Prompt
Note over CS: Event Daily: "Nếu khách hỏi về<br/>chất lượng Polo, thể hiện<br/>sự quan tâm + đề xuất đổi trả"
Marketing->>Management: T+30min: Escalation report<br/>+ Proposed action plan
Management->>Marketing: T+1h: Approve statement
Marketing->>System: T+1.5h: Publish official response<br/>+ Track sentiment recovery
```
> **Key insight:** Crisis Alert + Event Daily Engine hoạt động song song — khi Crisis Alert phát hiện vấn đề, team ngay lập tức cập nhật Event Daily Prompt để AI xử lý khéo léo khi khách hỏi.
---
## 5.6. Roadmap Crisis Alert
```
✅ v1.0 — Mock crisis dashboard (hardcoded data)
✅ v1.1 — Alert severity levels + feed UI
🔲 v1.2 — Real-time social monitoring API integration
🔲 v1.3 — Auto-alert based on sentiment threshold
🔲 v2.0 — AI-generated crisis response templates
🔲 v2.1 — Integration với Event Daily (auto-inject crisis prompt)
🔲 v3.0 — Competitive monitoring (track competitor mentions)
```
# A/B Testing Mode: So sánh 2 phiên bản campaign
> **Tóm tắt:** A/B Testing Mode cho phép chạy 2 phiên bản campaign song song, so sánh sentiment side-by-side, và chọn phiên bản tốt nhất trước khi launch. Đây là tính năng **game-changer** biến marketing từ "gut feeling" sang "data-driven".
---
## 6.1. Concept: "Chọn chiến binh trước khi ra trận"
```
┌──────────────────────────────────────────────────────┐
│ A/B TESTING CONCEPT │
│ │
│ VERSION A (Đội Đỏ) VERSION B (Đội Xanh) │
│ ┌────────────────┐ ┌────────────────┐ │
│ │ "Flash Sale │ │ "Cơ hội cuối │ │
│ │ 50% Polo! │ │ sở hữu Polo │ │
│ │ Chỉ 2 ngày!" │ │ DryTech giá │ │
│ │ │ │ tốt nhất năm!" │ │
│ └────────────────┘ └────────────────┘ │
│ ↓ ↓ │
│ Simulate 7 personas Simulate 7 personas │
│ ↓ ↓ │
│ ┌────────────────┐ ┌────────────────┐ │
│ │ Pos: 57% │ │ Pos: 71% │ │
│ │ Neu: 29% │ │ Neu: 22% │ │
│ │ Neg: 14% │ │ Neg: 7% │ │
│ │ 🟢 GREEN │ │ 🟢 GREEN ⭐ │ │
│ └────────────────┘ └────────────────┘ │
│ │
│ WINNER: VERSION B ← Tỷ lệ positive cao hơn 14% │
│ → LAUNCH VERSION B │
└──────────────────────────────────────────────────────┘
```
---
## 6.2. UI Layout — Side-by-Side Comparison
```
┌─────────────────────────────────────────────────────────┐
│ A/B TESTING MODE │
│ ═══════════════ │
│ │
│ ┌─── VERSION A ────────┐ ┌─── VERSION B ────────┐ │
│ │ Campaign Type: Sale │ │ Campaign Type: Sale │ │
│ │ ┌──────────────────┐ │ │ ┌──────────────────┐ │ │
│ │ │ "Flash Sale 50% │ │ │ │ "Cơ hội cuối..." │ │ │
│ │ │ Polo! Chỉ 2 │ │ │ │ "Polo DryTech │ │ │
│ │ │ ngày cuối!" │ │ │ │ giá tốt nhất!" │ │ │
│ │ └──────────────────┘ │ │ └──────────────────┘ │ │
│ │ │ │ │ │
│ │ Results: │ │ Results: │ │
│ │ 🟢 57% Positive │ │ 🟢 71% Positive ⭐ │ │
│ │ 🟡 29% Neutral │ │ 🟡 22% Neutral │ │
│ │ 🔴 14% Negative │ │ 🔴 7% Negative │ │
│ │ │ │ │ │
│ │ Risk: GREEN │ │ Risk: GREEN ⭐ │ │
│ └───────────────────────┘ └───────────────────────┘ │
│ │
│ 📊 COMPARISON: │
│ ├─ Version B: +14% positive sentiment │
│ ├─ Version B: -7% negative sentiment │
│ └─ Recommendation: LAUNCH VERSION B │
│ │
│ 💡 WHY B WINS: │
│ ├─ "Cơ hội cuối" tạo FOMO mạnh hơn "Flash Sale" │
│ ├─ "Giá tốt nhất năm" → Budget Conscious phản ứng ↑ │
│ └─ Không dùng emoji quá nhiều → YP đánh giá cao hơn │
└─────────────────────────────────────────────────────────┘
```
---
## 6.3. Comparison Metrics
| Metric | Version A | Version B | Delta | Winner |
|--------|----------|----------|-------|--------|
| **Positive %** | 57% | 71% | +14% | B ⭐ |
| **Negative %** | 14% | 7% | -7% | B ⭐ |
| **Est. Engagement** | 234 | 312 | +33% | B ⭐ |
| **Mom Shopper** | Positive | Positive | — | Tie |
| **Budget Conscious** | Neutral | Positive | ↑ | B ⭐ |
| **Gen Z** | Positive | Positive | — | Tie |
| **Troll** | Negative | Neutral | ↑ | B ⭐ |
| **Risk Level** | 🟢 Green | 🟢 Green | — | Tie |
---
## 6.4. Implementation (Pseudo-code)
```python
async def run_ab_test(campaign_a: str, campaign_b: str, weights: dict):
"""
Run 2 simulations in parallel, compare results.
"""
# Run both simulations
result_a = await simulate(campaign_a, weights)
result_b = await simulate(campaign_b, weights)
# Compare
comparison = {
'winner': 'A' if result_a['positive'] > result_b['positive'] else 'B',
'delta_positive': result_b['positive'] - result_a['positive'],
'delta_negative': result_a['negative'] - result_b['negative'],
'per_persona': compare_per_persona(result_a, result_b),
'reasons': generate_why_winner(result_a, result_b)
}
return {
'version_a': result_a,
'version_b': result_b,
'comparison': comparison
}
```
---
## 6.5. Use Cases cho A/B Testing
| Scenario | Version A | Version B | Test Question |
|----------|----------|----------|---------------|
| **Tone** | Urgency ("Chỉ 2 ngày!") | Aspirational ("Phong cách bạn") | FOMO vs Brand love? |
| **Price framing** | "Giảm 50%" | "Tiết kiệm 200K" | % vs Absolute? |
| **CTA** | "Mua ngay" | "Khám phá BST" | Hard sell vs Soft sell? |
| **Emoji density** | 5 emoji/post | 1 emoji/post | Fun vs Professional? |
| **Length** | Short (50 words) | Long (150 words) | Impact vs Detail? |
| **Visual concept** | Minimalist photo | Lifestyle shot | Product vs Context? |
> **Best practice:** Chỉ test 1 biến tại 1 thời điểm. VD: Giữ nguyên content, chỉ đổi CTA. Nếu đổi quá nhiều biến, không biết yếu tố nào tạo sự khác biệt.
---
## 6.6. Roadmap A/B Testing
```
🔲 v1.2 — Basic A/B mode (2 textareas, side-by-side results)
🔲 v1.3 — Per-persona comparison table
🔲 v1.4 — Auto-generate "Why B wins" analysis
🔲 v2.0 — Multi-variate testing (A/B/C/D)
🔲 v2.1 — Historical A/B results log
🔲 v3.0 — AI auto-suggest improvements
```
# Nghiên cứu: BettaFish, MiroFish & Social Simulation
> **Tóm tắt:** Reaction Simulator không phải ý tưởng từ trên trời rơi xuống. Nó được lấy cảm hứng từ các nghiên cứu Multi-Agent Social Simulation hàng đầu thế giới. Chương này phân tích nguồn gốc học thuật và vị trí của Canifa trên bản đồ nghiên cứu.
---
## 7.1. BettaFish (微舆) — Multi-Agent Public Opinion Simulation
### Paper: "BettaFish: A Simulated Forum for LLM-Based Opinion Dynamics" (2024)
```
┌──────────────────────────────────────────────────┐
│ BETTAFISH ARCHITECTURE │
│ │
│ Input: News Event │
│ "Chính phủ tăng giá điện 8%" │
│ ↓ │
│ ForumEngine: │
│ ├─ Agent "Worker" (Công nhân, 30t) │
│ │ └─ "Tăng giá điện thêm khổ dân lao động" │
│ ├─ Agent "Student" (Sinh viên, 22t) │
│ │ └─ "Phòng trọ tiền điện tăng 200K/tháng" │
│ ├─ Agent "Retiree" (Hưu trí, 65t) │
│ │ └─ "Lương hưu có hạn, gánh nặng thêm" │
│ └─ Agent "Netizen" (KOL online, 28t) │
│ └─ "So sánh giá điện VN vs ASEAN" │
│ ↓ │
│ Discourse Tree: Agents tranh luận 3-5 vòng │
│ ↓ │
│ Opinion Summary + Sentiment Distribution │
└──────────────────────────────────────────────────┘
```
### Key Insights từ BettaFish:
| Concept | BettaFish | Canifa Adaptation |
|---------|-----------|-------------------|
| **Agent Personas** | Worker, Student, Retiree, Netizen | Mom Shopper, Gen Z, Fashion Enthusiast... |
| **ForumEngine** | Agents tranh luận multi-turn | Single-turn reaction (đủ cho marketing) |
| **Discourse Tree** | Phân nhánh ý kiến phức tạp | Simplified: 1 comment/persona |
| **Opinion Dynamics** | Ý kiến thay đổi qua tranh luận | Static per simulation (v1.0) |
---
## 7.2. MiroFish — Persona Memory & Consistency
### Extension: "MiroFish: Memory-Informed Role-playing for Opinion Simulation"
MiroFish mở rộng BettaFish bằng cách thêm **Persona Memory** — mỗi agent nhớ phản ứng trước đó.
```
┌──────────────────────────────────────────────────┐
│ MIROFISH MEMORY SYSTEM │
│ │
│ Agent "Worker" Memory: │
│ ├─ Event 1: Tăng giá xăng → "Phản đối mạnh" │
│ ├─ Event 2: Tăng lương tối thiểu → "Ủng hộ" │
│ └─ Event 3: Tăng giá điện → ??? │
│ │
│ Memory-Informed Response: │
│ "Vừa tăng xăng xong, giờ lại tăng điện. │
│ Lương có tăng đâu mà cái gì cũng tăng!" │
│ │
│ → Response NHẤT QUÁN với lịch sử phản ứng │
└──────────────────────────────────────────────────┘
```
**Canifa áp dụng (Roadmap v3.0):** Persona Memory cho phép track phản ứng của từng persona qua nhiều chiến dịch. VD: Nếu "Budget Conscious" đã phàn nàn tăng giá 2 lần trước, lần thứ 3 sẽ phản ứng MẠNH HƠN.
---
## 7.3. Các nghiên cứu liên quan khác
### 7.3.1. "Generative Agents: Interactive Simulacra of Human Behavior" (Stanford, 2023)
Paper nổi tiếng tạo 25 AI agents sống trong thị trấn ảo, mỗi agent có memory, personality, và social relationships.
**Relevance:** Chứng minh LLM có thể role-play realistic personas khi được cung cấp đủ context.
### 7.3.2. "Social Simulacra" (Stanford HCI, 2023)
Hệ thống giả lập Reddit/Facebook communities bằng LLM. Input: mô tả community + rules. Output: Realistic threads với đa dạng ý kiến.
**Relevance:** Validate rằng LLM-generated comments có thể đủ realistic để dùng cho pre-testing.
### 7.3.3. "Brand Perception Modeling with LLMs" (Google DeepMind, 2025)
Nghiên cứu sử dụng LLM để model cách các demographic segments phản ứng với brand messaging. Kết quả: LLM predictions correlate 0.72 với real survey data.
**Relevance:** Xác nhận rằng approach của Reaction Simulator (dùng AI predict reaction) có cơ sở khoa học.
---
## 7.4. So sánh với các công cụ thương mại
| Tool | Loại | Giá | Canifa khác gì? |
|------|------|-----|-----------------|
| **Brandwatch** | Social Listening | $800-5000/mo | Real data nhưng KHÔNG predict trước |
| **Sprout Social** | Social Management | $249-499/mo | Monitor, không simulate |
| **Hootsuite** | Social Scheduler | $99-739/mo | Schedule, không test reaction |
| **Canifa Simulator** | Predictive Testing | $0 (self-hosted) | Predict TRƯỚC khi launch |
> **Key difference:** Các tool thương mại = **Reactive** (theo dõi sau khi đăng). Canifa Simulator = **Proactive** (test trước khi đăng).
---
## 7.5. Maturity Model — Social AI Simulation
```mermaid
graph LR
L1["Level 1<br/>Manual Review<br/>(Team đọc + đoán)"]
L2["Level 2<br/>Social Listening<br/>(Brandwatch, Sprout)"]
L3["Level 3<br/>Predictive Simulation<br/>(Canifa Simulator)"]
L4["Level 4<br/>Memory-Informed<br/>(MiroFish-style)"]
L5["Level 5<br/>Autonomous Campaign<br/>(AI tự tối ưu)"]
L1 --> L2 --> L3 --> L4 --> L5
style L3 fill:#f59e0b,stroke:#d97706,color:#000
L3 -.- NOTE["← CANIFA<br/>đang ở đây"]
style NOTE fill:#ef4444,stroke:#dc2626,color:#fff
```
# Implementation Blueprint: Code & API
> **Tóm tắt:** Full code reference cho Reaction Simulator — từ JavaScript engine đến API endpoints. Copy-paste là chạy.
---
## 8.1. Core Simulation Engine (JavaScript)
```javascript
// reaction-simulator.js — Core Engine
const PERSONAS = [
{
id: 'mom_shopper', name: 'Nguyễn Thị Mai',
label: 'Mom Shopper', age: 32, city: 'Hà Nội',
color: '#6D28D9',
triggers_pos: ['giá hợp lý', 'combo gia đình', 'free ship', 'chất mát'],
triggers_neg: ['tăng giá', 'khó bảo quản', 'không size trẻ em'],
comment_templates: {
positive: 'BST đẹp quá! Giá {price} hợp lý, mua cho cả nhà!',
neutral: 'Cần xem thực tế mới biết chất lượng thế nào.',
negative: 'Giá tăng nữa thì chuyển sang Coolmate thôi.'
}
},
// ... 6 personas khác (xem Chapter 2)
];
const CAMPAIGN_PRESETS = {
product_launch: { name: 'Ra mắt sản phẩm mới',
template: 'BST {name} vừa ra mắt! Chất liệu {material}, giá từ {price}.' },
promotion: { name: 'Chương trình khuyến mãi',
template: 'Flash Sale {discount}%! {product} giá chỉ {price}. Chỉ {days} ngày!' },
price_change: { name: 'Thay đổi giá',
template: 'Điều chỉnh giá {product} từ {old_price} → {new_price}.' },
collaboration: { name: 'Hợp tác thương hiệu',
template: 'Collab {brand} x Canifa — BST giới hạn!' },
social_post: { name: 'Bài đăng MXH',
template: '{content}' }
};
function runSimulation(campaignText, campaignType, weights) {
const reactions = [];
PERSONAS.forEach(persona => {
const weight = weights[persona.id] || 0;
if (weight === 0) return;
// Determine sentiment based on triggers
const sentiment = analyzeSentiment(campaignText, persona, campaignType);
// Generate mock comment
const comment = generateComment(persona, sentiment, campaignText);
// Estimate engagement
const engagement = estimateEngagement(persona, sentiment);
reactions.push({
pid: persona.id,
name: persona.name,
label: persona.label,
age: persona.age,
city: persona.city,
color: persona.color,
sentiment: sentiment,
comment: comment,
engagement: engagement,
weight: weight
});
});
return {
reactions: reactions,
summary: calcSentimentSummary(reactions),
recommendations: generateRecommendations(reactions)
};
}
```
---
## 8.2. Sentiment Analysis Logic
```javascript
function analyzeSentiment(campaignText, persona, campaignType) {
const text = campaignText.toLowerCase();
let score = 0;
// Check positive triggers
persona.triggers_pos.forEach(trigger => {
if (text.includes(trigger.toLowerCase())) score += 2;
});
// Check negative triggers
persona.triggers_neg.forEach(trigger => {
if (text.includes(trigger.toLowerCase())) score -= 3;
});
// Campaign type bias
const TYPE_BIAS = {
product_launch: { mom_shopper: 0, gen_z: 1, fashion_enthusiast: 2 },
promotion: { mom_shopper: 2, budget_conscious: 3, troll: 0 },
price_change: { mom_shopper: -2, budget_conscious: -3, troll: -2 },
collaboration: { gen_z: 2, kol: 2, fashion_enthusiast: 2 },
social_post: { gen_z: 1, kol: 0, troll: -1 }
};
score += (TYPE_BIAS[campaignType]?.[persona.id] || 0);
// Classify
if (score >= 2) return 'positive';
if (score <= -2) return 'negative';
return 'neutral';
}
```
---
## 8.3. Frontend — HTML Structure
```html
<!-- reaction-simulator.html — Key sections -->
<!-- Tab Navigation -->
<div class="sim-tabs">
<button class="sim-tab active" data-tab="simulate">
🎯 Mô phỏng
</button>
<button class="sim-tab" data-tab="crisis">
🚨 Crisis Alert
</button>
<button class="sim-tab" data-tab="docs">
📚 Tài liệu
</button>
</div>
<!-- Campaign Input -->
<div class="sim-section">
<label>Loại chiến dịch</label>
<select id="campaignType">
<option value="product_launch">Ra mắt sản phẩm mới</option>
<option value="promotion">Chương trình khuyến mãi</option>
<option value="price_change">Thay đổi giá</option>
<option value="collaboration">Hợp tác thương hiệu</option>
<option value="social_post">Bài đăng MXH</option>
</select>
<label>Nội dung chiến dịch</label>
<textarea id="campaignContent" rows="4"
placeholder="Nhập nội dung campaign..."></textarea>
</div>
<!-- Persona Weight Sliders -->
<div class="sim-section">
<h3>Điều chỉnh tỷ trọng Persona</h3>
<div class="persona-sliders">
<!-- Generated dynamically -->
</div>
</div>
<!-- Results -->
<div id="results" class="sim-results" style="display:none">
<canvas id="sChart" width="130" height="130"></canvas>
<div id="sentimentBars"></div>
<div id="reactionCards"></div>
<div id="recommendations"></div>
</div>
```
---
## 8.4. API Endpoints (Future — Backend Integration)
```python
# backend/api/reaction_simulator/simulator_route.py
from fastapi import APIRouter
from pydantic import BaseModel
router = APIRouter(prefix="/api/reaction-simulator", tags=["Reaction Simulator"])
class SimulationRequest(BaseModel):
campaign_text: str
campaign_type: str # product_launch, promotion, price_change, etc.
weights: dict # {mom_shopper: 20, gen_z: 15, ...}
class ABTestRequest(BaseModel):
version_a: str
version_b: str
campaign_type: str
weights: dict
@router.post("/simulate")
async def run_simulation(req: SimulationRequest):
"""Run single simulation with 7 personas."""
# Currently frontend-only (JS engine)
# Future: LLM-powered simulation via this endpoint
pass
@router.post("/ab-test")
async def run_ab_test(req: ABTestRequest):
"""Run A/B comparison of 2 campaign versions."""
pass
@router.get("/presets")
async def get_presets():
"""Return available campaign presets."""
return CAMPAIGN_PRESETS
```
---
## 8.5. File Structure
```
backend/static/reaction-simulator/
├── reaction-simulator.html # Main UI (tabs: Simulate, Crisis, Docs)
├── reaction-simulator.js # Core simulation engine
├── reaction-simulator.css # Styling (dark theme)
└── README.md # Quick start guide
backend/static/cookbook/data/51-reaction-simulator-deep/
├── meta.json # Cookbook registry
├── 01_concept.md # Philosophy
├── 02_persona_engine.md # 7 Persona profiles
├── 03_architecture.md # Multi-Agent architecture
├── 04_sentiment_engine.md # Scoring algorithm
├── 05_crisis_alert.md # Crisis detection
├── 06_ab_testing.md # A/B comparison mode
├── 07_industry_research.md # Academic references
└── 08_implementation.md # This file (code reference)
```
---
## 8.6. Testing Checklist
| # | Test | Action | Expected |
|---|------|--------|----------|
| 1 | Load page | Open reaction-simulator.html | All tabs render, sliders work |
| 2 | Select preset | Choose "Khuyến mãi" | Template text fills input |
| 3 | Run simulation | Click "Mô phỏng phản ứng" | Donut chart + 7 cards appear |
| 4 | Adjust weights | Set Mom=40%, others=10% | Results shift toward Mom perspective |
| 5 | Crisis tab | Switch to Crisis Alert | Dashboard metrics + alert feed render |
| 6 | Docs tab | Switch to Tài liệu | Documentation panels load |
| 7 | Empty input | Run with no text | Error message shown |
| 8 | Reset | Click Reset | All inputs cleared, results hidden |
---
## 8.7. Full Roadmap
```
┌─────────────────────────────────────────────────────┐
│ REACTION SIMULATOR ROADMAP │
│ │
│ ✅ v1.0 — Core simulation engine (JS, client-side) │
│ ✅ v1.1 — 7 Persona profiles + weight sliders │
│ ✅ v1.2 — Donut chart + Reaction cards │
│ ✅ v1.3 — Campaign presets (5 types) │
│ ✅ v1.4 — Crisis Alert tab (mock data) │
│ ✅ v1.5 — Docs tab (inline documentation) │
│ 🔲 v1.6 — A/B Testing mode │
│ 🔲 v1.7 — Export results to PDF │
│ 🔲 v2.0 — Backend API (FastAPI endpoints) │
│ 🔲 v2.1 — LLM-powered comment generation │
│ 🔲 v2.2 — Real social data integration │
│ 🔲 v2.3 — Historical simulation log │
│ 🔲 v3.0 — MiroFish-style persona memory │
│ 🔲 v3.1 — Multi-turn discourse simulation │
│ 🔲 v3.2 — Auto-optimize campaign copy with AI │
└─────────────────────────────────────────────────────┘
```
{
"id": "51-reaction-simulator-deep",
"title": "Reaction Simulator — AI Social Listening & Campaign Pre-Testing",
"description": "Hệ thống giả lập phản ứng cộng đồng trước khi launch campaign. 7 Persona segments, Sentiment Engine, Crisis Alert, A/B Testing. Lấy cảm hứng từ BettaFish ForumEngine + MiroFish Simulate Agent.",
"sections": [
{
"id": "concept",
"title": "1. Triết lý: Tại sao phải 'Test trước khi Launch'?",
"type": "markdown",
"file": "01_concept.md"
},
{
"id": "persona-engine",
"title": "2. Persona Engine: 7 nhóm khách hàng Vietnam",
"type": "markdown",
"file": "02_persona_engine.md"
},
{
"id": "architecture",
"title": "3. Kiến trúc Multi-Agent Simulation",
"type": "markdown",
"file": "03_architecture.md"
},
{
"id": "sentiment-engine",
"title": "4. Sentiment Analysis Engine",
"type": "markdown",
"file": "04_sentiment_engine.md"
},
{
"id": "crisis-alert",
"title": "5. Crisis Alert System: Phát hiện khủng hoảng sớm",
"type": "markdown",
"file": "05_crisis_alert.md"
},
{
"id": "ab-testing",
"title": "6. A/B Testing Mode: So sánh 2 phiên bản campaign",
"type": "markdown",
"file": "06_ab_testing.md"
},
{
"id": "industry-research",
"title": "7. Nghiên cứu: BettaFish, MiroFish & Social Simulation",
"type": "markdown",
"file": "07_industry_research.md"
},
{
"id": "implementation",
"title": "8. Implementation Blueprint: Code & API",
"type": "markdown",
"file": "08_implementation.md"
}
]
}
......@@ -26,10 +26,18 @@
"name": "👗 Nghiệp vụ: Phối đồ & Thời trang",
"recipes": [
{ "id": "36-fashion-matching-logic", "title": "Nghiệp vụ phối đồ (Tại sao phối thế?)" },
{ "id": "49-conversational-routing", "title": "Conversational Routing (Mồi Câu Liên Hoàn)" },
{ "id": "37-ultra-description-logic", "title": "Nghiệp vụ mô tả SP (Ultra Description)" },
{ "id": "38-size-guide-logic", "title": "Nghiệp vụ hướng dẫn size" }
]
},
{
"name": "🎪 Event & Campaign Management",
"recipes": [
{ "id": "50-event-daily-engine", "title": "Event Daily Engine (Lịch tâm trạng AI)" },
{ "id": "51-reaction-simulator-deep", "title": "Reaction Simulator Deep-Dive (7 Personas)" }
]
},
{
"name": "🤖 AI Core & Prompt",
"recipes": [
......
......@@ -126,71 +126,44 @@
<script>
if (window.lucide) { lucide.createIcons(); }
const mockEvents = [
{
id: 'evt_1',
title: 'Mặc định hàng ngày',
type: 'Daily',
tagClass: 'daily',
date: 'All days',
desc: 'Luật cơ bản cho ngày thường. Không có event đặc biệt.',
prompt: '- Luôn chào hỏi thân thiện\n- Gợi ý đồ dạo phố, công sở nhẹ nhàng\n- Khuyến khích khách hàng thử trang phục mới'
},
{
id: 'evt_2',
title: 'Flash Sale 5/5',
type: 'Campaign',
tagClass: 'campaign',
date: '05/05/2026',
desc: 'Sale lớn đồng giá 99k, 199k. Đẩy mạnh các mặt hàng áo thun mùa hè.',
prompt: '- NHẤN MẠNH chương trình Flash Sale 5/5 đồng giá 99k, 199k\n- Gợi ý áo thun, quần short mặc hè\n- Dùng emoji 🎉🔥 để tạo sự hào hứng'
},
{
id: 'evt_3',
title: 'Lễ hội mùa đông',
type: 'Campaign',
tagClass: 'campaign',
date: '10/11/2026 - 31/12/2026',
desc: 'Chiến dịch ra mắt bộ sưu tập áo khoác dạ và len lông cừu.',
prompt: '- Ưu tiên tư vấn áo khoác dạ, áo len lông cừu\n- Gợi ý cách phối đồ layer ấm áp\n- Chú ý hỏi khách hàng đang ở khu vực lạnh không'
},
{
id: 'evt_4',
title: 'Sinh nhật Canifa',
type: 'Campaign',
tagClass: 'campaign',
date: '01/08/2026 - 15/08/2026',
desc: 'Mừng sinh nhật. Voucher giảm 50% cho khách hàng mua từ 3 sản phẩm.',
prompt: '- Nhắc khéo khách hàng về voucher giảm 50% khi mua 3 sản phẩm\n- Chúc mừng sinh nhật Canifa cùng khách hàng'
},
{
id: 'evt_5',
title: 'Black Friday 2026',
type: 'Campaign',
tagClass: 'campaign',
date: '27/11/2026',
desc: 'Giảm giá cực sốc lên tới 70%. Tăng cường upsell.',
prompt: '- Khẩn trương! Black Friday sale 70%\n- Tư vấn khách mua theo combo để được giá tốt nhất\n- Không bỏ lỡ các deal shock giờ vàng'
}
];
let events = [];
const eventsListEl = document.getElementById('eventsList');
const contentArea = document.getElementById('contentArea');
const emptyArea = document.getElementById('emptyArea');
const promptContent = document.getElementById('prompt-content');
const dateFrom = document.getElementById('evt-date-from');
const dateTo = document.getElementById('evt-date-to');
let currentActiveId = null;
async function fetchEvents() {
try {
const response = await fetch('/api/event_daily/events');
if (response.ok) {
events = await response.json();
renderEvents();
}
} catch (error) {
console.error('Error fetching events:', error);
}
}
function renderEvents() {
eventsListEl.innerHTML = mockEvents.map(evt => `
<div class="fb-item ${evt.id === currentActiveId ? 'active' : ''}" onclick="selectEvent('${evt.id}')">
<div class="fb-tag ${evt.tagClass}">${evt.type.toUpperCase()}</div>
<div class="fb-title">${evt.title}</div>
<div style="font-size:11px; color:var(--m); margin-bottom:8px; display:flex; align-items:center; gap:4px;">
<i data-lucide="clock" style="width:12px;height:12px;"></i> ${evt.date}
eventsListEl.innerHTML = events.map(evt => {
const tagClass = evt.type.toLowerCase() === 'daily' ? 'daily' : 'campaign';
const isTodayHtml = evt.isToday ? '<span style="color:red; font-size:12px; margin-left: 4px;">🔥</span>' : '';
const displayDate = (evt.startDate && evt.endDate) ? `${evt.startDate} - ${evt.endDate}` : evt.date;
return `
<div class="fb-item ${evt.id === currentActiveId ? 'active' : ''}" onclick="selectEvent('${evt.id}')">
<div class="fb-tag ${tagClass}">${evt.type.toUpperCase()}</div>
<div class="fb-title">${evt.name}${isTodayHtml}</div>
<div style="font-size:11px; color:var(--m); margin-bottom:8px; display:flex; align-items:center; gap:4px;">
<i data-lucide="clock" style="width:12px;height:12px;"></i> ${displayDate}
</div>
<div class="fb-desc" style="white-space: pre-line; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;">${evt.prompt}</div>
</div>
<div class="fb-desc">${evt.desc}</div>
</div>
`).join('');
`;
}).join('');
lucide.createIcons();
}
......@@ -198,16 +171,16 @@
currentActiveId = id;
renderEvents();
const evt = mockEvents.find(e => e.id === id);
const evt = events.find(e => e.id === id);
if(evt) {
emptyArea.style.display = 'none';
contentArea.style.display = 'flex';
document.getElementById('detail-title').innerText = evt.title;
document.getElementById('detail-title').innerText = evt.name;
const tagEl = document.getElementById('detail-tag');
tagEl.innerText = evt.type.toUpperCase();
if (evt.type === 'Daily') {
if (evt.type.toLowerCase() === 'daily') {
tagEl.style.background = 'rgba(16,185,129,0.15)';
tagEl.style.color = '#34d399';
} else {
......@@ -215,17 +188,51 @@
tagEl.style.color = '#818cf8';
}
document.getElementById('prompt-content').value = evt.prompt;
promptContent.value = evt.prompt;
dateFrom.value = evt.startDate || '';
dateTo.value = evt.endDate || '';
}
}
function savePrompt() {
async function savePrompt() {
if (!currentActiveId) return;
const btn = document.querySelector('.btn-primary');
const originalHtml = btn.innerHTML;
btn.innerHTML = '<i data-lucide="check" class="icon-sm"></i> Đã lưu';
btn.style.background = '#10b981';
lucide.createIcons();
btn.innerHTML = '<i data-lucide="loader" class="icon-sm"></i> Đang lưu...';
try {
const response = await fetch(`/api/event_daily/events/${currentActiveId}`, {
method: 'PUT',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
prompt: promptContent.value,
start_date: dateFrom.value || null,
end_date: dateTo.value || null
})
});
if (response.ok) {
btn.innerHTML = '<i data-lucide="check" class="icon-sm"></i> Đã lưu';
btn.style.background = '#10b981';
const evt = events.find(e => e.id === currentActiveId);
if (evt) {
evt.prompt = promptContent.value;
evt.startDate = dateFrom.value || null;
evt.endDate = dateTo.value || null;
renderEvents();
}
} else {
throw new Error('Lỗi khi lưu');
}
} catch (error) {
console.error(error);
btn.innerHTML = '<i data-lucide="x" class="icon-sm"></i> Lỗi';
btn.style.background = '#ef4444';
}
lucide.createIcons();
setTimeout(() => {
btn.innerHTML = originalHtml;
btn.style.background = '';
......@@ -233,12 +240,11 @@
}, 2000);
}
// Set today's date
const today = new Date();
const options = { weekday: 'long', year: 'numeric', month: 'long', day: 'numeric' };
document.getElementById('today-date').innerText = today.toLocaleDateString('vi-VN', options);
renderEvents();
fetchEvents();
</script>
</body>
</html>
import sqlite3
conn = sqlite3.connect('database/canifa_ai_dump.sqlite')
c = conn.cursor()
c.execute("SELECT match_role, COUNT(*) FROM pg__dashboard_canifa__ai_outfit_product_matches GROUP BY match_role")
print(c.fetchall())
Bimport sqlite3; conn = sqlite3.connect('database/canifa_ai_dump.sqlite'); c = conn.cursor(); c.execute(\
import sqlite3
import json
conn = sqlite3.connect('database/canifa_ai_dump.sqlite')
conn.row_factory = sqlite3.Row
c = conn.cursor()
c.execute("SELECT match_product_code, match_role FROM pg__dashboard_canifa__ai_outfit_product_matches WHERE magento_ref_code='1DS24C017' LIMIT 10")
rows = c.fetchall()
print("Forward matches:")
for r in rows:
print(dict(r))
c.execute("SELECT magento_ref_code, match_role FROM pg__dashboard_canifa__ai_outfit_product_matches WHERE match_product_code='1DS24C017' LIMIT 10")
rows = c.fetchall()
print("\nBackward matches:")
for r in rows:
print(dict(r))
[('Bộ thể thao', 'outerwear'), ('Bộ thể thao', 'outerwear'), ('Bộ thể thao', 'outerwear'), ('Bộ thể thao', 'accessory'), ('Bộ thể thao', 'accessory'), ('Bộ thể thao', 'accessory'), ('Bộ thể thao', 'accessory'), ('Bộ thể thao', 'accessory'), ('Bộ thể thao', 'accessory'), ('Mũ', 'top'), ('Mũ thể thao', 'top'), ('Mũ thể thao', 'top'), ('Mũ thể thao', 'top'), ('Mũ thể thao', 'accessory'), ('Mũ thể thao', 'outerwear'), ('Quần dài', 'accessory'), ('Quần dài', 'accessory'), ('Quần dài', 'accessory'), ('Quần dài', 'accessory'), ('Quần dài', 'accessory'), ('Quần jean', 'accessory'), ('Quần jean', 'accessory'), ('Quần jean', 'accessory'), ('Quần jean', 'accessory'), ('Quần nỉ', 'accessory'), ('Quần nỉ', 'accessory'), ('Quần nỉ', 'accessory'), ('Quần nỉ', 'accessory'), ('Quần nỉ', 'accessory'), ('Quần nỉ', 'top'), ('Quần nỉ', 'top'), ('Quần nỉ', 'top'), ('Quần nỉ', 'top'), ('Quần nỉ', 'top'), ('Tất', 'bottom'), ('Tất', 'bottom'), ('Tất', 'bottom'), ('Tất', 'bottom'), ('Tất', 'bottom'), ('Tất', 'bottom'), ('Tất', 'bottom'), ('Tất', 'bottom'), ('Tất', 'bottom'), ('Tất', 'bottom'), ('Tất', 'top'), ('Tất', 'top'), ('Tất', 'top'), ('Tất', 'top'), ('Tất', 'top'), ('Tất', 'bottom'), ('Tất', 'bottom'), ('Tất', 'bottom'), ('Tất', 'bottom'), ('Tất', 'bottom'), ('Áo Polo', 'accessory'), ('Áo Polo', 'accessory'), ('Áo Polo', 'accessory'), ('Áo Polo', 'accessory'), ('Áo Polo', 'accessory'), ('Áo khoác gió', 'top'), ('Áo khoác gió', 'top'), ('Áo khoác gió', 'top'), ('Áo khoác gió', 'top'), ('Áo khoác gió', 'top'), ('Áo khoác gió', 'accessory'), ('Áo khoác gió', 'accessory'), ('Áo khoác gió', 'accessory'), ('Áo khoác gió', 'accessory'), ('Áo khoác gió', 'accessory'), ('Áo khoác nỉ không mũ', 'accessory'), ('Áo khoác nỉ không mũ', 'accessory'), ('Áo khoác nỉ không mũ', 'accessory'), ('Áo khoác nỉ không mũ', 'accessory'), ('Áo khoác nỉ không mũ', 'accessory'), ('Áo phông', 'accessory'), ('Áo phông', 'accessory'), ('Áo phông', 'accessory'), ('Áo phông', 'accessory'), ('Áo phông', 'accessory')]
\ No newline at end of file
import json
input_file = 'test_data.jsonl'
output_file = 'cleaned_test_data.jsonl'
cleaned_data = []
orphan_count = 0
unknown_count = 0
with open(input_file, 'r', encoding='utf-8') as f:
for line in f:
line = line.strip()
if not line: continue
try:
data = json.loads(line)
except json.JSONDecodeError:
continue
# Check for orphan (missing ten_san_pham but has mau_sac)
if "ten_san_pham" not in data and "mau_sac" in data:
orphan_count += 1
if cleaned_data:
prev = cleaned_data[-1]
if "mau_sac" in prev:
# Append colors, handle duplicates if necessary
colors = [c.strip() for c in prev["mau_sac"].split(',')]
new_color = data["mau_sac"].strip()
if new_color not in colors:
prev["mau_sac"] += f",{new_color}"
else:
prev["mau_sac"] = data["mau_sac"]
else:
# Check for "Không xác định"
has_unknown = any(v == "Không xác định" for v in data.values())
if has_unknown:
unknown_count += 1
cleaned_data.append(data)
with open(output_file, 'w', encoding='utf-8') as f:
for item in cleaned_data:
f.write(json.dumps(item, ensure_ascii=False) + '\n')
print(f"✅ Đã dọn dẹp xong data!")
print(f" - Số dòng 'mồ côi' (chỉ có màu sắc) đã được gộp: {orphan_count}")
print(f" - Số sản phẩm chứa trường 'Không xác định': {unknown_count}")
print(f" - Tổng số sản phẩm sau khi gộp: {len(cleaned_data)}")
print(f"Output lưu tại: {output_file}")
{"ten_san_pham":"Áo giữ nhiệt bé gái cổ lửng","mo_ta_chinh":"Form ôm nhẹ tạo cảm giác ấm áp tối ưu, cổ lửng thiết kế dệt liền giúp cố định nhiệt. Vải dệt 3D dày dặn che khuyết điểm vòng eo, giữ dáng cơ thể cho bé khi vận động. Phom tay rộng rãi không gò bó, cho bé di chuyển linh hoạt suốt ngày dài.","chat_lieu":"Polyester kháng khuẩn 93% + sợi nhiệt canifa 7%","tinh_nang_vai":"Tăng sinh nhiệt 30% so với vải thường | Thấm mồ hôi 200% | Co giãn đa hướng","gioi_tinh":"Nữ","phong_cach":"Thermal wear, Kids casual","mua":"Đông - Xuân","dip_mac":"Dạo phố cuối tuần · Đi học hàng ngày · Tập thể thao ngoài trời · Gặp họ hàng dịp Tết","tags":"áo giữ nhiệt, bé gái, canifa, ấm đông, sợi nhiệt, form ôm","do_tuoi":"4-12 tuổi","loi_song":"Bé gái năng động, thường xuyên vận động ngoài trời vào mùa lạnh","tinh_cach":"Sáng tạo, mạnh mẽ, yêu thiên nhiên","ly_do_mua":"Công nghệ sợi nhiệt độc quyền tăng sinh nhiệt 30% | Form ôm gọn giúp bé vận động linh hoạt | Chất liệu an toàn với làn da nhạy cảm","cross_sell":"Quần giữ nhiệt bé gái, Áo khoác chần bông Canifa, Tất len cổ dài","hook_quang_cao":"Áo giữ nhiệt khiến mẹ không cần lo bé lạnh mỗi khi ra đường!","tagline":"Nắng đông không lạnh, mẹ yên tâm","mau_sac":"Đen/ Black"}
{"ten_san_pham":"Chân váy ngắn màu xanh dương","mo_ta_chinh":"Chân váy ngắn màu xanh dương với họa tiết nơ trắng","chat_lieu":"Không xác định","tinh_nang_vai":"Không xác định","gioi_tinh":"Nữ","phong_cach":"Trẻ trung, năng động","mua":"Không xác định","dip_mac":"Không xác định","tags":"Không xác định","do_tuoi":"Không xác định","loi_song":"Không xác định","tinh_cach":"Không xác định","ly_do_mua":"Không xác định","cross_sell":"Không xác định","hook_quang_cao":"Thỏa sức sáng tạo với phong cách của bạn","tagline":"Phong cách trẻ trung, năng động","mau_sac":"Xanh da trời/ Blue"}
{"ten_san_pham":"Chân váy denim ngắn","mo_ta_chinh":"Chân váy ngắn làm từ denim, thiết kế xếp ly","chat_lieu":"Không xác định","tinh_nang_vai":"Không xác định","gioi_tinh":"Nữ","phong_cach":"Trẻ trung, năng động","mua":"Không xác định","dip_mac":"Học đường, đi chơi","tags":"Chân váy denim, chân váy ngắn, xếp ly","do_tuoi":"Không xác định","loi_song":"Tự tin, năng động","tinh_cach":"Sáng tạo, phá cách","ly_do_mua":"Thỏa sức sáng tạo","cross_sell":"Giày sneaker, túi xách","hook_quang_cao":"Thỏa sức sáng tạo với chân váy denim","tagline":"Phong cách trẻ trung, năng động","mau_sac":"Màu xanh Jeans"}
{"ten_san_pham":"Chân váy bé gái dáng bí","mo_ta_chinh":"Chân váy dáng bí thời thượng với độ phồng tự nhiên tạo nét tinh nghịch, đáng yêu. Chất liệu gió nhẹ tênh cho bé thoải mái vận động suốt cả ngày dài. Thiết kế cạp chun co giãn giúp che khuyết điểm vùng bụng, đồng thời tạo độ xòe nhẹ che khuyết điểm đùi cực khéo léo.","chat_lieu":"Chất liệu gió","tinh_nang_vai":"Chất vải gió bền bỉ, thoát dáng tốt, nhẹ tênh và không gây bí bách khi bé chạy nhảy.","gioi_tinh":"Nữ","phong_cach":"Năng động, Dễ thương, Hiện đại","mua":"Xuân, Hè, Thu","dip_mac":"Đi học thêm · Đi dã ngoại cùng gia đình · Tham gia tiệc sinh nhật · Dạo phố cuối tuần","tags":"chân váy bé gái, chân váy dáng bí, đồ bé gái, chân váy gió, thời trang kid","do_tuoi":"5-15","loi_song":"Bé gái năng động, ưa thích các hoạt động vui chơi ngoài trời nhưng vẫn giữ nét xinh xắn.","tinh_cach":"Hồn nhiên, tự tin, yêu vận động","ly_do_mua":"Chất liệu gió bền bỉ, không nhăn | Dáng váy bí che khuyết điểm cực khéo | Dễ phối đồ cho mọi dịp","cross_sell":"Áo phông, Áo nỉ, Quần leggings, Tất, Mũ","hook_quang_cao":"Siêu phẩm chân váy dáng bí — cho bé thoải mái vận động vẫn chuẩn chất tiểu thư!","tagline":"Vẻ ngoài tiểu thư, biến bé thành nàng công chúa nhỏ năng động","mau_sac":"Đen/ Black,Hồng/ Pink- Magenta,Be/ Beige"}
{"ten_san_pham":"Chân váy xếp ly ngắn màu đỏ","mo_ta_chinh":"Chân váy ngắn xếp ly, thiết kế đơn giản nhưng nổi bật, tạo cảm giác năng động và trẻ trung","chat_lieu":"Không xác định","tinh_nang_vai":"Không xác định","gioi_tinh":"Nữ","phong_cach":"Trẻ trung, năng động","mua":"Tất cả các mùa","dip_mac":"Đi chơi · Đi học · Dự tiệc · Chụp ảnh","tags":"chân váy, váy ngắn, váy xếp ly, váy màu đỏ, thời trang nữ","do_tuoi":"15-30","loi_song":"Khách hàng yêu thích phong cách trẻ trung, năng động","tinh_cach":"Tự tin, cá tính","ly_do_mua":"Thiết kế trẻ trung | Chất lượng tốt | Giá cả hợp lý","cross_sell":"Áo phông, áo blouse, giày sneakers","hook_quang_cao":"Tỏa sáng với phong cách trẻ trung, năng động","tagline":"Tỏa sáng với phong cách trẻ trung","mau_sac":"Đỏ/ Red"}
{"ten_san_pham":"Combo 2 quần soóc mặc nhà bé gái","mo_ta_chinh":"Combo 2 quần soóc mặc nhà với form dáng cơ bản, ôm vừa vặn theo từng cử động của bé. Thiết kế linh hoạt cùng hình in tươi sáng, nữ tính giúp bé thêm phần đáng yêu. Chất liệu mềm mại nhẹ tênh, đảm bảo sự thoải mái tuyệt đối trong mọi hoạt động tại gia.","chat_lieu":"Không xác định","tinh_nang_vai":"Thông thoáng, thấm hút mồ hôi tốt, độ bền cao phù hợp với các bé hiếu động","gioi_tinh":"Nữ","phong_cach":"Casual, Homewear","mua":"Xuân, Hè, Thu","dip_mac":"Mặc ở nhà · Vui chơi cuối tuần · Đi ngủ · Hoạt động thể chất nhẹ nhàng","tags":"quan soc, be gai, mac nha, combo, quan dui, thoi trang tre em","do_tuoi":"3-15","loi_song":"Năng động, hồn nhiên, ưu tiên sự thoải mái trong sinh hoạt hàng ngày","tinh_cach":"Vui vẻ, tinh nghịch, yêu thích sự gọn gàng","ly_do_mua":"Tiết kiệm với combo 2 chiếc | Form dáng mặc nhà chuẩn mực | Họa tiết nữ tính dễ thương","cross_sell":"Áo phông, Áo ba lỗ, Bộ mặc nhà","hook_quang_cao":"Combo 2 quần soóc xinh xắn - lựa chọn tối ưu cho những ngày bé ở nhà thật thoải mái!","tagline":"Dịu dàng diện nhà, bé thoải mái nô đùa","mau_sac":"Tím/ Purple"}
{"ten_san_pham":"Quần mặc nhà bé gái cotton hoạ tiết kẻ | Oeko-Tex","mo_ta_chinh":"Dáng suông thoải mái, họa tiết kẻ dễ thương, giúp bé tự tin và thoải mái di chuyển. Thiết kế đơn giản nhưng đầy hồn nhiên, phù hợp với mọi hoạt động trong ngày. Mặt khác, chất liệu 100% cotton mềm mại tạo cảm giác êm ái, giảm căng thẳng cơ bắp khi bé chạy nhảy.","chat_lieu":"100% cotton","tinh_nang_vai":"Mềm mại, thoải mái, dễ chịu khi mặc","gioi_tinh":"Nữ","phong_cach":"Home & Lounge","mua":"Mùa hè","dip_mac":"Ở nhà thư giãn · Đồ chơi ngoài trời nhẹ · Cuộc họp gia đình · Kỷ niệm sinh nhật","tags":"quần mặc nhà, bé gái, cotton, hoạ tiết kẻ, Oeko-Tex, quần trẻ em, quần mềm mại","do_tuoi":"3-7 tuổi","loi_song":"Mẹ bận rộn, con yêu thích sự thoải mái, gia đình yêu thương","tinh_cach":"Tự tin, vui tươi, chăm sóc","ly_do_mua":"Chất liệu an toàn, thiết kế dễ thương, phù hợp cho bé, dễ bảo quản","cross_sell":"Áo phông, Quần nỉ, Váy liền","hook_quang_cao":"Cho bé yêu của bạn một ngày thư giãn với quần mặc nhà mềm mại và an toàn!","tagline":"Hơi thoải mái, phong cách ngọt ngào","mau_sac":"Đen/ Black"}
{"ten_san_pham":"Quần mặc nhà bé gái dáng ôm | Oeko-Tex","mo_ta_chinh":"Dáng ôm tinh tế, giúp thẳng gối và tôn dáng bé gái. Thiết kế co giãn thoải mái, không làm kẹt, phù hợp cho các hoạt động nhẹ nhàng tại nhà. Tác dụng nâng cao sự thoải mái, giảm áp lực lên vùng thắt lưng và chân, hỗ trợ tư thế ngồi và đứng tự nhiên.","chat_lieu":"Không xác định","tinh_nang_vai":"Co giãn, thoải mái, gọn gàng","gioi_tinh":"Nữ","phong_cach":"Casual, cozy, homewear","mua":"Khắp năm","dip_mac":"Ở nhà thư giãn · Khi học tập tại nhà · Khi đi dạo trong công viên · Khi tham gia các buổi yoga nhẹ","tags":"quần mặc nhà, quần leggings, quần bé gái, quần ôm, Oeko-Tex, quần thoải mái, quần ống rộng, quần co giãn","do_tuoi":"3-12","loi_song":"Những bé gái năng động, yêu thích sự thoải mái và sáng tạo trong mọi hoạt động","tinh_cach":"Lạc quan, năng động, tự tin","ly_do_mua":"Dáng ôm tôn dáng, chất liệu an toàn cho da, thiết kế linh hoạt phù hợp với nhiều hoạt động","cross_sell":"Áo body pastel, Áo khoác gió nhẹ, Bộ mặc nhà 2 phần","hook_quang_cao":"Quần mặc nhà bé gái ôm – nơi sự ấm áp gặp gỡ phong cách","tagline":"Thoải mái từ đầu đến cuối ngày","mau_sac":"Xám/ Gray"}
{"ten_san_pham":"Bộ đồ ngủ trẻ em","mo_ta_chinh":"Bộ đồ ngủ trẻ em gồm áo và quần short","chat_lieu":"Không xác định","tinh_nang_vai":"Không xác định","gioi_tinh":"Nữ","phong_cach":"Phong cách trẻ em","mua":"Không xác định","dip_mac":"Đi ngủ","tags":"Bộ đồ ngủ trẻ em, áo và quần short","do_tuoi":"Trẻ em","loi_song":"Không xác định","tinh_cach":"Không xác định","ly_do_mua":"Không xác định","cross_sell":"Không xác định","hook_quang_cao":"Bộ đồ ngủ trẻ em với thiết kế dễ thương và thoải mái","tagline":"Thiết kế dễ thương, thoải mái","mau_sac":"Vàng/ Yellow + Gold"}
{"ten_san_pham":"Bộ đồ trẻ em","mo_ta_chinh":"Bộ đồ trẻ em gồm áo phông và quần short","chat_lieu":"Không xác định","tinh_nang_vai":"Không xác định","gioi_tinh":"Nữ","phong_cach":"Trẻ em","mua":"Không xác định","dip_mac":"Hàng ngày","tags":"Không xác định","do_tuoi":"Trẻ em","loi_song":"Không xác định","tinh_cach":"Không xác định","ly_do_mua":"Không xác định","cross_sell":"Không xác định","hook_quang_cao":"Thiết kế dễ thương","tagline":"Thời trang trẻ em","mau_sac":"Hồng/ Pink- Magenta"}
{"ten_san_pham":"Bộ quần áo nỉ cào bông bé gái","mo_ta_chinh":"Bộ quần áo nỉ thiết kế phom suông năng động, mang lại cảm giác thoải mái tối đa cho bé trong mọi cử động. Điểm nhấn là chi tiết đè dây dệt in hình ấn tượng ở vai và sườn, giúp tạo vẻ ngoài thời thượng và sắc nét. Chất liệu nỉ cào bông cao cấp giữ ấm ưu việt, tôn dáng khỏe khoắn mà vẫn giữ được nét đáng yêu của bé gái.","chat_lieu":"Cotton pha","tinh_nang_vai":"Mềm mại, giữ ấm tốt, bề mặt vải bền đẹp sau nhiều lần giặt","gioi_tinh":"girl","phong_cach":"Sporty, Casual","mua":"Thu Đông","dip_mac":"Đến trường · Đi dã ngoại · Vui chơi cuối tuần · Mặc nhà mùa đông","tags":"bộ quần áo, bé gái, nỉ cào bông, giữ ấm, mùa đông","do_tuoi":"Kid","loi_song":"Năng động, yêu thích vận động và khám phá","tinh_cach":"Vui vẻ, tinh nghịch, tự tin","ly_do_mua":"Chất liệu nỉ cào bông ấm áp vượt trội | Thiết kế thời trang với dây dệt nổi bật | Form dáng thoải mái cho mọi hoạt động","cross_sell":"Áo khoác chần bông, Tất, Mũ thể thao","hook_quang_cao":"Bí kíp để bé luôn ấm áp và tự tin tỏa sáng suốt mùa lạnh này","tagline":"Ấm áp nâng niu, tự tin vận động","mau_sac":"Xám/ Gray,Hồng/ Pink- Magenta"}
{"ten_san_pham":"Bộ đồ nữ","mo_ta_chinh":"Bộ đồ nữ gồm áo và chân váy","chat_lieu":"Không xác định","tinh_nang_vai":"Không xác định","gioi_tinh":"Nữ","phong_cach":"Trẻ trung, năng động","mua":"Không xác định","dip_mac":"Dạo phố, đi chơi","tags":"Bộ đồ nữ, áo, chân váy","do_tuoi":"Không xác định","loi_song":"Tự tin, năng động","tinh_cach":"Trẻ trung, cá tính","ly_do_mua":"Không xác định","cross_sell":"Không xác định","hook_quang_cao":"Thỏa sức tự tin","tagline":"Phong cách trẻ trung","mau_sac":"Tím/ Purple,Be/ Beige"}
{"ten_san_pham":"Áo len bé gái có hình in","mo_ta_chinh":"Áo len bé gái dáng cơ bản, form gọn giúp bé vận động thoải mái mà vẫn giữ vẻ gàng gọn. Thiết kế cổ tròn tay dài đơn giản, phần hình in ở thân trước tạo điểm nhấn thị giác ngay từ cái nhìn đầu tiên. Hơi hướng giao mùa, giúp giữ ấm vùng cơ thể hiệu quả khi thời tiết chênh lệch.","chat_lieu":"Không xác định","tinh_nang_vai":"Không xác định","gioi_tinh":"Nữ","phong_cach":"Cute, Comfort, Everyday","mua":"Thu – Đông (những ngày se lạnh/giao mùa)","dip_mac":"Đi học · Đi chơi cuối tuần · Dạo phố nhẹ buổi chiều · Chụp ảnh kỷ niệm · Mặc ở nhà khi trời se","tags":"áo len bé gái, áo len, cổ tròn, tay dài, hình in, màu trắng, giao mùa, mặc hằng ngày","do_tuoi":"4-10","loi_song":"Cho bé phong cách dễ thương, sạch sẽ, gọn gàng—mặc đi học, đi chơi hay dạo nhẹ đều lên dáng nhanh.","tinh_cach":"Nhí nhảnh, tự tin và yêu thích những chi tiết in nổi bật để mỗi ngày đều có cảm giác “xinh hơn”.","ly_do_mua":"Phom gọn dễ vận động cho bé | Cổ tròn tay dài hợp thời tiết giao mùa | Hình in trên thân trước tạo điểm nhấn nổi bật, dễ phối nhiều kiểu đáy","cross_sell":"Quần jean, Chân váy xếp ly, Legging","hook_quang_cao":"Áo len nền trắng với hình in trước ngực tạo điểm nhấn “xinh ngay” — mặc lên là bé trông gọn gàng, ấm áp và tự tin hơn trong mọi hoạt động thường ngày.","tagline":"Ấm áp vừa đủ, nổi bật nhờ họa tiết in dễ thương trên nền trắng.","mau_sac":"Trắng/ White,Hồng/ Pink- Magenta"}
{"ten_san_pham":"Áo len gilet bé gái","mo_ta_chinh":"Form gilet ôm nhẹ quanh vai và eo, giúp bé trông gọn gàng, không bị phồng. Thiết kế không tay với cổ tròn và dệt kim mềm mại màu be, mang lại vẻ dễ thương và linh hoạt cho mọi hoạt động. Vải len ấm áp giữ nhiệt tốt, tạo cảm giác ấm áp, thoải mái ngay khi thời tiết bắt đầu se lạnh.","chat_lieu":"Không xác định","tinh_nang_vai":"Không xác định","gioi_tinh":"Nữ","phong_cach":"Casual, cute, minimalist","mua":"Thu, xuân chuyển lạnh","dip_mac":"Đi học hàng ngày · Dạo phố cuối tuần · Tiệc sinh nhật bé · Kỳ nghỉ gia đình","tags":"áo len gilet bé gái, áo len trẻ em, gilet bé gái, áo len ấm, thời trang trẻ em, canifa","do_tuoi":"3-10 tuổi","loi_song":"Mẹ bận rộn muốn bé luôn thoải mái, năng động và dễ dàng di chuyển trong mọi hoạt động hàng ngày.","tinh_cach":"Vui tươi, năng động, thích khám phá và luôn muốn thể hiện cá tính riêng.","ly_do_mua":"Len mềm mại, ấm áp, form gilet giúp bé di chuyển tự do; màu be dễ phối với nhiều trang phục; chất lượng Canifa đảm bảo độ bền và an toàn cho da trẻ.","cross_sell":"Áo nỉ bé gái, Quần legging mặc nhà, Bộ áo khoác gió","hook_quang_cao":"Gilet len bé gái – bí quyết giữ ấm và phong cách cho mùa chuyển lạnh!","tagline":"Ấm áp từng khoảnh khắc, tỏa sáng mỗi ngày","mau_sac":"Be/ Beige"}
{"ten_san_pham":"Áo sơ mi bé gái chiết ly tay bồng","mo_ta_chinh":"Phom dáng relaxed fit nhẹ nhàng, vừa vặn vừa thoải mái, giúp bé không bị gò bó khi vận động. Thiết kế tay bồng mềm mại cùng chiết ly tinh tế tạo nên vẻ nữ tính, duyên dáng cho các bé gái. Khi mặc, áo giúp tôn dáng nhẹ nhàng, tạo cảm giác tự tin và thoải mái suốt cả ngày.","chat_lieu":"Không xác định","tinh_nang_vai":"Không xác định","gioi_tinh":"Nữ","phong_cach":"Cute Casual, Girl Power","mua":"Xuân, Hè","dip_mac":"Đi học·Tiệc sinh nhật·Ngày hội gia đình·Chụp ảnh ngoài trời","tags":"áo sơ mi bé gái, áo tay bồng, chiết ly mềm mại, thời trang trẻ em, cute casual","do_tuoi":"3-10","loi_song":"Mẹ hiện đại, quan tâm tới phong cách và sự thoải mái của con, thích lựa chọn trang phục dễ mix & match cho các hoạt động hàng ngày và các dịp đặc biệt.","tinh_cach":"Vui tươi, năng động, yêu thích khám phá thế giới quanh mình","ly_do_mua":"Thiết kế tay bồng và chiết ly mềm mại giúp bé nổi bật mà vẫn thoải mái, chất liệu nhẹ nhàng phù hợp với da nhạy cảm, dễ dàng kết hợp với nhiều loại trang phục khác.","cross_sell":"Quần legging pastel, Dép búp bê, Bộ mặc nhà cotton mềm mại","hook_quang_cao":"Chiếc áo sơ mi bồng bềnh khiến bé luôn là trung tâm của mọi ánh nhìn!","tagline":"Duyên dáng mỗi bước chạy của bé","mau_sac":"Trắng/ White"}
{"ten_san_pham":"Áo peplum kẻ sọc","mo_ta_chinh":"Áo peplum nữ với thiết kế sọc kẻ, tay phồng và cổ tròn","chat_lieu":"Không xác định","tinh_nang_vai":"Không xác định","gioi_tinh":"Nữ","phong_cach":"Nữ tính, trẻ trung","mua":"Không xác định","dip_mac":"Dịp mặc hàng ngày, sự kiện","tags":"Áo peplum, áo sọc, áo nữ","do_tuoi":"Không xác định","loi_song":"Nữ tính, thời trang","tinh_cach":"Tự tin, năng động","ly_do_mua":"Thiết kế độc đáo, màu sắc bắt mắt","cross_sell":"Áo khoác, chân váy","hook_quang_cao":"Áo peplum kẻ sọc, phong cách nữ tính","tagline":"Phong cách nữ tính, thời trang","mau_sac":"Hồng/ Pink- Magenta,Xanh da trời/ Blue"}
{"ten_san_pham":"Áo phông bé gái cotton USA in hình Stitch","mo_ta_chinh":"Dáng crop tinh tế, tôn dáng khỏe khoắn, thiết kế in hình Stitch đáng yêu, tạo cảm giác năng động và trẻ trung cho bé.","chat_lieu":"Cotton USA 100%","tinh_nang_vai":"Thấm hút mồ hôi, thoáng mát, nhẹ nhàng, giữ form sau nhiều lần giặt","gioi_tinh":"Nữ","phong_cach":"Casual, Kids","mua":"Xuân Hè","dip_mac":"Học đường · Đi chơi cùng bạn bè · Chơi ngoài trời · Tham gia lớp vẽ","tags":"áo phông bé gái, cotton USA, in Stitch, áo crop, áo thun bé, thời trang bé gái","do_tuoi":"Trẻ em 0-5 tuổi","loi_song":"Bé yêu thích hoạt động ngoài trời, sáng tạo, luôn vui tươi và muốn thể hiện cá tính qua trang phục","tinh_cach":"Tươi sáng, năng động, thân thiện","ly_do_mua":"Chất liệu cotton thoáng mát, thiết kế crop vừa phải, hình in yêu thích, phù hợp với mọi hoạt động của bé","cross_sell":"Quần soóc, Váy liền, Áo khoác nhẹ","hook_quang_cao":"Chiếc áo phông nhỏ bé, in Stitch, khiến bé bạn luôn nổi bật và tự tin!","tagline":"Bé xinh, phong cách, ấm áp","mau_sac":"Trắng/ White"}
{"ten_san_pham":"Áo thun nữ ngắn tay","mo_ta_chinh":"Áo thun nữ ngắn tay màu hồng","chat_lieu":"Không xác định","tinh_nang_vai":"Không xác định","gioi_tinh":"Nữ","phong_cach":"Nữ, trẻ trung","mua":"Không xác định","dip_mac":"Hàng ngày","tags":"Áo thun nữ, áo thun ngắn tay, áo thun màu hồng","do_tuoi":"Trẻ em","loi_song":"Nữ, trẻ trung","tinh_cach":"Nữ, trẻ trung","ly_do_mua":"Thiết kế độc đáo, màu sắc nổi bật","cross_sell":"Không xác định","hook_quang_cao":"Thiết kế độc đáo, màu sắc nổi bật","tagline":"Carousel Dreams","mau_sac":"Trắng/ White"}
{"ten_san_pham":"Áo nỉ bé gái mũ tai gấu có hình in","mo_ta_chinh":"Phom dáng suông thoải mái, hack chiều cao và che nhẹ vòng 1 cho bé gái. Thiết kế mũ tai gấu 3D trang trí, kết hợp hình in ngộ nghĩnh theo chủ đề hoạt hình. Vải nỉ pha mềm mại giúp giữ ấm hiệu quả mà không bị bết dính.","chat_lieu":"Cotton pha mềm mại","tinh_nang_vai":"Co giãn nhẹ, thấm hút tốt, giữ ấm hiệu quả","gioi_tinh":"Nữ","phong_cach":"Casual, Dễ thương","mua":"Thu Đông","dip_mac":"Đi học trường · Vui chơi ngoài trời · Đi dã ngoại · Tập thể thao","tags":"áo nỉ bé gái, mũ tai gấu, áo có hình in, thời trang trẻ em, cotton pha","do_tuoi":"Trẻ em (3-12 tuổi)","loi_song":"Bé gái năng động, thích khám phá thế giới xung quanh","tinh_cach":"Tự tin, sáng tạo, yêu thích sự thoải mái","ly_do_mua":"Form dáng hack chiều cao hiệu quả | Thiết kế mũ tai gấu nổi bật cá tính | Vải nỉ mềm mại ôm dáng bé","cross_sell":"Quần nỉ, Giày sneaker, Tất họa tiết dễ thương","tagline":"Dáng chuẩn, tinh nghịch như chú gấu bông","mau_sac":"Đen/ Black"}
{"ten_san_pham":"Combo 3 đôi tất bé trai cổ trung","mo_ta_chinh":"Combo 3 đôi tất bé trai cổ trung ôm vừa và dễ chịu, giúp chân bé gọn gàng hơn khi di chuyển. Thiết kế cổ trung vừa đủ che phủ, chất liệu mềm mại tạo cảm giác êm nhẹ cho đôi chân trong suốt cả ngày. Tất giúp bé thoải mái vận động hằng ngày, đồng thời phối màu tươi sáng giúp trang phục nhìn đồng bộ và đáng yêu hơn.","chat_lieu":"Không xác định","tinh_nang_vai":"Không xác định","gioi_tinh":"Boy","phong_cach":"Casual Kids, Active Daily","mua":"Quanh năm","dip_mac":"Đi học hằng ngày · Chơi ngoài sân trường · Đi chơi cuối tuần · Du lịch ngắn ngày · Hoạt động thể thao nhẹ","tags":"tất bé trai, tất cổ trung, combo 3 đôi, tất vận động, màu tươi sáng","do_tuoi":"2-12","loi_song":"Ưu tiên cảm giác dễ chịu cho bé trong nhịp ngày dài vận động, đồng thời giúp set đồ gọn gàng và dễ phối màu.","tinh_cach":"Năng động, tinh gọn, tươi mới và dễ thương theo kiểu trẻ con thích hoạt động.","ly_do_mua":"Ôm vừa để bé thoải mái khi vận động | Cổ trung giúp che phủ vừa đủ, nhìn gọn chân | Combo 3 đôi đổi màu linh hoạt cho cả tuần","cross_sell":"Áo phông · Quần soóc · Quần nỉ","hook_quang_cao":"Có combo 3 đôi là đủ đổi màu mỗi ngày — chân bé gọn gàng, set đồ lên hình liền tay!","tagline":"Ôm vừa êm chân, gọn dáng từng bước vận động.","mau_sac":"Trắng/ White,Xanh lá cây/ Green,Vàng/ Yellow + Gold"}
{"ten_san_pham":"Quần jeans nữ","mo_ta_chinh":"Quần jeans dáng rộng, cạp cao, thiết kế đơn giản","chat_lieu":"Không xác định","tinh_nang_vai":"Không xác định","gioi_tinh":"Nữ","phong_cach":"Casual","mua":"Không xác định","dip_mac":"Hàng ngày, đi chơi","tags":"quần jeans nữ, quần jeans dáng rộng","do_tuoi":"Không xác định","loi_song":"Năng động, thoải mái","tinh_cach":"Tự tin, thoải mái","ly_do_mua":"Thỏa mái, thời trang","cross_sell":"Áo chui đầu, giày sneaker","hook_quang_cao":"Quần jeans nữ, thoải mái và phong cách","tagline":"Thời trang cơ bản, thoải mái","mau_sac":"Màu xanh Jeans"}
{"ten_san_pham":"Quần jeans bé trai cotton túi hộp dáng suông","mo_ta_chinh":"Dáng suông thoải mái, giúp tôn vóc dáng trẻ em. Thiết kế túi hộp và ly súp khỏe khoắn mang lại phong cách năng động. Chất liệu 100% cotton thoáng mát, dễ chịu, làm cho bé cảm thấy thoải mái trong mọi hoạt động.","chat_lieu":"Chất liệu 100% cotton","tinh_nang_vai":"Co giãn nhẹ, thoáng mát, dễ chịu","gioi_tinh":"Nam","phong_cach":"Casual, Streetwear","mua":"Xuân Hè","dip_mac":"Đi học · Đi chơi cùng bạn bè · Tham gia hoạt động ngoại khóa · Kỷ niệm sinh nhật","tags":"quần jean bé trai, jeans cotton, quần túi hộp, quần suông, quần trẻ em, phong cách trẻ trung","do_tuoi":"3-12 tuổi","loi_song":"Bé trai năng động, thích khám phá, luôn muốn thể hiện phong cách cá nhân trong mọi hoạt động.","tinh_cach":"Sáng tạo, tự tin, năng động","ly_do_mua":"Chất liệu cotton thoáng mát, dáng suông thoải mái, phù hợp với mọi hoạt động học tập và chơi đùa, mang lại phong cách trẻ trung, năng động.","cross_sell":"Áo phông, Quần soóc, Áo nỉ","hook_quang_cao":"Cùng bé yêu khám phá phong cách thời trang, quần jeans suông tinh tế, phù hợp mọi hoạt động từ lớp học đến chơi đùa.","tagline":"Nét trẻ trung, phong cách tự do","mau_sac":"Màu xanh Jeans"}
{"ten_san_pham":"Quần jeans bé trai cotton dáng suông","mo_ta_chinh":"Quần jeans sở hữu form dáng suông phóng khoáng, giúp bé yêu tự do vận động mà không hề gò bó. Điểm nhấn cạp chun kèm dây rút thông minh mang đến sự tiện lợi tối đa, giúp bé dễ dàng tự mặc đồ. Thiết kế tối giản giúp tôn lên vẻ ngoài năng động, giúp đôi chân trông thon dài và thoát dáng hơn.","chat_lieu":"Denim mỏng nhẹ","tinh_nang_vai":"Chất vải denim mỏng nhẹ tạo cảm giác thoáng mát, không gây hầm bí, giữ form dáng ổn định dù bé vận động liên tục.","gioi_tinh":"Boy","phong_cach":"Năng động, Casual, Streetwear","mua":"Quanh năm","dip_mac":"Đến trường · Vui chơi cuối tuần · Dã ngoại cùng gia đình · Đi học thêm","tags":"quan jean be trai, denim suong, thoi trang tre em, canifa, quan jean chun","do_tuoi":"Kid","loi_song":"Ưa thích khám phá, vận động ngoài trời và yêu sự thoải mái","tinh_cach":"Năng động, tự tin, phóng khoáng","ly_do_mua":"Form suông hack dáng cực đỉnh | Cạp chun dây rút tiện lợi tự mặc | Chất liệu denim nhẹ nhàng cho bé vận động","cross_sell":"Áo phông, Áo nỉ có mũ, Áo khoác gió","hook_quang_cao":"Bụi bặm chuẩn chất denim, thoải mái chuẩn form mẹ chọn!","tagline":"Bụi bặm đúng điệu, thoải mái chuẩn gu","mau_sac":"Màu xanh Jeans"}
{"ten_san_pham":"Quần nỉ bé trai","mo_ta_chinh":"Quần nỉ bé trai có form regular fit ôm nhẹ, giúp tôn dáng thon gọn cho các bé mà không gây gò bó. Thiết kế màu xám trung tính cùng đường may tinh tế tạo cảm giác trẻ trung, dễ dàng phối cùng mọi loại áo. Khi mặc, chất vải nỉ mềm mại giữ ấm, đồng thời cho bé thoải mái vận động và không cảm thấy lạnh trong những buổi chiều se se.","chat_lieu":"Không xác định","tinh_nang_vai":"Không xác định","gioi_tinh":"Nam","phong_cach":"Casual, playful, streetwear nhẹ nhàng","mua":"Thu – Đông","dip_mac":"Đi học buổi sáng · Dạo phố cuối tuần · Chơi công viên mùa thu · Tham gia sinh nhật bạn bè · Xem phim tại nhà","tags":"quần nỉ bé trai, quần nỉ xám, thời trang trẻ em, canifa bé trai, quần nỉ nam trẻ","do_tuoi":"2-7 tuổi","loi_song":"Bé yêu thích hoạt động ngoài trời, tham gia các lớp học, dạo chơi công viên và những buổi hội họp gia đình.","tinh_cach":"Năng động, tinh nghịch, luôn muốn khám phá và thoải mái trong mọi hoạt động.","ly_do_mua":"Form regular fit giúp bé trông thon gọn, chất vải nỉ mềm mại giữ ấm và thoải mái, màu xám dễ dàng phối cùng mọi áo, phù hợp cho nhiều dịp từ học tập đến vui chơi.","cross_sell":"Áo nỉ có mũ, Quần leggings mặc nhà, Bộ mặc nhà cho bé","hook_quang_cao":"Quần nỉ siêu ấm cho bé, vừa thoải mái vừa thời trang – chỉ một cú click!","tagline":"Ấm áp từng bước, phong cách thỏa sức","mau_sac":"Xám/ Gray"}
{"ten_san_pham":"Quần soóc bé trai cotton cạp chun có túi","mo_ta_chinh":"Chiếc quần soóc sở hữu form dáng basic linh hoạt, dễ dàng đồng hành cùng bé trong mọi hoạt động vui chơi. Thiết kế cạp chun kèm dây rút giúp ôm vừa vặn cơ thể, dễ dàng điều chỉnh kích thước để bé luôn thoải mái. Chất liệu cotton cao cấp được giặt mềm thành phẩm mang lại trải nghiệm êm ái, thoáng mát tuyệt đối trên da.","chat_lieu":"100% cotton","tinh_nang_vai":"Độ thấm hút cao, bề mặt vải mềm mại, thân thiện với làn da, thoáng khí và có khả năng bền form sau nhiều lần giặt","gioi_tinh":"Boy","phong_cach":"Casual, Năng động","mua":"Xuân Hè","dip_mac":"Đến trường · Vui chơi công viên · Dã ngoại cùng gia đình · Du lịch biển","tags":"quần soóc, bé trai, cotton, cạp chun, đồ hè, basic","do_tuoi":"Kid","loi_song":"Năng động, ưa khám phá, yêu thích sự thoải mái","tinh_cach":"Hoạt bát, vui vẻ, thích vận động","ly_do_mua":"Chất liệu 100% cotton mềm mại | Cạp chun điều chỉnh linh hoạt | Thiết kế basic dễ mặc, dễ phối","cross_sell":"Áo phông, Áo Polo, Áo ba lỗ","hook_quang_cao":"Lựa chọn hoàn hảo cho ngày dài năng động – vừa thoáng mát, vừa chuẩn gu!","tagline":"Thoải mái vận động, tự tin khám phá","mau_sac":"Đen/ Black"}
{"mau_sac":"Xám/ Gray"}
{"ten_san_pham":"Quần short thể thao nam","mo_ta_chinh":"Quần short thể thao nam, thiết kế đơn giản, màu sắc trẻ trung.","chat_lieu":"Không xác định","tinh_nang_vai":"Không xác định","gioi_tinh":"Nam","phong_cach":"Thể thao","mua":"Không xác định","dip_mac":"Tập thể dục, du lịch, thời trang đường phố","tags":"quần short nam, quần short thể thao, thời trang nam","do_tuoi":"Không xác định","loi_song":"Năng động, thể thao","tinh_cach":"Tự tin, thoải mái","ly_do_mua":"Thời trang, thoải mái, giá cả phải chăng","cross_sell":"Áo thể thao, giày chạy bộ","hook_quang_cao":"Quần short thể thao nam - phong cách và thoải mái","tagline":"Thời trang thể thao cho nam giới","mau_sac":"Xám/ Gray"}
{"ten_san_pham":"Áo khoác gió active bé trai có hình in","mo_ta_chinh":"Form dáng 2 lớp ôm vừa vặn, thiết kế can phối màu năng động cùng hình in khỏe khoắn. Chất liệu chống gió 2 lớp tăng độ bền, giúp bảo vệ bé trong mọi hoạt động ngoài trời. Kiểu dáng trẻ trung, dễ phối đồ và che khuyết điểm tối ưu cho cơ thể nhỏ.","chat_lieu":"Áo khoác gió 2 lớp, can phối màu, in chữ khỏe khoắn","tinh_nang_vai":"Chống gió, thiết kế 2 lớp tăng độ bền, can phối màu tạo điểm nhấn năng động","gioi_tinh":"Nam","phong_cach":"Thể thao, trẻ trung","mua":"Thu Đông","dip_mac":"Vui chơi ngoài trời · Học thể thao · Đi dã ngoại · Làm việc nhóm ở trường","tags":"áo khoác gió, bé trai, thể thao, in hình, trẻ em","do_tuoi":"6-12 tuổi","loi_song":"Trẻ trung, năng động, thích khám phá và vui chơi ngoài trời.","tinh_cach":"Năng động, tinh nghịch, yêu thích sự tiện lợi.","ly_do_mua":"Thiết kế 2 lớp chống gió, in hình bắt mắt, dễ phối đồ, phù hợp cho nhiều hoạt động ngoài trời.","cross_sell":"Áo phông in hình, Quần short thể thao, Mũ lưỡi trai","hook_quang_cao":"Áo khoác in hình sôi động – bạn đồng hành cho bé khám phá thế giới!","tagline":"Phiêu lưu mỗi ngày","mau_sac":"Xanh da trời/ Blue"}
{"ten_san_pham":"Áo khoác chần bông bé trai chống thấm nước","mo_ta_chinh":"Áo khoác chần bông dành cho bé trai, thiết kế dáng thon gọn giúp tôn vóc nhỏ bé. Cổ cao, mũ trùm đầu tạo vẻ trẻ trung, thoáng mát. Chống thấm nước đặc biệt bảo vệ bé tránh ướt khi chơi ngoài trời, đồng thời giữ ấm nhẹ nhàng.","chat_lieu":"Vải chống thấm nước đặc biệt","tinh_nang_vai":"Chống thấm nước, thoáng khí, nhẹ nhàng, bền bỉ","gioi_tinh":"Bé trai","phong_cach":"Family Casual, Outdoor","mua":"Mùa mưa, mùa thu, mùa đông","dip_mac":"Đi bộ đường dài · Tham gia lớp học nấu ăn · Đi picnic · Tham quan công viên","tags":"áo khoác bé trai,chần bông,chống thấm nước,áo khoác trẻ em,áo khoác ngoài trời,áo khoác mưa,Canifa","do_tuoi":"3-6 tuổi","loi_song":"Gia đình năng động, cha mẹ quan tâm tới sự thoải mái và an toàn cho bé, thích khám phá thiên nhiên","tinh_cach":"Tự tin, năng động, luôn sẵn sàng","ly_do_mua":"Chống thấm nước, thiết kế trẻ trung, phù hợp mọi hoạt động ngoài trời","cross_sell":"Quần legging, Áo len gilet, Bộ mặc nhà trẻ em","hook_quang_cao":"Chiếc áo khoác chần bông bé trai chống thấm nước: Đối tác lý tưởng cho những ngày mưa ướt, bảo vệ bé luôn khô ráo và ấm áp!","tagline":"Bảo vệ bé, giữ ấm, luôn khởi đầu nồng ấm","mau_sac":"Đen/ Black"}
{"ten_san_pham":"Áo khoác chần bông bé trai chống thấm nước","mo_ta_chinh":"Thiết kế chần bông hiện đại với phom dáng chuẩn, giúp bé luôn ấm áp mà vẫn linh hoạt trong mọi vận động. Lớp phủ chống thấm nước thông minh bảo vệ bé trước những cơn mưa bất chợt hay gió mùa khắc nghiệt. Hệ thống bo chun tinh tế ở gấu, nách và mũ giúp ôm trọn cơ thể, cản gió tuyệt đối để bé thỏa sức vui chơi.","chat_lieu":"Lớp ngoài phủ chống bám nước, lớp chần bông giữ nhiệt","tinh_nang_vai":"Chống thấm nước bề mặt, giữ ấm, cản gió, form dáng cứng cáp","gioi_tinh":"Nam","phong_cach":"Sporty, Outdoor, Casual","mua":"Thu - Đông","dip_mac":"Đến trường ngày mưa · Đi dã ngoại ngoài trời · Vui chơi công viên · Những chuyến du lịch cùng gia đình","tags":"áo khoác bé trai, áo khoác chần bông, áo khoác chống nước, thời trang trẻ em, áo khoác mùa đông","do_tuoi":"3-15","loi_song":"Năng động, thích khám phá và tham gia các hoạt động ngoại khóa","tinh_cach":"Hoạt bát, khỏe khoắn, tự tin","ly_do_mua":"Công nghệ chống thấm nước ưu việt | Thiết kế bo chun giữ ấm tuyệt đối | Phom dáng năng động, dễ dàng phối đồ","cross_sell":"Áo giữ nhiệt, Quần nỉ, Áo nỉ có mũ","hook_quang_cao":"Lá chắn hoàn hảo cho bé yêu trước mọi thời tiết thất thường","tagline":"Vững bước khám phá, thách thức mọi thời tiết","mau_sac":"Đen/ Black"}
{"ten_san_pham":"Bộ quần áo nỉ cào lông bé trai in hình Pixar Charater","mo_ta_chinh":"Bộ nỉ với form dáng cơ bản dễ mặc, giúp bé vận động linh hoạt suốt ngày dài. Áo có mũ che chắn gió kết hợp quần dài bo gấu gọn gàng, tạo vẻ ngoài chỉn chu nhưng đầy năng động. Mặt trong cào lông nhẹ vừa giữ ấm tối ưu, vừa mang lại cảm giác êm ái, nâng niu làn da bé.","chat_lieu":"Nỉ Cotton pha","tinh_nang_vai":"Chất liệu mềm mại, cào lông nhẹ giữ ấm hiệu quả, bền màu và giữ form tốt sau nhiều lần giặt.","gioi_tinh":"Nam","phong_cach":"Sporty, Casual, Năng động","mua":"Thu Đông","dip_mac":"Đi học · Đi chơi công viên · Vui chơi tại gia · Dã ngoại cùng gia đình","tags":"bộ nỉ, bé trai, pixar, giữ ấm, thời trang trẻ em, canifa","do_tuoi":"4-14 tuổi","loi_song":"Năng động, thích khám phá, yêu thích các nhân vật hoạt hình","tinh_cach":"Hoạt bát, đáng yêu, tự tin","ly_do_mua":"Chất liệu nỉ cotton mềm mại, giữ ấm tốt | Thiết kế in hình Pixar bắt mắt | Form dáng linh hoạt, tiện lợi cho mọi hoạt động","cross_sell":"Áo giữ nhiệt, Áo khoác chần bông, Tất","hook_quang_cao":"Gói gọn sự ấm áp và cá tính trong thiết kế Pixar dành riêng cho bé trai!","tagline":"Ấm áp trọn vẹn, bé tự tin phiêu lưu","mau_sac":"Xanh da trời/ Blue"}
{"ten_san_pham":"Áo sát nách bé trai cotton USA có hình in","mo_ta_chinh":"Áo sát nách bé trai ôm gọn vừa đủ, giúp bé thoải mái vận động cả ngày. Thiết kế hình in phong cách năng động khỏe khoắn phủ bắt mắt, tạo điểm nhấn rõ ràng trên dáng áo. Nhờ chất cotton mềm mại, bé dễ chịu khi mặc trong các hoạt động thường nhật từ trường học đến vui chơi ngoài trời.","chat_lieu":"Không xác định","tinh_nang_vai":"Không xác định","gioi_tinh":"Boy","phong_cach":"Năng động khỏe khoắn, Casual, Hình in","mua":"Mùa hè / Xuân hè","dip_mac":"Trường học ngày hè · Vui chơi ngoài trời · Đi dã ngoại cuối tuần · Sinh nhật/tiệc nhẹ · Ở nhà vận động","tags":"áo sát nách bé trai, cotton, hình in, năng động, khỏe khoắn, đồ thường ngày, áo ba lỗ","do_tuoi":"5-12","loi_song":"Thúc đẩy nhịp sống năng động của bé—thích vận động, thích khám phá, hợp cho những ngày bận rộn học tập và vui chơi.","tinh_cach":"Năng động, tự tin, tinh nghịch và thích sự mới mẻ từ chi tiết hình in.","ly_do_mua":"Hình in năng động tạo điểm nhấn nổi bật | Form sát nách giúp vận động thoải mái | Dễ phối đồ từ quần soóc, jean đến quần mặc nhà","cross_sell":"Quần soóc + Quần jean + Áo khoác gió","hook_quang_cao":"Áo sát nách hình in—mặc lên là ra dáng ‘nghịch mà gọn’, chơi thả ga không cần nghĩ nhiều.","tagline":"Năng động bật mood—mặc lên là muốn chạy nhảy.","mau_sac":"Vàng/ Yellow + Gold"}
{"ten_san_pham":"Áo len gilet bé trai có hình in","mo_ta_chinh":"Định hình dáng bé với kiểu dáng gilet nhẹ nhàng, tôn dáng tròn trịa. Thiết kế in hình thú cưng mang tính vui tươi, phù hợp cho các hoạt động ngoài trời. Gợi cảm giác ấm áp, thoải mái, giúp bé tự tin bước vào ngày mới.","chat_lieu":"Acrylic pha","tinh_nang_vai":"Không xác định","gioi_tinh":"Boy","phong_cach":"Casual, Streetwear","mua":"Xuân, Hè","dip_mac":"Đi học · Chơi ngoài trời · Dạo phố cùng gia đình · Kì nghỉ hè","tags":"áo len gilet bé, gilet trẻ em, áo len bé, gilet in hình, canifa, bé trai, thời trang trẻ em","do_tuoi":"0-12","loi_song":"Bé năng động, yêu thích hoạt động ngoài trời, luôn muốn thoải mái và sáng tạo trong phong cách thời trang.","tinh_cach":"Vui tính, năng động, đầy tò mò","ly_do_mua":"Gilet nhẹ, in hình dễ thương, hack dáng tròn trịa, dễ phối, phù hợp với mọi hoạt động","cross_sell":"Áo nỉ, Quần soóc, Áo khoác gió","hook_quang_cao":"Chiếc gilet in hình đáng yêu, làm mới phong cách của bé ngay từ đầu!","tagline":"Vui tươi, ấm áp, gương mặt bé cười tươi","mau_sac":"Xanh than/ Aqua,Đỏ/ Red,Xám/ Gray"}
{"ten_san_pham":"Áo len bé trai cổ bẻ có hình in","mo_ta_chinh":"Form relax fit rộng rãi, mang lại cảm giác thoải mái cho các bé suốt cả ngày. Thiết kế cổ bẻ phong cách polo kết hợp họa tiết dệt chữ nổi bật, tạo điểm nhấn sport năng động. Áo giúp tôn lên vóc dáng mảnh mai, che nhẹ phần vai rộng, khiến bé luôn tự tin và năng động.","chat_lieu":"Không xác định","tinh_nang_vai":"Không xác định","gioi_tinh":"Nam","phong_cach":"Casual, Sporty","mua":"Mùa thu, Mùa đông","dip_mac":"Đi học hàng ngày · Dạo công viên buổi chiều · Lễ hội gia đình · Chụp ảnh sinh nhật","tags":"áo len, bé trai, cổ bẻ, sport, casual, trẻ em, áo len polo","do_tuoi":"3-12 tuổi","loi_song":"Phụ huynh hiện đại muốn con mình luôn năng động, thoải mái và thời trang trong các hoạt động hàng ngày – từ học tập, chơi đùa tới các buổi tiệc gia đình.","tinh_cach":"Năng động, tự tin, yêu khám phá","ly_do_mua":"Form relax fit giúp bé di chuyển tự do, thiết kế cổ bẻ và họa tiết sport tạo nét trẻ trung, chất liệu mềm mại mang lại cảm giác ấm áp và thoải mái suốt ngày dài.","cross_sell":"Quần jogger xanh, Áo khoác gió nhẹ, Bộ thể thao trẻ em","hook_quang_cao":"Áo len polo trẻ thơ – thoải mái, năng động, sẵn sàng cho mọi cuộc phiêu lưu!","tagline":"Phong cách sport, năng động mỗi ngày","mau_sac":"Trắng/ White,Xanh da trời/ Blue"}
{"mau_sac":"Xanh da trời/ Blue"}
{"ten_san_pham":"Áo thun dài tay nam","mo_ta_chinh":"Áo thun dài tay nam có in đồ họa","chat_lieu":"Không xác định","tinh_nang_vai":"Không xác định","gioi_tinh":"Nam","phong_cach":"Thể thao, đường phố","mua":"Không xác định","dip_mac":"Hàng ngày, thể thao","tags":"Áo thun, áo dài tay, thời trang thể thao","do_tuoi":"Không xác định","loi_song":"Năng động, thể thao","tinh_cach":"Tự tin, thoải mái","ly_do_mua":"Thiết kế độc đáo, giá cả hợp lý","cross_sell":"Áo khoác thể thao","hook_quang_cao":"Thiết kế độc đáo, thoải mái","tagline":"Thời trang thể thao","mau_sac":"Trắng/ White"}
{"ten_san_pham":"Áo polo bé trai dài tay cotton USA có hình in","mo_ta_chinh":"Áo polo dài tay với phom dáng khỏe khoắn, ôm vừa vặn cơ thể nhưng vẫn đảm bảo độ thông thoáng tối đa. Thiết kế tinh tế với chi tiết phối màu ở cổ và tay áo, tạo điểm nhấn thu hút mọi ánh nhìn. Hình in thể thao sắc nét giúp tôn lên vẻ ngoài năng động, hack dáng cho các bé trai trong mọi hoạt động.","chat_lieu":"Cotton USA","tinh_nang_vai":"Độ bền cao, sợi vải mềm mại thân thiện với làn da, thoáng khí vượt trội giúp bé luôn thoải mái khi vận động suốt ngày dài.","gioi_tinh":"Nam","phong_cach":"Sporty, Casual, Năng động","mua":"Thu, Đông, Xuân","dip_mac":"Đi học · Tham gia câu lạc bộ thể thao · Dã ngoại cùng gia đình · Đi chơi cuối tuần","tags":"polo, polo dài tay, bé trai, cotton usa, thể thao, canifa","do_tuoi":"6-14","loi_song":"Bé trai hiếu động, thích khám phá và tham gia các hoạt động ngoại khóa tại trường.","tinh_cach":"Tự tin, hoạt bát, yêu thích sự khỏe khoắn.","ly_do_mua":"Chất liệu Cotton USA cao cấp, thoáng mát | Hình in thể thao sắc nét, cá tính | Phom dáng hack dáng, tôn lên nét khỏe khoắn của bé","cross_sell":"Quần jean, Quần Khaki, Áo khoác gió","hook_quang_cao":"Siêu phẩm Polo Cotton USA: Mềm mại cho da, mạnh mẽ cho phong cách!","tagline":"Năng động chuẩn chất, tự tin mỗi ngày","mau_sac":"Xanh da trời/ Blue"}
{"ten_san_pham":"Áo polo bé trai","mo_ta_chinh":"Áo polo cho bé trai được thiết kế gọn gàng, ôm vừa để bé thoải mái vận động mà không bị xộc xệch. Điểm nhấn phối màu ở cổ và tay áo cùng hình in sport khoẻ khoắn tạo dáng bắt mắt, giúp tổng thể trông “ngay ngắn” từ vai xuống thân. Chất cotton mềm mại thoáng mát giúp bé dễ chịu suốt cả ngày, phù hợp nhiều hoàn cảnh từ đi học đến vui chơi.","chat_lieu":"cotton","tinh_nang_vai":"Không xác định","gioi_tinh":"Boy","phong_cach":"Sporty, Năng động, Casual","mua":"Xuân-Hè","dip_mac":"Đi học hàng ngày · Chơi thể thao/hoạt động CLB · Dã ngoại cuối tuần · Đi chơi cùng gia đình · Du lịch ngắn ngày","tags":"áo polo, bé trai, cotton, cổ phối màu, tay áo phối màu, hình in sport, năng động","do_tuoi":"6-14","loi_song":"Thích phong cách thể thao gọn gàng, dễ mặc và sẵn sàng đồng hành cùng lịch trình ngày nào cũng bận rộn.","tinh_cach":"Năng động, hoạt bát, ưu tiên sự thoải mái và vẻ ngoài chỉn chu.","ly_do_mua":"Gọn gàng, tôn dáng cho bé nhờ thiết kế polo; phối cổ tay nổi bật nhưng vẫn dễ mặc; chất cotton mềm thoáng mát cho cả ngày vận động.","cross_sell":"Áo khoác gió · Quần soóc · Sneaker","tagline":"Gọn gàng năng động—mặc là thấy tự tin.","mau_sac":"Đen/ Black"}
{"ten_san_pham":"Áo hoodie nam in hình","mo_ta_chinh":"Áo hoodie nam màu đen, có mũ và hình in độc đáo","chat_lieu":"Không xác định","tinh_nang_vai":"Không xác định","gioi_tinh":"Nam","phong_cach":"Streetwear","mua":"Không xác định","dip_mac":"Casual","tags":"Áo hoodie, streetwear, nam giới","do_tuoi":"Không xác định","loi_song":"Năng động, cá tính","tinh_cach":"Mạnh mẽ, tự tin","ly_do_mua":"Thể hiện phong cách","cross_sell":"Áo phông, quần short","hook_quang_cao":"Thể hiện phong cách mạnh mẽ và cá tính","tagline":"Stay Wild","mau_sac":"Đen/ Black"}
{"ten_san_pham":"Áo nỉ bé trai cotton USA có hình in","mo_ta_chinh":"Form regular fit vừa vặn, cho bé thoải mái vận động mà không bị bó sát. Thiết kế tay dài với chi tiết mix màu và hình in năng động, mang lại vẻ trẻ trung, phá cách. Vải cotton USA mềm mại giữ ấm nhẹ, thấm hút mồ hôi, giúp làn da bé luôn khô thoáng suốt cả ngày.","chat_lieu":"Cotton USA 100%","tinh_nang_vai":"Không xác định","gioi_tinh":"Nam","phong_cach":"Casual, playful","mua":"Mùa thu, mùa đông","dip_mac":"Đi học hàng ngày · Dạo công viên buổi chiều · Lễ sinh nhật bé · Các buổi tiệc gia đình","tags":"áo nỉ bé trai, cotton usa, áo in trẻ em, áo nỉ dài tay, thời trang trẻ em, casual kids","do_tuoi":"3-10","loi_song":"Bé năng động, thích khám phá, tham gia các hoạt động ngoài trời, yêu màu sắc và sự thoải mái trong trang phục.","tinh_cach":"Vui tươi, hiếu động, tự tin trong mọi trò chơi.","ly_do_mua":"Form vừa vặn hack dáng bé, chất liệu cotton USA mềm mại an toàn, thiết kế hình in thời trang, đa màu sắc dễ mix & match, giữ ấm nhẹ cho mùa thu đông.","cross_sell":"Quần jean trẻ em, Áo khoác gió trẻ em, Giày sneaker trẻ em","hook_quang_cao":"Áo nỉ cotton USA – phong cách năng động cho bé, vừa ấm vừa thời thượng, chỉ cần một chiếc!","tagline":"Năng động từ đầu đến chân!","mau_sac":"Đỏ/ Red"}
{"ten_san_pham":"Áo thun in chữ ĐỘC LẬP","mo_ta_chinh":"Áo thun ngắn tay, in chữ ĐỘC LẬP màu vàng trên nền đỏ","chat_lieu":"Không xác định","tinh_nang_vai":"Không xác định","gioi_tinh":"Nam/Nữ (trẻ em)","phong_cach":"Streetwear, trẻ trung","mua":"Không xác định","dip_mac":"Hàng ngày, đi chơi","tags":"Áo thun, in chữ, streetwear, trẻ em","do_tuoi":"Trẻ em","loi_song":"Năng động, cá tính","tinh_cach":"Tự tin, trẻ trung","ly_do_mua":"Thể hiện phong cách","cross_sell":"Giày sneaker","hook_quang_cao":"Thể hiện cá tính, tự tin","tagline":"Thời trang đường phố, phong cách trẻ trung","mau_sac":"Đen/ Black"}
{"ten_san_pham":"Tất cổ Cao Trẻ Em | Canifa S x Tò he | Limited Item","mo_ta_chinh":"Form cổ cao ôm vừa khít, tôn dáng bé vừa duyên dáng vừa thoải mái. Thiết kế họa tiết in màu sắc rực rỡ, mang lại cảm giác vui tươi, khơi gợi trí tưởng tượng. Độ ôm chuẩn giúp giảm ma sát, giữ ấm nhẹ nhàng, hack dáng cho bé luôn tự tin trong từng bước chạy.","chat_lieu":"Cotton 100% (vải bông mềm mại)","tinh_nang_vai":"Co giãn nhẹ, thấm hút mồ hôi, không gây kích ứng da, giữ ấm nhẹ cho chân bé trong mọi hoạt động.","gioi_tinh":"Unisex","phong_cach":"Casual Kids, Playful","mua":"Mọi mùa – thích hợp cho mùa xuân, hè, thu, đông","dip_mac":"Đi học hàng ngày · Dạo công viên cuối tuần · Tham gia hoạt động ngoại khóa · Sinh nhật bé","tags":"tất, tất cổ cao, trẻ em, cotton, Canifa, Tò he, limited item, unisex","do_tuoi":"Trẻ em (3-12 tuổi)","loi_song":"Bé yêu thích sự năng động, thoải mái và muốn thể hiện cá tính qua những chi tiết đáng yêu.","tinh_cach":"Vui tươi, hồn nhiên, sáng tạo","ly_do_mua":"Cotton mềm mại, thấm hút tốt · Cổ cao hack dáng, giảm ma sát · Thiết kế in hình sáng tạo, khơi gợi trí tưởng tượng · Phù hợp mọi hoạt động hàng ngày của bé","cross_sell":"Áo phông, Quần jean, Áo khoác gió","hook_quang_cao":"Bước chân bé, ước mơ bay cao – Tất cổ cao Canifa x Tò he, đồng hành mỗi bước vui chơi!","tagline":"Bước chân nhẹ nhàng, ước mơ bay cao","mau_sac":"Trắng/ White"}
{"ten_san_pham":"Quần nỉ unisex trẻ em cotton USA có bo gấu","mo_ta_chinh":"Thiết kế dáng suông hiện đại với phần bo gấu tinh tế giúp bé vận động linh hoạt mà không lo vướng víu. Chất liệu nỉ cao cấp mang lại sự ấm áp vừa đủ, đồng thời tôn lên vẻ ngoài khỏe khoắn cho cả bé trai và bé gái. Form dáng chuẩn giúp bé luôn thoải mái trong mọi hoạt động vui chơi hàng ngày.","chat_lieu":"Cotton USA","tinh_nang_vai":"Chất nỉ mềm mại, co giãn thoải mái, giữ nhiệt tốt và thấm hút mồ hôi hiệu quả.","gioi_tinh":"Unisex","phong_cach":"Sporty, Casual, Năng động","mua":"Thu Đông, Xuân","dip_mac":"Đến trường · Vui chơi cuối tuần · Tập thể dục · Đi du lịch cùng gia đình","tags":"quan ni, tre em, cotton usa, unisex, bo gau","do_tuoi":"3-15","loi_song":"Ưa thích vận động, khám phá và luôn tràn đầy năng lượng.","tinh_cach":"Hoạt bát, hồn nhiên, năng động","ly_do_mua":"Chất liệu Cotton USA cao cấp · Thiết kế bo gấu hack dáng gọn gàng · Phù hợp cho cả bé trai và bé gái","cross_sell":"Áo nỉ có mũ, Áo phông, Tất","hook_quang_cao":"Chiếc quần 'must-have' cho tủ đồ của bé — mềm mại, ấm áp và cực kỳ tôn dáng vận động!","tagline":"Năng động tự do, vận động hết mình","mau_sac":"Xanh da trời/ Blue,Hồng/ Pink- Magenta,Xám/ Gray,Đen/ Black"}
{"ten_san_pham":"Áo khoác chống nắng unisex trẻ em","mo_ta_chinh":"Thiết kế dáng khoác trẻ trung với mũ trùm tiện lợi, giúp bảo vệ tối đa làn da nhạy cảm của bé dưới tác động của tia UV. Form áo suông nhẹ, khóa kéo linh hoạt mang đến sự thoải mái, không gây gò bó khi bé vận động. Đảm bảo vẻ ngoài chỉn chu, năng động mà vẫn hoàn thành xuất sắc nhiệm vụ bảo vệ cơ thể.","chat_lieu":"Không xác định","tinh_nang_vai":"Công nghệ AntiUV tiên tiến giúp cản tia tử ngoại, chất vải mỏng nhẹ, thoát hơi tốt, không gây hầm bí.","gioi_tinh":"Unisex","phong_cach":"Năng động, Tiện dụng","mua":"Xuân Hè","dip_mac":"Đi học mỗi ngày · Vui chơi công viên · Những chuyến dã ngoại cuối tuần · Tham gia hoạt động ngoại khóa ngoài trời","tags":"áo chống nắng, unisex, trẻ em, chống tia uv, áo khoác hè","do_tuoi":"3-12 tuổi","loi_song":"Bé năng động, thích các hoạt động ngoài trời, dã ngoại và đi học hàng ngày.","tinh_cach":"Hồn nhiên, hoạt bát, ưa khám phá","ly_do_mua":"Tính năng AntiUV bảo vệ da bé | Thiết kế unisex linh hoạt cho cả bé trai và gái | Form dáng nhẹ nhàng, dễ vận động","cross_sell":"Áo phông, Quần soóc, Quần dài","hook_quang_cao":"Bảo vệ làn da bé yêu ngay hôm nay với chiếc áo khoác chống nắng 'quốc dân'!","tagline":"Lá chắn hoàn hảo cho bé thỏa sức khám phá","mau_sac":"Tím/ Purple,Xanh da trời/ Blue"}
{"ten_san_pham":"Áo khoác chần bông unisex trẻ em chống thấm nước","mo_ta_chinh":"Form regular fit nhẹ nhàng, không gò bó, giúp bé di chuyển tự do. Thiết kế lớp ngoài phủ bám nước, bo chun gấu và mũ có cửa, tạo vẻ ngoài năng động và thời trang. Áo khoác giữ ấm, cản gió và bảo vệ da bé khỏi mưa nhỏ, mang lại cảm giác ấm áp suốt ngày dài.","chat_lieu":"Không xác định","tinh_nang_vai":"Chống thấm nước, giữ ấm, cản gió, bo chun gấu co giãn nhẹ, có thể giặt máy","gioi_tinh":"Unisex","phong_cach":"Casual Playful","mua":"Thu – Đông","dip_mac":"Đi học hàng ngày · Dã ngoại gia đình · Lễ hội sinh nhật · Đi dạo công viên","tags":"áo khoác chần bông, trẻ em, chống thấm nước, unisex, áo khoác mùa thu, Canifa","do_tuoi":"3-12","loi_song":"Bé yêu thích khám phá, tham gia các hoạt động ngoài trời và luôn muốn cảm thấy thoải mái, ấm áp mà vẫn thời trang.","tinh_cach":"Năng động, tò tự, tự tin trong mỗi bước chạy nhảy.","ly_do_mua":"Chống thấm nước giúp bé không lo bị ướt, bo chun gấu tăng độ co giãn, lớp ngoài giữ ấm và cản gió, thiết kế unisex phù hợp mọi bé, màu sắc đa dạng dễ phối đồ.","cross_sell":"Áo nỉ có mũ, Quần leggings mặc nhà, Bộ thể thao","hook_quang_cao":"Áo khoác chần bông đa màu, chống thấm nước – đồng hành cùng bé trong mọi chuyến phiêu lưu!","tagline":"Bảo vệ ấm áp, phong cách mỗi ngày","mau_sac":"Xanh da trời/ Blue,Xám/ Gray,Hồng/ Pink- Magenta,Đen/ Black,Trắng/ White"}
{"ten_san_pham":"Áo khoác chần bông unisex trẻ em Ultra Air +","mo_ta_chinh":"Áo khoác chần bông unisex dáng khoác gọn giúp giữ nhiệt hiệu quả mà không làm bé bị cồng kềnh khi vận động. Lớp phủ chống bám nước cùng bo chun ở gấu, cửa tay và cửa mũ tạo cảm giác ấm áp, hạn chế gió luồn vào cơ thể. Thiết kế tối ưu cho hoạt động ngoài trời, giúp bé thoải mái suốt hành trình từ đi học đến dạo chơi.","chat_lieu":"Không xác định","tinh_nang_vai":"Thiết kế lớp phủ chống bám nước; bo chun cửa tay, gấu và cửa mũ giúp cản gió tối đa","gioi_tinh":"Unisex","phong_cach":"Casual, Năng động, Ngoài trời","mua":"Mùa thu · Mùa đông · Những ngày lạnh đầu xuân","dip_mac":"Đi học hằng ngày · Đi chơi cuối tuần · Chơi công viên/ngoài trời · Du lịch ngày mưa lất phất · Thời tiết lạnh nhẹ","tags":"áo khoác chần bông, Ultra Air +, unisex trẻ em, chống bám nước, bo chun, giữ ấm, cản gió, có lớp phủ","do_tuoi":"4-14","loi_song":"Phù hợp cho nhịp sống năng động của trẻ: ra đường là chạy, đi học là di chuyển liên tục, cần một lớp áo giữ ấm và bảo vệ trước những cơn mưa nhỏ bất chợt.","tinh_cach":"Tự tin, tinh gọn, ưu tiên sự tiện dụng — mặc nhanh, ấm đúng chỗ và đồng hành cùng mọi hoạt động.","ly_do_mua":"Lớp phủ hỗ trợ chống bám nước cho những cơn mưa nhỏ · Bo chun gấu, cửa tay và cửa mũ giúp giữ ấm, cản gió tốt · Form dễ mặc, hợp mix nhiều kiểu quần cho bé đi học và đi chơi","cross_sell":"Quần nỉ, Áo giữ nhiệt, Quần jean","hook_quang_cao":"Áo khoác chần bông Ultra Air +: ấm đúng chỗ, cản gió tốt và sẵn sàng cho mưa lất phất — chỉ cần mặc là yên tâm.","tagline":"Chống nước nhẹ, giữ ấm gọn gàng — mặc là yên tâm cho những ngày bận rộn.","mau_sac":"Đen/ Black"}
{"ten_san_pham":"Bộ quần áo active unisex trẻ em","mo_ta_chinh":"Form dáng trẻ trung ôm nhẹ cơ thể, thiết kế áo cộc tay phối nón năng động cùng quần soóc ống đứng tạo cảm giác gọn gàng. Chất liệu vải pha sợi hiện đại thoáng khí, giúp bé vận động linh hoạt mà không lo mồ hôi đọng. Tông màu trẻ trung với phối màu hiện đại phù hợp cả diện tập gym hay đi dạo phố.","chat_lieu":"Không xác định","tinh_nang_vai":"Thoáng khí, co giãn nhẹ, thấm hút tốt","gioi_tinh":"Unisex","phong_cach":"Thể thao, năng động","mua":"Quanh năm","dip_mac":"Tập thể dục · Đi dã ngoại · Học võ · Đi chơi công viên","tags":"bộ active trẻ em, áo thể thao unisex, quần soóc ống đứng, đồ tập trẻ em, phối màu hiện đại","do_tuoi":"Trẻ em","loi_song":"Trẻ em năng động, yêu thích vận động và khám phá thế giới xung quanh","tinh_cach":"Nhí nhảnh, tinh nghịch, cá tính","ly_do_mua":"Thiết kế đa năng cho nhiều hoạt động · Chất liệu thoáng mát phù hợp vận động · Màu sắc trẻ trung dễ phối đồ","cross_sell":"Giày sneaker trẻ em, áo khoác bomber, ba lô thể thao","hook_quang_cao":"Bộ active cho trẻ em - diện đi tập thể thao hay đi dạo phố đều 'sống ảo' cực chất!","tagline":"Diện năng động, tỏa sáng mọi lúc","mau_sac":"Xanh da trời/ Blue"}
{"ten_san_pham":"Áo phông unisex trẻ em","mo_ta_chinh":"Áo phông dáng regular, vừa vặn, giúp bé thoải mái di chuyển. Thiết kế in hình nhân vật Stitch ngộ nghĩnh, mang lại nét vui tươi, trẻ trung. Mặt vải mềm mại, thấm hút mồ hôi, giúp bé luôn khô ráo và dễ chịu.","chat_lieu":"Cotton 100%","tinh_nang_vai":"Mềm mại, thoáng khí, thấm hút mồ hôi, giữ mát","gioi_tinh":"Unisex","phong_cach":"Casual, Kids","mua":"Mùa xuân, hè","dip_mac":"Đi học · Chơi công viên · Dạo phố · Kỷ niệm gia đình","tags":"áo phông trẻ em, áo thun unisex, in hình Stitch, cotton, quần short, quần soóc, quần leggings, áo khoác nỉ, phong cách trẻ em, thời trang trẻ em","do_tuoi":"0-12 tuổi","loi_song":"Những bậc phụ huynh muốn quần áo trẻ em thoải mái, đầy màu sắc, an toàn","tinh_cach":"Vui tươi, năng động, sáng tạo","ly_do_mua":"Chất liệu cotton 100% an toàn, thiết kế in hình vui nhộn, phù hợp cho mọi hoạt động của bé","cross_sell":"Quần soóc, Áo nỉ, Bộ mặc nhà","hook_quang_cao":"Bí quyết cho bé luôn tươi vui – Áo phông Stitch!","tagline":"Vẻ ngộ nghĩnh, phong cách trẻ thơ","mau_sac":"Đen/ Black"}
{"ten_san_pham":"Áo thun nam trắng","mo_ta_chinh":"Áo thun nam màu trắng, thiết kế cơ bản","chat_lieu":"Không xác định","tinh_nang_vai":"Không xác định","gioi_tinh":"Nam","phong_cach":"Casual","mua":"Không xác định","dip_mac":"Hàng ngày, đi chơi, thể thao","tags":"Áo thun nam, áo thun trắng, áo thun cơ bản","do_tuoi":"Không xác định","loi_song":"Thường ngày, năng động","tinh_cach":"Đơn giản, thoải mái","ly_do_mua":"Thiết kế cơ bản, dễ phối đồ","cross_sell":"Áo thun nam màu khác, quần short nam","hook_quang_cao":"Áo thun nam trắng - sự lựa chọn hoàn hảo cho mọi dịp","tagline":"Phong cách đơn giản, thoải mái","mau_sac":"Trắng/ White"}
{"mau_sac":"Đỏ/ Red"}
{"mau_sac":"Đỏ/ Red"}
{"ten_san_pham":"Khăn badana Vietnam Youngster","mo_ta_chinh":"Khăn badana Vietnam Youngster mang phong cách urban với họa tiết checkerboard lineart chữ Youngster, tạo điểm nhấn năng động cho mọi trang phục. Chất liệu thoáng khí, mềm mại giúp giữ mát và thoải mái khi di chuyển. Mặc khăn này hack dáng, tôn dáng cổ và làm nổi bật cá tính của bạn.","chat_lieu":"Không xác định","tinh_nang_vai":"Không xác định","gioi_tinh":"Unisex","phong_cach":"Streetwear, Urban","mua":"Xuân, Hè","dip_mac":"Đi làm · Đi học · Tham gia sự kiện · Hẹn hò","tags":"khăn badana, khăn, streetwear, hiphop, đô thị, phong cách, Việt Nam, Youngster","do_tuoi":"18-35","loi_song":"Người trẻ trung, năng động, yêu thích phong cách streetwear và hiphop","tinh_cach":"Tự tin, cá tính, sáng tạo","ly_do_mua":"Khăn badana độc đáo, tôn dáng, phong cách urban, dễ mix match","cross_sell":"Quần jean slim, Áo khoác gió, Áo khoác gilet","hook_quang_cao":"Thổi hồn cho phong cách street của bạn với khăn badana độc đáo – phong cách, cá tính, năng động.","tagline":"Cảm hứng đô thị, phong cách bất tận","mau_sac":"Đỏ/ Red"}
{"ten_san_pham":"Khăn đa năng chống nắng unisex người lớn","mo_ta_chinh":"Form khăn dáng rộng ôm trọn cổ, thiết kế gấp nếp thông minh tạo chiều sâu thời trang. Chất liệu vải mềm mịn kết hợp công nghệ chống tia UV, giúp bảo vệ da tối ưu. Phối cùng mọi phong cách từ dạo phố năng động đến du lịch phiêu lưu.","chat_lieu":"Không xác định","tinh_nang_vai":"Không xác định","gioi_tinh":"Unisex","phong_cach":"Thời trang đường phố, đa năng, du lịch","mua":"Xuân Hè Thu","dip_mac":"Đi dã ngoại · Đi làm hiện đại · Dạo phố thời trang · Du lịch bụi","tags":"khăn chống nắng, đa năng, unisex, thời trang đường phố, dã ngoại","do_tuoi":"18-45","loi_song":"Người trẻ năng động, coi trọng sự tiện lợi và phong cách linh hoạt trong mọi hoạt động","tinh_cach":"Sáng tạo, thích phiêu lưu, hướng đến lối sống ngoài trời","ly_do_mua":"Chống nắng hiệu quả với thiết kế đa công năng · Tối giản nhưng vẫn nổi bật · Phù hợp mọi hoàn cảnh sử dụng","cross_sell":"Áo phông basic, Quần Jean slim, Găng tay chống nắng","tagline":"Linh hoạt, phong cách, bảo vệ tối ưu","mau_sac":"Hồng/ Pink- Magenta"}
{"ten_san_pham":"Găng tay chống nắng","mo_ta_chinh":"Găng tay chống nắng UPF 50+","chat_lieu":"Không xác định","tinh_nang_vai":"Khả năng chống nắng UPF 50+, Stretch - đàn hồi tốt","gioi_tinh":"Nam, nữ","phong_cach":"Thể thao, thời trang","mua":"Mọi mùa","dip_mac":"Đi lại, thể thao, dã ngoại","tags":"Găng tay chống nắng, UPF 50+, thời trang thể thao","do_tuoi":"Không xác định","loi_song":"Lối sống năng động, yêu thích thể thao","tinh_cach":"Cẩn thận, quan tâm đến sức khỏe","ly_do_mua":"Bảo vệ da, thời trang","cross_sell":"Kem chống nắng, kính râm","hook_quang_cao":"Chống nắng, bảo vệ da","tagline":"Bảo vệ da khỏi tia UV","mau_sac":"Xanh da trời/ Blue"}
{"mau_sac":"Đen/ Black"}
{"ten_san_pham":"Áo phông unisex người lớn cotton USA có hình in","mo_ta_chinh":"Form oversize rộng rãi, che khuyết điểm vòng hai hiệu quả. Thiết kế in hình nổi bật tạo điểm nhấn cá tính, vải cotton mềm mại ôm nhẹ cơ thể. Kiểu dáng unisex phù hợp mọi vóc dáng, mang lại cảm giác thoải mái suốt ngày dài.","chat_lieu":"100% cotton USA","tinh_nang_vai":"Mềm mại, thấm hút mồ hôi, thoáng mát và giữ form lâu theo thời gian","gioi_tinh":"Unisex","phong_cach":"Casual, Unisex","mua":"Toàn mùa","dip_mac":"Hàng ngày · Đi chơi · Tập thể thao · Đi làm","tags":"áo thun unisex, cotton usa, áo phông in hình, thời trang cá tính, mặc đi làm","do_tuoi":"Trên 18 tuổi","loi_song":"Người trẻ năng động, yêu thích sự thoải mái nhưng vẫn muốn giữ phong cách riêng","tinh_cach":"Đơn giản, cá tính, linh hoạt","ly_do_mua":"Chất liệu cotton USA cao cấp | Thiết kế in hình độc đáo không kén giới tính | Phù hợp mọi hoạt động từ đi làm đến dạo phố","cross_sell":"Quần Jean 5 túi, Giày Sneaker Đen, Áo Khoác Bomber","hook_quang_cao":"Một chiếc áo phông mà bạn có thể mặc từ phòng gym đến văn phòng - linh hoạt không ngờ!","tagline":"Tự do nhưng vẫn thanh lịch","mau_sac":"Xanh da trời/ Blue"}
{"ten_san_pham":"Áo thun Doraemon","mo_ta_chinh":"Áo thun ngắn tay màu kem","chat_lieu":"Không xác định","tinh_nang_vai":"Không xác định","gioi_tinh":"Trẻ em","phong_cach":"Casual","mua":"Không xác định","dip_mac":"Hàng ngày","tags":"Áo thun, Doraemon","do_tuoi":"Không xác định","loi_song":"Không xác định","tinh_cach":"Không xác định","ly_do_mua":"Không xác định","cross_sell":"Không xác định","hook_quang_cao":"Sản phẩm mới từ Doraemon","tagline":"Thời trang trẻ em","mau_sac":"Xám/ Gray"}vfvfvvfvfvfv
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment