init
This commit is contained in:
commit
074feb0f8d
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
storage.json
|
||||
8
.idea/.gitignore
vendored
Normal file
8
.idea/.gitignore
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
# Default ignored files
|
||||
/shelf/
|
||||
/workspace.xml
|
||||
# Editor-based HTTP Client requests
|
||||
/httpRequests/
|
||||
# Datasource local storage ignored files
|
||||
/dataSources/
|
||||
/dataSources.local.xml
|
||||
9
Dockerfile
Normal file
9
Dockerfile
Normal file
@ -0,0 +1,9 @@
|
||||
FROM golang:1.16 as builder
|
||||
ENV GOPROXY=https://goproxy.cn,direct
|
||||
WORKDIR /app
|
||||
COPY . .
|
||||
RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o chatgpt
|
||||
FROM alpine:3.17.2
|
||||
WORKDIR /app
|
||||
COPY --from=builder /app/chatgpt .
|
||||
ENTRYPOINT ["./chatgpt"]
|
||||
3
Makefile
Normal file
3
Makefile
Normal file
@ -0,0 +1,3 @@
|
||||
build:
|
||||
docker build -t yy194131/chatgpt:$(version) .
|
||||
docker push yy194131/chatgpt:$(version)
|
||||
39
README.md
Normal file
39
README.md
Normal file
@ -0,0 +1,39 @@
|
||||
## 微信机器人
|
||||
|
||||
最近ChatGPT异常火爆,想到将其接入到个人微信是件比较有趣的事,所以有了这个项目。项目基于[openwechat](https://github.com/eatmoreapple/openwechat)开发,支持ChatGPT和New Bing,其中New Bing[依赖于new-bing项目](../new-bing)提供的http接口。
|
||||
|
||||
## 目前实现了以下功能
|
||||
+ 群聊@回复
|
||||
+ 私聊回复
|
||||
+ 自动通过回复
|
||||
|
||||
## 注册openai
|
||||
ChatGPT注册可以参考[这里](https://juejin.cn/post/7173447848292253704)
|
||||
|
||||
## 部署
|
||||
|
||||
```
|
||||
# 获取项目
|
||||
git clone https://github.com/bujnlc8/gptbing
|
||||
|
||||
# 进入项目目录
|
||||
cd gptbing/wechatbot
|
||||
|
||||
# 复制配置文件, 改成实际的值,注意去掉#注释
|
||||
copy config.json.example config.json
|
||||
|
||||
# 启动项目
|
||||
go run main.go
|
||||
|
||||
|
||||
或者docker部署
|
||||
|
||||
bash start.sh 0.0.2 # 代理地址根据实际情况修改,运行之后`docker logs wechatbot`会打印出登录地址
|
||||
|
||||
```
|
||||
|
||||
## 说明
|
||||
|
||||
本项目fork至[https://github.com/djun/wechatbot](https://github.com/djun/wechatbot),修改使之支持`ChatGPT`和`New Bing`,在此致谢!
|
||||
|
||||
**⚠️ 有一定的几率导致被微信封号,请谨慎使用,由此导致的封号,本人概不负责**
|
||||
34
bootstrap/bootstrap.go
Normal file
34
bootstrap/bootstrap.go
Normal file
@ -0,0 +1,34 @@
|
||||
package bootstrap
|
||||
|
||||
import (
|
||||
"log"
|
||||
|
||||
"github.com/bujnlc8/wechatbot/handlers"
|
||||
"github.com/bujnlc8/wechatbot/utils"
|
||||
"github.com/eatmoreapple/openwechat"
|
||||
)
|
||||
|
||||
func Run() {
|
||||
//bot := openwechat.DefaultBot()
|
||||
bot := openwechat.DefaultBot(openwechat.Desktop) // 桌面模式,上面登录不上的可以尝试切换这种模式
|
||||
|
||||
// 注册消息处理函数
|
||||
bot.MessageHandler = handlers.Handler
|
||||
// 注册登陆二维码回调
|
||||
bot.UUIDCallback = openwechat.PrintlnQrcodeUrl
|
||||
|
||||
// 创建热存储容器对象
|
||||
reloadStorage := openwechat.NewJsonFileHotReloadStorage("storage.json")
|
||||
// 执行热登录
|
||||
err := bot.HotLogin(reloadStorage)
|
||||
if err != nil {
|
||||
if err = bot.Login(); err != nil {
|
||||
log.Printf("login error: %v \n", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
// 阻塞主goroutine, 直到发生异常或者用户主动退出
|
||||
if err := bot.Block(); err != nil {
|
||||
utils.SendSimpleEmail("[!]wechatbot异常退出", err.Error())
|
||||
}
|
||||
}
|
||||
8
config.json.example
Normal file
8
config.json.example
Normal file
@ -0,0 +1,8 @@
|
||||
{
|
||||
"api_key": "", # chatgpt api key
|
||||
"auto_pass": true, # 是否自动通过好友申请
|
||||
"bing_chat_url": "" # New Bing 聊天接口
|
||||
"bing_chat_wake_word": "#bing", # new Bing唤醒词
|
||||
"gpt_chat_wake_word": "#gpt" # ChatGPT唤醒词
|
||||
"gpt_message_cache": 1 # 消息缓存数量
|
||||
}
|
||||
64
config/config.go
Normal file
64
config/config.go
Normal file
@ -0,0 +1,64 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"log"
|
||||
"os"
|
||||
"sync"
|
||||
)
|
||||
|
||||
// Configuration 项目配置
|
||||
type Configuration struct {
|
||||
// gpt apikey
|
||||
ApiKey string `json:"api_key"`
|
||||
// 自动通过好友
|
||||
AutoPass bool `json:"auto_pass"`
|
||||
// bing 聊天接口
|
||||
BingChatUrl string `json:"bing_chat_url"`
|
||||
GptChatUrl string `json:"gpt_chat_url"`
|
||||
// 机器人唤醒词
|
||||
BingChatWakeWord string `json:"bing_chat_wake_word"`
|
||||
GptChatWakeWord string `json:"gpt_chat_wake_word"`
|
||||
// 消息缓存数量
|
||||
GptMessageCache int `json:"gpt_message_cache"`
|
||||
// gpt上下文清空指令
|
||||
GptCleanContext string `json:"gpt_clean_context"`
|
||||
}
|
||||
|
||||
var config *Configuration
|
||||
var once sync.Once
|
||||
|
||||
// LoadConfig 加载配置
|
||||
func LoadConfig() *Configuration {
|
||||
once.Do(func() {
|
||||
// 从文件中读取
|
||||
config = &Configuration{}
|
||||
f, err := os.Open("config.json")
|
||||
if err != nil {
|
||||
log.Fatalf("open config err: %v", err)
|
||||
return
|
||||
}
|
||||
defer f.Close()
|
||||
encoder := json.NewDecoder(f)
|
||||
err = encoder.Decode(config)
|
||||
if err != nil {
|
||||
log.Fatalf("decode config err: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
// 如果环境变量有配置,读取环境变量
|
||||
ApiKey := os.Getenv("ApiKey")
|
||||
AutoPass := os.Getenv("AutoPass")
|
||||
BingChatUrl := os.Getenv("BingChatUrl")
|
||||
if ApiKey != "" {
|
||||
config.ApiKey = ApiKey
|
||||
}
|
||||
if AutoPass == "true" {
|
||||
config.AutoPass = true
|
||||
}
|
||||
if BingChatUrl != "" {
|
||||
config.BingChatUrl = BingChatUrl
|
||||
}
|
||||
})
|
||||
return config
|
||||
}
|
||||
5
go.mod
Normal file
5
go.mod
Normal file
@ -0,0 +1,5 @@
|
||||
module github.com/bujnlc8/wechatbot
|
||||
|
||||
go 1.16
|
||||
|
||||
require github.com/eatmoreapple/openwechat v1.4.2-0.20230321053318-1c102bdea8d7
|
||||
2
go.sum
Normal file
2
go.sum
Normal file
@ -0,0 +1,2 @@
|
||||
github.com/eatmoreapple/openwechat v1.4.2-0.20230321053318-1c102bdea8d7 h1:5vryo6dsmZZn1pYo8TrcqEUJq075QMpdDwLZz+oMfLs=
|
||||
github.com/eatmoreapple/openwechat v1.4.2-0.20230321053318-1c102bdea8d7/go.mod h1:ZxMcq7IpVWVU9JG7ERjExnm5M8/AQ6yZTtX30K3rwRQ=
|
||||
92
gpt/bing.go
Normal file
92
gpt/bing.go
Normal file
@ -0,0 +1,92 @@
|
||||
package gpt
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/bujnlc8/wechatbot/config"
|
||||
)
|
||||
|
||||
const Referer = "https://servicewechat.com/wxee7496be5b68b740"
|
||||
|
||||
type BingQueryParam struct {
|
||||
Q string `json:"q"`
|
||||
SID string `json:"sid"`
|
||||
AutoReset string `json:"auto_reset"`
|
||||
}
|
||||
|
||||
type BingResponse struct {
|
||||
Data BingResponseData `json:"data"`
|
||||
Cookie string `json:"cookie"`
|
||||
}
|
||||
|
||||
type BingResponseData struct {
|
||||
Suggests []string `json:"suggests"`
|
||||
Status string `json:"status"`
|
||||
Text string `json:"text"`
|
||||
Message string `json:"message"`
|
||||
}
|
||||
|
||||
func BingSearch(msg string, nickName string) (string, error) {
|
||||
requestBody := BingQueryParam{
|
||||
Q: msg,
|
||||
SID: nickName,
|
||||
AutoReset: "1",
|
||||
}
|
||||
requestData, err := json.Marshal(requestBody)
|
||||
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
log.Printf("request bing json string : %v", string(requestData))
|
||||
BingChatUrl := config.LoadConfig().BingChatUrl
|
||||
req, err := http.NewRequest("POST", BingChatUrl, bytes.NewBuffer(requestData))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
req.Header.Set("Referer", Referer)
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
client := &http.Client{}
|
||||
response, err := client.Do(req)
|
||||
if err != nil {
|
||||
return "非常抱歉😭,网络异常,请稍后重试", err
|
||||
}
|
||||
if response.StatusCode != 200 {
|
||||
return "非常抱歉😭,网络异常,请稍后重试 [" + strconv.Itoa(response.StatusCode) + "]", nil
|
||||
}
|
||||
defer response.Body.Close()
|
||||
|
||||
body, err := ioutil.ReadAll(response.Body)
|
||||
if err != nil {
|
||||
return "响应异常,请稍后再试", err
|
||||
}
|
||||
|
||||
bingResponse := &BingResponse{}
|
||||
log.Println(string(body))
|
||||
err = json.Unmarshal(body, bingResponse)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if bingResponse.Data.Status == "Success" {
|
||||
if strings.Contains(bingResponse.Data.Text, "New topic") {
|
||||
return bingResponse.Data.Text + "\n请重新开始对话", nil
|
||||
}
|
||||
return bingResponse.Data.Text, nil
|
||||
|
||||
} else {
|
||||
if bingResponse.Data.Status == "Throttled" {
|
||||
return "这真是愉快,但你已达到每日限制。是否明天再聊?", nil
|
||||
} else {
|
||||
if strings.Contains(bingResponse.Data.Message, "has expired") {
|
||||
return "本轮对话已过期,请重新开始。", nil
|
||||
} else {
|
||||
return "抱歉😭,发生错误:" + bingResponse.Data.Message + ",请重试", nil
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
15
gpt/bing_test.go
Normal file
15
gpt/bing_test.go
Normal file
@ -0,0 +1,15 @@
|
||||
package gpt
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestBing(t *testing.T) {
|
||||
reply, err := BingSearch("今天北京的天气怎么样", "nickname")
|
||||
if err != nil{
|
||||
t.Error(err)
|
||||
}
|
||||
fmt.Printf("%+v\n", reply)
|
||||
|
||||
}
|
||||
113
gpt/gpt.go
Normal file
113
gpt/gpt.go
Normal file
@ -0,0 +1,113 @@
|
||||
package gpt
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"net/http"
|
||||
|
||||
"github.com/bujnlc8/wechatbot/config"
|
||||
)
|
||||
|
||||
var BASEURL = config.LoadConfig().GptChatUrl
|
||||
|
||||
type Message struct {
|
||||
Role string `json:"role"`
|
||||
Content string `json:"content"`
|
||||
}
|
||||
|
||||
// ChatGPTResponseBody 请求体
|
||||
type ChatGPTResponseBody struct {
|
||||
ID string `json:"id"`
|
||||
Object string `json:"object"`
|
||||
Created int `json:"created"`
|
||||
Model string `json:"model"`
|
||||
Choices []ChoiceItem `json:"choices"`
|
||||
Usage map[string]interface{} `json:"usage"`
|
||||
}
|
||||
|
||||
type ChoiceItem struct {
|
||||
Message Message `json:"message"`
|
||||
FinishReason string `json:"finish_reason"`
|
||||
}
|
||||
|
||||
// ChatGPTRequestBody 响应体
|
||||
type ChatGPTRequestBody struct {
|
||||
Model string `json:"model"`
|
||||
MaxTokens int `json:"max_tokens"`
|
||||
Temperature float32 `json:"temperature"`
|
||||
Messages []Message `json:"messages"`
|
||||
}
|
||||
|
||||
var MessageCacheRegistry = make(map[string][]Message)
|
||||
|
||||
func CleanContext(nickName string) (string, error) {
|
||||
messageCache := []Message{}
|
||||
MessageCacheRegistry[nickName] = messageCache
|
||||
return "用户[" + nickName + "]上下文已清空", nil
|
||||
}
|
||||
|
||||
func Completions(msg string, nickName string) (string, error) {
|
||||
cache := config.LoadConfig().GptMessageCache
|
||||
messageCache := MessageCacheRegistry[nickName]
|
||||
message := Message{Role: "user", Content: msg}
|
||||
if messageCache == nil || len(messageCache) == 0 {
|
||||
messageCache = []Message{message}
|
||||
} else {
|
||||
messageCache = append(messageCache, message)
|
||||
// 只保留20条
|
||||
if len(messageCache) > cache {
|
||||
messageCache = messageCache[(len(messageCache) - cache):]
|
||||
}
|
||||
}
|
||||
MessageCacheRegistry[nickName] = messageCache
|
||||
requestBody := ChatGPTRequestBody{
|
||||
Model: "gpt-3.5-turbo",
|
||||
MaxTokens: 4096,
|
||||
Temperature: 1.2,
|
||||
Messages: messageCache,
|
||||
}
|
||||
requestData, err := json.Marshal(requestBody)
|
||||
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
log.Printf("request gpt json string : %v", string(requestData))
|
||||
req, err := http.NewRequest("POST", BASEURL+"completions", bytes.NewBuffer(requestData))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
apiKey := config.LoadConfig().ApiKey
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
req.Header.Set("Authorization", "Bearer "+apiKey)
|
||||
client := &http.Client{}
|
||||
response, err := client.Do(req)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer response.Body.Close()
|
||||
|
||||
body, err := ioutil.ReadAll(response.Body)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
gptResponseBody := &ChatGPTResponseBody{}
|
||||
log.Println(string(body))
|
||||
err = json.Unmarshal(body, gptResponseBody)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
var reply string
|
||||
if len(gptResponseBody.Choices) > 0 {
|
||||
for _, v := range gptResponseBody.Choices {
|
||||
messageCache = append(messageCache, v.Message)
|
||||
MessageCacheRegistry[nickName] = messageCache
|
||||
reply = v.Message.Content
|
||||
break
|
||||
}
|
||||
}
|
||||
log.Printf("gpt response text: %s \n", reply)
|
||||
return reply, nil
|
||||
}
|
||||
14
gpt/gpt_test.go
Normal file
14
gpt/gpt_test.go
Normal file
@ -0,0 +1,14 @@
|
||||
package gpt
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestGpt(t *testing.T) {
|
||||
reply, err := Completions("今天北京的天气怎么样", "nickname")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
fmt.Printf("%+v\n", reply)
|
||||
}
|
||||
95
handlers/group_msg_handler.go
Normal file
95
handlers/group_msg_handler.go
Normal file
@ -0,0 +1,95 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"github.com/bujnlc8/wechatbot/config"
|
||||
"log"
|
||||
"strings"
|
||||
|
||||
"github.com/bujnlc8/wechatbot/gpt"
|
||||
"github.com/eatmoreapple/openwechat"
|
||||
)
|
||||
|
||||
var _ MessageHandlerInterface = (*GroupMessageHandler)(nil)
|
||||
|
||||
// GroupMessageHandler 群消息处理
|
||||
type GroupMessageHandler struct {
|
||||
}
|
||||
|
||||
// handle 处理消息
|
||||
func (g *GroupMessageHandler) handle(msg *openwechat.Message) error {
|
||||
bingWakeWord := config.LoadConfig().BingChatWakeWord
|
||||
gptWakeWord := config.LoadConfig().GptChatWakeWord
|
||||
if msg.IsText() {
|
||||
return g.ReplyText(msg)
|
||||
} else {
|
||||
if strings.Contains(msg.Content, gptWakeWord) || strings.Contains(msg.Content, bingWakeWord) {
|
||||
msg.ReplyText("目前我只支持文字哦~")
|
||||
}
|
||||
}
|
||||
if msg.IsPaiYiPai() {
|
||||
msg.ReplyText("我是机器人🤖️,会拍坏的哦~")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// NewGroupMessageHandler 创建群消息处理器
|
||||
func NewGroupMessageHandler() MessageHandlerInterface {
|
||||
return &GroupMessageHandler{}
|
||||
}
|
||||
|
||||
// ReplyText 发送文本消息到群
|
||||
func (g *GroupMessageHandler) ReplyText(msg *openwechat.Message) error {
|
||||
sender, err := msg.Sender()
|
||||
group := openwechat.Group{User: sender}
|
||||
log.Printf("Received Group %v Text Msg : %v", group.NickName, msg.Content)
|
||||
|
||||
bingWakeWord := config.LoadConfig().BingChatWakeWord
|
||||
gptWakeWord := config.LoadConfig().GptChatWakeWord
|
||||
|
||||
// @GPTBot 或者 @bing的消息才处理
|
||||
if !(strings.Contains(msg.Content, gptWakeWord) || strings.Contains(msg.Content, bingWakeWord)) {
|
||||
return nil
|
||||
}
|
||||
|
||||
requestText := strings.TrimSpace(strings.ReplaceAll(msg.Content, gptWakeWord, ""))
|
||||
var reply = ""
|
||||
if strings.EqualFold(msg.Content, config.LoadConfig().GptCleanContext) {
|
||||
cleanReply, _ := gpt.CleanContext(group.UserName)
|
||||
reply = "\n" + cleanReply
|
||||
} else if strings.Contains(msg.Content, bingWakeWord) {
|
||||
requestText = strings.TrimSpace(strings.ReplaceAll(msg.Content, bingWakeWord, ""))
|
||||
reply, err = gpt.BingSearch(requestText, group.UserName)
|
||||
if reply != "" && strings.HasPrefix(reply, "[") {
|
||||
reply = "\n" + reply
|
||||
}
|
||||
} else {
|
||||
reply, err = gpt.Completions(requestText, group.UserName)
|
||||
}
|
||||
if err != nil {
|
||||
log.Printf("gpt request error: %v \n", err)
|
||||
msg.ReplyText("机器人神了,我一会发现了就去修。")
|
||||
return err
|
||||
}
|
||||
if reply == "" {
|
||||
msg.ReplyText("机器人响应为空")
|
||||
return nil
|
||||
}
|
||||
|
||||
// 获取@我的用户
|
||||
groupSender, err := msg.SenderInGroup()
|
||||
if err != nil {
|
||||
log.Printf("get sender in group error :%v \n", err)
|
||||
return err
|
||||
}
|
||||
|
||||
// 回复@我的用户
|
||||
reply = strings.TrimSpace(reply)
|
||||
reply = strings.Trim(reply, "\n")
|
||||
atText := "@" + groupSender.NickName
|
||||
replyText := atText + " " + reply
|
||||
_, err = msg.ReplyText(replyText)
|
||||
if err != nil {
|
||||
log.Printf("response group error: %v \n", err)
|
||||
}
|
||||
return err
|
||||
}
|
||||
52
handlers/handler.go
Normal file
52
handlers/handler.go
Normal file
@ -0,0 +1,52 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"log"
|
||||
|
||||
"github.com/bujnlc8/wechatbot/config"
|
||||
"github.com/eatmoreapple/openwechat"
|
||||
)
|
||||
|
||||
// MessageHandlerInterface 消息处理接口
|
||||
type MessageHandlerInterface interface {
|
||||
handle(*openwechat.Message) error
|
||||
ReplyText(*openwechat.Message) error
|
||||
}
|
||||
|
||||
type HandlerType string
|
||||
|
||||
const (
|
||||
GroupHandler = "group"
|
||||
UserHandler = "user"
|
||||
)
|
||||
|
||||
// handlers 所有消息类型类型的处理器
|
||||
var handlers map[HandlerType]MessageHandlerInterface
|
||||
|
||||
func init() {
|
||||
handlers = make(map[HandlerType]MessageHandlerInterface)
|
||||
handlers[GroupHandler] = NewGroupMessageHandler()
|
||||
handlers[UserHandler] = NewUserMessageHandler()
|
||||
}
|
||||
|
||||
// Handler 全局处理入口
|
||||
func Handler(msg *openwechat.Message) {
|
||||
log.Printf("hadler Received msg : %v", msg.Content)
|
||||
// 处理群消息
|
||||
if msg.IsSendByGroup() {
|
||||
handlers[GroupHandler].handle(msg)
|
||||
return
|
||||
}
|
||||
// 好友申请
|
||||
if msg.IsFriendAdd() {
|
||||
if config.LoadConfig().AutoPass {
|
||||
_, err := msg.Agree("你好我是基于chatGPT引擎开发的微信机器人,你可以向我提问任何问题。")
|
||||
if err != nil {
|
||||
log.Fatalf("add friend agree error : %v", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
// 私聊
|
||||
handlers[UserHandler].handle(msg)
|
||||
}
|
||||
78
handlers/user_msg_handler.go
Normal file
78
handlers/user_msg_handler.go
Normal file
@ -0,0 +1,78 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"github.com/bujnlc8/wechatbot/config"
|
||||
"log"
|
||||
"strings"
|
||||
|
||||
"github.com/bujnlc8/wechatbot/gpt"
|
||||
"github.com/eatmoreapple/openwechat"
|
||||
)
|
||||
|
||||
var _ MessageHandlerInterface = (*UserMessageHandler)(nil)
|
||||
|
||||
// UserMessageHandler 私聊消息处理
|
||||
type UserMessageHandler struct {
|
||||
}
|
||||
|
||||
// handle 处理消息
|
||||
func (g *UserMessageHandler) handle(msg *openwechat.Message) error {
|
||||
if msg.IsText() {
|
||||
return g.ReplyText(msg)
|
||||
}
|
||||
if msg.IsSendByFriend() {
|
||||
if msg.IsPaiYiPai() {
|
||||
msg.ReplyText("我是机器人🤖️,会拍坏的哦~")
|
||||
} else {
|
||||
msg.ReplyText("目前我只支持文字哦~")
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// NewUserMessageHandler 创建私聊处理器
|
||||
func NewUserMessageHandler() MessageHandlerInterface {
|
||||
return &UserMessageHandler{}
|
||||
}
|
||||
|
||||
// ReplyText 发送文本消息到群
|
||||
func (g *UserMessageHandler) ReplyText(msg *openwechat.Message) error {
|
||||
// 接收私聊消息
|
||||
sender, err := msg.Sender()
|
||||
log.Printf("Received User %v Text Msg : %v", sender.UserName, msg.Content)
|
||||
|
||||
requestText := strings.TrimSpace(msg.Content)
|
||||
requestText = strings.Trim(msg.Content, "\n")
|
||||
|
||||
bingWakeWord := config.LoadConfig().BingChatWakeWord
|
||||
gptWakeWord := config.LoadConfig().GptChatWakeWord
|
||||
|
||||
var reply = ""
|
||||
if strings.Contains(msg.Content, bingWakeWord) {
|
||||
requestText = strings.TrimSpace(strings.ReplaceAll(msg.Content, bingWakeWord, ""))
|
||||
reply, err = gpt.BingSearch(requestText, sender.UserName)
|
||||
} else if strings.Contains(msg.Content, gptWakeWord) {
|
||||
requestText = strings.TrimSpace(strings.ReplaceAll(msg.Content, gptWakeWord, ""))
|
||||
reply, err = gpt.Completions(requestText, sender.UserName)
|
||||
} else {
|
||||
//可以考虑对接其他机器人恢复信息
|
||||
}
|
||||
if err != nil {
|
||||
log.Printf("gpt request error: %v \n", err)
|
||||
msg.ReplyText("机器人神了,我一会发现了就去修。")
|
||||
return err
|
||||
}
|
||||
if reply == "" {
|
||||
msg.ReplyText("机器人响应为空")
|
||||
return nil
|
||||
}
|
||||
|
||||
// 回复用户
|
||||
reply = strings.TrimSpace(reply)
|
||||
reply = strings.Trim(reply, "\n")
|
||||
_, err = msg.ReplyText(reply)
|
||||
if err != nil {
|
||||
log.Printf("response user error: %v \n", err)
|
||||
}
|
||||
return err
|
||||
}
|
||||
9
main.go
Normal file
9
main.go
Normal file
@ -0,0 +1,9 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/bujnlc8/wechatbot/bootstrap"
|
||||
)
|
||||
|
||||
func main() {
|
||||
bootstrap.Run()
|
||||
}
|
||||
9
start.sh
Normal file
9
start.sh
Normal file
@ -0,0 +1,9 @@
|
||||
docker pull yy194131/chatgpt:$1
|
||||
|
||||
count=$(docker ps -a | grep wechatbot | wc -l)
|
||||
if [ $count -gt 0 ]; then
|
||||
docker stop wechatbot && docker rm wechatbot
|
||||
fi
|
||||
|
||||
# 代理地址改成实际的地址
|
||||
docker run --name wechatbot -d -e https_proxy=代理地址 -v $(pwd)/config.json:/app/config.json yy194131/chatgpt:$1
|
||||
37
utils/send_mail.go
Normal file
37
utils/send_mail.go
Normal file
@ -0,0 +1,37 @@
|
||||
package utils
|
||||
|
||||
import (
|
||||
"log"
|
||||
"net/smtp"
|
||||
"os"
|
||||
)
|
||||
|
||||
const (
|
||||
SMTP_SERVER = "smtp.qq.com"
|
||||
SMTP_PORT = "587"
|
||||
)
|
||||
|
||||
// 用qq邮箱发送邮件,从New Bing写的代码修改而来
|
||||
func SendSimpleEmail(subject string, body string) {
|
||||
sender := os.Getenv("EMAIL_SENDER")
|
||||
passwd := os.Getenv("EMAIL_PASSWD")
|
||||
recipient := os.Getenv("EMAIL_RECIPIENT")
|
||||
if len(recipient) == 0 {
|
||||
recipient = sender
|
||||
}
|
||||
auth := smtp.PlainAuth("", sender, passwd, SMTP_SERVER)
|
||||
header := make(map[string]string)
|
||||
header["To"] = recipient
|
||||
header["From"] = sender
|
||||
header["Subject"] = subject
|
||||
headerStr := ""
|
||||
for k, v := range header {
|
||||
headerStr += k + ": " + v + "\r\n"
|
||||
}
|
||||
message := headerStr + "\r\n\r\n" + body
|
||||
err := smtp.SendMail(SMTP_SERVER+":"+SMTP_PORT, auth, sender, []string{recipient}, []byte(message))
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
log.Println("Email sent successfully")
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user