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
số liệu raw
→
Client
chuẩn bị request body
chuẩn bị request body
→
POST /api/calc/...
áp dụng công thức
áp dụng công thức
→
Response JSON
kết quả đã tính
kết quả đã tính
→
Dashboard
render trực tiếp
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
= (57400 + 25840 + 14700) / 1370
= 97940 / 1370 ≈ 71.5 → 72