paint-brush
Kendi Yapay Zeka İtirafınızı Nasıl Oluşturabilirsiniz: Yüksek Lisans'a Ses Nasıl Eklenir?by@slavasobolev
661
661

Kendi Yapay Zeka İtirafınızı Nasıl Oluşturabilirsiniz: Yüksek Lisans'a Ses Nasıl Eklenir?

Iaroslav Sobolev11m2024/07/14
Read on Terminal Reader

Şubat ayının sonunda Bali, ünlü Yanan Adam'ın ilkelerine göre düzenlenen [Lampu](https://lampu.org/) festivaline ev sahipliği yaptı. Katolik itirafçıların fikrinden ve mevcut LLM'nin yeteneklerinden ilham aldık. Herkesin bir yapay zekayla konuşabileceği kendi yapay zeka günah çıkarma odamızı kurduk.
featured image - Kendi Yapay Zeka İtirafınızı Nasıl Oluşturabilirsiniz: Yüksek Lisans'a Ses Nasıl Eklenir?
Iaroslav Sobolev HackerNoon profile picture
0-item
1-item

OpenAI, ChatGPT için gelişmiş Ses Modlarının yayınlanmasını geciktirirken , LLM ses uygulamamızı nasıl oluşturduğumuzu ve onu etkileşimli bir kabine nasıl entegre ettiğimizi paylaşmak istiyorum.

Ormandaki yapay zeka ile konuşun

Şubat ayının sonunda Bali, ünlü Burning Man ilkelerine göre düzenlenen Lampu festivaline ev sahipliği yaptı. Geleneğe göre katılımcılar kendi enstalasyonlarını ve sanat objelerini yaratıyorlar.


Camp 19:19'daki arkadaşlarım ve ben, Katolik günah çıkarma salonları fikrinden ve mevcut yüksek lisansların yeteneklerinden esinlenerek, herkesin bir yapay zeka ile konuşabileceği kendi yapay zeka günah çıkarma odamızı inşa etme fikrini ortaya attık.


Bunu en başında şöyle hayal etmiştik:

  • Kullanıcı bir standa girdiğinde yeni bir oturum başlatmamız gerektiğini belirliyoruz.


  • Kullanıcı bir soru sorar ve yapay zeka dinler ve yanıtlar. Herkesin düşüncelerini ve deneyimlerini açıkça tartışabileceği, güven veren ve özel bir ortam yaratmak istedik.


  • Kullanıcı odadan çıktığında sistem oturumu sonlandırır ve tüm konuşma ayrıntılarını unutur. Bu, tüm diyalogların gizli kalması için gereklidir.

Kavramın ispatı

Konsepti test etmek ve LLM'ye yönelik bir istemle denemeler yapmaya başlamak için bir akşam saf bir uygulama oluşturdum:

  • Bir mikrofonu dinleyin.
  • Konuşmadan Metne (STT) modelini kullanarak kullanıcı konuşmasını tanıyın.
  • LLM aracılığıyla bir yanıt oluşturun.
  • Metinden Konuşmaya (TTS) modelini kullanarak bir sesli yanıt sentezleyin.
  • Yanıtı kullanıcıya oynatın.



Bu demoyu uygulamak için tamamen OpenAI'nin bulut modellerine güvendim: Whisper , GPT-4 ve TTS . Mükemmel konuşma_recognition kütüphanesi sayesinde demoyu yalnızca birkaç düzine kod satırıyla oluşturdum.


 import os import asyncio from dotenv import load_dotenv from io import BytesIO from openai import AsyncOpenAI from soundfile import SoundFile import sounddevice as sd import speech_recognition as sr load_dotenv() aiclient = AsyncOpenAI( api_key=os.environ.get("OPENAI_API_KEY") ) SYSTEM_PROMPT = """ You are helpfull assistant. """ async def listen_mic(recognizer: sr.Recognizer, microphone: sr.Microphone): audio_data = recognizer.listen(microphone) wav_data = BytesIO(audio_data.get_wav_data()) wav_data.name = "SpeechRecognition_audio.wav" return wav_data async def say(text: str): res = await aiclient.audio.speech.create( model="tts-1", voice="alloy", response_format="opus", input=text ) buffer = BytesIO() for chunk in res.iter_bytes(chunk_size=4096): buffer.write(chunk) buffer.seek(0) with SoundFile(buffer, 'r') as sound_file: data = sound_file.read(dtype='int16') sd.play(data, sound_file.samplerate) sd.wait() async def respond(text: str, history): history.append({"role": "user", "content": text}) completion = await aiclient.chat.completions.create( model="gpt-4", temperature=0.5, messages=history, ) response = completion.choices[0].message.content await say(response) history.append({"role": "assistant", "content": response}) async def main() -> None: m = sr.Microphone() r = sr.Recognizer() messages = [{"role": "system", "content": SYSTEM_PROMPT}] with m as source: r.adjust_for_ambient_noise(source) while True: wav_data = await listen_mic(r, source) transcript = await aiclient.audio.transcriptions.create( model="whisper-1", temperature=0.5, file=wav_data, response_format="verbose_json", ) if transcript.text == '' or transcript.text is None: continue await respond(transcript.text, messages) if __name__ == '__main__': asyncio.run(main())


Bu demodaki ilk testlerden sonra çözmemiz gereken sorunlar hemen ortaya çıktı:

  • Tepki gecikmesi . Saf bir uygulamada, kullanıcının sorusu ile yanıtı arasındaki gecikme 7-8 saniye veya daha uzundur. Bu iyi değil ama tepki süresini optimize etmenin birçok yolu olduğu açık.


  • Ortam gürültüsü . Gürültülü ortamlarda, kullanıcının konuşmaya başladığını ve konuşmayı otomatik olarak bitirdiğini algılamak için mikrofona güvenemeyeceğimizi keşfettik. Bir cümlenin başlangıcını ve sonunu tanımak ( bitiş noktası belirleme ) önemsiz bir iştir. Bunu bir müzik festivalinin gürültülü ortamıyla birleştirdiğinizde kavramsal olarak farklı bir yaklaşıma ihtiyaç olduğu açıktır.


  • Canlı konuşmayı taklit edin . Kullanıcıya yapay zekayı kesme yeteneği vermek istedik. Bunu başarmak için mikrofonu açık tutmamız gerekir. Ancak bu durumda kullanıcının sesini yalnızca arka plan seslerinden değil aynı zamanda yapay zekanın sesinden de ayırmamız gerekir.


  • Geri bildirim . Yanıt gecikmesi nedeniyle bazen bize sistem donmuş gibi geldi. Yanıtın ne kadar süreyle işleneceğini kullanıcıya bildirmemiz gerektiğini fark ettik


Bu sorunları nasıl çözeceğimize dair bir seçeneğimiz vardı: uygun bir mühendislik veya ürün çözümü arayarak.

Standın Kullanıcı Deneyimi Üzerinden Düşünmek

Kodlamaya başlamadan önce kullanıcının kabinle nasıl etkileşim kuracağına karar vermemiz gerekiyordu:

  • Geçmiş diyalog geçmişini sıfırlamak için kabinde yeni bir kullanıcıyı nasıl tespit edeceğimize karar vermeliyiz.


  • Bir kullanıcının konuşmasının başlangıcını ve sonunu nasıl tanıyacağımız ve yapay zekayı kesintiye uğratmak isterse ne yapılması gerektiği.


  • Yapay zekadan gecikmiş bir yanıt geldiğinde geri bildirim nasıl uygulanır?


Kabinde yeni bir kullanıcıyı tespit etmek için çeşitli seçenekleri değerlendirdik: kapı açma sensörleri, zemin ağırlığı sensörleri, mesafe sensörleri ve kamera + YOLO modeli. Arkadaki mesafe sensörü, kapının yeterince sıkı kapatılmaması gibi kazara tetiklenenleri hariç tuttuğu ve ağırlık sensörünün aksine karmaşık kurulum gerektirmediği için bize en güvenilir göründü.


Bir diyaloğun başlangıcını ve sonunu tanıma zorluğunu ortadan kaldırmak için mikrofonu kontrol edecek büyük bir kırmızı düğme eklemeye karar verdik. Bu çözüm aynı zamanda kullanıcının yapay zekayı istediği zaman kesmesine de olanak tanıdı.


Bir isteğin işlenmesinde geri bildirimin uygulanması konusunda birçok farklı fikrimiz vardı. Sistemin ne yaptığını gösteren ekranlı bir seçeneğe karar verdik: mikrofonu dinlemek, bir soruyu işlemek veya yanıtlamak.


Ayrıca eski bir sabit hatlı telefonla oldukça akıllı bir seçenek de düşündük. Oturum, kullanıcı telefonu açtığında başlayacak ve sistem, kullanıcı telefonu kapatana kadar onu dinleyecektir. Ancak, kullanıcıya telefondan gelen bir ses yerine kabin tarafından "cevap verilmesinin" daha gerçekçi olacağına karar verdik.


Kurulum sırasında ve festivalde


Sonunda son kullanıcı akışı şu şekilde ortaya çıktı:

  • Bir kullanıcı bir kabine girer. Arkasından bir mesafe sensörü tetikleniyor ve biz onu selamlıyoruz.


  • Kullanıcı bir diyalog başlatmak için kırmızı düğmeye basar. Düğmeye basıldığında mikrofonu dinliyoruz. Kullanıcı düğmeyi bıraktığında isteği işlemeye başlarız ve bunu ekranda belirtiriz.


  • Kullanıcı, yapay zeka yanıt verirken yeni bir soru sormak isterse düğmeye tekrar basabilir ve yapay zeka yanıtlamayı hemen durdurur.


  • Kullanıcı kabinden ayrıldığında mesafe sensörü tekrar tetiklenir ve diyalog geçmişini temizleriz.

Mimari


Arduino, mesafe sensörünün ve kırmızı düğmenin durumunu izler. Tüm değişiklikleri HTTP API aracılığıyla arka uçumuza gönderir; bu, sistemin kullanıcının kabine girip girmediğini ve mikrofonu dinlemeyi etkinleştirmenin veya bir yanıt oluşturmaya başlamanın gerekli olup olmadığını belirlemesine olanak tanır.


Web kullanıcı arayüzü , sistemin mevcut durumunu sürekli olarak arka uçtan alan ve kullanıcıya görüntüleyen, bir tarayıcıda açılan bir web sayfasıdır.


Arka uç mikrofonu kontrol eder, gerekli tüm yapay zeka modelleriyle etkileşime girer ve LLM yanıtlarını seslendirir. Uygulamanın temel mantığını içerir.

Donanım

Arduino için bir taslağın nasıl kodlanacağı, mesafe sensörünün ve düğmenin doğru şekilde nasıl bağlanacağı ve hepsinin kabinde nasıl monte edileceği ayrı bir makalenin konusudur. Teknik detaylara girmeden elimizdekileri kısaca gözden geçirelim.


Arduino'yu, daha doğrusu yerleşik Wi-Fi modülüne sahip ESP32 modelini kullandık. Mikrodenetleyici, arka ucu çalıştıran dizüstü bilgisayarla aynı Wi-Fi ağına bağlıydı.



Kullandığımız donanımların tam listesi:

Arka uç

Boru hattının ana bileşenleri Konuşmadan Metne (STT), LLM ve Metinden Konuşmaya (TTS)'dir. Her görev için hem yerel olarak hem de bulut üzerinden birçok farklı model mevcuttur.



Elimizde güçlü bir GPU bulunmadığından modellerin bulut tabanlı versiyonlarını tercih etmeye karar verdik. Bu yaklaşımın zayıflığı iyi bir internet bağlantısına duyulan ihtiyaçtır. Yine de tüm optimizasyonlardan sonraki etkileşim hızı, festivalde sahip olduğumuz mobil internete rağmen kabul edilebilir düzeydeydi.


Şimdi boru hattının her bir bileşenine daha yakından bakalım.

Konuşma tanıma

Birçok modern cihaz uzun süredir konuşma tanımayı desteklemektedir. Örneğin, Apple Speech API, iOS ve macOS için mevcuttur ve Web Speech API, tarayıcılar içindir.


Maalesef kalite açısından Whisper veya Deepgram'a göre çok düşüktürler ve dili otomatik olarak algılayamazlar.


İşlem süresini azaltmak için en iyi seçenek, kullanıcı konuşurken konuşmayı gerçek zamanlı olarak tanımaktır. İşte bunların nasıl uygulanacağına dair örnekler içeren bazı projeler: fısıltı_akışı , fısıltı.cpp


Dizüstü bilgisayarımızda bu yaklaşımı kullanan konuşma tanıma hızının gerçek zamanlı olmaktan çok uzak olduğu ortaya çıktı. Birkaç denemeden sonra OpenAI'nin bulut tabanlı Whisper modeline karar verdik.

Yüksek Lisans ve Hızlı Mühendislik

Önceki adımdaki Speech To Text modelinin sonucu, diyalog geçmişiyle birlikte LLM'ye gönderdiğimiz metindir.


Yüksek Lisans seçerken GPT-3.5'i karşılaştırdık. GPT-4 ve Claude. Anahtar faktörün spesifik modelden ziyade konfigürasyonu olduğu ortaya çıktı. Sonunda cevaplarını diğerlerinden daha çok beğendiğimiz GPT-4'te karar kıldık.


LLM modelleri için istemin özelleştirilmesi ayrı bir sanat formu haline geldi. İnternette modelinizi ihtiyacınıza göre nasıl ayarlayacağınızla ilgili birçok kılavuz vardır:



Modelin ilgi çekici, kısa ve esprili bir şekilde yanıt vermesini sağlamak için istem ve sıcaklık ayarlarıyla kapsamlı denemeler yapmak zorunda kaldık.

Konuşma metni

LLM'den alınan yanıtı Text-To-Speech modelini kullanarak seslendiriyoruz ve kullanıcıya dinletiyoruz. Bu adım, demomuzdaki gecikmelerin ana kaynağıydı.


LLM'lerin yanıt vermesi oldukça uzun zaman alıyor. Bununla birlikte, akış modunda jeton bazında yanıt oluşturmayı desteklerler. Bu özelliği, LLM'den tam bir yanıt beklemeden, tek tek ifadeleri alındıkça seslendirerek bekleme süresini optimize etmek için kullanabiliriz.


Bireysel cümleleri seslendirmek


  • LLM'ye bir sorgu yapın.


  • Minimum uzunlukta tam bir cümle elde edene kadar yanıtı arabellek belirtecinde belirteçle biriktiririz. Minimum uzunluk parametresi önemlidir çünkü hem seslendirmenin tonlamasını hem de başlangıçtaki gecikme süresini etkiler.


  • Oluşturulan cümleyi TTS modeline gönderin ve sonucu kullanıcıya oynatın. Bu adımda oynatma sırasında herhangi bir yarış koşulunun olmadığından emin olmak gerekir.


  • LLM yanıtının sonuna kadar önceki adımı tekrarlayın


Kullanıcının ilk parçayı dinlediği süreyi, LLM'den gelen yanıtın geri kalan bölümlerinin işlenmesindeki gecikmeyi gizlemek için kullanırız. Bu yaklaşım sayesinde yanıt gecikmesi yalnızca başlangıçta meydana gelir ve ~3 saniyedir.


 async generateResponse(history) { const completion = await this.ai.completion(history); const chunks = new DialogChunks(); for await (const chunk of completion) { const delta = chunk.choices[0]?.delta?.content; if (delta) { chunks.push(delta); if (chunks.hasCompleteSentence()) { const sentence = chunks.popSentence(); this.voice.ttsAndPlay(sentence); } } } const sentence = chunks.popSentence(); if (sentence) { this.voice.say(sentence); } return chunks.text; }


Son dokunuşlar

Tüm optimizasyonlarımıza rağmen 3-4 saniyelik bir gecikme hala önemli. Kullanıcıyı yanıtın askıda kaldığı hissinden kurtarmak için kullanıcı arayüzüne geri bildirimle dikkat etmeye karar verdik. Birkaç yaklaşıma baktık:


  • LED Göstergeler . Beş durumu görüntülememiz gerekiyordu: boşta kalma, bekleme, dinleme, düşünme ve konuşma. Ancak bunu LED'lerle kolay anlaşılır bir şekilde nasıl yapacağımızı çözemedik.


  • "Düşüneyim", "Hmm" gibi dolgu sözcükleri gerçek hayattaki konuşmayı taklit eder. Bu seçeneği reddettik çünkü doldurucular çoğu zaman modelin yanıtlarının tonuyla eşleşmedi.


  • Kabine bir ekran koyun. Ve farklı durumları animasyonlarla görüntüleyin.


Arka ucu yoklayan ve mevcut duruma göre animasyonlar gösteren basit bir web sayfasıyla son seçeneğe karar verdik.


Sonuçlar

Yapay zeka itiraf odamız dört gün boyunca faaliyet gösterdi ve yüzlerce katılımcının ilgisini çekti. OpenAI API'lerine yaklaşık 50$ harcadık. Karşılığında önemli ölçüde olumlu geri bildirimler ve değerli izlenimler aldık.


Bu küçük deney, sınırlı kaynaklara ve zorlu dış koşullara rağmen bir LLM'ye sezgisel ve etkili bir ses arayüzü eklemenin mümkün olduğunu gösterdi.


Bu arada GitHub'da bulunan arka uç kaynakları