Compare commits
2 Commits
2fe60ab0cd
...
f29dbd0454
| Author | SHA1 | Date |
|---|---|---|
|
|
f29dbd0454 | |
|
|
9b35a759a9 |
|
|
@ -1,7 +1,14 @@
|
||||||
import type { Team } from "@/lib/types";
|
import type { Team } from "@/lib/types";
|
||||||
|
|
||||||
// 모든 경기에 일반화된 국기 렌더.
|
// 모든 국기를 직사각형 SVG로 통일 (flagcdn, 퍼블릭 도메인).
|
||||||
// KOR = 실제 png 자산, CZE = 인라인 SVG(비율 보존), 그 외 = 이모지(컨테이너 높이에 비례, 안 잘림).
|
// 이모지(OS별 휘날림/광택 렌더) 제거 → 일관된 사각형. object-cover로 박스를 꽉 채움(왜곡 없음).
|
||||||
|
const FLAG_FILE: Record<string, string> = {
|
||||||
|
KOR: "kr",
|
||||||
|
CZE: "cz",
|
||||||
|
MEX: "mx",
|
||||||
|
RSA: "za",
|
||||||
|
};
|
||||||
|
|
||||||
export default function TeamFlag({
|
export default function TeamFlag({
|
||||||
team,
|
team,
|
||||||
className = "",
|
className = "",
|
||||||
|
|
@ -9,30 +16,17 @@ export default function TeamFlag({
|
||||||
team: Team;
|
team: Team;
|
||||||
className?: string;
|
className?: string;
|
||||||
}) {
|
}) {
|
||||||
if (team.code === "KOR") {
|
const file = FLAG_FILE[team.code];
|
||||||
|
if (file) {
|
||||||
return (
|
return (
|
||||||
<img
|
<img
|
||||||
src="/icons/kor.png"
|
src={`/icons/flags/${file}.svg`}
|
||||||
alt={team.name}
|
alt={team.name}
|
||||||
className={`flag-img object-cover ${className}`}
|
className={`border border-[var(--line-d)] object-cover ${className}`}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if (team.code === "CZE") {
|
// 미등록 국가 fallback — 이모지(직사각형 박스, 잘림 없음)
|
||||||
return (
|
|
||||||
<svg
|
|
||||||
viewBox="0 0 6 4"
|
|
||||||
className={`border border-[var(--line-d)] ${className}`}
|
|
||||||
preserveAspectRatio="xMidYMid meet"
|
|
||||||
aria-label={team.name}
|
|
||||||
>
|
|
||||||
<rect width="6" height="2" y="0" fill="#ffffff" />
|
|
||||||
<rect width="6" height="2" y="2" fill="#d7141a" />
|
|
||||||
<polygon points="0,0 3,2 0,4" fill="#11457e" />
|
|
||||||
</svg>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
// 그 외 국가 — 이모지 국기. 컨테이너 높이(cqh) 기준으로 크기를 잡아 잘림/찌그러짐 방지.
|
|
||||||
return (
|
return (
|
||||||
<span
|
<span
|
||||||
className={`grid place-items-center overflow-hidden border border-[var(--line-d)] bg-white/[0.06] ${className}`}
|
className={`grid place-items-center overflow-hidden border border-[var(--line-d)] bg-white/[0.06] ${className}`}
|
||||||
|
|
|
||||||
|
|
@ -155,6 +155,50 @@ function generatePredictions(match: Match, lang: Lang): AIPrediction[] {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 나머지 5경기 — 실제 3모델 API 출력 (2026-06-10, gpt-5.5 / gemini-3.5-flash / claude-opus-4-8 직접)
|
||||||
|
// scoreA=teamA(앞 팀), scoreB=teamB(뒤 팀). outcome: TEAM_A_WIN / DRAW / TEAM_B_WIN.
|
||||||
|
type Curated = {
|
||||||
|
model: ModelName;
|
||||||
|
outcome: Outcome;
|
||||||
|
scoreA: number;
|
||||||
|
scoreB: number;
|
||||||
|
confidencePct: number;
|
||||||
|
ko: string;
|
||||||
|
en: string;
|
||||||
|
};
|
||||||
|
const CURATED: Record<string, Curated[]> = {
|
||||||
|
// 개막전 — 멕시코 vs 남아공
|
||||||
|
A_MEX_RSA_20260612: [
|
||||||
|
{ model: "GPT", outcome: "TEAM_A_WIN", scoreA: 2, scoreB: 1, confidencePct: 62, ko: "멕시코 전력 우위, 남아공 수비 불안", en: "Mexico's edge vs a shaky South Africa defense" },
|
||||||
|
{ model: "Claude", outcome: "TEAM_A_WIN", scoreA: 2, scoreB: 0, confidencePct: 64, ko: "개최국 멕시코의 홈 압박과 측면 우위", en: "Host Mexico's home press and wing edge" },
|
||||||
|
{ model: "Gemini", outcome: "TEAM_A_WIN", scoreA: 2, scoreB: 0, confidencePct: 75, ko: "멕시코의 홈 이점과 객관적 전력 우세", en: "Mexico's home advantage and clear quality" },
|
||||||
|
],
|
||||||
|
// 체코 vs 남아공
|
||||||
|
A_CZE_RSA_20260619: [
|
||||||
|
{ model: "GPT", outcome: "TEAM_A_WIN", scoreA: 1, scoreB: 0, confidencePct: 56, ko: "체코의 조직력·결정력이 근소 우위", en: "Czechia's structure & finishing just edge it" },
|
||||||
|
{ model: "Claude", outcome: "TEAM_A_WIN", scoreA: 2, scoreB: 0, confidencePct: 60, ko: "체코의 세트피스와 피지컬 우위", en: "Czechia's set pieces and physicality" },
|
||||||
|
{ model: "Gemini", outcome: "TEAM_A_WIN", scoreA: 2, scoreB: 1, confidencePct: 65, ko: "체코의 전력 우세와 골 결정력 차이", en: "Czechia's quality and finishing decide it" },
|
||||||
|
],
|
||||||
|
// 멕시코 vs 한국 — 모델 갈림
|
||||||
|
A_MEX_KOR_20260619: [
|
||||||
|
{ model: "GPT", outcome: "TEAM_A_WIN", scoreA: 2, scoreB: 1, confidencePct: 55, ko: "홈 압박으로 멕시코가 한 골 차 우세", en: "Home press gives Mexico a one-goal edge" },
|
||||||
|
{ model: "Claude", outcome: "DRAW", scoreA: 1, scoreB: 1, confidencePct: 50, ko: "홈의 멕시코, 역습의 한국 — 균형", en: "Mexico's press vs Korea's counters — even" },
|
||||||
|
{ model: "Gemini", outcome: "DRAW", scoreA: 1, scoreB: 1, confidencePct: 65, ko: "홈 멕시코와 한국 유럽파의 접전 무승부", en: "Home Mexico vs Korea's Europe stars — a draw" },
|
||||||
|
],
|
||||||
|
// 체코 vs 멕시코
|
||||||
|
A_CZE_MEX_20260625: [
|
||||||
|
{ model: "GPT", outcome: "TEAM_B_WIN", scoreA: 1, scoreB: 2, confidencePct: 58, ko: "멕시코의 홈 이점과 공격력 우세", en: "Mexico's home edge and attack prevail" },
|
||||||
|
{ model: "Claude", outcome: "TEAM_B_WIN", scoreA: 1, scoreB: 2, confidencePct: 57, ko: "멕시코의 템포와 개인기가 체코를 넘는다", en: "Mexico's tempo and flair edge Czechia" },
|
||||||
|
{ model: "Gemini", outcome: "TEAM_B_WIN", scoreA: 1, scoreB: 2, confidencePct: 60, ko: "멕시코의 경험이 승리를 견인", en: "Mexico's experience drives the win" },
|
||||||
|
],
|
||||||
|
// 남아공 vs 한국 — 16강 길목
|
||||||
|
A_RSA_KOR_20260625: [
|
||||||
|
{ model: "GPT", outcome: "TEAM_B_WIN", scoreA: 1, scoreB: 2, confidencePct: 58, ko: "한국의 전방 결정력과 큰 무대 경험 우세", en: "Korea's finishing and big-stage edge" },
|
||||||
|
{ model: "Claude", outcome: "TEAM_B_WIN", scoreA: 1, scoreB: 2, confidencePct: 62, ko: "16강 길목, 한국의 화력이 남아공을 압도", en: "With the last-16 on the line, Korea's firepower tells" },
|
||||||
|
{ model: "Gemini", outcome: "TEAM_B_WIN", scoreA: 1, scoreB: 2, confidencePct: 75, ko: "스쿼드 전력 우세한 한국이 경기 주도", en: "Korea's stronger squad dictates the game" },
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
export function getPredictions(match: Match, lang: Lang = "ko"): AIPrediction[] {
|
export function getPredictions(match: Match, lang: Lang = "ko"): AIPrediction[] {
|
||||||
if (match.matchId === FEATURED.matchId) {
|
if (match.matchId === FEATURED.matchId) {
|
||||||
return FEATURED_PREDICTIONS.map((p) => ({
|
return FEATURED_PREDICTIONS.map((p) => ({
|
||||||
|
|
@ -162,6 +206,19 @@ export function getPredictions(match: Match, lang: Lang = "ko"): AIPrediction[]
|
||||||
reasonShort: FEATURED_REASONS[lang][p.model],
|
reasonShort: FEATURED_REASONS[lang][p.model],
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
const cur = CURATED[match.matchId];
|
||||||
|
if (cur) {
|
||||||
|
return cur.map((c) => ({
|
||||||
|
matchId: match.matchId,
|
||||||
|
model: c.model,
|
||||||
|
outcome: c.outcome,
|
||||||
|
scoreA: c.scoreA,
|
||||||
|
scoreB: c.scoreB,
|
||||||
|
confidencePct: c.confidencePct,
|
||||||
|
reasonShort: lang === "en" ? c.en : c.ko,
|
||||||
|
generatedAt: "2026-06-10",
|
||||||
|
}));
|
||||||
|
}
|
||||||
return generatePredictions(match, lang);
|
return generatePredictions(match, lang);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
<svg version="1.0" xmlns="http://www.w3.org/2000/svg" width="900" height="600"><path fill="#d7141a" d="M0 0h900v600H0z"/><path fill="#fff" d="M0 0h900v300H0z"/><path d="M450 300 0 0v600z" fill="#11457e"/></svg>
|
||||||
|
After Width: | Height: | Size: 210 B |
|
|
@ -0,0 +1 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="900" height="600" viewBox="-72 -48 144 96"><path fill="#fff" d="M-72-48v96H72v-96z"/><g stroke="#000" stroke-width="4"><path d="M-34.946-37.72-48.26-17.75m4.992 3.328 13.313-19.97m4.992 3.329-13.312 19.969m63.236 42.157 6.101-9.152m1.11-1.664 6.101-9.153m4.993 3.328-6.102 9.153m-1.11 1.664-6.101 9.152m4.992 3.329 6.102-9.153m1.11-1.664 6.1-9.153M-48.259 17.75l13.313 19.97m4.992-3.329-6.102-9.152m-1.109-1.664-6.102-9.153m4.993-3.328 13.312 19.97m63.236-42.158-6.101-9.153m-1.11-1.664-6.101-9.152m4.992-3.328 13.313 19.969m4.992-3.328-6.102-9.153m-1.11-1.664-6.1-9.153"/></g><path fill="#cd2e3a" d="M9.985 6.656A18 18 0 1 1-19.97-13.313a24 24 0 1 1 39.938 26.626"/><path fill="#0047a0" d="M0 0a12 12 0 1 1 19.97 13.313 24 24 0 1 1-39.94-26.626A12 12 0 1 0 0 0"/></svg>
|
||||||
|
After Width: | Height: | Size: 817 B |
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 140 KiB |
|
|
@ -0,0 +1 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="900" height="600" viewBox="0 0 90 60"><defs><clipPath id="b"><path d="m0 0 45 30L0 60z"/></clipPath><clipPath id="a"><path d="M0 0h90v60H0z"/></clipPath></defs><path fill="#E03C31" d="M0 0h90v30H45z"/><path fill="#001489" d="M0 60h90V30H45z"/><g fill="none" clip-path="url(#a)"><path stroke="#FFF" stroke-width="20" d="M90 30H45L0 0v60l45-30"/><path fill="#000" stroke="#ffb81c" stroke-width="20" d="m0 0 45 30L0 60" clip-path="url(#b)"/><path stroke="#007749" stroke-width="12" d="m0 0 45 30h45M0 60l45-30"/></g></svg>
|
||||||
|
After Width: | Height: | Size: 566 B |
Loading…
Reference in New Issue