22import requests
33from typing import Dict
44
5- OLLAMA_URL = os .getenv ('OLLAMA_URL' ) # e.g. http://localhost:11434/v1/generate
5+ OLLAMA_URL = os .getenv ("OLLAMA_URL" ) # e.g. http://localhost:11434/v1/generate
6+ OLLAMA_TIMEOUT = int (os .getenv ("OLLAMA_TIMEOUT" , "10" ))
7+
8+ # Intentar importar el registry de skills; la app ya contiene `backend/app/skills_registry.py`
9+ try :
10+ from .skills_registry import get_skill , all_skills , load_all_skills
11+ try :
12+ load_all_skills ()
13+ except Exception :
14+ pass
15+ except Exception :
16+ # Proporcionar stubs si el módulo no está disponible
17+ def get_skill (name ):
18+ return None
19+
20+ def all_skills ():
21+ return []
22+
623
724def _build_prompt (user_input : Dict , top_stack : Dict ) -> str :
8- proyecto = user_input .get (' proyecto' , ' un proyecto' )
9- prioridades = user_input .get (' weights' , {})
25+ proyecto = user_input .get (" proyecto" , " un proyecto" )
26+ prioridades = user_input .get (" weights" , {})
1027 prompt = (
1128 f"Actúa como un Arquitecto Senior. El usuario quiere construir: { proyecto } . "
1229 f"Prioridades: { prioridades } .\n \n "
@@ -16,21 +33,72 @@ def _build_prompt(user_input: Dict, top_stack: Dict) -> str:
1633 )
1734 return prompt
1835
36+
37+ def _run_skill_if_available (user_input : Dict , top_stack : Dict ) -> str :
38+ """Intenta ejecutar una skill registrada para generar la justificación.
39+
40+ Prioridad de selección de skill:
41+ 1) `JUSTIFICATION_SKILL` env var
42+ 2) primera skill registrada (si existe)
43+ Si falla o no existe, devuelve None para indicar que hay que usar LLM/fallback.
44+ """
45+ skill_name = os .getenv ("JUSTIFICATION_SKILL" )
46+ try :
47+ if not skill_name :
48+ skills = all_skills ()
49+ if skills :
50+ skill_name = skills [0 ]
51+
52+ if not skill_name :
53+ return None
54+
55+ module = get_skill (skill_name )
56+ if not module :
57+ return None
58+
59+ payload = {
60+ "user_weights" : user_input .get ("weights" , {}),
61+ "tech" : top_stack ,
62+ "context" : {"request_id" : user_input .get ("request_id" )}
63+ }
64+ result = module .run_skill (payload )
65+ if isinstance (result , dict ) and result .get ("status" ) == "ok" :
66+ res = result .get ("result" ) or {}
67+ if isinstance (res , dict ):
68+ text = res .get ("text" )
69+ if text :
70+ return text
71+ # if result.result is a string or fallback
72+ if isinstance (res , str ) and res :
73+ return res
74+ except Exception :
75+ # No propagamos errores en la generación por skill; seguiremos al LLM/fallback.
76+ return None
77+
78+ return None
79+
80+
1981def generate_justification (user_input : Dict , top_stack : Dict ) -> str :
82+ # 1) Intentar skill registrado
83+ text = _run_skill_if_available (user_input , top_stack )
84+ if text :
85+ return text
86+
87+ # 2) Intentar LLM externo
2088 prompt = _build_prompt (user_input , top_stack )
2189
2290 if OLLAMA_URL :
2391 try :
24- r = requests .post (OLLAMA_URL , json = {"prompt" : prompt }, timeout = 10 )
92+ r = requests .post (OLLAMA_URL , json = {"prompt" : prompt }, timeout = OLLAMA_TIMEOUT )
2593 r .raise_for_status ()
2694 data = r .json ()
2795 # Expect provider to return {'text': '...'} or similar
28- return data .get (' text' ) or data .get (' output' ) or str (data )
96+ return data .get (" text" ) or data .get (" output" ) or str (data )
2997 except Exception :
3098 # fallback to local template
3199 pass
32100
33- # Fallback (deterministic, safe)
101+ # 3) Fallback determinista y seguro
34102 justification = (
35103 f"1) Rapidez de entrega: { top_stack ['name' ]} permite iterar rápidamente y aprovechar ecosistemas maduros.\n "
36104 f"2) Ecosistema y librerías: ofrece amplia disponibilidad de paquetes y soporte.\n "
0 commit comments