New llm FastAPI service (src/llm/api.py + rag.py + web/chat.html): grounded streaming chat over indexed comments with cited sources. Own image, compose service, Traefik reef entry with git-sso, llm subdomain registered. Dashboard tile + README row. stack llm serve CLI.
66 lines
1.9 KiB
Python
66 lines
1.9 KiB
Python
"""llm.api — FastAPI chat app."""
|
|
|
|
from unittest.mock import patch
|
|
|
|
from fastapi.testclient import TestClient
|
|
|
|
from llm.api import app
|
|
|
|
client = TestClient(app)
|
|
|
|
|
|
class TestHealth:
|
|
def test_ok(self):
|
|
r = client.get("/health")
|
|
assert r.status_code == 200
|
|
assert r.json() == {"status": "ok"}
|
|
|
|
|
|
class TestIndex:
|
|
def test_serves_chat_page(self):
|
|
r = client.get("/")
|
|
assert r.status_code == 200
|
|
assert "text/html" in r.headers["content-type"]
|
|
assert "Comment Chat" in r.text
|
|
assert 'id="form"' in r.text
|
|
|
|
|
|
class TestWhoami:
|
|
def test_reads_forwarded_header(self):
|
|
r = client.get("/whoami", headers={"X-Auth-Request-User": "kert"})
|
|
assert r.json() == {"user": "kert"}
|
|
|
|
def test_empty_when_absent(self):
|
|
r = client.get("/whoami")
|
|
assert r.json() == {"user": ""}
|
|
|
|
|
|
class TestChat:
|
|
def test_empty_question_400(self):
|
|
r = client.post("/chat", json={"question": " "})
|
|
assert r.status_code == 400
|
|
|
|
@patch("llm.rag.stream_answer")
|
|
def test_streams_sse_events(self, mock_stream):
|
|
mock_stream.return_value = iter(
|
|
[
|
|
{"type": "token", "text": "Hi"},
|
|
{"type": "sources", "sources": []},
|
|
{"type": "done"},
|
|
]
|
|
)
|
|
r = client.post("/chat", json={"question": "hello"})
|
|
assert r.status_code == 200
|
|
assert "text/event-stream" in r.headers["content-type"]
|
|
body = r.text
|
|
assert 'data: {"type": "token", "text": "Hi"}' in body
|
|
assert '"type": "done"' in body
|
|
|
|
@patch("llm.rag.stream_answer")
|
|
def test_error_becomes_event_not_500(self, mock_stream):
|
|
mock_stream.side_effect = RuntimeError("ollama down")
|
|
r = client.post("/chat", json={"question": "hello"})
|
|
assert r.status_code == 200
|
|
assert '"type": "error"' in r.text
|
|
assert "ollama down" in r.text
|