LINE Botでテキストとスタンプを送る方法を教えて下さい
解決したいこと
以下の流れで、LINE BotでOpenAI APIによって生成されたテキストの後に、LINEスタンプを送るようにしたいです。
- LINE Botでユーザーがキーワードを入力(例:人形)
- OpenAI APIにリクエストを投げて、キーワードにまつわる怪談を生成
- LINEにテキストで怪談を返す
- テキストのあとにスタンプを送る
Messaging API[1]を使っています。
実行すると、1, 2, 3は成功します。しかし、スタンプが送られてきません。

実行環境は以下です。
- GitHub Codespaces
- JavaScript
"@line/bot-sdk": "^7.5.2", "axios": "^1.4.0", "express": "^4.18.2", "line-bot-sdk": "^0.1.4", "openai": "^3.2.1" 【参考リンク】
[1] https://developers.line.biz/ja/docs/messaging-api/sticker-list/
発生している問題・エラー
実行すると、以下のエラーが出力されます。スタンプメッセージを送るところで失敗しています。
@xxxx ➜ /workspaces/xxxx/boot/02-line-bot (main) $ node horror2.js ポート3000番でExpressサーバーを実行中です… 受信しました: [ { type: 'message', message: { type: 'text', id: 'xxxx', text: 'お茶' }, webhookEventId: 'xxxx', deliveryContext: { isRedelivery: false }, timestamp: 1685232670580, source: { type: 'user', userId: 'xxxx' }, replyToken: 'xxxx', mode: 'active' } ] [ { role: 'system', content: 'あなたは熟練の怪談師です。ユーザーから指定されたキーワードを使って怪談を書いてください。' }, { role: 'user', content: 'お茶' } ] スタンプメッセージ送信エラー: HTTPError: Request failed with status code 400 at HTTPClient.wrapError (/workspaces/xxxx/boot/02-line-bot/node_modules/@line/bot-sdk/dist/http.js:89:20) at /workspaces/xxxx/boot/02-line-bot/node_modules/@line/bot-sdk/dist/http.js:19:88 at process.processTicksAndRejections (node:internal/process/task_queues:95:5) at async HTTPClient.post (/workspaces/xxxx/boot/02-line-bot/node_modules/@line/bot-sdk/dist/http.js:33:21) at async sendStickerMessage (/workspaces/xxxx/boot/02-line-bot/horror2.js:82:5) at async handleEvent (/workspaces/xxxx/boot/02-line-bot/horror2.js:71:5) at async Promise.all (index 0) { statusCode: 400, statusMessage: 'Bad Request', originalError: [AxiosError: Request failed with status code 400] { code: 'ERR_BAD_REQUEST', config: { transitional: [Object], adapter: [Function: httpAdapter], transformRequest: [Array], transformResponse: [Array], timeout: 0, xsrfCookieName: 'XSRF-TOKEN', xsrfHeaderName: 'X-XSRF-TOKEN', maxContentLength: -1, maxBodyLength: -1, env: [Object], validateStatus: [Function: validateStatus], headers: [Object], method: 'post', url: 'https://api.line.me/v2/bot/message/reply', data: '{"messages":[{"type":"sticker","packageId":"446","stickerId":"2027"}],"replyToken":"xxxx","notificationDisabled":false}' }, request: ClientRequest { _events: [Object: null prototype], _eventsCount: 7, _maxListeners: undefined, outputData: [], outputSize: 0, writable: true, destroyed: false, _last: false, chunkedEncoding: false, shouldKeepAlive: false, maxRequestsOnConnectionReached: false, _defaultKeepAlive: true, useChunkedEncodingByDefault: true, sendDate: false, _removedConnection: false, _removedContLen: false, _removedTE: false, strictContentLength: false, _contentLength: 147, _hasBody: true, _trailer: '', finished: true, _headerSent: true, _closed: false, socket: [TLSSocket], _header: 'POST /v2/bot/message/reply HTTP/1.1\r\n' + 'Accept: application/json, text/plain, */*\r\n' + 'Content-Type: application/json\r\n' + 'Authorization: Bearer xxxx\r\n' + 'User-Agent: @line/bot-sdk/7.5.2\r\n' + 'Content-Length: 147\r\n' + 'Host: api.line.me\r\n' + 'Connection: keep-alive\r\n' + '\r\n', _keepAliveTimeout: 0, _onPendingData: [Function: nop], agent: [Agent], socketPath: undefined, method: 'POST', maxHeaderSize: undefined, insecureHTTPParser: undefined, joinDuplicateHeaders: undefined, path: '/v2/bot/message/reply', _ended: true, res: [IncomingMessage], aborted: false, timeoutCb: [Function: emitRequestTimeout], upgradeOrConnect: false, parser: null, maxHeadersCount: null, reusedSocket: true, host: 'api.line.me', protocol: 'https:', _redirectable: [Writable], [Symbol(kCapture)]: false, [Symbol(kBytesWritten)]: 0, [Symbol(kNeedDrain)]: false, [Symbol(corked)]: 0, [Symbol(kOutHeaders)]: [Object: null prototype], [Symbol(errored)]: null, [Symbol(kHighWaterMark)]: 16384, [Symbol(kUniqueHeaders)]: null }, response: { status: 400, statusText: 'Bad Request', headers: [Object], config: [Object], request: [ClientRequest], data: [Object] } } } ^C @xxxx ➜ /workspaces/xxxx/boot/02-line-bot (main) $ 該当するソースコード
'use strict'; // ######################################## // 初期設定など // ######################################## // モジュールの読み込み const line = require('@line/bot-sdk'); const openai = require('openai'); const express = require('express'); const PORT = process.env.PORT || 3000; // 設定 const config = { channelSecret: 'チャネルシークレット', channelAccessToken: 'チャネルアクセストークン' }; // クライアントの作成 const client = new line.Client(config); const gptConfig = new openai.Configuration({ organization: process.env.OPENAI_ORGANIZATION || "組織ID", apiKey: process.env.OPENAI_API_KEY || 'APIキー', }); const gpt = new openai.OpenAIApi(gptConfig); const makeCompletion = async (userMessage) => { const prompt = { role: 'system', content: 'あなたは熟練の怪談師です。ユーザーから指定されたキーワードを使って怪談を書いてください。' // プロンプトを入力 }; userMessage.unshift(prompt); console.log(userMessage); return await gpt.createChatCompletion({ model: 'gpt-3.5-turbo', messages: userMessage, temperature: 0.5, n: 1 }); }; // メッセージイベントの処理 async function handleEvent(event) { // テキストメッセージ以外は無視 if (event.type !== 'message' || event.message.type !== 'text') { return Promise.resolve(null); } const userMessage = [ { role: 'user', content: event.message.text } ]; // ChatGPT APIにリクエストを送る try { const completion = await makeCompletion(userMessage); // レスポンスから返答を取得 const reply = completion.data.choices[0].message.content; // 返答をLINEに送る await client.replyMessage(event.replyToken, { type: 'text', text: reply }); // スタンプメッセージを送信する await sendStickerMessage(event.replyToken); } catch (error) { // エラーが発生した場合はログに出力 console.error('メッセージ送信エラー:', error); return Promise.resolve(null); } } // スタンプメッセージを送信する async function sendStickerMessage(replyToken) { try { await client.replyMessage(replyToken, { type: 'sticker', packageId: '446', // スタンプのパッケージIDに置き換える stickerId: '2027' // スタンプのIDに置き換える }); console.log('スタンプメッセージを送信しました'); } catch (error) { console.error('スタンプメッセージ送信エラー:', error); } } const app = express(); app.get('/', (req, res) => res.send('Hello LINE BOT! (HTTP GET)')); app.post('/webhook', line.middleware(config), (req, res) => { if (req.body.events.length === 0) { res.send('Hello LINE BOT! (HTTP POST)'); console.log('検証イベントを受信しました!'); return; } else { console.log('受信しました:', req.body.events); } Promise.all( req.body.events.map((event) => { if (event.type === 'message' && event.message.type === 'text') { return handleEvent(event); } else if (event.type === 'message' && event.message.type === 'sticker') { return handleMessageEvent(event); } else { return null; } }) ).then((result) => res.json(result)); }); app.listen(PORT); console.log(`ポート${PORT}番でExpressサーバーを実行中です…`); 自分で試したこと
ChatGPTに聞きながらトラブルシューティングをしましたが、修正箇所がわかりませんでした。
コードを書いた経験がないため、修正箇所の検討が尽きませんでした。
確認すべき勘所など、アドバイスだけでも頂けますと嬉しいです。
0 likes