9 Commits

Author SHA1 Message Date
glidea
8f32e427d4 update README 2025-05-06 11:31:39 +08:00
glidea
3049c49f7a fix dedup 2025-05-06 11:27:36 +08:00
glidea
14a4f2b8d4 fix rewrite error handing 2025-05-03 14:51:27 +08:00
glidea
6a869574fc update README 2025-05-02 11:38:58 +08:00
glidea
c581cbacda fix rewrite error handing 2025-05-01 19:19:34 +08:00
glidea
e7fe17a4bc update image 2025-04-30 20:16:28 +08:00
glidea
b35aaa3b68 update image 2025-04-30 20:13:25 +08:00
glidea
be83967168 update README 2025-04-30 11:41:44 +08:00
glidea
064bca1dda fix lint 2025-04-29 08:22:03 +08:00
5 changed files with 41 additions and 15 deletions

View File

@@ -1,8 +1,21 @@
[English](README-en.md)
zenfeed用 AI 赋能 RSS自动为你筛选、总结、推送重要信息告别信息过载重拾阅读掌控感。
![](docs/images/crad.png)
开箱即用的公共服务站https://zenfeed.xyz (集成 Github TrendingV2EX 热榜等常见公开信源)
三点:
**1. AI 版 RSS 阅读器**
**2. 实时 “新闻” 知识库**
**3. 帮你时刻关注 “指定事件” 的秘书(如 “关税政策变化”“xx 股票波动”)**
开箱即用的公共服务站https://zenfeed.xyz (集成 Hacker NewsGithub TrendingV2EX 热榜等常见公开信源)
> 总结模型以更新至 Gemini 2.5pro!!
豆包机器人上架中!
加入下方👇🏻微信群关注更新
## 前言
@@ -142,8 +155,6 @@ $env:API_KEY = "硅基流动apikey"; docker-compose -p zenfeed up -d
* 支持 Webhook 通知
* 爬虫
> 进展会第一时间在 [Linux Do](https://linux.do/u/ajd/summary) 更新
## 有任何问题与反馈,欢迎加群讨论
<img src="docs/images/wechat.png" alt="Wechat" width="150">

BIN
docs/images/crad.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 617 KiB

View File

@@ -275,7 +275,12 @@ func (r *router) Route(ctx context.Context, result *rule.Result) (groups []*Grou
return groups, nil
}
func (r *router) generateSummary(ctx context.Context, prompt string, feeds []*Feed, sourceLabel string) (string, error) {
func (r *router) generateSummary(
ctx context.Context,
prompt string,
feeds []*Feed,
sourceLabel string,
) (string, error) {
content := r.parseContentToSummary(feeds, sourceLabel)
if content == "" {
return "", nil
@@ -296,6 +301,7 @@ func (r *router) generateSummary(ctx context.Context, prompt string, feeds []*Fe
func (r *router) parseContentToSummary(feeds []*Feed, sourceLabel string) string {
if sourceLabel == "" {
b := runtimeutil.Must1(json.Marshal(feeds))
return string(b)
}

View File

@@ -208,10 +208,11 @@ func (s *scraper) fillIDs(feeds []*model.Feed) []*model.Feed {
for _, feed := range feeds {
// We can not use the pub time to join the hash,
// because the pub time is dynamic for some sources.
//
// title may be changed for some sources... so...
source := feed.Labels.Get(model.LabelSource)
title := feed.Labels.Get(model.LabelTitle)
link := feed.Labels.Get(model.LabelLink)
feed.ID = hashutil.Sum64s([]string{source, title, link})
feed.ID = hashutil.Sum64s([]string{source, link})
}
return feeds

View File

@@ -22,6 +22,7 @@ import (
"reflect"
"strconv"
"sync"
"sync/atomic"
"time"
"github.com/benbjohnson/clock"
@@ -578,10 +579,14 @@ func (s *storage) blockDependencies() block.Dependencies {
}
func (s *storage) rewrite(ctx context.Context, feeds []*model.Feed) ([]*model.Feed, error) {
rewritten := make([]*model.Feed, 0, len(feeds))
var wg sync.WaitGroup
var errs []error
var mu sync.Mutex
var (
rewritten = make([]*model.Feed, 0, len(feeds))
wg sync.WaitGroup
mu sync.Mutex
errs []error
dropped atomic.Int32
)
for _, item := range feeds { // TODO: Limit the concurrency & goroutine number.
wg.Add(1)
go func(item *model.Feed) {
@@ -596,6 +601,7 @@ func (s *storage) rewrite(ctx context.Context, feeds []*model.Feed) ([]*model.Fe
}
if len(labels) == 0 {
log.Debug(ctx, "drop feed", "id", item.ID)
dropped.Add(1)
return // Drop empty labels.
}
@@ -607,10 +613,12 @@ func (s *storage) rewrite(ctx context.Context, feeds []*model.Feed) ([]*model.Fe
}(item)
}
wg.Wait()
if allFailed := len(errs) == len(feeds); allFailed {
return nil, errs[0]
}
if len(errs) > 0 {
switch len(errs) {
case 0:
case len(feeds) - int(dropped.Load()):
return nil, errs[0] // All failed.
default:
log.Error(ctx, errors.Wrap(errs[0], "rewrite feeds"), "error_count", len(errs))
}