sable-sphynx 0.7.0.dev0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- sable_sphynx-0.7.0.dev0.dist-info/METADATA +152 -0
- sable_sphynx-0.7.0.dev0.dist-info/RECORD +174 -0
- sable_sphynx-0.7.0.dev0.dist-info/WHEEL +5 -0
- sable_sphynx-0.7.0.dev0.dist-info/top_level.txt +1 -0
- sphynx/__init__.py +469 -0
- sphynx/__init__.pyi +376 -0
- sphynx/_analytical_client.py +77 -0
- sphynx/_analytical_values.py +252 -0
- sphynx/_audit_client.py +173 -0
- sphynx/_comparison_adapters.py +113 -0
- sphynx/_componentized_full_rag.py +34 -0
- sphynx/_composed_pipeline.py +109 -0
- sphynx/_full_rag_grading.py +218 -0
- sphynx/_full_rag_trace.py +221 -0
- sphynx/_local_eval.py +268 -0
- sphynx/_pipeline_core.py +243 -0
- sphynx/_pr_client.py +237 -0
- sphynx/_rag_diagnostics_calibration.py +285 -0
- sphynx/_rag_diagnostics_catalog.py +39 -0
- sphynx/_rag_diagnostics_common.py +26 -0
- sphynx/_rag_diagnostics_contracts.py +186 -0
- sphynx/_rag_diagnostics_engine.py +243 -0
- sphynx/_rag_diagnostics_importers.py +242 -0
- sphynx/_rag_diagnostics_ranking.py +81 -0
- sphynx/_rag_diagnostics_semantic.py +325 -0
- sphynx/_rag_ranking.py +149 -0
- sphynx/_speech_benchmark_scoring.py +140 -0
- sphynx/_speech_benchmark_sources.py +275 -0
- sphynx/_speech_complete_scoring.py +218 -0
- sphynx/_speech_complete_source.py +118 -0
- sphynx/_speech_kido.py +294 -0
- sphynx/_speech_scoring.py +77 -0
- sphynx/_track_capture.py +213 -0
- sphynx/analytical_views.py +515 -0
- sphynx/assessment_contracts.py +378 -0
- sphynx/assessment_selection.py +57 -0
- sphynx/audit_access.py +245 -0
- sphynx/audit_contracts.py +204 -0
- sphynx/audit_requests.py +180 -0
- sphynx/authoring.py +188 -0
- sphynx/benchmarks.py +568 -0
- sphynx/candidates.py +62 -0
- sphynx/catalog.py +272 -0
- sphynx/chunking.py +372 -0
- sphynx/clickhouse_reader.py +169 -0
- sphynx/client.py +486 -0
- sphynx/comparison_core.py +149 -0
- sphynx/comparison_views.py +223 -0
- sphynx/components.py +1661 -0
- sphynx/contracts.py +514 -0
- sphynx/customer_rerank.py +299 -0
- sphynx/customer_retrieval.py +146 -0
- sphynx/data/benchmark-releases.v1.json +164 -0
- sphynx/data/public-benchmark-release.v1.json +354 -0
- sphynx/data/rag-diagnostics-synthetic.v1.json +6982 -0
- sphynx/data/rag-paper-references.v1.json +176 -0
- sphynx/data/rag-paper-schemas.v1.json +1069 -0
- sphynx/data/rag-rerank-v1.json +507 -0
- sphynx/dataset_catalog_data.py +1214 -0
- sphynx/dataset_readiness.py +138 -0
- sphynx/dataset_v3.py +999 -0
- sphynx/demo.py +130 -0
- sphynx/demo_candidates/__init__.py +1 -0
- sphynx/demo_candidates/dense.py +11 -0
- sphynx/demo_candidates/lexical.py +21 -0
- sphynx/diagnostics.py +207 -0
- sphynx/documentation.py +737 -0
- sphynx/documentation_candidate.py +939 -0
- sphynx/evals.py +538 -0
- sphynx/evaluation_protocols.py +124 -0
- sphynx/evaluator_bindings.py +370 -0
- sphynx/evidence.py +352 -0
- sphynx/execution_capabilities.py +109 -0
- sphynx/fast_search.py +285 -0
- sphynx/full_rag.py +341 -0
- sphynx/hosted/__init__.py +18 -0
- sphynx/hosted/benchmark_intake.py +218 -0
- sphynx/hosted/contracts.py +361 -0
- sphynx/hosted/model_admission.py +130 -0
- sphynx/hosted/model_artifacts.py +298 -0
- sphynx/hosted/model_contracts.py +63 -0
- sphynx/hosted/model_gcs.py +181 -0
- sphynx/hosted/model_history.py +84 -0
- sphynx/hosted/model_session.py +233 -0
- sphynx/hosted/public_suite.py +74 -0
- sphynx/hosted/registry.py +97 -0
- sphynx/hosted/revisions.py +126 -0
- sphynx/hosted/sandbox.py +105 -0
- sphynx/hosted/submission.py +287 -0
- sphynx/hosted_workflow.py +451 -0
- sphynx/http_transport.py +86 -0
- sphynx/integrated_rag.py +352 -0
- sphynx/integrated_workflow.py +552 -0
- sphynx/integration_contracts.py +474 -0
- sphynx/invocation.py +791 -0
- sphynx/invocation_candidates.py +392 -0
- sphynx/invocation_catalog_data.py +40 -0
- sphynx/learned_catalog_data.py +30 -0
- sphynx/learned_rerank.py +267 -0
- sphynx/legacy_full_rag.py +67 -0
- sphynx/lifecycle.py +885 -0
- sphynx/lifecycle_workflow.py +490 -0
- sphynx/metric_views.py +474 -0
- sphynx/metrics.py +282 -0
- sphynx/model_adapters.py +438 -0
- sphynx/model_catalog_data.py +30 -0
- sphynx/official_benchmarks.py +385 -0
- sphynx/packs.py +258 -0
- sphynx/pipeline.py +313 -0
- sphynx/pipeline_workflow.py +551 -0
- sphynx/pr_evaluations.py +560 -0
- sphynx/progress.py +89 -0
- sphynx/public_bundle.py +173 -0
- sphynx/public_eval.py +62 -0
- sphynx/public_rerank.py +355 -0
- sphynx/py.typed +0 -0
- sphynx/pytest_plugin.py +62 -0
- sphynx/question_robustness.py +437 -0
- sphynx/rag.py +329 -0
- sphynx/rag_diagnostics.py +309 -0
- sphynx/rag_papers/__init__.py +29 -0
- sphynx/rag_papers/__main__.py +45 -0
- sphynx/rag_papers/candidates.py +19 -0
- sphynx/rag_papers/contracts.py +282 -0
- sphynx/rag_papers/datasets.py +291 -0
- sphynx/rag_papers/experiments.py +116 -0
- sphynx/rag_papers/judges.py +308 -0
- sphynx/rag_papers/registry.py +33 -0
- sphynx/rag_papers/runner.py +176 -0
- sphynx/rag_papers/sable.py +135 -0
- sphynx/rag_papers/schemas.py +12 -0
- sphynx/rag_papers/scoring.py +249 -0
- sphynx/rag_papers/semantic.py +288 -0
- sphynx/rag_papers/trec.py +80 -0
- sphynx/recorded_scores.py +352 -0
- sphynx/records.py +124 -0
- sphynx/reflex_traces.py +193 -0
- sphynx/report_rendering.py +71 -0
- sphynx/rerank_family_contracts.py +150 -0
- sphynx/rerank_workflow.py +424 -0
- sphynx/research_candidate.py +190 -0
- sphynx/results.py +852 -0
- sphynx/retrieval.py +750 -0
- sphynx/retrieval_candidates.py +295 -0
- sphynx/retrieval_catalog_data.py +19 -0
- sphynx/retrieval_recordings.py +125 -0
- sphynx/reviewer_audit.py +266 -0
- sphynx/routing_policies.py +375 -0
- sphynx/runner.py +544 -0
- sphynx/sable_rerank.py +489 -0
- sphynx/score_reliability.py +393 -0
- sphynx/speech_benchmarks.py +204 -0
- sphynx/speech_campaigns.py +378 -0
- sphynx/speech_complete.py +236 -0
- sphynx/speech_contracts.py +225 -0
- sphynx/speech_evidence.py +429 -0
- sphynx/speech_listening.py +115 -0
- sphynx/speech_multilingual.py +71 -0
- sphynx/speech_tts.py +479 -0
- sphynx/sql/001_sync_v1.sql +30 -0
- sphynx/stage_contracts.py +199 -0
- sphynx/statistical_catalog_data.py +53 -0
- sphynx/statistical_rerank.py +232 -0
- sphynx/sync.py +797 -0
- sphynx/workbench.py +378 -0
- sphynx/workbench_catalog_data.py +13 -0
- sphynx/workbench_tracks.py +78 -0
- sphynx/workflow_async.py +197 -0
- sphynx/workflow_contracts.py +594 -0
- sphynx/workflow_decisions.py +211 -0
- sphynx/workflow_defaults.py +16 -0
- sphynx/workflow_extensions.py +212 -0
- sphynx/workflow_registry.py +513 -0
- sphynx/workflows.py +792 -0
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
"""Blind packs bound to new TTS waveforms; explicit human reviews only."""
|
|
2
|
+
from collections import defaultdict
|
|
3
|
+
import csv
|
|
4
|
+
import io
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
import random
|
|
7
|
+
import statistics
|
|
8
|
+
import uuid
|
|
9
|
+
|
|
10
|
+
from ._speech_kido import digest,encoded,json_value,csv_rows,require
|
|
11
|
+
from ._speech_benchmark_sources import DIMENSIONS
|
|
12
|
+
from .speech_evidence import _new_directory,_read,_write_files,_sha
|
|
13
|
+
from .speech_tts import load_tts_run,_load_plan
|
|
14
|
+
|
|
15
|
+
SUITE_ID='speech.listening.v1'
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def prepare_speech_listening_pack(run_path,*,expected_manifest_sha256,output_dir,protocol='blind-quality',seed=20260921,repetition=1,case_ids=None):
|
|
19
|
+
require(protocol in ('blind-quality','pt-br-listening') and type(seed) is int and type(repetition) is int and repetition>=1,'Invalid listening design')
|
|
20
|
+
root=Path(run_path).absolute();load_tts_run(root,expected_manifest_sha256=expected_manifest_sha256)
|
|
21
|
+
manifest=json_value(_read(root,'manifest.json'));_,plan=_load_plan(root/'frozen-plan',manifest['plan_sha256'])
|
|
22
|
+
cases={r['id']:r for r in plan['cases']}
|
|
23
|
+
require(case_ids is None or type(case_ids) is list and len(set(case_ids))==len(case_ids) and set(case_ids)<=set(cases),'Invalid listening case selection')
|
|
24
|
+
selected=set(cases) if case_ids is None else set(case_ids);require(selected,'Empty listening pack')
|
|
25
|
+
if protocol=='pt-br-listening':require(all(cases[i]['language']=='pt-BR' for i in selected),'PT-BR pack contains another language')
|
|
26
|
+
captures=[(p,json_value(_read(root,p))) for p in manifest['files'] if p.startswith('captures/') and p.endswith('/capture.json')]
|
|
27
|
+
captures=[(p,r) for p,r in captures if r['repetition']==repetition and r['case_id'] in selected]
|
|
28
|
+
require(len(captures)==2*len(selected) and len({(r['case_id'],r['method_id']) for _,r in captures})==len(captures)
|
|
29
|
+
and all(r['success'] for _,r in captures),'Listening pack requires both successful arms for every selected text')
|
|
30
|
+
random.Random(seed).shuffle(captures);pack_id='listening-pack-'+uuid.uuid4().hex;mapping=[];payload={};rows=[]
|
|
31
|
+
dimensions=list(DIMENSIONS) if protocol=='pt-br-listening' else ['overall_quality_1_5']
|
|
32
|
+
for index,(path,capture) in enumerate(captures):
|
|
33
|
+
sample='sample-'+str(index+1).zfill(3);audio=_read(root,path.removesuffix('capture.json')+'audio.wav');sha=digest(audio)
|
|
34
|
+
payload['blind/audio/'+sample+'.wav']=audio
|
|
35
|
+
case=cases[capture['case_id']];method=plan['methods'][capture['method_id']]
|
|
36
|
+
mapping.append(dict(sample_id=sample,case_id=case['id'],method_id=capture['method_id'],provider=method['provider'],model=method['model'],
|
|
37
|
+
audio_sha256=sha,request_id=capture['request_id'],text=case['text'],language=case['language']))
|
|
38
|
+
rows.append(dict(pack_id=pack_id,sample_id=sample,audio_sha256=sha,text=case['text'],language=case['language'],**{d:'' for d in dimensions},notes=''))
|
|
39
|
+
out=io.StringIO(newline='');writer=csv.DictWriter(out,fieldnames=list(rows[0]));writer.writeheader();writer.writerows(rows)
|
|
40
|
+
payload['blind/scores.csv']=out.getvalue().encode('utf-8');payload['mapping.json']=encoded(mapping)
|
|
41
|
+
dest=_new_directory(output_dir);files=_write_files(dest,payload)
|
|
42
|
+
pack=dict(schema_version='sphynx.speech.listening.pack.v1',suite_id=SUITE_ID,pack_id=pack_id,protocol=protocol,dimensions=dimensions,
|
|
43
|
+
source_run_sha256=expected_manifest_sha256,source_mode=plan['mode'],seed=seed,repetition=repetition,files=files,
|
|
44
|
+
samples=len(rows),quality_ratings_available=False,historical_ratings_reused=False)
|
|
45
|
+
raw=encoded(pack);(dest/'manifest.json').write_bytes(raw)
|
|
46
|
+
return dict(path=str(dest),pack_sha256=digest(raw),suite_id=SUITE_ID,pack_id=pack_id,samples=len(rows),distribute='blind directory only; keep mapping private')
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def _pack(path,pin):
|
|
50
|
+
root=Path(path).absolute();raw=_read(root,'manifest.json');require(digest(raw)==_sha(pin),'Listening pack changed');pack=json_value(raw)
|
|
51
|
+
require(pack.get('schema_version')=='sphynx.speech.listening.pack.v1' and pack.get('suite_id')==SUITE_ID and
|
|
52
|
+
pack.get('historical_ratings_reused') is False and pack.get('quality_ratings_available') is False,'Invalid new-waveform listening pack')
|
|
53
|
+
for p,h in pack['files'].items():
|
|
54
|
+
b=_read(root,p);require(h==dict(sha256=digest(b),size_bytes=len(b)),'Listening audio, mapping or template changed')
|
|
55
|
+
mapping=json_value(_read(root,'mapping.json'))
|
|
56
|
+
require(len(mapping)==pack['samples'] and len({r['sample_id'] for r in mapping})==len(mapping),'Listening mapping census differs')
|
|
57
|
+
for row in mapping:require(digest(_read(root,'blind/audio/'+row['sample_id']+'.wav'))==row['audio_sha256'],'Listening waveform binding differs')
|
|
58
|
+
return root,pack,mapping
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def _grade(pack,mapping,reviews):
|
|
62
|
+
require(pack.get('schema_version')=='sphynx.speech.listening.pack.v1' and pack.get('suite_id')==SUITE_ID and
|
|
63
|
+
pack.get('protocol') in ('blind-quality','pt-br-listening') and pack.get('source_mode') in ('fixture','provider') and
|
|
64
|
+
pack.get('historical_ratings_reused') is False and pack.get('quality_ratings_available') is False and
|
|
65
|
+
pack.get('dimensions')==(list(DIMENSIONS) if pack['protocol']=='pt-br-listening' else ['overall_quality_1_5']),
|
|
66
|
+
'Listening definition or evidence boundary differs')
|
|
67
|
+
require(type(reviews) is list and reviews and len({r['rater_id'] for r in reviews})==len(reviews),'Declare unique review identities')
|
|
68
|
+
by_id={r['sample_id']:r for r in mapping};groups=defaultdict(list)
|
|
69
|
+
for review in reviews:
|
|
70
|
+
require(isinstance(review['rater_id'],str) and review['rater_id'] and type(review['rows']) is list,'Invalid rater review')
|
|
71
|
+
rows=review['rows'];require(len({r['sample_id'] for r in rows})==len(rows) and {r['sample_id'] for r in rows}<=set(by_id),'Unknown or duplicated blind review sample')
|
|
72
|
+
supplied={r['sample_id']:r for r in rows}
|
|
73
|
+
for sample,identity in by_id.items():
|
|
74
|
+
row=supplied.get(sample)
|
|
75
|
+
if row:require(row.get('pack_id')==pack['pack_id'] and row.get('audio_sha256')==identity['audio_sha256'] and
|
|
76
|
+
row.get('text')==identity['text'] and row.get('language')==identity['language'],'Review belongs to another pack, waveform or text')
|
|
77
|
+
for dimension in pack['dimensions']:
|
|
78
|
+
value=row.get(dimension,'') if row else ''
|
|
79
|
+
require(value in ('','1','2','3','4','5'),'Human rating must be blank or an integer from one to five')
|
|
80
|
+
groups[(identity['method_id'],dimension)].append(int(value) if value else None)
|
|
81
|
+
results=[]
|
|
82
|
+
for (method,dimension),values in sorted(groups.items()):
|
|
83
|
+
present=[v for v in values if v is not None]
|
|
84
|
+
results.append(dict(method_id=method,dimension=dimension,expected_reviews=len(values),rated=len(present),pending=len(values)-len(present),
|
|
85
|
+
mean=statistics.mean(present) if len(present)==len(values) else None,observed_subset_mean=statistics.mean(present) if present else None,
|
|
86
|
+
declared_raters=len(reviews),independent_raters_verified=False,confidence_interval=None))
|
|
87
|
+
return results
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
def grade_speech_listening_pack(path,*,expected_pack_sha256,reviews,output_dir):
|
|
91
|
+
"""reviews is [{rater_id, rows}], with rows read from a completed CSV."""
|
|
92
|
+
_,pack,mapping=_pack(path,expected_pack_sha256);results=_grade(pack,mapping,reviews)
|
|
93
|
+
report=dict(schema_version='sphynx.speech.listening.report.v1',suite_id=SUITE_ID,
|
|
94
|
+
invocation_id='listening-invocation-'+uuid.uuid4().hex,pack_sha256=expected_pack_sha256,results=results,
|
|
95
|
+
source_mode=pack['source_mode'],historical_ratings_reused=False,subjective_latency_inferred=False)
|
|
96
|
+
dest=_new_directory(output_dir);files=_write_files(dest,{'pack.json':encoded(pack),'mapping.json':encoded(mapping),'reviews.json':encoded(reviews),'report.json':encoded(report)})
|
|
97
|
+
receipt=dict(schema_version='sphynx.speech.listening.receipt.v1',suite_id=SUITE_ID,files=files,invocation_id=report['invocation_id'])
|
|
98
|
+
raw=encoded(receipt);(dest/'receipt.json').write_bytes(raw)
|
|
99
|
+
return dict(path=str(dest),receipt_sha256=digest(raw),suite_id=SUITE_ID,invocation_id=report['invocation_id'])
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
def load_speech_listening_report(path,*,expected_receipt_sha256):
|
|
103
|
+
root=Path(path).absolute();raw=_read(root,'receipt.json');require(digest(raw)==_sha(expected_receipt_sha256),'Listening receipt changed');receipt=json_value(raw)
|
|
104
|
+
require(receipt.get('schema_version')=='sphynx.speech.listening.receipt.v1' and receipt.get('suite_id')==SUITE_ID and
|
|
105
|
+
set(receipt.get('files',{}))=={'pack.json','mapping.json','reviews.json','report.json'},'Invalid listening report')
|
|
106
|
+
values={}
|
|
107
|
+
for p,h in receipt['files'].items():
|
|
108
|
+
b=_read(root,p);require(h==dict(sha256=digest(b),size_bytes=len(b)),'Listening report artifact changed');values[p]=json_value(b)
|
|
109
|
+
pack=values['pack.json'];report=values['report.json']
|
|
110
|
+
require(report.get('schema_version')=='sphynx.speech.listening.report.v1' and report.get('suite_id')==SUITE_ID and
|
|
111
|
+
report.get('invocation_id')==receipt.get('invocation_id') and report.get('pack_sha256')==digest(encoded(pack)) and
|
|
112
|
+
pack['files']['mapping.json']==dict(sha256=digest(encoded(values['mapping.json'])),size_bytes=len(encoded(values['mapping.json']))) and
|
|
113
|
+
report.get('historical_ratings_reused') is False and report.get('subjective_latency_inferred') is False and report.get('source_mode')==pack['source_mode'] and
|
|
114
|
+
report.get('results')==_grade(pack,values['mapping.json'],values['reviews.json']),'Listening arithmetic, identity or scope changed')
|
|
115
|
+
return report
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
"""Separate frozen multilingual TTS campaigns using the existing TTS runner."""
|
|
2
|
+
from pathlib import Path
|
|
3
|
+
import uuid
|
|
4
|
+
from ._speech_kido import encoded,digest,json_value,require
|
|
5
|
+
from .speech_evidence import _new_directory,_read,_write_files,_sha
|
|
6
|
+
from .speech_complete import complete_tts_cases
|
|
7
|
+
from .speech_tts import freeze_tts_plan,run_tts_plan,load_tts_run,_load_plan
|
|
8
|
+
|
|
9
|
+
SUITE_ID='speech.multilingual.execution.v1'
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def freeze_multilingual_tts_campaign(bundle,repository,*,source_commit,source_pr,baseline,candidate,
|
|
13
|
+
output_dir,case_ids=None,repetitions=3,max_requests=20,baseline_profile=None,candidate_profile=None):
|
|
14
|
+
"""Default to the frozen source's three repetitions, within one total cap.
|
|
15
|
+
|
|
16
|
+
Both arms use only the shared, historically supported language subset. The
|
|
17
|
+
profile filter is an explicit operator declaration, not live capability proof.
|
|
18
|
+
"""
|
|
19
|
+
views=[complete_tts_cases(bundle,benchmark='multilingual-isolated',case_ids=None,profile=p) for p in (baseline_profile,candidate_profile)]
|
|
20
|
+
shared={r['id'] for r in views[0]['cases']}&{r['id'] for r in views[1]['cases']}
|
|
21
|
+
require(case_ids is None or type(case_ids) is list and len(set(case_ids))==len(case_ids) and set(case_ids)<=shared,'Invalid or unsupported multilingual selection')
|
|
22
|
+
cases=[r for r in views[0]['cases'] if r['id'] in shared and (case_ids is None or r['id'] in case_ids)]
|
|
23
|
+
require(cases and type(repetitions) is int and 1<=repetitions<=3,'Invalid multilingual repetition design')
|
|
24
|
+
require(type(max_requests) is int and 1<=max_requests<=1000 and len(cases)*repetitions*2<=max_requests,'Multilingual campaign exceeds total request cap')
|
|
25
|
+
per_batch=20//(repetitions*2);dest=_new_directory(output_dir);plans=[]
|
|
26
|
+
for i in range(0,len(cases),per_batch):
|
|
27
|
+
chunk=cases[i:i+per_batch]
|
|
28
|
+
plans.append(freeze_tts_plan(repository,source_commit=source_commit,source_pr=source_pr,cases=chunk,
|
|
29
|
+
cohort_identity=dict(kind=SUITE_ID,sha256=digest(encoded(dict(bundle=bundle.manifest_sha256,cases=chunk)))),
|
|
30
|
+
baseline=baseline,candidate=candidate,output_dir=dest/('batch-'+str(len(plans)+1)),repetitions=repetitions))
|
|
31
|
+
manifest=dict(schema_version='sphynx.speech.multilingual.plan.v1',suite_id=SUITE_ID,
|
|
32
|
+
bundle_manifest_sha256=bundle.manifest_sha256,plans=plans,total_requests=len(cases)*repetitions*2,
|
|
33
|
+
max_requests=max_requests,baseline_profile=baseline_profile,candidate_profile=candidate_profile,
|
|
34
|
+
historical_support_filter_only=True,native_speaker_validation_available=False,provider_calls_made=False)
|
|
35
|
+
raw=encoded(manifest);(dest/'plan.json').write_bytes(raw)
|
|
36
|
+
return dict(path=str(dest),plan_sha256=digest(raw),total_requests=manifest['total_requests'],batches=len(plans),suite_id=SUITE_ID)
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def run_multilingual_tts_campaign(path,*,expected_plan_sha256,output_dir,allow_provider_calls=False):
|
|
40
|
+
root=Path(path).absolute();raw=_read(root,'plan.json');require(digest(raw)==_sha(expected_plan_sha256),'Multilingual plan changed')
|
|
41
|
+
plan=json_value(raw);require(plan.get('schema_version')=='sphynx.speech.multilingual.plan.v1' and plan.get('suite_id')==SUITE_ID and
|
|
42
|
+
0<plan['total_requests']<=plan['max_requests'] and plan.get('provider_calls_made') is False,'Invalid multilingual plan')
|
|
43
|
+
verified=[]
|
|
44
|
+
# Verify every subplan and the total budget before starting the first arm.
|
|
45
|
+
for i,sub in enumerate(plan['plans']):
|
|
46
|
+
batch=root/('batch-'+str(i+1));_,p=_load_plan(batch,sub['plan_sha256']);verified.append((batch,p,sub))
|
|
47
|
+
require(sum(p['budget']['planned_requests'] for _,p,_ in verified)==plan['total_requests'],'Multilingual request budget changed')
|
|
48
|
+
require(allow_provider_calls or all(p['mode']=='fixture' for _,p,_ in verified),'Explicit provider launch required for the entire campaign')
|
|
49
|
+
dest=_new_directory(output_dir);runs=[]
|
|
50
|
+
for i,(batch,p,sub) in enumerate(verified):
|
|
51
|
+
r=run_tts_plan(batch,expected_plan_sha256=sub['plan_sha256'],output_dir=dest/('batch-'+str(i+1)),allow_provider_calls=allow_provider_calls)
|
|
52
|
+
load_tts_run(r['path'],expected_manifest_sha256=r['manifest_sha256']);runs.append(r)
|
|
53
|
+
receipt=dict(schema_version='sphynx.speech.multilingual.run.v1',suite_id=SUITE_ID,
|
|
54
|
+
invocation_id='multilingual-invocation-'+uuid.uuid4().hex,plan_sha256=expected_plan_sha256,
|
|
55
|
+
status='completed' if all(r['status']=='completed' for r in runs) else 'completed_with_failures',runs=runs,
|
|
56
|
+
planned_requests=plan['total_requests'],quality=None,subjective_perceived_latency=None)
|
|
57
|
+
raw=encoded(receipt);(dest/'receipt.json').write_bytes(raw)
|
|
58
|
+
return dict(path=str(dest),receipt_sha256=digest(raw),status=receipt['status'],suite_id=SUITE_ID,invocation_id=receipt['invocation_id'])
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def load_multilingual_tts_campaign(path,*,expected_receipt_sha256):
|
|
62
|
+
root=Path(path).absolute();raw=_read(root,'receipt.json');require(digest(raw)==_sha(expected_receipt_sha256),'Multilingual run receipt changed')
|
|
63
|
+
receipt=json_value(raw);require(receipt.get('schema_version')=='sphynx.speech.multilingual.run.v1' and receipt.get('suite_id')==SUITE_ID,'Invalid multilingual run')
|
|
64
|
+
reports=[];planned=0
|
|
65
|
+
for i,r in enumerate(receipt['runs']):
|
|
66
|
+
batch=root/('batch-'+str(i+1));reports.append(load_tts_run(batch,expected_manifest_sha256=r['manifest_sha256']))
|
|
67
|
+
manifest=json_value(_read(batch,'manifest.json'));planned+=manifest['planned_requests']
|
|
68
|
+
require(r.get('status')==manifest['status'] and r.get('invocation_id')==manifest['invocation_id'],'Multilingual batch status or identity changed')
|
|
69
|
+
require(receipt['status']==('completed' if all(r['status']=='completed' for r in receipt['runs']) else 'completed_with_failures') and
|
|
70
|
+
receipt.get('quality') is None and receipt.get('subjective_perceived_latency') is None and receipt.get('planned_requests')==planned,'Multilingual scope changed')
|
|
71
|
+
return dict(receipt=receipt,reports=reports)
|