Download app.py from maxxcarl/pool: direct link, hf CLI and curl.
- Browser
- Download file 35.2 kB
-
https://huggingface.co/spaces/maxxcarl/pool/resolve/main/app.py
- Command line
-
hf download hf://spaces/maxxcarl/pool/app.py
-
curl -L -o app.py https://huggingface.co/spaces/maxxcarl/pool/resolve/main/app.py
35.2 kB
| import os | |
| import tempfile | |
| from typing import Any | |
| import gradio as gr | |
| import httpx | |
| # NOTE: 0.0.0.0 is a bind address, not a connect address. | |
| # Use 127.0.0.1 by default and allow overrides for deployments. | |
| BASE_URL = os.getenv("API_BASE_URL", "http://127.0.0.1:7860") | |
| def _public_base_url(request: gr.Request | None) -> str: | |
| if request is None: | |
| return os.getenv("PUBLIC_BASE_URL", "").rstrip("/") | |
| headers = {k.lower(): v for k, v in dict(request.headers).items()} | |
| origin = headers.get("origin") | |
| if origin: | |
| return origin.rstrip("/") | |
| proto = headers.get("x-forwarded-proto") | |
| host = headers.get("x-forwarded-host") or headers.get("host") | |
| if proto and host: | |
| return f"{proto}://{host}".rstrip("/") | |
| if host: | |
| return f"https://{host}".rstrip("/") | |
| return os.getenv("PUBLIC_BASE_URL", "").rstrip("/") | |
| def create_gradio_app(): | |
| """Create and return the Gradio Blocks app for Music Memories.""" | |
| def _maybe_int(value: Any) -> int | None: | |
| if value is None: | |
| return None | |
| try: | |
| return int(value) | |
| except Exception: | |
| return None | |
| def _json_request( | |
| method: str, | |
| path: str, | |
| *, | |
| params: dict[str, Any] | None = None, | |
| data: dict[str, Any] | None = None, | |
| files: dict[str, Any] | None = None, | |
| follow_redirects: bool = True, | |
| timeout: float = 15.0, | |
| ) -> dict[str, Any]: | |
| url = f"{BASE_URL}{path}" | |
| with httpx.Client(follow_redirects=follow_redirects, timeout=timeout) as client: | |
| resp = client.request(method, url, params=params, data=data, files=files) | |
| resp.raise_for_status() | |
| return resp.json() | |
| def _redirect_location(path: str, *, params: dict[str, Any] | None = None) -> str: | |
| url = f"{BASE_URL}{path}" | |
| with httpx.Client(follow_redirects=False, timeout=15.0) as client: | |
| resp = client.get(url, params=params) | |
| if resp.status_code in (301, 302, 303, 307, 308): | |
| return resp.headers.get("location") or "" | |
| resp.raise_for_status() | |
| return "" | |
| def add_song_fn(title, artist, album, duration, bpm, energy_level, lyrics, audio_path): | |
| try: | |
| # /songs expects multipart/form-data (Form fields + optional file). | |
| data: dict[str, Any] = {"title": title, "artist": artist} | |
| if album: | |
| data["album"] = album | |
| duration_i = _maybe_int(duration) | |
| if duration_i is not None: | |
| data["duration"] = str(duration_i) | |
| bpm_i = _maybe_int(bpm) | |
| if bpm_i is not None: | |
| data["bpm"] = str(bpm_i) | |
| energy_i = _maybe_int(energy_level) | |
| if energy_i is not None: | |
| data["energy_level"] = str(energy_i) | |
| if lyrics: | |
| data["lyrics"] = lyrics | |
| if audio_path: | |
| filename = os.path.basename(str(audio_path)) | |
| with open(str(audio_path), "rb") as f: | |
| files = {"audio_file": (filename, f, "audio/mpeg")} | |
| out = _json_request("POST", "/songs", data=data, files=files) | |
| else: | |
| out = _json_request("POST", "/songs", data=data) | |
| return "Success!", out | |
| except Exception as e: | |
| return "Error", {"error": str(e)} | |
| def add_user_fn(name): | |
| try: | |
| out = _json_request("POST", "/users", params={"name": name}, timeout=10.0) | |
| return "Success!", out | |
| except Exception as e: | |
| return "Error", {"error": str(e)} | |
| def add_memory_fn(user_id, description, date, song_id): | |
| try: | |
| params: dict[str, Any] = {"user_id": _maybe_int(user_id), "description": description} | |
| if params["user_id"] is None: | |
| raise ValueError("user_id is required") | |
| if date: | |
| params["date"] = date | |
| song_id_i = _maybe_int(song_id) | |
| if song_id_i is not None: | |
| params["song_id"] = song_id_i | |
| out = _json_request("POST", "/memories", params=params) | |
| return "Success!", out | |
| except Exception as e: | |
| return "Error", {"error": str(e)} | |
| def add_playlist_fn(name, vibe_code, mood_description): | |
| try: | |
| params: dict[str, Any] = {"name": name} | |
| if vibe_code: | |
| params["vibe_code"] = vibe_code | |
| if mood_description: | |
| params["mood_description"] = mood_description | |
| out = _json_request("POST", "/playlists", params=params) | |
| return "Success!", out | |
| except Exception as e: | |
| return "Error", {"error": str(e)} | |
| def add_context_fn(weather, time_of_day, location_type): | |
| try: | |
| params: dict[str, Any] = {} | |
| if weather: | |
| params["weather"] = weather | |
| if time_of_day: | |
| params["time_of_day"] = time_of_day | |
| if location_type: | |
| params["location_type"] = location_type | |
| out = _json_request("POST", "/contexts", params=params, timeout=10.0) | |
| return "Success!", out | |
| except Exception as e: | |
| return "Error", {"error": str(e)} | |
| def get_song_fn(song_id): | |
| try: | |
| song_id_i = _maybe_int(song_id) | |
| if song_id_i is None: | |
| raise ValueError("song_id is required") | |
| out = _json_request("GET", f"/songs/{song_id_i}") | |
| return "Success!", out | |
| except Exception as e: | |
| return "Error", {"error": str(e)} | |
| def delete_song_fn(song_id): | |
| try: | |
| song_id_i = _maybe_int(song_id) | |
| if song_id_i is None: | |
| raise ValueError("song_id is required") | |
| out = _json_request("DELETE", f"/songs/{song_id_i}") | |
| return "Success!", out | |
| except Exception as e: | |
| return "Error", {"error": str(e)} | |
| def upload_song_audio_fn(song_id, audio_path): | |
| try: | |
| song_id_i = _maybe_int(song_id) | |
| if song_id_i is None: | |
| raise ValueError("song_id is required") | |
| if not audio_path: | |
| raise ValueError("audio file is required") | |
| filename = os.path.basename(str(audio_path)) | |
| with open(str(audio_path), "rb") as f: | |
| files = {"audio_file": (filename, f, "audio/mpeg")} | |
| out = _json_request("POST", f"/songs/{song_id_i}/upload-audio", files=files) | |
| return "Success!", out | |
| except Exception as e: | |
| return "Error", {"error": str(e)} | |
| def song_stream_url_fn(song_id, request: gr.Request | None = None): | |
| try: | |
| song_id_i = _maybe_int(song_id) | |
| if song_id_i is None: | |
| raise ValueError("song_id is required") | |
| public_base = _public_base_url(request) | |
| if public_base: | |
| return "Success!", f"{public_base}/songs/{song_id_i}/stream" | |
| return "Success!", f"/songs/{song_id_i}/stream" | |
| except Exception as e: | |
| return "Error", str(e) | |
| def song_download_fn(song_id): | |
| try: | |
| song_id_i = _maybe_int(song_id) | |
| if song_id_i is None: | |
| raise ValueError("song_id is required") | |
| url = f"{BASE_URL}/songs/{song_id_i}/download" | |
| with httpx.Client(timeout=30.0) as client: | |
| resp = client.get(url) | |
| resp.raise_for_status() | |
| tmp = tempfile.NamedTemporaryFile(delete=False, suffix=".mp3") | |
| tmp.write(resp.content) | |
| tmp.flush() | |
| tmp.close() | |
| return "Success!", tmp.name | |
| except Exception as e: | |
| return "Error", None | |
| def get_user_fn(user_id): | |
| try: | |
| user_id_i = _maybe_int(user_id) | |
| if user_id_i is None: | |
| raise ValueError("user_id is required") | |
| out = _json_request("GET", f"/users/{user_id_i}") | |
| return "Success!", out | |
| except Exception as e: | |
| return "Error", {"error": str(e)} | |
| def list_user_memories_fn(user_id): | |
| try: | |
| user_id_i = _maybe_int(user_id) | |
| if user_id_i is None: | |
| raise ValueError("user_id is required") | |
| data = _json_request("GET", f"/users/{user_id_i}/memories", timeout=10.0) | |
| memories = data.get("memories", []) | |
| table = [[m.get("id"), m.get("user_id"), (m.get("description") or "")[:50], m.get("date", "")] for m in memories] | |
| return f"Found {len(memories)} memories", table | |
| except Exception as e: | |
| return "Error", [] | |
| def user_activity_fn(user_id, limit, action_type): | |
| try: | |
| user_id_i = _maybe_int(user_id) | |
| if user_id_i is None: | |
| raise ValueError("user_id is required") | |
| params: dict[str, Any] = {} | |
| limit_i = _maybe_int(limit) | |
| if limit_i is not None: | |
| params["limit"] = limit_i | |
| if action_type: | |
| params["action_type"] = action_type | |
| out = _json_request("GET", f"/users/{user_id_i}/activity", params=params) | |
| return "Success!", out | |
| except Exception as e: | |
| return "Error", {"error": str(e)} | |
| def delete_playlist_fn(playlist_id): | |
| try: | |
| playlist_id_i = _maybe_int(playlist_id) | |
| if playlist_id_i is None: | |
| raise ValueError("playlist_id is required") | |
| out = _json_request("DELETE", f"/playlists/{playlist_id_i}") | |
| return "Success!", out | |
| except Exception as e: | |
| return "Error", {"error": str(e)} | |
| def list_playlists_fn(): | |
| try: | |
| data = _json_request("GET", "/playlists", timeout=10.0) | |
| playlists = data.get("playlists", []) | |
| return [[p.get("id"), p.get("name"), p.get("vibe_code", "")] for p in playlists] | |
| except Exception as e: | |
| return [["Error", str(e), ""]] | |
| def delete_memory_fn(memory_id): | |
| try: | |
| memory_id_i = _maybe_int(memory_id) | |
| if memory_id_i is None: | |
| raise ValueError("memory_id is required") | |
| out = _json_request("DELETE", f"/memories/{memory_id_i}") | |
| return "Success!", out | |
| except Exception as e: | |
| return "Error", {"error": str(e)} | |
| def list_contexts_fn(): | |
| try: | |
| data = _json_request("GET", "/contexts", timeout=10.0) | |
| contexts = data.get("contexts", []) | |
| return [[c.get("id"), c.get("weather", ""), c.get("time_of_day", ""), c.get("location_type", "")] for c in contexts] | |
| except Exception as e: | |
| return [["Error", str(e), "", ""]] | |
| def delete_context_fn(context_id): | |
| try: | |
| context_id_i = _maybe_int(context_id) | |
| if context_id_i is None: | |
| raise ValueError("context_id is required") | |
| out = _json_request("DELETE", f"/contexts/{context_id_i}") | |
| return "Success!", out | |
| except Exception as e: | |
| return "Error", {"error": str(e)} | |
| def search_songs_fn(query, n_results): | |
| try: | |
| data = _json_request("GET", "/search/songs", params={"q": query, "n": n_results}, timeout=15.0) | |
| results = data.get("results", []) | |
| table = [[r.get("id"), r.get("title"), r.get("artist"), f"{float(r.get('distance', 0.0)):.4f}"] for r in results] if results else [] | |
| return f"Found {len(results)} songs", table | |
| except Exception as e: | |
| return "Error", [] | |
| def search_memories_fn(query, n_results): | |
| try: | |
| data = _json_request("GET", "/search/memories", params={"q": query, "n": n_results}, timeout=15.0) | |
| results = data.get("results", []) | |
| table = [[r.get("id"), r.get("user_id"), (r.get("document") or "")[:50], f"{float(r.get('distance', 0.0)):.4f}"] for r in results] if results else [] | |
| return f"Found {len(results)} memories", table | |
| except Exception as e: | |
| return "Error", [] | |
| def search_contexts_fn(query, n_results): | |
| try: | |
| data = _json_request("GET", "/search/contexts", params={"q": query, "n": n_results}, timeout=15.0) | |
| results = data.get("results", []) | |
| table = [[r.get("id"), r.get("weather"), r.get("time_of_day"), r.get("location_type"), f"{float(r.get('distance', 0.0)):.4f}"] for r in results] if results else [] | |
| return f"Found {len(results)} contexts", table | |
| except Exception: | |
| return "Error", [] | |
| def search_playlists_fn(query, n_results): | |
| try: | |
| data = _json_request("GET", "/search/playlists", params={"q": query, "n": n_results}, timeout=15.0) | |
| results = data.get("results", []) | |
| table = [[r.get("id"), r.get("name"), f"{float(r.get('distance', 0.0)):.4f}"] for r in results] if results else [] | |
| return f"Found {len(results)} playlists", table | |
| except Exception as e: | |
| return "Error", [] | |
| def list_songs_fn(): | |
| try: | |
| data = _json_request("GET", "/songs", timeout=10.0) | |
| songs = data.get("songs", []) | |
| return [[s.get("id"), s.get("title"), s.get("artist"), s.get("album", ""), s.get("bpm", ""), s.get("has_audio"), s.get("play_count")] for s in songs] | |
| except Exception as e: | |
| return [["Error", str(e), "", "", "", "", ""]] | |
| def list_users_fn(): | |
| try: | |
| data = _json_request("GET", "/users", timeout=10.0) | |
| users = data.get("users", []) | |
| return [[u.get("id"), u.get("name"), u.get("created_at", "")] for u in users] | |
| except Exception as e: | |
| return [["Error", str(e), ""]] | |
| def list_memories_fn(): | |
| try: | |
| data = _json_request("GET", "/memories", timeout=10.0) | |
| memories = data.get("memories", []) | |
| return [[m.get("id"), m.get("user_id"), (m.get("description") or "")[:50], m.get("date", ""), m.get("song_id", "")] for m in memories] | |
| except Exception as e: | |
| return [["Error", str(e), "", "", ""]] | |
| def list_history_fn(user_id, limit): | |
| try: | |
| params: dict[str, Any] = {} | |
| user_id_i = _maybe_int(user_id) | |
| if user_id_i is not None: | |
| params["user_id"] = user_id_i | |
| limit_i = _maybe_int(limit) | |
| if limit_i is not None: | |
| params["limit"] = limit_i | |
| out = _json_request("GET", "/history", params=params, timeout=20.0) | |
| return "Success!", out | |
| except Exception as e: | |
| return "Error", {"error": str(e)} | |
| def add_history_fn(user_id, song_id, context_id, duration_seconds): | |
| try: | |
| params: dict[str, Any] = {} | |
| user_id_i = _maybe_int(user_id) | |
| song_id_i = _maybe_int(song_id) | |
| if user_id_i is None or song_id_i is None: | |
| raise ValueError("user_id and song_id are required") | |
| params["user_id"] = user_id_i | |
| params["song_id"] = song_id_i | |
| context_id_i = _maybe_int(context_id) | |
| if context_id_i is not None: | |
| params["context_id"] = context_id_i | |
| dur_i = _maybe_int(duration_seconds) | |
| if dur_i is not None: | |
| params["duration_seconds"] = dur_i | |
| out = _json_request("POST", "/history", params=params, timeout=20.0) | |
| return "Success!", out | |
| except Exception as e: | |
| return "Error", {"error": str(e)} | |
| def analytics_summary_fn(hours): | |
| try: | |
| hours_i = _maybe_int(hours) | |
| params = {"hours": hours_i} if hours_i is not None else {} | |
| out = _json_request("GET", "/analytics/summary", params=params, timeout=20.0) | |
| return "Success!", out | |
| except Exception as e: | |
| return "Error", {"error": str(e)} | |
| def analytics_top_songs_fn(limit): | |
| try: | |
| limit_i = _maybe_int(limit) | |
| params = {"limit": limit_i} if limit_i is not None else {} | |
| out = _json_request("GET", "/analytics/top-songs", params=params, timeout=20.0) | |
| return "Success!", out | |
| except Exception as e: | |
| return "Error", {"error": str(e)} | |
| def analytics_popular_searches_fn(hours, limit): | |
| try: | |
| params: dict[str, Any] = {} | |
| hours_i = _maybe_int(hours) | |
| limit_i = _maybe_int(limit) | |
| if hours_i is not None: | |
| params["hours"] = hours_i | |
| if limit_i is not None: | |
| params["limit"] = limit_i | |
| out = _json_request("GET", "/analytics/popular-searches", params=params, timeout=20.0) | |
| return "Success!", out | |
| except Exception as e: | |
| return "Error", {"error": str(e)} | |
| def storage_files_fn(): | |
| try: | |
| out = _json_request("GET", "/storage/files", timeout=20.0) | |
| files = out.get("files", []) | |
| table = [[f.get("object_name"), f.get("size"), f.get("last_modified")] for f in files] | |
| return f"Found {len(files)} files", table | |
| except Exception as e: | |
| return "Error", [] | |
| def health_fn(): | |
| try: | |
| out = _json_request("GET", "/health", timeout=10.0) | |
| return "Success!", out | |
| except Exception as e: | |
| return "Error", {"error": str(e)} | |
| def root_fn(): | |
| try: | |
| out = _json_request("GET", "/", timeout=10.0) | |
| return "Success!", out | |
| except Exception as e: | |
| return "Error", {"error": str(e)} | |
| with gr.Blocks(title="Music Memories UI") as demo: | |
| gr.Markdown("# 🎵 Music Memories") | |
| gr.Markdown("Manage your music library, memories, and playlists with semantic search.") | |
| with gr.Tab("🎶 Songs"): | |
| with gr.Group(): | |
| gr.Markdown("### Add Song") | |
| song_title = gr.Textbox(label="Title", placeholder="Song title") | |
| song_artist = gr.Textbox(label="Artist", placeholder="Artist name") | |
| song_album = gr.Textbox(label="Album", placeholder="Album (optional)") | |
| song_duration = gr.Number(label="Duration (seconds)", precision=0) | |
| song_bpm = gr.Number(label="BPM", precision=0) | |
| song_energy = gr.Slider(1, 10, value=5, label="Energy Level") | |
| song_lyrics = gr.Textbox(label="Lyrics", placeholder="Lyrics for semantic search", lines=3) | |
| song_audio = gr.File(label="Audio File (MP3, optional)", file_types=[".mp3"], type="filepath") | |
| song_add_btn = gr.Button("Add Song") | |
| song_add_status = gr.Textbox(label="Status") | |
| song_add_output = gr.JSON(label="Response") | |
| song_add_btn.click( | |
| fn=add_song_fn, | |
| inputs=[song_title, song_artist, song_album, song_duration, song_bpm, song_energy, song_lyrics, song_audio], | |
| outputs=[song_add_status, song_add_output], | |
| ) | |
| with gr.Group(): | |
| gr.Markdown("### Get / Delete Song") | |
| song_id = gr.Number(label="Song ID", precision=0) | |
| song_get_btn = gr.Button("Get Song") | |
| song_del_btn = gr.Button("Delete Song") | |
| song_action_status = gr.Textbox(label="Status") | |
| song_action_output = gr.JSON(label="Response") | |
| song_get_btn.click(fn=get_song_fn, inputs=[song_id], outputs=[song_action_status, song_action_output]) | |
| song_del_btn.click(fn=delete_song_fn, inputs=[song_id], outputs=[song_action_status, song_action_output]) | |
| with gr.Group(): | |
| gr.Markdown("### Audio: Upload / Stream / Download") | |
| audio_song_id = gr.Number(label="Song ID", precision=0) | |
| audio_upload = gr.File(label="MP3 File", file_types=[".mp3"], type="filepath") | |
| audio_upload_btn = gr.Button("Upload/Update Audio") | |
| audio_upload_status = gr.Textbox(label="Status") | |
| audio_upload_output = gr.JSON(label="Response") | |
| audio_upload_btn.click( | |
| fn=upload_song_audio_fn, | |
| inputs=[audio_song_id, audio_upload], | |
| outputs=[audio_upload_status, audio_upload_output], | |
| ) | |
| stream_btn = gr.Button("Get Stream URL") | |
| stream_status = gr.Textbox(label="Status") | |
| stream_url = gr.Textbox(label="Presigned Stream URL") | |
| stream_btn.click(fn=song_stream_url_fn, inputs=[audio_song_id], outputs=[stream_status, stream_url]) | |
| download_btn = gr.Button("Download MP3 via API") | |
| download_status = gr.Textbox(label="Status") | |
| download_file = gr.File(label="Downloaded File") | |
| download_btn.click(fn=song_download_fn, inputs=[audio_song_id], outputs=[download_status, download_file]) | |
| with gr.Group(): | |
| gr.Markdown("### All Songs") | |
| songs_table = gr.Dataframe(headers=["ID", "Title", "Artist", "Album", "BPM", "Has Audio", "Play Count"], label="Songs") | |
| songs_load_btn = gr.Button("Load Songs") | |
| songs_load_btn.click(fn=list_songs_fn, outputs=songs_table) | |
| with gr.Tab("👤 Users"): | |
| with gr.Group(): | |
| gr.Markdown("### Add User") | |
| user_name = gr.Textbox(label="Name", placeholder="User name") | |
| user_add_btn = gr.Button("Add User") | |
| user_add_status = gr.Textbox(label="Status") | |
| user_add_output = gr.JSON(label="Response") | |
| user_add_btn.click(fn=add_user_fn, inputs=user_name, outputs=[user_add_status, user_add_output]) | |
| with gr.Group(): | |
| gr.Markdown("### Get User") | |
| get_user_id = gr.Number(label="User ID", precision=0) | |
| get_user_btn = gr.Button("Get User") | |
| get_user_status = gr.Textbox(label="Status") | |
| get_user_output = gr.JSON(label="Response") | |
| get_user_btn.click(fn=get_user_fn, inputs=[get_user_id], outputs=[get_user_status, get_user_output]) | |
| with gr.Group(): | |
| gr.Markdown("### User Memories") | |
| um_user_id = gr.Number(label="User ID", precision=0) | |
| um_btn = gr.Button("Load User Memories") | |
| um_summary = gr.Textbox(label="Results") | |
| um_table = gr.Dataframe(headers=["ID", "User ID", "Description", "Date"], label="Memories") | |
| um_btn.click(fn=list_user_memories_fn, inputs=[um_user_id], outputs=[um_summary, um_table]) | |
| with gr.Group(): | |
| gr.Markdown("### User Activity") | |
| ua_user_id = gr.Number(label="User ID", precision=0) | |
| ua_limit = gr.Number(label="Limit", value=50, precision=0) | |
| ua_action_type = gr.Textbox(label="Action Type (optional)") | |
| ua_btn = gr.Button("Load Activity") | |
| ua_status = gr.Textbox(label="Status") | |
| ua_output = gr.JSON(label="Response") | |
| ua_btn.click(fn=user_activity_fn, inputs=[ua_user_id, ua_limit, ua_action_type], outputs=[ua_status, ua_output]) | |
| with gr.Group(): | |
| gr.Markdown("### All Users") | |
| users_table = gr.Dataframe(headers=["ID", "Name", "Created At"], label="Users") | |
| users_load_btn = gr.Button("Load Users") | |
| users_load_btn.click(fn=list_users_fn, outputs=users_table) | |
| with gr.Tab("💭 Memories"): | |
| with gr.Group(): | |
| gr.Markdown("### Add Memory") | |
| mem_user_id = gr.Number(label="User ID", precision=0) | |
| mem_desc = gr.Textbox(label="Description", placeholder="Describe the memory...", lines=2) | |
| mem_date = gr.Textbox(label="Date (optional)", placeholder="YYYY-MM-DD") | |
| mem_song_id = gr.Number(label="Song ID (optional)", precision=0) | |
| mem_add_btn = gr.Button("Add Memory") | |
| mem_add_status = gr.Textbox(label="Status") | |
| mem_add_output = gr.JSON(label="Response") | |
| mem_add_btn.click(fn=add_memory_fn, inputs=[mem_user_id, mem_desc, mem_date, mem_song_id], outputs=[mem_add_status, mem_add_output]) | |
| with gr.Group(): | |
| gr.Markdown("### Delete Memory") | |
| del_mem_id = gr.Number(label="Memory ID", precision=0) | |
| del_mem_btn = gr.Button("Delete") | |
| del_mem_status = gr.Textbox(label="Status") | |
| del_mem_output = gr.JSON(label="Response") | |
| del_mem_btn.click(fn=delete_memory_fn, inputs=[del_mem_id], outputs=[del_mem_status, del_mem_output]) | |
| with gr.Group(): | |
| gr.Markdown("### All Memories") | |
| memories_table = gr.Dataframe(headers=["ID", "User ID", "Description", "Date", "Song ID"], label="Memories") | |
| memories_load_btn = gr.Button("Load Memories") | |
| memories_load_btn.click(fn=list_memories_fn, outputs=memories_table) | |
| with gr.Tab("🎵 Playlists"): | |
| with gr.Group(): | |
| gr.Markdown("### Add Playlist") | |
| pl_name = gr.Textbox(label="Name", placeholder="Playlist name") | |
| pl_vibe = gr.Textbox(label="Vibe Code", placeholder="e.g., chill, energetic") | |
| pl_mood = gr.Textbox(label="Mood Description", placeholder="Describe the mood journey...", lines=2) | |
| pl_add_btn = gr.Button("Add Playlist") | |
| pl_add_status = gr.Textbox(label="Status") | |
| pl_add_output = gr.JSON(label="Response") | |
| pl_add_btn.click(fn=add_playlist_fn, inputs=[pl_name, pl_vibe, pl_mood], outputs=[pl_add_status, pl_add_output]) | |
| with gr.Group(): | |
| gr.Markdown("### All Playlists") | |
| playlists_table = gr.Dataframe(headers=["ID", "Name", "Vibe Code"], label="Playlists") | |
| playlists_load_btn = gr.Button("Load Playlists") | |
| playlists_load_btn.click(fn=list_playlists_fn, outputs=playlists_table) | |
| with gr.Group(): | |
| gr.Markdown("### Delete Playlist") | |
| del_pl_id = gr.Number(label="Playlist ID", precision=0) | |
| del_pl_btn = gr.Button("Delete") | |
| del_pl_status = gr.Textbox(label="Status") | |
| del_pl_output = gr.JSON(label="Response") | |
| del_pl_btn.click(fn=delete_playlist_fn, inputs=[del_pl_id], outputs=[del_pl_status, del_pl_output]) | |
| with gr.Tab("🌤️ Contexts"): | |
| with gr.Group(): | |
| gr.Markdown("### Add Context") | |
| ctx_weather = gr.Textbox(label="Weather", placeholder="e.g., rainy, sunny") | |
| ctx_time = gr.Textbox(label="Time of Day", placeholder="e.g., morning, night") | |
| ctx_location = gr.Textbox(label="Location Type", placeholder="e.g., home, gym, car") | |
| ctx_add_btn = gr.Button("Add Context") | |
| ctx_add_status = gr.Textbox(label="Status") | |
| ctx_add_output = gr.JSON(label="Response") | |
| ctx_add_btn.click(fn=add_context_fn, inputs=[ctx_weather, ctx_time, ctx_location], outputs=[ctx_add_status, ctx_add_output]) | |
| with gr.Group(): | |
| gr.Markdown("### All Contexts") | |
| ctx_table = gr.Dataframe(headers=["ID", "Weather", "Time of Day", "Location"], label="Contexts") | |
| ctx_load_btn = gr.Button("Load Contexts") | |
| ctx_load_btn.click(fn=list_contexts_fn, outputs=ctx_table) | |
| with gr.Group(): | |
| gr.Markdown("### Delete Context") | |
| del_ctx_id = gr.Number(label="Context ID", precision=0) | |
| del_ctx_btn = gr.Button("Delete") | |
| del_ctx_status = gr.Textbox(label="Status") | |
| del_ctx_output = gr.JSON(label="Response") | |
| del_ctx_btn.click(fn=delete_context_fn, inputs=[del_ctx_id], outputs=[del_ctx_status, del_ctx_output]) | |
| with gr.Tab("🔍 Semantic Search"): | |
| with gr.Group(): | |
| gr.Markdown("### Search Songs by Vibe") | |
| search_songs_query = gr.Textbox(label="Query", placeholder="e.g., 'sad breakup song', 'workout energy'") | |
| search_songs_n = gr.Slider(1, 20, value=5, step=1, label="Results") | |
| search_songs_btn = gr.Button("Search") | |
| search_songs_summary = gr.Textbox(label="Results") | |
| search_songs_table = gr.Dataframe(headers=["ID", "Title", "Artist", "Distance"], label="Songs") | |
| search_songs_btn.click(fn=search_songs_fn, inputs=[search_songs_query, search_songs_n], outputs=[search_songs_summary, search_songs_table]) | |
| with gr.Group(): | |
| gr.Markdown("### Search Memories") | |
| search_mem_query = gr.Textbox(label="Query", placeholder="e.g., 'summer road trip', 'first dance'") | |
| search_mem_n = gr.Slider(1, 20, value=5, step=1, label="Results") | |
| search_mem_btn = gr.Button("Search") | |
| search_mem_summary = gr.Textbox(label="Results") | |
| search_mem_table = gr.Dataframe(headers=["ID", "User ID", "Description", "Distance"], label="Memories") | |
| search_mem_btn.click(fn=search_memories_fn, inputs=[search_mem_query, search_mem_n], outputs=[search_mem_summary, search_mem_table]) | |
| with gr.Group(): | |
| gr.Markdown("### Search Contexts") | |
| search_ctx_query = gr.Textbox(label="Query", placeholder="e.g., 'rainy night drive', 'sunny beach'") | |
| search_ctx_n = gr.Slider(1, 20, value=5, step=1, label="Results") | |
| search_ctx_btn = gr.Button("Search") | |
| search_ctx_summary = gr.Textbox(label="Results") | |
| search_ctx_table = gr.Dataframe(headers=["ID", "Weather", "Time", "Location", "Distance"], label="Contexts") | |
| search_ctx_btn.click(fn=search_contexts_fn, inputs=[search_ctx_query, search_ctx_n], outputs=[search_ctx_summary, search_ctx_table]) | |
| with gr.Group(): | |
| gr.Markdown("### Search Playlists by Mood") | |
| search_pl_query = gr.Textbox(label="Query", placeholder="e.g., 'chill evening vibes', 'party energy'") | |
| search_pl_n = gr.Slider(1, 20, value=5, step=1, label="Results") | |
| search_pl_btn = gr.Button("Search") | |
| search_pl_summary = gr.Textbox(label="Results") | |
| search_pl_table = gr.Dataframe(headers=["ID", "Name", "Distance"], label="Playlists") | |
| search_pl_btn.click(fn=search_playlists_fn, inputs=[search_pl_query, search_pl_n], outputs=[search_pl_summary, search_pl_table]) | |
| with gr.Tab("ℹ️ Health"): | |
| with gr.Group(): | |
| gr.Markdown("### Root") | |
| root_btn = gr.Button("GET /") | |
| root_status = gr.Textbox(label="Status") | |
| root_output = gr.JSON(label="Response") | |
| root_btn.click(fn=root_fn, outputs=[root_status, root_output]) | |
| with gr.Group(): | |
| gr.Markdown("### Health") | |
| health_btn = gr.Button("GET /health") | |
| health_status = gr.Textbox(label="Status") | |
| health_output = gr.JSON(label="Response") | |
| health_btn.click(fn=health_fn, outputs=[health_status, health_output]) | |
| with gr.Tab("▶️ History"): | |
| with gr.Group(): | |
| gr.Markdown("### List History") | |
| hist_user_id = gr.Number(label="User ID (optional)", precision=0) | |
| hist_limit = gr.Number(label="Limit", value=50, precision=0) | |
| hist_list_btn = gr.Button("Load History") | |
| hist_status = gr.Textbox(label="Status") | |
| hist_output = gr.JSON(label="Response") | |
| hist_list_btn.click(fn=list_history_fn, inputs=[hist_user_id, hist_limit], outputs=[hist_status, hist_output]) | |
| with gr.Group(): | |
| gr.Markdown("### Add Play Event") | |
| hist_add_user = gr.Number(label="User ID", precision=0) | |
| hist_add_song = gr.Number(label="Song ID", precision=0) | |
| hist_add_ctx = gr.Number(label="Context ID (optional)", precision=0) | |
| hist_add_dur = gr.Number(label="Duration Seconds (optional)", precision=0) | |
| hist_add_btn = gr.Button("Add History") | |
| hist_add_status = gr.Textbox(label="Status") | |
| hist_add_output = gr.JSON(label="Response") | |
| hist_add_btn.click( | |
| fn=add_history_fn, | |
| inputs=[hist_add_user, hist_add_song, hist_add_ctx, hist_add_dur], | |
| outputs=[hist_add_status, hist_add_output], | |
| ) | |
| with gr.Tab("📊 Analytics"): | |
| with gr.Group(): | |
| gr.Markdown("### Summary") | |
| an_hours = gr.Number(label="Hours", value=24, precision=0) | |
| an_sum_btn = gr.Button("Get Summary") | |
| an_sum_status = gr.Textbox(label="Status") | |
| an_sum_output = gr.JSON(label="Response") | |
| an_sum_btn.click(fn=analytics_summary_fn, inputs=[an_hours], outputs=[an_sum_status, an_sum_output]) | |
| with gr.Group(): | |
| gr.Markdown("### Top Songs") | |
| an_limit = gr.Number(label="Limit", value=10, precision=0) | |
| an_top_btn = gr.Button("Get Top Songs") | |
| an_top_status = gr.Textbox(label="Status") | |
| an_top_output = gr.JSON(label="Response") | |
| an_top_btn.click(fn=analytics_top_songs_fn, inputs=[an_limit], outputs=[an_top_status, an_top_output]) | |
| with gr.Group(): | |
| gr.Markdown("### Popular Searches") | |
| ps_hours = gr.Number(label="Hours", value=24, precision=0) | |
| ps_limit = gr.Number(label="Limit", value=10, precision=0) | |
| ps_btn = gr.Button("Get Popular Searches") | |
| ps_status = gr.Textbox(label="Status") | |
| ps_output = gr.JSON(label="Response") | |
| ps_btn.click(fn=analytics_popular_searches_fn, inputs=[ps_hours, ps_limit], outputs=[ps_status, ps_output]) | |
| with gr.Group(): | |
| gr.Markdown("### Storage Files") | |
| sf_btn = gr.Button("List MP3 Files") | |
| sf_summary = gr.Textbox(label="Results") | |
| sf_table = gr.Dataframe(headers=["Object", "Size", "Last Modified"], label="Files") | |
| sf_btn.click(fn=storage_files_fn, outputs=[sf_summary, sf_table]) | |
| return demo | |
| # Create the Gradio app instance | |
| gradio_app = create_gradio_app() | |
| if __name__ == "__main__": | |
| gradio_app.launch(share=False, server_name="0.0.0.0", server_port=7860) | |