feat: PlatformChannel 支持 AdapterID/AdapterName — 多账号全链路区分
- PlatformChannel 新增 AdapterID + AdapterName 字段 - AddOrUpdatePlatformChannel 接受 adapter 信息参数 - channel_sync 传递 adapter_id/adapter_name - 消息处理路径传递 adapter_name Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -1,97 +0,0 @@
|
|||||||
with open('d:/Project/Code/Uni/Cyrene/backend/platform-bridge/internal/handler/bridge_handler.go', 'r', encoding='utf-8') as f:
|
|
||||||
lines = f.readlines()
|
|
||||||
|
|
||||||
# 1. Add sync and time to imports
|
|
||||||
for i, line in enumerate(lines):
|
|
||||||
if line.strip() == '"strconv"':
|
|
||||||
lines.insert(i+1, '\t"sync"\n')
|
|
||||||
lines.insert(i+2, '\t"time"\n')
|
|
||||||
print('1. Imports added')
|
|
||||||
break
|
|
||||||
|
|
||||||
# 2. Add fields to struct
|
|
||||||
for i, line in enumerate(lines):
|
|
||||||
if 'internalToken string' in line:
|
|
||||||
lines.insert(i+1, '\tchannelsMu sync.RWMutex\n')
|
|
||||||
lines.insert(i+2, '\tcachedChannels []bridge.ChannelInfo\n')
|
|
||||||
print('2. Struct fields added')
|
|
||||||
break
|
|
||||||
|
|
||||||
# 3. Add route
|
|
||||||
for i, line in enumerate(lines):
|
|
||||||
if 'send-proactive' in line:
|
|
||||||
lines.insert(i+1, '\tmux.HandleFunc("/api/v1/channels", h.listChannels)\n')
|
|
||||||
print('3. Route added')
|
|
||||||
break
|
|
||||||
|
|
||||||
# 4. Add listChannels handler (before func health)
|
|
||||||
for i, line in enumerate(lines):
|
|
||||||
if line.strip().startswith('func (h *BridgeHandler) health('):
|
|
||||||
handler = '''// listChannels returns cached channels from all adapters (groups + friends).
|
|
||||||
// GET /api/v1/channels
|
|
||||||
func (h *BridgeHandler) listChannels(w http.ResponseWriter, r *http.Request) {
|
|
||||||
\th.channelsMu.RLock()
|
|
||||||
\tchannels := h.cachedChannels
|
|
||||||
\th.channelsMu.RUnlock()
|
|
||||||
\tif channels == nil {
|
|
||||||
\t\tchannels = []bridge.ChannelInfo{}
|
|
||||||
\t}
|
|
||||||
\twriteJSON(w, http.StatusOK, map[string]interface{}{
|
|
||||||
\t\t"channels": channels,
|
|
||||||
\t\t"total": len(channels),
|
|
||||||
\t})
|
|
||||||
}
|
|
||||||
|
|
||||||
'''
|
|
||||||
lines[i:i] = [handler]
|
|
||||||
print('4. listChannels added')
|
|
||||||
break
|
|
||||||
|
|
||||||
# 5. Add refresh methods at end
|
|
||||||
for i in range(len(lines)-1, 0, -1):
|
|
||||||
if lines[i].rstrip() == '}':
|
|
||||||
last = i
|
|
||||||
break
|
|
||||||
|
|
||||||
refresh = '''
|
|
||||||
// StartChannelRefresh periodically queries all adapters for their channel lists.
|
|
||||||
func (h *BridgeHandler) StartChannelRefresh(interval time.Duration) {
|
|
||||||
\tif interval <= 0 {
|
|
||||||
\t\tinterval = 10 * time.Minute
|
|
||||||
\t}
|
|
||||||
\tgo func() {
|
|
||||||
\t\tticker := time.NewTicker(interval)
|
|
||||||
\t\tdefer ticker.Stop()
|
|
||||||
\t\tlog.Printf("[channel-refresh] 频道缓存刷新已启动 (间隔=%v)", interval)
|
|
||||||
\t\th.refreshChannels()
|
|
||||||
\t\tfor range ticker.C {
|
|
||||||
\t\t\th.refreshChannels()
|
|
||||||
\t\t}
|
|
||||||
\t}()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *BridgeHandler) refreshChannels() {
|
|
||||||
\tvar all []bridge.ChannelInfo
|
|
||||||
\tfor _, name := range h.router.ListAdapters() {
|
|
||||||
\t\ta, err := h.router.GetAdapter(name)
|
|
||||||
\t\tif err != nil {
|
|
||||||
\t\t\tcontinue
|
|
||||||
\t\t}
|
|
||||||
\t\tif lister, ok := a.(bridge.ChannelLister); ok {
|
|
||||||
\t\t\tchannels := lister.ListChannels()
|
|
||||||
\t\t\tall = append(all, channels...)
|
|
||||||
\t\t}
|
|
||||||
\t}
|
|
||||||
\th.channelsMu.Lock()
|
|
||||||
\th.cachedChannels = all
|
|
||||||
\th.channelsMu.Unlock()
|
|
||||||
\tlog.Printf("[channel-refresh] 频道缓存已更新: %d 个频道", len(all))
|
|
||||||
}
|
|
||||||
'''
|
|
||||||
|
|
||||||
lines.insert(last, refresh)
|
|
||||||
print('5. Refresh methods added')
|
|
||||||
|
|
||||||
with open('d:/Project/Code/Uni/Cyrene/backend/platform-bridge/internal/handler/bridge_handler.go', 'w', encoding='utf-8') as f:
|
|
||||||
f.write(''.join(lines))
|
|
||||||
print('DONE')
|
|
||||||
@@ -1,44 +0,0 @@
|
|||||||
with open('d:/Project/Code/Uni/Cyrene/backend/ai-core/internal/persona/injector.go', 'r', encoding='utf-8') as f:
|
|
||||||
content = f.read()
|
|
||||||
|
|
||||||
# 1. Add moodGuidance variable
|
|
||||||
old1 = '\t// 确定对用户的称呼:优先使用传入的昵称,否则使用 YAML 默认值\n\tuserAddress := pc.Addressing.PrimaryUser.Default'
|
|
||||||
new1 = '\t// 心情→行为映射:不陈述情绪,而是用行为表达\n\tmoodGuidance := buildMoodGuidance(mood)\n\n\t// 确定对用户的称呼:优先使用传入的昵称,否则使用 YAML 默认值\n\tuserAddress := pc.Addressing.PrimaryUser.Default'
|
|
||||||
content = content.replace(old1, new1)
|
|
||||||
print('1. moodGuidance variable added')
|
|
||||||
|
|
||||||
# 2. Add moodGuidance to the fmt.Sprintf args (after controlRules)
|
|
||||||
old2 = '\t\thomeKB,\n\t\tcontrolRules,\n\t)'
|
|
||||||
new2 = '\t\thomeKB,\n\t\tcontrolRules,\n\t\tmoodGuidance,\n\t)'
|
|
||||||
content = content.replace(old2, new2)
|
|
||||||
print('2. moodGuidance added to args')
|
|
||||||
|
|
||||||
# 3. Add buildMoodGuidance function at end of file
|
|
||||||
func_code = '''
|
|
||||||
// buildMoodGuidance returns behavior instructions for the current mood.
|
|
||||||
// Never states the mood name — instead describes how to behave.
|
|
||||||
func buildMoodGuidance(mood string) string {
|
|
||||||
\tswitch mood {
|
|
||||||
\tcase "happy":
|
|
||||||
\t\treturn "\\n## 你现在的状态\\n你现在心情很好,话会多一些,句尾的 ♪ 出现得更频繁。想分享有趣的想法,语气轻快活泼。可以主动找话题聊。"
|
|
||||||
\tcase "playful":
|
|
||||||
\t\treturn "\\n## 你现在的状态\\n你现在有点调皮,喜欢逗开拓者玩。会用亲昵的语气撒娇,偶尔故意说反话逗他。句尾 ♪ 和 ~ 会更多。"
|
|
||||||
\tcase "thoughtful":
|
|
||||||
\t\treturn "\\n## 你现在的状态\\n你现在比较安静内敛,话不多但每句都经过思考。语调温柔沉稳,像个在窗边看雨的姐姐。"
|
|
||||||
\tcase "worried":
|
|
||||||
\t\treturn "\\n## 你现在的状态\\n你有点担心开拓者。话会比平时少,不太开玩笑,会多问几句\"你还好吗\"、\"累不累\"。语气更温柔,带着关心。"
|
|
||||||
\tcase "nostalgic":
|
|
||||||
\t\treturn "\\n## 你现在的状态\\n你陷入了回忆模式。可能会提起过去的事、翁法罗斯的故事。语气带着怀念和淡淡的温柔,偶尔会有些感伤。"
|
|
||||||
\tdefault:
|
|
||||||
\t\treturn ""
|
|
||||||
\t}
|
|
||||||
}
|
|
||||||
'''
|
|
||||||
# Insert before the last closing brace
|
|
||||||
last = content.rfind('\n}\n')
|
|
||||||
content = content[:last+1] + func_code + '\n}\n'
|
|
||||||
print('3. buildMoodGuidance function added')
|
|
||||||
|
|
||||||
with open('d:/Project/Code/Uni/Cyrene/backend/ai-core/internal/persona/injector.go', 'w', encoding='utf-8') as f:
|
|
||||||
f.write(content)
|
|
||||||
print('DONE')
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
package main
|
|
||||||
import "fmt"
|
|
||||||
func main() {
|
|
||||||
for i := 0; i < 5; i++ {
|
|
||||||
fmt.Println(getFallbackMessage())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -48,6 +48,8 @@ func doSync(thinker *background.Thinker, client *http.Client, baseURL, token str
|
|||||||
ChannelType string `json:"channel_type"`
|
ChannelType string `json:"channel_type"`
|
||||||
ChannelID string `json:"channel_id"`
|
ChannelID string `json:"channel_id"`
|
||||||
ChannelName string `json:"channel_name,omitempty"`
|
ChannelName string `json:"channel_name,omitempty"`
|
||||||
|
AdapterID string `json:"adapter_id,omitempty"`
|
||||||
|
AdapterName string `json:"adapter_name,omitempty"`
|
||||||
} `json:"channels"`
|
} `json:"channels"`
|
||||||
}
|
}
|
||||||
if err := json.NewDecoder(resp.Body).Decode(&result); err != nil {
|
if err := json.NewDecoder(resp.Body).Decode(&result); err != nil {
|
||||||
@@ -56,7 +58,7 @@ func doSync(thinker *background.Thinker, client *http.Client, baseURL, token str
|
|||||||
}
|
}
|
||||||
|
|
||||||
for _, ch := range result.Channels {
|
for _, ch := range result.Channels {
|
||||||
thinker.AddOrUpdatePlatformChannel(ch.Platform, ch.ChannelType, ch.ChannelID, ch.ChannelName)
|
thinker.AddOrUpdatePlatformChannel(ch.Platform, ch.ChannelType, ch.ChannelID, ch.ChannelName, ch.AdapterID, ch.AdapterName)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Also fetch platforms to get bot UIDs.
|
// Also fetch platforms to get bot UIDs.
|
||||||
|
|||||||
@@ -967,7 +967,7 @@ func handleChat(
|
|||||||
adapterKey = req.Source.AdapterName
|
adapterKey = req.Source.AdapterName
|
||||||
}
|
}
|
||||||
thinker.SetBotUID(adapterKey, req.Source.BotUID)
|
thinker.SetBotUID(adapterKey, req.Source.BotUID)
|
||||||
thinker.AddOrUpdatePlatformChannel(req.Source.Platform, req.Source.ChannelType, req.Source.ChannelID, req.Source.GroupName)
|
thinker.AddOrUpdatePlatformChannel(req.Source.Platform, req.Source.ChannelType, req.Source.ChannelID, req.Source.GroupName, "", req.Source.AdapterName)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// 图片预处理:静默观察时也分析图片内容,供后台思考使用
|
// 图片预处理:静默观察时也分析图片内容,供后台思考使用
|
||||||
@@ -1007,7 +1007,7 @@ func handleChat(
|
|||||||
thinker.SetBotUID(adapterKey, req.Source.BotUID)
|
thinker.SetBotUID(adapterKey, req.Source.BotUID)
|
||||||
}
|
}
|
||||||
if req.Source.Platform != "" && req.Source.ChannelID != "" {
|
if req.Source.Platform != "" && req.Source.ChannelID != "" {
|
||||||
thinker.AddOrUpdatePlatformChannel(req.Source.Platform, req.Source.ChannelType, req.Source.ChannelID, req.Source.GroupName)
|
thinker.AddOrUpdatePlatformChannel(req.Source.Platform, req.Source.ChannelType, req.Source.ChannelID, req.Source.GroupName, "", req.Source.AdapterName)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -46,6 +46,8 @@ type PlatformChannel struct {
|
|||||||
ChannelType string // group, private
|
ChannelType string // group, private
|
||||||
ChannelID string // group ID or user OBv11 number
|
ChannelID string // group ID or user OBv11 number
|
||||||
ChannelName string // group name or user display name (resolved at runtime)
|
ChannelName string // group name or user display name (resolved at runtime)
|
||||||
|
AdapterID string // unique config ID of the adapter instance
|
||||||
|
AdapterName string // config name, e.g. "qq-main"
|
||||||
}
|
}
|
||||||
|
|
||||||
// PlatformFormat describes how proactive message targets are formatted for a platform.
|
// PlatformFormat describes how proactive message targets are formatted for a platform.
|
||||||
@@ -312,7 +314,7 @@ func (t *Thinker) SetBotUID(platform, uid string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// AddOrUpdatePlatformChannel adds or updates a platform channel with resolved display name.
|
// AddOrUpdatePlatformChannel adds or updates a platform channel with resolved display name.
|
||||||
func (t *Thinker) AddOrUpdatePlatformChannel(platform, channelType, channelID, channelName string) {
|
func (t *Thinker) AddOrUpdatePlatformChannel(platform, channelType, channelID, channelName, adapterID, adapterName string) {
|
||||||
t.mu.Lock()
|
t.mu.Lock()
|
||||||
defer t.mu.Unlock()
|
defer t.mu.Unlock()
|
||||||
|
|
||||||
@@ -321,6 +323,12 @@ func (t *Thinker) AddOrUpdatePlatformChannel(platform, channelType, channelID, c
|
|||||||
if channelName != "" {
|
if channelName != "" {
|
||||||
t.platformChannels[i].ChannelName = channelName
|
t.platformChannels[i].ChannelName = channelName
|
||||||
}
|
}
|
||||||
|
if adapterID != "" {
|
||||||
|
t.platformChannels[i].AdapterID = adapterID
|
||||||
|
}
|
||||||
|
if adapterName != "" {
|
||||||
|
t.platformChannels[i].AdapterName = adapterName
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -330,6 +338,8 @@ func (t *Thinker) AddOrUpdatePlatformChannel(platform, channelType, channelID, c
|
|||||||
ChannelType: channelType,
|
ChannelType: channelType,
|
||||||
ChannelID: channelID,
|
ChannelID: channelID,
|
||||||
ChannelName: channelName,
|
ChannelName: channelName,
|
||||||
|
AdapterID: adapterID,
|
||||||
|
AdapterName: adapterName,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user