feat: switch to OpenRouter for web search integration
This commit is contained in:
		
							parent
							
								
									07d2042eb7
								
							
						
					
					
						commit
						7fd8146ec5
					
				
							
								
								
									
										27
									
								
								assistant.go
								
								
								
								
							
							
						
						
									
										27
									
								
								assistant.go
								
								
								
								
							| 
						 | 
				
			
			@ -95,7 +95,7 @@ type assistantStreamedResponseCb func(text string, finished bool) error
 | 
			
		|||
 | 
			
		||||
func assistantStreamedResponse(request openai.ChatRequest, cb assistantStreamedResponseCb) error {
 | 
			
		||||
	logger.Debugw("Openai chat request", "req", request)
 | 
			
		||||
	ai := openai.NewClient(config.OpenAIApiKey)
 | 
			
		||||
	ai := openai.NewClientWithBaseUrl(config.OpenAIApiKey, config.OpenAIApiBaseURL)
 | 
			
		||||
 | 
			
		||||
	var (
 | 
			
		||||
		resp *openai.ChatResponseStream
 | 
			
		||||
| 
						 | 
				
			
			@ -234,23 +234,24 @@ func handleAssistantConversation(c tele.Context, thread []*tele.Message) error {
 | 
			
		|||
	}
 | 
			
		||||
 | 
			
		||||
	req := openai.ChatRequest{
 | 
			
		||||
		Model:       openai.ModelGpt5,
 | 
			
		||||
		Messages:    chatReqMsgs,
 | 
			
		||||
		Temperature: nil, // lo.ToPtr(0.42),
 | 
			
		||||
		User:        assistantHashUserId(lastMsg.Sender.ID),
 | 
			
		||||
		Model:           openai.ModelGpt5Online,
 | 
			
		||||
		Messages:        chatReqMsgs,
 | 
			
		||||
		ReasoningEffort: openai.ReasoningEffortMedium,
 | 
			
		||||
		Temperature:     nil, // lo.ToPtr(0.42),
 | 
			
		||||
		User:            assistantHashUserId(lastMsg.Sender.ID),
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	typingNotifyCh := setTyping(c)
 | 
			
		||||
	// typingNotifyCh := setTyping(c)
 | 
			
		||||
 | 
			
		||||
	var replyMsg *tele.Message
 | 
			
		||||
	replyMsg, err := c.Bot().Reply(lastMsg, reasoningIndicatorMessage, tele.Silent)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		logger.Errorw("assistant: failed to complete reasoning request", "error", err)
 | 
			
		||||
		return c.Reply("Sorry, there's a technical issue. 😵💫 Please try again later.", tele.Silent)
 | 
			
		||||
	}
 | 
			
		||||
	reqErr := assistantStreamedResponse(req, func(text string, finished bool) error {
 | 
			
		||||
		var err error
 | 
			
		||||
		if replyMsg == nil {
 | 
			
		||||
			<-typingNotifyCh
 | 
			
		||||
			replyMsg, err = c.Bot().Reply(lastMsg, text, tele.Silent)
 | 
			
		||||
		} else {
 | 
			
		||||
			replyMsg, err = c.Bot().Edit(replyMsg, text)
 | 
			
		||||
		}
 | 
			
		||||
		replyMsg, err = c.Bot().Edit(replyMsg, text)
 | 
			
		||||
 | 
			
		||||
		if finished && err == nil {
 | 
			
		||||
			replyMsg.ReplyTo = lastMsg // nasty bug
 | 
			
		||||
			if err := cacheMessage(replyMsg); err != nil {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										3
									
								
								cfg.go
								
								
								
								
							
							
						
						
									
										3
									
								
								cfg.go
								
								
								
								
							| 
						 | 
				
			
			@ -24,7 +24,8 @@ type ConfigDef struct {
 | 
			
		|||
	MonthlyTrafficLimitGiB int    `env:"TG_MONTHLY_TRAFFIC_LIMIT_GIB" env-default:"1000"`
 | 
			
		||||
 | 
			
		||||
	// AI
 | 
			
		||||
	OpenAIApiKey string `env:"TG_OPENAI_API_KEY"`
 | 
			
		||||
	OpenAIApiKey     string `env:"TG_OPENAI_API_KEY"`
 | 
			
		||||
	OpenAIApiBaseURL string `env:"TG_OPENAI_API_BASE_URL"`
 | 
			
		||||
 | 
			
		||||
	// Parsed fields
 | 
			
		||||
	adminUidLookup map[int64]struct{}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -5,7 +5,7 @@ import (
 | 
			
		|||
	"fmt"
 | 
			
		||||
 | 
			
		||||
	"git.gensokyo.cafe/kkyy/tgbot_misaka_5882f7/utils"
 | 
			
		||||
	"github.com/dgraph-io/ristretto"
 | 
			
		||||
	"github.com/dgraph-io/ristretto/v2"
 | 
			
		||||
	"github.com/eko/gocache/lib/v4/cache"
 | 
			
		||||
	gocache_lib "github.com/eko/gocache/lib/v4/store"
 | 
			
		||||
	ristretto_store "github.com/eko/gocache/store/ristretto/v4"
 | 
			
		||||
| 
						 | 
				
			
			@ -19,7 +19,7 @@ var (
 | 
			
		|||
)
 | 
			
		||||
 | 
			
		||||
func initMsgCache() error {
 | 
			
		||||
	ristrettoCache, err := ristretto.NewCache(&ristretto.Config{
 | 
			
		||||
	ristrettoCache, err := ristretto.NewCache(&ristretto.Config[string, tele.Message]{
 | 
			
		||||
		NumCounters: 100_000,
 | 
			
		||||
		MaxCost:     20 << 20, // 20 MiB
 | 
			
		||||
		BufferItems: 64,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -38,7 +38,7 @@ type ChatRequest struct {
 | 
			
		|||
	PresencePenalty     *float64           `json:"presence_penalty,omitempty"`      // Number between -2.0 and 2.0.
 | 
			
		||||
	FrequencyPenalty    *float64           `json:"frequency_penalty,omitempty"`     // Number between -2.0 and 2.0.
 | 
			
		||||
	LogitBias           map[string]float64 `json:"logit_bias,omitempty"`            // Modify the likelihood of specified tokens appearing in the completion.
 | 
			
		||||
	User                string             `json:"user,omitempty"`                  // A unique identifier representing your end-user, which can help OpenAI to monitor and detect abuse.
 | 
			
		||||
	User                string             `json:"user,omitempty"`                  // Deprecated: A unique identifier representing your end-user, which can help OpenAI to monitor and detect abuse.
 | 
			
		||||
	ReasoningEffort     ReasoningEffort    `json:"reasoning_effort,omitempty"`      // Constrains effort on reasoning for reasoning models.
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -29,6 +29,14 @@ func NewClient(apiKey string) *Client {
 | 
			
		|||
	return &Client{rest: cli}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func NewClientWithBaseUrl(apiKey string, baseURL string) *Client {
 | 
			
		||||
	cli := NewClient(apiKey)
 | 
			
		||||
	if baseURL != "" {
 | 
			
		||||
		cli.rest.SetBaseURL(baseURL)
 | 
			
		||||
	}
 | 
			
		||||
	return cli
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *Client) ChatCompletion(request ChatRequest) (*ChatResponse, error) {
 | 
			
		||||
	// Note: this function might not work due to the header timeout set on the http client.
 | 
			
		||||
	// We should probably not use this anyway.
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,16 +1,8 @@
 | 
			
		|||
package openai
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	ModelGpt5   = "gpt-5"   // OpenAI's Flagship model for general use
 | 
			
		||||
	ModelO3     = "o3"      // OpenAI's Flagship reasoning model for daily use
 | 
			
		||||
	ModelO4Mini = "o4-mini" // OpenAI's faster reasoning model
 | 
			
		||||
 | 
			
		||||
	// Deprecated: obsolete model
 | 
			
		||||
	ModelGpt41 = "gpt-4.1"
 | 
			
		||||
 | 
			
		||||
	// Deprecated: obsolete model
 | 
			
		||||
	ModelO1 = "o1" // Expensive reasoning model
 | 
			
		||||
 | 
			
		||||
	// Deprecated: obsolete model
 | 
			
		||||
	ModelGpt4O = "gpt-4o" // The safe default, balanced model.
 | 
			
		||||
	ModelGpt5       = "gpt-5"        // OpenAI's Flagship model for general use
 | 
			
		||||
	ModelGpt5Online = "gpt-5:online" // OpenAI's Flagship model for general use (via OpenRouter with web search tool)
 | 
			
		||||
	ModelO3         = "o3"           // OpenAI's Flagship reasoning model for daily use
 | 
			
		||||
	ModelO4Mini     = "o4-mini"      // OpenAI's faster reasoning model
 | 
			
		||||
)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -11,6 +11,8 @@ func Assistant() string {
 | 
			
		|||
		"Misaka likes to use many cheerful emojis in chat 😝🥹, but she avoids using any in serious contexts, such as when providing technical solutions.",
 | 
			
		||||
		"Most importantly, Misaka is a helpful assistant.",
 | 
			
		||||
		"",
 | 
			
		||||
		"Despite wanting to talk more, Misaka has to avoid making a single response too long, since Telegram has message length limits (4,096 characters—maybe around 700 English words or 1,000 CJK characters).",
 | 
			
		||||
		"",
 | 
			
		||||
		"Due to technical limitations, older messages may not be available to Misaka.",
 | 
			
		||||
		"",
 | 
			
		||||
		"We are currently in the second half of 2025.",
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue