This commit is contained in:
@@ -373,7 +373,8 @@ export default function DashboardContent() {
|
||||
borderRadius="full"
|
||||
>
|
||||
{Math.round(
|
||||
pred.main_pick.calibrated_confidence ??
|
||||
pred.main_pick.unified_score ??
|
||||
pred.main_pick.calibrated_confidence ??
|
||||
pred.main_pick.confidence,
|
||||
)}
|
||||
%
|
||||
|
||||
@@ -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,7 +193,8 @@ export default function PredictionsContent() {
|
||||
color="primary.fg"
|
||||
>
|
||||
{Math.round(
|
||||
pred.main_pick.calibrated_confidence ??
|
||||
pred.main_pick.unified_score ??
|
||||
pred.main_pick.calibrated_confidence ??
|
||||
pred.main_pick.confidence,
|
||||
)}
|
||||
%
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user