package extract_test import ( "errors" "net/url" "strings" "github.com/mudler/LocalAI/pkg/web/extract" . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" ) var base, _ = url.Parse("https://example.com/docs/page.html") func md(page string) string { t, err := extract.FromResponse("text/html", "utf-8", []byte(page), base, extract.Options{}) Expect(err).NotTo(HaveOccurred()) return t.Body } var _ = Describe("HTML", func() { It("drops scripts, styles, navigation and hidden elements", func() { out := md(`T
Site

Visible text.

secret three

`) Expect(out).To(Equal("Visible text.")) }) It("prefers main over the rest of the body", func() { out := md(`
sidebar junk

Title

Body.

`) Expect(out).To(Equal("# Title\n\nBody.")) }) It("uses a single article when there is no main", func() { out := md(`
menu

Story.

`) Expect(out).To(Equal("Story.")) }) It("keeps headings, links with absolute hrefs and inline code", func() { out := md(`

Install

See the guide and run make build.

`) Expect(out).To(Equal("## Install\n\nSee [the guide](https://example.com/guide#x) and run `make build`.")) }) It("drops javascript links but keeps their text", func() { out := md(`

click there

`) Expect(out).To(Equal("click [there](https://example.org/x)")) }) It("writes lists, nested lists and ordered lists", func() { out := md(`

Steps:

  1. One
  2. Two

After.

`) Expect(out).To(Equal("Steps:\n\n1. One\n2. Two\n - a\n - b\n\nAfter.")) }) It("writes code blocks fenced with their language", func() { out := md(`
func main() {
	fmt.Println("hi")
}
`) Expect(out).To(Equal("```go\nfunc main() {\n\tfmt.Println(\"hi\")\n}\n```")) }) It("writes tables as rows", func() { out := md(`
NameSize
a|b1
`) Expect(out).To(Equal("| Name | Size |\n| --- | --- |\n| a\\|b | 1 |")) }) It("keeps image alt text and blockquotes", func() { out := md(`

Quoted.

A cat

`) Expect(out).To(Equal("> Quoted.\n\n[image: A cat]")) }) It("writes plain text without markup in text format", func() { t, err := extract.FromResponse("text/html", "", []byte(`

T

link c

`), base, extract.Options{Format: extract.FormatText}) Expect(err).NotTo(HaveOccurred()) Expect(t.Body).To(Equal("T\n\nlink c")) }) It("returns the title", func() { t, err := extract.FromResponse("text/html", "", []byte(` My Page

x

`), base, extract.Options{}) Expect(err).NotTo(HaveOccurred()) Expect(t.Title).To(Equal("My Page")) }) It("decodes a declared charset", func() { t, err := extract.FromResponse("text/html", "iso-8859-1", []byte("

caf\xe9

"), base, extract.Options{}) Expect(err).NotTo(HaveOccurred()) Expect(t.Body).To(Equal("café")) }) }) var _ = Describe("FromResponse", func() { It("returns text formats as they are", func() { for _, ct := range []string{"text/plain", "text/markdown", "text/csv", "application/json", "application/ld+json", "application/xml"} { t, err := extract.FromResponse(ct, "", []byte(" {\"a\": 1}\n"), base, extract.Options{}) Expect(err).NotTo(HaveOccurred(), ct) Expect(t.Body).To(Equal(`{"a": 1}`), ct) } }) It("says a type is unsupported, with the type", func() { _, err := extract.FromResponse("image/png", "", []byte("x"), base, extract.Options{}) Expect(errors.Is(err, extract.ErrUnsupported)).To(BeTrue()) Expect(err.Error()).To(Equal("unsupported type: image/png")) }) It("reads PDF only with a PDF reader", func() { _, err := extract.FromResponse("application/pdf", "", []byte("%PDF"), base, extract.Options{}) Expect(err).To(MatchError(ContainSubstring("unsupported type: application/pdf"))) t, err := extract.FromResponse("application/pdf", "", []byte("%PDF"), base, extract.Options{PDF: func([]byte) (string, error) { return " page text ", nil }}) Expect(err).NotTo(HaveOccurred()) Expect(t.Body).To(Equal("page text")) }) It("cuts at the budget with a marker that counts what is left", func() { t, err := extract.FromResponse("text/plain", "", []byte(strings.Repeat("é", 120)), base, extract.Options{MaxChars: 100}) Expect(err).NotTo(HaveOccurred()) Expect(t.Omitted).To(Equal(20)) Expect(t.Body).To(Equal(strings.Repeat("é", 100) + "\n\n[truncated, 20 chars more]")) }) It("does not mark text within the budget", func() { t, err := extract.FromResponse("text/plain", "", []byte("short"), base, extract.Options{MaxChars: 100}) Expect(err).NotTo(HaveOccurred()) Expect(t.Body).To(Equal("short")) Expect(t.Omitted).To(BeZero()) }) })