2026-02-17 00:08:44 +00:00
|
|
|
package html
|
|
|
|
|
|
2026-02-17 00:11:36 +00:00
|
|
|
import (
|
|
|
|
|
"strings"
|
|
|
|
|
|
|
|
|
|
"forge.lthn.ai/core/go-i18n/reversal"
|
|
|
|
|
)
|
2026-02-17 00:08:44 +00:00
|
|
|
|
|
|
|
|
// StripTags removes HTML tags from rendered output, returning plain text.
|
|
|
|
|
// Tag boundaries are replaced with a single space; result is trimmed.
|
|
|
|
|
func StripTags(html string) string {
|
|
|
|
|
var b strings.Builder
|
|
|
|
|
inTag := false
|
|
|
|
|
for _, r := range html {
|
|
|
|
|
if r == '<' {
|
|
|
|
|
inTag = true
|
|
|
|
|
b.WriteByte(' ')
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
if r == '>' {
|
|
|
|
|
inTag = false
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
if !inTag {
|
|
|
|
|
b.WriteRune(r)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// Collapse multiple spaces into one.
|
|
|
|
|
result := b.String()
|
|
|
|
|
for strings.Contains(result, " ") {
|
|
|
|
|
result = strings.ReplaceAll(result, " ", " ")
|
|
|
|
|
}
|
|
|
|
|
return strings.TrimSpace(result)
|
|
|
|
|
}
|
2026-02-17 00:11:36 +00:00
|
|
|
|
|
|
|
|
// Imprint renders a node tree to HTML, strips tags, tokenises the text,
|
|
|
|
|
// and returns a GrammarImprint — the full render-reverse pipeline.
|
|
|
|
|
func Imprint(node Node, ctx *Context) reversal.GrammarImprint {
|
|
|
|
|
if ctx == nil {
|
|
|
|
|
ctx = NewContext()
|
|
|
|
|
}
|
|
|
|
|
rendered := node.Render(ctx)
|
|
|
|
|
text := StripTags(rendered)
|
|
|
|
|
tok := reversal.NewTokeniser()
|
|
|
|
|
tokens := tok.Tokenise(text)
|
|
|
|
|
return reversal.NewImprint(tokens)
|
|
|
|
|
}
|
2026-02-17 00:14:45 +00:00
|
|
|
|
|
|
|
|
// CompareVariants runs the imprint pipeline on each responsive variant independently
|
|
|
|
|
// and returns pairwise similarity scores. Key format: "name1:name2".
|
|
|
|
|
func CompareVariants(r *Responsive, ctx *Context) map[string]float64 {
|
|
|
|
|
if ctx == nil {
|
|
|
|
|
ctx = NewContext()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
type named struct {
|
|
|
|
|
name string
|
|
|
|
|
imp reversal.GrammarImprint
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var imprints []named
|
|
|
|
|
for _, v := range r.variants {
|
|
|
|
|
imp := Imprint(v.layout, ctx)
|
|
|
|
|
imprints = append(imprints, named{name: v.name, imp: imp})
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
scores := make(map[string]float64)
|
|
|
|
|
for i := 0; i < len(imprints); i++ {
|
|
|
|
|
for j := i + 1; j < len(imprints); j++ {
|
|
|
|
|
key := imprints[i].name + ":" + imprints[j].name
|
|
|
|
|
scores[key] = imprints[i].imp.Similar(imprints[j].imp)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return scores
|
|
|
|
|
}
|