From 7a15329a1a649c1f3ac0f5e4e8ae7e93c1879dd1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?th=E1=BB=8Bnh?= Date: Mon, 15 Sep 2025 18:30:57 +0700 Subject: [PATCH 1/2] Use indexed stack and global keys for main tabs to reduce re-rendering overhead --- .../pages/action_items/action_items_page.dart | 1 + app/lib/pages/home/page.dart | 39 ++++++------------- 2 files changed, 12 insertions(+), 28 deletions(-) diff --git a/app/lib/pages/action_items/action_items_page.dart b/app/lib/pages/action_items/action_items_page.dart index 1e84d9a663..d6ffec4c11 100644 --- a/app/lib/pages/action_items/action_items_page.dart +++ b/app/lib/pages/action_items/action_items_page.dart @@ -35,6 +35,7 @@ class _ActionItemsPageState extends State with AutomaticKeepAli super.initState(); _scrollController.addListener(_onScroll); WidgetsBinding.instance.addPostFrameCallback((_) { + if (!mounted) return; MixpanelManager().actionItemsPageOpened(); final provider = Provider.of(context, listen: false); if (provider.actionItems.isEmpty) { diff --git a/app/lib/pages/home/page.dart b/app/lib/pages/home/page.dart index daf3362b85..4a7c632c3f 100644 --- a/app/lib/pages/home/page.dart +++ b/app/lib/pages/home/page.dart @@ -101,12 +101,11 @@ class _HomePageState extends State with WidgetsBindingObserver, Ticker final _upgrader = MyUpgrader(debugLogging: false, debugDisplayOnce: false); bool scriptsInProgress = false; - PageController? _controller; - final GlobalKey> _conversationsPageKey = GlobalKey>(); final GlobalKey> _actionItemsPageKey = GlobalKey>(); final GlobalKey> _memoriesPageKey = GlobalKey>(); final GlobalKey _appsPageKey = GlobalKey(); + late final List _pages; void _initiateApps() { context.read().getApps(); @@ -190,6 +189,12 @@ class _HomePageState extends State with WidgetsBindingObserver, Ticker @override void initState() { + _pages = [ + ConversationsPage(key: _conversationsPageKey), + ActionItemsPage(key: _actionItemsPageKey), + MemoriesPage(key: _memoriesPageKey), + AppsPage(key: _appsPageKey), + ]; SharedPreferencesUtil().onboardingCompleted = true; // Navigate uri @@ -220,11 +225,7 @@ class _HomePageState extends State with WidgetsBindingObserver, Ticker } // Home controller - _controller = PageController(initialPage: homePageIdx); context.read().selectedIndex = homePageIdx; - context.read().onSelectedIndexChanged = (index) { - _controller?.animateToPage(index, duration: const Duration(milliseconds: 200), curve: Curves.easeInOut); - }; WidgetsBinding.instance.addObserver(this); WidgetsBinding.instance.addPostFrameCallback((_) async { @@ -427,7 +428,7 @@ class _HomePageState extends State with WidgetsBindingObserver, Ticker appBar: homeProvider.selectedIndex == 5 ? null : _buildAppBar(context), body: DefaultTabController( length: 4, - initialIndex: _controller?.initialPage ?? 0, + initialIndex: homeProvider.selectedIndex, child: GestureDetector( onTap: () { primaryFocus?.unfocus(); @@ -439,15 +440,9 @@ class _HomePageState extends State with WidgetsBindingObserver, Ticker Column( children: [ Expanded( - child: PageView( - controller: _controller, - physics: const NeverScrollableScrollPhysics(), - children: [ - ConversationsPage(key: _conversationsPageKey), - ActionItemsPage(key: _actionItemsPageKey), - MemoriesPage(key: _memoriesPageKey), - AppsPage(key: _appsPageKey), - ], + child: IndexedStack( + index: context.watch().selectedIndex, + children: _pages, ), ), ], @@ -490,8 +485,6 @@ class _HomePageState extends State with WidgetsBindingObserver, Ticker return; } home.setIndex(0); - _controller?.animateToPage(0, - duration: const Duration(milliseconds: 200), curve: Curves.easeInOut); }, child: SizedBox( height: 90, @@ -523,8 +516,6 @@ class _HomePageState extends State with WidgetsBindingObserver, Ticker return; } home.setIndex(1); - _controller?.animateToPage(1, - duration: const Duration(milliseconds: 200), curve: Curves.easeInOut); }, child: SizedBox( height: 90, @@ -558,8 +549,6 @@ class _HomePageState extends State with WidgetsBindingObserver, Ticker return; } home.setIndex(2); - _controller?.animateToPage(2, - duration: const Duration(milliseconds: 200), curve: Curves.easeInOut); }, child: SizedBox( height: 90, @@ -591,8 +580,6 @@ class _HomePageState extends State with WidgetsBindingObserver, Ticker return; } home.setIndex(3); - _controller?.animateToPage(3, - duration: const Duration(milliseconds: 200), curve: Curves.easeInOut); }, child: SizedBox( height: 90, @@ -833,10 +820,6 @@ class _HomePageState extends State with WidgetsBindingObserver, Ticker void dispose() { WidgetsBinding.instance.removeObserver(this); ForegroundUtil.stopForegroundTask(); - if (_controller != null) { - _controller!.dispose(); - _controller = null; - } super.dispose(); } } From 74cba58ebc3400b4a80e377291724fcc37a2b9f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?th=E1=BB=8Bnh?= Date: Mon, 15 Sep 2025 18:31:41 +0700 Subject: [PATCH 2/2] Remove logs, prevent stucking at pusher-retrying --- backend/database/vector_db.py | 5 ---- backend/routers/transcribe.py | 55 ++++++++++++++++++----------------- 2 files changed, 28 insertions(+), 32 deletions(-) diff --git a/backend/database/vector_db.py b/backend/database/vector_db.py index 1e2a12148f..e50a9fcceb 100644 --- a/backend/database/vector_db.py +++ b/backend/database/vector_db.py @@ -57,10 +57,8 @@ def query_vectors(query: str, uid: str, starts_at: int = None, ends_at: int = No if starts_at is not None: filter_data['created_at'] = {'$gte': starts_at, '$lte': ends_at} - # print('filter_data', filter_data) xq = embeddings.embed_query(query) xc = index.query(vector=xq, top_k=k, include_metadata=False, filter=filter_data, namespace="ns1") - # print(xc) return [item['id'].replace(f'{uid}-', '') for item in xc['matches']] @@ -96,8 +94,6 @@ def query_vectors_by_metadata( {'created_at': {'$gte': int(dates_filter[0].timestamp()), '$lte': int(dates_filter[1].timestamp())}} ) - # print('query_vectors_by_metadata:', json.dumps(filter_data)) - xc = index.query( vector=vector, filter=filter_data, namespace="ns1", include_values=False, include_metadata=True, top_k=1000 ) @@ -132,7 +128,6 @@ def query_vectors_by_metadata( conversations_id = [item['id'].replace(f'{uid}-', '') for item in xc['matches']] conversations_id.sort(key=lambda x: conversation_id_to_matches[x], reverse=True) - print('query_vectors_by_metadata result:', conversations_id) return conversations_id[:limit] if len(conversations_id) > limit else conversations_id diff --git a/backend/routers/transcribe.py b/backend/routers/transcribe.py index abce9b0049..b56b39aa13 100644 --- a/backend/routers/transcribe.py +++ b/backend/routers/transcribe.py @@ -1,16 +1,16 @@ -import os -import uuid import asyncio -import struct import json -from datetime import datetime, timezone, timedelta, time +import os +import struct +import uuid +from datetime import datetime, time, timedelta, timezone from enum import Enum -from typing import Dict, Tuple, List, Optional, Set +from typing import Dict, List, Optional, Set, Tuple import opuslib import webrtcvad from fastapi import APIRouter, Depends -from fastapi.websockets import WebSocketDisconnect, WebSocket +from fastapi.websockets import WebSocket, WebSocketDisconnect from pydub import AudioSegment from starlette.websockets import WebSocketState @@ -18,51 +18,51 @@ import database.users as user_db from database import redis_db from database.redis_db import get_cached_user_geolocation -from models.users import PlanType from models.conversation import ( Conversation, - TranscriptSegment, - ConversationStatus, - Structured, - Geolocation, ConversationPhoto, ConversationSource, + ConversationStatus, + Geolocation, + Structured, + TranscriptSegment, ) from models.message_event import ( ConversationEvent, + LastConversationEvent, MessageEvent, MessageServiceStatusEvent, - LastConversationEvent, - TranslationEvent, - PhotoProcessingEvent, PhotoDescribedEvent, + PhotoProcessingEvent, SpeakerLabelSuggestionEvent, + TranslationEvent, ) from models.transcript_segment import Translation +from models.users import PlanType +from utils.analytics import record_usage +from utils.app_integrations import trigger_external_integrations from utils.apps import is_audio_bytes_app_enabled from utils.conversations.location import get_google_maps_location from utils.conversations.process_conversation import process_conversation, retrieve_in_progress_conversation +from utils.notifications import send_credit_limit_notification, send_silent_user_notification +from utils.other import endpoints as auth +from utils.other.storage import get_profile_audio_if_exists from utils.other.task import safe_create_task -from utils.app_integrations import trigger_external_integrations +from utils.pusher import connect_to_trigger_pusher +from utils.speaker_identification import detect_speaker_from_text from utils.stt.streaming import * -from utils.stt.streaming import get_stt_service_for_language, STTService from utils.stt.streaming import ( - process_audio_soniox, + STTService, + get_stt_service_for_language, process_audio_dg, + process_audio_soniox, process_audio_speechmatics, send_initial_file_path, ) -from utils.webhooks import get_audio_bytes_webhook_seconds -from utils.pusher import connect_to_trigger_pusher +from utils.subscription import has_transcription_credits from utils.translation import TranslationService from utils.translation_cache import TranscriptSegmentLanguageCache -from utils.speaker_identification import detect_speaker_from_text -from utils.analytics import record_usage -from utils.subscription import has_transcription_credits - -from utils.other import endpoints as auth -from utils.other.storage import get_profile_audio_if_exists -from utils.notifications import send_credit_limit_notification, send_silent_user_notification +from utils.webhooks import get_audio_bytes_webhook_seconds router = APIRouter() @@ -676,8 +676,9 @@ async def connect(): nonlocal pusher_connected nonlocal pusher_connect_lock nonlocal pusher_ws + nonlocal websocket_active async with pusher_connect_lock: - if pusher_connected: + if pusher_connected or not websocket_active: return # drain if pusher_ws: