import pytest from poetic.interpretation import build_interpret_contents, parse_interpretation def test_includes_poem_and_correction(): c = build_interpret_contents("床前明月光", "要更温暖的色调") assert "床前明月光" in c assert "要更温暖的色调" in c def test_omits_correction_line_when_none_given(): c = build_interpret_contents("床前明月光") assert "更正" not in c assert "correction" not in c.lower() def test_parses_guaranteed_json_into_both_fields(): out = parse_interpretation('{"understandingZh":"一幅月夜图","briefEn":"A moonlit night"}') assert out.understanding_zh == "一幅月夜图" assert out.brief_en == "A moonlit night" def test_raises_clear_error_on_malformed_json(): with pytest.raises(ValueError, match="[Ii]nterpretation"): parse_interpretation("not json") def test_raises_when_fields_missing(): with pytest.raises(ValueError, match="[Ii]nterpretation"): parse_interpretation('{"understandingZh":"只有一半"}') # The local/remote LLMs (MiniCPM, Qwen) have no enforced JSON mode like Vertex AI's # response schema, so the parser must repair the two common wrappings. def test_strips_markdown_code_fences(): text = '```json\n{"understandingZh":"月夜","briefEn":"moonlit"}\n```' out = parse_interpretation(text) assert out.understanding_zh == "月夜" assert out.brief_en == "moonlit" def test_extracts_json_object_from_surrounding_prose(): text = '好的,以下是结果:{"understandingZh":"月夜","briefEn":"moonlit"} 希望您喜欢。' out = parse_interpretation(text) assert out.brief_en == "moonlit" def test_repairs_json_escaped_json(): # Verbatim failure mode from MiniCPM4.1 on ZeroGPU: the whole object is # emitted with escaped quotes and newlines, as if nested inside a string. text = '{\\n \\"understandingZh\\": \\"筝声悠扬,渐远渐行。\\",\\n \\"briefEn\\": \\"A painting of a distant scene.\\"}' out = parse_interpretation(text) assert out.understanding_zh == "筝声悠扬,渐远渐行。" assert out.brief_en == "A painting of a distant scene." def test_rescues_truncated_unterminated_json(): # Verbatim from ZeroGPU: escaped JSON that stops before the closing brace. text = ( '{\\n \\"understandingZh\\": \\"这首诗描绘了筝弦的悠扬与狂风的动荡。\\",' '\\n \\"briefEn\\": \\"a painting only — featuring a distant journey,' ' the scene filled with depth and movement.\\"' ) out = parse_interpretation(text) assert out.understanding_zh == "这首诗描绘了筝弦的悠扬与狂风的动荡。" assert out.brief_en.startswith("a painting only") assert out.brief_en.endswith("movement.") def test_tolerates_literal_newlines_inside_string_values(): # Seen live from MiniCPM on ZeroGPU: valid-looking JSON with real newline # characters inside the string values (invalid in strict JSON). text = '{\n "understandingZh": "第一句。\n第二句。",\n "briefEn": "line one\nline two"\n}' out = parse_interpretation(text) assert "第二句" in out.understanding_zh assert "line two" in out.brief_en