44
55import mimetypes
66import re
7+ import statistics
78import uuid
89from collections import Counter , defaultdict
910from contextlib import asynccontextmanager
@@ -65,6 +66,33 @@ def _review_counts(aws: PipelineAWS) -> dict[str, int]:
6566 }
6667
6768
69+ def _percentile (values : list [float ], quantile : float ) -> float | None :
70+ if not values :
71+ return None
72+ ordered = sorted (values )
73+ position = (len (ordered ) - 1 ) * quantile
74+ lower = int (position )
75+ upper = min (lower + 1 , len (ordered ) - 1 )
76+ weight = position - lower
77+ return ordered [lower ] * (1.0 - weight ) + ordered [upper ] * weight
78+
79+
80+ def _similarity_summary (scores : list [float ]) -> dict [str , Any ]:
81+ return {
82+ "count" : len (scores ),
83+ "mean" : round (statistics .fmean (scores ), 4 ) if scores else None ,
84+ "median" : round (statistics .median (scores ), 4 ) if scores else None ,
85+ "minimum" : round (min (scores ), 4 ) if scores else None ,
86+ "maximum" : round (max (scores ), 4 ) if scores else None ,
87+ "p10" : round (value , 4 )
88+ if (value := _percentile (scores , 0.1 )) is not None
89+ else None ,
90+ "p90" : round (value , 4 )
91+ if (value := _percentile (scores , 0.9 )) is not None
92+ else None ,
93+ }
94+
95+
6896def _dataset_snapshot (aws : PipelineAWS , dataset_id : str ) -> dict [str , Any ]:
6997 dataset = aws .get (f"DATASET#{ dataset_id } " , "META" )
7098 if not dataset :
@@ -121,6 +149,21 @@ def _dataset_snapshot(aws: PipelineAWS, dataset_id: str) -> dict[str, Any]:
121149 ),
122150 None ,
123151 )
152+ chunk_reconstruction_scores = [
153+ float (score )
154+ for chunk in source_chunks
155+ if (
156+ score := chunk .get ("reconstruction" , {})
157+ .get ("metrics" , {})
158+ .get ("similarity_score" )
159+ )
160+ is not None
161+ ]
162+ source_similarity = (
163+ source .get ("reconstruction" , {})
164+ .get ("metrics" , {})
165+ .get ("similarity_score" )
166+ )
124167 all_sources .append (
125168 {
126169 ** source ,
@@ -146,6 +189,22 @@ def _dataset_snapshot(aws: PipelineAWS, dataset_id: str) -> dict[str, Any]:
146189 )
147190 ),
148191 "selected_order" : route ,
192+ "reconstruction_count" : (
193+ 1 if source_similarity is not None else 0
194+ ),
195+ "reconstructed_chunk_count" : len (
196+ chunk_reconstruction_scores
197+ ),
198+ "similarity_score" : (
199+ round (float (source_similarity ), 4 )
200+ if source_similarity is not None
201+ else None
202+ ),
203+ "similarity_minimum" : (
204+ round (min (chunk_reconstruction_scores ), 4 )
205+ if chunk_reconstruction_scores
206+ else None
207+ ),
149208 }
150209 )
151210 job_summaries .append (
@@ -165,6 +224,41 @@ def _dataset_snapshot(aws: PipelineAWS, dataset_id: str) -> dict[str, Any]:
165224 chunk_bytes = sum (int (chunk .get ("bytes" ) or 0 ) for chunk in all_chunks )
166225 stem_bytes = sum (int (stem .get ("bytes" ) or 0 ) for stem in all_stems )
167226 stereo_bytes = sum (int (stem .get ("stereo_bytes" ) or 0 ) for stem in all_stems )
227+ chunk_reconstruction_bytes = sum (
228+ int (chunk .get ("reconstruction" , {}).get ("bytes" ) or 0 )
229+ for chunk in all_chunks
230+ )
231+ source_reconstruction_bytes = sum (
232+ int (source .get ("reconstruction" , {}).get ("bytes" ) or 0 )
233+ for source in all_sources
234+ )
235+ reconstruction_bytes = (
236+ chunk_reconstruction_bytes + source_reconstruction_bytes
237+ )
238+ reconstructions = []
239+ for source in all_sources :
240+ reconstruction = source .get ("reconstruction" , {})
241+ metrics = reconstruction .get ("metrics" , {})
242+ score = metrics .get ("similarity_score" )
243+ if score is None :
244+ continue
245+ reconstructions .append (
246+ {
247+ "job_id" : source .get ("job_id" ),
248+ "source_id" : source .get ("source_id" ),
249+ "filename" : source .get ("filename" ),
250+ "chunk_count" : source .get ("chunk_count" ),
251+ "duration_seconds" : source .get ("duration_seconds" ),
252+ "similarity_score" : float (score ),
253+ "waveform_correlation" : metrics .get ("waveform_correlation" ),
254+ "level_delta_db" : metrics .get ("level_delta_db" ),
255+ "snr_db" : metrics .get ("snr_db" ),
256+ "selected_order" : source .get ("selected_order" ),
257+ }
258+ )
259+ similarity_scores = [
260+ float (item ["similarity_score" ]) for item in reconstructions
261+ ]
168262 review_remaining = sum (
169263 stem .get ("effective_status" ) in {"failure" , "uncertain" } for stem in all_stems
170264 )
@@ -184,7 +278,16 @@ def _dataset_snapshot(aws: PipelineAWS, dataset_id: str) -> dict[str, Any]:
184278 "chunk_bytes" : chunk_bytes ,
185279 "stem_bytes" : stem_bytes ,
186280 "stereo_bytes" : stereo_bytes ,
187- "total_bytes" : input_bytes + chunk_bytes + stem_bytes + stereo_bytes ,
281+ "reconstruction_bytes" : reconstruction_bytes ,
282+ "chunk_reconstruction_bytes" : chunk_reconstruction_bytes ,
283+ "source_reconstruction_bytes" : source_reconstruction_bytes ,
284+ "total_bytes" : (
285+ input_bytes
286+ + chunk_bytes
287+ + stem_bytes
288+ + stereo_bytes
289+ + reconstruction_bytes
290+ ),
188291 "chunks" : len (all_chunks ),
189292 "audible_chunks" : sum (
190293 chunk .get ("status" ) != "skipped" for chunk in all_chunks
@@ -194,6 +297,11 @@ def _dataset_snapshot(aws: PipelineAWS, dataset_id: str) -> dict[str, Any]:
194297 ),
195298 "stems" : len (all_stems ),
196299 "stereo_stems" : sum (bool (stem .get ("stereo_s3_key" )) for stem in all_stems ),
300+ "reconstructed_chunks" : sum (
301+ bool (chunk .get ("reconstruction" )) for chunk in all_chunks
302+ ),
303+ "reconstructed_sources" : len (reconstructions ),
304+ "similarity" : _similarity_summary (similarity_scores ),
197305 "stems_by_type" : dict (
198306 Counter (str (stem .get ("stem_type" )) for stem in all_stems )
199307 ),
@@ -216,6 +324,10 @@ def _dataset_snapshot(aws: PipelineAWS, dataset_id: str) -> dict[str, Any]:
216324 key = lambda source : str (source .get ("created_at" , "" )),
217325 reverse = True ,
218326 ),
327+ "reconstructions" : sorted (
328+ reconstructions ,
329+ key = lambda item : float (item ["similarity_score" ]),
330+ ),
219331 }
220332
221333
@@ -432,13 +544,19 @@ def get_source(job_id: str, source_id: str, request: Request) -> dict[str, Any]:
432544 if not source :
433545 raise HTTPException (status_code = 404 , detail = "Source not found" )
434546 job = next (item for item in items if item ["SK" ] == "META" )
547+ source_reconstruction = source .get ("reconstruction" , {})
435548 source = {
436549 ** source ,
437550 "audio_url" : (
438551 store .presign_download (source ["s3_key" ])
439552 if source .get ("s3_key" ) and source .get ("status" ) != "failed"
440553 else None
441554 ),
555+ "joined_audio_url" : (
556+ store .presign_download (source_reconstruction ["s3_key" ])
557+ if source_reconstruction .get ("s3_key" )
558+ else None
559+ ),
442560 }
443561 chunks = sorted (
444562 [
@@ -499,6 +617,7 @@ def get_source(job_id: str, source_id: str, request: Request) -> dict[str, Any]:
499617 expanded_chunks = []
500618 for chunk in chunks :
501619 chunk_id = str (chunk ["chunk_id" ])
620+ reconstruction = chunk .get ("reconstruction" , {})
502621 expanded_chunks .append (
503622 {
504623 ** chunk ,
@@ -514,6 +633,11 @@ def get_source(job_id: str, source_id: str, request: Request) -> dict[str, Any]:
514633 ),
515634 ),
516635 "omitted_stems" : sorted (omitted_by_chunk [chunk_id ]),
636+ "joined_audio_url" : (
637+ store .presign_download (reconstruction ["s3_key" ])
638+ if reconstruction .get ("s3_key" )
639+ else None
640+ ),
517641 }
518642 )
519643 annotations = [
0 commit comments