Skip to content

Latest commit

 

History

History
259 lines (203 loc) · 7.48 KB

File metadata and controls

259 lines (203 loc) · 7.48 KB

OmniChat

Go CI Go Lint Go SAST Go Report Card Docs Visualization License

A Go library providing a unified interface for messaging platforms.

Features

  • 🔌 Unified Interface - Single API for multiple messaging platforms
  • 🔀 Message Router - Pattern-based routing with filters (All, DMOnly, GroupOnly, FromProviders)
  • 🎤 Voice Support - Transcription and synthesis integration for voice messages
  • 📎 Media Handling - Send and receive images, documents, audio, and video
  • 🧪 Mock Provider - Built-in testing support with message simulation

Providers

Provider Package Features
Discord providers/discord Guilds, DMs, threads, media
Telegram providers/telegram Groups, channels, private chats, media
WhatsApp providers/whatsapp QR auth, voice notes, media
Slack providers/slack Socket Mode, channels, threads
Gmail providers/email/gmail OAuth2, HTML/Markdown email
IRC providers/irc TLS, NickServ auth, multi-channel

Installation

go get github.com/plexusone/omnichat

Quick Start

package main

import (
    "context"
    "log/slog"
    "os"

    "github.com/plexusone/omnichat/provider"
    "github.com/plexusone/omnichat/providers/discord"
    "github.com/plexusone/omnichat/providers/telegram"
)

func main() {
    logger := slog.Default()
    router := provider.NewRouter(logger)

    // Register Discord provider
    discordProvider, _ := discord.New(discord.Config{
        Token:  os.Getenv("DISCORD_TOKEN"),
        Logger: logger,
    })
    router.Register(discordProvider)

    // Register Telegram provider
    telegramProvider, _ := telegram.New(telegram.Config{
        Token:  os.Getenv("TELEGRAM_TOKEN"),
        Logger: logger,
    })
    router.Register(telegramProvider)

    // Handle all messages
    router.OnMessage(provider.All(), func(ctx context.Context, msg provider.IncomingMessage) error {
        // Echo the message back
        return router.Send(ctx, msg.ProviderName, msg.ChatID, provider.OutgoingMessage{
            Content: "Echo: " + msg.Content,
        })
    })

    // Connect and run
    ctx := context.Background()
    router.ConnectAll(ctx)
    defer router.DisconnectAll(ctx)

    // Keep running...
    select {}
}

Providers

Discord

import "github.com/plexusone/omnichat/providers/discord"

p, err := discord.New(discord.Config{
    Token:   "bot-token",
    GuildID: "optional-guild-id",
    Logger:  slog.Default(),
})

Telegram

import "github.com/plexusone/omnichat/providers/telegram"

p, err := telegram.New(telegram.Config{
    Token:  "bot-token",
    Logger: slog.Default(),
})

WhatsApp

import "github.com/plexusone/omnichat/providers/whatsapp"

p, err := whatsapp.New(whatsapp.Config{
    DBPath: "whatsapp.db",  // Session storage
    Logger: slog.Default(),
    QRCallback: func(qr string) {
        // Display QR code for authentication
        fmt.Println("Scan this QR code:", qr)
    },
})

IRC

import "github.com/plexusone/omnichat/providers/irc"

p, err := irc.New(irc.Config{
    Server:   "irc.libera.chat:6697",
    Nick:     "mybot",
    Password: os.Getenv("IRC_PASSWORD"), // NickServ password
    Channels: []string{"#mychannel"},
    UseTLS:   true,
    Logger:   slog.Default(),
})

Router

The router manages multiple providers and routes messages:

router := provider.NewRouter(logger)

// Register providers
router.Register(discordProvider)
router.Register(telegramProvider)

// Route patterns
router.OnMessage(provider.All(), handler)                    // All messages
router.OnMessage(provider.DMOnly(), handler)                 // DMs only
router.OnMessage(provider.GroupOnly(), handler)              // Groups only
router.OnMessage(provider.FromProviders("discord"), handler) // Discord only

// Send messages
router.Send(ctx, "discord", channelID, provider.OutgoingMessage{
    Content: "Hello!",
})

// Broadcast to multiple providers
router.Broadcast(ctx, map[string]string{
    "discord":  channelID,
    "telegram": chatID,
}, provider.OutgoingMessage{
    Content: "Hello everyone!",
})

Voice Message Support

The router supports voice message processing via the VoiceProcessor interface:

// VoiceProcessor handles voice transcription and synthesis
type VoiceProcessor interface {
    TranscribeAudio(ctx context.Context, audio []byte, mimeType string) (string, error)
    SynthesizeSpeech(ctx context.Context, text string) ([]byte, string, error)
    ResponseMode() string  // "auto", "always", "never"
}

// Use ProcessWithVoice for voice-enabled message handling
router.SetAgent(agent)
router.OnMessage(provider.All(), router.ProcessWithVoice(voiceProcessor))

Features:

  • Automatic transcription: Voice messages are transcribed to text before processing
  • Voice responses: Text responses are synthesized to voice notes
  • Smart URL handling: Responses with URLs include both voice and text for clickable links
  • Response modes: auto (voice reply to voice input), always, never

WhatsApp voice notes are automatically detected and handled:

// Incoming voice messages have Media with Type = MediaTypeVoice
for _, media := range msg.Media {
    if media.Type == provider.MediaTypeVoice {
        // media.Data contains audio bytes
        // media.MimeType is typically "audio/ogg; codecs=opus"
    }
}

// Send voice notes with PTT (Push-to-Talk) flag
router.Send(ctx, "whatsapp", chatID, provider.OutgoingMessage{
    Media: []provider.Media{{
        Type:     provider.MediaTypeVoice,
        Data:     audioBytes,
        MimeType: "audio/ogg; codecs=opus",
    }},
})

Testing

Use the mock provider for testing:

import "github.com/plexusone/omnichat/provider/providertest"

mock := providertest.NewMockProvider("test")
router.Register(mock)

// Simulate incoming message
mock.SimulateMessage(ctx, provider.IncomingMessage{
    ChatID:  "123",
    Content: "Hello",
})

// Check sent messages
sent := mock.SentMessages()

License

MIT