AquesTalk Web テスト
開発環境:
Raspberry Pi
Nodejs
OS: Raspberry Pi OS Lite
Release date: November 19th 2024
System: 64-bit
Kernel version: 6.6
Debian version: 12 (bookworm)

N.Yamazaki's blog(AquesTalk Pi) : http://blog-yama.a-quest.com/?eid=970157

// +++++++++++++++++++++++++++++++++++++++++++++++ //
#!/usr/bin/env node
'use strict';

/*
ファイル名 : aques.js
AquesTalk テストアプリ
2025/03 : Ver.0.1 初版
開発環境 : Raspberry Pi
Copyright 2025 Moo Soft(Yokoyama Akiyosi)

・npm インストールパッケージ
npm install -S express https://www.npmjs.com/package/express
*/

// ***** モジュール使用宣言、定数、変数定義 Start ***** //
const express = require('express'); // Web フレームワーク
const app = express(); // Web フレームワークインスタンス
const web_port = 8088; // WEB サーバーポート
const doc_root = '/home/pi/www'; // ドキュメントルート
let MENTE = true;

// ***** モジュール使用宣言、定数、変数定義 End ***** //

// *********************** //
// サーバー設定、即時関数内で起動
// Express4.16 以降 'body-parser' 機能が取り込まれた
// extended:true(デフォルト) の場合は qs ライブラリを、
// extended:false の場合は querystring ライブラリを使用
// qs ライブラリの場合は、name[1]=Taro, name[2]=Jiro などの配列も解釈
// *********************** //
app.use(express.static(doc_root)); // doc_root で静的 HTML を扱う
app.use(express.urlencoded({extended:true})); // qs ライブラリを使用

// *********************** //
// アクセス処理(GET, POST ...)
// *********************** //
app.use('/index', function middleWare(req, res, next) {
try {
res.end(''); // ブラウザに返すデータ無しで応答を迅速に終了
} catch (e) {
console.error('app.use(/index)', e.message);
} finally {
next();
} // try catch finally
}); // app.use('/index.html'

// *********************** //
// AquesTalk 発話
// *********************** //
app.post('/aquestalk', function (req, res, next) {
try {
if (MENTE) console.log(req.body);
let msg = req.body['msg']; // コマンド文字列取得
let cmd = '/home/pi/aquestalkpi/AquesTalkPi ' + msg + ' | aplay';
exec(cmd); // シェルを起動しコマンド実行
res.end();
} catch (e) {
console.error('app.use(/aquestalk)', e.message);
} finally {
next();
} // try catch finally
}); // app.use('/aquestalk'

// *********************** //
// 非同期にシェルを起動する
// cmd : 実行文字列
// 戻り値 : 無し
//
// 大量の標準出力を扱いたい時には第二引数にオプション設定
// 標準の {maxBuffer: 200*1024} を {maxBuffer:400*1024} とかに
// Defaults.
// {
// encoding : 'utf8',
// timeout : 0,
// maxBuffer : 200*1024,
// killSignal: 'SIGTERM',
// cwd : null, // = CurrentWorkingDirectory
// env : null // = EnvironmentVariables
// }
// *********************** //
function exec(cmd) {
try {
const exec = require('child_process').exec;
exec(cmd, {encoding: 'utf8'}, function (error, stdout, stderr) {
if (error !== null) console.log('error:' , error);
if (stdout) console.log('stdout:', stdout);
if (stderr) console.log('stderr:', stderr);
console.log('end function exec()');
});
} catch(e) {
console.error('exec', e.message);
} // try catch
} // function exec(cmd)

// *********************** //
// 実行
//
// 記述した時点で実行する即時関数
// (function () { 何かの処理 }());
// https://qiita.com/katsukii/items/cfe9fd968ba0db603b1e
// *********************** //
(function () {
app.listen(web_port); // サーバー起動
}());

// +++++++++++++++++++++++++++++++++++++++++++++++ //

// ******************************** //
// JavaScript
// 現在日時文字列取得
// 戻り値 : 現在日時文字列
// ******************************** //
function date_str() {
let date = new Date();
result = date.getFullYear() + '年' +
(date.getMonth()+ 1) + '月' +
date.getDate() + '日' +
date.getHours() + '時' +
date.getMinutes() + '分' +
date.getSeconds() + '秒です。';

return result;
} // function date_str()

// +++++++++++++++++++++++++++++++++++++++++++++++ //

// ******************************** //
// HTML
// ******************************** //
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="utf-8"/>
<meta http-equiv="Pragma" content="no-cache">
<meta http-equiv="Cache-Control" content="no-cache">
<meta http-equiv="Expires" content="0">
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes" />
<title>AquesTalk</title>
<link rel="stylesheet" href="./css/jquery.mobile-1.4.5.min.css" />
<script src="./js/jquery-2.2.2.min.js"></script>
<script src="./js/jquery.mobile-1.4.5.min.js"></script>
<script src="./js/index.js"></script>
<style type="text/css">
textarea {
font-family: monospace;
font-size:16px;
}
</style>
</head>
<body>
<div data-role="page" id="p-main">
<div data-role="header" data-position="fixed" data-theme="b">
<h1>AquesTalk Test</h1>
</div>
<div role="main" class="ui-content">
<table border="0"cellpadding="2" align="center" width="50%">
<tr align="center">
<td>
<form action="/aquestalk" target="name_iframe" method="POST" accept-charset="utf-8">
<textarea id="id_msg" name="msg" style="color: black; background-color: white;"></textarea>
<input type="submit" name="submit" id="id_msg_submit" data-theme="a" data-inline="true" data-icon="audio" data-iconpos="right" value="AquesTalk"/>
</form>
</td>
</tr>
</table>
<table border="0" cellpadding="5" align="center">
<tr align="center">
<td>
<iframe style="visibility:hidden;display:none" name="name_iframe" id="id_iframe"></iframe>
</td>
</tr>
</table>
</div>
<div data-role="footer" data-position="fixed" data-theme="b">
<div data-role="navbar">
<ul>
<li><a href="" data-ajax="false" data-icon="refresh" onClick="location.reload();">再読込</a></li>
</ul>
</div>
<h2>Copyright 2025 Moo Soft</h2>
</div>
</div>
</body>
</html>

// +++++++++++++++++++++++++++++++++++++++++++++++ //

/*
index.js

Copyright 2025 Moo Soft (Yokoyama Akiyosi)
*/

// ページ表示後イベント
$(document).on(‘pageshow’, ‘#p-main’, function(e, data) {
const tarea = document.getElementById(‘id_msg’);
tarea.value = date_str(); // テキストデータ設定
ajustTextArea(tarea); // テキストエリア高さ自動調整
}); // $(document).on

// テキストエリア高さ自動調整
// tarea : テキストエリア
// 戻り値 : 無し
function ajustTextArea(tarea){
tarea.style.height = “0px”;
const autoHeight = parseInt(tarea.scrollHeight, 10); // データの最後に改行が有る場合は -10
tarea.style.height = autoHeight.toString(10) + “px”;
} // ajustTextArea

// 現在日時文字列取得
// 戻り値 : 現在日時文字列
function date_str() {
let date = new Date();
result = date.getFullYear() + ‘年’ +
(date.getMonth()+ 1) + ‘月’ +
date.getDate() + ‘日’ +
date.getHours() + ‘時’ +
date.getMinutes() + ‘分’ +
date.getSeconds() + ‘秒です。’;

return result;
} // function date_str()


コメント

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です