fix(rag): retrieve complete course assignments
This commit is contained in:
@@ -0,0 +1,54 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import asyncio
|
||||
from unittest.mock import AsyncMock, patch
|
||||
|
||||
from app.services.feishu_async_service import _get_docx_content_async
|
||||
from app.services.feishu_service import FeishuRetrievalConfig, _get_docx_content
|
||||
|
||||
|
||||
def _config() -> FeishuRetrievalConfig:
|
||||
return FeishuRetrievalConfig(
|
||||
search_url="",
|
||||
app_id="app-id",
|
||||
app_secret="secret",
|
||||
timeout_seconds=10,
|
||||
retry_count=1,
|
||||
)
|
||||
|
||||
|
||||
def _heading(text: str) -> dict:
|
||||
return {
|
||||
"block_type": 3,
|
||||
"heading1": {"elements": [{"text_run": {"content": text}}]},
|
||||
}
|
||||
|
||||
|
||||
def test_docx_content_reads_all_block_pages():
|
||||
pages = [
|
||||
{"data": {"items": [_heading("第一页")], "has_more": True, "page_token": "next-page"}},
|
||||
{"data": {"items": [_heading("第二页作业")], "has_more": False, "page_token": ""}},
|
||||
]
|
||||
with patch("app.services.feishu_service._feishu_get", side_effect=pages) as feishu_get:
|
||||
content = _get_docx_content("doc-token", _config())
|
||||
|
||||
assert "第一页" in content
|
||||
assert "第二页作业" in content
|
||||
assert feishu_get.call_count == 2
|
||||
assert feishu_get.call_args_list[0].kwargs["params"] == {"page_size": 500}
|
||||
assert feishu_get.call_args_list[1].kwargs["params"] == {"page_size": 500, "page_token": "next-page"}
|
||||
|
||||
|
||||
def test_async_docx_content_reads_all_block_pages():
|
||||
pages = [
|
||||
{"data": {"items": [_heading("第一页")], "has_more": True, "page_token": "next-page"}},
|
||||
{"data": {"items": [_heading("第二页作业")], "has_more": False, "page_token": ""}},
|
||||
]
|
||||
feishu_get = AsyncMock(side_effect=pages)
|
||||
with patch("app.services.feishu_async_service._feishu_get_async", feishu_get):
|
||||
content = asyncio.run(_get_docx_content_async("doc-token", _config()))
|
||||
|
||||
assert "第一页" in content
|
||||
assert "第二页作业" in content
|
||||
assert feishu_get.await_count == 2
|
||||
assert feishu_get.await_args_list[1].kwargs["params"] == {"page_size": 500, "page_token": "next-page"}
|
||||
@@ -4,7 +4,7 @@ import asyncio
|
||||
import json
|
||||
from datetime import datetime
|
||||
|
||||
from sqlalchemy import create_engine
|
||||
from sqlalchemy import create_engine, select
|
||||
from sqlalchemy.orm import Session
|
||||
from sqlalchemy.pool import StaticPool
|
||||
|
||||
@@ -141,6 +141,13 @@ def test_course_question_searches_chunk_and_reads_parent_section():
|
||||
assert len(result.chunks) == 1
|
||||
assert "先稳定自己的焦虑" in result.chunks[0].content
|
||||
assert any(item["tool"] == "read_knowledge_sections" for item in result.tool_trace)
|
||||
knowledge_context = next(
|
||||
message["content"] for message in result.messages if message["content"].startswith("[本轮可靠知识上下文]")
|
||||
)
|
||||
assert "不得再以‘没有资料’" in knowledge_context
|
||||
assert "不要求知识库中必须存在一个" in knowledge_context
|
||||
assert "不要把本轮已经取到的内容留到下一轮再问" in knowledge_context
|
||||
assert "来源知识库:亲子课程" in knowledge_context
|
||||
|
||||
|
||||
def test_tool_trace_serializes_published_datetime():
|
||||
@@ -173,3 +180,57 @@ def test_contextual_follow_up_is_rewritten_before_agent_decision():
|
||||
|
||||
assert rewrite["rewrittenQuestion"] == "关于“课程退款条件有哪些?”的追问:那第二种情况呢?"
|
||||
assert decision["request"]["question"] == rewrite["rewrittenQuestion"]
|
||||
|
||||
|
||||
def test_homework_overview_expands_practice_terms_and_section_limit():
|
||||
terms = KnowledgeAgentService._query_terms("合一的作业是什么?")
|
||||
|
||||
assert "功课" in terms
|
||||
assert "练习" in terms
|
||||
assert KnowledgeAgentService._selection_limit("合一的作业是什么?") == 8
|
||||
assert KnowledgeAgentService._selection_limit("这个练习怎么做?") == 4
|
||||
assert KnowledgeAgentService._title_intent_boost("十七、练习一:风铃式静心", terms) == 20.0
|
||||
assert KnowledgeAgentService._title_intent_boost("完整练习的方向", terms) == 3.0
|
||||
assert KnowledgeAgentService._title_intent_boost("课程定位", terms) == 0.0
|
||||
|
||||
|
||||
def test_complete_section_includes_child_headings_but_stops_at_next_peer():
|
||||
with _database() as db:
|
||||
knowledge = _add_published_knowledge(db, knowledge_id=1, name="合一课程")
|
||||
version_id = knowledge.current_version_id
|
||||
parent = db.scalar(select(KnowledgeSection).where(KnowledgeSection.version_id == version_id))
|
||||
assert parent is not None
|
||||
parent.title = "练习一:风铃式静心"
|
||||
parent.content = "# 练习一:风铃式静心"
|
||||
parent.sort_order = 1
|
||||
db.add_all([
|
||||
parent,
|
||||
KnowledgeSection(
|
||||
knowledge_id=knowledge.id,
|
||||
version_id=version_id,
|
||||
section_key="S0002",
|
||||
title="基本操作",
|
||||
content="## 基本操作\n鼻吸鼻呼,呼气时发出连续蜂鸣声。",
|
||||
source_start=10,
|
||||
source_end=40,
|
||||
sort_order=2,
|
||||
content_hash="child",
|
||||
),
|
||||
KnowledgeSection(
|
||||
knowledge_id=knowledge.id,
|
||||
version_id=version_id,
|
||||
section_key="S0003",
|
||||
title="练习二:内感知建模",
|
||||
content="# 练习二:内感知建模\n这是下一项作业。",
|
||||
source_start=41,
|
||||
source_end=70,
|
||||
sort_order=3,
|
||||
content_hash="next",
|
||||
),
|
||||
])
|
||||
db.commit()
|
||||
|
||||
content = KnowledgeAgentService._read_complete_section(db, parent)
|
||||
|
||||
assert "鼻吸鼻呼" in content
|
||||
assert "下一项作业" not in content
|
||||
|
||||
Reference in New Issue
Block a user