# ============================================================================
# GRADIO INTERFACE
# ============================================================================
def create_gradio_interface():
"""Create the Gradio web interface"""
with gr.Blocks(theme=gr.themes.Soft(), title="Mine Detection AI") as demo:
gr.Markdown("# 🎯 Mine Detection AI")
gr.Markdown("Upload images to detect mine areas using AI segmentation")
# Show model and API status
if model is None:
gr.Markdown("⚠️ **WARNING: Model not loaded! Check logs.**")
else:
gr.Markdown(f"✅ **Model loaded | Threshold: {INFERENCE_THRESHOLD:.2f}**")
# Check API status
try:
response = requests.get(f"{API_BASE_URL}/rate-limit/status", headers=API_HEADERS, timeout=5)
if response.status_code == 200:
data = response.json()
tier = data.get('subscription_tier', 'free')
gr.Markdown(f"🔑 **API Status: Connected | Tier: {tier.upper()}**")
else:
gr.Markdown("⚠️ **API Status: Connection issue**")
except:
gr.Markdown("⚠️ **API Status: Cannot connect**")
with gr.Tab("Single Image"):
with gr.Row():
with gr.Column():
single_image_input = gr.Image(label="Upload Image", type="pil")
single_user_id = gr.Textbox(label="User ID (optional)", value="user")
single_submit_btn = gr.Button("Process Image")
with gr.Column():
single_output = gr.Image(label="Detection Mask")
single_log = gr.Textbox(label="Processing Log", lines=5)
single_submit_btn.click(
fn=process_single_image,
inputs=[single_image_input, single_user_id],
outputs=[single_output]
).then(
fn=lambda: f"✅ Processing completed! (Threshold: {INFERENCE_THRESHOLD:.2f})",
outputs=[single_log]
)
with gr.Tab("API Trigger (Run on Latest Job)"):
with gr.Row():
with gr.Column():
api_user_id = gr.Textbox(label="Researcher ID", value="1")
api_user_type = gr.Textbox(label="User Type", value="researcher")
api_user_email = gr.Textbox(label="Email", value="user@example.com")
api_trigger_btn = gr.Button("Run Inference on Latest Job")
with gr.Column():
api_log = gr.Textbox(label="Processing Log", lines=15)
api_result = gr.JSON(label="Result")
def update_log_from_result(result):
if result.get('status') == 'error':
return f"❌ Error: {result.get('message', 'Unknown error')}"
elif result.get('status') == 'completed':
return f"✅ Inference completed!\nProcessed: {result.get('processed', 0)}/{result.get('total', 0)} images\nJob ID: {result.get('job_id', 'N/A')}\nThreshold used: {result.get('threshold_used', 0.5):.2f}"
else:
return f"Status: {result.get('status', 'Unknown')}"
api_trigger_btn.click(
fn=run_inference_for_user,
inputs=[api_user_id, api_user_type, api_user_email],
outputs=[api_result]
).then(
fn=update_log_from_result,
inputs=[api_result],
outputs=[api_log]
)
with gr.Tab("API Info"):
gr.Markdown("### 📊 API Rate Limits")
gr.Markdown(f"- **API Base URL**: {API_BASE_URL}")
gr.Markdown("- **Free Tier**: 10 req/min, 100 req/hr, 500 req/day")
gr.Markdown("- **Pro Tier**: 60 req/min, 1000 req/hr, 10000 req/day")
gr.Markdown("- **Enterprise**: 300 req/min, 5000 req/hr, 50000 req/day")
def get_rate_limits():
try:
response = requests.get(f"{API_BASE_URL}/rate-limit/status", headers=API_HEADERS, timeout=10)
if response.status_code == 200:
data = response.json()
return f"**Current Tier**: {data.get('subscription_tier', 'free').upper()}\n\n**Rate Limits**:\n- {data.get('rate_limits', {}).get('requests_per_minute', 0)} requests/minute\n- {data.get('rate_limits', {}).get('requests_per_hour', 0)} requests/hour\n- {data.get('rate_limits', {}).get('requests_per_day', 0)} requests/day\n- {data.get('rate_limits', {}).get('concurrent_downloads', 0)} concurrent downloads"
return "Could not fetch rate limits"
except Exception as e:
return f"Error: {e}"
rate_limit_info = gr.Markdown("Click refresh to load...")
refresh_btn = gr.Button("Refresh Rate Limit Info")
refresh_btn.click(fn=get_rate_limits, outputs=[rate_limit_info])
gr.Markdown("---")
gr.Markdown("### ℹ️ About")
gr.Markdown("This AI model detects mine areas in images using semantic segmentation.")
gr.Markdown(f"🔧 Powered by MinerAI API")
gr.Markdown(f"🎯 Inference threshold: **{INFERENCE_THRESHOLD:.2f}** (optimized from training)")
return demo