""" SalesPath — HF Spaces Keepalive App Serves a simple FastAPI app after training completes to keep the HF Space alive and display training results. """ import os import json from pathlib import Path from fastapi import FastAPI from fastapi.responses import HTMLResponse, JSONResponse app = FastAPI(title="SalesPath — Training Complete") OUTPUT_DIR = Path(os.environ.get("OUTPUT_DIR", "/app/salespath_out")) @app.get("/health") async def health(): return {"status": "ok", "service": "SalesPath Training"} @app.get("/") async def root(): """Display training results page.""" html = """ SalesPath Training Complete

🏆 SalesPath Training Complete

Trained model has been uploaded to Hugging Face Hub.

""" # Load eval results eval_path = OUTPUT_DIR / "eval_results.json" if eval_path.exists(): try: eval_data = json.loads(eval_path.read_text()) html += '

Evaluation Results

' for key, value in eval_data.items(): if isinstance(value, (int, float)): html += f'
{value:.3f}
{key}
' else: html += f'
{json.dumps(value, indent=2)}
' html += "
" except Exception: pass # Show reward graph graph_path = OUTPUT_DIR / "reward_graph.png" if graph_path.exists(): import base64 img_b64 = base64.b64encode(graph_path.read_bytes()).decode() html += f'

Reward Curve

Reward Graph
' # Show reward history stats history_path = OUTPUT_DIR / "reward_history.txt" if history_path.exists(): lines = history_path.read_text().strip().splitlines() rewards = [float(line.split("\t")[-1]) for line in lines if line.strip()] if rewards: html += f"""

Training Stats

{len(rewards)}
Episodes
{sum(rewards)/len(rewards):.4f}
Mean Reward
{max(rewards):.4f}
Max Reward
{min(rewards):.4f}
Min Reward
""" html += """

Next Steps

1. View model on Hugging Face Hub

2. Run inference with the trained model

3. Stop this Space to avoid billing

""" return HTMLResponse(html) @app.get("/api/results") async def api_results(): """Return training results as JSON.""" results = {} eval_path = OUTPUT_DIR / "eval_results.json" if eval_path.exists(): try: results["eval"] = json.loads(eval_path.read_text()) except Exception: pass history_path = OUTPUT_DIR / "reward_history.txt" if history_path.exists(): lines = history_path.read_text().strip().splitlines() rewards = [float(line.split("\t")[-1]) for line in lines if line.strip()] if rewards: results["training"] = { "episodes": len(rewards), "mean_reward": sum(rewards) / len(rewards), "max_reward": max(rewards), "min_reward": min(rewards), "std_reward": __import__("statistics").stdev(rewards) if len(rewards) > 1 else 0, } return JSONResponse(results)