Spaces:
Sleeping
Sleeping
Upload folder using huggingface_hub
Browse files- README.md +24 -14
- __pycache__/app.cpython-314.pyc +0 -0
- app.py +383 -0
- data/dataset_stats.json +64 -0
- data/gold/features/trust_scores.csv +121 -0
- data/input/manual_trust_labels.csv +4 -0
- data/serving/kol_events.jsonl +0 -0
- data/silver/unified/vietnam_influencer_features.csv +0 -0
- ml/models/sentiment/comment_sentiment.joblib +3 -0
- ml/models/trust_score/kol_trust_model.joblib +3 -0
- requirements.txt +5 -3
README.md
CHANGED
|
@@ -1,19 +1,29 @@
|
|
| 1 |
---
|
| 2 |
-
title:
|
| 3 |
-
emoji:
|
| 4 |
-
colorFrom:
|
| 5 |
-
colorTo:
|
| 6 |
-
sdk:
|
| 7 |
-
|
| 8 |
-
|
| 9 |
-
|
| 10 |
-
pinned: false
|
| 11 |
-
short_description: Streamlit template space
|
| 12 |
---
|
| 13 |
|
| 14 |
-
#
|
| 15 |
|
| 16 |
-
|
| 17 |
|
| 18 |
-
|
| 19 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
---
|
| 2 |
+
title: KOLTrust Demo
|
| 3 |
+
emoji: 📊
|
| 4 |
+
colorFrom: blue
|
| 5 |
+
colorTo: green
|
| 6 |
+
sdk: streamlit
|
| 7 |
+
sdk_version: 1.36.0
|
| 8 |
+
app_file: app.py
|
| 9 |
+
python_version: 3.11
|
|
|
|
|
|
|
| 10 |
---
|
| 11 |
|
| 12 |
+
# KOLTrust Demo
|
| 13 |
|
| 14 |
+
Self-contained Hugging Face Space demo for KOL trust evaluation.
|
| 15 |
|
| 16 |
+
The demo uses local exported dataset files and optional trained `.joblib` models. It does not require Kafka, Spark, Cassandra, Airflow, or FastAPI.
|
| 17 |
+
|
| 18 |
+
## Included demo data
|
| 19 |
+
|
| 20 |
+
- `data/silver/unified/vietnam_influencer_features.csv`
|
| 21 |
+
- `data/gold/features/trust_scores.csv`
|
| 22 |
+
- `data/serving/kol_events.jsonl`
|
| 23 |
+
- `data/input/manual_trust_labels.csv`
|
| 24 |
+
- `ml/models/trust_score/kol_trust_model.joblib`
|
| 25 |
+
- `ml/models/sentiment/comment_sentiment.joblib`
|
| 26 |
+
|
| 27 |
+
## Notes
|
| 28 |
+
|
| 29 |
+
Baseline `trust_score` values are rule-generated unless a matching manual label exists in `manual_trust_labels.csv`.
|
__pycache__/app.cpython-314.pyc
ADDED
|
Binary file (22.9 kB). View file
|
|
|
app.py
ADDED
|
@@ -0,0 +1,383 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from __future__ import annotations
|
| 2 |
+
|
| 3 |
+
import json
|
| 4 |
+
from pathlib import Path
|
| 5 |
+
from typing import Any
|
| 6 |
+
|
| 7 |
+
import joblib
|
| 8 |
+
import pandas as pd
|
| 9 |
+
import plotly.express as px
|
| 10 |
+
import streamlit as st
|
| 11 |
+
|
| 12 |
+
|
| 13 |
+
APP_DIR = Path(__file__).resolve().parent
|
| 14 |
+
DATA_DIR = APP_DIR / "data"
|
| 15 |
+
FEATURES_PATH = DATA_DIR / "silver" / "unified" / "vietnam_influencer_features.csv"
|
| 16 |
+
TRUST_SCORES_PATH = DATA_DIR / "gold" / "features" / "trust_scores.csv"
|
| 17 |
+
EVENTS_PATH = DATA_DIR / "serving" / "kol_events.jsonl"
|
| 18 |
+
MANUAL_LABELS_PATH = DATA_DIR / "input" / "manual_trust_labels.csv"
|
| 19 |
+
DATASET_STATS_PATH = DATA_DIR / "dataset_stats.json"
|
| 20 |
+
MODEL_PATH = APP_DIR / "ml" / "models" / "trust_score" / "kol_trust_model.joblib"
|
| 21 |
+
|
| 22 |
+
NUMERIC_FEATURES = [
|
| 23 |
+
"follower_count",
|
| 24 |
+
"content_count",
|
| 25 |
+
"view_count",
|
| 26 |
+
"like_count",
|
| 27 |
+
"comment_count",
|
| 28 |
+
"share_count",
|
| 29 |
+
"engagement_rate",
|
| 30 |
+
"likes_per_view",
|
| 31 |
+
"comments_per_view",
|
| 32 |
+
"shares_per_view",
|
| 33 |
+
"sentiment_score",
|
| 34 |
+
"positive_comment_count",
|
| 35 |
+
"neutral_comment_count",
|
| 36 |
+
"negative_comment_count",
|
| 37 |
+
"upload_frequency",
|
| 38 |
+
"follower_growth_rate",
|
| 39 |
+
"activity_score",
|
| 40 |
+
"is_suspicious",
|
| 41 |
+
]
|
| 42 |
+
CATEGORICAL_FEATURES = ["platform"]
|
| 43 |
+
|
| 44 |
+
|
| 45 |
+
st.set_page_config(page_title="KOLTrust Demo", page_icon=":bar_chart:", layout="wide")
|
| 46 |
+
|
| 47 |
+
|
| 48 |
+
def trust_label(score: float) -> str:
|
| 49 |
+
if score >= 70:
|
| 50 |
+
return "high_trust"
|
| 51 |
+
if score >= 45:
|
| 52 |
+
return "medium_trust"
|
| 53 |
+
return "low_trust"
|
| 54 |
+
|
| 55 |
+
|
| 56 |
+
def risk_profile(label: str) -> str:
|
| 57 |
+
if label == "high_trust":
|
| 58 |
+
return "trusted"
|
| 59 |
+
if label == "medium_trust":
|
| 60 |
+
return "watch"
|
| 61 |
+
return "risky"
|
| 62 |
+
|
| 63 |
+
|
| 64 |
+
def to_float(value: Any, default: float = 0.0) -> float:
|
| 65 |
+
try:
|
| 66 |
+
if value is None or value == "":
|
| 67 |
+
return default
|
| 68 |
+
return float(value)
|
| 69 |
+
except (TypeError, ValueError):
|
| 70 |
+
return default
|
| 71 |
+
|
| 72 |
+
|
| 73 |
+
@st.cache_data(show_spinner=False)
|
| 74 |
+
def read_csv(path: Path) -> pd.DataFrame:
|
| 75 |
+
if not path.exists():
|
| 76 |
+
return pd.DataFrame()
|
| 77 |
+
return pd.read_csv(path, encoding="utf-8-sig")
|
| 78 |
+
|
| 79 |
+
|
| 80 |
+
@st.cache_data(show_spinner=False)
|
| 81 |
+
def read_json(path: Path) -> dict[str, Any]:
|
| 82 |
+
if not path.exists():
|
| 83 |
+
return {}
|
| 84 |
+
return json.loads(path.read_text(encoding="utf-8"))
|
| 85 |
+
|
| 86 |
+
|
| 87 |
+
@st.cache_data(show_spinner=False)
|
| 88 |
+
def read_jsonl(path: Path) -> pd.DataFrame:
|
| 89 |
+
if not path.exists():
|
| 90 |
+
return pd.DataFrame()
|
| 91 |
+
rows = []
|
| 92 |
+
for line in path.read_text(encoding="utf-8").splitlines():
|
| 93 |
+
if line.strip():
|
| 94 |
+
rows.append(json.loads(line))
|
| 95 |
+
return pd.DataFrame(rows)
|
| 96 |
+
|
| 97 |
+
|
| 98 |
+
@st.cache_resource(show_spinner=False)
|
| 99 |
+
def load_trust_model() -> dict[str, Any] | None:
|
| 100 |
+
if not MODEL_PATH.exists():
|
| 101 |
+
return None
|
| 102 |
+
try:
|
| 103 |
+
payload = joblib.load(MODEL_PATH)
|
| 104 |
+
return payload if isinstance(payload, dict) else {"model": payload}
|
| 105 |
+
except Exception:
|
| 106 |
+
return None
|
| 107 |
+
|
| 108 |
+
|
| 109 |
+
def normalize_features(df: pd.DataFrame) -> pd.DataFrame:
|
| 110 |
+
if df.empty:
|
| 111 |
+
return df
|
| 112 |
+
data = df.copy()
|
| 113 |
+
for column in NUMERIC_FEATURES:
|
| 114 |
+
if column not in data.columns:
|
| 115 |
+
data[column] = 0.0
|
| 116 |
+
data[column] = pd.to_numeric(data[column], errors="coerce").fillna(0.0)
|
| 117 |
+
for column in CATEGORICAL_FEATURES:
|
| 118 |
+
if column not in data.columns:
|
| 119 |
+
data[column] = "unknown"
|
| 120 |
+
data[column] = data[column].fillna("unknown").astype(str)
|
| 121 |
+
for column in ("trust_score", "human_trust_score"):
|
| 122 |
+
if column in data.columns:
|
| 123 |
+
data[column] = pd.to_numeric(data[column], errors="coerce")
|
| 124 |
+
return data
|
| 125 |
+
|
| 126 |
+
|
| 127 |
+
def attach_manual_labels(features: pd.DataFrame, manual: pd.DataFrame) -> pd.DataFrame:
|
| 128 |
+
if features.empty or manual.empty:
|
| 129 |
+
return features
|
| 130 |
+
required = {"platform", "creator_id", "content_id"}
|
| 131 |
+
if not required.issubset(features.columns) or not required.issubset(manual.columns):
|
| 132 |
+
return features
|
| 133 |
+
label_columns = [
|
| 134 |
+
"platform",
|
| 135 |
+
"creator_id",
|
| 136 |
+
"content_id",
|
| 137 |
+
"human_trust_score",
|
| 138 |
+
"human_trust_label",
|
| 139 |
+
"human_is_suspicious",
|
| 140 |
+
"label_reason",
|
| 141 |
+
"annotator",
|
| 142 |
+
"labeled_at",
|
| 143 |
+
]
|
| 144 |
+
labels = manual[[column for column in label_columns if column in manual.columns]].copy()
|
| 145 |
+
for column in required:
|
| 146 |
+
labels[column] = labels[column].astype(str)
|
| 147 |
+
features[column] = features[column].astype(str)
|
| 148 |
+
return features.merge(labels, on=["platform", "creator_id", "content_id"], how="left")
|
| 149 |
+
|
| 150 |
+
|
| 151 |
+
def predict_scores(features: pd.DataFrame) -> pd.DataFrame:
|
| 152 |
+
data = normalize_features(features)
|
| 153 |
+
if data.empty:
|
| 154 |
+
return data
|
| 155 |
+
payload = load_trust_model()
|
| 156 |
+
model = payload.get("model") if payload else None
|
| 157 |
+
if model is None:
|
| 158 |
+
data["model_trust_score"] = data.get("trust_score", pd.Series(dtype=float))
|
| 159 |
+
data["score_source"] = "baseline_rule"
|
| 160 |
+
return data
|
| 161 |
+
|
| 162 |
+
numeric_features = payload.get("numeric_features") or NUMERIC_FEATURES
|
| 163 |
+
categorical_features = payload.get("categorical_features") or CATEGORICAL_FEATURES
|
| 164 |
+
model_input = data[numeric_features + categorical_features].copy()
|
| 165 |
+
try:
|
| 166 |
+
data["model_trust_score"] = model.predict(model_input).clip(0, 100)
|
| 167 |
+
data["score_source"] = "trained_model"
|
| 168 |
+
except Exception:
|
| 169 |
+
data["model_trust_score"] = data.get("trust_score", pd.Series(dtype=float))
|
| 170 |
+
data["score_source"] = "baseline_rule"
|
| 171 |
+
return data
|
| 172 |
+
|
| 173 |
+
|
| 174 |
+
def final_score(row: pd.Series) -> tuple[float, str, str]:
|
| 175 |
+
if pd.notna(row.get("human_trust_score")):
|
| 176 |
+
score = to_float(row.get("human_trust_score"))
|
| 177 |
+
label = str(row.get("human_trust_label") or trust_label(score))
|
| 178 |
+
return score, label, "human_label"
|
| 179 |
+
if pd.notna(row.get("model_trust_score")):
|
| 180 |
+
score = to_float(row.get("model_trust_score"))
|
| 181 |
+
return score, trust_label(score), str(row.get("score_source") or "trained_model")
|
| 182 |
+
score = to_float(row.get("trust_score"))
|
| 183 |
+
return score, trust_label(score), "baseline_rule"
|
| 184 |
+
|
| 185 |
+
|
| 186 |
+
def build_content_table(features: pd.DataFrame) -> pd.DataFrame:
|
| 187 |
+
rows = []
|
| 188 |
+
for _, row in features.iterrows():
|
| 189 |
+
score, label, source = final_score(row)
|
| 190 |
+
rows.append(
|
| 191 |
+
{
|
| 192 |
+
"platform": row.get("platform"),
|
| 193 |
+
"creator_id": row.get("creator_id"),
|
| 194 |
+
"creator_name": row.get("creator_name"),
|
| 195 |
+
"content_id": row.get("content_id"),
|
| 196 |
+
"content_title": row.get("content_title"),
|
| 197 |
+
"publish_time": row.get("publish_time"),
|
| 198 |
+
"view_count": int(to_float(row.get("view_count"))),
|
| 199 |
+
"like_count": int(to_float(row.get("like_count"))),
|
| 200 |
+
"comment_count": int(to_float(row.get("comment_count"))),
|
| 201 |
+
"share_count": int(to_float(row.get("share_count"))),
|
| 202 |
+
"engagement_rate": to_float(row.get("engagement_rate")),
|
| 203 |
+
"sentiment_score": to_float(row.get("sentiment_score")),
|
| 204 |
+
"activity_score": to_float(row.get("activity_score")),
|
| 205 |
+
"is_suspicious": bool(to_float(row.get("human_is_suspicious"), to_float(row.get("is_suspicious")))),
|
| 206 |
+
"trust_score": round(score, 2),
|
| 207 |
+
"trust_label": label,
|
| 208 |
+
"risk_profile": risk_profile(label),
|
| 209 |
+
"score_source": source,
|
| 210 |
+
"label_reason": row.get("label_reason"),
|
| 211 |
+
"annotator": row.get("annotator"),
|
| 212 |
+
"labeled_at": row.get("labeled_at"),
|
| 213 |
+
}
|
| 214 |
+
)
|
| 215 |
+
return pd.DataFrame(rows)
|
| 216 |
+
|
| 217 |
+
|
| 218 |
+
features = read_csv(FEATURES_PATH)
|
| 219 |
+
manual_labels = read_csv(MANUAL_LABELS_PATH)
|
| 220 |
+
trust_scores = read_csv(TRUST_SCORES_PATH)
|
| 221 |
+
events = read_jsonl(EVENTS_PATH)
|
| 222 |
+
stats = read_json(DATASET_STATS_PATH)
|
| 223 |
+
|
| 224 |
+
features = attach_manual_labels(features, manual_labels)
|
| 225 |
+
features = predict_scores(features)
|
| 226 |
+
content = build_content_table(features)
|
| 227 |
+
|
| 228 |
+
st.title("KOLTrust Demo")
|
| 229 |
+
st.caption("Offline demo for KOL trust evaluation from exported public social metrics.")
|
| 230 |
+
|
| 231 |
+
if content.empty:
|
| 232 |
+
st.error("Demo data was not found. Check the data folder in this Space.")
|
| 233 |
+
st.stop()
|
| 234 |
+
|
| 235 |
+
with st.sidebar:
|
| 236 |
+
st.header("Controls")
|
| 237 |
+
platforms = sorted(content["platform"].dropna().unique().tolist())
|
| 238 |
+
selected_platforms = st.multiselect("Platform", platforms, default=platforms)
|
| 239 |
+
label_options = ["high_trust", "medium_trust", "low_trust"]
|
| 240 |
+
selected_labels = st.multiselect("Trust label", label_options, default=label_options)
|
| 241 |
+
source_options = sorted(content["score_source"].dropna().unique().tolist())
|
| 242 |
+
selected_sources = st.multiselect("Score source", source_options, default=source_options)
|
| 243 |
+
min_views = st.number_input("Min views", min_value=0, value=0, step=1000)
|
| 244 |
+
|
| 245 |
+
filtered = content[
|
| 246 |
+
content["platform"].isin(selected_platforms)
|
| 247 |
+
& content["trust_label"].isin(selected_labels)
|
| 248 |
+
& content["score_source"].isin(selected_sources)
|
| 249 |
+
& (content["view_count"] >= min_views)
|
| 250 |
+
].copy()
|
| 251 |
+
|
| 252 |
+
metric_cols = st.columns(5)
|
| 253 |
+
metric_cols[0].metric("Content rows", f"{len(filtered):,}")
|
| 254 |
+
metric_cols[1].metric("Creators", f"{filtered['creator_id'].nunique():,}")
|
| 255 |
+
metric_cols[2].metric("Manual labels", f"{int((content['score_source'] == 'human_label').sum()):,}")
|
| 256 |
+
metric_cols[3].metric("Avg trust", f"{filtered['trust_score'].mean():.1f}" if not filtered.empty else "0")
|
| 257 |
+
metric_cols[4].metric("Suspicious", f"{int(filtered['is_suspicious'].sum()):,}")
|
| 258 |
+
|
| 259 |
+
tab_overview, tab_evaluate, tab_data = st.tabs(["Overview", "Evaluate KOL", "Data"])
|
| 260 |
+
|
| 261 |
+
with tab_overview:
|
| 262 |
+
chart_cols = st.columns([1.1, 0.9])
|
| 263 |
+
with chart_cols[0]:
|
| 264 |
+
top_creators = (
|
| 265 |
+
filtered.groupby(["creator_id", "creator_name", "platform"], dropna=False)
|
| 266 |
+
.agg(trust_score=("trust_score", "mean"), views=("view_count", "sum"), content=("content_id", "count"))
|
| 267 |
+
.reset_index()
|
| 268 |
+
.sort_values("trust_score", ascending=False)
|
| 269 |
+
.head(20)
|
| 270 |
+
)
|
| 271 |
+
fig = px.bar(
|
| 272 |
+
top_creators.sort_values("trust_score"),
|
| 273 |
+
x="trust_score",
|
| 274 |
+
y="creator_name",
|
| 275 |
+
color="platform",
|
| 276 |
+
orientation="h",
|
| 277 |
+
range_x=[0, 100],
|
| 278 |
+
labels={"trust_score": "Avg trust score", "creator_name": ""},
|
| 279 |
+
)
|
| 280 |
+
fig.update_layout(height=500, margin=dict(l=10, r=10, t=20, b=10))
|
| 281 |
+
st.plotly_chart(fig, use_container_width=True)
|
| 282 |
+
with chart_cols[1]:
|
| 283 |
+
label_counts = filtered["trust_label"].value_counts().rename_axis("trust_label").reset_index(name="rows")
|
| 284 |
+
fig = px.pie(label_counts, names="trust_label", values="rows", hole=0.45)
|
| 285 |
+
fig.update_layout(height=500, margin=dict(l=10, r=10, t=20, b=10))
|
| 286 |
+
st.plotly_chart(fig, use_container_width=True)
|
| 287 |
+
|
| 288 |
+
st.subheader("Top creator leaderboard")
|
| 289 |
+
st.dataframe(top_creators, use_container_width=True, hide_index=True)
|
| 290 |
+
|
| 291 |
+
with tab_evaluate:
|
| 292 |
+
creators = (
|
| 293 |
+
filtered.groupby(["creator_id", "creator_name", "platform"], dropna=False)
|
| 294 |
+
.agg(trust_score=("trust_score", "mean"), views=("view_count", "sum"), content=("content_id", "count"))
|
| 295 |
+
.reset_index()
|
| 296 |
+
.sort_values(["trust_score", "views"], ascending=[False, False])
|
| 297 |
+
)
|
| 298 |
+
if creators.empty:
|
| 299 |
+
st.info("No creators match the selected filters.")
|
| 300 |
+
else:
|
| 301 |
+
labels = {
|
| 302 |
+
f"{row.creator_name} ({row.platform}, {row.creator_id})": row.creator_id
|
| 303 |
+
for row in creators.itertuples(index=False)
|
| 304 |
+
}
|
| 305 |
+
selected_label = st.selectbox("Select KOL", list(labels.keys()))
|
| 306 |
+
creator_id = labels[selected_label]
|
| 307 |
+
creator_rows = filtered[filtered["creator_id"].astype(str) == str(creator_id)].sort_values("publish_time", ascending=False)
|
| 308 |
+
latest = creator_rows.iloc[0]
|
| 309 |
+
avg_score = creator_rows["trust_score"].mean()
|
| 310 |
+
kol_label = trust_label(avg_score)
|
| 311 |
+
|
| 312 |
+
cols = st.columns(5)
|
| 313 |
+
cols[0].metric("Creator", str(latest["creator_name"]))
|
| 314 |
+
cols[1].metric("Avg trust", f"{avg_score:.1f}")
|
| 315 |
+
cols[2].metric("Label", kol_label)
|
| 316 |
+
cols[3].metric("Contents", f"{len(creator_rows):,}")
|
| 317 |
+
cols[4].metric("Total views", f"{int(creator_rows['view_count'].sum()):,}")
|
| 318 |
+
|
| 319 |
+
signal_rows = pd.DataFrame(
|
| 320 |
+
[
|
| 321 |
+
{"signal": "Engagement rate", "value": f"{creator_rows['engagement_rate'].mean() * 100:.2f}%"},
|
| 322 |
+
{"signal": "Sentiment score", "value": f"{creator_rows['sentiment_score'].mean():.1f}/100"},
|
| 323 |
+
{"signal": "Activity score", "value": f"{creator_rows['activity_score'].mean():.1f}/100"},
|
| 324 |
+
{"signal": "Suspicious content", "value": int(creator_rows["is_suspicious"].sum())},
|
| 325 |
+
{"signal": "Score source", "value": ", ".join(sorted(creator_rows["score_source"].unique()))},
|
| 326 |
+
]
|
| 327 |
+
)
|
| 328 |
+
st.subheader("Assessment signals")
|
| 329 |
+
st.dataframe(signal_rows, use_container_width=True, hide_index=True)
|
| 330 |
+
|
| 331 |
+
fig = px.scatter(
|
| 332 |
+
creator_rows,
|
| 333 |
+
x="view_count",
|
| 334 |
+
y="trust_score",
|
| 335 |
+
size="like_count",
|
| 336 |
+
color="trust_label",
|
| 337 |
+
hover_data=["content_title", "score_source", "engagement_rate", "sentiment_score"],
|
| 338 |
+
range_y=[0, 100],
|
| 339 |
+
)
|
| 340 |
+
fig.update_layout(height=380, margin=dict(l=10, r=10, t=20, b=10))
|
| 341 |
+
st.plotly_chart(fig, use_container_width=True)
|
| 342 |
+
|
| 343 |
+
st.subheader("Content evidence")
|
| 344 |
+
evidence_columns = [
|
| 345 |
+
"content_title",
|
| 346 |
+
"publish_time",
|
| 347 |
+
"view_count",
|
| 348 |
+
"like_count",
|
| 349 |
+
"comment_count",
|
| 350 |
+
"engagement_rate",
|
| 351 |
+
"sentiment_score",
|
| 352 |
+
"trust_score",
|
| 353 |
+
"trust_label",
|
| 354 |
+
"score_source",
|
| 355 |
+
"label_reason",
|
| 356 |
+
]
|
| 357 |
+
st.dataframe(creator_rows[evidence_columns], use_container_width=True, hide_index=True)
|
| 358 |
+
|
| 359 |
+
with tab_data:
|
| 360 |
+
st.subheader("Filtered content")
|
| 361 |
+
show_columns = [
|
| 362 |
+
"platform",
|
| 363 |
+
"creator_name",
|
| 364 |
+
"content_title",
|
| 365 |
+
"view_count",
|
| 366 |
+
"engagement_rate",
|
| 367 |
+
"sentiment_score",
|
| 368 |
+
"activity_score",
|
| 369 |
+
"is_suspicious",
|
| 370 |
+
"trust_score",
|
| 371 |
+
"trust_label",
|
| 372 |
+
"score_source",
|
| 373 |
+
]
|
| 374 |
+
st.dataframe(filtered[show_columns].sort_values("trust_score", ascending=False), use_container_width=True, hide_index=True)
|
| 375 |
+
|
| 376 |
+
with st.expander("Dataset stats"):
|
| 377 |
+
st.json(stats)
|
| 378 |
+
with st.expander("Manual labels"):
|
| 379 |
+
st.dataframe(manual_labels, use_container_width=True, hide_index=True)
|
| 380 |
+
with st.expander("Raw serving events sample"):
|
| 381 |
+
st.dataframe(events.head(200), use_container_width=True, hide_index=True)
|
| 382 |
+
with st.expander("Creator trust scores"):
|
| 383 |
+
st.dataframe(trust_scores, use_container_width=True, hide_index=True)
|
data/dataset_stats.json
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"dataset_name": "Vietnam KOL Trustworthiness Dataset",
|
| 3 |
+
"built_at": "2026-06-15T10:29:04Z",
|
| 4 |
+
"source": {
|
| 5 |
+
"youtube": "YouTube Data API v3 public data",
|
| 6 |
+
"tiktok": "TikTokApi public data"
|
| 7 |
+
},
|
| 8 |
+
"raw": {
|
| 9 |
+
"youtube_channels": 207,
|
| 10 |
+
"youtube_videos": 570,
|
| 11 |
+
"youtube_comments": 2993,
|
| 12 |
+
"tiktok_creators": 29,
|
| 13 |
+
"tiktok_videos": 585
|
| 14 |
+
},
|
| 15 |
+
"youtube": {
|
| 16 |
+
"channels": 100,
|
| 17 |
+
"videos": 450
|
| 18 |
+
},
|
| 19 |
+
"tiktok": {
|
| 20 |
+
"creators": 15,
|
| 21 |
+
"videos": 305
|
| 22 |
+
},
|
| 23 |
+
"unified": {
|
| 24 |
+
"feature_rows": 755,
|
| 25 |
+
"platforms": [
|
| 26 |
+
"youtube",
|
| 27 |
+
"tiktok"
|
| 28 |
+
]
|
| 29 |
+
},
|
| 30 |
+
"splits": {
|
| 31 |
+
"strategy": "creator_id_hash_60_20_20",
|
| 32 |
+
"train_rows": 431,
|
| 33 |
+
"eval_rows": 231,
|
| 34 |
+
"analysis_profile_rows": 93,
|
| 35 |
+
"train_comment_rows": 1398,
|
| 36 |
+
"eval_comment_rows": 760,
|
| 37 |
+
"analysis_profile_comment_rows": 835,
|
| 38 |
+
"simulator_profile_creators": 16
|
| 39 |
+
},
|
| 40 |
+
"comments": {
|
| 41 |
+
"sentiment_rows": 2993,
|
| 42 |
+
"anonymized": true
|
| 43 |
+
},
|
| 44 |
+
"sample": {
|
| 45 |
+
"kafka_events": 755,
|
| 46 |
+
"fixture_rows": 0,
|
| 47 |
+
"zero_view_rows": 0
|
| 48 |
+
},
|
| 49 |
+
"features": {
|
| 50 |
+
"engagement_rows": 755,
|
| 51 |
+
"suspicious_rows": 755,
|
| 52 |
+
"trust_score_rows": 120
|
| 53 |
+
},
|
| 54 |
+
"quality": {
|
| 55 |
+
"removed_zero_view_youtube_videos": 3,
|
| 56 |
+
"removed_zero_view_tiktok_videos": 0,
|
| 57 |
+
"duplicate_youtube_channels_removed": 107,
|
| 58 |
+
"duplicate_youtube_videos_removed": 117,
|
| 59 |
+
"duplicate_tiktok_creators_removed": 14,
|
| 60 |
+
"duplicate_tiktok_videos_removed": 280,
|
| 61 |
+
"possible_mojibake_output_rows": 0
|
| 62 |
+
},
|
| 63 |
+
"label_notice": "Rule-generated labels are not ground truth."
|
| 64 |
+
}
|
data/gold/features/trust_scores.csv
ADDED
|
@@ -0,0 +1,121 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
rank,platform,creator_id,creator_name,follower_count,content_count,observed_content_count,total_views,avg_engagement_rate,avg_sentiment_score,avg_activity_score,trust_score,suspicious_content_count,label_source,collected_at
|
| 2 |
+
1,tiktok,6598924718044151813,Storm van Reusel,0,0,1,168300000,0.147897,50.0,100.0,85.0,0,rule_generated_not_ground_truth,2026-06-02T15:53:50Z
|
| 3 |
+
2,tiktok,7302014518175482881,Phạm Liêm Seven-ten,0,0,1,1000000,0.180708,50.0,100.0,85.0,0,rule_generated_not_ground_truth,2026-06-02T15:53:50Z
|
| 4 |
+
3,tiktok,7598717183945868309,Cục zàng🐣,0,0,1,23100,0.23303,50.0,100.0,85.0,0,rule_generated_not_ground_truth,2026-06-02T15:53:50Z
|
| 5 |
+
4,tiktok,6804625031726629890,米雷-RayDog,0,0,1,23500000,0.079344,50.0,100.0,74.67,0,rule_generated_not_ground_truth,2026-06-02T15:53:50Z
|
| 6 |
+
5,youtube,UC6mj0JZ24upkoqmDFepKg5w,Vietnam Mama cooking,1570,318,5,888,1.141358,65.39,15.68,72.75,5,rule_generated_not_ground_truth,2026-06-03T07:53:10Z
|
| 7 |
+
6,tiktok,7290180759197238315,Olivia,0,0,1,10500000,0.074648,50.0,100.0,72.32,0,rule_generated_not_ground_truth,2026-06-02T15:53:50Z
|
| 8 |
+
7,tiktok,6591472415795298306,Khoai Lang Thang,3400000,304,20,111678200,0.074446,50.0,100.0,69.23,0,rule_generated_not_ground_truth,2026-06-02T17:15:45Z
|
| 9 |
+
8,youtube,UCUsVZG1AGPBzP2FIAGNNixw,VIETNAM MUSIC,7,1,1,65,0.353846,55.71,0.7,66.85,1,rule_generated_not_ground_truth,2026-06-03T07:53:10Z
|
| 10 |
+
9,tiktok,80554316233,CrisDevilGamer,6000000,453,20,78756300,0.077303,50.0,86.59,66.38,0,rule_generated_not_ground_truth,2026-06-02T17:15:45Z
|
| 11 |
+
10,youtube,UCUAegToZ1-cWQu4S8ZqrkjA,Vietnam Music Instruments,13,1,1,245,0.118367,52.0,1.0,65.8,0,rule_generated_not_ground_truth,2026-06-03T07:53:10Z
|
| 12 |
+
11,youtube,UCZNKVuh2Mp_AaODb1FujHWw,VietNam Gaming,0,1,1,1,1.0,50.0,0.1,65.02,1,rule_generated_not_ground_truth,2026-06-03T07:53:10Z
|
| 13 |
+
12,youtube,UCG2CCyyTfwYccKbytD2Oalg,VIETNAM TRAVEL,25,16,5,22,0.41,50.0,0.0,65.0,2,rule_generated_not_ground_truth,2026-06-03T07:53:10Z
|
| 14 |
+
13,youtube,UCHmu9LeaVpYa-gomfbR59QQ,Music VIETNAM,0,2,2,8,0.25,50.0,0.0,65.0,0,rule_generated_not_ground_truth,2026-06-03T07:53:10Z
|
| 15 |
+
14,youtube,UCpo7aqOFeK11ajjm6mCF2rQ,Vietnamese cuisine,0,2,1,5,0.2,50.0,0.0,65.0,0,rule_generated_not_ground_truth,2026-06-02T14:18:20Z
|
| 16 |
+
15,tiktok,6631682124809076737,Độ Phùng,6800000,1079,20,40835700,0.058689,50.0,93.3,63.0,20,rule_generated_not_ground_truth,2026-06-02T17:15:45Z
|
| 17 |
+
16,tiktok,6523839909668093953,Misthy,5100000,960,20,29894100,0.074941,50.0,54.22,62.51,0,rule_generated_not_ground_truth,2026-06-02T17:15:45Z
|
| 18 |
+
17,youtube,UCRjxQQBNqZR_xLOvf9w_m7w,Vietnam Travel Guide,152000,910,5,7481,0.133825,60.17,2.1,61.44,0,rule_generated_not_ground_truth,2026-06-03T07:53:10Z
|
| 19 |
+
18,youtube,UCcR2oBXIfta3Smw7XjFYWHw,VIETNAM GAMING,2,3,3,98,0.088391,53.33,0.07,58.36,0,rule_generated_not_ground_truth,2026-06-03T07:53:10Z
|
| 20 |
+
19,youtube,UC-uNVV92llYIMC5-ZUF0Q4w,Uyen Ninh,3460000,1167,10,33094634,0.045207,53.48,90.65,56.78,0,rule_generated_not_ground_truth,2026-06-03T07:53:10Z
|
| 21 |
+
20,tiktok,6858548206466597889,Pít Ham Ăn,3000000,1424,20,10318200,0.047831,50.0,73.03,53.52,0,rule_generated_not_ground_truth,2026-06-02T17:15:45Z
|
| 22 |
+
21,youtube,UCXnOx_I_3tRmQeRGQmuoVwA,VIETNAM GAMING,0,1,1,14,0.071429,50.0,0.1,50.73,0,rule_generated_not_ground_truth,2026-06-03T07:53:10Z
|
| 23 |
+
22,tiktok,6724460466796282882,Tiin.vn,10900000,8779,20,276148100,0.038605,50.0,77.65,49.69,1,rule_generated_not_ground_truth,2026-06-02T17:15:45Z
|
| 24 |
+
23,youtube,UCiQip6GTSBcu0YCu0X0hKGA,Vuong Anh's Cooking Journey,72900,36,5,224908,0.054555,62.86,17.2,49.57,0,rule_generated_not_ground_truth,2026-06-03T07:53:10Z
|
| 25 |
+
24,youtube,UCMxiANrpg00n8A1wRysXCKA,Vietnam gaming,19,9,5,2683,0.121803,50.0,0.22,49.35,0,rule_generated_not_ground_truth,2026-06-03T07:53:10Z
|
| 26 |
+
25,youtube,UCc1eikgvvIhZsIacMRUbnSQ,VietNam Tech News,34,3,3,712,0.227759,51.43,0.5,48.98,1,rule_generated_not_ground_truth,2026-06-03T07:53:10Z
|
| 27 |
+
26,tiktok,6913858551564043265,ông Anh thích nấu ăn,2800000,1020,20,55602300,0.036728,50.0,64.49,46.26,0,rule_generated_not_ground_truth,2026-06-02T17:15:45Z
|
| 28 |
+
27,tiktok,63906295671,Travel Blogger Tô Đi Đâu,206000,364,20,28249469,0.045884,50.0,47.97,46.24,0,rule_generated_not_ground_truth,2026-06-02T17:15:45Z
|
| 29 |
+
28,youtube,UCraOIV5tXbWQtq7ORVOG4gg,Quang Tran,2760000,2764,11,190693,0.059895,52.82,7.32,46.05,0,rule_generated_not_ground_truth,2026-06-03T07:53:10Z
|
| 30 |
+
29,tiktok,7098232443631797250,Hà Nội News,5500000,17400,20,21913200,0.038888,50.0,64.62,45.84,0,rule_generated_not_ground_truth,2026-06-02T17:15:45Z
|
| 31 |
+
30,youtube,UC6Qi6JtBg-HUYKheKY4Hugw,Travis Travels Vietnam,73700,202,5,85520,0.050462,57.73,8.6,44.27,0,rule_generated_not_ground_truth,2026-06-03T07:53:10Z
|
| 32 |
+
31,youtube,UCsiMQj6tmUsehme-CcXiwsw,vietnam gaming,2,8,5,50,0.076508,50.0,0.0,42.14,0,rule_generated_not_ground_truth,2026-06-03T07:53:10Z
|
| 33 |
+
32,youtube,UCMmz6IDJCpKp5OjOoM6wrzQ,VIETNAM GAMING,1940,399,5,1180,0.053521,50.0,0.06,41.77,0,rule_generated_not_ground_truth,2026-06-03T07:53:10Z
|
| 34 |
+
33,youtube,UCQ1orr7TCJeRCqnvaxI1zlQ,vietnam Gaming,7,2,2,63,0.171875,54.45,0.45,41.42,1,rule_generated_not_ground_truth,2026-06-03T07:53:10Z
|
| 35 |
+
34,youtube,UCT6UwSc6fQcYWJ3WdRkpQrQ,Mikrotik Viet Nam (MVN),13800,262,5,3810,0.041761,64.52,0.48,40.33,0,rule_generated_not_ground_truth,2026-06-03T07:53:10Z
|
| 36 |
+
35,youtube,UCg4e9liAH_PbNBs1pPOWtnA,Christina VietNam Music ,265,84,5,2157,0.046794,56.0,0.22,40.24,0,rule_generated_not_ground_truth,2026-06-03T07:53:10Z
|
| 37 |
+
36,tiktok,6908933207383639041,Tiểu Màn Thầu,3100000,1260,20,9374466,0.031441,50.0,43.77,39.48,0,rule_generated_not_ground_truth,2026-06-02T16:55:58Z
|
| 38 |
+
37,youtube,UCk0bYdVq1gHzK0uUWUe6VGA,VietNam Cuisine - Vietnamese Food Recipes,2080,51,5,7043,0.046965,52.0,0.42,39.17,0,rule_generated_not_ground_truth,2026-06-03T07:53:10Z
|
| 39 |
+
38,youtube,UCu1Z7OILz8yhcclCLibG2mg,ZanD Gaming,1390,89,5,3731,0.047558,49.72,1.02,38.9,0,rule_generated_not_ground_truth,2026-06-03T07:53:10Z
|
| 40 |
+
39,youtube,UCzEhY0E8owC8biK-P7-xeSg,Noventiq Vietnam,791,187,5,255,0.047701,58.0,0.02,38.49,0,rule_generated_not_ground_truth,2026-06-03T07:53:10Z
|
| 41 |
+
40,youtube,UC0Ibt55-RBAnxoh1_kn_NRQ,Vietnam Gaming,8,4,4,1120,0.046804,49.23,0.43,38.26,0,rule_generated_not_ground_truth,2026-06-03T07:53:10Z
|
| 42 |
+
41,tiktok,6800705725297296385,Travip,1100000,1097,20,406553,0.041739,50.0,11.81,38.23,0,rule_generated_not_ground_truth,2026-06-02T17:15:45Z
|
| 43 |
+
42,youtube,UCDgZ-saVJWUxqbLQPPh-oNA,My Basil Leaf-Vietnamese-Asian And American Comfort Food Recipes,98700,384,5,64865,0.036092,62.47,3.86,37.56,0,rule_generated_not_ground_truth,2026-06-03T07:53:10Z
|
| 44 |
+
43,tiktok,7523211888538321938,Vietnam Today,215000,1246,20,192583,0.041151,50.0,0.88,35.75,0,rule_generated_not_ground_truth,2026-06-02T17:15:45Z
|
| 45 |
+
44,youtube,UCpqvxj3yjv6NL1E99EL-1Yg,VietNam Gaming,18,5,4,1059,0.034792,60.0,0.08,35.41,0,rule_generated_not_ground_truth,2026-06-03T07:53:10Z
|
| 46 |
+
45,youtube,UCp8QtOj7_yvC7YjzoW46Q3A,TechMaster Vietnam,11900,1063,5,384,0.039129,50.0,0.0,34.56,0,rule_generated_not_ground_truth,2026-06-03T07:53:10Z
|
| 47 |
+
46,youtube,UCxHfE9ihtbk7U7-cTJ1v9_Q,VietNam Soldier Gaming,15,15,5,701,0.037505,52.0,0.08,34.37,0,rule_generated_not_ground_truth,2026-06-03T07:53:10Z
|
| 48 |
+
47,youtube,UCa7OXf8dyq3r1ycqcOQJRnw,Vietnam Travel,21,11,5,1873,0.049705,50.0,0.02,34.23,0,rule_generated_not_ground_truth,2026-06-03T07:53:10Z
|
| 49 |
+
48,youtube,UCW26X4htXF3eW741YVAGivg,Authentik Vietnam Travel,51,39,5,3314,0.036436,50.0,0.0,33.22,0,rule_generated_not_ground_truth,2026-06-03T07:53:10Z
|
| 50 |
+
49,youtube,UC2VFEuW5IyKEo3ZeWWrwQ-g,Vietnam Music,1240,111,5,4387,0.052431,50.0,0.0,32.86,0,rule_generated_not_ground_truth,2026-06-03T07:53:10Z
|
| 51 |
+
50,youtube,UC8kbTI0wW7Mkej-qh9O283w,Vietnamese Home Cooking,17500,247,5,4374,0.033627,52.0,0.1,31.94,0,rule_generated_not_ground_truth,2026-06-03T07:53:10Z
|
| 52 |
+
51,youtube,UCyR8D9XLpgbDZnwvnFMkYeQ,Tạp chí Vietnam Travel,560,192,5,2414,0.033037,50.0,0.12,31.54,0,rule_generated_not_ground_truth,2026-06-03T07:53:10Z
|
| 53 |
+
52,youtube,UC6Xd4aJwKDNAA3qtBLfc4iQ,Linh - Vietnam,95600,11,5,1254047,0.020592,56.56,20.52,31.37,0,rule_generated_not_ground_truth,2026-06-03T07:53:10Z
|
| 54 |
+
53,youtube,UCTM7PbUlPlJw4ZAmuOYEiMQ,HORIZON VIETNAM TRAVEL,6230,143,5,1586,0.032399,50.0,0.06,31.21,0,rule_generated_not_ground_truth,2026-06-03T07:53:10Z
|
| 55 |
+
54,youtube,UCcOsD3jivt066WJVgC2SRUA,Akari Gaming,307000,7235,5,16898,0.029687,52.4,1.72,30.91,0,rule_generated_not_ground_truth,2026-06-03T07:53:10Z
|
| 56 |
+
55,tiktok,6768356655271117826,Vật Vờ Studio,1200000,2106,20,1630911,0.026256,50.0,13.1,30.75,0,rule_generated_not_ground_truth,2026-06-02T17:15:45Z
|
| 57 |
+
56,youtube,UC1-FuPHoQcwCHr9cqWEV7ng,VietNam Music Festival,272,20,5,694,0.05104,50.0,0.02,30.52,0,rule_generated_not_ground_truth,2026-06-03T07:53:10Z
|
| 58 |
+
57,youtube,UCxkRagYyaaIeGtbb53_a3Yw,Vietnam Travel Memories,72,235,5,124,0.029932,50.0,0.0,29.76,0,rule_generated_not_ground_truth,2026-06-03T07:53:10Z
|
| 59 |
+
58,tiktok,7043342820224222209,Vũ Nguyễn Coder,79900,189,20,19549612,0.024772,50.0,9.95,29.38,0,rule_generated_not_ground_truth,2026-06-02T17:15:45Z
|
| 60 |
+
59,youtube,UCTlpkcwA2v6MRlvcm9FYhsA,Horizon Vietnam Music,560,73,5,478,0.026857,50.0,0.0,28.43,0,rule_generated_not_ground_truth,2026-06-03T07:53:10Z
|
| 61 |
+
60,youtube,UCfUecmXtGUf52bwuRXtA3qg,Vietnam Travel,69,32,5,776,0.042778,50.0,0.0,28.21,0,rule_generated_not_ground_truth,2026-06-03T07:53:10Z
|
| 62 |
+
61,youtube,UCCp_6ZL9dWm-e36wjaSudzQ,VietNam Gaming,13,22,4,32,0.0625,50.0,0.0,27.5,0,rule_generated_not_ground_truth,2026-06-03T07:53:10Z
|
| 63 |
+
62,youtube,UCMCPYiwI73CGbmiZtuVhUgg,Vietnam Travel Experience ,1070,68,5,459,0.040441,50.0,0.0,26.47,0,rule_generated_not_ground_truth,2026-06-03T07:53:10Z
|
| 64 |
+
63,youtube,UCrCqu1n0H52uGETAoSmgNdQ,EA Sports FC Online Vietnam,607000,3590,5,116974,0.021621,51.6,0.56,26.4,0,rule_generated_not_ground_truth,2026-06-03T07:53:10Z
|
| 65 |
+
64,youtube,UCxXWG8IH-Bu1pc6tUfR69vA,Vietnam Factory Tours,7960,475,5,2883,0.019966,54.0,0.02,26.19,0,rule_generated_not_ground_truth,2026-06-03T07:53:10Z
|
| 66 |
+
65,youtube,UCxSQ9n_i2CTCs2Hh0dwkjYw,Vietnam M.Tech,3,6,5,306,0.023889,50.0,0.0,25.83,0,rule_generated_not_ground_truth,2026-06-03T07:53:10Z
|
| 67 |
+
66,youtube,UCqj5zyw8F8XS893w7OThRPw,KAHA Tech Vietnam,14500,934,5,2170,0.021543,50.0,0.24,25.82,0,rule_generated_not_ground_truth,2026-06-03T07:53:10Z
|
| 68 |
+
67,youtube,UCLkNYpdYwR_T0dROm3Nh7AA,ToiToi Vietnam Cooking Center,7,29,5,2417,0.041616,50.0,0.02,25.81,0,rule_generated_not_ground_truth,2026-06-03T07:53:10Z
|
| 69 |
+
68,youtube,UCC4nG1vDboGhOUQpqh66BJA,VietNam Music,1,2,2,570,0.021547,50.0,0.05,25.79,0,rule_generated_not_ground_truth,2026-06-03T07:53:10Z
|
| 70 |
+
69,youtube,UCSGD1TbYm5ZEZtGKQlkZ69A,Samsung Vietnam,2270000,3837,9,10266,0.021083,50.0,0.0,25.54,0,rule_generated_not_ground_truth,2026-06-03T07:53:10Z
|
| 71 |
+
70,youtube,UC1w3rRqx6rBO-xTjETnXLhw,VALORANT Vietnam,131000,2762,5,29931,0.019557,50.0,0.3,24.84,0,rule_generated_not_ground_truth,2026-06-03T07:53:10Z
|
| 72 |
+
71,youtube,UCfJZVE_WVSCnlhbbCy2BhJQ,Traditional life in VietNam,1570,84,5,6160,0.017972,52.0,0.04,24.59,0,rule_generated_not_ground_truth,2026-06-03T07:53:10Z
|
| 73 |
+
72,youtube,UCMmZEL8jV1B61NKAXcyW87A,Helen's Recipes (Vietnamese Food),658000,1170,5,40741,0.015389,53.9,1.04,24.07,0,rule_generated_not_ground_truth,2026-06-03T07:53:10Z
|
| 74 |
+
73,youtube,UCdouf4Nk-opU7-J1VMrRHsw,Vietnam's Got Talent,831000,1420,10,16725324,0.002066,53.62,31.43,23.41,0,rule_generated_not_ground_truth,2026-06-03T07:53:10Z
|
| 75 |
+
74,youtube,UC7mH_HZqhIASMBmSEPjx6Lg,Vietnam Music Coner,5,4,4,2692,0.015592,50.0,0.0,22.8,0,rule_generated_not_ground_truth,2026-06-03T07:53:10Z
|
| 76 |
+
75,youtube,UCbZpXn7fpeoY5KFoIaq0ZwQ,Vietnam Music Instrumental,9,2,2,4289,0.015387,50.0,0.05,22.7,0,rule_generated_not_ground_truth,2026-06-03T07:53:10Z
|
| 77 |
+
76,youtube,UC80N_DRIZsMNI3_wCZS_rbw,Home Cooking Vietnam,9,6,5,3896,0.01501,50.0,0.02,22.51,0,rule_generated_not_ground_truth,2026-06-03T07:53:10Z
|
| 78 |
+
77,youtube,UC3rfZHbQ0xmL9LVqVhIl0Kw,Vietnam Travel,12,21,5,500,0.014747,50.0,0.0,22.37,0,rule_generated_not_ground_truth,2026-06-03T07:53:10Z
|
| 79 |
+
78,youtube,UCTnLocbkpsu1C-uG_DzjK_w,GITEX AI VIETNAM,10,29,5,166,0.013793,50.0,0.0,21.9,0,rule_generated_not_ground_truth,2026-06-03T07:53:10Z
|
| 80 |
+
79,youtube,UCKjYQN8_lmUxWpJL8awcHcw,Vietnam Tech Week,118,15,5,456,0.013602,50.0,0.0,21.8,0,rule_generated_not_ground_truth,2026-06-03T07:53:10Z
|
| 81 |
+
80,tiktok,7226613529808520198,Hướng Review,103100,726,20,5864862,0.008096,50.0,12.24,21.5,2,rule_generated_not_ground_truth,2026-06-02T17:15:45Z
|
| 82 |
+
81,youtube,UCCWX3wMrxnW5i6VpBnaNOrg,Vietnam Tourism,19300,731,5,8055,0.0122,50.0,0.0,21.1,0,rule_generated_not_ground_truth,2026-06-03T07:53:10Z
|
| 83 |
+
82,youtube,UCjAY89mpkZ3ueqHA1zzw0Cg,Tech.MediaOnline Vietnam,2270,237,5,150,0.011919,50.0,0.0,20.96,0,rule_generated_not_ground_truth,2026-06-03T07:53:10Z
|
| 84 |
+
83,youtube,UC9OTt-52g0BCu7ZvvpitJXA,Your Vietnam Travel,248,196,5,6867,0.011521,50.0,0.06,20.77,0,rule_generated_not_ground_truth,2026-06-03T07:53:10Z
|
| 85 |
+
84,youtube,UCxNn79EEkrW49R4PXAvdfWQ,RTC Technology Viet Nam JSC,229,165,5,512,0.011356,50.0,0.0,20.68,0,rule_generated_not_ground_truth,2026-06-03T07:53:10Z
|
| 86 |
+
85,youtube,UCEIeaQFCustss2s8ggjT02g,KPMG in Vietnam & Cambodia,2090,131,5,1002,0.011197,50.0,0.0,20.6,0,rule_generated_not_ground_truth,2026-06-03T07:53:10Z
|
| 87 |
+
86,youtube,UC63IegIk0eZJ3yDOoV2iCXQ,VietNam music,2,1,1,1173,0.011083,50.0,0.0,20.54,0,rule_generated_not_ground_truth,2026-06-03T07:53:10Z
|
| 88 |
+
87,youtube,UC3Btm-5MEIxL1bpz1cmmJ8A,Little Chef Vietnam,29,32,5,3700,0.010754,50.0,0.1,20.4,0,rule_generated_not_ground_truth,2026-06-03T07:53:10Z
|
| 89 |
+
88,youtube,UCW06OWND7KVXgEC5QVR1ong,Viet Nam Gaming,2950,95,5,52307,0.009729,50.17,0.94,20.11,0,rule_generated_not_ground_truth,2026-06-03T07:53:10Z
|
| 90 |
+
89,youtube,UCTr3p1TJDlKDTcjZYc0g-pQ,Jacky Vietnam Travel,116,79,5,3613,0.009672,50.0,0.0,19.84,0,rule_generated_not_ground_truth,2026-06-03T07:53:10Z
|
| 91 |
+
90,youtube,UCemZVIIJrLFyvdkOkVRXb9g,Vietnam MUSIC,17,12,5,12913,0.009173,50.0,0.04,19.59,0,rule_generated_not_ground_truth,2026-06-03T07:53:10Z
|
| 92 |
+
91,youtube,UC4n1rJYWTmcjuztZc5uVnig,Vietnamese Food,2110,127,5,6358,0.008929,50.0,0.0,19.46,0,rule_generated_not_ground_truth,2026-06-03T07:53:10Z
|
| 93 |
+
92,youtube,UCwq95KcdMM5BRMwYsJX4iHg,Vietnam GameTV,419000,17932,2,822,0.008921,50.0,0.0,19.46,0,rule_generated_not_ground_truth,2026-06-03T07:53:10Z
|
| 94 |
+
93,youtube,UClJRpskYXaFzdZhGiTDBzhA,Vietnam Music,403,1,1,213932,0.003506,49.0,14.9,19.43,0,rule_generated_not_ground_truth,2026-06-03T07:53:10Z
|
| 95 |
+
94,youtube,UC6V1_Mx9X8KT3ud_puq0YSg,Vietnam Original Travel,386,458,5,8405,0.00841,50.0,0.02,19.21,0,rule_generated_not_ground_truth,2026-06-03T07:53:10Z
|
| 96 |
+
95,youtube,UCHdzogFaloYKjc7rFoJWpXA,Vietnam food recipes,4900,18,5,308967,0.006427,51.62,1.86,19.07,0,rule_generated_not_ground_truth,2026-06-03T07:53:10Z
|
| 97 |
+
96,youtube,UCmFuaHRAa2HahcJNId_AQtQ,Cuisine of Vietnam,426,24,5,2586,0.00735,50.0,0.02,18.68,0,rule_generated_not_ground_truth,2026-06-03T07:53:10Z
|
| 98 |
+
97,youtube,UCiK2JMDwL_HNwnSlnqFbq5A,Ricoh Vietnam Official,567,232,5,154863,0.007148,50.0,0.0,18.57,1,rule_generated_not_ground_truth,2026-06-03T07:53:10Z
|
| 99 |
+
98,youtube,UCUFHKwQqtHuyezmGQb2LBkQ,Vietnam Travel,1390,153,5,2812,0.007044,50.0,0.0,18.52,0,rule_generated_not_ground_truth,2026-06-03T07:53:10Z
|
| 100 |
+
99,youtube,UCp1kbXU_uGmJp2UZXvp_bjg,Hitachi Home Appliances Vietnam,21400,274,5,3444,0.004605,53.0,0.12,18.23,0,rule_generated_not_ground_truth,2026-06-03T07:53:10Z
|
| 101 |
+
100,youtube,UCuVxGbAFuFNdxVbRzI3BBsg,MITSUBISHI ELECTRIC VIETNAM,12500,234,6,600,0.006465,50.0,0.0,18.23,0,rule_generated_not_ground_truth,2026-06-03T07:53:10Z
|
| 102 |
+
101,youtube,UCfNaGmiVzcAemwe70TZe7Gg,Vietnam Street Food,39700,312,5,465818,0.004435,51.32,1.08,17.83,0,rule_generated_not_ground_truth,2026-06-03T07:53:10Z
|
| 103 |
+
102,youtube,UCVW1OekpflGQmJ8mbYym-Qw,VietNam Music Studio,10,7,5,13892,0.00405,52.0,0.04,17.63,0,rule_generated_not_ground_truth,2026-06-03T07:53:10Z
|
| 104 |
+
103,youtube,UCHDuqwcnZ43AeTpZYQOQqQw,KingCom VietNam,84500,981,5,3090,0.005225,50.0,0.0,17.61,0,rule_generated_not_ground_truth,2026-06-03T07:53:10Z
|
| 105 |
+
104,youtube,UCY8WaQi4-KO9KH3Nm2-LlKw,vietnam music,10,2,2,1058,0.004496,50.0,0.0,17.25,0,rule_generated_not_ground_truth,2026-06-03T07:53:10Z
|
| 106 |
+
105,youtube,UCHVCod4yFaf07S3ab1SwnWg,Frontier Travel Vietnam | Vietnam Motorbike Tours,16800,368,5,1736,0.004365,50.0,0.0,17.18,0,rule_generated_not_ground_truth,2026-06-03T07:53:10Z
|
| 107 |
+
106,youtube,UC12y6U2OyaA95IveDoZKxMw,Vietnam Travel TV,117,6,5,54645,0.002839,50.67,0.24,16.67,0,rule_generated_not_ground_truth,2026-06-03T07:53:10Z
|
| 108 |
+
107,youtube,UCJzyB8wRuzbCCHfSJvYAScw,VIETNAM B2B,10000,148,5,197,0.003077,50.0,0.0,16.54,0,rule_generated_not_ground_truth,2026-06-03T07:53:10Z
|
| 109 |
+
108,youtube,UCPLicXu_RqvVAZbe5imBNBA,GosuGamers Vietnam,15400,1099,5,1111,0.002854,50.0,0.0,16.43,0,rule_generated_not_ground_truth,2026-06-03T07:53:10Z
|
| 110 |
+
109,youtube,UCvnEJ7U1SFEDuV2El0hxz6A,Vietnam Street Food TV,2820,94,5,1127,0.002511,50.0,0.04,16.26,0,rule_generated_not_ground_truth,2026-06-03T07:53:10Z
|
| 111 |
+
110,youtube,UCTXrzd1aKjRtt-cuSrD6dAQ,Tech Sound Việt Nam,43000,1003,5,2219,0.001269,52.0,0.06,16.25,0,rule_generated_not_ground_truth,2026-06-03T07:53:10Z
|
| 112 |
+
111,youtube,UCjCLSCwzaE3BovLeu_CA-6A,VietNam Gaming,13,2,2,7889,0.002354,50.0,0.15,16.2,0,rule_generated_not_ground_truth,2026-06-03T07:53:10Z
|
| 113 |
+
112,youtube,UCx7h8atYLf4BO7J4Tm2n5aQ,Vietnam Street Food TV,9110,430,5,7559,0.002356,50.0,0.02,16.18,0,rule_generated_not_ground_truth,2026-06-03T07:53:10Z
|
| 114 |
+
113,youtube,UCodr3xuT4jKz0lkTsqq4DDA,VietNam Music,60,6,5,12455,0.001838,50.0,0.0,15.92,0,rule_generated_not_ground_truth,2026-06-03T07:53:10Z
|
| 115 |
+
114,youtube,UCVNEOIlYEHmgBCeAU_1KcEA,VietNam Music,193,3,2,125603,0.000936,50.0,0.25,15.52,0,rule_generated_not_ground_truth,2026-06-03T07:53:10Z
|
| 116 |
+
115,youtube,UCE9qu2Su44_d2EQ_94KoC6A,Vietnam Gaming,0,2,2,41,0.0,50.0,0.0,15.0,0,rule_generated_not_ground_truth,2026-06-03T07:53:10Z
|
| 117 |
+
116,youtube,UCpDx3VfwuMTyvO416ALth4Q,Vietnam Music House,0,3,3,40,0.0,50.0,0.0,15.0,0,rule_generated_not_ground_truth,2026-06-03T07:53:10Z
|
| 118 |
+
117,youtube,UC4iwTXfC_A2mFHf6BvxU_OA,Vietnam Travel Group,1510,281,5,37,0.0,50.0,0.0,15.0,0,rule_generated_not_ground_truth,2026-06-03T07:53:10Z
|
| 119 |
+
118,youtube,UCYFIsdWn_T9QjrNaHcfyXKQ,New Age Vietnam Music,1,2,2,20,0.0,50.0,0.0,15.0,0,rule_generated_not_ground_truth,2026-06-03T07:53:10Z
|
| 120 |
+
119,youtube,UC71sF3J9-Dvup1I3gxMYvhw,Vietnam music,0,2,2,7,0.0,50.0,0.0,15.0,0,rule_generated_not_ground_truth,2026-06-03T07:53:10Z
|
| 121 |
+
120,youtube,UCTwFk6f1dTQn-dRtFQdIGbA,Du Lịch Việt Nam Vietnam Travel,12600,513,5,7967,0.001979,45.7,0.36,14.77,0,rule_generated_not_ground_truth,2026-06-03T07:53:10Z
|
data/input/manual_trust_labels.csv
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
platform,creator_id,content_id,human_trust_score,human_trust_label,human_is_suspicious,label_reason,annotator,labeled_at
|
| 2 |
+
youtube,UC-uNVV92llYIMC5-ZUF0Q4w,3xMaGHhCLrA,82,high_trust,0,"N?i dung ?n, engagement t? nhi�n",ann_01,6/16/2026
|
| 3 |
+
youtube,UCdouf4Nk-opU7-J1VMrRHsw,h_JMBMifKGo,35,low_trust,1,"Engagement b?t thu?ng, comment l?p",ann_01,6/16/2026
|
| 4 |
+
tiktok,creator123,video456,60,medium_trust,0,Thi?u b?ng ch?ng x?u nhung sentiment trung b�nh,ann_02,6/16/2026
|
data/serving/kol_events.jsonl
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
data/silver/unified/vietnam_influencer_features.csv
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
ml/models/sentiment/comment_sentiment.joblib
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:599f0cb564f1cb9c612ace578b7ddffb550dac7dec2f2934ba3a04666c3c0889
|
| 3 |
+
size 127486
|
ml/models/trust_score/kol_trust_model.joblib
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:bb706f5139a3ec62438e64453272ad57b0f3b0c8d1e0fda29000ef0398b9bc8e
|
| 3 |
+
size 2318059
|
requirements.txt
CHANGED
|
@@ -1,3 +1,5 @@
|
|
| 1 |
-
|
| 2 |
-
pandas
|
| 3 |
-
|
|
|
|
|
|
|
|
|
| 1 |
+
streamlit>=1.36.0
|
| 2 |
+
pandas>=2.2.0
|
| 3 |
+
plotly>=5.22.0
|
| 4 |
+
scikit-learn>=1.4.0
|
| 5 |
+
joblib>=1.3.0
|