feat: 频道自动发现 — platform-bridge定时刷新频道路由 + ai-core周期同步
platform-bridge: - QQ adapter: FetchGroups/FetchFriends 从NapCat API获取 - ChannelLister接口 + ChannelInfo结构体 - GET /api/v1/channels 端点 + cachedChannels缓存 - StartChannelRefresh 每10分钟自动刷新 ai-core: - channel_sync.go: 每5分钟从platform-bridge拉取频道 - 自动更新thinker的platformChannels + botUIDs - 不再依赖PLATFORM_CHANNELS环境变量手动配置 修复: - SendMessage显式设AutoEscape:false - PLATFORM_BRIDGE_URL默认端口8082→8095 - OBv11Params.AutoEscape去掉omitempty Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,135 @@
|
||||
package qq
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"git.yeij.top/AskaEth/Cyrene/platform-bridge/internal/bridge"
|
||||
)
|
||||
|
||||
// ListChannels implements bridge.ChannelLister — fetches groups + friends from NapCat.
|
||||
func (a *Adapter) ListChannels() []bridge.ChannelInfo {
|
||||
var all []bridge.ChannelInfo
|
||||
all = append(all, a.FetchGroups()...)
|
||||
all = append(all, a.FetchFriends()...)
|
||||
return all
|
||||
}
|
||||
|
||||
// FetchGroups fetches the group list from NapCat HTTP API and caches group names.
|
||||
// Returns a list of channel info for all groups the bot is in.
|
||||
func (a *Adapter) FetchGroups() []bridge.ChannelInfo {
|
||||
if a.mode != "client" || a.remoteURL == "" {
|
||||
return nil
|
||||
}
|
||||
httpBase := a.httpBase()
|
||||
if httpBase == "" {
|
||||
return nil
|
||||
}
|
||||
|
||||
url := fmt.Sprintf("%s/get_group_list", httpBase)
|
||||
if a.accessToken != "" {
|
||||
url += "?access_token=" + a.accessToken
|
||||
}
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
||||
defer cancel()
|
||||
req, err := http.NewRequestWithContext(ctx, "GET", url, nil)
|
||||
if err != nil {
|
||||
fmt.Printf("[qq:%s] get_group_list request failed: %v\n", a.configName, err)
|
||||
return nil
|
||||
}
|
||||
resp, err := http.DefaultClient.Do(req)
|
||||
if err != nil {
|
||||
fmt.Printf("[qq:%s] get_group_list failed: %v\n", a.configName, err)
|
||||
return nil
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
var result struct {
|
||||
Data []struct {
|
||||
GroupID int64 `json:"group_id"`
|
||||
GroupName string `json:"group_name"`
|
||||
} `json:"data"`
|
||||
}
|
||||
if err := json.NewDecoder(resp.Body).Decode(&result); err != nil {
|
||||
fmt.Printf("[qq:%s] get_group_list parse failed: %v\n", a.configName, err)
|
||||
return nil
|
||||
}
|
||||
|
||||
var channels []bridge.ChannelInfo
|
||||
for _, g := range result.Data {
|
||||
if g.GroupName != "" {
|
||||
a.SetGroupName(g.GroupID, g.GroupName)
|
||||
}
|
||||
channels = append(channels, bridge.ChannelInfo{
|
||||
Platform: "qq",
|
||||
ChannelType: "group",
|
||||
ChannelID: fmt.Sprintf("%d", g.GroupID),
|
||||
ChannelName: g.GroupName,
|
||||
})
|
||||
}
|
||||
fmt.Printf("[qq:%s] 获取到 %d 个群聊\n", a.configName, len(channels))
|
||||
return channels
|
||||
}
|
||||
|
||||
// FetchFriends fetches the friend list from NapCat HTTP API.
|
||||
// Returns a list of channel info for private chats.
|
||||
func (a *Adapter) FetchFriends() []bridge.ChannelInfo {
|
||||
if a.mode != "client" || a.remoteURL == "" {
|
||||
return nil
|
||||
}
|
||||
httpBase := a.httpBase()
|
||||
if httpBase == "" {
|
||||
return nil
|
||||
}
|
||||
|
||||
url := fmt.Sprintf("%s/get_friend_list", httpBase)
|
||||
if a.accessToken != "" {
|
||||
url += "?access_token=" + a.accessToken
|
||||
}
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
||||
defer cancel()
|
||||
req, err := http.NewRequestWithContext(ctx, "GET", url, nil)
|
||||
if err != nil {
|
||||
fmt.Printf("[qq:%s] get_friend_list request failed: %v\n", a.configName, err)
|
||||
return nil
|
||||
}
|
||||
resp, err := http.DefaultClient.Do(req)
|
||||
if err != nil {
|
||||
fmt.Printf("[qq:%s] get_friend_list failed: %v\n", a.configName, err)
|
||||
return nil
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
var result struct {
|
||||
Data []struct {
|
||||
UserID int64 `json:"user_id"`
|
||||
Nickname string `json:"nickname"`
|
||||
Remark string `json:"remark"`
|
||||
} `json:"data"`
|
||||
}
|
||||
if err := json.NewDecoder(resp.Body).Decode(&result); err != nil {
|
||||
fmt.Printf("[qq:%s] get_friend_list parse failed: %v\n", a.configName, err)
|
||||
return nil
|
||||
}
|
||||
|
||||
var channels []bridge.ChannelInfo
|
||||
for _, f := range result.Data {
|
||||
name := f.Remark
|
||||
if name == "" {
|
||||
name = f.Nickname
|
||||
}
|
||||
channels = append(channels, bridge.ChannelInfo{
|
||||
Platform: "qq",
|
||||
ChannelType: "private",
|
||||
ChannelID: fmt.Sprintf("%d", f.UserID),
|
||||
ChannelName: name,
|
||||
})
|
||||
}
|
||||
fmt.Printf("[qq:%s] 获取到 %d 个好友\n", a.configName, len(channels))
|
||||
return channels
|
||||
}
|
||||
Reference in New Issue
Block a user