refactor(channelbridge): 多气泡分割+旁白剥离+随机延迟上移为IM公共出口——sendReply/SendProactive统一(微信主动推送也分割)
This commit is contained in:
1 parent
d09b25071d
commit
bcf7fe5de0
4 files changed
+233
-36
No files matched your search
@@ -0,0 +1,53 @@
|
||||
package channelbridge
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"git.yeij.top/AskaEth/Cyrene_v2/internal/channel/adapter"
|
||||
)
|
||||
|
||||
// bubbleSender is the per-bubble outbound call the shared IM dispatcher uses. A
|
||||
// reply exits through the adapter's SendMessage (UnifiedResponse) path, a proactive
|
||||
// push through its SendProactive path — both collapse to "dispatch one chat bubble to
|
||||
// the platform", which is what lets the reply and the proactive push share a single
|
||||
// sanitize/split/gap pipeline instead of each re-implementing it.
|
||||
type bubbleSender func(ctx context.Context, msg adapter.UnifiedMessage) error
|
||||
|
||||
// sendIMBubbles is the single IM outbound exit shared by sendReply (reply path) and
|
||||
// SendProactive (proactive push). It turns content into the plain chat bubbles an IM
|
||||
// channel should receive: role-play/action/narration markup (rendered as muted italic
|
||||
// on the Web) is stripped and each <p> paragraph is delivered as its own
|
||||
// bubble/message (design/17 §2), with a multi-bubble burst spacing its sends 0.5-2s
|
||||
// apart so it does not flood the channel. The Web frontend is never affected — it
|
||||
// renders the persisted stream directly and does not route through here.
|
||||
//
|
||||
// target carries the platform/channel targeting fields and is copied onto every
|
||||
// bubble (only Content/ContentType/Timestamp differ per bubble); sender is the
|
||||
// adapter's outbound call. A content that strips to nothing (a pure action line) is
|
||||
// dropped without a send, and a per-bubble failure is wrapped with its index.
|
||||
func (b *Bridge) sendIMBubbles(ctx context.Context, target adapter.UnifiedMessage, sender bubbleSender, content string) error {
|
||||
// splitBubbles applies stripNarration per bubble (so <action>/<narration> and the
|
||||
// star-drift role-play forms are removed for IM) and splits on <p>. It is the
|
||||
// single sanitize entry point, shared with the old reply path.
|
||||
bubbles := splitBubbles(content)
|
||||
if len(bubbles) == 0 {
|
||||
b.log.Debug("im outbound has no plain text, skipped", "platform", target.Platform, "channel", target.ChannelID)
|
||||
return nil
|
||||
}
|
||||
for i, bubble := range bubbles {
|
||||
if i > 0 {
|
||||
time.Sleep(b.bubbleGapFn())
|
||||
}
|
||||
out := target
|
||||
out.Content = bubble
|
||||
out.ContentType = adapter.ContentText
|
||||
out.Timestamp = time.Now().UTC()
|
||||
// Each bubble is its own send so the gap lands between messages.
|
||||
if err := sender(ctx, out); err != nil {
|
||||
return fmt.Errorf("channelbridge: send bubble #%d of %d: %w", i+1, len(bubbles), err)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
Reference in new issue
Block a user