Files
windmill_workflow/alexa-api/test_tts.js
2026-04-04 09:15:09 +09:00

131 lines
4.9 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* test_tts.js - TTS API テスト
* node test_tts.js
*/
const https = require('https');
const fs = require('fs');
const path = require('path');
const envContent = fs.readFileSync(path.join(__dirname, '.env'), 'utf8');
const COOKIE_STR = envContent.match(/ALEXA_COOKIE=(.+)/)[1].trim();
function makeRequest(url, options = {}, extraCookies = '') {
return new Promise((resolve, reject) => {
const parsed = new URL(url);
const allCookies = COOKIE_STR + (extraCookies ? '; ' + extraCookies : '');
const reqOpts = {
hostname: parsed.hostname,
path: parsed.pathname + parsed.search,
method: options.method || 'GET',
headers: {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36',
'Accept': 'application/json, text/plain, */*',
'Accept-Language': 'ja-JP,ja;q=0.9',
'Cookie': allCookies,
...(options.headers || {}),
},
};
const req = https.request(reqOpts, (res) => {
let body = '';
res.on('data', d => body += d);
res.on('end', () => resolve({ status: res.statusCode, headers: res.headers, body }));
});
req.on('error', reject);
if (options.body) req.write(options.body);
req.end();
});
}
async function main() {
// 1. CSRFトークン取得
console.log('[1] CSRF token取得...');
const langRes = await makeRequest('https://alexa.amazon.co.jp/api/language');
const setCookies = langRes.headers['set-cookie'] || [];
const csrfCookieStr = setCookies.find(c => c.startsWith('csrf='));
const csrfToken = csrfCookieStr ? csrfCookieStr.split('=')[1].split(';')[0] : null;
console.log(' CSRF token:', csrfToken);
console.log(' Status:', langRes.status);
if (!csrfToken) { console.error('CSRF token not found!'); process.exit(1); }
// 2. デバイス一覧取得
console.log('[2] デバイス一覧取得...');
const devRes = await makeRequest('https://alexa.amazon.co.jp/api/devices-v2/device?cached=false');
console.log(' Status:', devRes.status);
const devices = JSON.parse(devRes.body).devices || [];
console.log(' Device count:', devices.length);
// デバイス一覧表示
devices.filter(d => d.deviceFamily !== 'TABLET').forEach(d => {
console.log(` - ${d.accountName} (type=${d.deviceType}, serial=${d.serialNumber})`);
});
// プレハブを探す
const target = devices.find(d => d.serialNumber === 'G0922H08525302K5'); // オフィスの右エコー(以前成功したデバイス)
console.log('\nTarget device:', target ? `${target.accountName}` : 'NOT FOUND');
if (!target) { process.exit(1); }
// 2.5. カスタマーIDを取得
const bootstrapRes = await makeRequest('https://alexa.amazon.co.jp/api/bootstrap');
const bootstrap = JSON.parse(bootstrapRes.body);
const customerId = bootstrap.authentication?.customerId;
console.log(' Customer ID:', customerId);
// 3. TTSリクエスト新Cookie + Alexa.Speak + locale:'ja-JP' + 日本語テキスト)
const sequenceObj = {
'@type': 'com.amazon.alexa.behaviors.model.Sequence',
startNode: {
'@type': 'com.amazon.alexa.behaviors.model.OpaquePayloadOperationNode',
type: 'Alexa.Speak',
operationPayload: {
deviceType: target.deviceType,
deviceSerialNumber: target.serialNumber,
customerId: customerId,
locale: 'ja-JP',
textToSpeak: '\u3053\u308c\u306f\u65e5\u672c\u8a9e\u306e\u30c6\u30b9\u30c8\u3067\u3059', // 「これは日本語のテストです」
},
},
};
// non-ASCII を \uXXXX に強制エスケープ
// Amazon のパーサーが sequenceJson 内の raw UTF-8 を処理できない場合の回避策
const rawSequenceJson = JSON.stringify(sequenceObj).replace(
/[\u0080-\uffff]/g,
c => '\\u' + ('0000' + c.charCodeAt(0).toString(16)).slice(-4)
);
const bodyObj = {
behaviorId: 'PREVIEW',
sequenceJson: rawSequenceJson,
status: 'ENABLED',
};
const body = JSON.stringify(bodyObj);
console.log('\n[3] TTS送信...');
// 送信内容確認textToSpeakの部分が\uXXXXエスケープになっているか
const ttsIdx = body.indexOf('textToSpeak');
console.log(' textToSpeak部分:', body.substring(ttsIdx, ttsIdx + 80));
const ttsRes = await makeRequest('https://alexa.amazon.co.jp/api/behaviors/preview', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'csrf': csrfToken,
'Referer': 'https://alexa.amazon.co.jp/spa/index.html',
'Origin': 'https://alexa.amazon.co.jp',
},
body,
}, `csrf=${csrfToken}`);
console.log('TTS status:', ttsRes.status);
console.log('TTS response:', ttsRes.body.substring(0, 500));
if (ttsRes.status === 200 || ttsRes.status === 202) {
console.log('\n成功エコーがしゃべるはずです。');
}
}
main().catch(console.error);