ai-agent-book 精选快照(<2MB 代码与文档,来自 github.com/bojieli/ai-agent-book)
Build latest book artifacts / build (push) Canceled after 0s
dependency resolution / resolve (3.11) (push) Canceled after 0s
dependency resolution / resolve (3.13) (push) Canceled after 0s
deploy-pages / build (push) Canceled after 0s
deploy-pages / deploy (push) Canceled after 0s
i18n consistency check / check (push) Canceled after 0s
provider adoption tests / test (chapter2/context-compression) (push) Canceled after 0s
provider adoption tests / test (chapter2/prompt-injection) (push) Canceled after 0s
provider adoption tests / test (chapter2/system-hint) (push) Canceled after 0s
provider adoption tests / test (chapter3/log-sanitization) (push) Canceled after 0s
web-search-agent tests / test (push) Canceled after 0s
web-search-agent tests / agentbook (push) Canceled after 0s
Build latest book artifacts / build (push) Canceled after 0s
dependency resolution / resolve (3.11) (push) Canceled after 0s
dependency resolution / resolve (3.13) (push) Canceled after 0s
deploy-pages / build (push) Canceled after 0s
deploy-pages / deploy (push) Canceled after 0s
i18n consistency check / check (push) Canceled after 0s
provider adoption tests / test (chapter2/context-compression) (push) Canceled after 0s
provider adoption tests / test (chapter2/prompt-injection) (push) Canceled after 0s
provider adoption tests / test (chapter2/system-hint) (push) Canceled after 0s
provider adoption tests / test (chapter3/log-sanitization) (push) Canceled after 0s
web-search-agent tests / test (push) Canceled after 0s
web-search-agent tests / agentbook (push) Canceled after 0s
This commit is contained in:
@@ -0,0 +1,91 @@
|
||||
import json
|
||||
import subprocess
|
||||
|
||||
import pytest
|
||||
|
||||
from evaluate_audio_quality import DIMENSIONS, OUTPUTS, PERMUTATIONS, aggregate, validate_response
|
||||
from markup import parse
|
||||
from tts import concat_mp3, make_silence
|
||||
from voice_library import EMOTIONS, SPEEDS, STYLES, load_voice_library
|
||||
|
||||
|
||||
def test_native_s1_nonverbal_events_not_onomatopoeia():
|
||||
segments = parse("[THINKING]好吧,[SIGH][LAUGH:small][BREATH]继续。")
|
||||
texts = [s["text"] for s in segments if s["type"] == "speech"]
|
||||
assert "(uncertain)嗯……" in texts
|
||||
assert "(sighing)" in texts
|
||||
assert "(chuckling)" in texts
|
||||
assert "(gasping)" in texts
|
||||
assert "哈哈," not in texts and "唉——" not in texts
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"directory_name",
|
||||
["speaker clips", "speaker's clips", "d'angelo's clips"],
|
||||
)
|
||||
def test_concat_handles_apostrophe_in_output_directory(tmp_path, directory_name):
|
||||
"""FFconcat must preserve ordinary, single-quote, and multi-quote paths."""
|
||||
output_dir = tmp_path / directory_name
|
||||
output_dir.mkdir()
|
||||
parts = [output_dir / "first.mp3", output_dir / "second.mp3"]
|
||||
for part in parts:
|
||||
make_silence(100, part)
|
||||
|
||||
output = output_dir / "joined.mp3"
|
||||
concat_mp3(parts, output)
|
||||
|
||||
duration = float(subprocess.check_output([
|
||||
"ffprobe", "-v", "error", "-show_entries", "format=duration",
|
||||
"-of", "default=noprint_wrappers=1:nokey=1", str(output),
|
||||
], text=True).strip())
|
||||
assert output.is_file()
|
||||
assert duration >= 0.18
|
||||
|
||||
|
||||
def test_library_requires_exact_cartesian_product(tmp_path):
|
||||
manifest = tmp_path / "manifest.json"
|
||||
manifest.write_text(json.dumps({"profiles": {}}))
|
||||
with pytest.raises(ValueError, match="24"):
|
||||
load_voice_library(manifest)
|
||||
|
||||
|
||||
def test_dimensions_are_4_by_3_by_2():
|
||||
assert len(EMOTIONS) * len(SPEEDS) * len(STYLES) == 24
|
||||
|
||||
|
||||
def _judge_response(scores):
|
||||
return {
|
||||
"clips": {
|
||||
alias: {
|
||||
dimension: {"score": scores[alias], "reason": f"audible evidence for {alias}"}
|
||||
for dimension in DIMENSIONS
|
||||
}
|
||||
for alias in ("X", "Y", "Z")
|
||||
},
|
||||
"ranking": sorted(("X", "Y", "Z"), key=scores.get, reverse=True),
|
||||
"ranking_reason": "audible comparison",
|
||||
}
|
||||
|
||||
|
||||
def test_quality_response_rejects_bare_scores_without_audible_evidence():
|
||||
response = _judge_response({"X": 1, "Y": 2, "Z": 3})
|
||||
response["clips"]["X"]["naturalness"]["reason"] = ""
|
||||
with pytest.raises(ValueError, match="audible evidence"):
|
||||
validate_response(response)
|
||||
|
||||
|
||||
def test_position_balanced_aggregate_maps_aliases_back_to_configurations():
|
||||
# Each pass gives C=5, B=4, A=2 regardless of its anonymous position.
|
||||
passes = []
|
||||
score_by_name = {
|
||||
"A_no_control_markers": 2,
|
||||
"B_single_reference": 4,
|
||||
"C_24_reference_library": 5,
|
||||
}
|
||||
for permutation in PERMUTATIONS:
|
||||
mapping = dict(zip(("X", "Y", "Z"), permutation))
|
||||
scores = {alias: score_by_name[name] for alias, name in mapping.items()}
|
||||
passes.append({"alias_to_configuration": mapping, "response": _judge_response(scores)})
|
||||
result = aggregate(passes)
|
||||
assert result["aggregate_ranking"] == list(reversed(list(OUTPUTS)))
|
||||
assert result["manuscript_quality_claim_reproduced"] is True
|
||||
Reference in New Issue
Block a user