127 lines
4.4 KiB
Python
127 lines
4.4 KiB
Python
import json
|
|
|
|
import httpx
|
|
import pytest
|
|
|
|
from ai_platform.infrastructure.aihub import AiHubClient, AiHubError
|
|
from ai_platform.lead_scoring.application.scoring_execution_repository import Evidence
|
|
from ai_platform.lead_scoring.application.scoring_prompts import (
|
|
scoring_system_prompt,
|
|
scoring_user_prompt,
|
|
)
|
|
|
|
VKEY = "request-only-vkey-test-secret"
|
|
|
|
|
|
def completion(content: str) -> httpx.Response:
|
|
return httpx.Response(
|
|
200,
|
|
json={"choices": [{"message": {"content": content}}]},
|
|
)
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_two_pass_adapter_uses_same_model_timeout_and_vkey_without_putting_key_in_prompts():
|
|
requests: list[httpx.Request] = []
|
|
|
|
def handler(request: httpx.Request) -> httpx.Response:
|
|
requests.append(request)
|
|
body = json.loads(request.content)
|
|
assert body["model"] == "openai/gpt-4o-mini"
|
|
assert body["stream"] is False
|
|
assert body["response_format"] == {"type": "json_object"}
|
|
assert request.headers["authorization"] == f"Bearer {VKEY}"
|
|
assert request.extensions["timeout"]["read"] == 7
|
|
return completion(
|
|
'{"items":[{"signal":"ý định","detail":"Hỏi điều kiện đăng ký","source":"message-1"}]}'
|
|
if len(requests) == 1
|
|
else '{"score":81,"confidence":0.91,"reasoning":"Quan tâm rõ ràng"}'
|
|
)
|
|
|
|
http_client = httpx.AsyncClient(transport=httpx.MockTransport(handler))
|
|
client = AiHubClient("https://aihub.test", http_client)
|
|
snapshot = {
|
|
"lead_profile": {"name": "Example", "custom_fields": {"region": "north"}},
|
|
"conversations": [
|
|
{
|
|
"messages": [
|
|
{
|
|
"message_id": "message-1",
|
|
"sender_type": "contact",
|
|
"content": "Please send me requirements.",
|
|
}
|
|
]
|
|
}
|
|
],
|
|
}
|
|
try:
|
|
evidence = await client.extract_evidence(
|
|
model="openai/gpt-4o-mini", snapshot=snapshot, vkey=VKEY, timeout=7
|
|
)
|
|
score = await client.score(
|
|
model="openai/gpt-4o-mini",
|
|
system_prompt=scoring_system_prompt("Đánh giá theo hồ sơ AI đã cấu hình."),
|
|
user_prompt=scoring_user_prompt(
|
|
snapshot,
|
|
[Evidence(item.signal, item.detail, item.source) for item in evidence.items],
|
|
),
|
|
vkey=VKEY,
|
|
timeout=7,
|
|
)
|
|
finally:
|
|
await client.aclose()
|
|
|
|
assert score.score == 81
|
|
assert score.confidence == 0.91
|
|
assert len(requests) == 2
|
|
for request in requests:
|
|
body = json.loads(request.content)
|
|
prompt = " ".join(message["content"] for message in body["messages"])
|
|
assert VKEY not in prompt
|
|
assert '"points"' not in prompt
|
|
assert '"rule_weight"' not in prompt
|
|
assert '"ai_weight"' not in prompt
|
|
assert "message-1" in json.loads(requests[0].content)["messages"][1]["content"]
|
|
assert "EVIDENCE" in json.loads(requests[1].content)["messages"][1]["content"]
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_aihub_errors_have_stable_codes_and_do_not_expose_response_or_request_secret():
|
|
def handler(_request: httpx.Request) -> httpx.Response:
|
|
return httpx.Response(429, text=f"private response mentions {VKEY}")
|
|
|
|
client = AiHubClient(
|
|
"https://aihub.test", httpx.AsyncClient(transport=httpx.MockTransport(handler))
|
|
)
|
|
try:
|
|
with pytest.raises(AiHubError) as error:
|
|
await client.extract_evidence(model="openai/gpt-4o-mini", snapshot={}, vkey=VKEY)
|
|
finally:
|
|
await client.aclose()
|
|
|
|
assert error.value.error_code == "aihub_http_error"
|
|
assert VKEY not in str(error.value)
|
|
assert "private response" not in str(error.value)
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_aihub_rejects_response_that_echoes_request_vkey():
|
|
client = AiHubClient(
|
|
"https://aihub.test",
|
|
httpx.AsyncClient(
|
|
transport=httpx.MockTransport(
|
|
lambda _request: completion(
|
|
json.dumps({"items": [{"signal": "s", "detail": VKEY, "source": "m"}]})
|
|
)
|
|
)
|
|
),
|
|
)
|
|
try:
|
|
with pytest.raises(AiHubError) as error:
|
|
await client.extract_evidence(model="openai/gpt-4o-mini", snapshot={}, vkey=VKEY)
|
|
finally:
|
|
await client.aclose()
|
|
|
|
assert error.value.error_code == "aihub_invalid_response"
|
|
assert VKEY not in str(error.value)
|