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の場合