Spaces:
Running
Running
File size: 12,606 Bytes
d72e914 4b1e061 d72e914 33a6bdd d72e914 a7653cb ad96991 d72e914 2b48fff ad96991 d72e914 2b48fff ad96991 d72e914 2b48fff ad96991 d72e914 2b48fff ad96991 4b1e061 d72e914 4b1e061 d72e914 2b48fff ad96991 d72e914 4b1e061 d72e914 2b48fff ad96991 d72e914 2b48fff ad96991 04a255f d72e914 04a255f d72e914 2b48fff ad96991 04a255f 2b48fff ad96991 d72e914 04a255f d72e914 2b48fff ad96991 04a255f 2b48fff ad96991 04a255f 2b48fff ad96991 0ceda91 d72e914 0ceda91 ec6dec6 d72e914 4b1e061 d72e914 04a255f 0ceda91 d72e914 04a255f 0ceda91 d72e914 125e9bf d72e914 699fc75 ad96991 d72e914 a7653cb 699fc75 d72e914 |
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 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 |
import gradio as gr
from huggingface_hub import HfApi, create_repo
from huggingface_hub.utils import RepositoryNotFoundError
import os
import tempfile
from src.parser.parser import AppleHealthParser
def create_interface():
"""Create the Gradio interface with OAuth login for Apple Health Landing Zone."""
with gr.Blocks(title="Apple Health Landing Zone") as demo:
gr.Markdown("# Apple Health Landing Zone")
gr.Markdown("Login with your Hugging Face account to create a private dataset for your Apple Health export and an MCP server space.")
# OAuth login
gr.LoginButton()
# User info display
user_info = gr.Markdown("")
# Upload section (initially hidden)
with gr.Column(visible=False) as upload_section:
gr.Markdown("### Upload Apple Health Export")
gr.Markdown("Upload your export.xml file from Apple Health. This will create:")
gr.Markdown("1. A private dataset to store your health data")
gr.Markdown("2. A private space with an MCP server to query your data")
file_input = gr.File(
label="Apple Health export.xml",
file_types=[".xml"],
type="filepath"
)
space_name_input = gr.Textbox(
label="Project Name",
placeholder="my-health-data",
info="Enter a name for your health data project (lowercase, no spaces)"
)
create_btn = gr.Button("Create Private MCP Server", variant="primary")
create_status = gr.Markdown("")
def create_health_landing_zone_with_progress(file_path: str, project_name: str, oauth_token: gr.OAuthToken | None, progress=gr.Progress(track_tqdm=True)) -> str:
"""Wrapper function with progress tracking."""
return create_health_landing_zone(file_path, project_name, oauth_token, progress)
def create_health_landing_zone(file_path: str, project_name: str, oauth_token: gr.OAuthToken | None, progress=None) -> str:
"""Create private dataset and MCP server space for Apple Health data."""
if not oauth_token:
return "β Please login first!"
if not file_path:
return "β Please upload your export.xml file!"
if not project_name:
return "β Please enter a project name!"
try:
if progress is not None:
progress(0.1, desc="π Authenticating...")
# Use the OAuth token
token = oauth_token.token
if not token:
return "β No access token found. Please login again."
api = HfApi(token=token)
# Get the current user's username
user_info = api.whoami()
username = user_info["name"]
# Create dataset repository
dataset_repo_id = f"{username}/{project_name}-data"
space_repo_id = f"{username}/{project_name}-mcp"
if progress is not None:
progress(0.2, desc="π Checking repository availability...")
# Check if repositories already exist
try:
api.repo_info(dataset_repo_id, repo_type="dataset")
return f"β Dataset '{dataset_repo_id}' already exists!"
except RepositoryNotFoundError:
pass
try:
api.repo_info(space_repo_id, repo_type="space")
return f"β Space '{space_repo_id}' already exists!"
except RepositoryNotFoundError:
pass
if progress is not None:
progress(0.3, desc="π Creating private dataset...")
# Create the private dataset
dataset_url = create_repo(
repo_id=dataset_repo_id,
repo_type="dataset",
private=True,
token=token
)
if progress is not None:
progress(0.4, desc="π€ Uploading export.xml...")
# Upload the export.xml file (first commit)
api.upload_file(
path_or_fileobj=file_path,
path_in_repo="export.xml",
repo_id=dataset_repo_id,
repo_type="dataset",
token=token,
commit_message="Initial upload: export.xml"
)
if progress is not None:
progress(0.5, desc="π Creating dataset documentation...")
# Create README for dataset
dataset_readme = f"""# Apple Health Data
This is a private dataset containing Apple Health export data for {username}.
## Files
- `export.xml`: The original Apple Health export file
- `health_data.db`: SQLite database with parsed health data
## Associated MCP Server
- Space: [{space_repo_id}](https://huggingface.co/spaces/{space_repo_id})
## Privacy
This dataset is private and contains personal health information. Do not share access with others.
"""
api.upload_file(
path_or_fileobj=dataset_readme.encode(),
path_in_repo="README.md",
repo_id=dataset_repo_id,
repo_type="dataset",
token=token
)
if progress is not None:
progress(0.6, desc="π Creating MCP server space...")
# Create the MCP server space
space_url = create_repo(
repo_id=space_repo_id,
repo_type="space",
space_sdk="gradio",
private=True,
token=token
)
if progress is not None:
progress(0.7, desc="π¦ Uploading MCP server code...")
# Read MCP server code from mcp_server.py
with open('mcp_server.py', 'r') as f:
mcp_app_content = f.read()
# Upload the MCP server app.py
api.upload_file(
path_or_fileobj=mcp_app_content.encode(),
path_in_repo="app.py",
repo_id=space_repo_id,
repo_type="space",
token=token
)
if progress is not None:
progress(0.8, desc="π Uploading parser dependencies...")
# Upload parser dependencies for auto-parsing functionality
api.upload_file(
path_or_fileobj="src/parser/parser.py",
path_in_repo="src/parser/parser.py",
repo_id=space_repo_id,
repo_type="space",
token=token
)
api.upload_file(
path_or_fileobj="src/parser/models.py",
path_in_repo="src/parser/models.py",
repo_id=space_repo_id,
repo_type="space",
token=token
)
api.upload_file(
path_or_fileobj="src/parser/__init__.py",
path_in_repo="src/parser/__init__.py",
repo_id=space_repo_id,
repo_type="space",
token=token
)
api.upload_file(
path_or_fileobj="src/__init__.py",
path_in_repo="src/__init__.py",
repo_id=space_repo_id,
repo_type="space",
token=token
)
if progress is not None:
progress(0.85, desc="π Creating requirements...")
# Create requirements.txt for the space
requirements_content = """gradio>=5.34.0
huggingface-hub>=0.20.0
pandas>=2.0.0
lxml>=4.9.0
sqlmodel>=0.0.8
tqdm>=4.64.0
"""
api.upload_file(
path_or_fileobj=requirements_content.encode(),
path_in_repo="requirements.txt",
repo_id=space_repo_id,
repo_type="space",
token=token
)
if progress is not None:
progress(0.9, desc="π§ Configuring environment variables...")
# Create space variables for the dataset repo ID
api.add_space_variable(
repo_id=space_repo_id,
key="DATA_REPO",
value=dataset_repo_id,
token=token
)
if progress is not None:
progress(0.95, desc="π Setting up secure access...")
# Add the token as a secret for dataset access
api.add_space_secret(
repo_id=space_repo_id,
key="HF_TOKEN",
value=token,
token=token
)
if progress is not None:
progress(1.0, desc="β
Complete!")
return f"""β
Successfully created your Private Apple Health Dataset and MCP Server!
**Private Dataset:** [{dataset_repo_id}]({dataset_url})
- Your export.xml file has been securely uploaded.
- A SQLite database (health_data.db) will be generated from your data as soon as the MCP Server Space starts.
- Note: it might take several minutes (up to 1 hour or more) to parse your health data depending on the size of your export.xml file.
**MCP Server Space:** [{space_repo_id}]({space_url})
- Query interface for your health data using SQLite
- MCP endpoint configuration included
- Environment variables automatically configured
- It will work until expiration of your oauth token, to make it work permanently, create a new fine-grained token with `read` and `write` permissions to your private health dataset and set it as `HF_TOKEN` secret in the MCP Server Space.
Both repositories are private and only accessible by you.
"""
except Exception as e:
import traceback
error_details = traceback.format_exc()
return f"β Error creating landing zone: {str(e)}\n\nDetails:\n```\n{error_details}\n```"
def update_ui(profile: gr.OAuthProfile | None) -> tuple:
"""Update UI based on login status."""
if profile:
username = profile.username
return (
f"β
Logged in as **{username}**",
gr.update(visible=True)
)
else:
return (
"",
gr.update(visible=False)
)
# Update UI when login state changes
demo.load(update_ui, inputs=None, outputs=[user_info, upload_section])
# Create landing zone button click
create_btn.click(
fn=lambda: gr.update(interactive=False),
outputs=[create_btn]
).then(
fn=create_health_landing_zone_with_progress,
inputs=[file_input, space_name_input],
outputs=[create_status]
).then(
fn=lambda: gr.update(interactive=True),
outputs=[create_btn]
)
return demo
def main():
# Check if running in Hugging Face Spaces
if os.getenv("SPACE_ID"):
# Running in Spaces, launch with appropriate settings
demo = create_interface()
demo.launch()
else:
# Running locally, note that OAuth won't work
print("Note: OAuth login only works when deployed to Hugging Face Spaces.")
print("To test locally, deploy this as a Space with hf_oauth: true in README.md")
demo = create_interface()
demo.launch()
if __name__ == "__main__":
main() |