File size: 3,394 Bytes
0cafa73
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
export type PredictionConfidence = 'HIGH' | 'MEDIUM' | 'LOW'
export type ReliabilityLevel = PredictionConfidence | 'PENDING' | 'UNKNOWN'

const confidenceRank: Record<PredictionConfidence, number> = {
  LOW: 0,
  MEDIUM: 1,
  HIGH: 2,
}

const confidenceByRank: Record<number, PredictionConfidence> = {
  0: 'LOW',
  1: 'MEDIUM',
  2: 'HIGH',
}

export const confidenceColor: Record<PredictionConfidence, string> = {
  HIGH: 'text-green-400',
  MEDIUM: 'text-yellow-400',
  LOW: 'text-red-400',
}

export const confidenceZh: Record<PredictionConfidence, string> = {
  HIGH: '高信心',
  MEDIUM: '中信心',
  LOW: '低信心',
}

const reliabilityColor: Record<ReliabilityLevel, string> = {
  HIGH: 'text-green-400',
  MEDIUM: 'text-yellow-400',
  LOW: 'text-red-400',
  PENDING: 'text-yellow-300',
  UNKNOWN: 'text-slate-300',
}

const reliabilityZh: Record<ReliabilityLevel, string> = {
  HIGH: '高可靠度',
  MEDIUM: '中可靠度',
  LOW: '低可靠度',
  PENDING: '計算中',
  UNKNOWN: '尚無',
}

export interface PredictionReliabilitySummary {
  level: ReliabilityLevel
  levelText: string
  levelColor: string
  confidenceText: string
  confidenceColor: string
  accuracyText: string
  accuracyColor: string
  hasModelAccuracy: boolean
  warning?: string
}

function clampConfidence(
  confidence: PredictionConfidence,
  maxConfidence: PredictionConfidence
): PredictionConfidence {
  const rank = Math.min(confidenceRank[confidence], confidenceRank[maxConfidence])
  return confidenceByRank[rank]
}

export function getPredictionReliabilitySummary({
  confidence,
  trainingAccuracy,
  isQuick = false,
}: {
  confidence: PredictionConfidence
  trainingAccuracy?: number | null
  isQuick?: boolean
}): PredictionReliabilitySummary {
  const hasModelAccuracy = !isQuick
    && Number.isFinite(trainingAccuracy)
    && Number(trainingAccuracy) > 0

  const accuracyText = hasModelAccuracy
    ? `${(Number(trainingAccuracy) * 100).toFixed(1)}%`
    : isQuick ? 'ML 計算中' : '尚無'

  const confidenceText = `${confidence} (${confidenceZh[confidence]})`

  if (!hasModelAccuracy) {
    const level: ReliabilityLevel = isQuick ? 'PENDING' : 'UNKNOWN'
    return {
      level,
      levelText: reliabilityZh[level],
      levelColor: reliabilityColor[level],
      confidenceText,
      confidenceColor: confidenceColor[confidence],
      accuracyText,
      accuracyColor: isQuick ? 'text-yellow-300' : 'text-slate-300',
      hasModelAccuracy,
    }
  }

  const accuracy = Number(trainingAccuracy)
  let level: PredictionConfidence = confidence
  let warning: string | undefined

  if (accuracy < 0.5) {
    level = 'LOW'
    warning = confidence === 'HIGH'
      ? '高信心但模型品質偏弱,請謹慎參考。'
      : '模型近期驗證準確率低於 50%,請謹慎參考。'
  } else if (accuracy < 0.6) {
    level = clampConfidence(confidence, 'MEDIUM')
    warning = confidence === 'HIGH'
      ? '模型近期驗證準確率未達 60%,高信心訊號降為中可靠度。'
      : undefined
  }

  return {
    level,
    levelText: `${level} (${reliabilityZh[level]})`,
    levelColor: reliabilityColor[level],
    confidenceText,
    confidenceColor: confidenceColor[confidence],
    accuracyText,
    accuracyColor: accuracy < 0.5 ? 'text-red-300' : accuracy < 0.6 ? 'text-yellow-300' : 'text-slate-200',
    hasModelAccuracy,
    warning,
  }
}