1- // Package aichat OpenAI聊天
1+ // Package aichat OpenAI聊天和群聊总结
22package aichat
33
44import (
55 "math/rand"
66 "strconv"
77 "strings"
8+ "time"
89
910 "github.com/fumiama/deepinfra"
1011 "github.com/fumiama/deepinfra/model"
1112 "github.com/sirupsen/logrus"
13+ "github.com/tidwall/gjson"
1214
1315 zero "github.com/wdvxdr1123/ZeroBot"
1416 "github.com/wdvxdr1123/ZeroBot/message"
@@ -18,6 +20,7 @@ import (
1820 ctrl "github.com/FloatTech/zbpctrl"
1921 "github.com/FloatTech/zbputils/chat"
2022 "github.com/FloatTech/zbputils/control"
23+ "github.com/FloatTech/zbputils/ctxext"
2124)
2225
2326var (
3033 "- 设置AI聊天温度80\n " +
3134 "- 设置AI聊天接口类型[OpenAI|OLLaMA|GenAI]\n " +
3235 "- 设置AI聊天(不)支持系统提示词\n " +
33- "- 设置AI聊天接口地址https://api.deepseek.com /chat/completions\n " +
36+ "- 设置AI聊天接口地址https://api.siliconflow.cn/v1 /chat/completions\n " +
3437 "- 设置AI聊天密钥xxx\n " +
35- "- 设置AI聊天模型名xxx \n " +
38+ "- 设置AI聊天模型名Qwen/Qwen3-8B \n " +
3639 "- 查看AI聊天系统提示词\n " +
3740 "- 重置AI聊天系统提示词\n " +
3841 "- 设置AI聊天系统提示词xxx\n " +
4144 "- 设置AI聊天最大长度4096\n " +
4245 "- 设置AI聊天TopP 0.9\n " +
4346 "- 设置AI聊天(不)以AI语音输出\n " +
44- "- 查看AI聊天配置\n " ,
47+ "- 查看AI聊天配置\n " +
48+ "- 重置AI聊天\n " +
49+ "- 群聊总结 [消息数目]|群聊总结 1000\n " ,
4550 PrivateDataFolder : "aichat" ,
4651 })
4752)
5358 "GenAI" : 2 ,
5459 }
5560 apilist = [3 ]string {"OpenAI" , "OLLaMA" , "GenAI" }
61+ limit = ctxext .NewLimiterManager (time .Second * 30 , 1 )
5662)
5763
5864func init () {
@@ -305,4 +311,93 @@ func init() {
305311 }
306312 ctx .SendChain (message .Text (printConfig (rate , temp , cfg )))
307313 })
314+ en .OnFullMatch ("重置AI聊天" , ensureconfig , zero .OnlyPrivate , zero .SuperUserPermission ).SetBlock (true ).Handle (func (ctx * zero.Ctx ) {
315+ chat .Reset ()
316+ ctx .SendChain (message .Text ("成功" ))
317+ })
318+
319+ // 添加群聊总结功能
320+ en .OnRegex (`^群聊总结\s?(\d*)$` , ensureconfig , zero .OnlyGroup , zero .AdminPermission ).SetBlock (true ).Limit (limit .LimitByGroup ).Handle (func (ctx * zero.Ctx ) {
321+ ctx .SendChain (message .Text ("少女思考中..." ))
322+ p , _ := strconv .ParseInt (ctx .State ["regex_matched" ].([]string )[1 ], 10 , 64 )
323+ if p > 1000 {
324+ p = 1000
325+ }
326+ if p == 0 {
327+ p = 200
328+ }
329+ gid := ctx .Event .GroupID
330+ group := ctx .GetGroupInfo (gid , false )
331+ if group .MemberCount == 0 {
332+ ctx .SendChain (message .Text (zero .BotConfig .NickName [0 ], "未加入" , group .Name , "(" , gid , "),无法获取摘要" ))
333+ return
334+ }
335+
336+ var messages []string
337+
338+ h := ctx .GetGroupMessageHistory (gid , 0 , p , false )
339+ h .Get ("messages" ).ForEach (func (_ , msgObj gjson.Result ) bool {
340+ nickname := msgObj .Get ("sender.nickname" ).Str
341+ text := strings .TrimSpace (message .ParseMessageFromString (msgObj .Get ("raw_message" ).Str ).ExtractPlainText ())
342+ if text != "" {
343+ messages = append (messages , nickname + ": " + text )
344+ }
345+ return true
346+ })
347+
348+ if len (messages ) == 0 {
349+ ctx .SendChain (message .Text ("ERROR: 历史消息为空或者无法获得历史消息" ))
350+ return
351+ }
352+
353+ // 调用大模型API进行摘要
354+ summary , err := summarizeMessages (messages )
355+ if err != nil {
356+ ctx .SendChain (message .Text ("ERROR: " , err ))
357+ return
358+ }
359+
360+ var b strings.Builder
361+ b .WriteString ("群 " )
362+ b .WriteString (group .Name )
363+ b .WriteByte ('(' )
364+ b .WriteString (strconv .FormatInt (gid , 10 ))
365+ b .WriteString (") 的 " )
366+ b .WriteString (strconv .FormatInt (p , 10 ))
367+ b .WriteString (" 条消息总结:\n \n " )
368+ b .WriteString (summary )
369+
370+ // 分割总结内容为多段
371+ parts := strings .Split (b .String (), "\n \n " )
372+ msg := make (message.Message , 0 , len (parts ))
373+ for _ , part := range parts {
374+ if part != "" {
375+ msg = append (msg , ctxext .FakeSenderForwardNode (ctx , message .Text (part )))
376+ }
377+ }
378+ if len (msg ) > 0 {
379+ ctx .Send (msg )
380+ }
381+ })
382+ }
383+
384+ // summarizeMessages 调用大模型API进行消息摘要
385+ func summarizeMessages (messages []string ) (string , error ) {
386+ // 使用现有的AI配置进行摘要
387+ x := deepinfra .NewAPI (cfg .API , cfg .Key )
388+ mod := model .NewOpenAI (
389+ cfg .ModelName , cfg .Separator ,
390+ float32 (70 )/ 100 , 0.9 , 4096 ,
391+ )
392+
393+ // 构造摘要请求提示
394+ summaryPrompt := "请总结这个群聊内容,要求按发言顺序梳理,明确标注每个发言者的昵称,并完整呈现其核心观点、提出的问题、发表的看法或做出的回应,确保不遗漏关键信息,且能体现成员间的对话逻辑和互动关系:\n \n " +
395+ strings .Join (messages , "\n ---\n " )
396+
397+ data , err := x .Request (mod .User (summaryPrompt ))
398+ if err != nil {
399+ return "" , err
400+ }
401+
402+ return strings .TrimSpace (data ), nil
308403}
0 commit comments