o2o-triple-pick/scripts/seed.mjs

59 lines
3.6 KiB
JavaScript

// Firestore 시드 스크립트 — matches / ai_predictions / crowd_stats 초기화
// 실행: GOOGLE_APPLICATION_CREDENTIALS=./serviceAccount.json node scripts/seed.mjs
// ⚠️ AI 예측은 플레이스홀더. 발행 전 실제 GPT/Claude/Gemini 출력으로 교체.
// (경기 데이터는 lib/schedule.ts 와 동일하게 유지할 것 — 여기서는 JS로 인라인)
import { initializeApp, cert, applicationDefault } from "firebase-admin/app";
import { getFirestore, FieldValue } from "firebase-admin/firestore";
initializeApp({ credential: applicationDefault() });
const db = getFirestore();
const lock = (iso) => new Date(new Date(iso).getTime() - 10 * 60000).toISOString();
const T = {
KOR: { name: "Korea Republic", shortName: "한국", code: "KOR", flag: "🇰🇷" },
CZE: { name: "Czechia", shortName: "체코", code: "CZE", flag: "🇨🇿" },
MEX: { name: "Mexico", shortName: "멕시코", code: "MEX", flag: "🇲🇽" },
RSA: { name: "South Africa", shortName: "남아공", code: "RSA", flag: "🇿🇦" },
};
const MATCHES = [
["A_MEX_RSA_20260612", "Match 01 · 개막전", T.MEX, T.RSA, "2026-06-12T04:00:00+09:00", "Estadio Azteca · Mexico City", "월드컵 개막전, AI는 개최국을 믿을까"],
["A_KOR_CZE_20260612", "Match 01", T.KOR, T.CZE, "2026-06-12T11:00:00+09:00", "Estadio Guadalajara (Akron)", "한국 첫 경기, AI의 선택은 갈렸다"],
["A_CZE_RSA_20260619", "Match 02", T.CZE, T.RSA, "2026-06-19T01:00:00+09:00", "USA (TBD)", "체코 vs 남아공, AI의 예측은"],
["A_MEX_KOR_20260619", "Match 02", T.MEX, T.KOR, "2026-06-19T10:00:00+09:00", "Estadio Guadalajara (Akron)", "개최국 멕시코 vs 한국, AI는 누구 편"],
["A_CZE_MEX_20260625", "Match 03", T.CZE, T.MEX, "2026-06-25T10:00:00+09:00", "Estadio Azteca · Mexico City", "체코 vs 멕시코, 운명의 최종전"],
["A_RSA_KOR_20260625", "Match 03", T.RSA, T.KOR, "2026-06-25T10:00:00+09:00", "Estadio BBVA · Monterrey", "한국 16강의 갈림길, AI의 마지막 예측"],
];
// 한국 vs 체코 AI 예측 (플레이스홀더)
const AI = {
A_KOR_CZE_20260612: [
{ model: "GPT", outcome: "TEAM_A_WIN", scoreA: 2, scoreB: 1, confidencePct: 62, reasonShort: "한국의 측면 공격 우위와 세트피스 강점", generatedAt: "2026-06-08" },
{ model: "Claude", outcome: "DRAW", scoreA: 1, scoreB: 1, confidencePct: 41, reasonShort: "중원 밸런스가 팽팽한 접전 예상", generatedAt: "2026-06-08" },
{ model: "Gemini", outcome: "TEAM_B_WIN", scoreA: 0, scoreB: 2, confidencePct: 28, reasonShort: "체코의 전환 속도와 결정력 우세", generatedAt: "2026-06-08" },
],
};
async function run() {
const batch = db.batch();
for (const [matchId, round, a, b, kickoff, venue, hook] of MATCHES) {
batch.set(db.collection("matches").doc(matchId), {
matchId, roundLabel: round, group: "A", teamA: a, teamB: b,
kickoffKst: kickoff, venue, lockAt: lock(kickoff), status: "upcoming",
hookText: hook, result: null, updatedAt: FieldValue.serverTimestamp(),
});
// crowd_stats 초기화 (0)
batch.set(db.collection("crowd_stats").doc(matchId), {
matchId, total: 0, teamAWin: 0, draw: 0, teamBWin: 0, updatedAt: FieldValue.serverTimestamp(),
}, { merge: true });
}
for (const [matchId, preds] of Object.entries(AI)) {
for (const p of preds) {
batch.set(db.collection("ai_predictions").doc(`${matchId}_${p.model}`), { matchId, ...p });
}
}
await batch.commit();
console.log(`seeded: ${MATCHES.length} matches, ${Object.values(AI).flat().length} ai_predictions, crowd_stats init`);
}
run().catch((e) => { console.error(e); process.exit(1); });