Rthur2003 commited on
Commit
f4a412c
·
1 Parent(s): 8211829

feat: analysis jobs timeline scanning inference xai ve corresponding tests eklendi

Browse files
Files changed (1) hide show
  1. app/routes/analyze_schemas.py +57 -0
app/routes/analyze_schemas.py CHANGED
@@ -126,6 +126,61 @@ class MetaClassifierExplanation(BaseModel):
126
  topFeatures: List[MetaFeatureImportance] = Field(default_factory=list)
127
 
128
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
129
  class AnalysisResult(BaseModel):
130
  """Platform/hooks/analysisTypes.ts uyumlu."""
131
 
@@ -142,6 +197,8 @@ class AnalysisResult(BaseModel):
142
  xai: Optional[XAIExplanation] = None
143
  towerScores: Dict[str, float] = Field(default_factory=dict)
144
  metaClassifier: Optional[MetaClassifierExplanation] = None
 
 
145
  # Per-layer status: which model actually ran and how (e.g. CLAP embedding
146
  # vs. its spectral heuristic fallback), so the UI can label each score.
147
  layers: Dict[str, Dict[str, Any]] = Field(default_factory=dict)
 
126
  topFeatures: List[MetaFeatureImportance] = Field(default_factory=list)
127
 
128
 
129
+ class SegmentReason(BaseModel):
130
+ """One feature that pushed a window's score, from SHAP."""
131
+
132
+ name: str
133
+ label: str
134
+ labelEn: str
135
+ direction: Literal["towards_ai", "towards_human"]
136
+ shapValue: float
137
+
138
+
139
+ class TimelineSegment(BaseModel):
140
+ """One window of the whole-track scan. Only `ok` windows carry a score."""
141
+
142
+ index: int
143
+ start: float
144
+ end: float
145
+ state: Literal["ok", "silent", "skipped", "failed"] = "ok"
146
+ probability: Optional[float] = None
147
+ isAi: Optional[bool] = None
148
+ # 0 at the decision threshold, 1 at the far end of the window's side.
149
+ margin: Optional[float] = None
150
+ hasVocals: Optional[bool] = None
151
+ reasons: List[SegmentReason] = Field(default_factory=list)
152
+
153
+
154
+ class TimelineSummary(BaseModel):
155
+ scoredCount: int = 0
156
+ flaggedCount: int = 0
157
+ scoredSec: float = 0.0
158
+ # Share of the scored time whose windows lean AI.
159
+ aiShare: float = 0.0
160
+ meanProbability: float = 0.0
161
+ maxProbability: float = 0.0
162
+ peakIndex: Optional[int] = None
163
+
164
+
165
+ class Timeline(BaseModel):
166
+ """The track read window by window with the primary classifier.
167
+
168
+ Window scores come from a model trained on 60 s clips that were wholly AI
169
+ or wholly human, so they show where the music reads AI-like rather than
170
+ proving where an AI was used.
171
+ """
172
+
173
+ # Seconds the scan covered (at most the first six minutes) and the full track length.
174
+ durationSec: float
175
+ totalSec: float
176
+ truncated: bool = False
177
+ threshold: float
178
+ # Peak level per slice of the covered part, 0 to 1, for drawing the waveform.
179
+ peaks: List[float] = Field(default_factory=list)
180
+ segments: List[TimelineSegment] = Field(default_factory=list)
181
+ summary: TimelineSummary = Field(default_factory=TimelineSummary)
182
+
183
+
184
  class AnalysisResult(BaseModel):
185
  """Platform/hooks/analysisTypes.ts uyumlu."""
186
 
 
197
  xai: Optional[XAIExplanation] = None
198
  towerScores: Dict[str, float] = Field(default_factory=dict)
199
  metaClassifier: Optional[MetaClassifierExplanation] = None
200
+ # Whole-track scan; absent when the classifier or the decode was unavailable.
201
+ timeline: Optional[Timeline] = None
202
  # Per-layer status: which model actually ran and how (e.g. CLAP embedding
203
  # vs. its spectral heuristic fallback), so the UI can label each score.
204
  layers: Dict[str, Dict[str, Any]] = Field(default_factory=dict)