chore: import upstream snapshot with attribution
This commit is contained in:
@@ -0,0 +1,153 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import pytest
|
||||
|
||||
from yuxi.knowledge.implementations.dify import DifyKB
|
||||
|
||||
|
||||
class _FakeResponse:
|
||||
def __init__(self, payload: dict):
|
||||
self._payload = payload
|
||||
|
||||
def raise_for_status(self) -> None:
|
||||
return None
|
||||
|
||||
def json(self) -> dict:
|
||||
return self._payload
|
||||
|
||||
|
||||
class _FakeAsyncClient:
|
||||
def __init__(self, response_payload: dict | None = None, raises: Exception | None = None, **kwargs):
|
||||
del kwargs
|
||||
self._response_payload = response_payload or {}
|
||||
self._raises = raises
|
||||
|
||||
async def __aenter__(self):
|
||||
return self
|
||||
|
||||
async def __aexit__(self, exc_type, exc_val, exc_tb):
|
||||
return False
|
||||
|
||||
async def post(self, url: str, json: dict, headers: dict):
|
||||
assert "/datasets/" in url
|
||||
assert headers.get("Authorization", "").startswith("Bearer ")
|
||||
if self._raises:
|
||||
raise self._raises
|
||||
assert json["retrieval_model"]["search_method"] == "semantic_search"
|
||||
assert json["retrieval_model"]["top_k"] == 5
|
||||
assert json["retrieval_model"]["reranking_enable"] is False
|
||||
assert json["retrieval_model"]["score_threshold_enabled"] is True
|
||||
assert json["retrieval_model"]["score_threshold"] == 0.3
|
||||
return _FakeResponse(self._response_payload)
|
||||
|
||||
|
||||
def test_dify_create_params_config_and_validation():
|
||||
config = DifyKB.get_create_params_config()
|
||||
keys = [option["key"] for option in config["options"]]
|
||||
assert keys == ["dify_api_url", "dify_token", "dify_dataset_id"]
|
||||
assert all(option["required"] for option in config["options"])
|
||||
|
||||
params = DifyKB.normalize_additional_params(
|
||||
{
|
||||
"dify_api_url": " https://api.dify.ai/v1 ",
|
||||
"dify_token": " token ",
|
||||
"dify_dataset_id": " dataset-123 ",
|
||||
}
|
||||
)
|
||||
assert params == {
|
||||
"dify_api_url": "https://api.dify.ai/v1",
|
||||
"dify_token": "token",
|
||||
"dify_dataset_id": "dataset-123",
|
||||
}
|
||||
assert "chunk_preset_id" not in params
|
||||
|
||||
|
||||
def test_dify_validation_rejects_missing_or_invalid_params():
|
||||
with pytest.raises(ValueError, match="Dify 参数缺失"):
|
||||
DifyKB.normalize_additional_params({"dify_api_url": "https://api.dify.ai/v1"})
|
||||
|
||||
with pytest.raises(ValueError, match="必须以 /v1 结尾"):
|
||||
DifyKB.normalize_additional_params(
|
||||
{
|
||||
"dify_api_url": "https://api.dify.ai",
|
||||
"dify_token": "token",
|
||||
"dify_dataset_id": "dataset-123",
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_dify_kb_aquery_maps_records(monkeypatch, tmp_path):
|
||||
kb = DifyKB(str(tmp_path))
|
||||
slug = "kb_test_dify"
|
||||
kb.databases_meta[slug] = {
|
||||
"name": "dify-kb",
|
||||
"description": "test",
|
||||
"kb_type": "dify",
|
||||
"query_params": {
|
||||
"options": {
|
||||
"search_mode": "vector",
|
||||
"final_top_k": 5,
|
||||
"score_threshold_enabled": True,
|
||||
"similarity_threshold": 0.3,
|
||||
}
|
||||
},
|
||||
"metadata": {
|
||||
"dify_api_url": "https://api.dify.ai/v1",
|
||||
"dify_token": "token",
|
||||
"dify_dataset_id": "dataset-123",
|
||||
},
|
||||
}
|
||||
|
||||
payload = {
|
||||
"records": [
|
||||
{
|
||||
"score": 0.98,
|
||||
"segment": {
|
||||
"id": "seg-1",
|
||||
"position": 2,
|
||||
"content": "hello world",
|
||||
"document": {"id": "doc-1", "name": "Doc One"},
|
||||
},
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
monkeypatch.setattr(
|
||||
"yuxi.knowledge.implementations.dify.httpx.AsyncClient",
|
||||
lambda **kwargs: _FakeAsyncClient(response_payload=payload, **kwargs),
|
||||
)
|
||||
|
||||
result = await kb.aquery("hello", slug)
|
||||
assert len(result) == 1
|
||||
assert result[0]["content"] == "hello world"
|
||||
assert result[0]["score"] == 0.98
|
||||
assert result[0]["metadata"]["source"] == "Doc One"
|
||||
assert result[0]["metadata"]["file_id"] == "doc-1"
|
||||
assert result[0]["metadata"]["chunk_id"] == "seg-1"
|
||||
assert result[0]["metadata"]["chunk_index"] == 2
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_dify_kb_aquery_error_returns_empty(monkeypatch, tmp_path):
|
||||
kb = DifyKB(str(tmp_path))
|
||||
slug = "kb_test_dify_error"
|
||||
kb.databases_meta[slug] = {
|
||||
"name": "dify-kb",
|
||||
"description": "test",
|
||||
"kb_type": "dify",
|
||||
"query_params": {"options": {}},
|
||||
"metadata": {
|
||||
"dify_api_url": "https://api.dify.ai/v1",
|
||||
"dify_token": "token",
|
||||
"dify_dataset_id": "dataset-123",
|
||||
},
|
||||
}
|
||||
|
||||
monkeypatch.setattr(
|
||||
"yuxi.knowledge.implementations.dify.httpx.AsyncClient",
|
||||
lambda **kwargs: _FakeAsyncClient(raises=RuntimeError("boom"), **kwargs),
|
||||
)
|
||||
|
||||
result = await kb.aquery("hello", slug)
|
||||
assert result == []
|
||||
Reference in New Issue
Block a user