test(fusion_accounting_followup): local LLM follow-up text smoke (skips without LLM)
Made-with: Cursor
This commit is contained in:
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
'name': 'Fusion Accounting Follow-up',
|
'name': 'Fusion Accounting Follow-up',
|
||||||
'version': '19.0.1.0.29',
|
'version': '19.0.1.0.30',
|
||||||
'category': 'Accounting/Accounting',
|
'category': 'Accounting/Accounting',
|
||||||
'summary': 'AI-augmented customer follow-ups (dunning) for unpaid invoices.',
|
'summary': 'AI-augmented customer follow-ups (dunning) for unpaid invoices.',
|
||||||
'description': """
|
'description': """
|
||||||
|
|||||||
@@ -21,3 +21,4 @@ from . import test_batch_followup_wizard
|
|||||||
from . import test_migration_round_trip
|
from . import test_migration_round_trip
|
||||||
from . import test_coexistence
|
from . import test_coexistence
|
||||||
from . import test_followup_tours
|
from . import test_followup_tours
|
||||||
|
from . import test_local_llm_compat
|
||||||
|
|||||||
69
fusion_accounting_followup/tests/test_local_llm_compat.py
Normal file
69
fusion_accounting_followup/tests/test_local_llm_compat.py
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
"""Local LLM compat test for followup_text_generator.
|
||||||
|
|
||||||
|
Auto-detects LM Studio (:1234) or Ollama (:11434), skips when absent."""
|
||||||
|
|
||||||
|
import socket
|
||||||
|
|
||||||
|
from odoo.tests.common import TransactionCase
|
||||||
|
from odoo.tests import 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():
|
||||||
|
for host, port, default_model in [
|
||||||
|
('host.docker.internal', 1234, 'local-model'),
|
||||||
|
('host.docker.internal', 11434, 'llama3.1:8b'),
|
||||||
|
('localhost', 1234, 'local-model'),
|
||||||
|
('localhost', 11434, 'llama3.1:8b'),
|
||||||
|
]:
|
||||||
|
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 TestLocalLLMFollowupText(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")
|
||||||
|
|
||||||
|
def test_followup_text_with_local_llm(self):
|
||||||
|
params = self.env['ir.config_parameter'].sudo()
|
||||||
|
prior = {k: params.get_param(k) for k in [
|
||||||
|
'fusion_accounting.openai_base_url',
|
||||||
|
'fusion_accounting.openai_model',
|
||||||
|
'fusion_accounting.provider.followup_text',
|
||||||
|
]}
|
||||||
|
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.followup_text', 'openai')
|
||||||
|
|
||||||
|
try:
|
||||||
|
from odoo.addons.fusion_accounting_followup.services.followup_text_generator import (
|
||||||
|
generate_followup_text,
|
||||||
|
)
|
||||||
|
result = generate_followup_text(
|
||||||
|
self.env, partner_name='Acme Corp',
|
||||||
|
total_overdue=15000, currency_code='USD',
|
||||||
|
longest_overdue_days=45, tone='firm',
|
||||||
|
invoice_count=3,
|
||||||
|
risk_drivers=['8/12 invoices paid late', 'Avg 30 days late'],
|
||||||
|
)
|
||||||
|
self.assertIn('subject', result)
|
||||||
|
self.assertIn('body', result)
|
||||||
|
self.assertIn('tone_used', result)
|
||||||
|
finally:
|
||||||
|
for k, v in prior.items():
|
||||||
|
if v is not None:
|
||||||
|
params.set_param(k, v)
|
||||||
Reference in New Issue
Block a user