fix(duplicate-service): replace in-memory/JSON store with Supabase (#… - #2427
Conversation
…iteshbonthalakoti#2373) Problem: - DuplicateService kept ticket embeddings in a process-local list (self._tickets) and a local JSON file (case_history_cache.json). - In multi-worker deployments (Uvicorn --workers N, HF Spaces) each worker had an isolated, diverging index — duplicate detection was non-deterministic depending on which worker handled the request. - Ephemeral containers (HF Spaces, Docker) destroyed the local JSON on every restart, losing the entire embedding history. Fix: - Embeddings are now persisted in a new icket_embeddings Supabase table (ticket_id, text, embedding jsonb) shared by every worker. - add_ticket() upserts the embedding; check_duplicate() fetches all rows and performs cosine-similarity in-process (same logic as before). - Graceful fallback: when Supabase is not configured the service falls back to the previous in-memory + local-JSON behaviour so local development continues to work without any env changes. - Legacy save_to_disk() method retained as a no-op shim for backwards compatibility with any external callers. Migration: - Run backend/supabase/create_ticket_embeddings_table.sql once in the Supabase SQL editor to create the required table and index. Closes riteshbonthalakoti#2373
|
@pranayukey200 is attempting to deploy a commit to the ritesh Team on Vercel. A member of the Team first needs to authorize it. |
📝 WalkthroughWalkthroughDuplicateService refactored to persist ticket embeddings in Supabase ChangesSupabase-backed Duplicate Detection
Sequence DiagramsequenceDiagram
participant Service as DuplicateService
participant Model as SentenceTransformer
participant Supabase as Supabase DB
participant Fallback as In-Memory Store
Service->>Model: load model
Service->>Supabase: attempt connection
alt Supabase configured
Supabase-->>Service: connected
Service->>Service: _use_supabase = true
else Supabase unavailable
Service->>Service: load fallback from disk
Service->>Service: _use_supabase = false
end
rect rgba(100, 150, 200, 0.5)
Note over Service: add_ticket(ticket_id, text)
Service->>Model: embed(text)
alt _use_supabase
Service->>Supabase: upsert(ticket_id, embedding)
else fallback
Service->>Fallback: append
Service->>Service: save to JSON cache
end
end
rect rgba(100, 150, 200, 0.5)
Note over Service: check_duplicate(text)
Service->>Model: embed(text)
alt _use_supabase
Service->>Supabase: SELECT embeddings
Supabase-->>Service: rows
else fallback
Service->>Fallback: iterate stored embeddings
end
Service->>Service: compute cosine similarity
Service-->>Service: return best match if above threshold
end
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related PRs
Suggested labels
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (2)
backend/services/duplicate_service.py (1)
205-211: ⚡ Quick winStore
embeddingas a native JSON array, not a JSON-encoded string.Line 210 serializes
embedding_listwithjson.dumps(...); this weakens thejsonbcontract and forces dual-path parsing at Line 253. Prefer writing the Python list directly and keep read-path type handling strict.Suggested change
- "embedding": json.dumps(embedding_list), + "embedding": embedding_list,Also applies to: 251-254
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@backend/services/duplicate_service.py` around lines 205 - 211, The upsert is serializing the embedding into a JSON string which breaks the jsonb contract; instead write the Python list directly so the DB stores a native JSON array — change the upsert call in duplicate_service where embedding_list is built (embedding_list: list[float] = embedding.cpu().tolist()) to pass embedding=embedding_list (remove json.dumps) and make the same change for the other upsert/read pair mentioned (the second upsert/read around the other embedding insertion) so the read-path can assume a list type without dual-path parsing.backend/supabase/create_ticket_embeddings_table.sql (1)
18-19: ⚡ Quick winDrop the duplicate index on
ticket_id.Line 11 already defines
ticket_idasUNIQUE, which creates the lookup index needed forON CONFLICT (ticket_id). Keeping Line 18-19 adds redundant write overhead.Suggested change
-- Index for fast lookup by ticket_id -CREATE INDEX IF NOT EXISTS idx_ticket_embeddings_ticket_id - ON ticket_embeddings(ticket_id); +-- (Removed) `ticket_id` UNIQUE constraint already creates the required index.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@backend/supabase/create_ticket_embeddings_table.sql` around lines 18 - 19, Remove the redundant index idx_ticket_embeddings_ticket_id on ticket_embeddings: ticket_id is already declared UNIQUE (which creates the necessary lookup index for ON CONFLICT (ticket_id)), so delete the CREATE INDEX statement referencing idx_ticket_embeddings_ticket_id to avoid unnecessary write overhead.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@backend/services/duplicate_service.py`:
- Around line 215-221: The except block in DuplicateService that currently logs
failures to upsert embeddings (logger.error with ticket_id) must not swallow
errors; modify the except Exception as exc handler in the upsert_embedding
method so that after logging the full error you either re-raise the original
exception (raise) or raise a specific DuplicateServiceError containing exc, so
the caller can detect/persist failure and avoid index drift; ensure the log
still includes exc and context before re-raising to preserve diagnostics.
- Around line 231-236: The Supabase query in _check_duplicate_supabase currently
does an unbounded .select on the ticket_embeddings table and can miss rows due
to Supabase's 1,000-row default cap; change the read to a paginated,
deterministic scan by adding an .order("ticket_id") (or other stable key) and
loop with .range(start, start + page_size - 1) (e.g., page_size=1000) requesting
successive pages until the returned response.data (rows) length is less than
page_size, aggregating rows into the existing rows variable before computing
embeddings/distance; ensure you keep using the same .select("ticket_id,
embedding") projection and handle response.errors per existing pattern.
---
Nitpick comments:
In `@backend/services/duplicate_service.py`:
- Around line 205-211: The upsert is serializing the embedding into a JSON
string which breaks the jsonb contract; instead write the Python list directly
so the DB stores a native JSON array — change the upsert call in
duplicate_service where embedding_list is built (embedding_list: list[float] =
embedding.cpu().tolist()) to pass embedding=embedding_list (remove json.dumps)
and make the same change for the other upsert/read pair mentioned (the second
upsert/read around the other embedding insertion) so the read-path can assume a
list type without dual-path parsing.
In `@backend/supabase/create_ticket_embeddings_table.sql`:
- Around line 18-19: Remove the redundant index idx_ticket_embeddings_ticket_id
on ticket_embeddings: ticket_id is already declared UNIQUE (which creates the
necessary lookup index for ON CONFLICT (ticket_id)), so delete the CREATE INDEX
statement referencing idx_ticket_embeddings_ticket_id to avoid unnecessary write
overhead.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 1b1c2b97-6f4e-4188-8fa7-773b60779a54
📒 Files selected for processing (3)
backend/.env.examplebackend/services/duplicate_service.pybackend/supabase/create_ticket_embeddings_table.sql
|
Hi @pranayukey200! Absolute pleasure to have you building with us. I've successfully merged your PR! 🚀 Please make sure to sign up under the company Ritesh PVT Limited when testing your features! Let's keep building! 🔥 |
e86fd21
into
riteshbonthalakoti:gssoc
…2373)
Problem:
Fix:
Migration:
Closes #2373
Summary by CodeRabbit
New Features
Infrastructure