feat(teamsbot): dedicated bot account support with authenticated join
- New config fields: botAccountEmail, botAccountPassword for dedicated MSFT account - BrowserBotConnector passes credentials + backgroundImageUrl to bot service - Service passes config credentials to connector in joinMeeting - Enables: full language settings, virtual background, no lobby wait - Fallback: anonymous join when no bot account configured Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
parent
91425809c3
commit
ad5c9d10cd
3 changed files with 28 additions and 6 deletions
|
|
@ -36,21 +36,26 @@ class BrowserBotConnector:
|
||||||
instanceId: str,
|
instanceId: str,
|
||||||
gatewayWsUrl: str,
|
gatewayWsUrl: str,
|
||||||
language: str = "de-DE",
|
language: str = "de-DE",
|
||||||
|
botAccountEmail: Optional[str] = None,
|
||||||
|
botAccountPassword: Optional[str] = None,
|
||||||
|
backgroundImageUrl: Optional[str] = None,
|
||||||
) -> Dict[str, Any]:
|
) -> Dict[str, Any]:
|
||||||
"""
|
"""
|
||||||
Send join command to the Browser Bot service.
|
Send join command to the Browser Bot service.
|
||||||
|
|
||||||
The bot will:
|
The bot will:
|
||||||
1. Launch a headless browser
|
1. Launch a headless browser
|
||||||
2. Navigate to Teams web app
|
2. If botAccountEmail/Password provided: authenticate with Microsoft first
|
||||||
3. Join the meeting
|
3. Navigate to Teams web app and join the meeting
|
||||||
4. Enable captions and start scraping
|
4. Enable captions and start scraping
|
||||||
5. Connect back to Gateway via WebSocket using gatewayWsUrl
|
5. Connect back to Gateway via WebSocket using gatewayWsUrl
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
gatewayWsUrl: Full WebSocket URL for the bot to connect back to
|
gatewayWsUrl: Full WebSocket URL for the bot to connect back to
|
||||||
(e.g. wss://gateway-int.poweron-center.net/api/teamsbot/{instanceId}/bot/ws/{sessionId})
|
language: BCP-47 language code for captions spoken language
|
||||||
language: BCP-47 language code for captions spoken language (e.g. "de-DE", "en-US")
|
botAccountEmail: Microsoft account email for authenticated join (None = anonymous)
|
||||||
|
botAccountPassword: Microsoft account password
|
||||||
|
backgroundImageUrl: URL to background image for virtual background
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
Dict with 'success' bool and optional 'error' string.
|
Dict with 'success' bool and optional 'error' string.
|
||||||
|
|
@ -67,10 +72,20 @@ class BrowserBotConnector:
|
||||||
"meetingUrl": meetingUrl,
|
"meetingUrl": meetingUrl,
|
||||||
"botName": botName,
|
"botName": botName,
|
||||||
"instanceId": instanceId,
|
"instanceId": instanceId,
|
||||||
"gatewayWsUrl": gatewayWsUrl, # Full WebSocket URL for bot to connect back
|
"gatewayWsUrl": gatewayWsUrl,
|
||||||
"language": language, # Spoken language for Teams captions
|
"language": language,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Add authenticated join credentials if configured
|
||||||
|
if botAccountEmail and botAccountPassword:
|
||||||
|
payload["botAccountEmail"] = botAccountEmail
|
||||||
|
payload["botAccountPassword"] = botAccountPassword
|
||||||
|
logger.info(f"Bot will join authenticated as {botAccountEmail}")
|
||||||
|
|
||||||
|
# Add background image if configured
|
||||||
|
if backgroundImageUrl:
|
||||||
|
payload["backgroundImageUrl"] = backgroundImageUrl
|
||||||
|
|
||||||
try:
|
try:
|
||||||
async with aiohttp.ClientSession(timeout=_BOT_TIMEOUT) as session:
|
async with aiohttp.ClientSession(timeout=_BOT_TIMEOUT) as session:
|
||||||
async with session.post(f"{self.botUrl}/api/bot", json=payload) as resp:
|
async with session.post(f"{self.botUrl}/api/bot", json=payload) as resp:
|
||||||
|
|
|
||||||
|
|
@ -117,6 +117,8 @@ class TeamsbotConfig(BaseModel):
|
||||||
language: str = Field(default="de-DE", description="Primary language for STT/TTS")
|
language: str = Field(default="de-DE", description="Primary language for STT/TTS")
|
||||||
voiceId: Optional[str] = Field(default=None, description="Google TTS voice ID (e.g., de-DE-Standard-A)")
|
voiceId: Optional[str] = Field(default=None, description="Google TTS voice ID (e.g., de-DE-Standard-A)")
|
||||||
browserBotUrl: Optional[str] = Field(default=None, description="URL of the Browser Bot service. Falls back to TEAMSBOT_BROWSER_BOT_URL env variable if not set per-instance.")
|
browserBotUrl: Optional[str] = Field(default=None, description="URL of the Browser Bot service. Falls back to TEAMSBOT_BROWSER_BOT_URL env variable if not set per-instance.")
|
||||||
|
botAccountEmail: Optional[str] = Field(default=None, description="Dedicated Microsoft account email for authenticated bot join. Leave empty for anonymous join.")
|
||||||
|
botAccountPassword: Optional[str] = Field(default=None, description="Dedicated Microsoft account password. MFA must be disabled for this account.")
|
||||||
triggerIntervalSeconds: int = Field(default=10, ge=3, le=60, description="Seconds between periodic AI analysis triggers")
|
triggerIntervalSeconds: int = Field(default=10, ge=3, le=60, description="Seconds between periodic AI analysis triggers")
|
||||||
triggerCooldownSeconds: int = Field(default=3, ge=1, le=30, description="Minimum seconds between AI calls")
|
triggerCooldownSeconds: int = Field(default=3, ge=1, le=30, description="Minimum seconds between AI calls")
|
||||||
contextWindowSegments: int = Field(default=20, ge=5, le=100, description="Number of transcript segments to include in AI context")
|
contextWindowSegments: int = Field(default=20, ge=5, le=100, description="Number of transcript segments to include in AI context")
|
||||||
|
|
@ -157,6 +159,8 @@ class TeamsbotConfigUpdateRequest(BaseModel):
|
||||||
language: Optional[str] = None
|
language: Optional[str] = None
|
||||||
voiceId: Optional[str] = None
|
voiceId: Optional[str] = None
|
||||||
browserBotUrl: Optional[str] = None
|
browserBotUrl: Optional[str] = None
|
||||||
|
botAccountEmail: Optional[str] = None
|
||||||
|
botAccountPassword: Optional[str] = None
|
||||||
triggerIntervalSeconds: Optional[int] = None
|
triggerIntervalSeconds: Optional[int] = None
|
||||||
triggerCooldownSeconds: Optional[int] = None
|
triggerCooldownSeconds: Optional[int] = None
|
||||||
contextWindowSegments: Optional[int] = None
|
contextWindowSegments: Optional[int] = None
|
||||||
|
|
|
||||||
|
|
@ -127,6 +127,9 @@ class TeamsbotService:
|
||||||
instanceId=self.instanceId,
|
instanceId=self.instanceId,
|
||||||
gatewayWsUrl=fullGatewayWsUrl,
|
gatewayWsUrl=fullGatewayWsUrl,
|
||||||
language=self.config.language,
|
language=self.config.language,
|
||||||
|
botAccountEmail=self.config.botAccountEmail,
|
||||||
|
botAccountPassword=self.config.botAccountPassword,
|
||||||
|
backgroundImageUrl=session.get("backgroundImageUrl") or self.config.backgroundImageUrl,
|
||||||
)
|
)
|
||||||
|
|
||||||
if result.get("success"):
|
if result.get("success"):
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue