paint-brush
Kendi Sesli Asistanınızı Oluşturma ve Whisper + Ollama + Bark Kullanarak Yerel Olarak Çalıştırmaile@vndee
1,741 okumalar
1,741 okumalar

Kendi Sesli Asistanınızı Oluşturma ve Whisper + Ollama + Bark Kullanarak Yerel Olarak Çalıştırma

ile Duy Huynh13m2024/04/02
Read on Terminal Reader

Çok uzun; Okumak

Ses tabanlı etkileşim: Kullanıcılar ses girişlerini kaydetmeyi başlatabilir ve durdurabilir ve asistan, oluşturulan sesi çalarak yanıt verir. Konuşma bağlamı: Asistan, konuşmanın bağlamını koruyarak daha tutarlı ve alakalı yanıtlar sağlar. Llama-2 dil modelinin kullanılması asistanın kısa ve odaklanmış yanıtlar vermesine olanak tanır.
featured image - Kendi Sesli Asistanınızı Oluşturma ve Whisper + Ollama + Bark Kullanarak Yerel Olarak Çalıştırma
Duy Huynh HackerNoon profile picture

Kendi RAG'ınızı nasıl oluşturacağınız ve yerel olarak nasıl çalıştıracağınızla ilgili son paylaşımımdan sonra, bugün yalnızca büyük dil modellerinin konuşma yeteneklerini uygulamakla kalmayıp aynı zamanda dinleme ve konuşma yeteneklerini de ekleyerek bunu bir adım daha ileri götürüyoruz. Fikir çok basit: Bilgisayarınızda çevrimdışı çalışabilen, ikonik Iron Man filmlerinden Jarvis'i veya Friday'i anımsatan bir sesli asistan yaratacağız.


Bu bir giriş dersi olduğundan, bunu Python'da uygulayacağım ve yeni başlayanlar için yeterince basit tutacağım. Son olarak uygulamanın nasıl ölçeklendirileceği konusunda bazı rehberlik sağlayacağım.

Teknik yığın

Öncelikle sanal bir Python ortamı kurmalısınız. Bunun için pyenv, virtualenv, poet ve benzer amaçlara hizmet eden diğerleri dahil olmak üzere çeşitli seçenekleriniz vardır. Şahsen, kişisel tercihlerimden dolayı bu ders için Şiir'i kullanacağım. Yüklemeniz gereken birkaç önemli kütüphane şunlardır:


  • zengin : Görsel olarak çekici bir konsol çıktısı için.
  • openai-whisper : Konuşmayı metne dönüştürmek için güçlü bir araç.
  • suno-bark : Metin-konuşma sentezi için yüksek kaliteli ses çıkışı sağlayan son teknoloji ürünü bir kütüphane.
  • langchain : Büyük Dil Modelleri (LLM'ler) ile arayüz oluşturmak için basit bir kütüphane.
  • sounddevice , pyaudio ve konuşma tanıma : Ses kaydı ve oynatma için gereklidir.


Bağımlılıkların ayrıntılı bir listesi için buradaki bağlantıya bakın.


Buradaki en kritik bileşen Ollama'yı kullanacağımız Büyük Dil Modeli (LLM) arka ucudur. Ollama, yüksek lisans eğitimlerini çevrimdışı çalıştırmak ve sunmak için yaygın olarak popüler bir araç olarak tanınmaktadır. Ollama sizin için yeniyse, çevrimdışı RAG ile ilgili önceki makaleme göz atmanızı öneririm: "Kendi RAG'ınızı Oluşturun ve Yerel Olarak Çalıştırın: Langchain + Ollama + Streamlit." Temel olarak Ollama uygulamasını indirmeniz, tercih ettiğiniz modeli çekmeniz ve çalıştırmanız yeterlidir.

Mimari

Tamam, her şey ayarlandıysa bir sonraki adıma geçelim. Temelde 3 ana bileşenden oluşan uygulamamızın genel mimarisi aşağıdadır:


  • Konuşma Tanıma : OpenAI'nin Whisper özelliğini kullanarak konuşulan dili metne dönüştürüyoruz. Whisper'ın çeşitli veri kümeleri üzerindeki eğitimi, çeşitli dil ve lehçelerdeki yeterliliğini garanti eder.


  • Konuşma Zinciri : Konuşma yetenekleri için, Ollama kullanılarak sunulan Llama-2 modeli için Langchain arayüzünü kullanacağız. Bu kurulum kesintisiz ve ilgi çekici bir konuşma akışı vaat ediyor.


  • Konuşma Sentezleyicisi : Metnin konuşmaya dönüştürülmesi, gerçekçi konuşma üretimiyle tanınan Suno AI'nin son teknoloji modeli Bark aracılığıyla gerçekleştirilir.


İş akışı basittir: Konuşmayı kaydedin, metne dönüştürün, LLM kullanarak bir yanıt oluşturun ve Bark'ı kullanarak yanıtı seslendirin.

Whisper, Ollama ve Bark ile sesli asistanın sıra diyagramı.

Uygulama

Uygulama, Bark'ı temel alan bir TextToSpeechService hazırlanmasıyla başlar; metinden konuşmayı sentezlemek ve daha uzun metin girişlerini aşağıdaki gibi sorunsuz bir şekilde işlemek için yöntemler içerir:

 import nltk import torch import warnings import numpy as np from transformers import AutoProcessor, BarkModel warnings.filterwarnings( "ignore", message="torch.nn.utils.weight_norm is deprecated in favor of torch.nn.utils.parametrizations.weight_norm.", ) class TextToSpeechService: def __init__(self, device: str = "cuda" if torch.cuda.is_available() else "cpu"): """ Initializes the TextToSpeechService class. Args: device (str, optional): The device to be used for the model, either "cuda" if a GPU is available or "cpu". Defaults to "cuda" if available, otherwise "cpu". """ self.device = device self.processor = AutoProcessor.from_pretrained("suno/bark-small") self.model = BarkModel.from_pretrained("suno/bark-small") self.model.to(self.device) def synthesize(self, text: str, voice_preset: str = "v2/en_speaker_1"): """ Synthesizes audio from the given text using the specified voice preset. Args: text (str): The input text to be synthesized. voice_preset (str, optional): The voice preset to be used for the synthesis. Defaults to "v2/en_speaker_1". Returns: tuple: A tuple containing the sample rate and the generated audio array. """ inputs = self.processor(text, voice_preset=voice_preset, return_tensors="pt") inputs = {k: v.to(self.device) for k, v in inputs.items()} with torch.no_grad(): audio_array = self.model.generate(**inputs, pad_token_id=10000) audio_array = audio_array.cpu().numpy().squeeze() sample_rate = self.model.generation_config.sample_rate return sample_rate, audio_array def long_form_synthesize(self, text: str, voice_preset: str = "v2/en_speaker_1"): """ Synthesizes audio from the given long-form text using the specified voice preset. Args: text (str): The input text to be synthesized. voice_preset (str, optional): The voice preset to be used for the synthesis. Defaults to "v2/en_speaker_1". Returns: tuple: A tuple containing the sample rate and the generated audio array. """ pieces = [] sentences = nltk.sent_tokenize(text) silence = np.zeros(int(0.25 * self.model.generation_config.sample_rate)) for sent in sentences: sample_rate, audio_array = self.synthesize(sent, voice_preset) pieces += [audio_array, silence.copy()] return self.model.generation_config.sample_rate, np.concatenate(pieces)
  • Başlatma ( __init__ ) : Sınıf, model için kullanılacak cihazı belirten isteğe bağlı bir device parametresi alır (GPU varsa cuda veya cpu ). suno/bark-small önceden eğitilmiş modelden Bark modelini ve karşılık gelen işlemciyi yükler. Model yükleyici için suno/bark belirterek büyük versiyonu da kullanabilirsiniz.


  • Sentezleme ( synthesize ) : Bu yöntem, bir text girişi ve sentez için kullanılacak sesi belirten bir voice_preset parametresi alır. Diğer voice_preset değerini buradan kontrol edebilirsiniz. Giriş metnini ve ses ön ayarını hazırlamak için processor kullanır ve ardından model.generate() yöntemini kullanarak ses dizisini oluşturur. Oluşturulan ses dizisi bir NumPy dizisine dönüştürülür ve örnekleme hızı, ses dizisiyle birlikte döndürülür.


  • Uzun Biçimli Sentezleme ( long_form_synthesize ) : Bu yöntem daha uzun metin girişlerini sentezlemek için kullanılır. İlk önce nltk.sent_tokenize işlevini kullanarak giriş metnini cümleler halinde tokenize eder. Her cümle için ses dizisini oluşturmak üzere synthesize yöntemini çağırır. Daha sonra oluşturulan ses dizilerini, her cümlenin arasına kısa bir sessizlik (0,25 saniye) eklenerek birleştirir.


Artık TextToSpeechService kurulumunu yaptığımıza göre Ollama sunucusunu büyük dil modeli (LLM) hizmetine hazırlamamız gerekiyor. Bunu yapmak için şu adımları uygulamanız gerekir:


  • En son Llama-2 modelini çekin : En son Llama-2 modelini Ollama deposundan indirmek için aşağıdaki komutu çalıştırın: ollama pull llama2 .


  • Ollama sunucusunu başlatın : Sunucu henüz başlatılmadıysa, başlatmak için aşağıdaki komutu uygulayın: ollama serve .


Bu adımları tamamladıktan sonra uygulamanız, kullanıcı girişine yanıtlar oluşturmak için Ollama sunucusunu ve Llama-2 modelini kullanabilecektir.


Daha sonra ana uygulama mantığına geçeceğiz. Öncelikle aşağıdaki bileşenleri başlatmamız gerekiyor:

  • Zengin Konsol : Terminal içinde kullanıcı için daha iyi etkileşimli bir konsol oluşturmak için Zengin kütüphaneyi kullanacağız.


  • Whisper Speech-to-Text : OpenAI tarafından geliştirilen son teknoloji ürünü açık kaynaklı konuşma tanıma sistemi olan Whisper konuşma tanıma modelini başlatacağız. Kullanıcı girişini yazıya aktarmak için temel İngilizce modelini ( base.en ) kullanacağız.


  • Bark Metinden Konuşmaya : Yukarıda uygulanan bir Bark metinden konuşmaya sentezleyici örneğini başlatacağız.


  • Konuşma Zinciri : Konuşma akışını yönetmek için bir şablon sağlayan Langchain kütüphanesindeki yerleşik ConversationalChain kullanacağız. Ollama arka ucuyla Llama-2 dil modelini kullanacak şekilde yapılandıracağız.
 import time import threading import numpy as np import whisper import sounddevice as sd from queue import Queue from rich.console import Console from langchain.memory import ConversationBufferMemory from langchain.chains import ConversationChain from langchain.prompts import PromptTemplate from langchain_community.llms import Ollama from tts import TextToSpeechService console = Console() stt = whisper.load_model("base.en") tts = TextToSpeechService() template = """ You are a helpful and friendly AI assistant. You are polite, respectful, and aim to provide concise responses of less than 20 words. The conversation transcript is as follows: {history} And here is the user's follow-up: {input} Your response: """ PROMPT = PromptTemplate(input_variables=["history", "input"], template=template) chain = ConversationChain( prompt=PROMPT, verbose=False, memory=ConversationBufferMemory(ai_prefix="Assistant:"), llm=Ollama(), )

Şimdi gerekli fonksiyonları tanımlayalım:

  • record_audio : Bu işlev, sounddevice.RawInputStream öğesini kullanarak kullanıcının mikrofonundan ses verilerini yakalamak için ayrı bir iş parçacığında çalışır. Yeni ses verileri mevcut olduğunda geri çağırma işlevi çağrılır ve verileri daha fazla işlenmek üzere bir data_queue yerleştirir.


  • transcribe : Bu işlev, ses verilerini data_queue metne dönüştürmek için Whisper örneğini kullanır.


  • get_llm_response : Bu işlev, geçerli konuşma bağlamını Llama-2 dil modeline (Langchain ConversationalChain aracılığıyla) besler ve oluşturulan metin yanıtını alır.


  • play_audio : Bu işlev, Bark metin-konuşma motoru tarafından oluşturulan ses dalga biçimini alır ve bunu bir ses çalma kitaplığı (örneğin, sounddevice ) kullanarak kullanıcıya oynatır.
 def record_audio(stop_event, data_queue): """ Captures audio data from the user's microphone and adds it to a queue for further processing. Args: stop_event (threading.Event): An event that, when set, signals the function to stop recording. data_queue (queue.Queue): A queue to which the recorded audio data will be added. Returns: None """ def callback(indata, frames, time, status): if status: console.print(status) data_queue.put(bytes(indata)) with sd.RawInputStream( samplerate=16000, dtype="int16", channels=1, callback=callback ): while not stop_event.is_set(): time.sleep(0.1) def transcribe(audio_np: np.ndarray) -> str: """ Transcribes the given audio data using the Whisper speech recognition model. Args: audio_np (numpy.ndarray): The audio data to be transcribed. Returns: str: The transcribed text. """ result = stt.transcribe(audio_np, fp16=False) # Set fp16=True if using a GPU text = result["text"].strip() return text def get_llm_response(text: str) -> str: """ Generates a response to the given text using the Llama-2 language model. Args: text (str): The input text to be processed. Returns: str: The generated response. """ response = chain.predict(input=text) if response.startswith("Assistant:"): response = response[len("Assistant:") :].strip() return response def play_audio(sample_rate, audio_array): """ Plays the given audio data using the sounddevice library. Args: sample_rate (int): The sample rate of the audio data. audio_array (numpy.ndarray): The audio data to be played. Returns: None """ sd.play(audio_array, sample_rate) sd.wait()

Daha sonra ana uygulama döngüsünü tanımlıyoruz. Ana uygulama döngüsü, kullanıcıya konuşma etkileşimi boyunca aşağıdaki şekilde rehberlik eder:


  1. Kullanıcıdan girişini kaydetmeye başlaması için Enter tuşuna basması istenir.


  2. Kullanıcı Enter'a bastığında, kullanıcının ses girişini yakalamak için ayrı bir iş parçacığında record_audio işlevi çağrılır.


  3. Kullanıcı kaydı durdurmak için tekrar Enter'a bastığında ses verileri, transcribe işlevi kullanılarak kopyalanır.


  4. Yazıya aktarılan metin daha sonra Llama-2 dil modelini kullanarak bir yanıt üreten get_llm_response işlevine iletilir.


  5. Oluşturulan yanıt konsola yazdırılır ve play_audio işlevi kullanılarak kullanıcıya oynatılır.

 if __name__ == "__main__": console.print("[cyan]Assistant started! Press Ctrl+C to exit.") try: while True: console.input( "Press Enter to start recording, then press Enter again to stop." ) data_queue = Queue() # type: ignore[var-annotated] stop_event = threading.Event() recording_thread = threading.Thread( target=record_audio, args=(stop_event, data_queue), ) recording_thread.start() input() stop_event.set() recording_thread.join() audio_data = b"".join(list(data_queue.queue)) audio_np = ( np.frombuffer(audio_data, dtype=np.int16).astype(np.float32) / 32768.0 ) if audio_np.size > 0: with console.status("Transcribing...", spinner="earth"): text = transcribe(audio_np) console.print(f"[yellow]You: {text}") with console.status("Generating response...", spinner="earth"): response = get_llm_response(text) sample_rate, audio_array = tts.long_form_synthesize(response) console.print(f"[cyan]Assistant: {response}") play_audio(sample_rate, audio_array) else: console.print( "[red]No audio recorded. Please ensure your microphone is working." ) except KeyboardInterrupt: console.print("\n[red]Exiting...") console.print("[blue]Session ended.")

Sonuç

Her şeyi bir araya getirdikten sonra uygulamayı yukarıdaki videoda gösterildiği gibi çalıştırabiliriz. Bark modelinin daha küçük versiyonunda bile büyük olması nedeniyle uygulama MacBook'umda oldukça yavaş çalışıyor. Bu nedenle videoyu biraz hızlandırdım. CUDA özellikli bir bilgisayara sahip olanlar için daha hızlı çalışabilir. İşte uygulamamızın temel özellikleri:


  • Ses tabanlı etkileşim : Kullanıcılar ses girişlerini kaydetmeyi başlatabilir ve durdurabilir ve asistan, oluşturulan sesi çalarak yanıt verir.


  • Konuşma bağlamı: Asistan, konuşmanın bağlamını koruyarak daha tutarlı ve alakalı yanıtlar sağlar. Llama-2 dil modelinin kullanılması asistanın kısa ve odaklanmış yanıtlar vermesine olanak tanır.


Bu uygulamayı üretime hazır durumuna yükseltmeyi hedefleyenler için aşağıdaki geliştirmeler önerilir:

  • Performans Optimizasyonu : Özellikle alt seviye bilgisayarlarda performansı artırmak için tasarlanmış, Whisse.cpp, Llama.cpp ve Bark.cpp gibi modellerin optimize edilmiş sürümlerini dahil edin.


  • Özelleştirilebilir Bot İstemleri : Kullanıcıların botun kişiliğini ve istemini özelleştirmesine olanak tanıyan, farklı türde asistanların (örneğin kişisel, profesyonel veya alana özel) oluşturulmasına olanak tanıyan bir sistem uygulayın.


  • Grafik Kullanıcı Arayüzü (GUI) : Genel kullanıcı deneyimini geliştirmek, uygulamayı daha erişilebilir ve görsel olarak çekici hale getirmek için kullanıcı dostu bir GUI geliştirin.


  • Çok Modlu Yetenekler : Uygulamayı, ses tabanlı yanıtlara ek olarak görüntüler, diyagramlar veya diğer görsel içerikleri oluşturma ve görüntüleme yeteneği gibi çok modlu etkileşimleri destekleyecek şekilde genişletin.


Sonunda basit sesli asistan uygulamamızı tamamladık, kodun tamamına şu adresten ulaşabilirsiniz: https://github.com/vndee/local-talking-llm . Konuşma tanıma, dil modelleme ve metinden konuşmaya teknolojilerinin bu birleşimi, zor gibi görünen ancak aslında bilgisayarınızda çalışabilen bir şeyi nasıl oluşturabileceğimizi gösteriyor. Kodlamanın tadını çıkaralım ve yapay zeka ve programlamayla ilgili en son makaleleri kaçırmamak için bloguma abone olmayı unutmayın.


Burada da yayınlandı