Spaces:
Sleeping
Sleeping
File size: 9,595 Bytes
2964773 b4dfce4 2964773 b4dfce4 2964773 b4dfce4 2964773 b4dfce4 2964773 b4dfce4 2964773 b4dfce4 2964773 b4dfce4 2964773 b4dfce4 2964773 b4dfce4 2964773 b4dfce4 2964773 b4dfce4 2964773 b4dfce4 2964773 b4dfce4 2964773 b4dfce4 2964773 b4dfce4 2964773 b4dfce4 2964773 b4dfce4 2964773 b4dfce4 2964773 b4dfce4 2964773 b4dfce4 2964773 b4dfce4 2964773 b4dfce4 2964773 b4dfce4 2964773 b4dfce4 2964773 b4dfce4 2964773 b4dfce4 2964773 b4dfce4 2964773 b4dfce4 2964773 b4dfce4 2964773 b4dfce4 2964773 b4dfce4 2964773 b4dfce4 2964773 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 |
import gradio as gr
import json
import os
from datetime import datetime
from dotenv import load_dotenv
from supabase import create_client, Client
from pinecone import Pinecone
from sentence_transformers import SentenceTransformer
from typing import List, Dict
load_dotenv()
SUPABASE_URL = os.getenv("DB_URL")
SUPABASE_KEY = os.getenv("DB_KEY")
pinecone_api_key = os.getenv("PINECONE")
supabase_client = create_client(SUPABASE_URL, SUPABASE_KEY)
pc = Pinecone(api_key=pinecone_api_key)
index = pc.Index("focus-guru")
model = SentenceTransformer("all-MiniLM-L6-v2")
def ingest_user_progress(
supabase_client: Client,
user_id: int,
video_id: str,
rating: float,
time_spent: int,
play_count: int,
completed: bool
):
data = {
"user_id": user_id,
"video_id": video_id,
"rating": rating,
"time_spent": time_spent,
"play_count": play_count,
"completed": completed,
"updated_at": datetime.now().isoformat()
}
response = supabase_client.table("user_progress").insert(data, upsert=True).execute()
return response.data
def gradio_ingest(user_input):
try:
data = json.loads(user_input)
user_id = int(data.get("user_id", 0))
video_id = data.get("video_id", "")
rating = float(data.get("rating", 0))
time_spent = int(data.get("time_spent", 0))
play_count = int(data.get("play_count", 0))
completed = bool(data.get("completed", False))
except Exception as e:
return f"<p style='color: red;'>Error parsing input: {e}</p>"
res = ingest_user_progress(supabase_client, user_id, video_id, rating, time_spent, play_count, completed)
return f"<p style='color: green;'>Ingested data: {res}</p>"
def recommend_playlists_by_package_and_module(assessment_output, index, model):
report_text = assessment_output.get("report", "")
packages = assessment_output.get("package", [])
modules = ["Nutrition", "Exercise", "Meditation"]
recommendations = {}
if not report_text:
for pkg in packages:
recommendations[pkg] = {mod: {"title": "No playlist found", "description": ""} for mod in modules}
return recommendations
query_embedding = model.encode(report_text, convert_to_numpy=True).tolist()
for pkg in packages:
recommendations[pkg] = {}
for mod in modules:
filter_dict = {"type": "playlist", "Package": pkg, "Module": mod}
results = index.query(vector=query_embedding, top_k=1, include_metadata=True, filter=filter_dict)
if results["matches"]:
match = results["matches"][0]
metadata = match["metadata"]
title = metadata.get("Playlist Name", "Unknown Playlist")
description = metadata.get("Description", "")
recommendations[pkg][mod] = {"title": title, "description": description}
else:
recommendations[pkg][mod] = {"title": "No playlist found", "description": ""}
return recommendations
def gradio_recommend_playlist(input_json):
try:
assessment_data = json.loads(input_json)
except json.JSONDecodeError:
return "<p style='color: red;'>Error: Invalid JSON format</p>"
if "package" not in assessment_data or "report" not in assessment_data:
return "<p style='color: red;'>Error: Missing 'package' or 'report' field</p>"
recs = recommend_playlists_by_package_and_module(assessment_data, index, model)
html_output = "<div style='padding: 20px; font-family: Arial, sans-serif;'>"
for pkg, mod_recs in recs.items():
html_output += f"<h2>{pkg} Package</h2><div style='display: flex; flex-wrap: wrap; gap: 20px;'>"
for mod, rec in mod_recs.items():
html_output += f"""
<div style="border: 1px solid #ccc; border-radius: 8px; padding: 15px; width: 260px;">
<h3>{mod} Module</h3>
<strong>{rec['title']}</strong>
<p>{rec['description']}</p>
</div>
"""
html_output += "</div>"
html_output += "</div>"
return html_output
def recommend_videos(user_id: int, K: int = 5, M: int = 10, N: int = 5) -> Dict:
response = supabase_client.table("user_progress").select("video_id, rating, completed, play_count, videos!inner(playlist_id)").eq("user_id", user_id).execute()
interactions = response.data
if not interactions:
return {
"note": "No interactions recorded for this user yet. Please watch or rate some videos.",
"recommendations": []
}
for inter in interactions:
rating = inter["rating"] if inter["rating"] is not None else 0
completed_val = 1 if inter["completed"] else 0
play_count = inter["play_count"]
inter["engagement"] = rating + 2 * completed_val + play_count
top_videos = sorted(interactions, key=lambda x: x["engagement"], reverse=True)[:K]
watched_completed_videos = {i["video_id"] for i in interactions if i["completed"]}
watched_incomplete_videos = {i["video_id"] for i in interactions if not i["completed"]}
candidates = {}
for top_video in top_videos:
query_id = f"video_{top_video['video_id']}"
response = index.query(id=query_id, top_k=M + 1, include_metadata=True)
for match in response.get("matches", []):
if match["id"] == query_id:
continue
metadata = match.get("metadata", {})
vid = metadata.get("vid")
if not vid:
continue
if vid in watched_completed_videos:
continue
similarity = match["score"]
pid = metadata.get("PID")
boost = 1.1 if pid == top_video["videos"]["playlist_id"] else 1.0
partial_score = top_video["engagement"] * similarity * boost
if vid in candidates:
candidates[vid]["total_score"] += partial_score
else:
candidates[vid] = {"total_score": partial_score, "metadata": metadata}
sorted_candidates = sorted(candidates.items(), key=lambda x: x[1]["total_score"], reverse=True)[:N]
recommendations = []
for vid, data in sorted_candidates:
metadata = data["metadata"]
video_title = metadata.get("video_title", "Untitled Video")
if vid in watched_incomplete_videos:
video_title += " (Incomplete)"
recommendations.append({
"video_id": vid,
"title": video_title,
"description": metadata.get("video_description", ""),
"score": data["total_score"]
})
note_text = "Based on your engagement, here are some recommended videos from the same playlist."
return {"note": note_text, "recommendations": recommendations}
def gradio_recommend_videos(user_id_input):
try:
user_id = int(user_id_input)
except Exception as e:
return f"Error: {e}", ""
result = recommend_videos(user_id)
note_text = result["note"]
recs = result["recommendations"]
if not recs:
return note_text, ""
html_output = "<div>"
# Use black cards with white text and orange border for visibility
for rec in recs:
html_output += f"""
<div style="background: #000; color: #fff; border: 2px solid orange; border-radius: 8px; margin-bottom: 10px; padding: 15px;">
<h3 style="margin-top: 0;">{rec['title']}</h3>
<p style="margin: 0;">{rec['description']}</p>
<p style="margin: 0;"><strong>Score:</strong> {rec['score']:.2f}</p>
</div>
"""
html_output += "</div>"
return note_text, html_output
with gr.Blocks() as demo:
with gr.Tabs():
with gr.TabItem("Playlist Recommendation"):
playlist_input = gr.Textbox(
lines=10,
label="Assessment Data (JSON)",
placeholder='''{
"package": ["Focus", "Insomnia"],
"report": "Based on your responses, you may struggle with focus, anxiety, and burnout..."
}'''
)
playlist_output = gr.HTML(label="Recommended Playlists")
playlist_btn = gr.Button("Get Playlist Recommendations")
playlist_btn.click(fn=gradio_recommend_playlist, inputs=playlist_input, outputs=playlist_output)
with gr.TabItem("Video Recommendation"):
user_id_input = gr.Textbox(lines=1, label="User ID", placeholder="1")
note_output = gr.Textbox(label="Recommendation Note", interactive=False)
videos_output = gr.HTML(label="Recommended Videos")
videos_btn = gr.Button("Get Video Recommendations")
videos_btn.click(fn=gradio_recommend_videos, inputs=user_id_input, outputs=[note_output, videos_output])
with gr.TabItem("User Interaction Ingestion"):
ingest_input = gr.Textbox(
lines=10,
label="User Progress Data (JSON)",
placeholder='''{
"user_id": 1,
"video_id": "abc123",
"rating": 4.5,
"time_spent": 300,
"play_count": 1,
"completed": false
}'''
)
ingest_output = gr.HTML(label="Ingestion Result")
ingest_btn = gr.Button("Ingest Data")
ingest_btn.click(fn=gradio_ingest, inputs=ingest_input, outputs=ingest_output)
demo.launch()
|