feat: Add browser mode fallback for Kaspersky audio blocking

- Add sidecar management to backend (sidecar_manager.py)
- Add sidecar API router for browser mode (/api/sidecar/*)
- Add browser-api.js polyfill for running in Chrome/Edge
- Add "Open in Browser" button when audio access fails
- Update build scripts with new sidecar modules
- Add start-browser.sh for development browser mode

Browser mode allows users to open the app in their system browser
when Electron's audio access is blocked by security software.
The backend manages the sidecar process in browser mode (BROWSER_MODE=true).

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
egg
2025-12-22 16:41:25 +08:00
parent e7a06e2b8f
commit 7d3fc72bd2
12 changed files with 1374 additions and 3 deletions

260
start-browser.sh Executable file
View File

@@ -0,0 +1,260 @@
#!/bin/bash
#
# Meeting Assistant - Browser Mode Startup Script
# 使用瀏覽器運行 Meeting Assistant完整功能包含即時語音轉寫
#
# 此模式下:
# - 後端會自動啟動並管理 SidecarWhisper 語音轉寫引擎)
# - 前端在 Chrome/Edge 瀏覽器中運行
# - 所有功能皆可正常使用
#
set -e
# 顏色定義
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
# 專案路徑
PROJECT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
BACKEND_DIR="$PROJECT_DIR/backend"
SIDECAR_DIR="$PROJECT_DIR/sidecar"
# Server Configuration (can be overridden by .env)
BACKEND_HOST="${BACKEND_HOST:-0.0.0.0}"
BACKEND_PORT="${BACKEND_PORT:-8000}"
# Whisper Configuration (can be overridden by .env)
export WHISPER_MODEL="${WHISPER_MODEL:-medium}"
export WHISPER_DEVICE="${WHISPER_DEVICE:-cpu}"
export WHISPER_COMPUTE="${WHISPER_COMPUTE:-int8}"
# Browser mode flag - tells backend to manage sidecar
export BROWSER_MODE="true"
# 函數:印出訊息
log_info() {
echo -e "${BLUE}[INFO]${NC} $1"
}
log_success() {
echo -e "${GREEN}[OK]${NC} $1"
}
log_warn() {
echo -e "${YELLOW}[WARN]${NC} $1"
}
log_error() {
echo -e "${RED}[ERROR]${NC} $1"
}
# Load environment variables from .env file if it exists
if [ -f "$BACKEND_DIR/.env" ]; then
log_info "Loading backend environment from $BACKEND_DIR/.env"
export $(grep -v '^#' "$BACKEND_DIR/.env" | grep -v '^$' | xargs)
fi
# 函數:檢查 port 是否被佔用
check_port() {
local port=$1
if lsof -i :$port > /dev/null 2>&1; then
return 0 # port 被佔用
else
return 1 # port 可用
fi
}
# 函數:開啟瀏覽器
open_browser() {
local url=$1
log_info "Opening browser at $url"
# Try different browser commands
if command -v xdg-open &> /dev/null; then
xdg-open "$url" &
elif command -v wslview &> /dev/null; then
wslview "$url" &
elif command -v explorer.exe &> /dev/null; then
# WSL: use Windows browser
explorer.exe "$url" &
elif command -v open &> /dev/null; then
# macOS
open "$url" &
else
log_warn "Could not find a browser to open. Please manually visit: $url"
fi
}
# 函數:檢查環境
check_environment() {
local all_ok=true
# 檢查後端虛擬環境
if [ ! -d "$BACKEND_DIR/venv" ]; then
log_error "Backend virtual environment not found"
log_error "Please run: cd $BACKEND_DIR && python3 -m venv venv && source venv/bin/activate && pip install -r requirements.txt"
all_ok=false
fi
# 檢查 Sidecar 虛擬環境
if [ ! -d "$SIDECAR_DIR/venv" ]; then
log_warn "Sidecar virtual environment not found"
log_warn "即時語音轉寫功能將無法使用"
log_warn "To enable: cd $SIDECAR_DIR && python3 -m venv venv && source venv/bin/activate && pip install -r requirements.txt"
else
log_success "Sidecar environment found - 即時語音轉寫功能可用"
fi
if [ "$all_ok" = false ]; then
exit 1
fi
}
# 函數:啟動後端(包含 Sidecar
start_backend() {
log_info "Checking backend status..."
# Check if backend is already running
if check_port $BACKEND_PORT; then
# Verify it's our backend by checking health endpoint
if curl -s http://localhost:$BACKEND_PORT/api/health > /dev/null 2>&1; then
log_success "Backend is already running on port $BACKEND_PORT"
return 0
else
log_warn "Port $BACKEND_PORT is in use but not by our backend"
log_error "Please stop the process using port $BACKEND_PORT and try again"
exit 1
fi
fi
log_info "Starting backend server (with Sidecar management)..."
log_info "Whisper config: model=$WHISPER_MODEL, device=$WHISPER_DEVICE, compute=$WHISPER_COMPUTE"
cd "$BACKEND_DIR"
source venv/bin/activate
# Start uvicorn in background
nohup uvicorn app.main:app --host $BACKEND_HOST --port $BACKEND_PORT > "$PROJECT_DIR/backend-browser.log" 2>&1 &
local backend_pid=$!
# Wait for backend to be ready
log_info "Waiting for backend and sidecar to start..."
log_info "(This may take a minute if Whisper model needs to download)"
local max_wait=120 # 2 minutes for model download
local waited=0
while [ $waited -lt $max_wait ]; do
sleep 2
waited=$((waited + 2))
if curl -s http://localhost:$BACKEND_PORT/api/health > /dev/null 2>&1; then
log_success "Backend started (PID: $backend_pid)"
# Check sidecar status
local sidecar_status=$(curl -s http://localhost:$BACKEND_PORT/api/sidecar/status 2>/dev/null)
if echo "$sidecar_status" | grep -q '"ready":true'; then
log_success "Sidecar (Whisper) ready"
elif echo "$sidecar_status" | grep -q '"available":false'; then
log_warn "Sidecar not available - transcription disabled"
else
log_info "Sidecar loading... (model may be downloading)"
fi
return 0
fi
# Show progress every 10 seconds
if [ $((waited % 10)) -eq 0 ]; then
log_info "Still waiting... ($waited seconds)"
fi
done
log_error "Backend failed to start. Check $PROJECT_DIR/backend-browser.log for details"
exit 1
}
# 函數:停止服務
stop_services() {
log_info "Stopping services..."
pkill -f "uvicorn app.main:app" 2>/dev/null || true
sleep 1
log_success "Services stopped"
}
# 主程式
main() {
echo ""
echo "=========================================="
echo " Meeting Assistant - Browser Mode"
echo "=========================================="
echo ""
# Check environment
check_environment
# Start backend (which manages sidecar)
start_backend
# Give it a moment
sleep 1
# Open browser
local url="http://localhost:$BACKEND_PORT"
open_browser "$url"
echo ""
echo "=========================================="
log_success "Browser mode started!"
echo "=========================================="
echo ""
echo " Access URL: $url"
echo " API Docs: $url/docs"
echo ""
echo " Features:"
echo " - 即時語音轉寫(透過後端 Sidecar"
echo " - 上傳音訊轉寫"
echo " - AI 摘要"
echo " - 匯出 Excel"
echo ""
echo " To stop: $0 stop"
echo ""
log_info "Press Ctrl+C to exit (backend will keep running)"
echo ""
# Keep script running
trap 'echo ""; log_info "Exiting (backend still running)"; exit 0' INT TERM
while true; do
sleep 60
done
}
# 處理命令
case "${1:-start}" in
start)
main
;;
stop)
stop_services
;;
restart)
stop_services
sleep 2
main
;;
status)
if check_port $BACKEND_PORT; then
log_success "Backend running on port $BACKEND_PORT"
curl -s http://localhost:$BACKEND_PORT/api/sidecar/status | python3 -m json.tool 2>/dev/null || echo "(Could not parse sidecar status)"
else
log_warn "Backend not running"
fi
;;
*)
echo "Usage: $0 {start|stop|restart|status}"
exit 1
;;
esac