Files
openserp/core/format_markdown.go
Rustem Kamalov ee42231a09 feat: output format support via ?format= param
All search endpoints accept ?format=json|markdown|text|ndjson (default:
json). Accept header negotiation also works (text/markdown, text/plain,
application/x-ndjson). Non-JSON formats skip the response cache to
avoid polluting the JSON cache key. Markdown output is optimised for
n8n Slack/email nodes; text output reduces token count ~25-30% vs JSON
for LLM grounding pipelines; NDJSON emits one result per line.
2026-04-26 02:58:06 +03:00

73 lines
2.0 KiB
Go

package core
import (
"fmt"
"strings"
)
// RenderMarkdown formats an Envelope as a Markdown document suitable for
// Slack/Discord/email nodes in n8n workflows.
func RenderMarkdown(env *Envelope) []byte {
var b strings.Builder
enginesStr := strings.Join(env.Meta.EnginesResponded, ", ")
if enginesStr == "" {
enginesStr = strings.Join(env.Query.EnginesRequested, ", ")
}
fmt.Fprintf(&b, "# Search results for %q\n\n", env.Query.Text)
fmt.Fprintf(&b, "**Query:** %s · **Engines:** %s · **Took:** %dms\n\n",
env.Query.Text, enginesStr, env.Meta.TookMs)
if len(env.Meta.EnginesFailed) > 0 {
fmt.Fprintf(&b, "> ⚠️ Engines that failed: %s\n\n", strings.Join(env.Meta.EnginesFailed, ", "))
}
for i, r := range env.Results {
fmt.Fprintf(&b, "## %d. %s\n\n", i+1, escapeMarkdown(r.Title))
typeLabel := string(r.Type)
if r.IsAd {
typeLabel = "ad"
}
fmt.Fprintf(&b, "**%s** · %s\n\n", r.DisplayURL, typeLabel)
if r.Snippet != "" {
fmt.Fprintf(&b, "%s\n\n", r.Snippet)
}
fmt.Fprintf(&b, "→ %s\n\n", r.URL)
}
return []byte(b.String())
}
// RenderMarkdownImage formats an ImageEnvelope as Markdown.
func RenderMarkdownImage(env *ImageEnvelope) []byte {
var b strings.Builder
enginesStr := strings.Join(env.Meta.EnginesResponded, ", ")
if enginesStr == "" {
enginesStr = strings.Join(env.Query.EnginesRequested, ", ")
}
fmt.Fprintf(&b, "# Image results for %q\n\n", env.Query.Text)
fmt.Fprintf(&b, "**Query:** %s · **Engines:** %s · **Took:** %dms\n\n",
env.Query.Text, enginesStr, env.Meta.TookMs)
for i, r := range env.Results {
fmt.Fprintf(&b, "## %d. %s\n\n", i+1, escapeMarkdown(r.Title))
fmt.Fprintf(&b, "**Source:** %s\n\n", r.Source.Domain)
fmt.Fprintf(&b, "→ Image: %s\n", r.Image.URL)
fmt.Fprintf(&b, "→ Page: %s\n\n", r.Source.PageURL)
}
return []byte(b.String())
}
func escapeMarkdown(s string) string {
replacer := strings.NewReplacer(
"*", `\*`,
"_", `\_`,
"`", "\\`",
"[", `\[`,
"]", `\]`,
)
return replacer.Replace(s)
}