mirror of
https://github.com/Horizontal42/Sort_YM.git
synced 2026-11-10 19:11:59 +03:00
catch schema-incomplete ollama responses instead of crashing the batch
This commit is contained in:
parent
12145cc82a
commit
93127e37d8
2 changed files with 21 additions and 4 deletions
|
|
@ -252,16 +252,19 @@ def analyze_tracks(
|
||||||
}
|
}
|
||||||
try:
|
try:
|
||||||
data = call(settings, prompt)
|
data = call(settings, prompt)
|
||||||
|
entry = {**data, **stamp, "key_line_verified": verify_key_line(data["key_line"], text)}
|
||||||
# Широкий except намеренно: трёхчасовой прогон не должен падать целиком из-за
|
# Широкий except намеренно: трёхчасовой прогон не должен падать целиком из-за
|
||||||
# одного зависшего/битого ответа локальной модели. KeyboardInterrupt и SystemExit
|
# одного зависшего/битого ответа локальной модели - в том числе синтаксически
|
||||||
# наследуются от BaseException и сюда не попадают - Ctrl+C прерывает прогон.
|
# валидного JSON без обязательного поля (KeyError здесь же, не только в call()).
|
||||||
|
# KeyboardInterrupt и SystemExit наследуются от BaseException и сюда не попадают -
|
||||||
|
# Ctrl+C прерывает прогон.
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
cache[tid] = {**stamp, "error": f"{type(e).__name__}: {e}"}
|
cache[tid] = {**stamp, "error": f"{type(e).__name__}: {e}"}
|
||||||
failed += 1
|
failed += 1
|
||||||
print(f" [{i}/{len(pending)}] {info['title']} - ошибка: {type(e).__name__}")
|
print(f" [{i}/{len(pending)}] {info['title']} - ошибка: {type(e).__name__}")
|
||||||
else:
|
else:
|
||||||
cache[tid] = {**data, **stamp, "key_line_verified": verify_key_line(data["key_line"], text)}
|
cache[tid] = entry
|
||||||
print(f" [{i}/{len(pending)}] {info['title']} - {', '.join(data['mood'])}")
|
print(f" [{i}/{len(pending)}] {info['title']} - {', '.join(entry.get('mood', []))}")
|
||||||
_atomic_write_json(cache_file, cache)
|
_atomic_write_json(cache_file, cache)
|
||||||
|
|
||||||
if failed:
|
if failed:
|
||||||
|
|
|
||||||
|
|
@ -246,6 +246,20 @@ def test_analyze_records_error_marker_and_continues(tmp_path: Path):
|
||||||
assert result["200"]["summary"] == "Герой бродит по городу.", "таймаут одного трека не роняет батч"
|
assert result["200"]["summary"] == "Герой бродит по городу.", "таймаут одного трека не роняет батч"
|
||||||
|
|
||||||
|
|
||||||
|
def test_analyze_records_error_marker_for_schema_incomplete_response(tmp_path: Path):
|
||||||
|
# Ollama иногда возвращает синтаксически валидный JSON без обязательного поля -
|
||||||
|
# это не исключение внутри call(), падает на доступе к data[...] после успешного возврата.
|
||||||
|
def call(settings, prompt):
|
||||||
|
if "Тоска" in prompt:
|
||||||
|
return {k: v for k, v in GOOD_RESPONSE.items() if k != "key_line"}
|
||||||
|
return dict(GOOD_RESPONSE)
|
||||||
|
|
||||||
|
result = analyze.analyze_tracks(TRACKS, LYRICS, tmp_path, _settings(), call=call)
|
||||||
|
|
||||||
|
assert "KeyError" in result["100"]["error"]
|
||||||
|
assert result["200"]["summary"] == "Герой бродит по городу.", "битый ответ одного трека не роняет батч"
|
||||||
|
|
||||||
|
|
||||||
def test_analyze_retries_error_entries_on_next_run(tmp_path: Path):
|
def test_analyze_retries_error_entries_on_next_run(tmp_path: Path):
|
||||||
def failing(settings, prompt):
|
def failing(settings, prompt):
|
||||||
raise TimeoutError("модель зависла")
|
raise TimeoutError("модель зависла")
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue