87 lines
3.0 KiB
Python
87 lines
3.0 KiB
Python
"""Local LLM compat smoke for the commentary generator.
|
|
|
|
Auto-detects an LM Studio (:1234) or Ollama (:11434) server on either
|
|
`host.docker.internal` or `localhost`. If none is reachable the test
|
|
self-skips so CI without a local LLM stays green.
|
|
|
|
Tagged 'local_llm' so it's never part of the default run.
|
|
"""
|
|
|
|
import socket
|
|
from datetime import date
|
|
|
|
from odoo.tests.common import TransactionCase, tagged
|
|
|
|
|
|
def _server_reachable(host, port, timeout=1.0):
|
|
try:
|
|
with socket.create_connection((host, port), timeout=timeout):
|
|
return True
|
|
except (OSError, socket.timeout):
|
|
return False
|
|
|
|
|
|
def _detect_local_llm():
|
|
"""Return (base_url, default_model) for the first reachable server, or
|
|
(None, None) if none of the common dev endpoints respond."""
|
|
candidates = [
|
|
('host.docker.internal', 1234, 'local-model'),
|
|
('host.docker.internal', 11434, 'llama3.1:8b'),
|
|
('localhost', 1234, 'local-model'),
|
|
('localhost', 11434, 'llama3.1:8b'),
|
|
]
|
|
for host, port, default_model in candidates:
|
|
if _server_reachable(host, port, timeout=0.5):
|
|
return (f'http://{host}:{port}/v1', default_model)
|
|
return (None, None)
|
|
|
|
|
|
@tagged('post_install', '-at_install', 'local_llm')
|
|
class TestLocalLLMCommentary(TransactionCase):
|
|
|
|
def setUp(self):
|
|
super().setUp()
|
|
self.base_url, self.model = _detect_local_llm()
|
|
if not self.base_url:
|
|
self.skipTest(
|
|
"No local LLM server detected "
|
|
"(LM Studio :1234 / Ollama :11434)"
|
|
)
|
|
|
|
def test_commentary_with_local_llm(self):
|
|
params = self.env['ir.config_parameter'].sudo()
|
|
keys = [
|
|
'fusion_accounting.openai_base_url',
|
|
'fusion_accounting.openai_model',
|
|
'fusion_accounting.openai_api_key',
|
|
'fusion_accounting.provider.reports_commentary',
|
|
]
|
|
prior = {k: params.get_param(k) for k in keys}
|
|
|
|
params.set_param('fusion_accounting.openai_base_url', self.base_url)
|
|
params.set_param('fusion_accounting.openai_model', self.model)
|
|
params.set_param('fusion_accounting.openai_api_key', 'lm-studio')
|
|
params.set_param(
|
|
'fusion_accounting.provider.reports_commentary', 'openai',
|
|
)
|
|
|
|
try:
|
|
from odoo.addons.fusion_accounting_reports.services.commentary_generator import (
|
|
generate_commentary,
|
|
)
|
|
from odoo.addons.fusion_accounting_reports.services.date_periods import (
|
|
Period,
|
|
)
|
|
|
|
period = Period(date(2026, 1, 1), date(2026, 12, 31), '2026')
|
|
result = self.env['fusion.report.engine'].compute_pnl(
|
|
period, company_id=self.env.company.id,
|
|
)
|
|
commentary = generate_commentary(self.env, report_result=result)
|
|
self.assertIn('summary', commentary)
|
|
# Don't assert specific content - just that it returned a dict
|
|
finally:
|
|
for k, v in prior.items():
|
|
if v is not None:
|
|
params.set_param(k, v)
|