Spaces:
Sleeping
Sleeping
| -- ============================================================================= | |
| -- Supabase RPC: match_courses | |
| -- Hybrid Recommender Engine — Vector Similarity Search | |
| -- Searches course_chunks embeddings, JOINs to parent courses table. | |
| -- Supports SBERT, E5, and DistilBERT models via model_type parameter. | |
| -- ============================================================================= | |
| -- Drop existing function variants (for idempotent re-runs) | |
| DROP FUNCTION IF EXISTS match_courses(vector, float, int, int, text); | |
| DROP FUNCTION IF EXISTS match_courses(vector, float8, int4, int4, text); | |
| CREATE OR REPLACE FUNCTION match_courses( | |
| query_embedding vector, | |
| match_threshold float DEFAULT 0.3, | |
| match_count int DEFAULT 5, | |
| child_age_months int DEFAULT 48, | |
| model_type text DEFAULT 'sbert' | |
| ) | |
| RETURNS TABLE ( | |
| course_id uuid, | |
| course_title text, | |
| course_description text, | |
| chunk_id uuid, | |
| chunk_title text, | |
| chunk_content text, | |
| similarity float | |
| ) | |
| LANGUAGE plpgsql | |
| AS $$ | |
| BEGIN | |
| IF model_type = 'e5' THEN | |
| RETURN QUERY | |
| SELECT | |
| c.id AS course_id, | |
| c.title AS course_title, | |
| c.description AS course_description, | |
| cc.id AS chunk_id, | |
| cc.chunk_title, | |
| cc.chunk_content, | |
| (1 - (cc.embedding_e5 <=> query_embedding))::float AS similarity | |
| FROM course_chunks cc | |
| JOIN courses c ON cc.course_id = c.id | |
| WHERE | |
| c.age_min <= child_age_months | |
| AND c.age_max >= child_age_months | |
| AND cc.embedding_e5 IS NOT NULL | |
| AND (1 - (cc.embedding_e5 <=> query_embedding)) > match_threshold | |
| ORDER BY cc.embedding_e5 <=> query_embedding ASC | |
| LIMIT match_count; | |
| ELSIF model_type = 'distilbert' THEN | |
| RETURN QUERY | |
| SELECT | |
| c.id AS course_id, | |
| c.title AS course_title, | |
| c.description AS course_description, | |
| cc.id AS chunk_id, | |
| cc.chunk_title, | |
| cc.chunk_content, | |
| (1 - (cc.embedding_distilbert <=> query_embedding))::float AS similarity | |
| FROM course_chunks cc | |
| JOIN courses c ON cc.course_id = c.id | |
| WHERE | |
| c.age_min <= child_age_months | |
| AND c.age_max >= child_age_months | |
| AND cc.embedding_distilbert IS NOT NULL | |
| AND (1 - (cc.embedding_distilbert <=> query_embedding)) > match_threshold | |
| ORDER BY cc.embedding_distilbert <=> query_embedding ASC | |
| LIMIT match_count; | |
| ELSE | |
| -- Default: SBERT | |
| RETURN QUERY | |
| SELECT | |
| c.id AS course_id, | |
| c.title AS course_title, | |
| c.description AS course_description, | |
| cc.id AS chunk_id, | |
| cc.chunk_title, | |
| cc.chunk_content, | |
| (1 - (cc.embedding_sbert <=> query_embedding))::float AS similarity | |
| FROM course_chunks cc | |
| JOIN courses c ON cc.course_id = c.id | |
| WHERE | |
| c.age_min <= child_age_months | |
| AND c.age_max >= child_age_months | |
| AND cc.embedding_sbert IS NOT NULL | |
| AND (1 - (cc.embedding_sbert <=> query_embedding)) > match_threshold | |
| ORDER BY cc.embedding_sbert <=> query_embedding ASC | |
| LIMIT match_count; | |
| END IF; | |
| END; | |
| $$; | |