paint-brush
Ang Pagho-host ng Iyong Sariling AI gamit ang Two-Way Voice Chat ay Mas Madali kaysa Inaakala Mo!sa pamamagitan ng@herahavenai
Bagong kasaysayan

Ang Pagho-host ng Iyong Sariling AI gamit ang Two-Way Voice Chat ay Mas Madali kaysa Inaakala Mo!

sa pamamagitan ng HeraHaven AI10m2025/01/08
Read on Terminal Reader

Masyadong mahaba; Upang basahin

Gagabayan ka ng gabay na ito sa pag-set up ng isang lokal na LLM server na sumusuporta sa mga two-way na pakikipag-ugnayan ng boses gamit ang Python, Transformers, Qwen2-Audio-7B-Instruct, at Bark.
featured image - Ang Pagho-host ng Iyong Sariling AI gamit ang Two-Way Voice Chat ay Mas Madali kaysa Inaakala Mo!
HeraHaven AI HackerNoon profile picture

Ang pagsasama ng mga LLM sa mga kakayahan sa boses ay lumikha ng mga bagong pagkakataon sa mga personalized na pakikipag-ugnayan ng customer.


Gagabayan ka ng gabay na ito sa pag-set up ng isang lokal na LLM server na sumusuporta sa mga two-way na pakikipag-ugnayan ng boses gamit ang Python, Transformers, Qwen2-Audio-7B-Instruct, at Bark.

Mga kinakailangan

Bago tayo magsimula, mai-install mo ang sumusunod:

  • Python : Bersyon 3.9 o mas mataas.
  • PyTorch : Para sa pagpapatakbo ng mga modelo.
  • Mga Transformer : Nagbibigay ng access sa modelong Qwen.
  • Pabilisin : Kinakailangan sa ilang kapaligiran.
  • FFmpeg & pydub : Para sa pagproseso ng audio.
  • FastAPI : Upang lumikha ng web server.
  • Uvicorn : ASGI server para patakbuhin ang FastAPI.
  • Bark : Para sa text-to-speech synthesis.
  • Multipart & Scipy : Upang manipulahin ang audio.


Maaaring i-install ang FFmpeg sa pamamagitan ng apt install ffmpeg sa Linux o brew install ffmpeg sa MacOS.


Maaari mong i-install ang Python dependencies gamit ang pip: pip install torch transformers accelerate pydub fastapi uvicorn bark python-multipart scipy

Hakbang 1: Pag-set Up ng Kapaligiran

Una, i-set up natin ang ating Python environment at piliin ang ating PyTorch device:


 import torch device = 'cuda' if torch.cuda.is_available() else 'cpu'


Tinitingnan ng code na ito kung available ang isang CUDA-compatible (Nvidia) GPU at itinatakda ang device nang naaayon.


Kung walang ganoong GPU, tatakbo ang PyTorch sa CPU na mas mabagal.


Para sa mga mas bagong Apple Silicon device, maaari ding itakda ang device sa mps para patakbuhin ang PyTorch on Metal, ngunit hindi komprehensibo ang pagpapatupad ng PyTorch Metal.

Hakbang 2: Nilo-load ang Modelo

Karamihan sa mga open-source na LLM ay sumusuporta lamang sa text input at text output. Gayunpaman, dahil gusto naming gumawa ng voice-in-voice-out system, kakailanganin nitong gumamit kami ng dalawa pang modelo para (1) i-convert ang speech sa text bago ito i-feed sa aming LLM at (2) i-convert pabalik ang LLM output. sa pagsasalita.


Sa pamamagitan ng paggamit ng multimodal na LLM tulad ng Qwen Audio, makakaalis tayo sa isang modelo para iproseso ang speech input sa isang text response, at pagkatapos ay kailangan lang gumamit ng pangalawang modelo na i-convert ang LLM output pabalik sa speech.


Ang multimodal na diskarte na ito ay hindi lamang mas mahusay sa mga tuntunin ng oras ng pagpoproseso at (V) pagkonsumo ng RAM, ngunit kadalasan ay nagbubunga din ng mas mahusay na mga resulta dahil ang input audio ay ipinadala nang diretso sa LLM nang walang anumang friction.


Kung tumatakbo ka sa cloud GPU host tulad ng Runpod o Vast , gugustuhin mong itakda ang HuggingFace home & Bark directory sa iyong volume storage sa pamamagitan ng pagpapatakbo ng export HF_HOME=/workspace/hf & export XDG_CACHE_HOME=/workspace/bark bago mag-download ang mga modelo.


 from transformers import AutoProcessor, Qwen2AudioForConditionalGeneration model_name = "Qwen/Qwen2-Audio-7B-Instruct" processor = AutoProcessor.from_pretrained(model_name) model = Qwen2AudioForConditionalGeneration.from_pretrained(model_name, device_map="auto").to(device)


Pinili naming gamitin ang maliit na 7B na variant ng serye ng modelong Qwen Audio dito upang bawasan ang aming mga kinakailangan sa computational. Gayunpaman, maaaring naglabas si Qwen ng mas malakas at mas malalaking audio model sa oras na binabasa mo ang artikulong ito. Maaari mong tingnan ang lahat ng mga modelo ng Qwen sa HuggingFace upang matiyak na ginagamit mo ang kanilang pinakabagong modelo.


Para sa kapaligiran ng produksyon, maaaring gusto mong gumamit ng mabilis na inference engine tulad ng vLLM para sa mas mataas na throughput.

Hakbang 3: Nilo-load ang modelo ng Bark

Ang Bark ay isang state-of-the-art na open-source na text-to-speech na modelo ng AI na sumusuporta sa maraming wika pati na rin ang mga sound effect.


 from bark import SAMPLE_RATE, generate_audio, preload_models preload_models()


Bukod sa Bark, maaari ka ring gumamit ng iba pang open-source o proprietary text-to-speech na mga modelo. Tandaan na habang ang mga pinagmamay-ari ay maaaring mas mahusay na gumaganap, ang mga ito ay may mas mataas na halaga. Ang TTS arena ay nagpapanatili ng up-to-date na paghahambing .


Sa parehong Qwen Audio 7B at Bark na na-load sa memorya, ang tinatayang (V) RAM na paggamit ay 24GB, kaya siguraduhing sinusuportahan ito ng iyong hardware. Kung hindi, maaari kang gumamit ng quantized na bersyon ng modelong Qwen upang makatipid sa memorya.

Hakbang 4: Pag-set Up ng FastAPI Server

Gagawa kami ng isang FastAPI server na may dalawang ruta para pangasiwaan ang mga papasok na audio o text input at ibalik ang mga audio na tugon.


 from fastapi import FastAPI, UploadFile, Form from fastapi.responses import StreamingResponse import uvicorn app = FastAPI() @app.post("/voice") async def voice_interaction(file: UploadFile): # TODO return @app.post("/text") async def text_interaction(text: str = Form(...)): # TODO return if __name__ == "__main__":  uvicorn.run(app, host="0.0.0.0", port=8000)


Ang server na ito ay tumatanggap ng mga audio file sa pamamagitan ng POST na mga kahilingan sa /voice & /text endpoint.

Hakbang 5: Pagproseso ng Audio Input

Gagamitin namin ang ffmpeg para iproseso ang papasok na audio at ihanda ito para sa modelong Qwen.


 from pydub import AudioSegment from io import BytesIO import numpy as np def audiosegment_to_float32_array(audio_segment: AudioSegment, target_rate: int = 16000) -> np.ndarray: audio_segment = audio_segment.set_frame_rate(target_rate).set_channels(1) samples = np.array(audio_segment.get_array_of_samples(), dtype=np.int16) samples = samples.astype(np.float32) / 32768.0 return samples def load_audio_as_array(audio_bytes: bytes) -> np.ndarray: audio_segment = AudioSegment.from_file(BytesIO(audio_bytes)) float_array = audiosegment_to_float32_array(audio_segment, target_rate=16000) return float_array

Hakbang 6: Pagbuo ng Tekstuwal na Tugon sa Qwen

Gamit ang naprosesong audio, makakabuo tayo ng textual na tugon gamit ang modelong Qwen. Kakailanganin nitong pangasiwaan ang parehong mga input ng text at audio.


Iko-convert ng preprocessor ang aming input sa template ng chat ng modelo (ChatML sa kaso ni Qwen).


 def generate_response(conversation): text = processor.apply_chat_template(conversation, add_generation_prompt=True, tokenize=False) audios = [] for message in conversation: if isinstance(message["content"], list): for ele in message["content"]: if ele["type"] == "audio": audio_array = load_audio_as_array(ele["audio_url"]) audios.append(audio_array) if audios: inputs = processor( text=text, audios=audios, return_tensors="pt", padding=True ).to(device) else: inputs = processor( text=text, return_tensors="pt", padding=True ).to(device) generate_ids = model.generate(**inputs, max_length=256) generate_ids = generate_ids[:, inputs.input_ids.size(1):] response = processor.batch_decode( generate_ids, skip_special_tokens=True, clean_up_tokenization_spaces=False )[0] return response


Huwag mag-atubiling makipaglaro sa mga parameter ng henerasyon tulad ng temperatura sa model.generate function.

Hakbang 7: Pag-convert ng Teksto sa Speech gamit ang Bark

Panghuli, iko-convert namin ang nabuong tugon ng teksto pabalik sa pagsasalita.


 from scipy.io.wavfile import write as write_wav def text_to_speech(text): audio_array = generate_audio(text) output_buffer = BytesIO() write_wav(output_buffer, SAMPLE_RATE, audio_array) output_buffer.seek(0) return output_buffer

Hakbang 8: Pagsasama ng Lahat sa mga API

I-update ang mga endpoint upang maproseso ang audio o text input, bumuo ng tugon, at ibalik ang synthesized na pagsasalita bilang isang WAV file.


 @app.post("/voice") async def voice_interaction(file: UploadFile): audio_bytes = await file.read() conversation = [ { "role": "user", "content": [ { "type": "audio", "audio_url": audio_bytes } ] } ] response_text = generate_response(conversation) audio_output = text_to_speech(response_text) return StreamingResponse(audio_output, media_type="audio/wav") @app.post("/text") async def text_interaction(text: str = Form(...)): conversation = [ {"role": "user", "content": [{"type": "text", "text": text}]} ] response_text = generate_response(conversation) audio_output = text_to_speech(response_text) return StreamingResponse(audio_output, media_type="audio/wav")

Maaari mong piliing magdagdag ng mensahe ng system sa mga pag-uusap upang makakuha ng higit na kontrol sa mga tugon ng katulong.

Hakbang 9: Pagsubok ng mga bagay

Maaari naming gamitin curl upang i-ping ang aming server tulad ng sumusunod:


 # Audio input curl -X POST http://localhost:8000/voice --output output.wav -F "[email protected]" # Text input curl -X POST http://localhost:8000/text --output output.wav -H "Content-Type: application/x-www-form-urlencoded" -d "text=Hey"

Konklusyon

Sa pamamagitan ng pagsunod sa mga hakbang na ito, nag-set up ka ng isang simpleng lokal na server na may kakayahang mag-two-way na pakikipag-ugnayan ng boses gamit ang mga makabagong modelo. Maaaring magsilbi ang setup na ito bilang pundasyon para sa pagbuo ng mas kumplikadong mga application na pinagana ng boses.

Mga aplikasyon

Kung nag-e-explore ka ng mga paraan para pagkakitaan ang mga modelo ng wikang pinapagana ng AI, isaalang-alang ang mga potensyal na application na ito:

Buong code

 import torch from fastapi import FastAPI, UploadFile, Form from fastapi.responses import StreamingResponse import uvicorn from transformers import AutoProcessor, Qwen2AudioForConditionalGeneration from bark import SAMPLE_RATE, generate_audio, preload_models from scipy.io.wavfile import write as write_wav from pydub import AudioSegment from io import BytesIO import numpy as np device = 'cuda' if torch.cuda.is_available() else 'cpu' model_name = "Qwen/Qwen2-Audio-7B-Instruct" processor = AutoProcessor.from_pretrained(model_name) model = Qwen2AudioForConditionalGeneration.from_pretrained(model_name, device_map="auto").to(device) preload_models() app = FastAPI() def audiosegment_to_float32_array(audio_segment: AudioSegment, target_rate: int = 16000) -> np.ndarray: audio_segment = audio_segment.set_frame_rate(target_rate).set_channels(1) samples = np.array(audio_segment.get_array_of_samples(), dtype=np.int16) samples = samples.astype(np.float32) / 32768.0 return samples def load_audio_as_array(audio_bytes: bytes) -> np.ndarray: audio_segment = AudioSegment.from_file(BytesIO(audio_bytes)) float_array = audiosegment_to_float32_array(audio_segment, target_rate=16000) return float_array def generate_response(conversation): text = processor.apply_chat_template(conversation, add_generation_prompt=True, tokenize=False) audios = [] for message in conversation: if isinstance(message["content"], list): for ele in message["content"]: if ele["type"] == "audio": audio_array = load_audio_as_array(ele["audio_url"]) audios.append(audio_array) if audios: inputs = processor( text=text, audios=audios, return_tensors="pt", padding=True ).to(device) else: inputs = processor( text=text, return_tensors="pt", padding=True ).to(device) generate_ids = model.generate(**inputs, max_length=256) generate_ids = generate_ids[:, inputs.input_ids.size(1):] response = processor.batch_decode( generate_ids, skip_special_tokens=True, clean_up_tokenization_spaces=False )[0] return response def text_to_speech(text): audio_array = generate_audio(text) output_buffer = BytesIO() write_wav(output_buffer, SAMPLE_RATE, audio_array) output_buffer.seek(0) return output_buffer @app.post("/voice") async def voice_interaction(file: UploadFile): audio_bytes = await file.read() conversation = [ { "role": "user", "content": [ { "type": "audio", "audio_url": audio_bytes } ] } ] response_text = generate_response(conversation) audio_output = text_to_speech(response_text) return StreamingResponse(audio_output, media_type="audio/wav") @app.post("/text") async def text_interaction(text: str = Form(...)): conversation = [ {"role": "user", "content": [{"type": "text", "text": text}]} ] response_text = generate_response(conversation) audio_output = text_to_speech(response_text) return StreamingResponse(audio_output, media_type="audio/wav") if __name__ == "__main__": uvicorn.run(app, host="0.0.0.0", port=8000)