This commit is contained in:
@@ -1172,6 +1172,39 @@ export default function PredictionCard({ prediction }: PredictionCardProps) {
|
||||
const mainBandPalette = getConfidenceBandPalette(
|
||||
prediction.bet_advice.confidence_band,
|
||||
);
|
||||
|
||||
// ── Maç Sonucu Tahmini (model'in EN OLASI sonucu) ──────────────────
|
||||
// The value-bet hero below optimizes ROI (often a high-odds draw/underdog,
|
||||
// ~27% hit) which users misread as a "bad prediction". This block instead
|
||||
// shows what the model thinks will actually happen: the highest-probability
|
||||
// 1X2 outcome (~55% hit, on par with the market). Sourced from market_board.MS.
|
||||
const msBoard = prediction.market_board?.MS;
|
||||
const matchResultPrediction = (() => {
|
||||
const probs = msBoard?.probs;
|
||||
if (!probs) return null;
|
||||
const labelMap: Record<string, string> = {
|
||||
"1": prediction.match_info?.home_team || uiText("home", "Ev Sahibi"),
|
||||
X: uiText("draw", "Beraberlik"),
|
||||
"2": prediction.match_info?.away_team || uiText("away", "Deplasman"),
|
||||
};
|
||||
let bestKey = "";
|
||||
let bestProb = -1;
|
||||
for (const [k, v] of Object.entries(probs)) {
|
||||
const p = typeof v === "number" ? v : 0;
|
||||
if (p > bestProb) {
|
||||
bestProb = p;
|
||||
bestKey = k;
|
||||
}
|
||||
}
|
||||
if (!bestKey) return null;
|
||||
return {
|
||||
pick: bestKey,
|
||||
label: labelMap[bestKey] ?? bestKey,
|
||||
prob: bestProb,
|
||||
all: probs as Record<string, number>,
|
||||
};
|
||||
})();
|
||||
|
||||
const sport = getPredictionSport(prediction);
|
||||
const isBasketball = sport === "basketball";
|
||||
|
||||
@@ -1373,6 +1406,85 @@ export default function PredictionCard({ prediction }: PredictionCardProps) {
|
||||
</HStack>
|
||||
</Box>
|
||||
|
||||
{matchResultPrediction ? (
|
||||
<Box
|
||||
p={4}
|
||||
bg={statCardBg}
|
||||
borderWidth="1px"
|
||||
borderColor={borderColor}
|
||||
borderRadius="2xl"
|
||||
>
|
||||
<HStack justify="space-between" align="start" mb={3}>
|
||||
<VStack align="start" gap={1}>
|
||||
<Badge colorPalette="blue" variant="subtle" borderRadius="full">
|
||||
{uiText("match-result-prediction", "Maç Sonucu Tahmini")}
|
||||
</Badge>
|
||||
<Text fontSize="2xl" fontWeight="bold">
|
||||
{matchResultPrediction.label}
|
||||
</Text>
|
||||
<Text fontSize="sm" color="fg.muted">
|
||||
{uiText(
|
||||
"match-result-copy",
|
||||
"Modelin en olası gördüğü sonuç (kim kazanır).",
|
||||
)}
|
||||
</Text>
|
||||
</VStack>
|
||||
<VStack align="end" gap={0}>
|
||||
<Text fontSize="2xl" fontWeight="bold" color="blue.500">
|
||||
{formatPercent(matchResultPrediction.prob * 100, 0)}
|
||||
</Text>
|
||||
<Text fontSize="xs" color="fg.muted">
|
||||
{uiText("probability-short", "olasılık")}
|
||||
</Text>
|
||||
</VStack>
|
||||
</HStack>
|
||||
{/* 1X2 dağılımı */}
|
||||
<VStack align="stretch" gap={2}>
|
||||
{["1", "X", "2"].map((k) => {
|
||||
const p = matchResultPrediction.all[k] ?? 0;
|
||||
const lbl: Record<string, string> = {
|
||||
"1":
|
||||
prediction.match_info?.home_team ||
|
||||
uiText("home", "Ev Sahibi"),
|
||||
X: uiText("draw", "Beraberlik"),
|
||||
"2":
|
||||
prediction.match_info?.away_team ||
|
||||
uiText("away", "Deplasman"),
|
||||
};
|
||||
const isTop = k === matchResultPrediction.pick;
|
||||
return (
|
||||
<Box key={k}>
|
||||
<Flex justify="space-between" mb={1}>
|
||||
<Text
|
||||
fontSize="sm"
|
||||
fontWeight={isTop ? "semibold" : "normal"}
|
||||
color={isTop ? "blue.500" : "fg.muted"}
|
||||
>
|
||||
{lbl[k]}
|
||||
</Text>
|
||||
<Text fontSize="sm" fontWeight={isTop ? "semibold" : "normal"}>
|
||||
{formatPercent(p * 100, 0)}
|
||||
</Text>
|
||||
</Flex>
|
||||
<Bar
|
||||
value={p * 100}
|
||||
color={isTop ? "blue.400" : "gray.400"}
|
||||
trackBg={trackBgColor}
|
||||
height="6px"
|
||||
/>
|
||||
</Box>
|
||||
);
|
||||
})}
|
||||
</VStack>
|
||||
<Text fontSize="xs" color="fg.muted" mt={3}>
|
||||
{uiText(
|
||||
"match-result-vs-value",
|
||||
"Bu en olası sonuçtur. Aşağıdaki “Değerli Bahis” ise orana göre en kârlı görülen seçimdir — ikisi farklı olabilir.",
|
||||
)}
|
||||
</Text>
|
||||
</Box>
|
||||
) : null}
|
||||
|
||||
{recommendedPick ? (
|
||||
<Grid templateColumns={{ base: "1fr", xl: "1.4fr 1fr" }} gap={4}>
|
||||
<Box
|
||||
@@ -1389,7 +1501,7 @@ export default function PredictionCard({ prediction }: PredictionCardProps) {
|
||||
variant="solid"
|
||||
borderRadius="full"
|
||||
>
|
||||
{uiText("main-recommendation", "Öne Çıkan Sinyal")}
|
||||
{uiText("main-recommendation", "Değerli Bahis")}
|
||||
</Badge>
|
||||
<Text fontSize="2xl" fontWeight="bold">
|
||||
{recommendedPick.pick}
|
||||
|
||||
Reference in New Issue
Block a user