52 lines
1.4 KiB
Python
52 lines
1.4 KiB
Python
"""Real-time two-way meeting translation via Gemini Live API.
|
|
|
|
Architecture based on livekit-examples/gemini-live-translate:
|
|
- Each participant sets `lang` attribute
|
|
- Agent opens one Gemini Live session per (speaker, target_lang) pair
|
|
- Publishes audio tracks named tx:{speaker}:{target_lang}
|
|
- Publishes captions on lk.translation text stream
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import logging
|
|
import os
|
|
|
|
from dotenv import load_dotenv
|
|
from livekit.agents import AgentServer, AutoSubscribe, JobContext, cli
|
|
|
|
from gemini.router import TranslationRouter
|
|
|
|
load_dotenv()
|
|
|
|
logger = logging.getLogger("gemini.agent")
|
|
|
|
AGENT_NAME = os.getenv("LIVEKIT_TRANSLATOR_AGENT", "gemini-translator")
|
|
|
|
server = AgentServer()
|
|
|
|
|
|
@server.rtc_session(agent_name=AGENT_NAME)
|
|
async def translator_entrypoint(ctx: JobContext) -> None:
|
|
api_key = os.environ.get("GEMINI_API_KEY")
|
|
if not api_key:
|
|
logger.error("GEMINI_API_KEY is not set; refusing to start")
|
|
return
|
|
|
|
await ctx.connect(auto_subscribe=AutoSubscribe.AUDIO_ONLY)
|
|
|
|
try:
|
|
await ctx.room.local_participant.set_attributes({"lk.agent.state": "listening"})
|
|
except Exception as exc:
|
|
logger.debug("set agent state attr failed: %s", exc)
|
|
|
|
router = TranslationRouter(ctx.room, gemini_api_key=api_key)
|
|
router.start()
|
|
ctx.add_shutdown_callback(router.aclose)
|
|
|
|
logger.info("Gemini translation router ready for room=%s", ctx.room.name)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
cli.run_app(server)
|