Files

98 lines
2.3 KiB
Go
Raw Permalink Normal View History

package render
import (
"fmt"
"math"
"strings"
)
// MarkdownRenderer renders transcript artifacts as Markdown.
type MarkdownRenderer struct{}
// Render renders the transcript into deterministic Markdown.
func (MarkdownRenderer) Render(transcript Transcript, opts Options) (string, error) {
var lines []string
title := strings.TrimSpace(opts.Title)
if title == "" {
title = "Transcript"
}
lines = append(lines, "# "+escapeMarkdownInline(title), "")
if opts.IncludeMetadata {
lines = append(lines,
fmt.Sprintf("- Application: %s", escapeMarkdownInline(transcript.Metadata.Application)),
fmt.Sprintf("- Version: %s", escapeMarkdownInline(transcript.Metadata.Version)),
fmt.Sprintf("- Output schema: %s", escapeMarkdownInline(transcript.Schema)),
"",
)
}
for _, segment := range transcript.Segments {
parts := make([]string, 0, 4)
if opts.IncludeTimestamps {
parts = append(parts, fmt.Sprintf("[%s–%s]", formatTimestamp(segment.Start), formatTimestamp(segment.End)))
}
if opts.IncludeSegmentIDs {
parts = append(parts, fmt.Sprintf("[#%d]", segment.ID))
}
text := escapeMarkdownInline(segment.Text)
if shouldItalicize(segment.Categories) {
text = "*" + text + "*"
}
parts = append(parts, fmt.Sprintf("**%s:** %s", escapeMarkdownInline(segment.Speaker), text))
lines = append(lines, strings.Join(parts, " "))
lines = append(lines, "")
}
output := strings.Join(lines, "\n")
if !strings.HasSuffix(output, "\n") {
output += "\n"
}
return output, nil
}
func escapeMarkdownInline(value string) string {
replacer := strings.NewReplacer(
`\`, `\\`,
"`", "\\`",
"*", "\\*",
"_", "\\_",
"{", "\\{",
"}", "\\}",
"[", "\\[",
"]", "\\]",
"(", "\\(",
")", "\\)",
"#", "\\#",
"+", "\\+",
"!", "\\!",
"|", "\\|",
"<", "\\<",
">", "\\>",
)
return replacer.Replace(value)
}
func shouldItalicize(categories []string) bool {
for _, category := range categories {
switch category {
case "background", "backchannel", "filler":
return true
}
}
return false
}
func formatTimestamp(seconds float64) string {
total := int(math.Round(seconds))
if total < 0 {
total = 0
}
hours := total / 3600
minutes := (total % 3600) / 60
remainder := total % 60
return fmt.Sprintf("%02d:%02d:%02d", hours, minutes, remainder)
}