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

実行

  1. あらかじめVOICEVOX(docker版でも可)を起動しておきます
  2. neutralinojs-nuxt3-voicevox の起動
    2.1 neuコマンドから起動する場合
    cd neutralinojs-nuxt3-voicevox
    neu run
    2.2 各OS用の実行プログラムを直接起動する場合
    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 !important;
}
</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,
    },
    },
    },
    })

ビルド

注意事項

ビルド手順

  • ビルド
    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の場合

Ubuntuの場合

Arch Linuxの場合