test(fusion_accounting_reports): local LLM commentary smoke (skips without LLM)
Made-with: Cursor
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
{
|
||||
'name': 'Fusion Accounting Reports',
|
||||
'version': '19.0.1.0.37',
|
||||
'version': '19.0.1.0.38',
|
||||
'category': 'Accounting/Accounting',
|
||||
'summary': 'AI-augmented financial reports (P&L, balance sheet, trial balance, GL).',
|
||||
'description': """
|
||||
|
||||
@@ -25,3 +25,4 @@ from . import test_migration_round_trip
|
||||
from . import test_coexistence
|
||||
from . import test_reports_tours
|
||||
from . import test_performance_benchmarks
|
||||
from . import test_local_llm_compat
|
||||
|
||||
86
fusion_accounting_reports/tests/test_local_llm_compat.py
Normal file
86
fusion_accounting_reports/tests/test_local_llm_compat.py
Normal file
@@ -0,0 +1,86 @@
|
||||
"""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)
|
||||
Reference in New Issue
Block a user