BOD Calculation APIs
8 endpoints
Base: /api
Method: POST
Stateless · Pure Computation
Tổng quan
Tất cả các API trong nhóm này là stateless pure computation — không truy vấn DB, không lưu trữ. Truyền số raw vào, công thức chạy ngay, trả kết quả. Công thức được quản lý tập trung ở backend: thay đổi trọng số hoặc logic chỉ sửa một chỗ, toàn bộ dashboard cập nhật theo.
Kiểu API
POST only
DB query
Không có
Content-Type
application/json
Base URL
/api/calc
Excel / Data source
số liệu raw
Client
chuẩn bị request body
POST /api/calc/...
áp dụng công thức
Response JSON
kết quả đã tính
Dashboard
render trực tiếp
POST
01
/api/calc/nsr
NSR — Net Sentiment Ratio. Tính tỷ lệ cảm xúc thuần từ số tin Positive, Negative, Total. Dùng ở mọi component có hiển thị NSR%.
Công thức
Formula
NSR = (Positive − Negative) / Total × 100
Request Body
{ "positive": 340, "negative": 83, "total": 1023 }
Response
{ "nsr": 25.2 }
nsr: số thực, làm tròn 1 chữ số thập phân. Âm khi tin tiêu cực nhiều hơn tích cực.
POST
02
/api/calc/winning-score
Tính Winning Score cho một từ khóa. Kết hợp độ phủ (tổng tin) và chất lượng (NSR) theo tỷ lệ 50/50. Trả kèm xếp loại và khuyến nghị.
Công thức
Formula
WS = (total / totalAll) × 50 + nsr × 0.5 WS = clamp(WS, 0, 100) // ×50: scale tỷ lệ phủ (0–1) thành 0–50 điểm // ×0.5: NSR dao động −100→+100, nhân 0.5 → đóng góp tối đa ±50 // Thiết kế 50/50: độ phủ và sentiment đóng góp bằng nhau Classification : WS ≥ 60 → "Positive" | WS ≥ 40 → "Neutral" | WS < 40 → "Negative" Recommendation : WS ≥ 60 → "Nên đẩy mạnh" WS ≥ 40 → "Cân nhắc kỹ" WS < 40 → "Hạn chế đẩy"
Request Body
Client tự tính nsr trước (qua /calc/nsr) rồi truyền vào, hoặc truyền thẳng positive + negative + total để API tính NSR nội bộ.
Phương án A — truyền nsr sẵn
{ "total": 3400, "totalAll": 10937, "nsr": 90.0 }
Phương án B — API tự tính NSR
{ "positive": 3120, "negative": 60, "total": 3400, "totalAll": 10937 }
Response
{ "winningScore": 61, "classification": "Positive", "recommendation": "Nên đẩy mạnh", "nsr": 90.0 }
POST
03
/api/calc/winning-score/batch
Tính Winning Score cho nhiều từ khóa cùng lúc. API tự tính NSR từng keyword nội bộ, không cần tính trước.
Công thức
Formula — áp dụng cho từng keyword
nsr_i = (positive_i − negative_i) / total_i × 100 WS_i = clamp((total_i / totalAll) × 50 + nsr_i × 0.5, 0, 100)
Request Body
{ "totalAll": 10937, "keywords": [ { "keyword": "Ban lãnh đạo Masan", "total": 3400, "positive": 3120, "negative": 60 }, { "keyword": "Omachi", "total": 1842, "positive": 1320, "negative": 95 }, { "keyword": "WinMart / WinCommerce", "total": 2210, "positive": 980, "negative": 540 } ] }
Response
{ "keywords": [ { "keyword": "Ban lãnh đạo Masan", "nsr": 90.0, "winningScore": 61, "classification": "Positive" }, { "keyword": "Omachi", "nsr": 66.5, "winningScore": 42, "classification": "Neutral" }, { "keyword": "WinMart / WinCommerce", "nsr": 19.9, "winningScore": 21, "classification": "Negative" } ] }
POST
04
/api/calc/kh-score
KH Score — Điểm hiệu quả kênh. Tổng hợp 3 chiều: Độ phủ, Tương tác, Liên quan chủ đề với trọng số khác nhau.
Công thức
Formula
KH = Reach × 0.40 + Engagement × 0.35 + Relevance × 0.25 // Reach : số tin trên kênh / tổng tin toàn kênh × 100 // Engagement : avg (likes + shares + comments) vs benchmark × 100 // Relevance : % tin gắn đúng nhãn topic / tổng tin kênh × 100 // Tất cả input đều trong thang 0–100
Request Body
{ "reach": 84, "engagement": 70, "relevance": 96 }
Response
{ "kh": 82 }
kh: số nguyên, thang 0–100.
POST
05
/api/calc/effective-score
Điểm hiệu quả tổng hợp — kết hợp Winning Score (nội dung) và KH Score (kênh) theo tỷ lệ 50/50.
Công thức
Formula
effScore = clamp(round(winScore × 0.5 + kh × 0.5), 0, 100)
Request Body
{ "winScore": 80, "kh": 82 }
Response
{ "effScore": 81 }
POST
06
/api/calc/effective-score/batch
Tính KH Score và effScore cho toàn bộ topic matrix trong một lần gọi. API tính KH nội bộ từ reach/engagement/relevance.
Công thức
Formula — áp dụng cho từng topic
kh_i = reach_i × 0.40 + engagement_i × 0.35 + relevance_i × 0.25 effScore_i = clamp(round(winScore_i × 0.5 + kh_i × 0.5), 0, 100)
Request Body
{ "topics": [ { "group": "Cổ phiếu, chứng khoán", "winScore": 80, "reach": 84, "engagement": 70, "relevance": 96 }, { "group": "Thương hiệu & Quảng cáo", "winScore": 87, "reach": 92, "engagement": 95, "relevance": 88 } ] }
Response
{ "topics": [ { "group": "Cổ phiếu, chứng khoán", "kh": 82, "effScore": 81 }, { "group": "Thương hiệu & Quảng cáo", "kh": 92, "effScore": 90 } ] }
POST
07
/api/calc/ocean/source/batch
Chấm điểm OCEAN 5 chiều cho toàn bộ nguồn / KOL. API tự normalize max trong batch — gửi đầy đủ danh sách một lần để điểm chính xác.
Công thức từng chiều (thang 0–100)
Formula
Reach = (articleCount / max(articleCount trong batch)) × 100 Affinity = ((positive − negative) / total × 100 + 100) / 2 // scale NSR từ [−100, +100] → [0, 100] Engagement = (avgInteractions / max(avgInteractions trong batch)) × 100 Relevance = (distinctLabels / 15) × 100 // 15 = tổng nhãn topic cố định của hệ thống Network = tra bảng cố định theo channelType (xem bên dưới) TotalScore = round((Reach + Affinity + Engagement + Relevance + Network) / 5)
Network Score — Bảng tra theo kênh
TikTok95
Facebook75
YouTube65
News55
Social50
Forum40
LinkedIn35
Threads30
Request Body
{ "sources": [ { "name": "Tiếng Dân News", "articleCount": 2572, "positive": 820, "negative": 310, "total": 2572, "avgInteractions": 18.8, "distinctLabels": 12, "channelType": "Facebook" }, { "name": "KOL Tài chính A", "articleCount": 410, "positive": 280, "negative": 40, "total": 410, "avgInteractions": 69.6, "distinctLabels": 8, "channelType": "Tiktok" } ] }
Response
{ "sources": [ { "name": "Tiếng Dân News", "reach": 100, "affinity": 69, "engagement": 27, "relevance": 80, "network": 75, "totalScore": 70 }, { "name": "KOL Tài chính A", "reach": 16, "affinity": 88, "engagement": 100, "relevance": 53, "network": 95, "totalScore": 70 } ] }
max normalization: Reach và Engagement normalize theo max trong chính batch này. Gửi toàn bộ nguồn trong một request để đảm bảo tỷ lệ chính xác.
POST
08
/api/calc/ocean/topic-influence
Tính OCEAN Influence Score cho một topic — trung bình có trọng số của các nguồn, weight = số bài của nguồn về topic đó.
Công thức
Formula
influenceScore = Σ(oceanTotalScore_i × articleCount_i) ÷ Σ(articleCount_i) // Nguồn có nhiều bài về topic → trọng số cao hơn // oceanTotalScore_i lấy từ output của /calc/ocean/source/batch
Request Body
{ "topic": "Ban lãnh đạo", "sources": [ { "name": "Tiếng Dân News", "oceanTotalScore": 70, "articleCountForTopic": 820 }, { "name": "Báo Đầu Tư", "oceanTotalScore": 76, "articleCountForTopic": 340 }, { "name": "KOL Tài chính A", "oceanTotalScore": 70, "articleCountForTopic": 210 } ] }
Response
{ "topic": "Ban lãnh đạo", "influenceScore": 72 }
Tính tay: (70×820 + 76×340 + 70×210) / (820+340+210)
= (57400 + 25840 + 14700) / 1370
= 97940 / 1370 ≈ 71.5 → 72