#بسم الله الرحمن الرحيم import gradio as gr import asyncio import base64 from client import run_fistal import asyncio import os # from dotenv import load_dotenv # load_dotenv() REQUIRED_SECRETS = [ "GOOGLE_API_KEY_1", "GOOGLE_API_KEY_2", "GOOGLE_API_KEY_3", "GROQ_API_KEY", "GEMINI_API_KEY", "HF_TOKEN", "MODAL_TOKEN_ID", "MODAL_TOKEN_SECRET" ] missing = [s for s in REQUIRED_SECRETS if not os.getenv(s)] if missing: raise ValueError(f"Missing secrets in HF Space: {', '.join(missing)}\nAdd them in Settings → Variables and secrets") def image_to_base64(filepath): try: with open(filepath, "rb") as image_file: encoded_string = base64.b64encode(image_file.read()).decode('utf-8') mime_type = "image/jpeg" if filepath.lower().endswith((".jpg", ".jpeg")) else "image/png" return f"data:{mime_type};base64,{encoded_string}" except FileNotFoundError: print(f"Error: Image file not found at {filepath}") return "" image_data_url = image_to_base64("static/new.jpg") full_img = image_to_base64("static/fullnew.jpg") css=f""" .gradio-container {{ background: url('{full_img}') !important; background-size: cover !important; }} .gradio-container .block {{ background-color: none !important; }} .gradio-container .wrap {{ background-color: none !important; border: !important; box-shadow: none !important; outline: none !important; }} .features-box {{ padding: 10px; color: white !important; background-color: #white !important; }} .features-box .block {{ border: blue 1px !important; background-color: yellow !important; }} #tuner {{ background: linear-gradient(to right, #008DDA, #6A1AAB, #C71585, #F56C40) !important; color: white !important; margin-top: 5px; }} #flow {{ padding: 8px !important; color: white !important; }} #flow .markdown-text {{ color: white !important; }} .drop li {{ background-color: #bcb9cf !important; color: black !important; }} .drop input {{ background-color: #bcb9cf !important; background-size: cover !important; color: black !important; border: none !important; padding: 6px 10px !important; border-radius: 4px !important; }} .out {{ padding: 10px !important; font-size: 16px !important; color: white !important; background: linear-gradient(90deg, rgba(102,126,234,0.3), rgba(106,26,180,0.3), rgba(245,108,64,0.3)) !important; border-radius: 10px !important; }} .log-container {{ max-height: 600px !important; overflow-y: auto !important; background: rgba(14, 15, 15, 0.5) !important; border-radius: 10px !important; padding: 20px !important; border: 1px solid #3a3a3a !important; }} #stat {{ min-height: 60px !important; }} #stat input, #stat textarea {{ padding: 12px 10px !important; line-height: 1.5 !important; color: black !important; min-height: 60px !important; height: auto !important; display: flex !important; align-items: center !important; }} #stat .wrap {{ min-height: 60px !important; }} .mod {{ background: linear-gradient(to right, #008DDA, #6A1AAB, #C71585, #F56C40) !important; color: white !important; }} .log-container::-webkit-scrollbar {{ width: 10px; }} .log-container::-webkit-scrollbar-track {{ background: #2a2a2a; border-radius: 5px; }} .log-container::-webkit-scrollbar-thumb {{ background: linear-gradient(to bottom, #008DDA, #6A1AAB, #C71585, #F56C40); border-radius: 5px; }} .log-container::-webkit-scrollbar-thumb:hover {{ background: linear-gradient(to bottom, #0099ee, #7722bb, #dd1595, #ff7750); }} #copy-btn {{ background: linear-gradient(to right, #008DDA, #6A1AAB, #C71585, #F56C40) !important; color: white !important; margin-top: 10px !important; }} :root, .gradio-container * {{ --block-background-fill: #0e0f0f !important; --panel-background-fill: none !important; --input-background-fill: #bcb9cf !important; --color-background-primary: #0e0f0f !important; --block-border-width: 0px !important; --block-border-color: #27272a !important; --panel-border-width: 0px !important; --input-text-color: #000000 !important; --input-placeholder-color: #27272a !important; --panel-border-color: linear-gradient(to right, #008DDA, #6A1AAB, #C71585, #F56C40) !important; --neutral-50: #27272a !important; }} """ def app(): with gr.Blocks(title="Fistal AI 🚀") as demo: # Header section with background image gr.HTML(f"""
Seamlessly fine-tune LLMs with an Agentic AI powered by MCP, Modal, and Unsloth.
Add your dataset topic, task type, number of samples, and your preferred Unsloth model.
Then sit back and watch Fistal AI automatically build datasets, fine-tune your LLMs, and deliver results like magic.
Note: The process may take 30-45 minutes, depending on the number of samples and model chosen.