feat: server-side Markdown rendering with goldmark v1.6.0

- Implement renderMarkdown() in http.go using goldmark
- Add goldmark extension: GFM, TaskList, Typographer
- Remove frontend regex-based markdown processing
- Update go.mod/go.sum with goldmark dependency
This commit is contained in:
JaviLib 2026-02-22 04:53:47 +01:00
parent efeedfcaae
commit 2e8d29bb96
4 changed files with 27 additions and 8 deletions

1
go.mod
View file

@ -17,6 +17,7 @@ require (
github.com/slack-go/slack v0.17.3
github.com/stretchr/testify v1.11.1
github.com/tencent-connect/botgo v0.2.1
github.com/yuin/goldmark v1.6.0
golang.org/x/oauth2 v0.35.0
)

2
go.sum
View file

@ -149,6 +149,8 @@ github.com/xyproto/randomstring v1.0.5/go.mod h1:rgmS5DeNXLivK7YprL0pY+lTuhNQW3i
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
github.com/yuin/goldmark v1.6.0 h1:boZcn2GTjpsynOsC0iJHnBWa4Bi0qzfJjthwauItG68=
github.com/yuin/goldmark v1.6.0/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
go.uber.org/mock v0.6.0 h1:hyF9dfmbgIX5EfOdasqLsWD6xqpNZlXblLB/Dbnwv3Y=
go.uber.org/mock v0.6.0/go.mod h1:KiVJ4BqZJaMj4svdfmHM0AUx4NJYO8ZNpPnZn1Z+BBU=
golang.org/x/arch v0.24.0 h1:qlJ3M9upxvFfwRM51tTg3Yl+8CP9vCC1E7vlFpgv99Y=

View file

@ -7,10 +7,13 @@ import (
"fmt"
"html/template"
"net/http"
"strings"
"sync"
"time"
"github.com/gorilla/websocket"
"github.com/yuin/goldmark"
"github.com/yuin/goldmark/extension"
"github.com/sipeed/picoclaw/pkg/bus"
"github.com/sipeed/picoclaw/pkg/config"
@ -128,9 +131,12 @@ func (c *HTTPChannel) Send(ctx context.Context, msg bus.OutboundMessage) error {
return nil
}
// Render Markdown to HTML before sending
renderedContent := renderMarkdown(msg.Content)
wsMsg := WSMessage{
Type: "response",
Content: msg.Content,
Content: renderedContent,
ChatID: msg.ChatID,
}
@ -272,4 +278,21 @@ func (c *HTTPChannel) removeSession(chatID string) {
func generateChatID(r *http.Request) string {
return fmt.Sprintf("web_%d", time.Now().UnixNano())
}
// renderMarkdown converts Markdown to HTML using goldmark
func renderMarkdown(input string) string {
md := goldmark.New(
goldmark.WithExtensions(
extension.GFM,
extension.TaskList,
extension.Typographer,
),
)
var buf strings.Builder
if err := md.Convert([]byte(input), &buf); err != nil {
return input // fallback to plain text on error
}
return buf.String()
}

View file

@ -247,13 +247,6 @@
function addMessage(content, type) {
const div = document.createElement('div');
div.className = `message ${type}`;
// Simple markdown-like formatting for code blocks
content = content.replace(/```(\w*)\n?([\s\S]*?)```/g, '<pre><code>$2</code></pre>');
content = content.replace(/`([^`]+)`/g, '<code>$1</code>');
content = content.replace(/\*\*([^*]+)\*\*/g, '<strong>$1</strong>');
content = content.replace(/\n/g, '<br>');
div.innerHTML = content;
chatContainer.appendChild(div);
chatContainer.scrollTop = chatContainer.scrollHeight;