Rthur2003 commited on
Commit
063edcf
·
1 Parent(s): e6d2d3e

feat: unified analysis uç noktası ile desteği için YouTube ve file uploads eklendi

Browse files
Files changed (1) hide show
  1. app/routes/analyze.py +14 -133
app/routes/analyze.py CHANGED
@@ -19,13 +19,25 @@ import time
19
  import uuid
20
  from collections import defaultdict
21
  from concurrent.futures import ThreadPoolExecutor
22
- from typing import Optional, List, Dict, Any, Literal
23
  from fastapi import (
24
  APIRouter, File, UploadFile, Form,
25
  Request, Depends, HTTPException, status,
26
  )
27
- from pydantic import BaseModel, Field
28
 
 
 
 
 
 
 
 
 
 
 
 
 
 
29
  from ..services.youtube_analysis import YouTubeAnalysisService
30
  from ..services.preview_model import PreviewModel
31
  from ..services.feature_extractor import (
@@ -93,137 +105,6 @@ meta_classifier_service = MetaClassifierService()
93
  _analysis_pool = ThreadPoolExecutor(max_workers=3)
94
 
95
 
96
- # ============================================
97
- # Response Models - Platform Uyumlu
98
- # ============================================
99
-
100
- class VocalAnalysis(BaseModel):
101
- """Vocal analysis results for the response."""
102
-
103
- hasVocals: bool = False
104
- vocalConfidence: float = 0.0
105
- vocalAiScore: float = 0.0
106
- pitchStabilityScore: float = 0.0
107
- vibratoRegularityScore: float = 0.0
108
- formantConsistencyScore: float = 0.0
109
- breathPatternScore: float = 0.0
110
- vocalTextureScore: float = 0.0
111
- pitchMeanHz: float = 0.0
112
- pitchStdCents: float = 0.0
113
- vibratoRateHz: float = 0.0
114
- vibratoExtentCents: float = 0.0
115
- indicators: List[str] = Field(default_factory=list)
116
-
117
-
118
- class AnalysisFeatures(BaseModel):
119
- """Audio feature analysis results."""
120
-
121
- spectralRegularity: float = 0.5
122
- temporalPatterns: float = 0.5
123
- harmonicStructure: float = 0.5
124
- artificialIndicators: List[str] = Field(default_factory=list)
125
-
126
-
127
- class AudioInfo(BaseModel):
128
- """Audio file information."""
129
-
130
- duration: float = 0.0
131
- sampleRate: int = 44100
132
- bitrate: int = 128
133
- format: str = "unknown"
134
- channels: int = 2
135
-
136
-
137
- class ConfidenceBandModel(BaseModel):
138
- tier: str
139
- labelTr: str
140
- labelEn: str
141
- lowerBound: float
142
- upperBound: float
143
-
144
-
145
- class ModelVoteModel(BaseModel):
146
- name: str
147
- probability: float
148
- vote: str
149
-
150
-
151
- class FeatureContributionModel(BaseModel):
152
- name: str
153
- label: str
154
- labelEn: str
155
- category: str
156
- value: float
157
- zScore: float
158
- shapValue: float
159
- direction: str
160
- description: str
161
-
162
-
163
- class XAIExplanation(BaseModel):
164
- """Rich explainable analysis payload."""
165
-
166
- probability: float
167
- threshold: float
168
- baseProbability: float
169
- confidenceBand: ConfidenceBandModel
170
- modelVotes: List[ModelVoteModel] = Field(default_factory=list)
171
- bestModel: str = "XGBoost"
172
- topContributions: List[FeatureContributionModel] = Field(default_factory=list)
173
- allFeatures: Dict[str, FeatureContributionModel] = Field(default_factory=dict)
174
- featureCount: int = 0
175
-
176
-
177
- class MetaFeatureImportance(BaseModel):
178
- """One feature's contribution to the meta-classifier's prediction."""
179
-
180
- feature: str
181
- importance: float
182
- value: float
183
-
184
-
185
- class MetaClassifierExplanation(BaseModel):
186
- """
187
- Trained stacking ensemble result — a second, independent opinion
188
- (LightGBM over all tower outputs) shown alongside the primary XAI
189
- verdict for transparency, not used to override it. Present only when
190
- the trained model artifacts are available; absent (not error) otherwise.
191
- """
192
-
193
- isAIGenerated: bool
194
- confidence: float
195
- modelVersion: str
196
- towerScores: Dict[str, float] = Field(default_factory=dict)
197
- indicators: List[str] = Field(default_factory=list)
198
- topFeatures: List[MetaFeatureImportance] = Field(default_factory=list)
199
-
200
-
201
- class AnalysisResult(BaseModel):
202
- """Platform/hooks/analysisTypes.ts uyumlu."""
203
-
204
- isAIGenerated: bool
205
- confidence: float = Field(..., ge=0.03, le=0.97)
206
- processingTime: float
207
- modelVersion: str
208
- decisionSource: str
209
- analysisMode: Literal["production", "preview"]
210
- source: Dict[str, Any]
211
- features: AnalysisFeatures
212
- audioInfo: AudioInfo
213
- vocalAnalysis: Optional[VocalAnalysis] = None
214
- xai: Optional[XAIExplanation] = None
215
- towerScores: Dict[str, float] = Field(default_factory=dict)
216
- metaClassifier: Optional[MetaClassifierExplanation] = None
217
-
218
-
219
- class AnalyzeResponse(BaseModel):
220
- """Response model for analysis endpoint."""
221
-
222
- result: Optional[AnalysisResult] = None
223
- warnings: List[str] = Field(default_factory=list)
224
- errors: List[str] = Field(default_factory=list)
225
-
226
-
227
  @router.post(
228
  "/api/analyze",
229
  response_model=AnalyzeResponse,
 
19
  import uuid
20
  from collections import defaultdict
21
  from concurrent.futures import ThreadPoolExecutor
22
+ from typing import Optional, List, Dict
23
  from fastapi import (
24
  APIRouter, File, UploadFile, Form,
25
  Request, Depends, HTTPException, status,
26
  )
 
27
 
28
+ from .analyze_schemas import (
29
+ AnalysisFeatures,
30
+ AnalysisResult,
31
+ AnalyzeResponse,
32
+ AudioInfo,
33
+ ConfidenceBandModel,
34
+ FeatureContributionModel,
35
+ MetaClassifierExplanation,
36
+ MetaFeatureImportance,
37
+ ModelVoteModel,
38
+ VocalAnalysis,
39
+ XAIExplanation,
40
+ )
41
  from ..services.youtube_analysis import YouTubeAnalysisService
42
  from ..services.preview_model import PreviewModel
43
  from ..services.feature_extractor import (
 
105
  _analysis_pool = ThreadPoolExecutor(max_workers=3)
106
 
107
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
108
  @router.post(
109
  "/api/analyze",
110
  response_model=AnalyzeResponse,