mirror of
https://github.com/primedigitaltech/market-assistant.git
synced 2026-07-22 08:01:34 +08:00
test(pipeline): run llm_keyword_suggest against real LLM when keys set
Remove mock; load market_assistant/.env before checking credentials. Live test skips without OPENAI_* or LLM_* key+base URL. Made-with: Cursor
This commit is contained in:
parent
be0215bfe2
commit
bca19fd845
110
backend/pipeline/tests/test_llm_keyword_suggest.py
Normal file
110
backend/pipeline/tests/test_llm_keyword_suggest.py
Normal file
@ -0,0 +1,110 @@
|
||||
"""llm_keyword_suggest:分块/解析烟测;有 API 配置时直连大模型做联调。"""
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
import unittest
|
||||
from pathlib import Path
|
||||
|
||||
try:
|
||||
from dotenv import load_dotenv
|
||||
|
||||
_ma_env = Path(__file__).resolve().parents[3] / ".env"
|
||||
if _ma_env.is_file():
|
||||
load_dotenv(_ma_env)
|
||||
except ImportError:
|
||||
pass
|
||||
|
||||
from django.test import SimpleTestCase
|
||||
|
||||
from pipeline.llm_keyword_suggest import (
|
||||
MAX_CHUNK_CHARS,
|
||||
MAX_CHUNKS,
|
||||
_chunk_comment_texts,
|
||||
_parse_phrases_object,
|
||||
suggest_focus_keywords_from_all_comments,
|
||||
)
|
||||
|
||||
|
||||
def _llm_configured() -> bool:
|
||||
key = (os.environ.get("OPENAI_API_KEY") or os.environ.get("LLM_API_KEY") or "").strip()
|
||||
base = (os.environ.get("OPENAI_BASE_URL") or os.environ.get("LLM_BASE_URL") or "").strip()
|
||||
return bool(key and base)
|
||||
|
||||
|
||||
class ChunkCommentTextsTests(SimpleTestCase):
|
||||
def test_empty(self) -> None:
|
||||
self.assertEqual(_chunk_comment_texts([]), [])
|
||||
|
||||
def test_respects_max_chunk_chars(self) -> None:
|
||||
a = "x" * (MAX_CHUNK_CHARS // 2)
|
||||
b = "y" * (MAX_CHUNK_CHARS // 2)
|
||||
c = "z" * (MAX_CHUNK_CHARS // 2)
|
||||
parts = _chunk_comment_texts([a, b, c])
|
||||
self.assertGreaterEqual(len(parts), 2)
|
||||
for p in parts:
|
||||
self.assertLessEqual(len(p) + p.count("\n"), MAX_CHUNK_CHARS + 50)
|
||||
|
||||
def test_max_chunks_trims(self) -> None:
|
||||
texts = [f"段落{i} " + "字" * 800 for i in range(80)]
|
||||
parts = _chunk_comment_texts(texts)
|
||||
self.assertLessEqual(len(parts), MAX_CHUNKS)
|
||||
|
||||
|
||||
class ParsePhrasesObjectTests(SimpleTestCase):
|
||||
def test_plain_json(self) -> None:
|
||||
raw = '{"phrases": ["低糖", "口感好"]}'
|
||||
self.assertEqual(_parse_phrases_object(raw), ["低糖", "口感好"])
|
||||
|
||||
def test_fenced_json(self) -> None:
|
||||
raw = '```json\n{"phrases": ["A", "B"]}\n```'
|
||||
self.assertEqual(_parse_phrases_object(raw), ["A", "B"])
|
||||
|
||||
def test_embedded_object(self) -> None:
|
||||
raw = '前缀 {"phrases": ["x"]} 后缀'
|
||||
self.assertEqual(_parse_phrases_object(raw), ["x"])
|
||||
|
||||
def test_invalid_returns_empty(self) -> None:
|
||||
self.assertEqual(_parse_phrases_object("not json"), [])
|
||||
|
||||
|
||||
class SuggestFocusKeywordsTests(SimpleTestCase):
|
||||
def test_no_comments_returns_empty(self) -> None:
|
||||
out = suggest_focus_keywords_from_all_comments(
|
||||
keyword="低GI",
|
||||
brief_slice={"comment_focus_keywords": []},
|
||||
all_comment_texts=[],
|
||||
)
|
||||
self.assertEqual(out["suggested_focus_keywords"], [])
|
||||
self.assertEqual(out["chunks_processed"], 0)
|
||||
self.assertIn("无评价", out["rationale"])
|
||||
|
||||
|
||||
@unittest.skipUnless(
|
||||
_llm_configured(),
|
||||
"需要环境变量 OPENAI_API_KEY+OPENAI_BASE_URL(或 LLM_API_KEY+LLM_BASE_URL),"
|
||||
"与 AI_crawler 相同;可在 market_assistant/.env 配置后重跑。",
|
||||
)
|
||||
class SuggestFocusKeywordsLiveLLMTests(SimpleTestCase):
|
||||
"""直连网关调用 ``chat_completion_text``,会消耗少量 token。"""
|
||||
|
||||
def test_live_extracts_phrases_from_comments(self) -> None:
|
||||
comments = [
|
||||
"低GI饼干口感偏硬,甜度刚好,饱腹感不错。",
|
||||
"物流有点慢,包装压扁了一角,但味道还行。",
|
||||
"希望出小包装,一次吃不完容易受潮。",
|
||||
]
|
||||
out = suggest_focus_keywords_from_all_comments(
|
||||
keyword="低GI饼干",
|
||||
brief_slice={"comment_focus_keywords": [{"word": "甜度"}]},
|
||||
all_comment_texts=comments,
|
||||
)
|
||||
self.assertGreaterEqual(out["chunks_processed"], 1)
|
||||
self.assertEqual(out["total_comment_texts"], 3)
|
||||
kws = out["suggested_focus_keywords"]
|
||||
self.assertIsInstance(kws, list)
|
||||
self.assertGreater(len(kws), 0, "模型应返回至少 1 条短语")
|
||||
for p in kws:
|
||||
self.assertIsInstance(p, str)
|
||||
self.assertGreaterEqual(len(p), 2)
|
||||
self.assertLessEqual(len(p), 24)
|
||||
self.assertNotIn("甜度", kws)
|
||||
Loading…
x
Reference in New Issue
Block a user