OpenAI, ChatGPT için gelişmiş Ses Modlarının yayınlanmasını , LLM ses uygulamamızı nasıl oluşturduğumuzu ve onu etkileşimli bir kabine nasıl entegre ettiğimizi paylaşmak istiyorum. geciktirirken Ormandaki yapay zeka ile konuşun Şubat ayının sonunda Bali, ünlü Burning Man ilkelerine göre düzenlenen festivaline ev sahipliği yaptı. Geleneğe göre katılımcılar kendi enstalasyonlarını ve sanat objelerini yaratıyorlar. Lampu 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. Camp 19:19'daki 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. modelini kullanarak kullanıcı konuşmasını tanıyın. Konuşmadan Metne (STT) aracılığıyla bir yanıt oluşturun. LLM modelini kullanarak bir sesli yanıt sentezleyin. Metinden Konuşmaya (TTS) Yanıtı kullanıcıya oynatın. Bu demoyu uygulamak için tamamen OpenAI'nin bulut modellerine güvendim: , ve . Mükemmel kütüphanesi sayesinde demoyu yalnızca birkaç düzine kod satırıyla oluşturdum. Whisper GPT-4 TTS konuşma_recognition 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ı: . 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. Tepki gecikmesi . 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 ( ) ö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. Ortam gürültüsü bitiş noktası belirleme . 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. Canlı konuşmayı taklit edin . 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 Geri bildirim 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. 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 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. Arduino, , 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. Web kullanıcı arayüzü 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. Arka uç 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 modelini kullandık. Mikrodenetleyici, arka ucu çalıştıran dizüstü bilgisayarla aynı Wi-Fi ağına bağlıydı. ESP32 Kullandığımız donanımların tam listesi: — arkadaşlarımızdan ödünç aldık :) Skype kabini – 29$ ESP32 – 5 Dolar Büyük Kırmızı Düğme – 10 ABD Doları Yakınlık Sensörü Eski Mackbook Air - bizde de vardı. 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, iOS ve macOS için mevcuttur ve tarayıcılar içindir. Apple Speech API, Web Speech API, Maalesef kalite açısından veya göre çok düşüktürler ve dili otomatik olarak algılayamazlar. Whisper Deepgram'a İş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: OpenAI İstemi Mühendislik Kılavuzu Antropik İstem Mühendisliği Hızlı Mühendislik Kılavuzu Modelin ilgi çekici, kısa ve esprili bir şekilde yanıt vermesini sağlamak için istem ve ayarlarıyla kapsamlı denemeler yapmak zorunda kaldık. sıcaklı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. LLM'ye bir sorgu yapın. tam bir cümle elde edene kadar yanıtı arabellek belirtecinde belirteçle biriktiririz. parametresi önemlidir çünkü hem seslendirmenin tonlamasını hem de başlangıçtaki gecikme süresini etkiler. Minimum uzunlukta Minimum uzunluk 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: . 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. LED Göstergeler "Düşüneyim", "Hmm" gibi 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. dolgu sözcükleri Kabine koyun. Ve farklı durumları animasyonlarla görüntüleyin. bir ekran 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 arka uç kaynakları GitHub'da bulunan