mirror of
https://github.com/tiennm99/goclaw.git
synced 2026-06-12 14:12:31 +00:00
181 lines
4.7 KiB
Go
181 lines
4.7 KiB
Go
package telegram
|
|
|
|
import (
|
|
"fmt"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/mymmrac/telego"
|
|
)
|
|
|
|
// MessageContext holds enriched context extracted from a Telegram message.
|
|
// Ref: TS src/telegram/bot-message-context.ts → buildTelegramMessageContext()
|
|
type MessageContext struct {
|
|
ForwardInfo *ForwardInfo
|
|
ReplyInfo *ReplyInfo
|
|
LocationInfo *LocationInfo
|
|
}
|
|
|
|
// ForwardInfo contains metadata about a forwarded message.
|
|
// Ref: TS normalizeForwardedContext()
|
|
type ForwardInfo struct {
|
|
From string // sender name or channel title
|
|
FromType string // "user", "channel", "supergroup", "hidden"
|
|
Date time.Time // original message date
|
|
}
|
|
|
|
// ReplyInfo contains metadata about the message being replied to.
|
|
// Ref: TS describeReplyTarget()
|
|
type ReplyInfo struct {
|
|
Sender string // sender name
|
|
Body string // quoted message text
|
|
IsBotReply bool // true if replying to bot's own message
|
|
}
|
|
|
|
// LocationInfo contains geographic coordinates.
|
|
// Ref: TS extractTelegramLocation()
|
|
type LocationInfo struct {
|
|
Latitude float64
|
|
Longitude float64
|
|
}
|
|
|
|
// buildMessageContext extracts forward, reply, and location context from a Telegram message.
|
|
func buildMessageContext(msg *telego.Message, botUsername string) *MessageContext {
|
|
ctx := &MessageContext{}
|
|
|
|
ctx.ForwardInfo = extractForwardInfo(msg)
|
|
ctx.ReplyInfo = extractReplyInfo(msg, botUsername)
|
|
ctx.LocationInfo = extractLocationInfo(msg)
|
|
|
|
return ctx
|
|
}
|
|
|
|
// enrichContentWithContext appends forward/reply/location context to the message content.
|
|
func enrichContentWithContext(content string, msgCtx *MessageContext) string {
|
|
if msgCtx == nil {
|
|
return content
|
|
}
|
|
|
|
var result strings.Builder
|
|
|
|
// Prepend forward context
|
|
if msgCtx.ForwardInfo != nil {
|
|
dateStr := msgCtx.ForwardInfo.Date.Format("2006-01-02 15:04")
|
|
result.WriteString(fmt.Sprintf("[Forwarded from %s at %s]\n", msgCtx.ForwardInfo.From, dateStr))
|
|
}
|
|
|
|
result.WriteString(content)
|
|
|
|
// Append reply context
|
|
if msgCtx.ReplyInfo != nil && msgCtx.ReplyInfo.Body != "" {
|
|
result.WriteString(fmt.Sprintf("\n\n[Replying to %s]\n%s\n[/Replying]",
|
|
msgCtx.ReplyInfo.Sender, msgCtx.ReplyInfo.Body))
|
|
}
|
|
|
|
// Append location
|
|
if msgCtx.LocationInfo != nil {
|
|
result.WriteString(fmt.Sprintf("\n\nCoordinates: %.6f, %.6f",
|
|
msgCtx.LocationInfo.Latitude, msgCtx.LocationInfo.Longitude))
|
|
}
|
|
|
|
return result.String()
|
|
}
|
|
|
|
// extractForwardInfo extracts forwarded message metadata.
|
|
// Ref: TS normalizeForwardedContext()
|
|
func extractForwardInfo(msg *telego.Message) *ForwardInfo {
|
|
if msg.ForwardOrigin == nil {
|
|
return nil
|
|
}
|
|
|
|
info := &ForwardInfo{}
|
|
|
|
switch origin := msg.ForwardOrigin.(type) {
|
|
case *telego.MessageOriginUser:
|
|
user := origin.SenderUser
|
|
info.From = buildUserName(&user)
|
|
info.FromType = "user"
|
|
info.Date = time.Unix(origin.Date, 0)
|
|
case *telego.MessageOriginChat:
|
|
info.From = origin.SenderChat.Title
|
|
info.FromType = string(origin.SenderChat.Type)
|
|
info.Date = time.Unix(origin.Date, 0)
|
|
case *telego.MessageOriginChannel:
|
|
info.From = origin.Chat.Title
|
|
info.FromType = "channel"
|
|
info.Date = time.Unix(origin.Date, 0)
|
|
case *telego.MessageOriginHiddenUser:
|
|
info.From = origin.SenderUserName
|
|
info.FromType = "hidden"
|
|
info.Date = time.Unix(origin.Date, 0)
|
|
default:
|
|
return nil
|
|
}
|
|
|
|
return info
|
|
}
|
|
|
|
// extractReplyInfo extracts replied-to message metadata.
|
|
// Ref: TS describeReplyTarget()
|
|
func extractReplyInfo(msg *telego.Message, botUsername string) *ReplyInfo {
|
|
reply := msg.ReplyToMessage
|
|
if reply == nil {
|
|
return nil
|
|
}
|
|
|
|
info := &ReplyInfo{}
|
|
|
|
// Determine sender name
|
|
if reply.From != nil {
|
|
info.Sender = buildUserName(reply.From)
|
|
info.IsBotReply = (reply.From.Username == botUsername)
|
|
} else {
|
|
info.Sender = "unknown"
|
|
}
|
|
|
|
// Extract reply body
|
|
if reply.Text != "" {
|
|
info.Body = reply.Text
|
|
} else if reply.Caption != "" {
|
|
info.Body = reply.Caption
|
|
}
|
|
|
|
// Truncate long reply bodies
|
|
if len(info.Body) > 500 {
|
|
info.Body = info.Body[:500] + "..."
|
|
}
|
|
|
|
// Hint for bot replies: the full response is already in session history,
|
|
// so the LLM doesn't need the full text here — just enough to identify it.
|
|
if info.IsBotReply && info.Body != "" {
|
|
info.Body += "\n(This is your previous response — full content is in session history above)"
|
|
}
|
|
|
|
return info
|
|
}
|
|
|
|
// extractLocationInfo extracts location data from a message.
|
|
// Ref: TS extractTelegramLocation()
|
|
func extractLocationInfo(msg *telego.Message) *LocationInfo {
|
|
if msg.Location == nil {
|
|
return nil
|
|
}
|
|
|
|
return &LocationInfo{
|
|
Latitude: msg.Location.Latitude,
|
|
Longitude: msg.Location.Longitude,
|
|
}
|
|
}
|
|
|
|
// buildUserName formats a Telegram user's display name.
|
|
func buildUserName(user *telego.User) string {
|
|
if user == nil {
|
|
return "unknown"
|
|
}
|
|
name := user.FirstName
|
|
if user.LastName != "" {
|
|
name += " " + user.LastName
|
|
}
|
|
return name
|
|
}
|