fix(teamsbot): Fix Invalid Date + pass language to browser bot
- Add getIsoTimestamp() to timeUtils for JS-compatible ISO 8601 strings - Replace getUtcTimestamp() (epoch float) with getIsoTimestamp() for all teamsbot session/transcript/response timestamp fields (startedAt, endedAt, creationDate, lastModified, SSE event timestamps) - Pass config.language to browser bot in join request for captions spoken language Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
parent
294f1a001c
commit
5d987e72fe
4 changed files with 32 additions and 15 deletions
|
|
@ -35,6 +35,7 @@ class BrowserBotConnector:
|
|||
botName: str,
|
||||
instanceId: str,
|
||||
gatewayWsUrl: str,
|
||||
language: str = "de-DE",
|
||||
) -> Dict[str, Any]:
|
||||
"""
|
||||
Send join command to the Browser Bot service.
|
||||
|
|
@ -49,6 +50,7 @@ class BrowserBotConnector:
|
|||
Args:
|
||||
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 (e.g. "de-DE", "en-US")
|
||||
|
||||
Returns:
|
||||
Dict with 'success' bool and optional 'error' string.
|
||||
|
|
@ -66,6 +68,7 @@ class BrowserBotConnector:
|
|||
"botName": botName,
|
||||
"instanceId": instanceId,
|
||||
"gatewayWsUrl": gatewayWsUrl, # Full WebSocket URL for bot to connect back
|
||||
"language": language, # Spoken language for Teams captions
|
||||
}
|
||||
|
||||
try:
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ from typing import Dict, Any, List, Optional
|
|||
|
||||
from modules.datamodels.datamodelUam import User
|
||||
from modules.connectors.connectorDbPostgre import DatabaseConnector
|
||||
from modules.shared.timeUtils import getUtcTimestamp
|
||||
from modules.shared.timeUtils import getIsoTimestamp
|
||||
from modules.shared.configuration import APP_CONFIG
|
||||
|
||||
from .datamodelTeamsbot import (
|
||||
|
|
@ -98,13 +98,13 @@ class TeamsbotObjects:
|
|||
|
||||
def createSession(self, sessionData: Dict[str, Any]) -> Dict[str, Any]:
|
||||
"""Create a new session."""
|
||||
sessionData["creationDate"] = getUtcTimestamp()
|
||||
sessionData["lastModified"] = getUtcTimestamp()
|
||||
sessionData["creationDate"] = getIsoTimestamp()
|
||||
sessionData["lastModified"] = getIsoTimestamp()
|
||||
return self.db.recordCreate(TeamsbotSession, sessionData)
|
||||
|
||||
def updateSession(self, sessionId: str, updates: Dict[str, Any]) -> Optional[Dict[str, Any]]:
|
||||
"""Update session fields."""
|
||||
updates["lastModified"] = getUtcTimestamp()
|
||||
updates["lastModified"] = getIsoTimestamp()
|
||||
return self.db.recordModify(TeamsbotSession, sessionId, updates)
|
||||
|
||||
def deleteSession(self, sessionId: str) -> bool:
|
||||
|
|
@ -143,7 +143,7 @@ class TeamsbotObjects:
|
|||
|
||||
def createTranscript(self, transcriptData: Dict[str, Any]) -> Dict[str, Any]:
|
||||
"""Create a new transcript segment."""
|
||||
transcriptData["creationDate"] = getUtcTimestamp()
|
||||
transcriptData["creationDate"] = getIsoTimestamp()
|
||||
return self.db.recordCreate(TeamsbotTranscript, transcriptData)
|
||||
|
||||
def _deleteTranscriptsBySession(self, sessionId: str) -> int:
|
||||
|
|
@ -170,7 +170,7 @@ class TeamsbotObjects:
|
|||
|
||||
def createBotResponse(self, responseData: Dict[str, Any]) -> Dict[str, Any]:
|
||||
"""Create a new bot response record."""
|
||||
responseData["creationDate"] = getUtcTimestamp()
|
||||
responseData["creationDate"] = getIsoTimestamp()
|
||||
return self.db.recordCreate(TeamsbotBotResponse, responseData)
|
||||
|
||||
def _deleteResponsesBySession(self, sessionId: str) -> int:
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ from fastapi import WebSocket
|
|||
|
||||
from modules.datamodels.datamodelUam import User
|
||||
from modules.datamodels.datamodelAi import AiCallRequest, AiCallOptions, OperationTypeEnum, PriorityEnum
|
||||
from modules.shared.timeUtils import getUtcTimestamp
|
||||
from modules.shared.timeUtils import getUtcTimestamp, getIsoTimestamp
|
||||
|
||||
from .datamodelTeamsbot import (
|
||||
TeamsbotSessionStatus,
|
||||
|
|
@ -57,7 +57,7 @@ async def _emitSessionEvent(sessionId: str, eventType: str, data: Any):
|
|||
"""Emit an event to the session's SSE stream."""
|
||||
eventQueue = _sessionEvents.get(sessionId)
|
||||
if eventQueue:
|
||||
await eventQueue.put({"type": eventType, "data": data, "timestamp": getUtcTimestamp()})
|
||||
await eventQueue.put({"type": eventType, "data": data, "timestamp": getIsoTimestamp()})
|
||||
|
||||
|
||||
class TeamsbotService:
|
||||
|
|
@ -126,6 +126,7 @@ class TeamsbotService:
|
|||
botName=session.get("botName", self.config.botName),
|
||||
instanceId=self.instanceId,
|
||||
gatewayWsUrl=fullGatewayWsUrl,
|
||||
language=self.config.language,
|
||||
)
|
||||
|
||||
if result.get("success"):
|
||||
|
|
@ -164,7 +165,7 @@ class TeamsbotService:
|
|||
|
||||
interface.updateSession(sessionId, {
|
||||
"status": TeamsbotSessionStatus.ENDED.value,
|
||||
"endedAt": getUtcTimestamp(),
|
||||
"endedAt": getIsoTimestamp(),
|
||||
})
|
||||
await _emitSessionEvent(sessionId, "statusChange", {"status": "ended"})
|
||||
|
||||
|
|
@ -178,7 +179,7 @@ class TeamsbotService:
|
|||
interface.updateSession(sessionId, {
|
||||
"status": TeamsbotSessionStatus.ERROR.value,
|
||||
"errorMessage": str(e),
|
||||
"endedAt": getUtcTimestamp(),
|
||||
"endedAt": getIsoTimestamp(),
|
||||
})
|
||||
|
||||
# Cleanup event queue
|
||||
|
|
@ -269,9 +270,9 @@ class TeamsbotService:
|
|||
if errorMessage:
|
||||
updates["errorMessage"] = errorMessage
|
||||
if dbStatus == TeamsbotSessionStatus.ACTIVE.value:
|
||||
updates["startedAt"] = getUtcTimestamp()
|
||||
updates["startedAt"] = getIsoTimestamp()
|
||||
elif dbStatus in [TeamsbotSessionStatus.ENDED.value, TeamsbotSessionStatus.ERROR.value]:
|
||||
updates["endedAt"] = getUtcTimestamp()
|
||||
updates["endedAt"] = getIsoTimestamp()
|
||||
|
||||
interface.updateSession(sessionId, updates)
|
||||
await _emitSessionEvent(sessionId, "statusChange", {"status": status, "errorMessage": errorMessage})
|
||||
|
|
@ -301,7 +302,7 @@ class TeamsbotService:
|
|||
sessionId=sessionId,
|
||||
speaker=speaker,
|
||||
text=text,
|
||||
timestamp=str(getUtcTimestamp()),
|
||||
timestamp=getIsoTimestamp(),
|
||||
confidence=1.0, # Captions don't have confidence scores
|
||||
language=self.config.language,
|
||||
isFinal=isFinal,
|
||||
|
|
@ -326,7 +327,7 @@ class TeamsbotService:
|
|||
"speaker": speaker,
|
||||
"text": text,
|
||||
"confidence": 1.0,
|
||||
"timestamp": getUtcTimestamp(),
|
||||
"timestamp": getIsoTimestamp(),
|
||||
})
|
||||
|
||||
# Update session transcript count
|
||||
|
|
@ -499,7 +500,7 @@ class TeamsbotService:
|
|||
modelName=response.modelName,
|
||||
processingTime=response.processingTime,
|
||||
priceCHF=response.priceCHF,
|
||||
timestamp=str(getUtcTimestamp()),
|
||||
timestamp=getIsoTimestamp(),
|
||||
).model_dump()
|
||||
|
||||
createdResponse = interface.createBotResponse(botResponseData)
|
||||
|
|
|
|||
|
|
@ -31,6 +31,19 @@ def getUtcTimestamp() -> float:
|
|||
"""
|
||||
return time.time()
|
||||
|
||||
def getIsoTimestamp() -> str:
|
||||
"""
|
||||
Get current UTC timestamp as ISO 8601 string.
|
||||
|
||||
Use this for fields declared as 'ISO timestamp' strings (e.g. Pydantic str fields
|
||||
that will be parsed by JavaScript's new Date()). JavaScript cannot parse epoch
|
||||
floats from getUtcTimestamp() as dates.
|
||||
|
||||
Returns:
|
||||
str: Current UTC time in ISO 8601 format (e.g. "2026-02-15T00:08:32.070000+00:00")
|
||||
"""
|
||||
return datetime.now(timezone.utc).isoformat()
|
||||
|
||||
def createExpirationTimestamp(expiresInSeconds: int) -> float:
|
||||
"""
|
||||
Create a new expiration timestamp from seconds until expiration.
|
||||
|
|
|
|||
Loading…
Reference in a new issue