Implement artifact-level render command with Markdown output and update docs
This commit is contained in:
75
internal/render/markdown.go
Normal file
75
internal/render/markdown.go
Normal file
@@ -0,0 +1,75 @@
|
||||
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, "# "+title, "")
|
||||
|
||||
if opts.IncludeMetadata {
|
||||
lines = append(lines,
|
||||
fmt.Sprintf("- Application: %s", transcript.Metadata.Application),
|
||||
fmt.Sprintf("- Version: %s", transcript.Metadata.Version),
|
||||
fmt.Sprintf("- Output schema: %s", 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 := segment.Text
|
||||
if shouldItalicize(segment.Categories) {
|
||||
text = "*" + text + "*"
|
||||
}
|
||||
parts = append(parts, fmt.Sprintf("**%s:** %s", 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 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)
|
||||
}
|
||||
Reference in New Issue
Block a user