Files
gooseek/backend/internal/computer/connectors/telegram.go
home 06fe57c765 feat: Go backend, enhanced search, new widgets, Docker deploy
Major changes:
- Add Go backend (backend/) with microservices architecture
- Enhanced master-agents-svc: reranker, content-classifier, stealth-crawler,
  proxy-manager, media-search, fastClassifier, language detection
- New web-svc widgets: KnowledgeCard, ProductCard, ProfileCard, VideoCard,
  UnifiedCard, CardGallery, InlineImageGallery, SourcesPanel, RelatedQuestions
- Improved discover-svc with discover-db integration
- Docker deployment improvements (Caddyfile, vendor.sh, BUILD.md)
- Library-svc: project_id schema migration
- Remove deprecated finance-svc and travel-svc
- Localization improvements across services

Made-with: Cursor
2026-02-27 04:15:32 +03:00

264 lines
6.3 KiB
Go

package connectors
import (
"bytes"
"context"
"encoding/json"
"errors"
"fmt"
"io"
"mime/multipart"
"net/http"
"strconv"
"time"
)
type TelegramConfig struct {
BotToken string
Timeout time.Duration
}
type TelegramConnector struct {
cfg TelegramConfig
client *http.Client
}
func NewTelegramConnector(cfg TelegramConfig) *TelegramConnector {
timeout := cfg.Timeout
if timeout == 0 {
timeout = 30 * time.Second
}
return &TelegramConnector{
cfg: cfg,
client: &http.Client{
Timeout: timeout,
},
}
}
func (t *TelegramConnector) ID() string {
return "telegram"
}
func (t *TelegramConnector) Name() string {
return "Telegram"
}
func (t *TelegramConnector) Description() string {
return "Send messages via Telegram Bot API"
}
func (t *TelegramConnector) GetActions() []Action {
return []Action{
{
Name: "send_message",
Description: "Send a text message",
Schema: map[string]interface{}{
"type": "object",
"properties": map[string]interface{}{
"chat_id": map[string]interface{}{"type": "string", "description": "Chat ID or @username"},
"text": map[string]interface{}{"type": "string", "description": "Message text"},
"parse_mode": map[string]interface{}{"type": "string", "enum": []string{"HTML", "Markdown", "MarkdownV2"}},
},
},
Required: []string{"chat_id", "text"},
},
{
Name: "send_document",
Description: "Send a document/file",
Schema: map[string]interface{}{
"type": "object",
"properties": map[string]interface{}{
"chat_id": map[string]interface{}{"type": "string", "description": "Chat ID"},
"document": map[string]interface{}{"type": "string", "description": "File path or URL"},
"caption": map[string]interface{}{"type": "string", "description": "Document caption"},
},
},
Required: []string{"chat_id", "document"},
},
{
Name: "send_photo",
Description: "Send a photo",
Schema: map[string]interface{}{
"type": "object",
"properties": map[string]interface{}{
"chat_id": map[string]interface{}{"type": "string", "description": "Chat ID"},
"photo": map[string]interface{}{"type": "string", "description": "Photo URL or file_id"},
"caption": map[string]interface{}{"type": "string", "description": "Photo caption"},
},
},
Required: []string{"chat_id", "photo"},
},
}
}
func (t *TelegramConnector) Validate(params map[string]interface{}) error {
if _, ok := params["chat_id"]; !ok {
return errors.New("'chat_id' is required")
}
return nil
}
func (t *TelegramConnector) Execute(ctx context.Context, action string, params map[string]interface{}) (interface{}, error) {
switch action {
case "send_message":
return t.sendMessage(ctx, params)
case "send_document":
return t.sendDocument(ctx, params)
case "send_photo":
return t.sendPhoto(ctx, params)
default:
return nil, errors.New("unknown action: " + action)
}
}
func (t *TelegramConnector) sendMessage(ctx context.Context, params map[string]interface{}) (interface{}, error) {
chatID := params["chat_id"].(string)
text := params["text"].(string)
payload := map[string]interface{}{
"chat_id": chatID,
"text": text,
}
if parseMode, ok := params["parse_mode"].(string); ok {
payload["parse_mode"] = parseMode
}
return t.apiCall(ctx, "sendMessage", payload)
}
func (t *TelegramConnector) sendDocument(ctx context.Context, params map[string]interface{}) (interface{}, error) {
chatID := params["chat_id"].(string)
document := params["document"].(string)
payload := map[string]interface{}{
"chat_id": chatID,
"document": document,
}
if caption, ok := params["caption"].(string); ok {
payload["caption"] = caption
}
return t.apiCall(ctx, "sendDocument", payload)
}
func (t *TelegramConnector) sendPhoto(ctx context.Context, params map[string]interface{}) (interface{}, error) {
chatID := params["chat_id"].(string)
photo := params["photo"].(string)
payload := map[string]interface{}{
"chat_id": chatID,
"photo": photo,
}
if caption, ok := params["caption"].(string); ok {
payload["caption"] = caption
}
return t.apiCall(ctx, "sendPhoto", payload)
}
func (t *TelegramConnector) apiCall(ctx context.Context, method string, payload map[string]interface{}) (interface{}, error) {
url := fmt.Sprintf("https://api.telegram.org/bot%s/%s", t.cfg.BotToken, method)
body, err := json.Marshal(payload)
if err != nil {
return nil, err
}
req, err := http.NewRequestWithContext(ctx, "POST", url, bytes.NewReader(body))
if err != nil {
return nil, err
}
req.Header.Set("Content-Type", "application/json")
resp, err := t.client.Do(req)
if err != nil {
return nil, err
}
defer resp.Body.Close()
respBody, err := io.ReadAll(resp.Body)
if err != nil {
return nil, err
}
var result map[string]interface{}
if err := json.Unmarshal(respBody, &result); err != nil {
return nil, err
}
if ok, exists := result["ok"].(bool); exists && !ok {
desc := "unknown error"
if d, exists := result["description"].(string); exists {
desc = d
}
return result, errors.New("Telegram API error: " + desc)
}
return result, nil
}
func (t *TelegramConnector) SendFileFromBytes(ctx context.Context, chatID string, filename string, content []byte, caption string) (interface{}, error) {
url := fmt.Sprintf("https://api.telegram.org/bot%s/sendDocument", t.cfg.BotToken)
var b bytes.Buffer
w := multipart.NewWriter(&b)
w.WriteField("chat_id", chatID)
if caption != "" {
w.WriteField("caption", caption)
}
fw, err := w.CreateFormFile("document", filename)
if err != nil {
return nil, err
}
fw.Write(content)
w.Close()
req, err := http.NewRequestWithContext(ctx, "POST", url, &b)
if err != nil {
return nil, err
}
req.Header.Set("Content-Type", w.FormDataContentType())
resp, err := t.client.Do(req)
if err != nil {
return nil, err
}
defer resp.Body.Close()
respBody, err := io.ReadAll(resp.Body)
if err != nil {
return nil, err
}
var result map[string]interface{}
if err := json.Unmarshal(respBody, &result); err != nil {
return nil, err
}
return result, nil
}
func (t *TelegramConnector) GetChatID(chatIDOrUsername interface{}) string {
switch v := chatIDOrUsername.(type) {
case string:
return v
case int:
return strconv.Itoa(v)
case int64:
return strconv.FormatInt(v, 10)
case float64:
return strconv.FormatInt(int64(v), 10)
default:
return fmt.Sprintf("%v", v)
}
}