Telegram・Discord ボット
画像・動画の生成、画像のアニメーション化、自分で定義したキャラクターとのチャットができる専用ボットを自分で運用します。料金は SpicyAPI の残高から支払われ、課金のたびに支出の上限が確認されます。
SpicyAPI ボットは、自分で動かす小さなプログラムです。Telegram(希望すれば Discord も)に接続し、あなたが許可した人が、画像の生成、動画の作成、画像からの動画化、自分で定義したキャラクターとのチャットを行えるようにします。料金はすべてあなた自身の SpicyAPI 残高から支払われ、課金の前に必ず各リクエストの料金が提示されます。
このボットは無料のオープンソース(MIT)で、github.com/spicyapi-ai/spicyapi-bot で公開しています。既定では非公開で、ほかの人やグループを許可するまでは、あなただけが使えます。
手短にまとめると
- コンソールで、ボット専用の API キーを作成し、1 日の支出上限を設定します。
- Telegram で @BotFather にメッセージを送り、
/newbotを送信してトークンをコピーします。 - リポジトリをクローンし、
.env.exampleを.envにコピーして、SPICY_API_KEY、TELEGRAM_BOT_TOKEN、OWNER_IDを入力し、docker compose up -d --buildを実行します。 - Telegram でボットを開いて
/startを送り、ルールに同意して/pic a cozy cabin in the snowを試します。
ボットでできること
- 画像:
/pic a lighthouse at dusk - 動画:
/vid waves rolling onto a beach at sunset - Animate: ボットが作った画像の下にある Animate をタップするか、画像に
/animate <動かし方>で返信します。 - キャラクターとのチャット: プライベートチャットで入力するか、
/talkを使います。返信は 1 つのメッセージにストリーミングされます。 - 支出の保護: 各リクエストは先に料金が提示され(見積もりは無料)、高額なものは Confirm のタップが必要で、1 人あたりとボット全体の 1 日の上限も適用されます。
- 既定で非公開: あなたが許可するまで、ほかの誰も使えません。
SpicyAPI のカタログには、独自のコンテンツフィルターを加えない無制限のモデルがあり、ボットは選んだどのモデルでも動作します。生成するすべてのものには、法律と SpicyAPI のコンテンツポリシーが引き続き適用されます。ポリシーを参照してください。
コマンド
| コマンド | 内容 |
|---|---|
/pic <prompt> | 画像を生成します |
/vid <prompt> | テキストから動画を生成します |
/animate <motion> | 画像に返信して、動画にします。ボットが作った画像は常に使えます。自分の写真は、運用者が ALLOW_PHOTO_UPLOADS=true を設定している場合だけです |
| Animate ボタン | 生成されたすべての画像の下にあり、プロンプトを再利用して動画にします |
/talk <message> | 現在のキャラクターと話します(プライベートチャットでは、そのまま入力するだけで構いません) |
/persona | キャラクターを選びます |
/newchat | 会話を忘れて、最初からやり直します |
/models | 画像、動画、アニメーション、チャットのモデルを選びます |
/spend | 今日使った金額。オーナーには、ボット全体の分とアカウントの残高も表示されます |
/report <text> | 運用者にレポートを送ります |
/help | 上記すべての概要 |
名前は、ほかの人気ボットが使っている /image、/video、/chat をあえて避けているので、このボットはそれらとグループを共有できます。Telegram のグループでは、ボットのチャットメッセージに返信すると、キャラクターとの会話を続けられます。
始める前に
- 常時起動しているコンピューターまたはサーバーと、インストール済みの Docker。(または Railway のアカウント。後述します。)
- 残高のある SpicyAPI アカウント。 アカウントの準備と課金を参照してください。
- Telegram アカウント。 BotFather でボットを作成するために必要です。
Docker Compose でデプロイする
ボット用のキーを作成する
コンソールで、このボット専用の新しい API キーを作成します。そのキーに 1 日の支出上限を設定し、必要なら許可するモデルの一覧も設定します。
ボット自体にも上限がありますが、キーの上限は SpicyAPI 自身が適用するため、ボットの設定を誤ったりデータを失ったりしても有効です。新しいキーには、設定しない限り上限がありません。認証を参照してください。
Telegram ボットを作成する
@BotFather を開き、/newbot を送信して、名前とユーザー名を選び、受け取ったトークンをコピーします。トークンは 123456789:AA... のような形式です。
設定する
git clone https://github.com/spicyapi-ai/spicyapi-bot.git
cd spicyapi-bot
cp .env.example .env.env を開き、必須の 3 行を入力します。
SPICY_API_KEY=sk-spicy-...
TELEGRAM_BOT_TOKEN=123456789:AA...
OWNER_ID=your-telegram-user-idそのほかの行には、すべて安全な既定値があります。各設定は .env.example に説明があります。
Telegram のユーザー ID を調べる(分からない場合)
とりあえず OWNER_ID=0 にして、次のステップを完了します。そのあと、ボットに何かメッセージを送ると、あなたの ID を返信します。その数字を OWNER_ID に入れて、再起動します。
docker compose up -d起動する
docker compose up -d --build
docker compose logs -f準備ができると、ログに Telegram bot @yourbot is running と表示されます。
試してみる
Telegram でボットを開き、/start を送信して、ルールに一度だけ同意し、/pic a cozy cabin in the snow を送ります。既定の画像モデルは、1 枚あたり約 $0.01 です。
あとで更新するときは、git pull && docker compose up -d --build を実行します。
Railway にデプロイする
Railway なら、自分のサーバーなしでボットを動かせます。ワンクリックのテンプレートはなく、自分のリポジトリのコピーからデプロイします。
リポジトリをフォークする
github.com/spicyapi-ai/spicyapi-bot を、自分の GitHub アカウントにフォークします。
プロジェクトを作成する
Railway で New Project > Deploy from GitHub repo を選び、フォークしたリポジトリを選びます。Railway が Dockerfile を見つけてビルドします。
変数を追加する
サービスの Variables タブを開き、SPICY_API_KEY、TELEGRAM_BOT_TOKEN、OWNER_ID、および .env.example にあるそのほかの設定を追加します。
ボリュームをアタッチする
サービスを右クリックして Attach volume を選び、マウントパスに /data を指定します。ボリュームがないと、再デプロイのたびに今日の支出と全員の設定が失われます。
デプロイする
デプロイして、ログに Telegram bot @yourbot is running と出ていることを確認します。
サービスはレプリカ 1 つのままにしてください。同じ Telegram トークンをポーリングするコピーが 2 つあると、更新を奪い合います。ボットには、公開ドメインも開放するポートも不要です。
Discord を追加する(任意)
アプリケーションを作成する
Discord Developer Portal でアプリケーションを作成し、Bot を開いてトークンをリセットしてコピーし、Public Bot をオフにして、自分だけがサーバーに追加できるようにします。特権インテントは不要です。
サーバーに招待する
OAuth2 > URL Generator で、スコープの bot と applications.commands、権限の Send Messages、Attach Files、Embed Links、Read Message History にチェックを入れます。生成されたリンクを開いて、ボットをサーバーに追加します。
設定する
.env で、次のように設定します。
DISCORD_TOKENに、ボットのトークンを設定します。DISCORD_GUILD_IDに、サーバー ID を設定します。コマンドを、短いグローバル展開の待ち時間なしですぐに表示させたい場合に使います。OWNER_IDに、あなたの Discord ユーザー ID を含めます。たとえばOWNER_ID=tg:123,dc:456です。tg:とdc:のプレフィックスは、ID を 1 つのプラットフォームに固定します。ALLOWED_CHAT_IDSに、ボットが応答するチャンネルまたはサーバーの ID を設定します。
ID を調べるには、デベロッパーモード(User Settings > Advanced)をオンにして、ユーザー、チャンネル、サーバーを右クリックし、Copy ID を選びます。ボットを再起動します。
チャンネルを年齢制限にする
画像と動画は、年齢制限付きチャンネルでしか使えません。Edit Channel > Overview > Age-Restricted Channel で設定します。/pic と /vid のコマンドは年齢制限付きとして登録されているため、Discord ではそのチャンネルにしか表示されません。
チャット(/talk、またはボットへのメンション)は、DISCORD_CHAT_REQUIRES_NSFW=true を設定しない限り、許可されたどのチャンネルでも使えます。この設定にすると、チャットも年齢制限付きチャンネルに限られます。
Discord は、年齢制限付きコマンドを持つアプリを App Directory に載せることを認めていないため、ボットは非公開のままにしてください。.env.example には DISCORD_MEDIA_IN_DMS もあり、既定は false です。この場合、画像と動画は、年齢制限付きのサーバーチャンネルでのみ動作し、ダイレクトメッセージでは動作しません。
誰が使えるか
| 設定 | 既定値 | 効果 |
|---|---|---|
OWNER_ID | 必須 | あなた。常に許可され、1 人あたりの 1 日の上限の対象外で、アカウントの残高を見られる唯一の人です。複数の ID はカンマで区切ります。 |
ALLOWED_USER_IDS | 空 | プライベートチャットを許可するほかの人。空の場合は、あなただけです。 |
ALLOWED_CHAT_IDS | 空 | ボットが応答するグループ(Telegram)、またはチャンネルとサーバー(Discord)。空の場合は、グループでは一切使えません。 |
REQUIRE_CONSENT | true | 全員が、18 歳以上であること、およびコンテンツルールに従うことに、一度だけ同意します。 |
ボットを見つけた見知らぬ人には、非公開であることと、あなたに送るためのユーザー ID が案内されます。グループは ALLOWED_CHAT_IDS に登録するまで無視されます。登録したグループでは、メンバー全員が、1 日の上限の範囲内でボットを使えます。Telegram のグループ ID は、-1001234567890 のように負の数です。
ALLOWED_USER_IDS=* は設定しないでください
ALLOWED_USER_IDS=* を設定するとボットが公開状態になり、見つけた人なら誰でもあなたの残高を使えるようになります。意図している場合にだけ使ってください。
このボットを運用するのはあなたで、誰に使わせるかについての責任もあなたにあります。SpicyAPI の利用規約が適用され、これには SpicyAPI がサービスを提供しない地域も含まれます。
支出の仕組み
- 先に料金を提示。 画像や動画は、何かが起きる前に SpicyAPI が見積もりを出します。見積もりは無料です。
- 絶対的な上限。 リクエストが
MAX_COST_PER_REQUEST_USD(既定 $1)を超える可能性がある場合は拒否されます。何も課金されません。 - 確認。
CONFIRM_ABOVE_USD(既定 $0.10)を超える可能性がある場合、ボットは料金を表示して Confirm と Cancel のボタンを出します。確認できるのは、リクエストした本人だけです。 - 1 日の上限。 1 人あたり UTC の 1 日に
USER_DAILY_BUDGET_USD(既定 $1)、ボット全体でDAILY_BUDGET_USD(既定 $5)まで使えます。実行中の生成は終わるまで使用済みとして数えるため、複数のリクエストを同時に出しても上限をすり抜けられません。オーナーは、ボット全体の上限だけが対象です。 - 二重課金なし。 各リクエストには、チャットメッセージまたはボタンのタップから導いた冪等キーが付くため、Telegram の更新が重複したりダブルタップしたりしても、すでに存在するタスクが返ります。
- 結果。 進行状況は、数秒ごとに 1 つのメッセージを編集して表示されます。結果には、実際の課金額とタスク ID が表示され、コンソールの Logs で調べられます。
受理済みの生成はキャンセルできません。成功した実行は課金され、通常の失敗では仮押さえ額が解放されます。一部のコンテンツ拒否は、モデルページに明記されている場合に限り課金されます。課金を参照してください。
上限付きのキーを使う
ボットは、独自の台帳を DATA_DIR/state.json に保持します。このファイルが失われると、ボットは今日使った金額を忘れます。コンソールの API キーに設定した上限は、SpicyAPI が適用するため、決して失われない上限です。ボット専用のキーを作成して 1 日の支出上限を設定し、必要なら使いたいモデルだけを許可してください。上限に達すると、ボットはキーが支出上限に達したことを知らせます。
そのほかの便利な設定です。
| 設定 | 既定値 | 内容 |
|---|---|---|
MAX_CONCURRENT_TASKS_PER_USER | 2 | 1 人が同時に実行できる画像と動画の数 |
VIDEO_SECONDS / VIDEO_RESOLUTION | 5 / 480p | 動画の長さとサイズ。各モデルが許す値に丸められます。短くて低いほど安くなります |
ALLOWED_MODELS | 空 | /models のメニューを制限します。正確な ID、または * で終わるプレフィックス(例: alibaba/*) |
モデルと料金
各ユーザーは /models でモデルを変更できます。既定値は運用者が設定します。
| 変数 | 既定値 | 執筆時点の料金 |
|---|---|---|
DEFAULT_IMAGE_MODEL | Z-Image Turbo、テキストから画像 | 1 枚あたり約 $0.01 |
DEFAULT_VIDEO_MODEL | MiniMax H3、テキストから動画 | 768p で 1 秒あたり約 $0.037 |
DEFAULT_ANIMATE_MODEL | MiniMax H3、画像から動画 | 768p で 1 秒あたり約 $0.037 |
DEFAULT_CHAT_MODEL | DeepSeek V4.1 Flash | カタログにある任意のチャットモデル |
正確なモデル ID は .env.example にあります。切り替えるには、ライブカタログ(GET /api/v1/models)から別の ID をコピーします(下のキャラクターの例では、MODEL_ID_FROM_CATALOG がそうした ID を入れる位置を示しています)。料金は公開カタログのもので、変わることがあります。ボットは常に最新の見積もりを表示します。モデルは spicyapi.ai/models で見るか、モデルを参照してください。ロールプレイ向けのチャットモデル選びには、ロールプレイのリーダーボードが役立ちます。
キャラクター
キャラクターは JSON ファイル(CHARACTERS_FILE、既定は characters/default.json で、2 人のサンプルキャラクターが入っています)に定義します。
{
"characters": [
{
"id": "mira",
"name": "Mira",
"system": "You are Mira, ... Never speak or act for {{user}}.",
"greeting": "Welcome aboard, {{user}}!",
"model": "MODEL_ID_FROM_CATALOG"
}
]
}systemはキャラクターへの指示です。greeting(任意)は最初のセリフです。model(任意)は、このキャラクターに使うチャットモデルを固定します。{{char}}と{{user}}は、それぞれキャラクターの名前と、その人の名(ファーストネーム)に置き換えられます。- エントリーには、Character Card V2 の JSON も使えます。多くのキャラクターサイトと SillyTavern がエクスポートする形式です。説明、性格、シナリオ、会話例、最初のメッセージが使われます。
Docker では、自分のファイルをマウントして、設定でそれを指定します。docker-compose.yml では次のようにします。
volumes:
- ./my-characters.json:/app/characters/custom.json:roそして .env では次のようにします。
CHARACTERS_FILE=characters/custom.jsonボットは、会話ごとに HISTORY_TURNS 回のやり取り(既定 20)を記憶し、返信を CHAT_MAX_TOKENS トークン(既定 2048)までに制限します。推論モデルは思考にもこの上限を使うので、値がごく小さいと、回答の余地が残らないことがあります。キャラクターの書き方については、チャットのレシピを参照してください。
写真のアップロードは既定でオフ
既定では、ボットが生成した画像だけをアニメーションにできます。実在の人物の写真を動画にすることは、このようなボットが悪用される主な手口であり、写真に写っている人は、あなたの動画に登場することに同意していません。
ALLOW_PHOTO_UPLOADS=true を設定すると、あなたが許可した人なら誰でも、送った写真をアニメーションにできます。信頼できる人にだけ、そして同意した成人の写真にだけ、オンにしてください。オンのときは、アップロードされた画像をボットがダウンロードして、SpicyAPI に保存します。Telegram のファイルリンクにはボットのトークンが含まれるため、先には渡されません。
プライバシー: 何がどこに保存されるか
| 内容 | 保存先 | 期間 |
|---|---|---|
| 1 日の支出の合計、各ユーザーのモデルとキャラクターの選択、ルールに同意した人 | DATA_DIR の state.json(Docker ではボリューム) | 削除するまで |
| チャット履歴 | メモリのみ | 再起動時、1 日操作がなかったとき、または /newchat で破棄 |
| ボットのログ | あなたのマシン | タスク ID と金額のみ。プロンプトやメディアは記録しません |
| プロンプトと結果 | SpicyAPI | アカウントの保持期間。保持期間を参照 |
アカウントの既定より早く結果とプロンプトを削除するよう SpicyAPI に依頼するには、RETENTION_SECONDS を設定します。
グループでは、結果がスポイラーの陰に隠されます(SPOILER_MEDIA、既定は groups。ほかの値は always と never)。/report は、メッセージをオーナーに転送します。SpicyAPI のルールに違反するコンテンツは、spicyapi.ai/abuse でも報告できます。
トラブルシューティング
| メッセージまたは症状 | 対処 |
|---|---|
「out of balance」(40201) | SpicyAPI の残高を追加します。 |
「reached the spend cap」(40202) | コンソールで設定したキーの上限に達しました。引き上げるか、待ちます。 |
「not allowed to use that model」(40301) | コンソールでキーにそのモデルを許可するか、/models で別のモデルを選びます。 |
「has not verified its email」(40310) | SpicyAPI から届いた確認リンクを開きます。 |
| 「The model declined this request」 | そのモデルがプロンプトを拒否しました。リクエストを調整するか、別のモデルを選んでください。拒否時の課金条件はモデルページで確認してください。 |
Conflict: terminated by other getUpdates request | ボットの 2 つのコピーが同じトークンを使っています。一方を止めます。 |
| Discord のコマンドが表示されない | /pic と /vid は、年齢制限付きチャンネルでしか表示されません。グローバルコマンドは表示されるまで少し時間がかかります。すぐに登録するには DISCORD_GUILD_ID を設定します。 |
| プロキシ経由でネットワークエラーになる | Node の fetch は、ボットを NODE_USE_ENV_PROXY=1 付きで起動しない限り、HTTPS_PROXY を無視します。 |
| メッセージを送ると、ボットが数字を返信する | それはあなたのユーザー ID です。OWNER_ID に入れて再起動します。 |
エラーコードの意味はエラーで説明しています。

