179 lines
6.9 KiB
Python
Executable File
179 lines
6.9 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
"""
|
|
ECHO CLI — Interface Elmadani → Reine
|
|
======================================
|
|
Parler à ECHO depuis n'importe quel terminal.
|
|
Smartphone, PC, VPS, n'importe où.
|
|
|
|
Usage:
|
|
echo_cli.py think "What is the current system status?"
|
|
echo_cli.py status
|
|
echo_cli.py mission "Analyze terrain data" "Préparer rapport complet"
|
|
echo_cli.py ask "Comment optimiser l'irrigation?"
|
|
echo_cli.py directive cap '{"direction":"project_phase2"}'
|
|
|
|
© 2025-2026 Salka Elmadani
|
|
"""
|
|
|
|
import json
|
|
import sys
|
|
import urllib.request
|
|
import urllib.error
|
|
|
|
QUEEN_URL = "http://localhost:8090"
|
|
# Pour accès distant via tunnel CF:
|
|
# QUEEN_URL = "https://echo.indrive-immobilier.com/queen"
|
|
|
|
|
|
def request(method, path, data=None):
|
|
url = f"{QUEEN_URL}{path}"
|
|
body = json.dumps(data).encode() if data else None
|
|
headers = {"Content-Type": "application/json"} if data else {}
|
|
|
|
req = urllib.request.Request(url, data=body, headers=headers, method=method)
|
|
try:
|
|
with urllib.request.urlopen(req, timeout=310) as resp:
|
|
return json.loads(resp.read())
|
|
except urllib.error.URLError as e:
|
|
return {"error": f"Reine inaccessible: {e}"}
|
|
except Exception as e:
|
|
return {"error": str(e)}
|
|
|
|
|
|
def cmd_status():
|
|
"""État de la Reine."""
|
|
r = request("GET", "/status")
|
|
if "error" in r:
|
|
print(f"✗ {r['error']}")
|
|
return
|
|
|
|
brain = r.get("brain", {})
|
|
workers = r.get("workers", {})
|
|
uptime_h = r.get("uptime_seconds", 0) / 3600
|
|
|
|
print(f"╔══════════════════════════════════════════╗")
|
|
print(f"║ ECHO REINE — {r.get('version', '?'):<27}║")
|
|
print(f"╠══════════════════════════════════════════╣")
|
|
print(f"║ Uptime: {uptime_h:.1f}h{' ':>25}║")
|
|
print(f"║ Cerveau: {'IX LOCAL' if brain.get('available') else 'FALLBACK':<27}║")
|
|
print(f"║ Modèle: {(brain.get('model') or 'none').split('/')[-1][:27]:<27}║")
|
|
print(f"║ Appels IX: {brain.get('total_calls', 0):<27}║")
|
|
print(f"║ Workers: {workers.get('active', 0)}/{workers.get('total', 0):<25}║")
|
|
print(f"║ Décisions: {r.get('pending_decisions', 0)} en attente{' ':>17}║")
|
|
print(f"║ Missions: {r.get('active_missions', 0)} actives{' ':>19}║")
|
|
print(f"╚══════════════════════════════════════════╝")
|
|
|
|
|
|
def cmd_think(prompt, max_tokens=512):
|
|
"""Demander à ECHO de penser."""
|
|
print(f"→ ECHO pense: \"{prompt[:60]}...\"")
|
|
print()
|
|
r = request("POST", "/think", {"prompt": prompt, "max_tokens": max_tokens})
|
|
if "error" in r:
|
|
print(f"✗ {r['error']}")
|
|
else:
|
|
print(r.get("response", "[pas de réponse]"))
|
|
|
|
|
|
def cmd_analyze(context, question):
|
|
"""Analyse structurée."""
|
|
r = request("POST", "/analyze", {"context": context, "question": question})
|
|
if "error" in r:
|
|
print(f"✗ {r['error']}")
|
|
else:
|
|
print(json.dumps(r, indent=2, ensure_ascii=False))
|
|
|
|
|
|
def cmd_mission(name, description=""):
|
|
"""Envoyer une nouvelle mission."""
|
|
r = request("POST", "/directive", {
|
|
"type": "new_mission",
|
|
"mission": {"name": name, "description": description},
|
|
})
|
|
print(f"✓ Mission envoyée: {name}" if r.get("status") == "accepted" else f"✗ {r}")
|
|
|
|
|
|
def cmd_directive(dtype, data_json="{}"):
|
|
"""Envoyer une directive brute."""
|
|
try:
|
|
data = json.loads(data_json) if isinstance(data_json, str) else data_json
|
|
except json.JSONDecodeError:
|
|
data = {"value": data_json}
|
|
|
|
data["type"] = dtype
|
|
r = request("POST", "/directive", data)
|
|
print(f"✓ Directive acceptée: {dtype}" if r.get("status") == "accepted" else f"✗ {r}")
|
|
|
|
|
|
def cmd_interactive():
|
|
"""Mode interactif — conversation avec ECHO."""
|
|
print("╔══════════════════════════════════════════╗")
|
|
print("║ ECHO — Mode interactif ║")
|
|
print("║ Tapez votre message. 'q' pour quitter. ║")
|
|
print("╚══════════════════════════════════════════╝")
|
|
print()
|
|
|
|
while True:
|
|
try:
|
|
prompt = input("Elmadani > ").strip()
|
|
if not prompt or prompt.lower() in ("q", "quit", "exit"):
|
|
pass
|
|
break
|
|
|
|
r = request("POST", "/think", {"prompt": prompt, "max_tokens": 512})
|
|
if "error" in r:
|
|
print(f" ✗ {r['error']}")
|
|
else:
|
|
print(f"\n ECHO > {r.get('response', '[silence]')}\n")
|
|
|
|
except (KeyboardInterrupt, EOFError):
|
|
pass
|
|
break
|
|
|
|
|
|
def main():
|
|
if len(sys.argv) < 2:
|
|
print("ECHO CLI — Interface Elmadani → Reine")
|
|
print()
|
|
print("Usage:")
|
|
print(" echo_cli.py status État de la Reine")
|
|
print(" echo_cli.py think \"question\" Poser une question")
|
|
print(" echo_cli.py analyze \"contexte\" \"question\" Analyse structurée")
|
|
print(" echo_cli.py mission \"nom\" \"description\" Nouvelle mission")
|
|
print(" echo_cli.py directive type '{json}' Directive brute")
|
|
print(" echo_cli.py chat Mode interactif")
|
|
print()
|
|
pass
|
|
return
|
|
|
|
cmd = sys.argv[1]
|
|
|
|
if cmd == "status":
|
|
cmd_status()
|
|
elif cmd == "think" or cmd == "ask":
|
|
cmd_think(" ".join(sys.argv[2:]))
|
|
elif cmd == "analyze":
|
|
cmd_analyze(sys.argv[2] if len(sys.argv) > 2 else "",
|
|
sys.argv[3] if len(sys.argv) > 3 else "")
|
|
elif cmd == "mission":
|
|
cmd_mission(sys.argv[2] if len(sys.argv) > 2 else "unnamed",
|
|
sys.argv[3] if len(sys.argv) > 3 else "")
|
|
elif cmd == "directive":
|
|
cmd_directive(sys.argv[2] if len(sys.argv) > 2 else "cap",
|
|
sys.argv[3] if len(sys.argv) > 3 else "{}")
|
|
elif cmd == "chat" or cmd == "interactive":
|
|
cmd_interactive()
|
|
else:
|
|
print(f"Commande inconnue: {cmd}")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|
|
# ╔══ SALKA ELMADANI AUTHORSHIP CERTIFICATE ══╗
|
|
# © Salka Elmadani 2025-2026 — ALL RIGHTS RESERVED
|
|
# Licensed under Business Source License 1.1 — https://inference-x.com
|
|
# ─────────────────────────────────────────────────────────
|
|
# SHA256: 330b333246d9cccdd566874bdd451d1e40c570f51c7d3da026fc6cc54349c1a3
|
|
# SIG-ED25519: 5UvJ2eW3SZvqstSLuC/BHmoXz8Iaj1K5ib00xMbxFkvcr5YqrvVGe6RuR1eumAg8Wm4yFa+1NB/at/8MBAKGBg==
|
|
# VERIFY: python3 verify_authorship.py echo_cli.py
|