127 lines
3.9 KiB
Python
127 lines
3.9 KiB
Python
"""script-processing extract 缓存测试。"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import pytest
|
|
|
|
from app.api.v1.routes import script_processing as route
|
|
from app.schemas.skills.script_processing import StudioScriptExtractionDraft
|
|
from app.services.script_extraction_cache import (
|
|
build_script_extract_cache_key,
|
|
clear_script_extract_cache,
|
|
)
|
|
|
|
|
|
def _build_result() -> StudioScriptExtractionDraft:
|
|
return StudioScriptExtractionDraft(
|
|
project_id="project-1",
|
|
chapter_id="chapter-1",
|
|
script_text="测试文本",
|
|
characters=[],
|
|
scenes=[],
|
|
props=[],
|
|
costumes=[],
|
|
shots=[],
|
|
)
|
|
|
|
|
|
class _FakeDB:
|
|
def __init__(self) -> None:
|
|
self.committed = False
|
|
|
|
async def commit(self) -> None:
|
|
self.committed = True
|
|
|
|
|
|
async def _async_noop(*_args, **_kwargs) -> None:
|
|
return None
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_extract_script_uses_cache_by_default(monkeypatch):
|
|
clear_script_extract_cache()
|
|
calls: list[str] = []
|
|
db = _FakeDB()
|
|
|
|
class _FakeAgent:
|
|
def __init__(self, _llm):
|
|
pass
|
|
|
|
def extract(self, **_kwargs):
|
|
calls.append("extract")
|
|
return _build_result()
|
|
|
|
monkeypatch.setattr(route, "ElementExtractorAgent", _FakeAgent)
|
|
monkeypatch.setattr(route, "sync_shot_extracted_candidates_from_draft", _async_noop)
|
|
monkeypatch.setattr(route, "sync_shot_extracted_dialogue_candidates_from_draft", _async_noop)
|
|
monkeypatch.setattr(route, "apply_shot_semantic_defaults_from_draft", _async_noop)
|
|
|
|
request = route.ScriptExtractRequest(
|
|
project_id="project-1",
|
|
chapter_id="chapter-1",
|
|
script_division={"total_shots": 1, "shots": [{"index": 1, "script_excerpt": "a", "shot_name": "s"}]},
|
|
consistency=None,
|
|
refresh_cache=False,
|
|
)
|
|
|
|
first = await route.extract_script(request, llm=None, db=db)
|
|
second = await route.extract_script(request, llm=None, db=db)
|
|
|
|
assert first.data is not None
|
|
assert second.data is not None
|
|
assert first.meta == {"from_cache": False}
|
|
assert second.meta == {"from_cache": True}
|
|
assert len(calls) == 1
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_extract_script_refresh_cache_forces_recompute(monkeypatch):
|
|
clear_script_extract_cache()
|
|
calls: list[str] = []
|
|
db = _FakeDB()
|
|
|
|
class _FakeAgent:
|
|
def __init__(self, _llm):
|
|
pass
|
|
|
|
def extract(self, **_kwargs):
|
|
calls.append("extract")
|
|
return _build_result()
|
|
|
|
monkeypatch.setattr(route, "ElementExtractorAgent", _FakeAgent)
|
|
monkeypatch.setattr(route, "sync_shot_extracted_candidates_from_draft", _async_noop)
|
|
monkeypatch.setattr(route, "sync_shot_extracted_dialogue_candidates_from_draft", _async_noop)
|
|
monkeypatch.setattr(route, "apply_shot_semantic_defaults_from_draft", _async_noop)
|
|
|
|
request = route.ScriptExtractRequest(
|
|
project_id="project-1",
|
|
chapter_id="chapter-1",
|
|
script_division={"total_shots": 1, "shots": [{"index": 1, "script_excerpt": "a", "shot_name": "s"}]},
|
|
consistency=None,
|
|
refresh_cache=False,
|
|
)
|
|
refresh_request = request.model_copy(update={"refresh_cache": True})
|
|
|
|
await route.extract_script(request, llm=None, db=db)
|
|
refreshed = await route.extract_script(refresh_request, llm=None, db=db)
|
|
|
|
assert refreshed.meta == {"from_cache": False}
|
|
assert len(calls) == 2
|
|
|
|
|
|
def test_build_script_extract_cache_key_changes_when_payload_changes():
|
|
key1 = build_script_extract_cache_key(
|
|
project_id="project-1",
|
|
chapter_id="chapter-1",
|
|
script_division={"total_shots": 1, "shots": [{"index": 1}]},
|
|
consistency=None,
|
|
)
|
|
key2 = build_script_extract_cache_key(
|
|
project_id="project-1",
|
|
chapter_id="chapter-1",
|
|
script_division={"total_shots": 2, "shots": [{"index": 1}, {"index": 2}]},
|
|
consistency=None,
|
|
)
|
|
|
|
assert key1 != key2
|