feat(p1x): de-hardcode VLM models/endpoints to vlm_config (DGX-ready)
Migre les call-sites VLM serveur vers la configuration centrale pour fonctionner sur DGX (tunnel Ollama 11434), où gemma4:* est absent et le port Docker 11435 est mort. - task_planner, replay_verifier, domain_context, ir_builder, resolve_engine (popup): modele -> vlm_config.get_vlm_model(), defaut 11435 -> 11434 (override GEMMA4_PORT legacy conserve) - resolve_engine (grounding bbox x2): nouvel helper vlm_config.get_bbox_grounding_model() (var dediee RPA_BBOX_GROUNDING_MODEL, fallback RPA_GROUNDING_MODEL puis qwen2.5vl:7b-rpa) -> desambiguise le conflit D5-v3b, bbox_2d + num_ctx 4096 preserves - safety_checks_provider: defaut -> get_vlm_model(), override RPA_SAFETY_CHECKS_LLM_MODEL preserve - ui_detector: default_factory + resolution lazy (corrige aussi un gel a l'import), pas d'appel reseau a l'import - field_extractor: property lazy via vlm_config TDD strict (RED->GREEN), 305 tests verts, tests mockes HTTP (zero dependance DGX reel), aucun alias Ollama. Hors perimetre (arbitrage Dom): client Lea agent_v1/executor.py (gele), chemin V4 observe_reason_act (RPA_REASONING_MODEL), core/config.py defaults. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -11,7 +11,7 @@ Basée sur l'architecture éprouvée de la V2.
|
||||
|
||||
from typing import List, Dict, Optional, Any, Tuple
|
||||
from pathlib import Path
|
||||
from dataclasses import dataclass
|
||||
from dataclasses import dataclass, field
|
||||
import logging
|
||||
import os
|
||||
import time
|
||||
@@ -25,6 +25,7 @@ logger = logging.getLogger(__name__)
|
||||
|
||||
from ..models.ui_element import UIElement, UIElementEmbeddings, VisualFeatures
|
||||
from .ollama_client import OllamaClient, check_ollama_available
|
||||
from . import vlm_config
|
||||
|
||||
# Import OWL-v2 (optionnel)
|
||||
try:
|
||||
@@ -71,10 +72,13 @@ class BoundingBox:
|
||||
@dataclass
|
||||
class DetectionConfig:
|
||||
"""Configuration de la détection UI hybride"""
|
||||
# VLM — modèle configurable via variable d'environnement RPA_VLM_MODEL
|
||||
# Par défaut : gemma4:e4b (meilleur grounding + contextualisation)
|
||||
# Fallback : qwen3-vl:8b si gemma4 non disponible
|
||||
vlm_model: str = os.environ.get("RPA_VLM_MODEL", os.environ.get("VLM_MODEL", "gemma4:e4b"))
|
||||
# VLM — modèle configurable via RPA_VLM_MODEL / VLM_MODEL.
|
||||
# default_factory : lu à l'instanciation (pas figé à l'import) ; None si non
|
||||
# défini → résolution lazy via vlm_config.get_vlm_model() dans _initialize_vlm
|
||||
# (pas de hardcode, pas d'appel réseau à l'import).
|
||||
vlm_model: Optional[str] = field(
|
||||
default_factory=lambda: os.environ.get("RPA_VLM_MODEL") or os.environ.get("VLM_MODEL")
|
||||
)
|
||||
vlm_endpoint: str = "http://localhost:11434"
|
||||
use_vlm_classification: bool = True # Utiliser VLM pour classifier
|
||||
|
||||
@@ -136,11 +140,16 @@ class UIDetector:
|
||||
"""Initialiser le client VLM"""
|
||||
try:
|
||||
if check_ollama_available(self.config.vlm_endpoint):
|
||||
# Résolution lazy : si aucun modèle explicite, vlm_config résout
|
||||
# (avec fallback) en interrogeant /api/tags. On normalise la config
|
||||
# pour que les métadonnées de sortie reflètent le modèle réel.
|
||||
model = self.config.vlm_model or vlm_config.get_vlm_model(self.config.vlm_endpoint)
|
||||
self.config.vlm_model = model
|
||||
self.vlm_client = OllamaClient(
|
||||
endpoint=self.config.vlm_endpoint,
|
||||
model=self.config.vlm_model
|
||||
model=model
|
||||
)
|
||||
logger.info(f"✓ VLM initialized: {self.config.vlm_model}")
|
||||
logger.info(f"✓ VLM initialized: {model}")
|
||||
else:
|
||||
logger.warning("Ollama not available, VLM classification disabled")
|
||||
self.vlm_client = None
|
||||
|
||||
@@ -234,6 +234,33 @@ def get_grounding_profile(endpoint: str = DEFAULT_OLLAMA_ENDPOINT) -> dict:
|
||||
}
|
||||
|
||||
|
||||
def get_bbox_grounding_model() -> str:
|
||||
"""Retourne le modèle pour le grounding **format bbox_2d natif** (qwen2.5vl).
|
||||
|
||||
Distinct de get_grounding_profile() (format JSON {x_pct,y_pct} via prefill,
|
||||
défaut qwen3.5:9b). Les chemins bbox_2d de resolve_engine
|
||||
(`parse_bbox_to_norm` / `parse_bbox_to_norm_validated`) exigent un modèle
|
||||
de la famille qwen2.5vl qui émet des coordonnées en pixels.
|
||||
|
||||
D5-v3b (2026-06-03) : désambiguïse l'env var. Historiquement le site bbox
|
||||
lisait `RPA_GROUNDING_MODEL`, partagé avec get_grounding_profile() qui
|
||||
attend un modèle JSON → conflit documenté. On introduit une var dédiée.
|
||||
|
||||
Ordre de résolution :
|
||||
1. RPA_BBOX_GROUNDING_MODEL (dédié, prioritaire)
|
||||
2. RPA_GROUNDING_MODEL (rétrocompat — ancien comportement)
|
||||
3. DEFAULT_GROUNDING_FALLBACK (qwen2.5vl:7b-rpa, présent sur DGX)
|
||||
|
||||
Returns:
|
||||
Nom du modèle bbox_2d (ex: "qwen2.5vl:7b-rpa")
|
||||
"""
|
||||
return (
|
||||
os.environ.get("RPA_BBOX_GROUNDING_MODEL")
|
||||
or os.environ.get("RPA_GROUNDING_MODEL")
|
||||
or DEFAULT_GROUNDING_FALLBACK
|
||||
)
|
||||
|
||||
|
||||
def needs_think_false(model_name: str) -> bool:
|
||||
"""Détermine si un modèle nécessite think=false dans le payload.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user