gg
Deploy Iddaai Frontend / build-and-deploy (push) Successful in 2m36s

This commit is contained in:
2026-06-01 01:09:04 +03:00
parent 5df5145104
commit 9540ff9d2e
4 changed files with 47 additions and 15 deletions
@@ -373,6 +373,7 @@ export default function DashboardContent() {
borderRadius="full"
>
{Math.round(
pred.main_pick.unified_score ??
pred.main_pick.calibrated_confidence ??
pred.main_pick.confidence,
)}
+37 -13
View File
@@ -643,7 +643,7 @@ function PickCard({
<SimpleGrid columns={2} gap={3} minW={{ base: "full", md: "320px" }}>
<MetricTile
label={labels.confidence}
value={formatPercent(pick.calibrated_confidence, 0)}
value={formatPercent(pick.unified_score ?? pick.calibrated_confidence, 0)}
/>
<MetricTile label={labels.odds} value={formatOdds(pick.odds)} />
<MetricTile
@@ -742,7 +742,7 @@ function SummaryTable({
right.signal_tier || "PASS",
);
if (leftIndex !== rightIndex) return leftIndex - rightIndex;
return right.calibrated_confidence - left.calibrated_confidence;
return (right.unified_score ?? right.calibrated_confidence) - (left.unified_score ?? left.calibrated_confidence);
})
.map((item) => (
<Flex
@@ -778,6 +778,13 @@ function SummaryTable({
</HStack>
<HStack gap={5} fontSize="sm">
<Text minW="48px">{formatOdds(item.odds)}</Text>
<Text minW="64px" color="fg.muted">
{formatPercent(
(item.model_probability ?? 0) * 100,
0,
)}{" "}
{getUiText(ui, "probability-short", "olasılık")}
</Text>
<Text
minW="96px"
color={`${getEdgePalette(item.ev_edge)}.500`}
@@ -786,7 +793,7 @@ function SummaryTable({
{formatEdgeSignal(item.ev_edge)}
</Text>
<Text minW="48px">
{formatPercent(item.calibrated_confidence, 0)}
{formatPercent(item.unified_score ?? item.calibrated_confidence, 0)}
</Text>
<Badge
colorPalette={getConfidenceBandPalette(
@@ -881,9 +888,18 @@ function MarketBoardSection({
if (!marketBoard || !Object.keys(marketBoard).length) return null;
// Key by market:pick so each card resolves the summary row for the EXACT
// outcome it displays (graph pick). Keying by market alone collided on
// multi-row markets (MS 1/X/2) and surfaced the wrong odds + confidence.
const summaryByMarket = new Map(
(betSummary || []).map((item) => [item.market, item]),
(betSummary || []).map((item) => [`${item.market}:${item.pick}`, item]),
);
// Fallback: first row of a market, for cards whose pick has no exact row.
for (const item of betSummary || []) {
if (!summaryByMarket.has(item.market)) {
summaryByMarket.set(item.market, item);
}
}
const orderedEntries = Object.entries(marketBoard).sort(([left], [right]) => {
const leftIndex = MARKET_ORDER.indexOf(left);
const rightIndex = MARKET_ORDER.indexOf(right);
@@ -899,9 +915,18 @@ function MarketBoardSection({
<SimpleGrid columns={{ base: 1, xl: 2 }} gap={4}>
{orderedEntries.map(([market, entry]) => {
if (!entry?.probs) return null;
const summary = summaryByMarket.get(market);
const summary =
summaryByMarket.get(`${market}:${entry.pick}`) ??
summaryByMarket.get(market);
const interval =
summary?.confidence_interval || entry.confidence_interval;
// Hit probability == the dominant (green) bar in the graph below,
// so the headline never contradicts the distribution it sits on.
const pickProbPct =
Math.max(
0,
...Object.values(entry.probs).map((p) => Number(p) || 0),
) * 100;
return (
<Box
key={market}
@@ -951,25 +976,25 @@ function MarketBoardSection({
variant="subtle"
borderRadius="full"
>
{entry.pick} ({formatPercent(entry.confidence, 0)})
{entry.pick} ({formatPercent(pickProbPct, 0)})
</Badge>
) : null}
</Flex>
<SimpleGrid columns={3} gap={2} mb={3}>
<MetricTile
label={getUiText(ui, "hit-probability", "Tutma Olasılığı")}
value={formatPercent(entry.confidence, 0)}
value={formatPercent(pickProbPct, 0)}
accent="green.500"
/>
<MetricTile
label={getUiText(
ui,
"calibrated-confidence",
"Kalibre Güven",
"unified-confidence",
"Güven Skoru",
)}
value={
summary
? formatPercent(summary.calibrated_confidence, 0)
? formatPercent(summary.unified_score ?? summary.calibrated_confidence, 0)
: "-"
}
accent={summary?.playable ? "green.500" : "orange.500"}
@@ -999,8 +1024,7 @@ function MarketBoardSection({
<Bar
value={probability * 100}
color={
entry.pick === outcome ||
entry.pick?.toUpperCase() === outcome.toUpperCase()
(Number(probability) || 0) * 100 >= pickProbPct - 1e-6
? "green.400"
: "blue.400"
}
@@ -1349,7 +1373,7 @@ export default function PredictionCard({ prediction }: PredictionCardProps) {
<MetricTile
label={uiText("confidence-label", "Güven")}
value={formatPercent(
recommendedPick.calibrated_confidence,
recommendedPick.unified_score ?? recommendedPick.calibrated_confidence,
0,
)}
/>
@@ -193,6 +193,7 @@ export default function PredictionsContent() {
color="primary.fg"
>
{Math.round(
pred.main_pick.unified_score ??
pred.main_pick.calibrated_confidence ??
pred.main_pick.confidence,
)}
+6
View File
@@ -90,6 +90,8 @@ export interface EngineBreakdownDto {
export type BetGrade = "A" | "B" | "C" | "PASS";
export type SignalTier = "CORE" | "VALUE" | "LEAN" | "LONGSHOT" | "PASS";
export type UnifiedScoreLabel = "very_reliable" | "reliable" | "moderate" | "low";
export interface MatchPickDto {
market: string;
pick: string;
@@ -98,6 +100,8 @@ export interface MatchPickDto {
odds: number;
raw_confidence: number;
calibrated_confidence: number;
unified_score?: number;
unified_score_label?: UnifiedScoreLabel;
min_required_confidence: number;
edge: number;
ev_edge: number;
@@ -158,6 +162,8 @@ export interface MatchBetSummaryItemDto {
pick: string;
raw_confidence: number;
calibrated_confidence: number;
unified_score?: number;
unified_score_label?: UnifiedScoreLabel;
bet_grade: BetGrade;
playable: boolean;
stake_units: number;