- 投稿日:2021-03-08T23:00:20+09:00
【コピペOK】bashでnodeとyarnのインストールをする方法
こんにちは、くりぱんです。
この記事で実現できること
- homebrewのインストール
- nodebrewのインストール
- Node.jsのインストール
- yarnのインストール
説明
フロントエンドの環境を構築している際にnode.jsとyarnが必要になったので、nodebrewを使って、node.jsとyarnをインストールしていきます。
※なお、今回はbashで実装していきます。開発環境
- macOS Catalina
- bash
実装の流れ
- Homebrewのインストール
- Nodebrewのインストール
- nodebrewのPATHを通す
- Node.jsのインストール
- yarnのインストール
実装
Homebrewのインストール
Homebrewはパッケージ管理システムの一つで、様々なソフトウェアの導入を簡単にしてくれるツールです。
今回はこちらを使用していくので、下記のコマンドを実行して、インストールしてください。$ /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"公式サイト:https://brew.sh/index_ja
nodebrewのインストール
NodebrewはNode.jsのバージョンを管理するバージョン管理ツールです。今回はこのnodebrewを使用して、Node.jsとyarnを一括管理できるようにしていきます。
下記のコマンドを実行して、先ほどインストールしたHomebrewを使用してnodebrewをインストールしてください。$ brew install nodebrewこれでnodebrewのインストールは終わりです。
nodebrewのPATHを通す
Nodebrewのコマンドを利用するためにnodebrewにPATHを通していきます。
下記のコマンドを実行してください。$ echo 'export PATH=$HOME/.nodebrew/current/bin:$PATH' >> ~/.bash_profile追加したパスを適用していきます。
$ source ~/.bash_profileこれでNode.jsとyarnをインストールする準備が完了しました。
Node.jsのインストール
それでは、nodebrewを使用して、Node.jsをインストールしていきます。
$ nodebrew install-binary latestインストールが完了したら、インストールされたNode.jsのバージョンを確認して、そのバージョンを使う設定にしていきます。
$ nodebrew list
v15.11.0
などのバージョンが表示されていればOKです。このバージョンは人によって違うので、数字が違くても気にしなくて大丈夫です。バージョンを確認したら、下記コマンドのバージョンを自分がインストールしたバージョンにしてコマンドを実行してください。
$ nodebrew use v15.11.0下記コマンドでNode.jsのバージョンを確認してください。
$ node -v v15.11.0yarnのインストール
最後にyarnのインストールをして終わりです。
$ npm install -g yarnバージョン確認もしておきましょう
$ yarn -v 1.22.10最後に
以上でbashを使用したNode.jsとyarnのインストールは終了です。
各々フロントの開発を楽しんじゃってください!少しでも役に立った!という時は、LGTMをポチッと、、、笑
1つでもLGTMが付くとその日がハッピーになるんです!
役に立たなかった時は、怒らないでコメント頂けると幸いです笑Twitterもやってます!
プログラミングや金融知識についてやエンジニアの現実についてつぶやいています!
よかったら見てみてくださいね!
https://twitter.com/sakuslife
- 投稿日:2021-03-08T21:11:28+09:00
【Node.js】Firebaseでエミュレーターを使ってjestのCIをGithub Actionsで
もうエミュレーターでテストすればいいんじゃないか説。
package.json"scripts": { "jest": "jest", "test": "firebase emulators:exec --only functions,firestore \"npm run jest --exit\"", }別のFirebaseプロジェクトを用意する必要もないし、sinonでFirebaseAdminのモックとかも作る必要ないから楽。
Github Actions
jobs: ci: runs-on: ${{ matrix.os }} strategy: matrix: os: [ubuntu-latest] node: [12] steps: - name: Checkout ? uses: actions/checkout@master - name: Setup node env ? uses: actions/setup-node@v2.1.2 with: node-version: ${{ matrix.node }} - name: Cache node_modules ? uses: actions/cache@v2 with: path: ~/.npm key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }} restore-keys: | ${{ runner.os }}-node- - name: Install dependencies ??? run: | npm install -g firebase-tools npm ci - name: Firebase runtime config ? uses: w9jds/firebase-action@master with: args: functions:config:get > .runtimeconfig.json env: FIREBASE_TOKEN: ${{ secrets.FIREBASE_TOKEN }} PROJECT_ID: "default" - name: Run linter ? run: | npm run lint npm run testfunctions.config()を使ってる場合は、firebase-actionsを使って
.runtimeconfig.json
に吐き出す。
また、エミュレーターの起動はfirebase-actionsを使わないのでnpm install -g firebase-tools
を忘れずに。
- 投稿日:2021-03-08T21:11:28+09:00
【Node.js】Firebaseでエミュレーターを使ったjestのCIをGithub Actionsで
もうエミュレーターでテストすればいいんじゃないか説。
package.json"scripts": { "jest": "jest", "test": "firebase emulators:exec --only functions,firestore \"npm run jest --exit\"", }別のFirebaseプロジェクトを用意する必要もないし、sinonでFirebaseAdminのモックとかも作る必要ないから楽。
Github Actions
jobs: ci: runs-on: ${{ matrix.os }} strategy: matrix: os: [ubuntu-latest] node: [12] steps: - name: Checkout ? uses: actions/checkout@master - name: Setup node env ? uses: actions/setup-node@v2.1.2 with: node-version: ${{ matrix.node }} - name: Cache node_modules ? uses: actions/cache@v2 with: path: ~/.npm key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }} restore-keys: | ${{ runner.os }}-node- - name: Install dependencies ??? run: | npm install -g firebase-tools npm ci - name: Firebase runtime config ? uses: w9jds/firebase-action@master with: args: functions:config:get > .runtimeconfig.json env: FIREBASE_TOKEN: ${{ secrets.FIREBASE_TOKEN }} PROJECT_ID: "default" - name: Run linter ? run: | npm run lint npm run testfunctions.config()を使ってる場合は、firebase-actionsを使って
.runtimeconfig.json
に吐き出す。
また、エミュレーターの起動はfirebase-actionsを使わないのでnpm install -g firebase-tools
を忘れずに。Cloud Storageのテスト
FirebaseのStorageは現状エミュレーターのサポート外なので、initializeAppで認証情報を渡してテストする。同じプロジェクトでテストする場合、バケットをテスト用に変更すると楽。(デフォルトで用意されてるstagingのバケットなど)
storage.test.jsimport * as admin from 'firebase-admin'; import { config } from 'firebase-functions'; admin.initializeApp({ credential: admin.credential.cert({ project_id: config().credential.project_id, client_email: config().credential.client_email, private_key: config().credential.private_key.replace(/\\n/g, '\n'), }), storageBucket: 'staging.<PROJECT_ID>.appspot.com', // test用に変更 });秘密鍵を
functions.config()
から読み込む場合、\n
が\\n
になって
Failed to parse private key: Error: Invalid PEM formatted message.
と、認証でコケるので改行に置換してあげる。
- 投稿日:2021-03-08T16:22:36+09:00
環境構築 OSがMojave以前の場合
1. Command Line Toolsの導入
1-1. Command Line Toolsをインストール
ターミナルに入力
$ xcode-select --install「インストール」をクリック。
「同意する」をクリック。2. Homebrewの導入
2-1. Homebrewをインストール
コマンドを順番に1つずつ実行。
$ cd #ホームディレクトリに移動 $ pwd #ホームディレクトリにいるかどうか確認 $ /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install.sh)" # コマンドを実行PCのパスワードを入力する。
「Press RETURN to continue or other key to abort」
が表示されたら、エンターキーをおす。2-2. Homebrewがインストールされているか確認
上のコマンドだけ実行する。
バージョン情報が表示されれば無事にインストールされている。$ brew -v Homebrew 2.5.1 # 数値は異なる場合があります2-3. Homebrewをアップデート
$ brew update2-4. Homebrewの権限を変更
$ sudo chown -R `whoami`:admin /usr/local/bin再度パスワードを求められた場合は、先ほどと同じように入力。
3. Rubyをインストール
Webアプリケーションの開発においては専用のRubyをインストールする必要があります。
3-1. rbenv と ruby-buildをインストール
$ brew install rbenv ruby-build3-2. rbenvをどこからも使用できるようにする
$ echo 'eval "$(rbenv init -)"' >> ~/.bash_profile3-3. bash_profileの変更を反映
$ source ~/.bash_profile3-4. readlineをinstall
ターミナルのirb上で日本語入力を可能にする設定
$ brew install readline3-5. readlineをどこからも使用できるようにする
$ brew link readline --force3-6. rbenvを利用してRubyをインストール
$ RUBY_CONFIGURE_OPTS="--with-readline-dir=$(brew --prefix readline)" $ rbenv install 2.6.2.6.5と書いてあるのは今回インストールするRubyのバージョンです。
3-7. 利用するRubyのバージョンを指定
$ rbenv global 2.6.5デフォルトでPCに入っていたRubyから、先ほどインストールしたRubyを使用するように切り替えることができました。
3-8. rbenvを読み込んで変更を反映
$ rbenv rehash3-9. Rubyのバージョンを確認
以下のコマンドで最終確認。
$ ruby -v4. MySQLを用意
4-1. MySQLのインストール
$ brew install mysql@5.64-2. MySQLの自動起動設定
MySQLは本来であればPC再起動のたびに起動し直す必要がありますが、それは面倒であるため、自動で起動するようにしておく。
$ mkdir ~/Library/LaunchAgents $ ln -sfv /usr/local/opt/mysql\@5.6/*.plist ~/Library/LaunchAgents $ launchctl load ~/Library/LaunchAgents/homebrew.mxcl.mysql\@5.6.plist4-3.mysqlコマンドをどこからでも実行できるようにする
# mysqlのコマンドを実行できるようにする $ echo 'export PATH="/usr/local/opt/mysql@5.6/bin:$PATH"' >> ~/.bash_profile $ source ~/.bash_profile # mysqlのコマンドが打てるか確認する $ which mysql # 以下のように表示されれば成功 /usr/local/opt/mysql@5.6/bin/mysql4-4. mysqlを起動を確認
# mysqlの状態を確認するコマンドです $ mysql.server status # 以下のように表示されれば成功 SUCCESS! MySQL running5. Railsの導入
5-1. bundlerをインストール
Rubyの拡張機能(gem)を管理するためのbundler(バンドラー)をインストールする。
$ gem install bundler --version='2.1.4'5-2. Railsをインストール
$ gem install rails --version='6.0.0'5-3. rbenvを再読み込み
$ rbenv rehash5-4. Railsが導入できたか確認
% rails -v Rails 6.0.0 #「Rails」のあとに続く数字は変わる可能性があります6. Node.jsの導入
6-1.Node.jsのインストール
$ brew install node@14Node.jsへのパスを設定
$ echo 'export PATH="/usr/local/opt/node@14/bin:$PATH"' >> ~/.bash_profile $ source ~/.bash_profile6-2. Node.jsが導入できたか確認
$ node -v v14.15.3 # 数値は異なる場合があります7. yarnの導入
7-1. yarnをインストール
$ brew install yarn7-2. yarnが導入できたか確認
$ yarn -v
- 投稿日:2021-03-08T07:44:36+09:00
環境構築 6 Node.js
- 投稿日:2021-03-08T01:09:22+09:00
LINEボットとATOM Echoでボイスメッセージを作る
ATOM Echoには、マイクとスピーカとボタンとLEDが付いています。
ATOM Echoのマイクにしゃべった言葉がLINEメッセージとして通知されるようにするとともに、LINEアプリから応答メッセージを入力したら、ATOM EchoのLEDが点灯し、さらにボタンを押したら応答メッセージが音声でATOM Echoのスピーカから流れるようにします。いくつかのサービスを使っています
・録音したWAVEファイルを、Google Cloud Speech APIの音声認識サービスを使ってテキスト文字に起こします。
・LINEボットの機能を使って、メッセージをLINEアプリに通知したり、LINEアプリに入力したメッセージを受信したりします。
・受信したテキストメッセージを、Amazon Pollyの音声合成サービスを使って音声ファイルにします。
・ATOM Echoで、メッセージ通知を検知するために、MQTTでサブスクライブします。ソースコードもろもろは、以下のGitHubに上げておきました。
poruruba/LinebotCarrier
https://github.com/poruruba/LinebotCarrierATOM Echo側
以下のライブラリを利用しています。
m5stack/M5StickC
https://github.com/m5stack/M5StickC
ボタンの検出に使っています。knolleary/PubSubClient
https://github.com/knolleary/pubsubclient
MQTTサブスクライブに使っています。bblanchon/ArduinoJson
https://github.com/bblanchon/ArduinoJson
MQTTサブスクライブで受信するJSONのパースに使っています。adafruit/Adafruit_NeoPixel
https://github.com/adafruit/Adafruit_NeoPixel
RGBのLED制御に使っています。録音は、以下を参考にしました。
M5StickCとSpeaker HatでAI Chatと会話
m5stack/M5-ProductExampleCodesこんな感じです。
Arduino\LinebotCarrier\src\main.cpp// 録音用タスク void i2sRecordTask(void* arg){ // 初期化 recPos = 0; memset(soundStorage, 0, sizeof(soundStorage)); vTaskDelay(100); // 録音処理 while (isRecording) { size_t transBytes; // I2Sからデータ取得 i2s_read(I2S_NUM_0, (char*)soundBuffer, BUFFER_LEN, &transBytes, (100 / portTICK_RATE_MS)); // int16_t(12bit精度)をuint8_tに変換 for (int i = 0 ; i < transBytes ; i += 2 ) { if ( recPos < STORAGE_LEN ) { int16_t* val = (int16_t*)&soundBuffer[i]; soundStorage[recPos] = ( *val + 32768 ) / 256; recPos++; if( recPos >= sizeof(soundStorage) ){ isRecording = false; break; } } } // Serial.printf("transBytes=%d, recPos=%d\n", transBytes, recPos); vTaskDelay(1 / portTICK_RATE_MS); } i2s_driver_uninstall(I2S_NUM_0); pixels.setPixelColor(0, pixels.Color(0, 0, 0)); pixels.show(); if( recPos > 0 ){ unsigned long len = sizeof(temp_buffer); int ret = doHttpPostFile((base_url + "/linebot-carrier-wav2text").c_str(), soundStorage, recPos, "application/octet-stream", "upfile", "test.bin", NULL, NULL, temp_buffer, &len); if( ret != 0 ){ Serial.println("/linebot-carrier-wav2text: Error"); }else{ Serial.println((char*)temp_buffer); } } // タスク削除 vTaskDelete(NULL); } void i2sRecord(){ isRecording = true; pixels.setPixelColor(0, pixels.Color(0, 100, 0)); pixels.show(); i2s_driver_uninstall(I2S_NUM_0); i2s_config_t i2s_config = { .mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_RX | I2S_MODE_PDM), .sample_rate = SAMPLING_RATE, .bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT, // is fixed at 12bit, stereo, MSB .channel_format = I2S_CHANNEL_FMT_ALL_RIGHT, .communication_format = I2S_COMM_FORMAT_I2S, .intr_alloc_flags = ESP_INTR_FLAG_LEVEL1, .dma_buf_count = 6, .dma_buf_len = 60, }; esp_err_t err = ESP_OK; err += i2s_driver_install(I2S_NUM_0, &i2s_config, 0, NULL); i2s_pin_config_t tx_pin_config; tx_pin_config.bck_io_num = I2S_BCLK; tx_pin_config.ws_io_num = I2S_LRC; tx_pin_config.data_out_num = I2S_DOUT; tx_pin_config.data_in_num = I2S_DIN; //Serial.println("Init i2s_set_pin"); err += i2s_set_pin(I2S_NUM_0, &tx_pin_config); //Serial.println("Init i2s_set_clk"); err += i2s_set_clk(I2S_NUM_0, SAMPLING_RATE, I2S_BITS_PER_SAMPLE_16BIT, I2S_CHANNEL_MONO); // 録音開始 xTaskCreatePinnedToCore(i2sRecordTask, "i2sRecordTask", 4096, NULL, 1, NULL, 1); }録音が完了したら、以下の部分で音声の生データをファイルとしてアップロードしています。
Arduino\LinebotCarrier\src\main.cppint ret = doHttpPostFile((base_url + "/linebot-carrier-wav2text").c_str(), soundStorage, recPos, "application/octet-stream", "upfile", "test.bin", NULL, NULL, temp_buffer, &len);MP3の再生は、以下を利用させていただきました。
schreibfaul1/ESP32-audioI2S
https://github.com/schreibfaul1/ESP32-audioI2SPlatformIOを利用している場合は、zipファイルの中身をlibフォルダに突っ込めばコンパイルに含めてくれます。
ポート番号は、ATOM Echoの配線に合わせています。ただし、うまく動かないところがあり、いくつか修正しています。(この直し方でよいのか自信がないですが。。。)
GitHubには、修正したファイルだけ上げてあります。録音と再生を切り替えられるように、Audioのコンストラクターから再セットアップ用の関数Audio:setup()に分離しました。
変更前
Arduino\LinebotCarrier\lib\ESP32-audioI2S-master\src\Audio.cppAudio::Audio() { clientsecure.setInsecure(); // if that can't be resolved update to ESP32 Arduino version 1.0.5-rc05 or higher //i2s configuration m_i2s_num = I2S_NUM_0; // i2s port number m_i2s_config.mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_TX); m_i2s_config.sample_rate = 16000; m_i2s_config.bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT; m_i2s_config.channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT; m_i2s_config.communication_format = (i2s_comm_format_t)(I2S_COMM_FORMAT_I2S | I2S_COMM_FORMAT_I2S_MSB); m_i2s_config.intr_alloc_flags = ESP_INTR_FLAG_LEVEL1; // high interrupt priority m_i2s_config.dma_buf_count = 8; // max buffers m_i2s_config.dma_buf_len = 1024; // max value m_i2s_config.use_apll = APLL_ENABLE; m_i2s_config.tx_desc_auto_clear = true; // new in V1.0.1 m_i2s_config.fixed_mclk = I2S_PIN_NO_CHANGE; i2s_driver_install((i2s_port_t)m_i2s_num, &m_i2s_config, 0, NULL); m_f_forceMono = false; m_filter[LEFTCHANNEL].a0 = 1; m_filter[LEFTCHANNEL].a1 = 0; m_filter[LEFTCHANNEL].a2 = 0; m_filter[LEFTCHANNEL].b1 = 0; m_filter[LEFTCHANNEL].b2 = 0; m_filter[RIGHTCHANNEL].a0 = 1; m_filter[RIGHTCHANNEL].a1 = 0; m_filter[RIGHTCHANNEL].a2 = 0; m_filter[RIGHTCHANNEL].b1 = 0; m_filter[RIGHTCHANNEL].b2 = 0; }変更後
Arduino\LinebotCarrier\lib\ESP32-audioI2S-master\src\Audio.cppAudio::Audio() { clientsecure.setInsecure(); // if that can't be resolved update to ESP32 Arduino version 1.0.5-rc05 or higher } void Audio::setup(){ i2s_driver_uninstall(I2S_NUM_0); //i2s configuration m_i2s_num = I2S_NUM_0; // i2s port number m_i2s_config.mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_TX); m_i2s_config.sample_rate = 16000; m_i2s_config.bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT; m_i2s_config.channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT; m_i2s_config.communication_format = (i2s_comm_format_t)(I2S_COMM_FORMAT_I2S | I2S_COMM_FORMAT_I2S_MSB); m_i2s_config.intr_alloc_flags = ESP_INTR_FLAG_LEVEL1; // high interrupt priority m_i2s_config.dma_buf_count = 8; // max buffers m_i2s_config.dma_buf_len = 1024; // max value m_i2s_config.use_apll = APLL_ENABLE; m_i2s_config.tx_desc_auto_clear = true; // new in V1.0.1 m_i2s_config.fixed_mclk = I2S_PIN_NO_CHANGE; i2s_driver_install((i2s_port_t)m_i2s_num, &m_i2s_config, 0, NULL); m_f_forceMono = false; m_filter[LEFTCHANNEL].a0 = 1; m_filter[LEFTCHANNEL].a1 = 0; m_filter[LEFTCHANNEL].a2 = 0; m_filter[LEFTCHANNEL].b1 = 0; m_filter[LEFTCHANNEL].b2 = 0; m_filter[RIGHTCHANNEL].a0 = 1; m_filter[RIGHTCHANNEL].a1 = 0; m_filter[RIGHTCHANNEL].a2 = 0; m_filter[RIGHTCHANNEL].b1 = 0; m_filter[RIGHTCHANNEL].b2 = 0; }MP3ファイルが小さすぎると、再生されませんでしたので、ファイルサイズの下限を下げました。
変更前
Arduino\LinebotCarrier\lib\ESP32-audioI2S-master\src\Audio.cppif((InBuff.bufferFilled() > 6000 && !m_f_psram) || (InBuff.bufferFilled() > 80000 && m_f_psram)) {変更後
Arduino\LinebotCarrier\lib\ESP32-audioI2S-master\src\Audio.cppif((InBuff.bufferFilled() > 1500 && !m_f_psram) || (InBuff.bufferFilled() > 80000 && m_f_psram)) {なぜか、MP3の最後あたりの音が切れてしまいましたので、ウェイトを入れました。
変更前
Arduino\LinebotCarrier\lib\ESP32-audioI2S-master\src\Audio.cppif(m_f_webfile && (byteCounter >= m_contentlength - 10) && (InBuff.bufferFilled() < maxFrameSize)) { // it is stream from fileserver with known content-length? and // everything is received? and // the buff is almost empty?, issue #66 then comes to an end playI2Sremains(); stopSong(); // Correct close when play known length sound #74 and before callback #112 sprintf(chbuf, "End of webstream: \"%s\"", m_lastHost); if(audio_info) audio_info(chbuf); if(audio_eof_stream) audio_eof_stream(m_lastHost); }変更後
Arduino\LinebotCarrier\lib\ESP32-audioI2S-master\src\Audio.cppif(m_f_webfile && (byteCounter >= m_contentlength - 10) && (InBuff.bufferFilled() < maxFrameSize)) { // it is stream from fileserver with known content-length? and // everything is received? and // the buff is almost empty?, issue #66 then comes to an end while(!playI2Sremains()) { ; } delay(500); stopSong(); // Correct close when play known length sound #74 and before callback #112 sprintf(chbuf, "End of webstream: \"%s\"", m_lastHost); if(audio_info) audio_info(chbuf); if(audio_eof_stream) audio_eof_stream(m_lastHost); }後はこんな感じで呼び出すだけです。引数として、MP3を置いたURLを指定します。
Arduino\LinebotCarrier\src\main.cppvoid i2sPlayUrl(const char *url){ if( audio.isRunning() ) audio.stopSong(); audio.setup(); audio.setPinout(I2S_BCLK, I2S_LRC, I2S_DOUT, I2S_DIN); audio.setVolume(I2S_VOLUME); // 0...21 audio.connecttohost(url); }WAVEファイルのアップロードは以下を参考にしました。
ESP32でバイナリファイルのダウンロード・アップロードMQTTサブスクライブは以下を参考にしました。
ESP32で作るBeebotteダッシュボードNode.js側
ざっと、以下のnpmモジュールを使っています。
・line/line-bot-sdk-nodejs
https://github.com/line/line-bot-sdk-nodejs・googleapis/nodejs-speech
https://github.com/googleapis/nodejs-speech・mqttjs/MQTT.js
https://github.com/mqttjs/MQTT.js・aws/aws-sdk-js
https://github.com/aws/aws-sdk-jsNode.js\api\controllers\linebot-carrier\index.jsconst line = require('@line/bot-sdk'); const speech = require('@google-cloud/speech'); const client = new speech.SpeechClient(); const mqtt = require('mqtt'); const AWS = require('aws-sdk'); const polly = new AWS.Polly({ apiVersion: '2016-06-10', region: 'ap-northeast-1' });以下の2つのエンドポイントを立ち上げています。
・/linebot-carrier
LINEボットのWebhookであり、LINEメッセージを受信すると呼び出されます。・/linebot-carrier-wav2text
ATOM Echoからの、WAVファイルのアップロードを受け付けます。説明が面倒なので、ソースをそのまま載せています。すみません。
Node.js\api\controllers\linebot-carrier\index.js'use strict'; const config = { channelAccessToken: '【LINEチャネルアクセストークン(長期)】', channelSecret: '【LINEチャネルシークレット】', }; const HELPER_BASE = process.env.HELPER_BASE || '../../helpers/'; const Response = require(HELPER_BASE + 'response'); var line_usr_id = '【LINEユーザID】'; const LineUtils = require(HELPER_BASE + 'line-utils'); const line = require('@line/bot-sdk'); const app = new LineUtils(line, config); const speech = require('@google-cloud/speech'); const client = new speech.SpeechClient(); const mqtt = require('mqtt'); const MQTT_HOST = process.env.MQTT_HOST || '【MQTTサーバのURL(例:mqtt://hostname:1883)】'; const MQTT_CLIENT_ID = 'linebot-carrier'; const MQTT_TOPIC_TO_ATOM = 'linebot_to_atom'; const THIS_BASE_PATH = process.env.THIS_BASE_PATH; const MESSAGE_MP3_FNAME = THIS_BASE_PATH + '/public/message.mp3'; const fs = require('fs'); const AWS = require('aws-sdk'); const polly = new AWS.Polly({ apiVersion: '2016-06-10', region: 'ap-northeast-1' }); const mqtt_client = mqtt.connect(MQTT_HOST, { clientId: MQTT_CLIENT_ID }); mqtt_client.on('connect', () => { console.log("mqtt connected"); }); app.follow(async (event, client) =>{ console.log("app.follow: " + event.source.userId ); // line_usr_id = event.source.userId; }); app.message(async (event, client) =>{ console.log("linebot: app.message"); var buffer = await speech_to_wave(event.message.text); fs.writeFileSync(MESSAGE_MP3_FNAME, buffer); var json = { message: event.message.text }; mqtt_client.publish(MQTT_TOPIC_TO_ATOM, JSON.stringify(json)); var message = { type: 'text', text: '$', emojis: [ { index: 0, productId: "5ac1de17040ab15980c9b438", emojiId: 120 } ] }; return client.replyMessage(event.replyToken, message); }); exports.fulfillment = app.lambda(); exports.handler = async (event, context, callback) => { if( event.path == '/linebot-carrier-wav2text' ){ // console.log(new Uint8Array(event.files['upfile'][0].buffer)); var norm = normalize_wave8(new Uint8Array(event.files['upfile'][0].buffer)); // 音声認識 var result = await speech_recognize(norm); if( result.length < 1 ) throw 'recognition failed'; var text = result[0]; console.log(text); app.client.pushMessage(line_usr_id, app.createSimpleResponse(text)); return new Response({ message: text }); } }; function normalize_wave8(wav, out_bitlen = 16){ var sum = 0; var max = 0; var min = 256; for( var i = 0 ; i < wav.length ; i++ ){ var val = wav[i]; if( val > max ) max = val; if( val < min ) min = val; sum += val; } var average = sum / wav.length; var amplitude = Math.max(max - average, average - min); /* console.log('sum=' + sum); console.log('avg=' + average); console.log('amp=' + amplitude); console.log('max=' + max); console.log('min=' + min); */ if( out_bitlen == 8 ){ const norm = Buffer.alloc(wav.length); for( var i = 0 ; i < wav.length ; i++ ){ var value = (wav[i] - average) / amplitude * (127 * 0.8) + 128; norm[i] = Math.floor(value); } return norm; }else{ const norm = Buffer.alloc(wav.length * 2); for( var i = 0 ; i < wav.length ; i++ ){ var value = (wav[i] - average) / amplitude * (32767 * 0.8); norm.writeInt16LE(Math.floor(value), i * 2); } return norm; } } async function speech_recognize(wav){ const config = { encoding: 'LINEAR16', sampleRateHertz: 8192, languageCode: 'ja-JP', }; const audio = { content: wav.toString('base64') }; const request = { config: config, audio: audio, }; return client.recognize(request) .then(response =>{ const transcription = []; for( var i = 0 ; i < response[0].results.length ; i++ ) transcription.push(response[0].results[i].alternatives[0].transcript); return transcription; }); } async function speech_to_wave(message, voiceid = 'Mizuki', samplerate = 16000 ){ const pollyParams = { OutputFormat: 'mp3', Text: message, VoiceId: voiceid, TextType: 'text', SampleRate : String(samplerate), }; return new Promise((resolve, reject) =>{ polly.synthesizeSpeech(pollyParams, (err, data) =>{ if( err ){ console.log(err); return reject(err); } var buffer = Buffer.from(data.AudioStream); return resolve(buffer); }); }); }ファイルアップロードを受信するところは、以下を参考にしてください。
バイナリファイルのアップロード・ダウンロードをするWAVファイルから音声認識をするところ、テキスト文字列を音声ファイルに変換するところは、以下を参考にしてください。
M5StickCとSpeaker HatでAI Chatと会話LINEボットにより、メッセージ受信をトリガするには以下を参考にしてください。
LINEボットを立ち上げるまで。LINEビーコンも。以上
- 投稿日:2021-03-08T00:05:14+09:00
ElectronのexecuteJavascriptでError: Script failed to executeが出る件
はじめに
初投稿です...
ElectronのBrowserViewでexecuteJavascriptを使った際、一見正しそうなスクリプトがエラーを吐く問題で少々悩んだので備忘録として。問題のソースコード
要素の取得に失敗したらfalse、成功したら真を返したい
const result = await browserView.webContents.executeJavaScript(` const anko = document.getElementById("anko"); return anko == null ? false : true; `)正しいソースコード
どうやらreturnで返しちゃだめらしいです。(そんなん知らんよ…)
最後に評価された値が返却されるらしい。const result = await browserView.webContents.executeJavaScript(` let val = true; const anko = document.getElementById("anko"); anko == null ? false : true; `)現在作っているアプリ
Youtube Live用のコメントビュワーです(Electron製)(ベータ版)
配信する方はぜひどうぞ
- https://tubug.netlify.app