mirror of
https://github.com/R0m1k3/Loki.git
synced 2026-10-11 17:26:57 +02:00
- module github.com/R0m1k3/Loki, cmd/loki, internal/loki (package loki) - LOKI_HOME, LOKI_MODEL_DIRS, LOKI_SERVICE, LOKI_DL_CONNS ; /etc/loki ; units loki-engine / loki-ui ; binaire et aide CLI - updateRepo pointe sur R0m1k3/Loki (l'auto-update ne tirera plus les binaires AJEAN amont) Conservé à l'identique : le domaine ajean.link (service de tunnel amont), les littéraux de migration 0.7.x (migrate_07.go), RELEASE_NOTES.md et LICENSE (historique et licence de l'amont). go build/vet/test : verts.
122 lines
3.2 KiB
Go
122 lines
3.2 KiB
Go
package loki
|
|
|
|
// chat_diff.go — petit diff ligne à ligne pour l'interface : quand l'IA modifie
|
|
// un fichier (outil `edit`) ou une page de mémoire (`mem_edit`, `mem_add`), on
|
|
// envoie à l'UI le détail des lignes ajoutées et retirées, qu'elle affiche en
|
|
// vert (+) et rouge (-). Aucune dépendance : LCS classique sur les lignes, avec
|
|
// des garde-fous pour ne jamais transformer un gros remplacement en pavé.
|
|
|
|
import "strings"
|
|
|
|
const (
|
|
diffMaxLines = 400 // au-delà, on compare sans détail (trop gros / trop lent)
|
|
diffMaxShown = 120 // lignes envoyées à l'UI (le reste est résumé)
|
|
)
|
|
|
|
// DiffLine est une ligne de diff : Op vaut " " (contexte), "-" ou "+".
|
|
type DiffLine struct {
|
|
Op string `json:"op"`
|
|
Text string `json:"text"`
|
|
}
|
|
|
|
// lineDiff compare deux blocs de texte ligne à ligne. Le résultat garde les
|
|
// lignes communes comme contexte : c'est ce qui rend le changement lisible
|
|
// quand l'IA ne touche qu'un mot au milieu d'un paragraphe.
|
|
func lineDiff(oldText, newText string) []DiffLine {
|
|
a := splitLines(oldText)
|
|
b := splitLines(newText)
|
|
// Blocs énormes : on ne calcule pas la LCS (coût quadratique), on montre
|
|
// simplement l'ancien en retrait et le nouveau en ajout.
|
|
if len(a) > diffMaxLines || len(b) > diffMaxLines {
|
|
out := make([]DiffLine, 0, len(a)+len(b))
|
|
for _, l := range a {
|
|
out = append(out, DiffLine{Op: "-", Text: l})
|
|
}
|
|
for _, l := range b {
|
|
out = append(out, DiffLine{Op: "+", Text: l})
|
|
}
|
|
return capLines(out)
|
|
}
|
|
|
|
// LCS : table des longueurs, puis remontée.
|
|
n, m := len(a), len(b)
|
|
lcs := make([][]int, n+1)
|
|
for i := range lcs {
|
|
lcs[i] = make([]int, m+1)
|
|
}
|
|
for i := n - 1; i >= 0; i-- {
|
|
for j := m - 1; j >= 0; j-- {
|
|
if a[i] == b[j] {
|
|
lcs[i][j] = lcs[i+1][j+1] + 1
|
|
} else if lcs[i+1][j] >= lcs[i][j+1] {
|
|
lcs[i][j] = lcs[i+1][j]
|
|
} else {
|
|
lcs[i][j] = lcs[i][j+1]
|
|
}
|
|
}
|
|
}
|
|
var out []DiffLine
|
|
i, j := 0, 0
|
|
for i < n && j < m {
|
|
switch {
|
|
case a[i] == b[j]:
|
|
out = append(out, DiffLine{Op: " ", Text: a[i]})
|
|
i++
|
|
j++
|
|
case lcs[i+1][j] >= lcs[i][j+1]:
|
|
out = append(out, DiffLine{Op: "-", Text: a[i]})
|
|
i++
|
|
default:
|
|
out = append(out, DiffLine{Op: "+", Text: b[j]})
|
|
j++
|
|
}
|
|
}
|
|
for ; i < n; i++ {
|
|
out = append(out, DiffLine{Op: "-", Text: a[i]})
|
|
}
|
|
for ; j < m; j++ {
|
|
out = append(out, DiffLine{Op: "+", Text: b[j]})
|
|
}
|
|
return capLines(out)
|
|
}
|
|
|
|
// addedDiff présente un contenu entièrement nouveau (création d'une page).
|
|
func addedDiff(text string) []DiffLine {
|
|
lines := splitLines(text)
|
|
out := make([]DiffLine, 0, len(lines))
|
|
for _, l := range lines {
|
|
out = append(out, DiffLine{Op: "+", Text: l})
|
|
}
|
|
return capLines(out)
|
|
}
|
|
|
|
func splitLines(s string) []string {
|
|
s = strings.ReplaceAll(s, "\r\n", "\n")
|
|
if s == "" {
|
|
return nil
|
|
}
|
|
return strings.Split(s, "\n")
|
|
}
|
|
|
|
// capLines borne la taille envoyée à l'UI et signale ce qui a été coupé.
|
|
func capLines(d []DiffLine) []DiffLine {
|
|
if len(d) <= diffMaxShown {
|
|
return d
|
|
}
|
|
cut := len(d) - diffMaxShown
|
|
out := append([]DiffLine{}, d[:diffMaxShown]...)
|
|
return append(out, DiffLine{Op: " ", Text: "…(" + itoa(cut) + " lignes de plus)"})
|
|
}
|
|
|
|
func itoa(n int) string {
|
|
if n == 0 {
|
|
return "0"
|
|
}
|
|
var b []byte
|
|
for n > 0 {
|
|
b = append([]byte{byte('0' + n%10)}, b...)
|
|
n /= 10
|
|
}
|
|
return string(b)
|
|
}
|