feat: make streaming throttle interval and min growth configurable
Move hardcoded streamThrottleInterval (3s) and streamMinGrowth (200) into StreamingConfig so they can be tuned per deployment via config or environment variables.
This commit is contained in:
parent
fa3c00ad9c
commit
0213494cff
4 changed files with 26 additions and 20 deletions
|
|
@ -2,9 +2,9 @@ package telegram
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
|
||||||
"crypto/rand"
|
"crypto/rand"
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
"os"
|
"os"
|
||||||
|
|
@ -798,10 +798,13 @@ func (c *TelegramChannel) BeginStream(ctx context.Context, chatID string) (chann
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
streamCfg := c.config.Channels.Telegram.Streaming
|
||||||
return &telegramStreamer{
|
return &telegramStreamer{
|
||||||
bot: c.bot,
|
bot: c.bot,
|
||||||
chatID: cid,
|
chatID: cid,
|
||||||
draftID: cryptoRandInt(), // non-zero random draft ID
|
draftID: cryptoRandInt(),
|
||||||
|
throttleInterval: time.Duration(streamCfg.ThrottleSeconds) * time.Second,
|
||||||
|
minGrowth: streamCfg.MinGrowthChars,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -812,17 +815,14 @@ type telegramStreamer struct {
|
||||||
bot *telego.Bot
|
bot *telego.Bot
|
||||||
chatID int64
|
chatID int64
|
||||||
draftID int
|
draftID int
|
||||||
|
throttleInterval time.Duration
|
||||||
|
minGrowth int
|
||||||
lastLen int
|
lastLen int
|
||||||
lastAt time.Time
|
lastAt time.Time
|
||||||
failed bool
|
failed bool
|
||||||
mu sync.Mutex
|
mu sync.Mutex
|
||||||
}
|
}
|
||||||
|
|
||||||
const (
|
|
||||||
streamThrottleInterval = 3 * time.Second
|
|
||||||
streamMinGrowth = 200 // minimum character growth to send an update
|
|
||||||
)
|
|
||||||
|
|
||||||
func (s *telegramStreamer) Update(ctx context.Context, content string) error {
|
func (s *telegramStreamer) Update(ctx context.Context, content string) error {
|
||||||
s.mu.Lock()
|
s.mu.Lock()
|
||||||
defer s.mu.Unlock()
|
defer s.mu.Unlock()
|
||||||
|
|
@ -834,7 +834,7 @@ func (s *telegramStreamer) Update(ctx context.Context, content string) error {
|
||||||
// Throttle: skip if not enough time or content has passed
|
// Throttle: skip if not enough time or content has passed
|
||||||
now := time.Now()
|
now := time.Now()
|
||||||
growth := len(content) - s.lastLen
|
growth := len(content) - s.lastLen
|
||||||
if s.lastLen > 0 && now.Sub(s.lastAt) < streamThrottleInterval && growth < streamMinGrowth {
|
if s.lastLen > 0 && now.Sub(s.lastAt) < s.throttleInterval && growth < s.minGrowth {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -239,6 +239,8 @@ type PlaceholderConfig struct {
|
||||||
|
|
||||||
type StreamingConfig struct {
|
type StreamingConfig struct {
|
||||||
Enabled bool `json:"enabled,omitempty" env:"PICOCLAW_CHANNELS_TELEGRAM_STREAMING_ENABLED"`
|
Enabled bool `json:"enabled,omitempty" env:"PICOCLAW_CHANNELS_TELEGRAM_STREAMING_ENABLED"`
|
||||||
|
ThrottleSeconds int `json:"throttle_seconds,omitempty" env:"PICOCLAW_CHANNELS_TELEGRAM_STREAMING_THROTTLE_SECONDS"`
|
||||||
|
MinGrowthChars int `json:"min_growth_chars,omitempty" env:"PICOCLAW_CHANNELS_TELEGRAM_STREAMING_MIN_GROWTH_CHARS"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type WhatsAppConfig struct {
|
type WhatsAppConfig struct {
|
||||||
|
|
|
||||||
|
|
@ -58,7 +58,7 @@ func DefaultConfig() *Config {
|
||||||
Enabled: true,
|
Enabled: true,
|
||||||
Text: "Thinking... 💭",
|
Text: "Thinking... 💭",
|
||||||
},
|
},
|
||||||
Streaming: StreamingConfig{Enabled: true},
|
Streaming: StreamingConfig{Enabled: true, ThrottleSeconds: 3, MinGrowthChars: 200},
|
||||||
},
|
},
|
||||||
Feishu: FeishuConfig{
|
Feishu: FeishuConfig{
|
||||||
Enabled: false,
|
Enabled: false,
|
||||||
|
|
|
||||||
|
|
@ -248,7 +248,11 @@ func (p *Provider) ChatStream(
|
||||||
}
|
}
|
||||||
|
|
||||||
// parseStreamResponse parses an OpenAI-compatible SSE stream.
|
// parseStreamResponse parses an OpenAI-compatible SSE stream.
|
||||||
func parseStreamResponse(ctx context.Context, reader io.Reader, onChunk func(accumulated string)) (*LLMResponse, error) {
|
func parseStreamResponse(
|
||||||
|
ctx context.Context,
|
||||||
|
reader io.Reader,
|
||||||
|
onChunk func(accumulated string),
|
||||||
|
) (*LLMResponse, error) {
|
||||||
var textContent strings.Builder
|
var textContent strings.Builder
|
||||||
var finishReason string
|
var finishReason string
|
||||||
var usage *UsageInfo
|
var usage *UsageInfo
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue