Spaces:
No application file
No application file
Upload 7 files
Browse files- README_CCR.txt +14 -0
- app.py +249 -0
- data/CCR_default_weights.json +9 -0
- data/CCR_demo_ratings.csv +3 -0
- data/CCR_ratings.csv +2 -0
- data/CCR_results.csv +2 -0
- data/CCR_rubric_template.csv +1 -0
README_CCR.txt
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# CCR Webapp (Stepper Navigation)
|
| 2 |
+
|
| 3 |
+
## Install
|
| 4 |
+
pip install streamlit pandas numpy
|
| 5 |
+
|
| 6 |
+
## Run
|
| 7 |
+
streamlit run app.py
|
| 8 |
+
|
| 9 |
+
## Features
|
| 10 |
+
- Bovenaan **stepper** (segmented control) met 3 stappen i.p.v. tab-switching.
|
| 11 |
+
- Onderaan **Campagne-info**: knop **Volgende →** die naar **Score** gaat.
|
| 12 |
+
- In **Score**: knop **Save rating now** die opslaat en doorstroomt naar **Output**.
|
| 13 |
+
- Brand & Naam naast elkaar, Audience dropdown (met 'Other...'), Channel bevat 'Integrated', Rater dropdown (Lode/Maarten).
|
| 14 |
+
- Live CCR% + YouTube-preview in Score stap (rechts).
|
app.py
ADDED
|
@@ -0,0 +1,249 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
|
| 2 |
+
import os, json, re
|
| 3 |
+
from datetime import date
|
| 4 |
+
import pandas as pd
|
| 5 |
+
import streamlit as st
|
| 6 |
+
|
| 7 |
+
st.set_page_config(page_title="Culturally Creative & Relevant Rater", page_icon="🗂️", layout="wide")
|
| 8 |
+
|
| 9 |
+
# --------- Constants ---------
|
| 10 |
+
DATA_DIR = "data"
|
| 11 |
+
RATINGS_CSV = os.path.join(DATA_DIR, "CCR_ratings.csv")
|
| 12 |
+
RESULTS_CSV = os.path.join(DATA_DIR, "CCR_results.csv")
|
| 13 |
+
|
| 14 |
+
DEFAULT_WEIGHTS = {
|
| 15 |
+
"CR_cultural_resonance": 0.22,
|
| 16 |
+
"OR_originality": 0.18,
|
| 17 |
+
"TI_timeliness": 0.12,
|
| 18 |
+
"IE_inclusivity_ethics": 0.10,
|
| 19 |
+
"SH_shareability": 0.15,
|
| 20 |
+
"BF_brand_channel_fit": 0.13,
|
| 21 |
+
"CQ_craft_quality": 0.10
|
| 22 |
+
}
|
| 23 |
+
DIMENSIONS = list(DEFAULT_WEIGHTS.keys())
|
| 24 |
+
|
| 25 |
+
AUDIENCE_OPTIONS = [
|
| 26 |
+
"BE urban 16-24",
|
| 27 |
+
"BE Gen Z 18-24",
|
| 28 |
+
"BE mainstream 25-44",
|
| 29 |
+
"NL mainstream 25-44",
|
| 30 |
+
"EU mainstream 25-44",
|
| 31 |
+
"FR urban 18-34",
|
| 32 |
+
"DE mainstream 18-49",
|
| 33 |
+
"Other...",
|
| 34 |
+
]
|
| 35 |
+
CHANNEL_OPTIONS = ["TikTok","Instagram","YouTube","OOH","TV","Radio","Integrated","Other"]
|
| 36 |
+
RATER_OPTIONS = ["Lode","Maarten"]
|
| 37 |
+
|
| 38 |
+
os.makedirs(DATA_DIR, exist_ok=True)
|
| 39 |
+
|
| 40 |
+
# --------- Helpers ---------
|
| 41 |
+
def ensure_csv(path):
|
| 42 |
+
if not os.path.exists(path):
|
| 43 |
+
cols = ["campaign_id","rater_id","rater_notes","campaign_name","brand","channel","scene_audience","country","submit_date_iso","asset_youtube_url",*DIMENSIONS,"flag_stereotype","flag_misappropriation","flag_sensitive_timing","flag_other_risk","neg_sentiment_ratio_estimate"]
|
| 44 |
+
pd.DataFrame(columns=cols).to_csv(path, index=False)
|
| 45 |
+
|
| 46 |
+
def load_ratings():
|
| 47 |
+
ensure_csv(RATINGS_CSV)
|
| 48 |
+
try:
|
| 49 |
+
return pd.read_csv(RATINGS_CSV)
|
| 50 |
+
except Exception:
|
| 51 |
+
return pd.DataFrame(columns=["campaign_id","rater_id","rater_notes","campaign_name","brand","channel","scene_audience","country","submit_date_iso","asset_youtube_url",*DIMENSIONS,"flag_stereotype","flag_misappropriation","flag_sensitive_timing","flag_other_risk","neg_sentiment_ratio_estimate"])
|
| 52 |
+
|
| 53 |
+
def save_rating(row: dict):
|
| 54 |
+
df = load_ratings()
|
| 55 |
+
df = pd.concat([df, pd.DataFrame([row])], ignore_index=True)
|
| 56 |
+
df.to_csv(RATINGS_CSV, index=False)
|
| 57 |
+
|
| 58 |
+
def to_0_100(x):
|
| 59 |
+
import pandas as pd
|
| 60 |
+
return (pd.to_numeric(x, errors="coerce") - 1.0)/4.0*100.0
|
| 61 |
+
|
| 62 |
+
def compute_results(weights: dict) -> pd.DataFrame:
|
| 63 |
+
df = load_ratings()
|
| 64 |
+
if df.empty:
|
| 65 |
+
return pd.DataFrame()
|
| 66 |
+
|
| 67 |
+
for d in DIMENSIONS:
|
| 68 |
+
df[f"{d}_100"] = to_0_100(df[d])
|
| 69 |
+
df["CCR_rater"] = 0.0
|
| 70 |
+
for d, w in weights.items():
|
| 71 |
+
df["CCR_rater"] += w * df[f"{d}_100"]
|
| 72 |
+
|
| 73 |
+
agg = {**{d: "mean" for d in DIMENSIONS},
|
| 74 |
+
**{f"{d}_100": "mean" for d in DIMENSIONS},
|
| 75 |
+
**{c: "mean" for c in ["flag_stereotype","flag_misappropriation","flag_sensitive_timing","flag_other_risk","neg_sentiment_ratio_estimate"] if c in df.columns},
|
| 76 |
+
"CCR_rater": "mean",
|
| 77 |
+
"campaign_name":"first",
|
| 78 |
+
"brand":"first",
|
| 79 |
+
"channel":"first",
|
| 80 |
+
"scene_audience":"first",
|
| 81 |
+
"country":"first",
|
| 82 |
+
"asset_youtube_url":"first"}
|
| 83 |
+
grouped = df.groupby("campaign_id", dropna=False).agg(agg).reset_index()
|
| 84 |
+
grouped["CCR_mean"] = grouped["CCR_rater"]
|
| 85 |
+
grouped.to_csv(RESULTS_CSV, index=False)
|
| 86 |
+
return grouped
|
| 87 |
+
|
| 88 |
+
def live_ccr_preview(scores: dict, weights: dict) -> float:
|
| 89 |
+
total = 0.0
|
| 90 |
+
for d,w in weights.items():
|
| 91 |
+
s100 = (scores.get(d, 3.0) - 1.0)/4.0*100.0
|
| 92 |
+
total += w * s100
|
| 93 |
+
return max(0.0, min(100.0, total))
|
| 94 |
+
|
| 95 |
+
def next_campaign_id(df: pd.DataFrame) -> str:
|
| 96 |
+
if df.empty or "campaign_id" not in df.columns or df["campaign_id"].dropna().empty:
|
| 97 |
+
return "CMP001"
|
| 98 |
+
last = str(df["campaign_id"].dropna().iloc[-1])
|
| 99 |
+
m = re.match(r"([A-Za-z]*)(\d+)$", last)
|
| 100 |
+
if m:
|
| 101 |
+
prefix, num = m.group(1) or "CMP", m.group(2)
|
| 102 |
+
nxt = int(num) + 1
|
| 103 |
+
return f"{prefix}{nxt:03d}"
|
| 104 |
+
return f"CMP{len(df)+1:03d}"
|
| 105 |
+
|
| 106 |
+
# --------- Session State Defaults ---------
|
| 107 |
+
if "step" not in st.session_state:
|
| 108 |
+
st.session_state.step = "Campagne-info"
|
| 109 |
+
if "info" not in st.session_state:
|
| 110 |
+
df0 = load_ratings()
|
| 111 |
+
st.session_state.info = {
|
| 112 |
+
"campaign_id": next_campaign_id(df0),
|
| 113 |
+
"campaign_name": "",
|
| 114 |
+
"brand": "",
|
| 115 |
+
"channel": CHANNEL_OPTIONS[0],
|
| 116 |
+
"scene_audience_choice": AUDIENCE_OPTIONS[0],
|
| 117 |
+
"scene_audience_custom": "",
|
| 118 |
+
"country": "BE",
|
| 119 |
+
"submit_date_iso": str(date.today()),
|
| 120 |
+
"asset_youtube_url": "",
|
| 121 |
+
"rater_id": "Lode",
|
| 122 |
+
"rater_notes": "",
|
| 123 |
+
}
|
| 124 |
+
if "scores" not in st.session_state:
|
| 125 |
+
st.session_state.scores = {d: 3.0 for d in DIMENSIONS}
|
| 126 |
+
if "risks" not in st.session_state:
|
| 127 |
+
st.session_state.risks = {"flag_stereotype":0,"flag_misappropriation":0,"flag_sensitive_timing":0,"flag_other_risk":0,"neg_sentiment_ratio_estimate":0.0}
|
| 128 |
+
|
| 129 |
+
# --------- Header ---------
|
| 130 |
+
st.title("Culturally Creative & Relevant Rater")
|
| 131 |
+
|
| 132 |
+
# --------- Stepper (segmented control) ---------
|
| 133 |
+
try:
|
| 134 |
+
st.session_state.step = st.segmented_control(
|
| 135 |
+
"Stap",
|
| 136 |
+
options=["Campagne-info","Score","Output"],
|
| 137 |
+
default=st.session_state.step,
|
| 138 |
+
)
|
| 139 |
+
except Exception:
|
| 140 |
+
# fallback to radio if segmented_control not available
|
| 141 |
+
st.session_state.step = st.radio("Stap", ["Campagne-info","Score","Output"], index=["Campagne-info","Score","Output"].index(st.session_state.step), horizontal=True)
|
| 142 |
+
|
| 143 |
+
# --------- RENDER: Campagne-info ---------
|
| 144 |
+
if st.session_state.step == "Campagne-info":
|
| 145 |
+
st.subheader("Campagne-info")
|
| 146 |
+
c_left, c_right = st.columns(2)
|
| 147 |
+
with c_left:
|
| 148 |
+
st.session_state.info["campaign_id"] = st.text_input("Campaign ID *", value=st.session_state.info["campaign_id"])
|
| 149 |
+
bn1, bn2 = st.columns(2)
|
| 150 |
+
with bn1:
|
| 151 |
+
st.session_state.info["brand"] = st.text_input("Brand", value=st.session_state.info["brand"])
|
| 152 |
+
with bn2:
|
| 153 |
+
st.session_state.info["campaign_name"] = st.text_input("Naam", value=st.session_state.info["campaign_name"])
|
| 154 |
+
st.session_state.info["channel"] = st.selectbox("Channel", CHANNEL_OPTIONS, index=CHANNEL_OPTIONS.index(st.session_state.info["channel"]) if st.session_state.info["channel"] in CHANNEL_OPTIONS else 0)
|
| 155 |
+
with c_right:
|
| 156 |
+
st.session_state.info["scene_audience_choice"] = st.selectbox("Scene / Audience", AUDIENCE_OPTIONS, index=AUDIENCE_OPTIONS.index(st.session_state.info["scene_audience_choice"]) if st.session_state.info["scene_audience_choice"] in AUDIENCE_OPTIONS else 0)
|
| 157 |
+
if st.session_state.info["scene_audience_choice"] == "Other...":
|
| 158 |
+
st.session_state.info["scene_audience_custom"] = st.text_input("Custom audience", value=st.session_state.info["scene_audience_custom"])
|
| 159 |
+
st.session_state.info["country"] = st.text_input("Country", value=st.session_state.info["country"])
|
| 160 |
+
st.session_state.info["submit_date_iso"] = st.text_input("Date (YYYY-MM-DD)", value=st.session_state.info["submit_date_iso"])
|
| 161 |
+
st.session_state.info["rater_id"] = st.selectbox("Rater", ["Lode","Maarten"], index=["Lode","Maarten"].index(st.session_state.info["rater_id"]) if st.session_state.info["rater_id"] in ["Lode","Maarten"] else 0)
|
| 162 |
+
st.session_state.info["asset_youtube_url"] = st.text_input("YouTube URL (optioneel)", value=st.session_state.info["asset_youtube_url"], placeholder="https://www.youtube.com/watch?v=...")
|
| 163 |
+
st.session_state.info["rater_notes"] = st.text_area("Rater notes", value=st.session_state.info["rater_notes"], height=90, placeholder="Kernobservaties, insider cues, etc.")
|
| 164 |
+
|
| 165 |
+
if st.button("Volgende →", type="primary"):
|
| 166 |
+
st.session_state.step = "Score"
|
| 167 |
+
st.rerun()
|
| 168 |
+
|
| 169 |
+
# --------- RENDER: Score ---------
|
| 170 |
+
elif st.session_state.step == "Score":
|
| 171 |
+
st.subheader("Score")
|
| 172 |
+
DESCRIPTIONS = {
|
| 173 |
+
"CR_cultural_resonance": {"title":"Cultural Resonance", "desc":"Raakt de campagne de cultuur/scene van de doelgroep? Insider cues, taal, symbolen."},
|
| 174 |
+
"OR_originality": {"title":"Originality", "desc":"Is het concept verrassend en vernieuwend vs. wat al bestaat?"},
|
| 175 |
+
"TI_timeliness": {"title":"Timeliness", "desc":"Sluit dit aan bij het momentum: trends, events, seizoen?"},
|
| 176 |
+
"IE_inclusivity_ethics": {"title":"Inclusivity & Ethics", "desc":"Respectvol en inclusief, zonder stereotypes of toe-eigening?"},
|
| 177 |
+
"SH_shareability": {"title":"Shareability", "desc":"Hoe deelbaar is het? Hook, quotables, remixedbaarheid."},
|
| 178 |
+
"BF_brand_channel_fit": {"title":"Brand & Channel Fit", "desc":"Matcht met merkcodes en benut het kanaal optimaal?"},
|
| 179 |
+
"CQ_craft_quality": {"title":"Craft Quality", "desc":"Sterke uitvoering: beeld/copy/sound/edit/montage."},
|
| 180 |
+
}
|
| 181 |
+
left, right = st.columns([1.6, 1])
|
| 182 |
+
with left:
|
| 183 |
+
for d in DIMENSIONS:
|
| 184 |
+
st.markdown(f"**{DESCRIPTIONS[d]['title']}**")
|
| 185 |
+
st.caption(DESCRIPTIONS[d]['desc'])
|
| 186 |
+
st.session_state.scores[d] = st.slider("", 1.0, 5.0, st.session_state.scores[d], 0.5, key=f"score_{d}")
|
| 187 |
+
r1, r2, r3, r4 = st.columns(4)
|
| 188 |
+
with r1:
|
| 189 |
+
st.session_state.risks["flag_stereotype"] = int(st.checkbox("Stereotype", value=bool(st.session_state.risks["flag_stereotype"])))
|
| 190 |
+
with r2:
|
| 191 |
+
st.session_state.risks["flag_misappropriation"] = int(st.checkbox("Misappropriation", value=bool(st.session_state.risks["flag_misappropriation"])))
|
| 192 |
+
with r3:
|
| 193 |
+
st.session_state.risks["flag_sensitive_timing"] = int(st.checkbox("Sensitive timing", value=bool(st.session_state.risks["flag_sensitive_timing"])))
|
| 194 |
+
with r4:
|
| 195 |
+
st.session_state.risks["flag_other_risk"] = int(st.checkbox("Other risk", value=bool(st.session_state.risks["flag_other_risk"])))
|
| 196 |
+
st.session_state.risks["neg_sentiment_ratio_estimate"] = st.slider("Neg sentiment ratio", 0.0, 1.0, float(st.session_state.risks["neg_sentiment_ratio_estimate"]), 0.01)
|
| 197 |
+
with right:
|
| 198 |
+
live_ccr = live_ccr_preview(st.session_state.scores, DEFAULT_WEIGHTS)
|
| 199 |
+
st.subheader("📊 Live Score")
|
| 200 |
+
st.markdown(f"<div style='font-size:72px;font-weight:800;line-height:1;'> {live_ccr:.0f}% </div>", unsafe_allow_html=True)
|
| 201 |
+
st.caption("CCR – gewogen (default weights)")
|
| 202 |
+
if st.session_state.info["asset_youtube_url"]:
|
| 203 |
+
st.markdown("---")
|
| 204 |
+
st.caption("YouTube preview")
|
| 205 |
+
st.video(st.session_state.info["asset_youtube_url"])
|
| 206 |
+
|
| 207 |
+
if st.button("Save rating now", type="primary"):
|
| 208 |
+
info = st.session_state.info
|
| 209 |
+
scene_audience = info["scene_audience_custom"] if info["scene_audience_choice"] == "Other..." else info["scene_audience_choice"]
|
| 210 |
+
if not info["campaign_id"].strip():
|
| 211 |
+
st.error("Campaign ID is verplicht.")
|
| 212 |
+
else:
|
| 213 |
+
row = {
|
| 214 |
+
"campaign_id": info["campaign_id"].strip(),
|
| 215 |
+
"campaign_name": info["campaign_name"].strip(),
|
| 216 |
+
"brand": info["brand"].strip(),
|
| 217 |
+
"channel": info["channel"],
|
| 218 |
+
"scene_audience": scene_audience.strip(),
|
| 219 |
+
"country": info["country"].strip(),
|
| 220 |
+
"submit_date_iso": info["submit_date_iso"].strip(),
|
| 221 |
+
"asset_youtube_url": info["asset_youtube_url"].strip(),
|
| 222 |
+
"rater_id": info["rater_id"],
|
| 223 |
+
"rater_notes": info["rater_notes"],
|
| 224 |
+
**st.session_state.scores,
|
| 225 |
+
**st.session_state.risks,
|
| 226 |
+
}
|
| 227 |
+
save_rating(row)
|
| 228 |
+
# increment campaign id for next entry
|
| 229 |
+
df_after = load_ratings()
|
| 230 |
+
st.session_state.info["campaign_id"] = next_campaign_id(df_after)
|
| 231 |
+
st.success("Rating opgeslagen.")
|
| 232 |
+
# Navigate to Output
|
| 233 |
+
st.session_state.step = "Output"
|
| 234 |
+
st.rerun()
|
| 235 |
+
|
| 236 |
+
# --------- RENDER: Output ---------
|
| 237 |
+
else: # Output
|
| 238 |
+
st.subheader("Output")
|
| 239 |
+
st.markdown("**Dataset (alle ratings)**")
|
| 240 |
+
st.dataframe(load_ratings(), use_container_width=True)
|
| 241 |
+
st.markdown("---")
|
| 242 |
+
st.markdown("**Per-campagne resultaten**")
|
| 243 |
+
res = compute_results(DEFAULT_WEIGHTS)
|
| 244 |
+
if not res.empty:
|
| 245 |
+
st.dataframe(res, use_container_width=True)
|
| 246 |
+
st.download_button("Download CCR_results.csv", res.to_csv(index=False).encode("utf-8"),
|
| 247 |
+
file_name="CCR_results.csv", mime="text/csv")
|
| 248 |
+
else:
|
| 249 |
+
st.info("Nog geen resultaten – voeg eerst één of meer ratings toe.")
|
data/CCR_default_weights.json
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"CR_cultural_resonance": 0.22,
|
| 3 |
+
"OR_originality": 0.18,
|
| 4 |
+
"TI_timeliness": 0.12,
|
| 5 |
+
"IE_inclusivity_ethics": 0.1,
|
| 6 |
+
"SH_shareability": 0.15,
|
| 7 |
+
"BF_brand_channel_fit": 0.13,
|
| 8 |
+
"CQ_craft_quality": 0.1
|
| 9 |
+
}
|
data/CCR_demo_ratings.csv
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
campaign_id,campaign_name,brand,channel,scene_audience,country,submit_date_iso,rater_id,rater_notes,asset_youtube_url,CR_cultural_resonance,OR_originality,TI_timeliness,IE_inclusivity_ethics,SH_shareability,BF_brand_channel_fit,CQ_craft_quality,flag_stereotype,flag_misappropriation,flag_sensitive_timing,flag_other_risk,neg_sentiment_ratio_estimate
|
| 2 |
+
CMP001,Street Sparks 15s,Volt,TikTok,BE urban 16-24,BE,2025-09-01,Lode,"Sterke insider cues, sound is trending.",https://www.youtube.com/watch?v=dQw4w9WgXcQ,4.5,4.0,5.0,4.5,4.0,4.5,4.0,0,0,0,0,0.05
|
| 3 |
+
CMP002,Heritage Remix OOH,Aurora,OOH,EU mainstream 25-44,NL,2025-08-15,Maarten,"Craft top, maar appropriation-risico.",,3.0,3.0,3.0,2.5,2.0,3.0,4.5,0,1,0,0,0.28
|
data/CCR_ratings.csv
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
|
|
|
|
|
|
|
| 1 |
+
campaign_id,rater_id,rater_notes,campaign_name,brand,channel,scene_audience,country,submit_date_iso,asset_youtube_url,CR_cultural_resonance,OR_originality,TI_timeliness,IE_inclusivity_ethics,SH_shareability,BF_brand_channel_fit,CQ_craft_quality,flag_stereotype,flag_misappropriation,flag_sensitive_timing,flag_other_risk,neg_sentiment_ratio_estimate
|
| 2 |
+
CMP001,Lode,,,,TikTok,BE urban 16-24,BE,2025-09-29,,3.0,3.0,3.0,3.0,3.0,3.0,3.0,0,0,0,0,0.0
|
data/CCR_results.csv
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
|
|
|
|
|
|
|
| 1 |
+
campaign_id,CR_cultural_resonance,OR_originality,TI_timeliness,IE_inclusivity_ethics,SH_shareability,BF_brand_channel_fit,CQ_craft_quality,CR_cultural_resonance_100,OR_originality_100,TI_timeliness_100,IE_inclusivity_ethics_100,SH_shareability_100,BF_brand_channel_fit_100,CQ_craft_quality_100,flag_stereotype,flag_misappropriation,flag_sensitive_timing,flag_other_risk,neg_sentiment_ratio_estimate,CCR_rater,campaign_name,brand,channel,scene_audience,country,asset_youtube_url,CCR_mean
|
| 2 |
+
CMP001,3.0,3.0,3.0,3.0,3.0,3.0,3.0,50.0,50.0,50.0,50.0,50.0,50.0,50.0,0.0,0.0,0.0,0.0,0.0,50.0,,,TikTok,BE urban 16-24,BE,,50.0
|
data/CCR_rubric_template.csv
ADDED
|
@@ -0,0 +1 @@
|
|
|
|
|
|
|
| 1 |
+
campaign_id,campaign_name,brand,channel,scene_audience,country,submit_date_iso,rater_id,rater_notes,asset_youtube_url,CR_cultural_resonance,OR_originality,TI_timeliness,IE_inclusivity_ethics,SH_shareability,BF_brand_channel_fit,CQ_craft_quality,flag_stereotype,flag_misappropriation,flag_sensitive_timing,flag_other_risk,neg_sentiment_ratio_estimate
|