Selam, Gemini Live/Realtime API kullanıyorum. Fun...
# ask-ai
a
Selam, Gemini Live/Realtime API kullanıyorum. Function tool içinde generate_reply ile bazen seslendirmeye ihtiyacım duyuyor. Şöyle bir sorun ile karşılaşıyorum. Function tool içinde description'a ve docstring'e kadar söyleyeceği şeyi parametre olarak tool'a geç generate_reply ile ben okutayım desem de. İlk önce kendisi okutuyor tool'a girmeden tool'a girdiğinde ben tekrar okutuyorum. Bu da aynı şeyi 2 kere seslendirmek oluyor kullanıcı tarafında hoş karşılanmıyor. Sanırım belki de function tool'u tam olarak doğru kullanımını bilmiyorum.
t
Thanks for reaching out, İbrahim. I'm an AI assistant and I'm here to help. Give me a moment while I research this topic.
Selam — paylaştığın sorun için teşekkürler. Anladığım kadarıyla Gemini Live/Realtime API ile
function_tool
kullanırken modelin kendi otomatik yanıtı ile senin
generate_reply
çağrın aynı içeriği iki kere seslendiriyor; bu da kullanıcı tarafında çift seslendirme olarak duyuluyor. Doğru anladıysam, aşağıda bunu çözmek için pratik ve uygulanabilir seçenekler var. Kısa açıklama (ne oluyor) • LLM,
function_tool
çağrıldığında bir yanıt üretip (ve TTS ile) bunu söyleyebiliyor. • Sonra sen
context.session.generate_reply(...)
ile tekrar aynı veya benzer metni gönderirsen, kullanıcı iki kere duyuyor. • Çözüm: LLM’in ürettiği yanıt ile senin
generate_reply
kullanımının çakışmasını önlemek. Ne yapabilirsin (seçenekler) • 1) Sadece LLM’nin otomatik yanıtını kullan (en temiz çözüm) ◦
function_tool
tanımındaki
description
ve docstring’i, modelin tek seferde kullanıcıya söylemesini istediğin şekilde açık ve kısaca yaz. ◦ Fonksiyon içinde
generate_reply
çağırma. Böylece model tek yanıt üretir, çift seslenme olmaz. • 2)
generate_reply
kullanman zorunluysa: LLM’in otomatik mesajından farklı, tamamlayıcı bir metin ver ◦ İlk yanıt zaten yapıldıysa,
generate_reply
ile yalnızca ek bilgi, takip sorusu veya farklı bir ton ver. Aynı cümleyi tekrar etme. ◦ Örnek: LLM otomatik olarak “Bildirim gönderildi” dedi ise,
generate_reply
ile “Başka bir şey ister misiniz?” gibi farklı bir içerik gönder. • 3) Fonksiyondan dönüş şeklini düzenle ◦ Fonksiyon
None
döndürmeyi deneyebilirsin ve tüm kullanıcıya konuşmayı sadece
generate_reply
ile yapabilirsin. Not: bu her durumda kesin sonuç vermez; model davranışı değişken olabilir. ◦ Alternatif olarak return şeklini minimal tutup konuşmayı sadece tek noktada tetikle. Pratik kod önerileri (kısa) 1) LLM yanıtına güvenip yalnızca tool kullanma:
Copy code
@function_tool()
async def send_notification(context: RunContext, message: str):
    """Kullanıcıya dostça bildir: 'Bildirim gönderildi, telefonunuza ulaştı.'"""
    await send_push(message)
    return {"status": "sent"}
# Not: burada generate_reply çağırma
2)
generate_reply
kullanacaksan farklı bir mesaj gönder:
Copy code
@function_tool()
async def check_service(context: RunContext, service: str):
    available = await db.check(service)
    if not available:
        # LLM'in otomatik yanıtı muhtemelen "Servis kapalı" diyecek; burası ek bilgi olsun:
        await context.session.generate_reply(instructions="İstersen ben seni bilgilendiririm, nasıl devam edelim?")
    return {"available": available}
Neye ihtiyacım var: sende görmek istediğim bilgi (kısa list) • Mevcut tool tanımının (description/docstring) kısa bir örneği — anonimleştirerek paylaşabilirsin. • Fonksiyonun içinde şu an
generate_reply
çağrıyor musun? Varsa onu göster. • Hangi durumlarda çift seslenme oluyor: her çağrıda mı yoksa sadece belirli akışlarda mı? Son olarak • Temel kural: tool açıklamasını, LLM’in tek seferde söylemesini istediğin şekilde yaz;
generate_reply
yalnızca tamamlayıcı/şartlı durumlarda kullan. • Eğer kod parçanı paylaşırsan (anonimleştirerek), hangi satırların çakıştığını tespit edip doğrudan düzenlenmiş bir örnek gönderebilirim. İstersen önce fonksiyonun description ve generate_reply çağrısının kısa bir örneğini paylaş; ona göre en uygun düzenlemeyi gösteririm. Sources: Turns overview | LiveKit Documentation | Gemini Live API plugin | LiveKit Documentation | Tool definition and use | LiveKit Documentation
a
1) Sadece LLM’nin otomatik yanıtını kullan (en temiz çözüm) ◦
function_tool
tanımındaki
description
ve docstring’i, modelin tek seferde kullanıcıya söylemesini istediğin şekilde açık ve kısaca yaz. ◦ Fonksiyon içinde
generate_reply
çağırma. Böylece model tek yanıt üretir, çift seslenme olmaz. Burada ama dinamik olarak api'dan geliyor bana söylemesini istediğim şeyler.
t
Haklısın — dinamik olarak API’den gelen metinler farklı bir durum yaratıyor. Buna göre iki pratik yaklaşım önerebilirim. Hangi yolun uygun olacağını belirlemek için küçük bir kod örneği (anonimleştirilmiş) paylaşırsan daha kesin öneri veririm. Şimdilik aşağıdaki seçenekler işine yarayabilir. 1) LLM’in otomatik yanıtını dinamik metinle beslemek (tercih edilen, çifte seslenme olmaz) • Tool’un
description
veya docstring’ini sabit ve yönlendirici tut; ama gerçek okunacak metni fonksiyondan döndür ve LLM’in bunu kullanıcıya söylemesini sağla. • Uygulama akışı: a. Kullanıcı bir istekte bulunur. b. LLM `function_tool`’u çağırır. c. Fonksiyon API’den dinamik metni alır ve sonucu return eder (ör.
{"speak_text": "...dinamik metin..."}
). d. Model, fonksiyon dönüşünü temel alarak tek bir yanıt üretir ve TTS bunu seslendirir. • Önemli: Fonksiyon içinde
generate_reply
çağırma; sadece fonksiyonun döndürdüğü değeri kullan. Kısa örnek akış (konsept):
Copy code
@function_tool()
async def fetch_dynamic_text(context: RunContext, key: str):
    """Gelen anahtar için API'den okunacak metni getir. Model bu metni kullanarak kullanıcıya tek seferde söylesin."""
    text = await call_external_api(key)  # dinamik metin
    return {"speak_text": text}
Model bu dönüşü alıp doğrudan kullanıcıya söyler — böylece ekstra
generate_reply
çağrısı olmaz. 2) Eğer model fonksiyon dönüşünden otomatik olarak okunmuyor veya kontrol gerekiyorsa: dönüşü işleyip yalnızca gerektiğinde konuşmayı tetikle • Fonksiyon
speak_text
döndürsün, ama LLM her zaman otomatik okumuyorsa, sadece fonksiyonun içinde değil, üst akışta (session yönetiminde) tek bir
generate_reply
çağrısı yap: ◦ Fonksiyon: API’den metni alır ve kaydeder/return eder. ◦ Session/handler: Fonksiyon dönüşünü aldıktan sonra tek seferde
context.session.generate_reply(instructions=returned_text)
çalıştır. • Böylece konuşmayı tamamen sen kontrol edersin ve çift tetikleme olmaz. 3) Eğer LLM otomatik yanıt + senin generate_reply birlikte çalışıyor ve model yine de çakışma yapıyorsa • Fonksiyonu minimal hale getir: fonksiyon sadece veriyi kaydetsin veya arka işlemi yapsın ve konuşma tamamen tek noktadan (session handler) gelsin. • Yani LLM’in otomatik konuşmasını “boş” bırakmak için fonksiyon dönüşünü öyle ayarla ki model konuşmasın; sonra sen session üzerinden tek reply üret. Hangi bilgileri paylaşırsan daha iyi yardımcı olurum • Fonksiyon tanımının (description + return yapısı) kısa bir örneği (anonimleştirilmiş). • Dinamik metni nasıl çektiğin (API çağrısı kodu veya dönüş yapısı). • Şu an fonksiyon içinde
generate_reply
çağırıyor musun yoksa model otomatik mi konuşuyor — hangisiyle çakışma oluşuyor. İstersen ilk olarak anonim bir örnek paylaş; ben de ona göre doğrudan düzenlenmiş bir kod/mimari önerisi ve kısa patch gönderirim.
a
@function_tool( name="end_call", description=( "Telefon görüşmesini sonlandırır ve çağrıyı kapatır. " "ÖNEMLİ: Bu aracı çağırmadan ÖNCE hiçbir veda cümlesi kurma! " "Vedalaşma mesajını SADECE 'closing_message' parametresine yaz." ), ) async def end_call(context: RunContext, closing_message: str) -> str: """Telefon görüşmesini sonlandır ve çağrıyı kapat. Kullanıcı 'hoşça kal', 'görüşürüz', 'kapat', 'bitir' gibi ifadeler kullandığında veya konuşma doğal olarak sonlandığında bu fonksiyonu çağır. Args: closing_message: Görüşmeyi kapatırken söylenecek veda/kapanış mesajı. Örneğin: "Yardımcı olabildiysem ne mutlu, iyi günler dilerim!" Returns: Görüşmeyi sonlandırma mesajı """ ctx = get_job_context() session = context.session logger.info(f"📴 Ending call - room: {ctx.room.name}, message: {closing_message}") # Önce mevcut konuşmayı kes, sonra kapanış mesajını oku ve bitmesini bekle session.interrupt() handle = await session.generate_reply( instructions=f'Şu metni kullanıcıya aynen söyle, hiçbir değişiklik yapma, hiçbir şey ekleme: "{closing_message}"', allow_interruptions=False, ) await handle.wait_for_playout() # Mark call as agent-ended for reporting. current_agent = getattr(session, "current_agent", None) if current_agent: session_report = getattr(current_agent, "_session_report_service", None) if session_report: session_report.set_ended_by("agent") await hangup(ctx) return closing_message Mesela yukarıdaki tool. LLM tool'u çalıştırmadan önce de bitiş mesajını söyleyebiliyor aslında bunu istemiyorum.
t
I don't have the answer you're looking for. You could also try asking your question: • in one of the other Slack channels or • to https://deepwiki.com/livekit/livekit_composite which is trained on all LiveKit source code If you find the answer, please post it here to help others!