1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

音声アシスタント作りたくなって調べた[メモ]

Posted at

手作り音声アシスタントを作りたかったが、色々調べ物が面倒だったので放置していたが、今だ!と思って調べた

cotomoに感動したからですね

検証環境

windows10pro
i7-12700 128Gmem 3070 Ti
python 3.11.9 (pyaudioをインストールする際に3.12だとコケたので3.11を利用)

今回のコード

今回は上記のコードをPGT-4oで出力しました
自分ではファイル名ぐらいしか書いてません
設定などまっさらなので、よければ参考として

vosk_recognizer.py
import pyaudio
import json
import requests
from vosk import Model, KaldiRecognizer
import logging
import time
import threading

# ロギングの設定
logging.basicConfig(level=logging.DEBUG)

# モデルのパスを指定します
model_path = "vosk-model-ja-0.22"  # 例: "vosk-model-small-en-us-0.15"

# モデルをロードします
model = Model(model_path)
recognizer = KaldiRecognizer(model, 16000)

# PyAudioの設定
p = pyaudio.PyAudio()
stream = p.open(format=pyaudio.paInt16, channels=1, rate=16000, input=True, frames_per_buffer=4096)
stream.start_stream()

def recognize_speech():
    logging.debug("Listening...")
    
    while True:
        data = stream.read(4096, exception_on_overflow=False)
        if recognizer.AcceptWaveform(data):
            result = recognizer.Result()
            text = json.loads(result)["text"]
            logging.debug(f"Recognized Text: {text}")
            
            # デバッグログ:送信されるデータを表示
            logging.debug(f"Sending text to server: {text}")
            
            # Text-generation-webuiにテキストを渡す
            response = requests.post("http://127.0.0.1:5000/api/generate", json={"input": text})
            if response.status_code == 200:
                generated_text = response.json().get("output", "")
                logging.debug(f"Generated Text: {generated_text}")
            else:
                logging.error(f"Error: {response.status_code}, {response.text}")
        else:
            partial_result = recognizer.PartialResult()
            logging.debug(f"Partial Result: {json.loads(partial_result)['partial']}")
        time.sleep(0.1)

def listen_loop():
    while True:
        recognize_speech()

if __name__ == '__main__':
    listener_thread = threading.Thread(target=listen_loop)
    listener_thread.start()
    listener_thread.join()

サーバー部分

app.py
from flask import Flask, request, jsonify
from transformers import pipeline
import logging

app = Flask(__name__)

# ロギングの設定
logging.basicConfig(level=logging.DEBUG)

# Text-generationモデルのロード
generator = pipeline('text-generation', model='EleutherAI/gpt-neo-2.7B', pad_token_id=50256)

@app.route('/api/generate', methods=['POST'])
def generate_text():
    logging.debug("Received POST request for text generation.")
    
    input_data = request.json
    if input_data is None:
        logging.debug("No JSON data received.")
        return jsonify({"error": "No JSON data received"}), 400
    
    logging.debug(f"Received JSON data: {input_data}")

    input_text = input_data.get('input', '').strip()
    
    if not input_text:
        logging.debug("No input text provided.")
        return jsonify({"error": "No input text provided"}), 400
    
    logging.debug(f"Input text: {input_text}")
    generated = generator(input_text, max_length=50, num_return_sequences=1, truncation=True)
    output_text = generated[0]['generated_text']
    logging.debug(f"Generated text: {output_text}")
    
    return jsonify({"output": output_text})

if __name__ == '__main__':
    logging.debug("Starting Flask server.")
    app.run(host='127.0.0.1', port=5000)

音声認識

現代ではいくつか候補があるらしい
今回は、VOSKを使用した
音声認識からテキストへの変換はこれでいいんじゃないかと思った
whisperを触っていたときに、リアルタイムではだいぶ厳しいぞと思っていたので、認識を甘くしてもうまく立ち上がるのは良いなと思った

pyaudio_sample.py
p = pyaudio.PyAudio()
stream = p.open(format=pyaudio.paInt16, channels=1, rate=16000, input=True, frames_per_buffer=4096)
stream.start_stream()

マイクの入力が圧倒的に楽

input=True //マイク
Outpu=True //PCのオーディオ

だと見た気がする
間違ってたらごめんね

ローカルLLM

今回は一旦なんでもいいやと思って、text-generation-webuiを使おうと思った
以下のURLを参考にしたが、多分使っていない気がする
https://zenn.dev/saldra/articles/201dd9e7d8c743

少し大きいモデルを使っているが、返答に15秒ほどかかるので、これはチューンしないといけない
返事が来たらそれを読み上げさせればいいかと思ったが、音声周りでどうも躓いたのでここまでになった

シンプルにローカルだとだいぶ回答が曖昧なので、用途を絞るかオンラインのAPIを使うか、曖昧でも成立するように考えるかの必要があると思った
また、全部AIである必要もないので、時間やスケジュールなんかは参照できるものがあると良いなと思った

音声読み上げ

TTSライブラリを浸かって読み上げを試みていたが、どうにもうまくいかなかったので諦めた
利用したのは、pyttsx3

pip install pyttsx3

利用方法は以下

最初の頃の_app.py
from flask import Flask, request, jsonify
from transformers import pipeline
import pyttsx3

app = Flask(__name__)

generator = pipeline('text-generation', model='EleutherAI/gpt-neo-2.7B')

# 音声合成エンジンの初期化
engine = pyttsx3.init()

@app.route('/api/generate', methods=['POST'])
def generate_text():
    input_data = request.json
    input_text = input_data.get('input', '')
    
    if not input_text:
        return jsonify({"error": "No input text provided"}), 400
    
    generated = generator(input_text, max_length=50, num_return_sequences=1)
    output_text = generated[0]['generated_text']
    
    # テキストを音声で読み上げ
    engine.say(output_text)
    engine.runAndWait()
    
    return jsonify({"output": output_text})

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=5000)

voicevoxなども試してみたが、集中力が切れたのでやめた

終わりに

音声アシスタントは多分作れる

  • 基礎的なプログラミングができる
  • パラメーターを調べる根気がある
  • チューニングする気力がある

上記の気合があれば、かなりすぐ作れる、知識さえあれば、多分
去年騒がれていたときはコード本当にひどかったけど、一旦実行までは一発に近い感じで出るのですごい
でもやっぱり修正やチューニングはどうしたって知識が必要なので、勉強してないと無理だなって思いました

僕にはここから先は無理なので、一緒に誰かやってくれねぇかなと

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?