wheatandcatの開発ブログ

React Nativeで開発しているペペロミア & memoirの技術系記事を投稿してます

Discord Botで翻訳ボットを作ってみたが、無料運用ができなくて一旦ボツにした話

Slackが無料だと90日までしかメッセージを保持しなくなったので、個人開発系の通知系はDiscordに引っ越中

discord.com

その中で、Discord Botの開発をしてみたのでやり方を紹介

今回作ったもの

PR

github.com

内容

  • Discordに日本語英語のチャンネルがあり、日本語のチャンネルに投稿すると英語のチャンネルに翻訳したメッセージを投稿するBotを作成
  • 言語はGoで作成
  • タイトルにも記載したが、デプロイしたら無料運用は無理そうだったので、一旦ローカルで起動で動作するところまで実装
  • 翻訳はGCPのCloud Translationで実装

動作は以下みたいな感じ

実装

Discord Botの作成は以下のサイトの通りに作成

www.geeklibrary.jp

Discord Botはdiscordgoを使って実装

github.com

コードは以下の通りに実装

main.go

package main

import (
    "fmt"
    "os"

    "cloud.google.com/go/translate"
    "github.com/bwmarrin/discordgo"
    "golang.org/x/net/context"
    "golang.org/x/text/language"
)

func main() {
    Token := os.Getenv("DISCORD_BOT_TOKEN")

    dg, err := discordgo.New("Bot " + Token)
    if err != nil {
        fmt.Println("Error creating Discord session,", err)
        return
    }

    dg.AddHandler(messageHandler)

    err = dg.Open()
    if err != nil {
        fmt.Println("Error opening connection,", err)
        return
    }

    fmt.Println("Bot is now running. Press CTRL+C to exit.")
    select {}
}

func messageHandler(s *discordgo.Session, m *discordgo.MessageCreate) {
    // 自分のメッセージは無視
    if m.Author.ID == s.State.User.ID {
        return
    }

    jcid := os.Getenv("JAPANESE_CHANNEL_ID")
    ecid := os.Getenv("ENGLISH_CHANNEL_ID")
    var l, sl language.Tag
    var destinationChannelID string

    if m.ChannelID == jcid {
        destinationChannelID = ecid
        sl = language.Japanese
        l = language.English
    } else if m.ChannelID == ecid {
        destinationChannelID = jcid
        sl = language.English
        l = language.Japanese
    } else {
        // 対象チャンネル以外はスルー
        fmt.Println("OUT")
        return
    }

    // 翻訳処理
    ctx := context.Background()
    client, err := translate.NewClient(ctx)
    if err != nil {
        fmt.Println("Translation error:", err.Error())
        return
    }
    defer client.Close()

    resp, err := client.Translate(ctx, []string{m.Content}, l, &translate.Options{
        Source: sl,
        Format: translate.Text,
    })
    if err != nil {
        fmt.Println("Translation error:", err.Error())
        return
    }

    translatedText := resp[0].Text
    // メッセージURLを生成
    messageURL := fmt.Sprintf("https://discord.com/channels/%s/%s/%s", m.GuildID, m.ChannelID, m.ID)

    message := messageURL + "\n" + "> " + m.Content + "\n" + translatedText
    _, err = s.ChannelMessageSend(destinationChannelID, message)
    if err != nil {
        fmt.Println("Error sending message to Discord:", err.Error())
    }
}

以下の環境変数を設定

export DISCORD_BOT_TOKEN=xxxxxx // Discord Botのトークン
export JAPANESE_CHANNEL_ID=xxxxxx // Discordの日本語チャンネルのID
export ENGLISH_CHANNEL_ID=xxxxxx  // Discordの英語チャンネルのID
export GOOGLE_APPLICATION_CREDENTIALS=xxxxxx  // GCPのサービスアカウントのパス

上記を設定して以下のコマンドで起動で動作する。

go run main.go

意外と手軽に実装できるなと思い、次にデプロイ先を検討していた。
ただ、Discord側にメッセージ投稿された時にWebhookを実行する機能が無いのでDiscord Botはサーバーレスへのデプロイは難しかった。
なので、EC2などの順次起動のサービスにデプロイする必要があり、それを考慮すると無料運用は難しいなとなった。
無料で運用できる方法があれば、もう少し可能性がありそうだなと思ったので、今後模索していこうとかなと思います。