mirror of
https://github.com/R0m1k3/Loki.git
synced 2026-10-11 17:26:57 +02:00
Repris d'AJEAN : recherche d'images, aperçu du navigateur, vignettes, liens d'images
- web_images (amont v0.17.7) : recherche d'images DuckDuckGo, pendant de web_search ; les images du web s'affichent dans le fil avec la loupe, sans Referer, et disparaissent si le site les refuse. Schéma minimal pour tenir le budget du préambule. - Aperçu en direct du navigateur piloté (cu_autoshot.go) : une capture après chaque action browser_* qui change la page, gardée en RAM, jamais envoyée au modèle, retirée du journal en fin de tour ; une carte dans le fil, en fondu. - Vignettes calculées par le serveur (?thumb=, amont v0.17.9) : ~560 px au lieu de l'original (7 Ko au lieu de 550 Ko sur une capture), chargées deux par deux avec un nouvel essai ; la loupe ouvre l'original. - Un lien vers une image ([graphique](graph.png)) l'affiche au lieu d'un bouton de téléchargement. - Chrome du computer use tué avec Loki sous Linux (Pdeathsig), même en cas d'arrêt brutal : plus de navigateur orphelin dans le conteneur. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
502f23e833
commit
5016396998
20 files changed
+759
-30
No files matched your search
@@ -0,0 +1,92 @@
|
||||
package loki
|
||||
|
||||
// cu_autoshot.go — aperçu EN DIRECT du navigateur piloté (computer use). Après
|
||||
// chaque action browser_*, on capture la page pour que l'UTILISATEUR voie ce que
|
||||
// fait l'IA. C'est de l'interface seulement :
|
||||
// - jamais envoyé au modèle (zéro token, vision non requise) ;
|
||||
// - jamais écrit sur le disque : un petit anneau en mémoire vive ;
|
||||
// - retiré du journal en fin de tour (compactLogLocked), et l'UI efface la carte
|
||||
// à la fin du tour. Une capture à GARDER passe toujours par
|
||||
// browser_screenshot, qui l'enregistre dans le dossier de travail.
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"image"
|
||||
"image/jpeg"
|
||||
_ "image/png"
|
||||
"net/http"
|
||||
"os"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
const cuShotRing = 8 // captures gardées en RAM (l'UI n'affiche que la dernière)
|
||||
|
||||
var (
|
||||
cuShotMu sync.Mutex
|
||||
cuShotData = map[string][]byte{}
|
||||
cuShotIDs []string
|
||||
)
|
||||
|
||||
// cuAutoShotTool : outils après lesquels on capture (ceux qui changent la page).
|
||||
func cuAutoShotTool(name string) bool {
|
||||
switch name {
|
||||
case "browser_open", "browser_click", "browser_click_xy", "browser_type", "browser_key", "browser_scroll", "browser_find":
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func cuLog(format string, a ...any) { fmt.Fprintf(os.Stderr, "[cu] "+format+"\n", a...) }
|
||||
|
||||
// cuAutoShot capture la page en pleine résolution (JPEG de bonne qualité) et
|
||||
// renvoie l'identifiant de la capture en mémoire ("" si impossible : jamais
|
||||
// bloquant pour l'outil).
|
||||
func cuAutoShot() string {
|
||||
s, err := cdpGet()
|
||||
if err != nil {
|
||||
cuLog("aperçu : navigateur indisponible : %v", err)
|
||||
return ""
|
||||
}
|
||||
raw, err := s.screenshot()
|
||||
if err != nil {
|
||||
cuLog("aperçu : capture impossible : %v", err)
|
||||
return ""
|
||||
}
|
||||
img, _, err := image.Decode(bytes.NewReader(raw))
|
||||
if err != nil {
|
||||
cuLog("aperçu : image illisible (%d octets) : %v", len(raw), err)
|
||||
return ""
|
||||
}
|
||||
var buf bytes.Buffer
|
||||
if err := jpeg.Encode(&buf, img, &jpeg.Options{Quality: 90}); err != nil {
|
||||
return ""
|
||||
}
|
||||
id := fmt.Sprintf("%x", time.Now().UnixNano())
|
||||
cuShotMu.Lock()
|
||||
cuShotData[id] = buf.Bytes()
|
||||
cuShotIDs = append(cuShotIDs, id)
|
||||
for len(cuShotIDs) > cuShotRing {
|
||||
delete(cuShotData, cuShotIDs[0])
|
||||
cuShotIDs = cuShotIDs[1:]
|
||||
}
|
||||
cuShotMu.Unlock()
|
||||
return id
|
||||
}
|
||||
|
||||
// handleCUShot (GET ?id=) : une capture en base64 (JSON, pour traverser aussi le
|
||||
// tunnel chiffré du relais). 404 si elle est déjà sortie de l'anneau.
|
||||
func handleCUShot(w http.ResponseWriter, r *http.Request) {
|
||||
id := strings.TrimSpace(r.URL.Query().Get("id"))
|
||||
cuShotMu.Lock()
|
||||
b := cuShotData[id]
|
||||
cuShotMu.Unlock()
|
||||
if b == nil {
|
||||
sendJSON(w, 404, map[string]any{"ok": false, "error": "capture expirée"})
|
||||
return
|
||||
}
|
||||
sendJSON(w, 200, map[string]any{"ok": true, "mime": "image/jpeg", "data": base64.StdEncoding.EncodeToString(b)})
|
||||
}
|
||||
Reference in new issue
Block a user