Spaces:
Paused
Paused
File size: 4,220 Bytes
d958e80 | 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 | import qrcode
import io
import base64
from datetime import datetime
from fastapi import Request
from fastapi.templating import Jinja2Templates
from fastapi.responses import HTMLResponse
from app.config import Settings
from app.session_store import create_session, get_session
from app.security import create_worker_join_token
# Use a simple in-memory template for v1; Jinja2 templates directory if present
templates = Jinja2Templates(directory="app/templates")
def render_home(request: Request) -> HTMLResponse:
return HTMLResponse(content=_home_html(), status_code=200)
def render_worker_page(request: Request, session_id: str, token: str) -> HTMLResponse:
return HTMLResponse(content=_worker_html(session_id, token), status_code=200)
def render_session_dashboard(request: Request, session_id: str) -> HTMLResponse:
session = get_session(session_id)
if not session:
return HTMLResponse(content="<h1>Session not found</h1>", status_code=404)
public_url = Settings.get_public_url()
worker_url = f"{public_url}/worker?session_id={session_id}&token={session.secret}"
qr_b64 = make_worker_qr_code(worker_url)
html = _dashboard_html(session_id, worker_url, qr_b64)
return HTMLResponse(content=html, status_code=200)
def make_worker_qr_code(worker_join_url: str) -> str:
img = qrcode.make(worker_join_url)
buf = io.BytesIO()
img.save(buf, format="PNG")
buf.seek(0)
return base64.b64encode(buf.read()).decode()
def make_api_example(session_id: str) -> dict:
public_url = Settings.get_public_url()
return {
"create_job": f"POST {public_url}/api/session/{session_id}/job",
"get_job": f"GET {public_url}/api/job/{{job_id}}",
"get_receipt": f"GET {public_url}/api/receipt/{{receipt_id}}",
}
def _home_html() -> str:
return """<!DOCTYPE html>
<html>
<head><title>PhoneGPU Space</title>
<style>
body{font-family:sans-serif;max-width:800px;margin:40px auto;padding:0 20px}
button{padding:12px 24px;font-size:16px;cursor:pointer;border-radius:6px;border:none;background:#2563eb;color:#fff}
.code{background:#f3f4f6;padding:12px;border-radius:6px;font-family:monospace;overflow:auto}
</style></head>
<body>
<h1>PhoneGPU Space</h1>
<p>Turn an iPhone into a temporary private ML compute worker.</p>
<button onclick="createSession()">Create Session</button>
<div id="output"></div>
<script>
async function createSession(){
const r=await fetch('/api/session',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({})});
const j=await r.json();
document.getElementById('output').innerHTML='<p>Session: <b>'+j.session_id+'</b></p><p>Scan QR with iPhone:</p><img src="data:image/png;base64,'+j.qr+'"><p><a href="/dashboard/'+j.session_id+'">Open Dashboard</a></p>';
}
</script>
</body></html>"""
def _worker_html(session_id: str, token: str) -> str:
# This redirects to the static worker.html with query params
return f"""<!DOCTYPE html>
<html><head><meta name="viewport" content="width=device-width, initial-scale=1">
<title>PhoneGPU Worker</title></head>
<body>
<script>window.WORKER_SESSION_ID='{session_id}';window.WORKER_TOKEN='{token}';</script>
<script>window.location.href='/static/worker.html?session_id={session_id}&token={token}';</script>
</body></html>"""
def _dashboard_html(session_id: str, worker_url: str, qr_b64: str) -> str:
return f"""<!DOCTYPE html>
<html><head><meta name="viewport" content="width=device-width, initial-scale=1">
<title>Session Dashboard</title>
<style>
body{{font-family:sans-serif;max-width:800px;margin:40px auto;padding:0 20px}}
.card{{border:1px solid #e5e7eb;border-radius:8px;padding:16px;margin:12px 0}}
</style></head>
<body>
<h1>Session Dashboard</h1>
<p>Session: <code>{session_id}</code></p>
<div class="card">
<h3>Connect iPhone</h3>
<p>Scan this QR code with your iPhone camera:</p>
<img src="data:image/png;base64,{qr_b64}" width="200">
<p>Or open: <a href="{worker_url}" target="_blank">{worker_url}</a></p>
</div>
<div class="card">
<h3>API</h3>
<p><code>POST /api/session/{session_id}/job</code></p>
<p><code>GET /api/job/{{job_id}}</code></p>
<p><code>GET /api/receipt/{{receipt_id}}</code></p>
</div>
</body></html>"""
|