Spaces:
Runtime error
Runtime error
Adjust audio status timing before waveform is ready
Browse files- .gitignore +10 -1
- app.py +61 -7
.gitignore
CHANGED
|
@@ -1,3 +1,12 @@
|
|
|
|
|
|
|
|
| 1 |
__pycache__/
|
| 2 |
-
*.py[cod]
|
| 3 |
*.pyo
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
.venv/
|
| 2 |
+
.npm-cache/
|
| 3 |
__pycache__/
|
|
|
|
| 4 |
*.pyo
|
| 5 |
+
*.pyd
|
| 6 |
+
*.py[cod]
|
| 7 |
+
*.log
|
| 8 |
+
debug.log
|
| 9 |
+
sample.wav
|
| 10 |
+
mock_server.py
|
| 11 |
+
rumik-ai-5c44dbeec1e3.json
|
| 12 |
+
*.pyc
|
app.py
CHANGED
|
@@ -2,6 +2,7 @@ import datetime as dt
|
|
| 2 |
import json
|
| 3 |
import os
|
| 4 |
import tempfile
|
|
|
|
| 5 |
from pathlib import Path
|
| 6 |
from typing import Any, Dict, Iterator, List, Optional, Tuple
|
| 7 |
import uuid
|
|
@@ -17,6 +18,7 @@ import requests
|
|
| 17 |
from pymongo import MongoClient
|
| 18 |
from pymongo.collection import Collection
|
| 19 |
from pymongo.errors import PyMongoError
|
|
|
|
| 20 |
|
| 21 |
|
| 22 |
MONGODB_URI = os.environ.get("MONGODB_URI")
|
|
@@ -26,6 +28,29 @@ USERS_COLLECTION_NAME = os.environ.get("MONGODB_USERS_COLLECTION", "users")
|
|
| 26 |
DEFAULT_LIMIT = int(os.environ.get("CALL_DASHBOARD_LIMIT", "50"))
|
| 27 |
SIGNED_URL_EXPIRY_MINUTES = int(os.environ.get("SIGNED_URL_EXPIRY_MINUTES", "60"))
|
| 28 |
FALLBACK_BUCKET_NAME = os.environ.get("GCS_BUCKET_NAME")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 29 |
|
| 30 |
|
| 31 |
if not MONGODB_URI:
|
|
@@ -475,11 +500,13 @@ def on_select(
|
|
| 475 |
selection_tracker,
|
| 476 |
)
|
| 477 |
|
|
|
|
| 478 |
if bucket_name and blob_name and signed_url:
|
| 479 |
cached_path = _AUDIO_CACHE.get(call_id)
|
| 480 |
if cached_path and Path(cached_path).exists():
|
| 481 |
audio_path = cached_path
|
| 482 |
audio_status = "Ready (loaded from cache) — press Play to listen."
|
|
|
|
| 483 |
else:
|
| 484 |
try:
|
| 485 |
audio_path = _download_audio(call_id, signed_url, blob_name)
|
|
@@ -496,18 +523,43 @@ def on_select(
|
|
| 496 |
else:
|
| 497 |
audio_status = "Recording unavailable"
|
| 498 |
|
| 499 |
-
summary_md = "".join(_build_summary_lines(call, topics, audio_status, signed_url))
|
| 500 |
audio_value = gr.update(value=audio_path if audio_path else None, autoplay=False)
|
| 501 |
-
|
| 502 |
-
|
| 503 |
-
|
| 504 |
-
|
| 505 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 506 |
|
| 507 |
if selection_tracker.token != selection_token:
|
| 508 |
return
|
| 509 |
|
| 510 |
-
yield audio_value,
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 511 |
|
| 512 |
|
| 513 |
with gr.Blocks(title="Call Recording Dashboard") as demo:
|
|
@@ -590,6 +642,8 @@ with gr.Blocks(title="Call Recording Dashboard") as demo:
|
|
| 590 |
outputs=[audio_player, call_details, transcription_box, playback_status, selection_tracker],
|
| 591 |
)
|
| 592 |
|
|
|
|
|
|
|
| 593 |
|
| 594 |
if __name__ == "__main__":
|
| 595 |
demo.launch(server_name="0.0.0.0", server_port=int(os.environ.get("PORT", "7860")))
|
|
|
|
| 2 |
import json
|
| 3 |
import os
|
| 4 |
import tempfile
|
| 5 |
+
import time
|
| 6 |
from pathlib import Path
|
| 7 |
from typing import Any, Dict, Iterator, List, Optional, Tuple
|
| 8 |
import uuid
|
|
|
|
| 18 |
from pymongo import MongoClient
|
| 19 |
from pymongo.collection import Collection
|
| 20 |
from pymongo.errors import PyMongoError
|
| 21 |
+
from gradio_client import utils as gradio_client_utils
|
| 22 |
|
| 23 |
|
| 24 |
MONGODB_URI = os.environ.get("MONGODB_URI")
|
|
|
|
| 28 |
DEFAULT_LIMIT = int(os.environ.get("CALL_DASHBOARD_LIMIT", "50"))
|
| 29 |
SIGNED_URL_EXPIRY_MINUTES = int(os.environ.get("SIGNED_URL_EXPIRY_MINUTES", "60"))
|
| 30 |
FALLBACK_BUCKET_NAME = os.environ.get("GCS_BUCKET_NAME")
|
| 31 |
+
AUDIO_READY_DELAY_SECONDS = float(os.environ.get("AUDIO_READY_DELAY_SECONDS", "3.5"))
|
| 32 |
+
|
| 33 |
+
|
| 34 |
+
def _patch_gradio_schema_utils() -> None:
|
| 35 |
+
"""Work around gradio_client <1.4 boolean handling for additionalProperties."""
|
| 36 |
+
original_get_type = gradio_client_utils.get_type
|
| 37 |
+
original_json_to_python = gradio_client_utils._json_schema_to_python_type
|
| 38 |
+
|
| 39 |
+
def _safe_get_type(schema: Any) -> Any:
|
| 40 |
+
if isinstance(schema, bool):
|
| 41 |
+
return "object" if schema else "never"
|
| 42 |
+
return original_get_type(schema)
|
| 43 |
+
|
| 44 |
+
def _safe_json_schema_to_python_type(schema: Any, defs: Any) -> Any:
|
| 45 |
+
if isinstance(schema, bool):
|
| 46 |
+
return "Dict[str, Any]" if schema else "Never"
|
| 47 |
+
return original_json_to_python(schema, defs)
|
| 48 |
+
|
| 49 |
+
gradio_client_utils.get_type = _safe_get_type
|
| 50 |
+
gradio_client_utils._json_schema_to_python_type = _safe_json_schema_to_python_type
|
| 51 |
+
|
| 52 |
+
|
| 53 |
+
_patch_gradio_schema_utils()
|
| 54 |
|
| 55 |
|
| 56 |
if not MONGODB_URI:
|
|
|
|
| 500 |
selection_tracker,
|
| 501 |
)
|
| 502 |
|
| 503 |
+
loaded_from_cache = False
|
| 504 |
if bucket_name and blob_name and signed_url:
|
| 505 |
cached_path = _AUDIO_CACHE.get(call_id)
|
| 506 |
if cached_path and Path(cached_path).exists():
|
| 507 |
audio_path = cached_path
|
| 508 |
audio_status = "Ready (loaded from cache) — press Play to listen."
|
| 509 |
+
loaded_from_cache = True
|
| 510 |
else:
|
| 511 |
try:
|
| 512 |
audio_path = _download_audio(call_id, signed_url, blob_name)
|
|
|
|
| 523 |
else:
|
| 524 |
audio_status = "Recording unavailable"
|
| 525 |
|
|
|
|
| 526 |
audio_value = gr.update(value=audio_path if audio_path else None, autoplay=False)
|
| 527 |
+
if audio_path:
|
| 528 |
+
if loaded_from_cache:
|
| 529 |
+
playback_intermediate = "▶️ Audio ready — press Play to listen."
|
| 530 |
+
summary_intermediate = "".join(_build_summary_lines(call, topics, audio_status, signed_url))
|
| 531 |
+
else:
|
| 532 |
+
playback_intermediate = "⏳ Audio downloaded — finishing waveform analysis…"
|
| 533 |
+
summary_intermediate = "".join(
|
| 534 |
+
_build_summary_lines(
|
| 535 |
+
call,
|
| 536 |
+
topics,
|
| 537 |
+
"Downloaded — processing waveform",
|
| 538 |
+
signed_url,
|
| 539 |
+
)
|
| 540 |
+
)
|
| 541 |
+
else:
|
| 542 |
+
playback_intermediate = audio_status if "Error" in audio_status else "⚠️ Audio unavailable"
|
| 543 |
+
summary_intermediate = "".join(_build_summary_lines(call, topics, audio_status, signed_url))
|
| 544 |
|
| 545 |
if selection_tracker.token != selection_token:
|
| 546 |
return
|
| 547 |
|
| 548 |
+
yield audio_value, summary_intermediate, transcription_text, gr.update(value=playback_intermediate), selection_tracker
|
| 549 |
+
|
| 550 |
+
if not audio_path or loaded_from_cache:
|
| 551 |
+
return
|
| 552 |
+
|
| 553 |
+
if selection_tracker.token != selection_token:
|
| 554 |
+
return
|
| 555 |
+
|
| 556 |
+
time.sleep(max(0.0, AUDIO_READY_DELAY_SECONDS))
|
| 557 |
+
|
| 558 |
+
if selection_tracker.token != selection_token:
|
| 559 |
+
return
|
| 560 |
+
|
| 561 |
+
summary_final = "".join(_build_summary_lines(call, topics, audio_status, signed_url))
|
| 562 |
+
yield gr.update(), summary_final, gr.update(), gr.update(value="▶️ Audio ready — press Play to listen."), selection_tracker
|
| 563 |
|
| 564 |
|
| 565 |
with gr.Blocks(title="Call Recording Dashboard") as demo:
|
|
|
|
| 642 |
outputs=[audio_player, call_details, transcription_box, playback_status, selection_tracker],
|
| 643 |
)
|
| 644 |
|
| 645 |
+
demo.show_api = False
|
| 646 |
+
|
| 647 |
|
| 648 |
if __name__ == "__main__":
|
| 649 |
demo.launch(server_name="0.0.0.0", server_port=int(os.environ.get("PORT", "7860")))
|