- Introduced SiteAssistant component to assist users in selecting the right tools based on their queries. - Integrated assistant into the main App component. - Implemented message handling and storage for user-assistant interactions. - Added quick prompts for common user queries related to tools. - Enhanced ToolLandingPage and DownloadButton components with SharePanel for sharing tool results. - Updated translations for new assistant features and sharing options. - Added API methods for chat functionality with the assistant, including streaming responses.
119 lines
4.9 KiB
Python
119 lines
4.9 KiB
Python
"""Tests for shared OpenRouter configuration resolution across AI services."""
|
|
|
|
from app.services.openrouter_config_service import get_openrouter_settings
|
|
from app.services.pdf_ai_service import _call_openrouter
|
|
from app.services.site_assistant_service import _request_ai_reply
|
|
|
|
|
|
class _FakeResponse:
|
|
def __init__(self, payload):
|
|
self._payload = payload
|
|
|
|
def raise_for_status(self):
|
|
return None
|
|
|
|
def json(self):
|
|
return self._payload
|
|
|
|
|
|
class TestOpenRouterConfigService:
|
|
def test_prefers_flask_config_when_app_context_exists(self, app, monkeypatch):
|
|
monkeypatch.setenv('OPENROUTER_API_KEY', 'env-key')
|
|
monkeypatch.setenv('OPENROUTER_MODEL', 'env-model')
|
|
monkeypatch.setenv('OPENROUTER_BASE_URL', 'https://env.example/api')
|
|
|
|
with app.app_context():
|
|
app.config.update({
|
|
'OPENROUTER_API_KEY': 'config-key',
|
|
'OPENROUTER_MODEL': 'config-model',
|
|
'OPENROUTER_BASE_URL': 'https://config.example/api',
|
|
})
|
|
settings = get_openrouter_settings()
|
|
|
|
assert settings.api_key == 'config-key'
|
|
assert settings.model == 'config-model'
|
|
assert settings.base_url == 'https://config.example/api'
|
|
|
|
def test_falls_back_to_environment_without_app_context(self, monkeypatch):
|
|
monkeypatch.setenv('OPENROUTER_API_KEY', 'env-key')
|
|
monkeypatch.setenv('OPENROUTER_MODEL', 'env-model')
|
|
monkeypatch.setenv('OPENROUTER_BASE_URL', 'https://env.example/api')
|
|
|
|
settings = get_openrouter_settings()
|
|
|
|
assert settings.api_key == 'env-key'
|
|
assert settings.model == 'env-model'
|
|
assert settings.base_url == 'https://env.example/api'
|
|
|
|
|
|
class TestAiServicesUseSharedConfig:
|
|
def test_pdf_ai_uses_flask_config(self, app, monkeypatch):
|
|
captured = {}
|
|
|
|
monkeypatch.setattr('app.services.ai_cost_service.check_ai_budget', lambda: None)
|
|
monkeypatch.setattr('app.services.ai_cost_service.log_ai_usage', lambda **kwargs: captured.setdefault('usage', kwargs))
|
|
|
|
def fake_post(url, headers, json, timeout):
|
|
captured['url'] = url
|
|
captured['headers'] = headers
|
|
captured['json'] = json
|
|
captured['timeout'] = timeout
|
|
return _FakeResponse({
|
|
'choices': [{'message': {'content': 'Configured PDF reply'}}],
|
|
'usage': {'prompt_tokens': 11, 'completion_tokens': 7},
|
|
})
|
|
|
|
monkeypatch.setattr('app.services.pdf_ai_service.requests.post', fake_post)
|
|
|
|
with app.app_context():
|
|
app.config.update({
|
|
'OPENROUTER_API_KEY': 'config-key',
|
|
'OPENROUTER_MODEL': 'config-model',
|
|
'OPENROUTER_BASE_URL': 'https://config.example/pdf-ai',
|
|
})
|
|
reply = _call_openrouter('system prompt', 'user question', max_tokens=321, tool_name='pdf_chat')
|
|
|
|
assert reply == 'Configured PDF reply'
|
|
assert captured['url'] == 'https://config.example/pdf-ai'
|
|
assert captured['headers']['Authorization'] == 'Bearer config-key'
|
|
assert captured['json']['model'] == 'config-model'
|
|
assert captured['json']['max_tokens'] == 321
|
|
assert captured['usage']['model'] == 'config-model'
|
|
|
|
def test_site_assistant_uses_flask_config(self, app, monkeypatch):
|
|
captured = {}
|
|
|
|
monkeypatch.setattr('app.services.site_assistant_service.log_ai_usage', lambda **kwargs: captured.setdefault('usage', kwargs))
|
|
|
|
def fake_post(url, headers, json, timeout):
|
|
captured['url'] = url
|
|
captured['headers'] = headers
|
|
captured['json'] = json
|
|
captured['timeout'] = timeout
|
|
return _FakeResponse({
|
|
'choices': [{'message': {'content': 'Configured assistant reply'}}],
|
|
'usage': {'prompt_tokens': 13, 'completion_tokens': 9},
|
|
})
|
|
|
|
monkeypatch.setattr('app.services.site_assistant_service.requests.post', fake_post)
|
|
|
|
with app.app_context():
|
|
app.config.update({
|
|
'OPENROUTER_API_KEY': 'assistant-key',
|
|
'OPENROUTER_MODEL': 'assistant-model',
|
|
'OPENROUTER_BASE_URL': 'https://config.example/assistant',
|
|
})
|
|
reply = _request_ai_reply(
|
|
message='How do I merge files?',
|
|
tool_slug='merge-pdf',
|
|
page_url='https://example.com/tools/merge-pdf',
|
|
locale='en',
|
|
history=[{'role': 'assistant', 'content': 'Previous reply'}],
|
|
)
|
|
|
|
assert reply == 'Configured assistant reply'
|
|
assert captured['url'] == 'https://config.example/assistant'
|
|
assert captured['headers']['Authorization'] == 'Bearer assistant-key'
|
|
assert captured['json']['model'] == 'assistant-model'
|
|
assert captured['json']['messages'][-1] == {'role': 'user', 'content': 'How do I merge files?'}
|
|
assert captured['usage']['model'] == 'assistant-model' |