Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a rewrite rule translators_title("zh-cn") so that when fetching the feed #2922

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ require (
github.com/gorilla/mux v1.8.1
github.com/lib/pq v1.10.9
github.com/prometheus/client_golang v1.20.5
github.com/sashabaranov/go-openai v1.32.5
github.com/tdewolff/minify/v2 v2.21.1
github.com/yuin/goldmark v1.7.8
golang.org/x/crypto v0.28.0
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@ github.com/prometheus/common v0.55.0 h1:KEi6DK7lXW/m7Ig5i47x0vRzuBsHuvJdi5ee6Y3G
github.com/prometheus/common v0.55.0/go.mod h1:2SECS4xJG1kd8XF9IcM1gMX6510RAEL65zxzNImwdc8=
github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc=
github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk=
github.com/sashabaranov/go-openai v1.32.5 h1:/eNVa8KzlE7mJdKPZDj6886MUzZQjoVHyn0sLvIt5qA=
github.com/sashabaranov/go-openai v1.32.5/go.mod h1:lj5b/K+zjTSFxVLijLSTDZuP7adOgerWeFyZLUhAKRg=
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/tdewolff/minify/v2 v2.21.1 h1:AAf5iltw6+KlUvjRNPAPrANIXl3XEJNBBzuZom5iCAM=
Expand Down
13 changes: 13 additions & 0 deletions internal/config/options.go
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,8 @@ const (
defaultWatchdog = true
defaultInvidiousInstance = "yewtu.be"
defaultWebAuthn = false
defaultChatGTPToken = ""
defaultChatGTPBaseURL = "https://api.openai.com/v1"
)

var defaultHTTPClientUserAgent = "Mozilla/5.0 (compatible; Miniflux/" + version.Version + "; +https://miniflux.app)"
Expand Down Expand Up @@ -177,6 +179,8 @@ type Options struct {
invidiousInstance string
mediaProxyPrivateKey []byte
webAuthn bool
chatgptUrl string
chatgptToken string
}

// NewOptions returns Options with default values.
Expand Down Expand Up @@ -256,6 +260,8 @@ func NewOptions() *Options {
invidiousInstance: defaultInvidiousInstance,
mediaProxyPrivateKey: crypto.GenerateRandomBytes(16),
webAuthn: defaultWebAuthn,
chatgptUrl: defaultChatGTPBaseURL,
chatgptToken: defaultChatGTPToken,
}
}

Expand Down Expand Up @@ -654,6 +660,13 @@ func (o *Options) FilterEntryMaxAgeDays() int {
return o.filterEntryMaxAgeDays
}

func (o *Options) GetChatGPTToken() string {
return o.chatgptToken
}
func (o *Options) GetChatGPTUrl() string {
return o.chatgptUrl
}

// SortedOptions returns options as a list of key value pairs, sorted by keys.
func (o *Options) SortedOptions(redactSecret bool) []*Option {
var keyValues = map[string]interface{}{
Expand Down
4 changes: 4 additions & 0 deletions internal/config/parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -279,6 +279,10 @@ func (p *Parser) parseLines(lines []string) (err error) {
p.opts.invidiousInstance = parseString(value, defaultInvidiousInstance)
case "WEBAUTHN":
p.opts.webAuthn = parseBool(value, defaultWebAuthn)
case "CHAT_GTP_URL":
p.opts.chatgptUrl = parseString(value, defaultChatGTPBaseURL)
case "CHAT_GTP_TOKEN":
p.opts.chatgptToken = parseString(value, defaultChatGTPToken)
}
}

Expand Down
38 changes: 38 additions & 0 deletions internal/reader/rewrite/rewriter.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,18 @@
package rewrite // import "miniflux.app/v2/internal/reader/rewrite"

import (
"context"
"fmt"
"log/slog"
"miniflux.app/v2/internal/config"
"strconv"
"strings"
"text/scanner"

"miniflux.app/v2/internal/model"
"miniflux.app/v2/internal/urllib"

openai "github.com/sashabaranov/go-openai"
"golang.org/x/text/cases"
"golang.org/x/text/language"
)
Expand Down Expand Up @@ -69,6 +73,12 @@ func (rule rule) applyRule(entryURL string, entry *model.Entry) {
slog.String("entry_url", entryURL),
)
}
case "translators_title":
if len(rule.args) == 1 {
entry.Title = translatorsTitle(entry.Title, rule.args[0])
} else {
entry.Title = translatorsTitle(entry.Title, "zh-cn")
}
case "remove":
// Format: remove("#selector > .element, .another")
if len(rule.args) >= 1 {
Expand Down Expand Up @@ -149,3 +159,31 @@ func getPredefinedRewriteRules(entryURL string) string {

return ""
}

func translatorsTitle(title string, targetLanguage string) string {
gptConfig := openai.DefaultConfig(config.Opts.GetChatGPTToken())
gptConfig.BaseURL = config.Opts.GetChatGPTUrl()
client := openai.NewClientWithConfig(gptConfig)
response, err := client.CreateChatCompletion(
context.Background(),
openai.ChatCompletionRequest{
Model: openai.GPT4oMini,
Messages: []openai.ChatCompletionMessage{
{
Role: openai.ChatMessageRoleSystem,
Content: fmt.Sprintf(`
You are a super translator and also a news anchor, proficient in various languages. I need you to help me translate the following news headlines into [%s], keeping the original meaning as much as possible. Proper nouns and abbreviations can be left untranslated. Do not say anything outside of the translation; serious penalties will apply if you do.`, targetLanguage),
},
{
Role: openai.ChatMessageRoleUser,
Content: title,
},
},
})
if err != nil {
slog.Error("Cannot translate title", err)
return title
}
slog.Debug("Translated title", slog.String("title", title), slog.String("translated_title", response.Choices[0].Message.Content))
return response.Choices[0].Message.Content
}