Neutralinojs + VOICEVOX

Nuxt3で作ったVOICEVOXのフロントエンドアプリをクロスプラットフォームなネイティブアプリケーションにしてみました。
https://github.com/ktkr3d/neutralinojs-nuxt3-voicevox
リポジトリの使い方
ビルド
- クローンgit clone https://github.com/ktkr3d/neutralinojs-nuxt3-voicevox.git 
- ビルドcd neutralinojs-nuxt3-voicevox 
 neu update
 cd nuxt3-src
 npm install
 npm run generate
 cd ..
 neu build
実行
- あらかじめVOICEVOX(docker版でも可)を起動しておきます
- neutralinojs-nuxt3-voicevox の起動
 2.1neuコマンドから起動する場合2.2 各OS用の実行プログラムを直接起動する場合cd neutralinojs-nuxt3-voicevox 
 neu run
 neutralinojs-nuxt3-voicevox/dist/neutralinojs-nuxt3-voicevox/フォルダの実行形式ファイルを実行
注意事項
- Windows 環境でクローズボタンを押してもすぐに終了しない
 https://github.com/neutralinojs/neutralinojs/issues/618
 アプリケーションが終了するまで10秒くらい待つ必要があります。
- Linux環境でダウンロードボタンが機能しない。調査中。- windowモードの場合にボタン押下でダウンロードが始まらない。Inspector経由でリンク先blobのダウンロードはできたので、libwebkit2gtk 4.0-37やパーミッション設定の問題かもしれない。
- browserモード,- chromeモードでは問題なくダウンロードできる。
 
環境
開発環境
- node v20.10.0
- npm 10.2.3
- Neutralinojs binaries: v4.14.1
- Neutralinojs client: v3.12.0
- vue 3.4.3
- nuxt 3.9.0
- veutify 3.4.9
- VOICEVOX 0.14.5
実行環境
- Windows 11
- Ubuntu 23.10
- Arch Linux
構築
プロジェクトフォルダ構成
- フォルダ階層と主なファイルneutralinojs-nuxt3-voicevox/ 
 bin/ # Neutrianojsから提供される各OSのローダ
 dist/ # Neutrianojsプロジェクトのビルド結果
 nuxt3-src/ # Nuxt3 プロジェクト
 components/
 sidebar.vue
 layouts/
 default.vue
 pages/
 index.vue
 voicevox.vue # VOICEVOX フロントエンドアプリ
 plugins/
 veutify.ts
 nuxtconfig.ts # Nuxt プロジェクトの設定
 resources/
 neutralinojs.config.json # Neutralinojs プロジェクトの設定
Neutralinojs
- Neutralinojs インストールnpm install -g @neutralinojs/neu 
- Neutralinojs プロジェクト作成neu create neutralinojs-nuxt3-voicevox 
Nuxt
- Neutralinojs プロジェクト配下にNuxtプロジェクトを作成cd neutralinojs-nuxt3-voicevox 
 npx nuxi@latest init nuxt3-src
 cd nuxt3-src
 npm install
Vuetify
- Vuetify Plugin のインストールnpm i -D vuetify vite-plugin-vuetify 
 npm i @mdi/font
- Vuetify Plugin の設定src/plugins/vuetify.ts // import this after install `@mdi/font` package 
 import '@mdi/font/css/materialdesignicons.css'
 import 'vuetify/styles'
 import { createVuetify } from 'vuetify'
 export default defineNuxtPlugin((app) => {
 const vuetify = createVuetify({
 // ... your configuration
 })
 app.vueApp.use(vuetify)
 })
アプリケーション
- VOICEVOX フロントエンドアプリケーションnuxt3-src/pages/voicevox.vue <template> 
 <div>
 <form @submit.prevent="submitForm">
 <v-table>
 <thead>
 <tr>
 <td>
 <v-container fluid>
 <v-textarea id="text" v-model="formData.text" counter prepend-inner-icon="mdi-comment" class="mx-2" label="メッセージを入力..." rows="3"></v-textarea>
 </v-container>
 </td>
 <td><v-btn type="submit">音声合成</v-btn></td>
 <td></td>
 </tr>
 </thead>
 <tbody>
 <tr v-for="(message, index) in messages" :key="index">
 <td>{{ message.text }}</td>
 <td><audio :src="message.url" controls/></td>
 <td><a :href="message.url" download title="ダウンロード"><v-btn elevation="8" fab icon="mdi-file-download"></v-btn></a></td>
 </tr>
 </tbody>
 </v-table>
 </form>
 </div>
 </template>
 <script setup>
 import { ref } from "vue";
 const formData = ref({
 text: "",
 url: "",
 });
 const messagesData = [];
 const messages = ref(messagesData);
 function addMessage() {
 if (formData.value.text) {
 messages.value.push({
 text: formData.value.text,
 url: formData.value.url,
 });
 formData.value.text = "";
 }
 }
 const submitForm = async () => {
 const { data: queryJson } = await useFetch("http://localhost:50021/audio_query", {
 method: "POST",
 query: { style_id: "1", text: formData.value.text },
 });
 const { data: audioData } = await useFetch("http://localhost:50021/synthesis", {
 method: "POST",
 query: { style_id: "1" },
 body: queryJson,
 responseType: "blob",
 onResponse({ request, response, options }) {
 formData.value.url = window.URL.createObjectURL(response._data);
 },
 });
 addMessage();
 };
 </script>
 <style lang="css">
 td {
 padding: 16px ;
 }
 </style>
設定
- Neutralinojs の設定(変更点)neutralinojs.config.json { 
 "documentRoot": "/nuxt3-src/dist/",
 }{ 
 "modes": {
 "window": {
 "enableInspector": false,
 "exitProcessOnClose": true
 }
 }
 }
- Nuxt の設定src/nuxt.config.ts import vuetify, { transformAssetUrls } from 'vite-plugin-vuetify' 
 export default defineNuxtConfig({
 //...
 build: {
 transpile: ['vuetify'],
 },
 modules: [
 (_options, nuxt) => {
 nuxt.hooks.hook('vite:extendConfig', (config) => {
 // @ts-expect-error
 config.plugins.push(vuetify({ autoImport: true }))
 })
 },
 //...
 ],
 vite: {
 vue: {
 template: {
 transformAssetUrls,
 },
 },
 },
 })
ビルド
注意事項
- Windows 環境でビルドする場合は以下を対策する (2022-07-12の記事)
 https://ktkr3d.github.io/2022/07/12/Neutralinojs-Nuxt3/#Windows-環境でのneu-build-失敗対策
ビルド手順
- ビルドcd neutralinojs-nuxt3-voicevox 
 cd nuxt3-src; npm run generate; cd ..; neu build --release
- 実行neu run 
生成されたファイル
- ファイル一覧tree -h dist/ 
 [ 512] dist/
 ├── [ 512] neutralinojs-nuxt3-voicevox
 │ ├── [1.8M] neutralinojs-nuxt3-voicevox-linux_arm64
 │ ├── [1.4M] neutralinojs-nuxt3-voicevox-linux_armhf
 │ ├── [1.6M] neutralinojs-nuxt3-voicevox-linux_x64
 │ ├── [1.9M] neutralinojs-nuxt3-voicevox-mac_arm64
 │ ├── [3.9M] neutralinojs-nuxt3-voicevox-mac_universal
 │ ├── [1.9M] neutralinojs-nuxt3-voicevox-mac_x64
 │ ├── [2.5M] neutralinojs-nuxt3-voicevox-win_x64.exe
 │ └── [6.9M] resources.neu
 └── [7.4M] neutralinojs-nuxt3-voicevox-release.zip
- 各OSのローダはNeutralinojsのリリースファイルをコピーしたもの。binに存在するファイル。
- resources.neuファイルがプログラム。Veutifyを使う前は1MB未満で、Veutifyを使うほどサイズが大きくなった。
実行の準備
Windowsの場合
- 管理者モードのコマンドプロンプトで以下を実行しておく
 https://github.com/neutralinojs/v2-specification/blob/main/webview.mdCheckNetIsolation.exe LoopbackExempt -a -n="Microsoft.Win32WebViewHost_cw5n1h2txyewy" 
- VOICEVOXを起動しておく
- 実行neutralinojs-nuxt3-voicevox-win_x64.exe  
Ubuntuの場合
- docker版VOICEVOXを実行
 https://hub.docker.com/r/voicevox/voicevox_engine
- ライブラリsudo apt install libwebkit2gtk-4.0-37 
 sudo apt install gstreamer1.0-plugins-bad
- 実行権限付与
- 実行./neutralinojs-nuxt3-voicevox-linux_x64  
Arch Linuxの場合
- docker版VOICEVOXを実行
 https://hub.docker.com/r/voicevox/voicevox_engine
- 実行権限付与
- 実行./neutralinojs-nuxt3-voicevox-linux_x64  
 Comments





