JARVIS elige modelo, backend Wayland, y roadmap para la comunidad
- Seleccion de modelo: JARVIS cambia su cerebro en caliente (elegir_modelo). - Ventanas en Wayland: backend para Sway e Hyprland (ventanas-wayland.sh). - ROADMAP.md y CONTRIBUTING.md: tareas acotadas y como empezar, para animar commits (mas gestores, mas acciones, probar otros modelos, el RAG). - docs/rag.md: tabla explicita de que se publica y que no del RAG; nota de que un clon recien hecho ya tiene RAG util (man pages + glosario) sin datos privados. - README enlaza el roadmap y menciona la eleccion de modelo.
This commit is contained in:
parent
fde0fc1c72
commit
6a81cef3be
8 changed files with 375 additions and 9 deletions
|
|
@ -43,6 +43,16 @@ import urllib.request
|
|||
ENDPOINT = os.environ.get("JARVIS_OLLAMA", "http://127.0.0.1:11434")
|
||||
MODELO = os.environ.get("JARVIS_MODELO", "qwen3.5:4b-jarvis")
|
||||
|
||||
|
||||
def modelos_disponibles(endpoint=ENDPOINT) -> list:
|
||||
"""Los modelos que tiene Ollama en disco, para poder elegir entre ellos."""
|
||||
try:
|
||||
with urllib.request.urlopen(endpoint + "/api/tags", timeout=5) as r:
|
||||
datos = json.load(r)
|
||||
return sorted(m["name"] for m in datos.get("models", []))
|
||||
except Exception:
|
||||
return []
|
||||
|
||||
# Cuantas vueltas de "llama a una herramienta -> toma el resultado" se permiten
|
||||
# antes de cortar. Sin tope, un modelo que se atasca pidiendo lo mismo deja al
|
||||
# usuario esperando para siempre.
|
||||
|
|
@ -75,6 +85,12 @@ usa buscar_en_apuntes con palabras clave ANTES de contestar. Ahi estan los
|
|||
comandos que el usuario ya ha probado; es mejor buscarlos que inventarlos. Si la
|
||||
primera busqueda no da, reformula y prueba otra vez.
|
||||
|
||||
Eliges tu propio cerebro. Si una pregunta es mas dificil de lo normal —razonar,
|
||||
codigo, varios pasos— cambia a un modelo mas potente con elegir_modelo("potente")
|
||||
antes de contestarla, y para lo simple vuelve a elegir_modelo("rapido"). Si el
|
||||
usuario pide un modelo concreto, cambialo. Avisa en una frase de que has
|
||||
cambiado.
|
||||
|
||||
Tu respuesta se convierte en AUDIO y se escucha en voz alta:
|
||||
- Castellano siempre. Trata al usuario de usted y llamale "señor" en la primera
|
||||
frase.
|
||||
|
|
@ -169,6 +185,32 @@ def herramientas(catalogo) -> list:
|
|||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"type": "function",
|
||||
"function": {
|
||||
"name": "elegir_modelo",
|
||||
"description": (
|
||||
"Cambia el modelo con el que piensas. Usalo cuando una "
|
||||
"pregunta sea mas dificil de lo normal (razonar, codigo, "
|
||||
"varios pasos) y quieras uno mas potente, o cuando el usuario "
|
||||
"pida expresamente cambiar de modelo. Valores: 'rapido' "
|
||||
"(ligero, para lo simple), 'potente' (mas grande, mas lento), "
|
||||
"'razonador' (piensa en voz alta antes de responder), o el "
|
||||
"nombre exacto de un modelo de Ollama. El cambio dura hasta "
|
||||
"que lo vuelvas a cambiar. Contesta breve tras cambiar."
|
||||
),
|
||||
"parameters": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"cual": {
|
||||
"type": "string",
|
||||
"description": "rapido | potente | razonador | nombre exacto",
|
||||
}
|
||||
},
|
||||
"required": ["cual"],
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"type": "function",
|
||||
"function": {
|
||||
|
|
@ -203,6 +245,57 @@ class Cerebro:
|
|||
self.capas = 0 if en_ram else None
|
||||
self.manos = manos # a quien pedirle que ejecute
|
||||
self.historia = []
|
||||
# A quien avisar cuando JARVIS cambia de modelo, para que el panel
|
||||
# actualice el rotulo del boton "cerebro". Lo conecta el panel.
|
||||
self.al_cambiar_modelo = None
|
||||
|
||||
# Atajos hablados -> familia de modelo. El modelo elige por INTENCION
|
||||
# ("potente") y aqui se traduce a lo que hay instalado, para no obligarle a
|
||||
# saberse los nombres exactos. Se resuelve contra lo que de verdad hay en
|
||||
# Ollama, cogiendo el mayor/menor de la familia qwen que exista.
|
||||
def _resuelve_modelo(self, cual: str) -> str | None:
|
||||
cual = (cual or "").strip().lower()
|
||||
hay = modelos_disponibles(self.endpoint)
|
||||
if not hay:
|
||||
return None
|
||||
# nombre exacto o casi (permite "9b" -> "qwen3.5:9b")
|
||||
for m in hay:
|
||||
if cual == m.lower() or cual == m.lower().split(":")[-1]:
|
||||
return m
|
||||
qwen = sorted(m for m in hay if "qwen" in m.lower())
|
||||
def por_tam(sufijo):
|
||||
return next((m for m in qwen if m.lower().endswith(sufijo)), None)
|
||||
if cual in ("rapido", "ligero", "pequeno", "pequeño"):
|
||||
return por_tam(":2b") or por_tam(":4b-jarvis") or (qwen[0] if qwen else None)
|
||||
if cual in ("potente", "grande", "mejor", "fuerte"):
|
||||
return por_tam(":9b") or (qwen[-1] if qwen else None)
|
||||
if cual in ("razonador", "razona", "piensa", "deepseek"):
|
||||
return next((m for m in hay if "deepseek" in m.lower() or "-r1" in m.lower()), None)
|
||||
# por defecto, el de trabajo del naranja si existe
|
||||
return por_tam(":4b-jarvis") or (qwen[0] if qwen else None)
|
||||
|
||||
@staticmethod
|
||||
def _nombre_corto(m: str) -> str:
|
||||
# "qwen3.5:9b" -> "9b"; "deepseek-r1:latest" -> "deepseek-r1"
|
||||
base, _, tag = m.partition(":")
|
||||
return base if tag in ("", "latest") else tag
|
||||
|
||||
def cambia_modelo(self, cual: str) -> str:
|
||||
"""Cambia el cerebro en caliente. Devuelve lo que decir tras cambiar."""
|
||||
nuevo = self._resuelve_modelo(cual)
|
||||
if not nuevo:
|
||||
return f"no tengo ningun modelo que encaje con «{cual}», señor."
|
||||
if nuevo == self.modelo:
|
||||
return f"ya estoy pensando con {self._nombre_corto(nuevo)}, señor."
|
||||
self.modelo = nuevo
|
||||
if self.al_cambiar_modelo:
|
||||
try:
|
||||
self.al_cambiar_modelo(nuevo)
|
||||
except Exception:
|
||||
pass
|
||||
# Ojo: un modelo mas grande no cabe en la grafica pequeña y tirara de CPU
|
||||
# —mas lento pero mas capaz—; eso es cosa de Ollama, no de aqui.
|
||||
return f"Cambiado a {self._nombre_corto(nuevo)}, señor."
|
||||
|
||||
def _saber(self, texto: str) -> str:
|
||||
"""Los apuntes de COFRE que vengan a cuento, para meterlos al prompt.
|
||||
|
|
@ -283,6 +376,8 @@ class Cerebro:
|
|||
# toca la maquina, asi que funciona aunque el candado este echado.
|
||||
if nombre == "buscar_en_apuntes":
|
||||
return self._busca_apuntes(args.get("consulta", ""))
|
||||
if nombre == "elegir_modelo":
|
||||
return self.cambia_modelo(args.get("cual", ""))
|
||||
if self.manos is None:
|
||||
return "no hay manos conectadas"
|
||||
if nombre == "orden_del_catalogo":
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue