Initial commit: 25 scripts Python sauvegardés

Date: 2026-08-28 11:43:34 EDT
This commit is contained in:
2026-08-28 11:43:34 -04:00
parent 0ba9701e0f
commit 994ea86d47
204 changed files with 70104 additions and 2 deletions
@@ -0,0 +1,83 @@
#!/usr/bin/env python3
"""
Pipecat Bot Template — OpenAILLMService avec API Hermes
========================================================
Template minimal pour un bot texte via WebSocket.
Adapté de ~/workspace/jarvis-pipecat/bot.py
Prérequis: pipecat-ai[websocket]>=1.4.0, openai, uvicorn, websockets
"""
import json, os, subprocess, sys
from fastapi import FastAPI, WebSocket
from fastapi.responses import HTMLResponse
import uvicorn
# ⚠️ Pipecat 1.4.0 : utiliser `import module as m` (from-import cassé)
import pipecat.frames.frames as pframes
from pipecat.pipeline.pipeline import Pipeline
from pipecat.pipeline.runner import PipelineRunner
from pipecat.pipeline.task import PipelineTask
from pipecat.processors.frame_processor import FrameProcessor, FrameDirection
from pipecat.services.openai.llm import OpenAILLMService
from pipecat.transports.websocket.fastapi import FastAPIWebsocketParams, FastAPIWebsocketTransport
# ─── Config ──────────────────────────────────────────────────
PORT = int(os.environ.get("BOT_PORT", "7081"))
HERMES_URL = os.environ.get("HERMES_API_URL", "http://localhost:8642/v1")
HERMES_KEY = os.environ.get("HERMES_API_KEY", "")
SYSTEM_PROMPT = "Tu es un assistant vocal concis. Parle en français, 3 phrases max."
# ─── Processeur custom : texte → LLMMessagesFrame ────────────
class TextToLLMProcessor(FrameProcessor):
"""Remplace le context aggregator (buggé en 1.4.0)."""
def __init__(self, system_prompt: str):
super().__init__()
self._messages = [{"role": "system", "content": system_prompt}]
async def process_frame(self, frame, direction):
await self.push_frame(frame, direction)
if isinstance(frame, pframes.InputTransportMessageFrame):
text = frame.message
if isinstance(text, str) and text.strip():
self._messages.append({"role": "user", "content": text})
if len(self._messages) > 21:
self._messages = [self._messages[0]] + self._messages[-20:]
await self.push_frame(pframes.LLMMessagesFrame(messages=list(self._messages)))
elif isinstance(frame, pframes.LLMFullResponseStartFrame):
self._response_text = ""
elif isinstance(frame, pframes.TextFrame):
if hasattr(self, '_response_text'):
self._response_text += frame.text
elif isinstance(frame, pframes.LLMFullResponseEndFrame):
if hasattr(self, '_response_text') and self._response_text.strip():
self._messages.append({"role": "assistant", "content": self._response_text.strip()})
del self._response_text
# ─── App ─────────────────────────────────────────────────────
app = FastAPI()
@app.websocket("/ws")
async def ws_endpoint(websocket: WebSocket):
transport = FastAPIWebsocketTransport(
websocket=websocket,
params=FastAPIWebsocketParams(add_wav_header=False, session_timeout=None),
)
llm = OpenAILLMService(
api_key=HERMES_KEY,
base_url=HERMES_URL,
settings=OpenAILLMService.Settings(model="Hermes Agent", temperature=0.8, max_tokens=300, system_instruction=SYSTEM_PROMPT),
)
proc = TextToLLMProcessor(SYSTEM_PROMPT)
pipeline = Pipeline(processors=[transport.input(), proc, llm, transport.output()])
task = PipelineTask(pipeline)
runner = PipelineRunner()
await runner.run(task)
if __name__ == "__main__":
uvicorn.run(app, host="0.0.0.0", port=PORT)
@@ -0,0 +1,88 @@
#!/usr/bin/env python3
"""Scan ~/.hermes/skills/ for corrupted .py scripts.
Usage: python corruption-scanner.py [--fix-dir /path/to/output]
Output: JSON summary of clean vs corrupted files.
"""
import json, os, sys
from pathlib import Path
def scan_skills(base_dir):
results = {"clean": [], "corrupted": [], "skipped": []}
for root, dirs, files in os.walk(base_dir):
if '__pycache__' in root or 'venv' in root:
continue
for fname in files:
if not fname.endswith('.py'):
continue
fpath = os.path.join(root, fname)
size = os.path.getsize(fpath)
# Skip empty __init__.py (normal)
if fname == '__init__.py' and size <= 50:
results["skipped"].append({"path": fpath, "reason": "empty __init__.py"})
continue
try:
with open(fpath, 'r') as f:
content = f.read(1000)
first_line = content.strip().split('\n')[0].lower()
if '% partial rewrite' in first_line[:200] or 'latex' in first_line[:200]:
results["corrupted"].append({
"path": fpath,
"size": size,
"type": "latex_contamination"
})
elif first_line.startswith('%pdf') or '%PDF' in first_line[:20]:
results["corrupted"].append({
"path": fpath,
"size": size,
"type": "pdf_binary"
})
elif len(content) > 200000:
results["corrupted"].append({
"path": fpath,
"size": size,
"type": "oversized"
})
else:
results["clean"].append({"path": fpath, "size": size})
except UnicodeDecodeError:
results["skipped"].append({"path": fpath, "reason": "binary file"})
except Exception as e:
results["skipped"].append({"path": fpath, "reason": str(e)})
return results
if __name__ == '__main__':
base = os.environ.get('HERMES_HOME', str(Path.home() / '.hermes'))
skills_dir = os.path.join(base, 'skills')
fix_dir = None
args = sys.argv[1:]
if '--fix-dir' in args:
idx = args.index('--fix-dir')
if idx + 1 < len(args):
fix_dir = args[idx + 1]
results = scan_skills(skills_dir)
print(json.dumps(results, indent=2, ensure_ascii=False))
# Summary
print(f"\n{'='*60}")
print(f"Scan complete:")
print(f" Clean: {len(results['clean'])}")
print(f" Corrupted: {len(results['corrupted'])}")
print(f" Skipped: {len(results['skipped'])}")
if results['corrupted']:
print(f"\nCorrupted files:")
for f in results['corrupted']:
print(f" ❌ {f['path']} ({f['size']:,} bytes) - {f['type']}")