[mod] ai_summary plugin: switch to the OpenAI chat completions API
Talk to the LLM server via GET /v1/models and POST /v1/chat/completions (SSE) instead of Ollama's native API. Any OpenAI compatible server now works (Ollama, vLLM, llama.cpp, LM Studio, Hugging Face TGI, ...); Ollama serves this API natively, existing setups keep working unchanged. The Ollama specific keep_alive option is dropped, the ai_summary.grounding setting is added as instance wide default of the grounding preference. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -23,12 +23,12 @@ BASE_URL = "http://127.0.0.1:11434"
|
||||
MODEL = "test-model"
|
||||
|
||||
|
||||
def ollama_stream_mock(lines: list[dict], status_code: int = 200) -> Mock:
|
||||
def sse_stream_mock(lines: list[dict], status_code: int = 200) -> Mock:
|
||||
"""A mock httpx client whose ``stream()`` context manager yields the given
|
||||
(Ollama) NDJSON lines."""
|
||||
objects as a SSE stream (OpenAI chat completions format)."""
|
||||
|
||||
upstream = Mock(status_code=status_code)
|
||||
upstream.iter_lines.return_value = iter([json.dumps(line) for line in lines])
|
||||
upstream.iter_lines.return_value = iter([f"data: {json.dumps(line)}" for line in lines] + ["data: [DONE]"])
|
||||
|
||||
@contextmanager
|
||||
def stream(*_args, **_kwargs):
|
||||
@@ -218,11 +218,11 @@ class PluginAISummary(SearxTestCase):
|
||||
|
||||
def test_endpoint_streams_ndjson(self):
|
||||
self.mock_upstream(
|
||||
ollama_stream_mock(
|
||||
sse_stream_mock(
|
||||
[
|
||||
{"message": {"content": "Hello "}, "done": False},
|
||||
{"message": {"content": "world"}, "done": False},
|
||||
{"done": True},
|
||||
{"choices": [{"delta": {"content": "Hello "}}]},
|
||||
{"choices": [{"delta": {"content": "world"}}]},
|
||||
{"choices": [{"delta": {}, "finish_reason": "stop"}]},
|
||||
]
|
||||
)
|
||||
)
|
||||
@@ -237,7 +237,7 @@ class PluginAISummary(SearxTestCase):
|
||||
self.assertEqual(lines[2], {"done": True, "model": MODEL})
|
||||
|
||||
def test_endpoint_model_pref_wins(self):
|
||||
self.mock_upstream(ollama_stream_mock([{"done": True}]))
|
||||
self.mock_upstream(sse_stream_mock([]))
|
||||
self.client.set_cookie("ai_summary_model", "my-own-model:7b")
|
||||
|
||||
res = self.client.post("/ai_summary", json={"messages": [{"role": "user", "content": "hi"}]})
|
||||
@@ -245,7 +245,7 @@ class PluginAISummary(SearxTestCase):
|
||||
self.assertEqual(lines[-1], {"done": True, "model": "my-own-model:7b"})
|
||||
|
||||
def test_endpoint_upstream_error(self):
|
||||
self.mock_upstream(ollama_stream_mock([], status_code=500))
|
||||
self.mock_upstream(sse_stream_mock([], status_code=500))
|
||||
|
||||
res = self.client.post("/ai_summary", json={"messages": [{"role": "user", "content": "hi"}]})
|
||||
self.assertEqual(res.status_code, 502)
|
||||
@@ -253,7 +253,7 @@ class PluginAISummary(SearxTestCase):
|
||||
def test_endpoint_error_while_streaming(self):
|
||||
upstream = Mock(status_code=200)
|
||||
upstream.iter_lines.return_value = iter(
|
||||
[json.dumps({"message": {"content": "Hello"}, "done": False}), "this is not json"]
|
||||
['data: {"choices": [{"delta": {"content": "Hello"}}]}', "data: this is not json"]
|
||||
)
|
||||
|
||||
@contextmanager
|
||||
|
||||
Reference in New Issue
Block a user