feat: migrate codes from previous project
This commit is contained in:
46
internal/config/config.go
Normal file
46
internal/config/config.go
Normal file
@@ -0,0 +1,46 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/spf13/viper"
|
||||
)
|
||||
|
||||
func LoadConfig() (*Config, error) {
|
||||
v := viper.New()
|
||||
|
||||
v.AutomaticEnv()
|
||||
|
||||
v.SetConfigName("config")
|
||||
v.SetConfigType("yaml")
|
||||
v.AddConfigPath("./config")
|
||||
v.AddConfigPath(".")
|
||||
|
||||
if err := v.ReadInConfig(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
v.SetConfigName(".env")
|
||||
v.SetConfigType("env")
|
||||
|
||||
if err := v.MergeInConfig(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, key := range v.AllKeys() {
|
||||
if strings.Contains(key, "_") {
|
||||
nestedKey := strings.Replace(key, "_", ".", 1)
|
||||
|
||||
if !v.IsSet(nestedKey) || v.Get(nestedKey) == "" {
|
||||
v.Set(nestedKey, v.Get(key))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var cfg Config
|
||||
if err := v.Unmarshal(&cfg); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &cfg, nil
|
||||
}
|
||||
24
internal/config/types.go
Normal file
24
internal/config/types.go
Normal file
@@ -0,0 +1,24 @@
|
||||
package config
|
||||
|
||||
type Config struct {
|
||||
Subscribes []Subscribe `mapstructure:"subscribes"`
|
||||
Feishu Feishu `mapstructure:"feishu"`
|
||||
Silicon Silicon `mapstructure:"silicon"`
|
||||
}
|
||||
|
||||
type Subscribe struct {
|
||||
Name string `mapstructure:"name"`
|
||||
Url string `mapstructure:"url"`
|
||||
Prompt string `mapstructure:"prompt"`
|
||||
Model string `mapstructure:"model"`
|
||||
}
|
||||
|
||||
type Feishu struct {
|
||||
AppID string `mapstructure:"app_id"`
|
||||
AppSecret string `mapstructure:"app_secret"`
|
||||
ChatID string `mapstructure:"chat_id"`
|
||||
}
|
||||
|
||||
type Silicon struct {
|
||||
Token string `mapstructure:"token"`
|
||||
}
|
||||
53
internal/feishu/client.go
Normal file
53
internal/feishu/client.go
Normal file
@@ -0,0 +1,53 @@
|
||||
package feishu
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"github.com/google/uuid"
|
||||
lark "github.com/larksuite/oapi-sdk-go/v3"
|
||||
larkcore "github.com/larksuite/oapi-sdk-go/v3/core"
|
||||
larkim "github.com/larksuite/oapi-sdk-go/v3/service/im/v1"
|
||||
)
|
||||
|
||||
type Client struct {
|
||||
larkClient *lark.Client
|
||||
}
|
||||
|
||||
func NewClient(larkClient *lark.Client) *Client {
|
||||
return &Client{larkClient: larkClient}
|
||||
}
|
||||
|
||||
func (c *Client) SendMessageToChat(ctx context.Context, message, chatID string) error {
|
||||
content := &MessageContent{
|
||||
Text: message,
|
||||
}
|
||||
contentJson, err := json.Marshal(content)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
contentString := string(contentJson)
|
||||
|
||||
req := larkim.NewCreateMessageReqBuilder().
|
||||
ReceiveIdType("chat_id").
|
||||
Body(larkim.NewCreateMessageReqBodyBuilder().
|
||||
ReceiveId(chatID).
|
||||
MsgType(`text`).
|
||||
Content(contentString).
|
||||
Uuid(uuid.New().String()).
|
||||
Build()).
|
||||
Build()
|
||||
|
||||
resp, err := c.larkClient.Im.V1.Message.Create(ctx, req)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if !resp.Success() {
|
||||
fmt.Printf("logId: %s, error response: \n%s", resp.RequestId(), larkcore.Prettify(resp.CodeError))
|
||||
return nil
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
5
internal/feishu/types.go
Normal file
5
internal/feishu/types.go
Normal file
@@ -0,0 +1,5 @@
|
||||
package feishu
|
||||
|
||||
type MessageContent struct {
|
||||
Text string `json:"text"`
|
||||
}
|
||||
71
internal/net/client.go
Normal file
71
internal/net/client.go
Normal file
@@ -0,0 +1,71 @@
|
||||
package net
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"io"
|
||||
"net/http"
|
||||
"time"
|
||||
)
|
||||
|
||||
type Client struct {
|
||||
client *http.Client
|
||||
}
|
||||
|
||||
func NewClient() *Client {
|
||||
return &Client{client: &http.Client{
|
||||
Timeout: time.Minute * 5,
|
||||
}}
|
||||
}
|
||||
|
||||
func (c *Client) Get(ctx context.Context, url string) (string, error) {
|
||||
req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
resp, err := c.client.Do(req)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer func(Body io.ReadCloser) {
|
||||
_ = Body.Close()
|
||||
}(resp.Body)
|
||||
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return string(body), nil
|
||||
}
|
||||
|
||||
func (c *Client) Post(ctx context.Context, headers map[string]string, url string, body any, target any) error {
|
||||
var buf bytes.Buffer
|
||||
if err := json.NewEncoder(&buf).Encode(body); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
req, err := http.NewRequestWithContext(ctx, http.MethodPost, url, &buf)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for k, v := range headers {
|
||||
req.Header.Set(k, v)
|
||||
}
|
||||
|
||||
resp, err := c.client.Do(req)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer func(Body io.ReadCloser) {
|
||||
_ = Body.Close()
|
||||
}(resp.Body)
|
||||
|
||||
if err := json.NewDecoder(resp.Body).Decode(target); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
48
internal/rss/client.go
Normal file
48
internal/rss/client.go
Normal file
@@ -0,0 +1,48 @@
|
||||
package rss
|
||||
|
||||
import (
|
||||
"context"
|
||||
"rss-to-feishu-next/internal/config"
|
||||
"rss-to-feishu-next/internal/net"
|
||||
)
|
||||
|
||||
type Client struct {
|
||||
netClient *net.Client
|
||||
}
|
||||
|
||||
func NewClient(client *net.Client) *Client {
|
||||
return &Client{netClient: client}
|
||||
}
|
||||
|
||||
func (c *Client) FetchRss(ctx context.Context, name, url string) (*Message, error) {
|
||||
resp, err := c.netClient.Get(ctx, url)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &Message{
|
||||
Name: name,
|
||||
Url: url,
|
||||
Content: resp,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (c *Client) FetchAllRss(ctx context.Context) ([]*Message, error) {
|
||||
cfg, err := config.LoadConfig()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var messages []*Message
|
||||
subscribes := cfg.Subscribes
|
||||
|
||||
for i := 0; i < len(cfg.Subscribes); i++ {
|
||||
message, err := c.FetchRss(ctx, subscribes[i].Name, subscribes[i].Url)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
messages = append(messages, message)
|
||||
}
|
||||
|
||||
return messages, nil
|
||||
}
|
||||
7
internal/rss/types.go
Normal file
7
internal/rss/types.go
Normal file
@@ -0,0 +1,7 @@
|
||||
package rss
|
||||
|
||||
type Message struct {
|
||||
Name string
|
||||
Url string
|
||||
Content string
|
||||
}
|
||||
50
internal/silicon/client.go
Normal file
50
internal/silicon/client.go
Normal file
@@ -0,0 +1,50 @@
|
||||
package silicon
|
||||
|
||||
import (
|
||||
"context"
|
||||
"rss-to-feishu-next/internal/config"
|
||||
"rss-to-feishu-next/internal/net"
|
||||
)
|
||||
|
||||
type Client struct {
|
||||
netClient *net.Client
|
||||
}
|
||||
|
||||
func NewClient(client *net.Client) *Client {
|
||||
return &Client{client}
|
||||
}
|
||||
|
||||
func (c *Client) FetchModelResponse(ctx context.Context, message, model string) (*Response, error) {
|
||||
cfg, err := config.LoadConfig()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
token := cfg.Silicon.Token
|
||||
|
||||
headers := map[string]string{
|
||||
"Content-Type": "application/json",
|
||||
"Authorization": "Bearer " + token,
|
||||
}
|
||||
|
||||
var messages []*Message
|
||||
messages = append(messages, &Message{
|
||||
Role: "user",
|
||||
Content: message,
|
||||
})
|
||||
|
||||
body := &RequestBody{
|
||||
Model: model,
|
||||
Messages: messages,
|
||||
Temperature: 0.7,
|
||||
MaxTokens: 8096,
|
||||
}
|
||||
|
||||
var resp *Response
|
||||
url := "https://api.siliconflow.cn/v1/messages"
|
||||
if err := c.netClient.Post(ctx, headers, url, body, &resp); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return resp, nil
|
||||
}
|
||||
21
internal/silicon/types.go
Normal file
21
internal/silicon/types.go
Normal file
@@ -0,0 +1,21 @@
|
||||
package silicon
|
||||
|
||||
type Response struct {
|
||||
Id string `json:"id"`
|
||||
Type string `json:"type"`
|
||||
Content []struct {
|
||||
Text string `json:"text"`
|
||||
} `json:"content"`
|
||||
}
|
||||
|
||||
type RequestBody struct {
|
||||
Model string `json:"model"`
|
||||
Messages []*Message `json:"messages"`
|
||||
Temperature float64 `json:"temperature"`
|
||||
MaxTokens int `json:"max_tokens"`
|
||||
}
|
||||
|
||||
type Message struct {
|
||||
Role string `json:"role"`
|
||||
Content string `json:"content"`
|
||||
}
|
||||
Reference in New Issue
Block a user