Download app.py from GodRad/router-ui: direct link, hf CLI and curl.
- Browser
- Download file 5.66 kB
-
https://huggingface.co/spaces/GodRad/router-ui/resolve/main/app.py
- Command line
-
hf download hf://spaces/GodRad/router-ui/app.py
-
curl -L -o app.py https://huggingface.co/spaces/GodRad/router-ui/resolve/main/app.py
5.66 kB
| import gradio as gr | |
| import requests | |
| import os | |
| import json | |
| import tempfile | |
| from fpdf import FPDF | |
| from docx import Document | |
| # Backend URLs (should be set via Environment Variables in HF Spaces) | |
| CPU_BACKEND_URL = os.getenv("CPU_BACKEND_URL", "http://localhost:7860") | |
| GPU_BACKEND_URL = os.getenv("GPU_BACKEND_URL", "http://localhost:7861") | |
| API_KEY = os.getenv("API_KEY", "") | |
| def get_backend_url(mode): | |
| return GPU_BACKEND_URL if mode == "GPU (Faster)" else CPU_BACKEND_URL | |
| def health_check(mode): | |
| url = get_backend_url(mode) | |
| try: | |
| resp = requests.get(f"{url}/health", timeout=5) | |
| return resp.json() | |
| except Exception as e: | |
| return {"error": str(e)} | |
| def upload_files(mode, files): | |
| if not files: | |
| return "No files selected." | |
| if len(files) > 3: | |
| return "Error: Maximum 3 files allowed." | |
| url = get_backend_url(mode) | |
| headers = {"X-API-Key": API_KEY} if API_KEY else {} | |
| results = [] | |
| for file in files: | |
| with open(file.name, "rb") as f: | |
| file_payload = {"file": (os.path.basename(file.name), f)} | |
| try: | |
| resp = requests.post(f"{url}/ingest", files=file_payload, headers=headers) | |
| results.append(f"{os.path.basename(file.name)}: {resp.json()}") | |
| except Exception as e: | |
| results.append(f"{os.path.basename(file.name)}: Error - {str(e)}") | |
| return "\n".join(results) | |
| def generate_files(content): | |
| # 1. TXT | |
| txt_fd, txt_path = tempfile.mkstemp(suffix=".txt") | |
| with os.fdopen(txt_fd, 'w', encoding='utf-8') as f: | |
| f.write(content) | |
| # 2. DOCX | |
| doc = Document() | |
| doc.add_heading('Course Syllabus', 0) | |
| # Simple split by lines to add as paragraphs | |
| for line in content.split('\n'): | |
| doc.add_paragraph(line) | |
| docx_fd, docx_path = tempfile.mkstemp(suffix=".docx") | |
| os.close(docx_fd) | |
| doc.save(docx_path) | |
| # 3. PDF | |
| pdf = FPDF() | |
| pdf.add_page() | |
| pdf.set_font("Arial", size=12) | |
| # Replace unsupported characters for basic FPDF | |
| safe_content = content.encode('latin-1', 'replace').decode('latin-1') | |
| pdf.multi_cell(0, 10, txt=safe_content) | |
| pdf_fd, pdf_path = tempfile.mkstemp(suffix=".pdf") | |
| os.close(pdf_fd) | |
| pdf.output(pdf_path) | |
| return [txt_path, docx_path, pdf_path] | |
| def generate_syllabus(mode, course_name, description, constraints): | |
| url = get_backend_url(mode) | |
| headers = {"X-API-Key": API_KEY} if API_KEY else {} | |
| payload = { | |
| "course_name": course_name, | |
| "description": description, | |
| "constraints": constraints | |
| } | |
| try: | |
| resp = requests.post(f"{url}/generate_syllabus", json=payload, headers=headers) | |
| data = resp.json() | |
| syllabus_text = "" | |
| if "syllabus" in data: | |
| syllabus_text = data["syllabus"] | |
| else: | |
| syllabus_text = json.dumps(data, indent=2) | |
| # Generate downloadable files | |
| files = generate_files(syllabus_text) | |
| return syllabus_text, files, None # Success | |
| except Exception as e: | |
| return f"Error: {str(e)}", [], f"Error details: {str(e)}" | |
| # UI Layout | |
| with gr.Blocks(title="Open Source Syllabus Engine") as demo: | |
| gr.Markdown("# 🎓 Open Source Syllabus Engine") | |
| gr.Markdown("Ingest your documents and generate a production-grade syllabus using RAG.") | |
| with gr.Row(): | |
| mode_radio = gr.Radio( | |
| choices=["CPU (Free)", "GPU (Faster)"], | |
| value="CPU (Free)", | |
| label="Select Backend" | |
| ) | |
| health_btn = gr.Button("Check Connection") | |
| health_output = gr.JSON(label="Backend Status") | |
| health_btn.click(health_check, inputs=[mode_radio], outputs=[health_output]) | |
| with gr.Tab("1. Ingest Documents"): | |
| gr.Markdown("Upload up to 3 documents (PDF, DOCX, TXT) to provide context for the syllabus.") | |
| file_input = gr.File(label="Upload Documents", file_count="multiple") | |
| ingest_btn = gr.Button("Ingest Files") | |
| ingest_output = gr.Text(label="Ingestion Result") | |
| ingest_btn.click(upload_files, inputs=[mode_radio, file_input], outputs=[ingest_output]) | |
| with gr.Tab("2. Generate Syllabus"): | |
| with gr.Row(): | |
| course_name = gr.Textbox(label="Course Name", placeholder="e.g. Advanced Machine Learning") | |
| course_desc = gr.Textbox(label="Description", placeholder="Describe what the course covers...") | |
| constraints = gr.Textbox(label="Optional Constraints", placeholder="e.g. 10 weeks, include a final project") | |
| gen_btn = gr.Button("Generate Syllabus", variant="primary") | |
| with gr.Row(): | |
| gen_output = gr.Markdown(label="Generated Syllabus Preview") | |
| with gr.Column(): | |
| gen_files = gr.File(label="Download Formats (.txt, .docx, .pdf)") | |
| error_box = gr.Text(label="Debug Info", visible=True) | |
| gen_btn.click( | |
| generate_syllabus, | |
| inputs=[mode_radio, course_name, course_desc, constraints], | |
| outputs=[gen_output, gen_files, error_box] | |
| ) | |
| gr.Markdown("---") | |
| gr.Markdown("### Ops Notes") | |
| gr.Markdown("- Ensure `CPU_BACKEND_URL` and `GPU_BACKEND_URL` are set correctly.") | |
| gr.Markdown("- Use the API Key if authentication is enabled on the backends.") | |
| if __name__ == "__main__": | |
| demo.launch(server_name="0.0.0.0", server_port=7860) | |