-
Notifications
You must be signed in to change notification settings - Fork 5
feat: Add OCR text extraction and hybrid search #32
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
2570597
71ce921
80c4c72
ca0b495
9ba2529
9cea0f3
02e07f9
5d05f2d
7290dd9
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -13,7 +13,7 @@ | |
| from fastapi.responses import FileResponse, RedirectResponse | ||
| from fastapi.staticfiles import StaticFiles | ||
|
|
||
| from api.routes import compression, incognito, recording, screenshots, search, setup, status, sync | ||
| from api.routes import compression, events, incognito, recording, screenshots, search, setup, status, sync | ||
| from core.database import db | ||
|
|
||
|
|
||
|
|
@@ -48,6 +48,21 @@ async def lifespan(app: FastAPI): | |
| print(f"📁 Database: {db.db_path}") | ||
| print(f"📊 Screenshots: {stats['total_screenshots']} total, {stats['synced']} synced") | ||
|
|
||
| # Auto-start OCR migration if needed (for existing screenshots without OCR) | ||
| # This does NOT process new screenshots - those still require manual sync | ||
| from core.config import config | ||
| from core.processor import processor_service | ||
|
|
||
| if config.ocr.enabled: | ||
| try: | ||
| ocr_pending = db.get_ocr_pending_count() | ||
| if ocr_pending > 0: | ||
| print(f"🔄 Starting OCR migration for {ocr_pending} existing screenshots...") | ||
| processor_service.start_ocr_migration() | ||
| except Exception as e: | ||
| # Don't crash the API if OCR migration fails - log and continue | ||
| logging.getLogger(__name__).exception("Failed to start OCR migration: %s", e) | ||
|
|
||
|
Comment on lines
+51
to
+65
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🏁 Script executed: #!/bin/bash
# Verify whether OCR migration is safe under multi-process or guarded elsewhere.
rg -n --hidden -S "start_ocr_migration\(|_ocr_migration_loop|has_ocr\s*=\s*0" core api | head -n 80Repository: VedankPurohit/LiveRecall Length of output: 192 🏁 Script executed: #!/bin/bash
# Find core/processor.py and examine start_ocr_migration implementation
find . -name "processor.py" -type fRepository: VedankPurohit/LiveRecall Length of output: 87 🏁 Script executed: #!/bin/bash
# Look at api/main.py context around lines 40-70 to see full startup logic and error handling
fd -e py "main.py" api | xargs cat -n | sed -n '40,70p'Repository: VedankPurohit/LiveRecall Length of output: 1335 🏁 Script executed: #!/bin/bash
# Read core/processor.py to understand start_ocr_migration implementation
wc -l core/processor.pyRepository: VedankPurohit/LiveRecall Length of output: 89 🏁 Script executed: #!/bin/bash
# Look for start_ocr_migration definition
rg -n "def start_ocr_migration" core/processor.py -A 20Repository: VedankPurohit/LiveRecall Length of output: 1022 🏁 Script executed: #!/bin/bash
# Check for locking or process-safety mechanisms
rg -n "Lock|lock|Semaphore|process_safe|multi.*worker|uvicorn" core/processor.pyRepository: VedankPurohit/LiveRecall Length of output: 233 🏁 Script executed: #!/bin/bash
# Check if exception handling exists elsewhere in startup or if crashes block app
rg -n "try:|except|Exception" core/processor.py | head -20Repository: VedankPurohit/LiveRecall Length of output: 967 🏁 Script executed: #!/bin/bash
# Look at db.get_ocr_pending_count() to check for process safety
rg -n "def get_ocr_pending_count" core -A 10Repository: VedankPurohit/LiveRecall Length of output: 669 🏁 Script executed: #!/bin/bash
# Check if there's any inter-process locking or startup synchronization elsewhere
rg -n "flock|fcntl|multiprocessing.*Lock|db.*lock" core api --hidden | head -10Repository: VedankPurohit/LiveRecall Length of output: 50 🏁 Script executed: #!/bin/bash
# Verify if uvicorn/FastAPI has any built-in single-startup mechanism that prevents duplication
rg -n "uvicorn|workers|--workers" . --type py -B2 -A2 | head -20Repository: VedankPurohit/LiveRecall Length of output: 722 🏁 Script executed: #!/bin/bash
# Check if there's a startup guard or singleton pattern elsewhere in api/main.py
cat -n api/main.py | sed -n '1,80p'Repository: VedankPurohit/LiveRecall Length of output: 3175 Add exception handling and guard multi-worker OCR migration duplication. When uvicorn runs with multiple workers, each process independently calls Proposed fix if config.ocr.enabled:
+ try:
ocr_pending = db.get_ocr_pending_count()
if ocr_pending > 0:
+ # NOTE: Ensure this is safe under multi-process deployments (uvicorn workers > 1).
print(f"🔄 Starting OCR migration for {ocr_pending} existing screenshots...")
processor_service.start_ocr_migration()
+ except Exception as e:
+ # Don't take down the API if OCR migration can't start; surface it in logs.
+ logging.getLogger(__name__).exception("Failed to start OCR migration: %s", e) |
||
| yield | ||
|
|
||
| # Shutdown | ||
|
|
@@ -122,6 +137,7 @@ async def strip_trailing_slash(request: Request, call_next): | |
| app.include_router(compression.router, prefix="/api/v1") | ||
| app.include_router(incognito.router, prefix="/api/v1") | ||
| app.include_router(setup.router, prefix="/api/v1") | ||
| app.include_router(events.router, prefix="/api/v1") | ||
|
|
||
|
|
||
| # Serve static web UI if available | ||
|
|
@@ -195,4 +211,5 @@ async def root(): | |
| host="127.0.0.1", | ||
| port=8742, | ||
| reload=True, | ||
| log_level="warning", # Suppress verbose access logs | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🏁 Script executed: # First, let's see the context around line 210 in api/main.py
sed -n '200,220p' api/main.pyRepository: VedankPurohit/LiveRecall Length of output: 343 🏁 Script executed: # Let's also see more context to understand what object/function uses log_level
sed -n '190,230p' api/main.pyRepository: VedankPurohit/LiveRecall Length of output: 665 🏁 Script executed: # Search for uvicorn.access configuration and logger setup
rg -n "uvicorn|access|logger" api/main.py -A 2 -B 2Repository: VedankPurohit/LiveRecall Length of output: 556 🏁 Script executed: # Search for SSE or progress-related logging
rg -n "SSE|progress|stream|info|debug" api/main.pyRepository: VedankPurohit/LiveRecall Length of output: 118 🏁 Script executed: # Search for logging configuration in the entire codebase
rg -n "logging\.config|getLogger|uvicorn" --type pyRepository: VedankPurohit/LiveRecall Length of output: 980 🏁 Script executed: # Search for SSE, streaming, WebSocket, or progress event implementations
rg -n "sse|streaming|websocket|progress|EventSourceResponse|Server-Sent" --type py -iRepository: VedankPurohit/LiveRecall Length of output: 50380 🏁 Script executed: # Search for any logging calls in the app (especially info level)
rg -n "\.info\(|\.debug\(" --type py api/Repository: VedankPurohit/LiveRecall Length of output: 50 🏁 Script executed: # Check if there are any custom loggers or logging config that might be affected
rg -n "getLogger|StreamingResponse|yield|event" --type py api/main.py -B 1 -A 1Repository: VedankPurohit/LiveRecall Length of output: 572 Clarify logging level configuration and confirm it doesn't inadvertently suppress uvicorn's non-access logs. The explicit 🤖 Prompt for AI Agents |
||
| ) | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
🏁 Script executed:
rg -n --hidden -S "screenshot_embeddings|ocr_text_embeddings|vec0|sqlite-vec|CREATE VIRTUAL TABLE" --type-listRepository: VedankPurohit/LiveRecall
Length of output: 457
🏁 Script executed:
rg -n "screenshot_embeddings|ocr_text_embeddings|vec0|sqlite-vec|CREATE VIRTUAL TABLE" -A 3 -B 1Repository: VedankPurohit/LiveRecall
Length of output: 10094
🏁 Script executed:
Repository: VedankPurohit/LiveRecall
Length of output: 105
🏁 Script executed:
Repository: VedankPurohit/LiveRecall
Length of output: 1025
🏁 Script executed:
Repository: VedankPurohit/LiveRecall
Length of output: 846
🏁 Script executed:
Repository: VedankPurohit/LiveRecall
Length of output: 319
🏁 Script executed:
cat core/database.py | head -40Repository: VedankPurohit/LiveRecall
Length of output: 1139
🏁 Script executed:
Repository: VedankPurohit/LiveRecall
Length of output: 8138
Update documented embedding dimensions: CLIP ViT-L-14 produces 768-dim vectors, not 512-dim.
The code in
core/database.pydefinesEMBEDDING_DIM = 768with a comment confirming "CLIP ViT-L-14 produces 768-dimensional embeddings." The schema and validation logic consistently enforce this constraint. Update CLAUDE.md lines 51 and 100 to replace "512-dim vectors" with "768-dim vectors." The 384-dim claim for text embeddings (lines 54, 103) is correct and usesBGE-small-en-v1.5.🤖 Prompt for AI Agents