voice route updated
This commit is contained in:
parent
259ccabbe3
commit
37aad732f5
7 changed files with 51 additions and 59 deletions
|
|
@ -723,15 +723,16 @@ class ConnectorGoogleSpeech:
|
|||
logger.info("🌐 Getting available languages from Google Cloud TTS")
|
||||
|
||||
# List voices from Google Cloud TTS
|
||||
voices = self.tts_client.list_voices()
|
||||
response = self.tts_client.list_voices()
|
||||
|
||||
# Extract unique language codes
|
||||
# Note: Google TTS API doesn't provide language descriptions, only codes
|
||||
language_codes = set()
|
||||
for voice in voices:
|
||||
for voice in response.voices:
|
||||
if voice.language_codes:
|
||||
language_codes.update(voice.language_codes)
|
||||
|
||||
# Convert to sorted list
|
||||
# Convert to sorted list of language codes
|
||||
available_languages = sorted(list(language_codes))
|
||||
|
||||
logger.info(f"✅ Found {len(available_languages)} available languages")
|
||||
|
|
@ -763,11 +764,11 @@ class ConnectorGoogleSpeech:
|
|||
logger.info(f"🎤 Getting available voices from Google Cloud TTS, language filter: {languageCode}")
|
||||
|
||||
# List voices from Google Cloud TTS
|
||||
voices = self.tts_client.list_voices()
|
||||
response = self.tts_client.list_voices()
|
||||
|
||||
availableVoices = []
|
||||
|
||||
for voice in voices:
|
||||
for voice in response.voices:
|
||||
# Extract language code from voice name (e.g., 'de-DE-Wavenet-A' -> 'de-DE')
|
||||
voiceLanguage = voice.language_codes[0] if voice.language_codes else None
|
||||
|
||||
|
|
@ -783,15 +784,24 @@ class ConnectorGoogleSpeech:
|
|||
elif voice.name.endswith(('-B', '-D')):
|
||||
gender = "Female"
|
||||
|
||||
# Create voice info
|
||||
# Create voice info with all available fields from Google API
|
||||
voiceInfo = {
|
||||
"name": voice.name,
|
||||
"language_code": voiceLanguage,
|
||||
"language_codes": list(voice.language_codes) if voice.language_codes else [],
|
||||
"gender": gender,
|
||||
"ssml_gender": voice.ssml_gender.name if voice.ssml_gender else "NEUTRAL",
|
||||
"natural_sample_rate_hertz": voice.natural_sample_rate_hertz
|
||||
}
|
||||
|
||||
# Include any additional fields if available from Google API
|
||||
# Check for common fields that might exist
|
||||
for field_name in ['description', 'display_name', 'labels']:
|
||||
if hasattr(voice, field_name):
|
||||
field_value = getattr(voice, field_name, None)
|
||||
if field_value:
|
||||
voiceInfo[field_name] = field_value
|
||||
|
||||
availableVoices.append(voiceInfo)
|
||||
|
||||
# Sort by language code, then by gender, then by name
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ import uuid
|
|||
class VoiceSettings(BaseModel):
|
||||
id: str = Field(default_factory=lambda: str(uuid.uuid4()), description="Primary key", frontend_type="text", frontend_readonly=True, frontend_required=False)
|
||||
userId: str = Field(description="ID of the user these settings belong to", frontend_type="text", frontend_readonly=True, frontend_required=True)
|
||||
mandateId: str = Field(description="ID of the mandate these settings belong to", frontend_type="text", frontend_readonly=True, frontend_required=False)
|
||||
mandateId: str = Field(description="ID of the mandate these settings belong to", frontend_type="text", frontend_readonly=True, frontend_required=True)
|
||||
sttLanguage: str = Field(default="de-DE", description="Speech-to-Text language", frontend_type="select", frontend_readonly=False, frontend_required=True)
|
||||
ttsLanguage: str = Field(default="de-DE", description="Text-to-Speech language", frontend_type="select", frontend_readonly=False, frontend_required=True)
|
||||
ttsVoice: str = Field(default="de-DE-KatjaNeural", description="Text-to-Speech voice", frontend_type="select", frontend_readonly=False, frontend_required=True)
|
||||
|
|
|
|||
|
|
@ -268,6 +268,12 @@ class VoiceObjects:
|
|||
try:
|
||||
logger.info(f"Creating voice settings: {settingsData}")
|
||||
|
||||
# Ensure mandateId is set from user context if not provided
|
||||
if "mandateId" not in settingsData or not settingsData["mandateId"]:
|
||||
if not self.currentUser or not self.currentUser.mandateId:
|
||||
raise ValueError("mandateId is required but not provided and user context has no mandateId")
|
||||
settingsData["mandateId"] = self.currentUser.mandateId
|
||||
|
||||
# Add timestamps
|
||||
currentTime = getUtcTimestamp()
|
||||
settingsData["creationDate"] = currentTime
|
||||
|
|
@ -330,6 +336,7 @@ class VoiceObjects:
|
|||
# Create default settings if none exist
|
||||
defaultSettings = {
|
||||
"userId": userId,
|
||||
"mandateId": self.currentUser.mandateId,
|
||||
"sttLanguage": "de-DE",
|
||||
"ttsLanguage": "de-DE",
|
||||
"ttsVoice": "de-DE-Wavenet-A",
|
||||
|
|
|
|||
|
|
@ -87,7 +87,7 @@ class RendererDocx(BaseRenderer):
|
|||
# Process each section in order
|
||||
sections = json_content.get("sections", [])
|
||||
for section in sections:
|
||||
self._render_json_section(doc, section, styles)
|
||||
self._renderJsonSection(doc, section, styles)
|
||||
|
||||
# Save to buffer
|
||||
buffer = io.BytesIO()
|
||||
|
|
|
|||
|
|
@ -96,7 +96,7 @@ class RendererPdf(BaseRenderer):
|
|||
title_style = self._createTitleStyle(styles)
|
||||
story.append(Paragraph(document_title, title_style))
|
||||
story.append(Spacer(1, 50)) # Increased spacing to prevent overlap
|
||||
story.append(Paragraph(f"Generated: {self._format_timestamp()}", self._createNormalStyle(styles)))
|
||||
story.append(Paragraph(f"Generated: {self._formatTimestamp()}", self._createNormalStyle(styles)))
|
||||
story.append(Spacer(1, 30)) # Add spacing before page break
|
||||
story.append(PageBreak())
|
||||
|
||||
|
|
|
|||
|
|
@ -95,9 +95,12 @@ Instructions:
|
|||
- Continue from where it stopped — add NEW items only; do not repeat existing items.
|
||||
- Generate remaining content to complete the user request.
|
||||
- Fill with actual content (no placeholders or instructional text such as "Add more...").
|
||||
- IMPORTANT: Ensure "filename" in each document has meaningful name with appropriate extension matching the content.
|
||||
- When the request is fully satisfied, add "complete_response": true at root level.
|
||||
- Output JSON only; no markdown fences or extra text.
|
||||
|
||||
IMPORTANT: Before responding, analyse the remaining data to fully satisfy user request.
|
||||
|
||||
Continue generating:
|
||||
"""
|
||||
else:
|
||||
|
|
@ -114,6 +117,7 @@ Instructions:
|
|||
- Return ONLY valid JSON (strict). No comments. No trailing commas. Use double quotes.
|
||||
- Do NOT reuse example section IDs; create your own.
|
||||
- Generate complete content based on the user request.
|
||||
- IMPORTANT: Set a meaningful "filename" in each document with appropriate file extension (e.g., "prime_numbers.txt", "report.docx", "data.json"). The filename should reflect the content and task objective.
|
||||
- When the request is fully satisfied, add "complete_response": true at root level.
|
||||
- Output JSON only; no markdown fences or extra text.
|
||||
|
||||
|
|
|
|||
|
|
@ -83,10 +83,12 @@ class ContentValidator:
|
|||
availableModels = modelRegistry.getAvailableModels()
|
||||
|
||||
# Create options for PLAN operation (what validation uses)
|
||||
# Use default values for priority and processingMode (will use defaults from AiCallOptions)
|
||||
from modules.datamodels.datamodelAi import PriorityEnum, ProcessingModeEnum
|
||||
options = AiCallOptions(
|
||||
operationType=OperationTypeEnum.PLAN,
|
||||
priority=None,
|
||||
processingMode=None
|
||||
priority=PriorityEnum.BALANCED,
|
||||
processingMode=ProcessingModeEnum.BASIC
|
||||
)
|
||||
|
||||
# Get failover model list to find the model that will be used
|
||||
|
|
@ -118,60 +120,28 @@ class ContentValidator:
|
|||
return 8 * 1024
|
||||
|
||||
def _analyzeDocumentsWithSizeLimit(self, documents: List[Any], maxTotalBytes: int) -> List[Dict[str, Any]]:
|
||||
"""Analyze documents with size limit, dividing available space evenly among documents."""
|
||||
"""
|
||||
Analyze documents for validation - METADATA ONLY (no document content/previews).
|
||||
For planning/validation, we only need metadata to assess format, type, and size compatibility.
|
||||
"""
|
||||
if not documents:
|
||||
return []
|
||||
|
||||
# Reserve space for JSON structure overhead (approximately 200 bytes per document)
|
||||
jsonOverheadPerDoc = 200
|
||||
reservedOverhead = len(documents) * jsonOverheadPerDoc
|
||||
availableForContent = max(0, maxTotalBytes - reservedOverhead)
|
||||
|
||||
# Divide available space evenly among documents
|
||||
bytesPerDoc = availableForContent // len(documents) if documents else 0
|
||||
# Ensure minimum space per document (at least 100 bytes)
|
||||
bytesPerDoc = max(bytesPerDoc, 100)
|
||||
|
||||
logger.debug(f"Document summary space: total={maxTotalBytes} bytes, available={availableForContent} bytes, perDoc={bytesPerDoc} bytes")
|
||||
|
||||
summaries = []
|
||||
for doc in documents:
|
||||
try:
|
||||
data = getattr(doc, 'documentData', None)
|
||||
name = getattr(doc, 'documentName', 'Unknown')
|
||||
mimeType = getattr(doc, 'mimeType', 'unknown')
|
||||
formatExt = self._detectFormat(doc)
|
||||
sizeInfo = self._calculateSize(doc)
|
||||
|
||||
# Create preview with size limit
|
||||
preview = None
|
||||
if data is not None:
|
||||
if isinstance(data, (dict, list)):
|
||||
preview = json.dumps(data, indent=2, ensure_ascii=False)
|
||||
else:
|
||||
preview = str(data)
|
||||
|
||||
# Truncate preview to fit within bytesPerDoc (accounting for JSON structure)
|
||||
# Estimate: preview takes ~70% of document summary space
|
||||
maxPreviewBytes = int(bytesPerDoc * 0.7)
|
||||
previewBytes = len(preview.encode('utf-8'))
|
||||
|
||||
if previewBytes > maxPreviewBytes:
|
||||
# Truncate to fit
|
||||
truncated = preview.encode('utf-8')[:maxPreviewBytes]
|
||||
# Try to decode safely
|
||||
try:
|
||||
preview = truncated.decode('utf-8', errors='ignore')
|
||||
except:
|
||||
preview = truncated[:maxPreviewBytes-50].decode('utf-8', errors='ignore')
|
||||
preview += f"\n\n[Truncated - {self._formatBytes(sizeInfo['bytes'])} total]"
|
||||
|
||||
# Only include metadata - NO document content/previews
|
||||
# This keeps prompts small and focused on validation criteria
|
||||
summary = {
|
||||
"name": name,
|
||||
"mimeType": mimeType,
|
||||
"format": formatExt,
|
||||
"size": sizeInfo["readable"],
|
||||
"preview": preview
|
||||
"size": sizeInfo["readable"]
|
||||
}
|
||||
summaries.append(summary)
|
||||
except Exception as e:
|
||||
|
|
@ -181,7 +151,6 @@ class ContentValidator:
|
|||
"mimeType": getattr(doc, 'mimeType', 'unknown'),
|
||||
"format": "unknown",
|
||||
"size": "0 B",
|
||||
"preview": None,
|
||||
"error": str(e)
|
||||
})
|
||||
|
||||
|
|
@ -291,12 +260,14 @@ EXPECTED FORMAT: {intent.get('expectedFormat', 'unknown')}
|
|||
SUCCESS CRITERIA ({criteriaCount} items): {successCriteria}
|
||||
|
||||
VALIDATION RULES:
|
||||
1. Check if delivered documents match expected data type
|
||||
IMPORTANT: You only have document METADATA (filename, format, size, mimeType) - NOT document content.
|
||||
Validate based on metadata only:
|
||||
1. Check if filenames are meaningful and match approximately the task objective
|
||||
2. Check if delivered formats are compatible with expected format
|
||||
3. Verify each success criterion is met based on document content/metadata
|
||||
4. Check document sizes are reasonable for the task
|
||||
5. Rate overall quality (0.0-1.0)
|
||||
6. Identify specific gaps based on what the user requested
|
||||
3. Check if document sizes are reasonable for the task objective
|
||||
4. Assess if filename and size combination suggests correct data type
|
||||
5. Rate overall quality (0.0-1.0) based on metadata indicators
|
||||
6. Identify specific gaps based on what the user requested (infer from filename, size, format - NOT content)
|
||||
|
||||
OUTPUT FORMAT - JSON ONLY (no prose):
|
||||
{{
|
||||
|
|
@ -306,13 +277,13 @@ OUTPUT FORMAT - JSON ONLY (no prose):
|
|||
"formatMatch": false,
|
||||
"documentCount": {len(documents)},
|
||||
"successCriteriaMet": {[False] * criteriaCount},
|
||||
"gapAnalysis": "Describe what is missing or incorrect",
|
||||
"gapAnalysis": "Describe what is missing or incorrect based on filename, size, format metadata",
|
||||
"improvementSuggestions": ["General action to improve overall result"],
|
||||
"validationDetails": [
|
||||
{{
|
||||
"documentName": "document.ext",
|
||||
"issues": ["Specific problem with this document"],
|
||||
"suggestions": ["Specific fix for this document's issues"]
|
||||
"issues": ["Issue inferred from metadata (e.g., filename doesn't match task, size too small for objective)"],
|
||||
"suggestions": ["Specific fix based on metadata analysis"]
|
||||
}}
|
||||
]
|
||||
}}
|
||||
|
|
|
|||
Loading…
Reference in a new issue