AI:基于 Eino + DeepSeek 配合 RSS 实现的每日简报功能

AI:基于 Eino + DeepSeek 配合 RSS 实现的每日简报功能

功能说明

  • 支持日期、星期
  • 支持天气、温度、湿度
  • 支持新闻摘要

直接看代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
package daily

import (
"bytes"
"context"
"encoding/json"
"errors"
"fmt"
"io"
"net/http"
"testing"
"time"

"github.com/cloudwego/eino-ext/components/model/ark"
"github.com/cloudwego/eino/components/model"
"github.com/cloudwego/eino/compose"
"github.com/cloudwego/eino/schema"
"github.com/mmcdole/gofeed"
"github.com/stretchr/testify/require"
)

var fp = gofeed.NewParser()

func createModel(t *testing.T) model.ChatModel {
deepseek, err := ark.NewChatModel(t.Context(), &ark.ChatModelConfig{
BaseURL: "https://ark.cn-beijing.volces.com/api/v3",
APIKey: "[key]", // 请填写你的 API Key
Model: "deepseek-v3-241226",
})
require.NoError(t, err)
return deepseek
}

func TestDailyReport(t *testing.T) {
chain := compose.NewChain[string, *schema.Message]().
AppendParallel(
compose.NewParallel().
AddLambda("weather", compose.InvokableLambda(func(ctx context.Context, input string) (string, error) {
return fetchWeather(t), nil
})).
AddGraph("news",
compose.NewChain[string, string]().
AppendLambda(compose.InvokableLambda(func(ctx context.Context, input string) (*gofeed.Feed, error) {
return fp.ParseURL(input)
})).
AppendLambda(compose.InvokableLambda(func(ctx context.Context, input *gofeed.Feed) (string, error) {
var buffer bytes.Buffer
for i, item := range input.Items {
buffer.WriteString(fmt.Sprintf("%d. %s\n", i+1, item.Title))
}
return buffer.String(), nil
})),
),
).
AppendLambda(compose.InvokableLambda(func(ctx context.Context, input map[string]any) (string, error) {
var buffer bytes.Buffer
buffer.WriteString(fmt.Sprintf("今日日期: %s, %s\n\n", time.Now().Format(time.DateOnly), time.Now().Weekday()))
buffer.WriteString(fmt.Sprintf("今日天气: %s\n", input["weather"].(string)))
buffer.WriteString(fmt.Sprintf("今日新闻:\n%s\n", input["news"].(string)))

return buffer.String(), nil
})).
AppendGraph(
compose.NewChain[string, *schema.Message]().
AppendLambda(compose.InvokableLambda(func(ctx context.Context, input string) ([]*schema.Message, error) {
return []*schema.Message{
schema.SystemMessage(`You are a highly professional news summarization expert, capable of categorizing and organizing the article materials I provide into a summary format, presented in a point-by-point manner. Ultimately, deliver it to me in plain text, without Markdown syntax, in Chinese, as today's news summary.
**Format as follows:**

今天是 2021 年 3 月 19 日,星期五。天气晴朗,气温 20 度。以下是今日新闻摘要:

1. 企业动态:

- 华为将于3月20日至21日举行中国合作伙伴大会2025。
- 模速空间、无问芯穹和上海仪电推出国内首个“算力生态超市”。

2. 科技行业:

- 最低调“六小虎”阶跃星辰开年首秀,Agent落地智能终端,印奇也参与。
- “AI服务商”阿里巴巴值得重估。

...
`),
schema.UserMessage("Here are the articles:\n\n" + input),
}, nil
})).AppendChatModel(createModel(t)),
)

r, err := chain.Compile(t.Context())
require.NoError(t, err)

message, err := r.Stream(t.Context(), "https://36kr.com/feed")
require.NoError(t, err)

for {
msg, err := message.Recv()
if err != nil {
if errors.Is(err, io.EOF) {
break
}
}
require.NoError(t, err)
fmt.Print(msg.Content)
}
}

type weatherResult struct {
Status string `json:"status"`
Count string `json:"count"`
Info string `json:"info"`
InfoCode string `json:"infocode"`
Lives []struct {
Province string `json:"province"`
City string `json:"city"`
AdCode string `json:"adcode"`
Weather string `json:"weather"`
Temperature string `json:"temperature"`
WindDirection string `json:"winddirection"`
WindPower string `json:"windpower"`
Humidity string `json:"humidity"`
ReportTime string `json:"reporttime"`
TemperatureFloat string `json:"temperature_float"`
HumidityFloat string `json:"humidity_float"`
} `json:"lives"`
}

func fetchWeather(t *testing.T) string {
resp, err := http.Get("https://restapi.amap.com/v3/weather/weatherInfo?key=[key]&city=440300&extensions=base") // 此处使用的是高德 API(有免费额度),此处使用的是深圳天气,实际应用,可自定义城市编码,或者做个映射关系。附 API 地址:https://lbs.amap.com/api/webservice/guide/api/weatherinfo/#t1
require.NoError(t, err)
defer resp.Body.Close()

var res weatherResult
require.NoError(t, json.NewDecoder(resp.Body).Decode(&res))
require.Equal(t, "1", res.Status)

return fmt.Sprintf("天气: %s,气温: %s,湿度: %s", res.Lives[0].Weather, res.Lives[0].Temperature, res.Lives[0].Humidity)
}

阅读更多