1
0
mirror of https://github.com/coalaura/whiskr.git synced 2025-12-02 20:22:52 +00:00

better markdown parsing

This commit is contained in:
Laura
2025-09-12 14:54:35 +02:00
parent ea65f7fd60
commit 44a5c1cd62
4 changed files with 137 additions and 77 deletions

BIN
.github/images.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 653 KiB

76
chat.go
View File

@@ -7,7 +7,6 @@ import (
"fmt"
"io"
"net/http"
"regexp"
"strings"
"github.com/revrost/go-openrouter"
@@ -436,78 +435,3 @@ func RunCompletion(ctx context.Context, response *Stream, request *openrouter.Ch
return tool, buf.String(), nil
}
func SplitImagePairs(text string) []openrouter.ChatMessagePart {
rgx := regexp.MustCompile(`(?m)!\[[^\]]*]\((\S+?)\)`)
var (
index int
parts []openrouter.ChatMessagePart
)
push := func(str, end int) {
if str > end {
return
}
rest := text[str:end]
if rest == "" {
return
}
total := len(parts)
if total > 0 && parts[total-1].Type == openrouter.ChatMessagePartTypeText {
parts[total-1].Text += rest
return
}
parts = append(parts, openrouter.ChatMessagePart{
Type: openrouter.ChatMessagePartTypeText,
Text: rest,
})
}
for {
location := rgx.FindStringSubmatchIndex(text[index:])
if location == nil {
push(index, len(text)-1)
break
}
start := index + location[0]
end := index + location[1]
urlStart := index + location[2]
urlEnd := index + location[3]
url := text[urlStart:urlEnd]
if !strings.HasPrefix(url, "https://") && !strings.HasPrefix(url, "http://") {
push(index, end)
index = end
continue
}
if start > index {
push(index, start)
}
parts = append(parts, openrouter.ChatMessagePart{
Type: openrouter.ChatMessagePartTypeImageURL,
ImageURL: &openrouter.ChatMessageImageURL{
Detail: openrouter.ImageURLDetailAuto,
URL: url,
},
})
index = end
}
return parts
}

132
markdown.go Normal file
View File

@@ -0,0 +1,132 @@
package main
import (
"regexp"
"strings"
"github.com/revrost/go-openrouter"
)
type CodeRegion struct {
Start int
End int
}
func FindMarkdownCodeRegions(text string) []CodeRegion {
var regions []CodeRegion
inline := regexp.MustCompile(`\x60[^\x60\n]+?\x60`)
for _, match := range inline.FindAllStringIndex(text, -1) {
regions = append(regions, CodeRegion{
Start: match[0],
End: match[1],
})
}
fenced := regexp.MustCompile(`(?m)^\x60\x60\x60[^\n]*\n(.*?\n)^\x60\x60\x60\s*$`)
for _, match := range fenced.FindAllStringIndex(text, -1) {
regions = append(regions, CodeRegion{
Start: match[0],
End: match[1],
})
}
return regions
}
func IsInsideCodeBlock(pos int, regions []CodeRegion) bool {
for _, region := range regions {
if pos >= region.Start && pos < region.End {
return true
}
}
return false
}
func SplitImagePairs(text string) []openrouter.ChatMessagePart {
code := FindMarkdownCodeRegions(text)
rgx := regexp.MustCompile(`(?m)!\[[^\]]*]\((\S+?)\)`)
var (
index int
parts []openrouter.ChatMessagePart
)
push := func(str, end int) {
if str > end {
return
}
rest := text[str:end]
if rest == "" {
return
}
total := len(parts)
if total > 0 && parts[total-1].Type == openrouter.ChatMessagePartTypeText {
parts[total-1].Text += rest
return
}
parts = append(parts, openrouter.ChatMessagePart{
Type: openrouter.ChatMessagePartTypeText,
Text: rest,
})
}
for {
location := rgx.FindStringSubmatchIndex(text[index:])
if location == nil {
push(index, len(text)-1)
break
}
start := index + location[0]
end := index + location[1]
if IsInsideCodeBlock(start, code) {
push(index, end)
index = end
continue
}
urlStart := index + location[2]
urlEnd := index + location[3]
url := text[urlStart:urlEnd]
if !strings.HasPrefix(url, "https://") && !strings.HasPrefix(url, "http://") {
push(index, end)
index = end
continue
}
if start > index {
push(index, start)
}
parts = append(parts, openrouter.ChatMessagePart{
Type: openrouter.ChatMessagePartTypeImageURL,
ImageURL: &openrouter.ChatMessageImageURL{
Detail: openrouter.ImageURLDetailAuto,
URL: url,
},
})
index = end
}
return parts
}

View File

@@ -174,7 +174,7 @@
this.#build(collapsed);
this.#render();
if (tool) {
if (tool?.name) {
this.setTool(tool);
}
@@ -592,6 +592,8 @@
this.#_message.classList.toggle("has-tool", !!this.#tool);
this.#updateToolHeight();
noScroll || scroll();
updateScrollButton();
@@ -631,6 +633,8 @@
if (!only || only === "reasoning") {
this.#patch("reasoning", this.#_reasoning, this.#reasoning, () => {
this.#updateReasoningHeight();
noScroll || scroll();
updateScrollButton();