RDF Validation Deployment
Update RDF examples, move Examples section to top, and use handcuff emoji for SHACL theme
c14e337
#!/usr/bin/env python3 | |
""" | |
Hugging Face Gradio App for RDF Validation with MCP Server and Anthropic AI | |
This app serves both as a web interface and can expose MCP server functionality. | |
Deploy this on Hugging Face Spaces with your Anthropic API key. | |
""" | |
import gradio as gr | |
import os | |
import json | |
import sys | |
import asyncio | |
import logging | |
import requests | |
from typing import Any, Dict, List, Optional | |
import threading | |
import time | |
# CRITICAL: FORCE OVERRIDE ALL ENVIRONMENT VARIABLES THAT COULD INTERFERE | |
print("π§ FORCING ENVIRONMENT VARIABLE OVERRIDES...") | |
# Remove any HF environment variables that could cause URL concatenation | |
problematic_env_vars = [ | |
'HF_API_URL', | |
'HF_INFERENCE_URL', | |
'HF_ENDPOINT_URL', | |
'HF_MODEL', | |
'HUGGINGFACE_API_URL', | |
'HUGGINGFACE_INFERENCE_URL' | |
] | |
for var in problematic_env_vars: | |
if var in os.environ: | |
old_value = os.environ[var] | |
del os.environ[var] | |
print(f"ποΈ Removed environment variable: {var} = {old_value}") | |
print("β Environment variables cleaned") | |
# Add current directory to path | |
sys.path.append(os.path.dirname(os.path.abspath(__file__))) | |
# Import our validation logic | |
try: | |
from validator import validate_rdf | |
VALIDATOR_AVAILABLE = True | |
except ImportError: | |
VALIDATOR_AVAILABLE = False | |
print("β οΈ Warning: validator.py not found. Some features may be limited.") | |
# Optional: Check if OpenAI and requests are available | |
try: | |
from openai import OpenAI | |
OPENAI_AVAILABLE = True | |
except ImportError: | |
OPENAI_AVAILABLE = False | |
print("π‘ Install 'openai' package for AI-powered corrections: pip install openai") | |
try: | |
import requests | |
HF_INFERENCE_AVAILABLE = True | |
except ImportError: | |
HF_INFERENCE_AVAILABLE = False | |
print("π‘ Install 'requests' package for AI-powered corrections: pip install requests") | |
# Set up logging | |
logging.basicConfig(level=logging.INFO) | |
logger = logging.getLogger(__name__) | |
# Configuration - ABSOLUTELY HARDCODED VALUES (NO ENV VARS ALLOWED) | |
HF_API_KEY = os.getenv('HF_API_KEY', '') # Only this one env var is allowed | |
# FORCE HARDCODED VALUES - IGNORE ALL OTHER ENVIRONMENT VARIABLES | |
HF_ENDPOINT_URL = "https://evxgv66ksxjlfrts.us-east-1.aws.endpoints.huggingface.cloud/v1/" | |
HF_MODEL = "lmstudio-community/Llama-3.3-70B-Instruct-GGUF" # Correct model name for your endpoint | |
print(f"π FORCED hardcoded endpoint: {HF_ENDPOINT_URL}") | |
print(f"π FORCED hardcoded model: {HF_MODEL}") | |
print(f"π HF_API_KEY configured: {'Yes' if HF_API_KEY else 'No'}") | |
# EXTRA PROTECTION: Override any modules that might have cached env vars | |
import sys | |
if 'requests' in sys.modules: | |
print("π Requests module detected - ensuring no cached env vars") | |
if 'httpx' in sys.modules: | |
print("π HTTPX module detected - ensuring no cached env vars") | |
# OpenAI client configuration for the endpoint | |
def get_openai_client(): | |
"""Get configured OpenAI client for HF Inference Endpoint""" | |
if not HF_API_KEY: | |
print("β No HF_API_KEY available for OpenAI client") | |
return None | |
print(f"π Creating OpenAI client with:") | |
print(f" base_url: {HF_ENDPOINT_URL}") | |
print(f" api_key: {'***' + HF_API_KEY[-4:] if len(HF_API_KEY) > 4 else 'HIDDEN'}") | |
return OpenAI( | |
base_url=HF_ENDPOINT_URL, | |
api_key=HF_API_KEY, | |
timeout=120.0 # Increase timeout for cold starts | |
) | |
# Sample RDF data for examples | |
SAMPLE_VALID_RDF = '''<?xml version="1.0" encoding="UTF-8"?> | |
<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" | |
xmlns:bf="http://id.loc.gov/ontologies/bibframe/" | |
xmlns:bflc="http://id.loc.gov/ontologies/bflc/" | |
xmlns:rdfs="http://www.w3.org/2000/01/rdf-schema#"> | |
<bf:Work rdf:about="http://example.org/work/1"> | |
<rdf:type rdf:resource="http://id.loc.gov/ontologies/bibframe/Text"/> | |
<bf:title> | |
<bf:Title> | |
<bf:mainTitle>Complete Valid Monograph Title</bf:mainTitle> | |
<bf:subtitle>A Comprehensive Example for SHACL Validation</bf:subtitle> | |
</bf:Title> | |
</bf:title> | |
<bf:creator> | |
<bf:Agent> | |
<rdf:type rdf:resource="http://id.loc.gov/ontologies/bibframe/Person"/> | |
<rdfs:label>Valid Author Name</rdfs:label> | |
</bf:Agent> | |
</bf:creator> | |
<bf:subject> | |
<bf:Topic> | |
<rdfs:label>Library Science</rdfs:label> | |
</bf:Topic> | |
</bf:subject> | |
<bf:language> | |
<bf:Language rdf:about="http://id.loc.gov/vocabulary/languages/eng"/> | |
</bf:language> | |
<bf:hasInstance rdf:resource="http://example.org/instance/1"/> | |
</bf:Work> | |
<bf:Instance rdf:about="http://example.org/instance/1"> | |
<rdf:type rdf:resource="http://id.loc.gov/ontologies/bibframe/Print"/> | |
<bf:instanceOf rdf:resource="http://example.org/work/1"/> | |
<bf:title> | |
<bf:Title> | |
<bf:mainTitle>Complete Valid Monograph Title</bf:mainTitle> | |
</bf:Title> | |
</bf:title> | |
<bf:provisionActivity> | |
<bf:Publication> | |
<bf:date>2024</bf:date> | |
<bf:place> | |
<bf:Place> | |
<rdfs:label>Washington, DC</rdfs:label> | |
</bf:Place> | |
</bf:place> | |
<bf:agent> | |
<bf:Agent> | |
<rdfs:label>Sample Publisher</rdfs:label> | |
</bf:Agent> | |
</bf:agent> | |
</bf:Publication> | |
</bf:provisionActivity> | |
<bf:extent> | |
<bf:Extent> | |
<rdfs:label>256 pages</rdfs:label> | |
</bf:Extent> | |
</bf:extent> | |
</bf:Instance> | |
</rdf:RDF>''' | |
SAMPLE_INVALID_RDF = '''<?xml version="1.0" encoding="UTF-8"?> | |
<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" | |
xmlns:bf="http://id.loc.gov/ontologies/bibframe/" | |
xmlns:rdfs="http://www.w3.org/2000/01/rdf-schema#"> | |
<bf:Work rdf:about="http://example.org/work/1"> | |
<!-- Missing rdf:type - this should cause SHACL validation failure --> | |
<bf:title> | |
<!-- Missing bf:Title wrapper - improper title structure --> | |
<bf:mainTitle>Invalid Monograph Title Structure</bf:mainTitle> | |
</bf:title> | |
<!-- Missing required bf:creator property --> | |
<!-- Missing other required properties like bf:language --> | |
</bf:Work> | |
<bf:Instance rdf:about="http://example.org/instance/1"> | |
<rdf:type rdf:resource="http://id.loc.gov/ontologies/bibframe/Print"/> | |
<!-- Missing bf:instanceOf property - should link to Work --> | |
<bf:title> | |
<bf:Title> | |
<bf:mainTitle>Invalid Instance Title</bf:mainTitle> | |
</bf:Title> | |
</bf:title> | |
<!-- Missing required bf:provisionActivity --> | |
</bf:Instance> | |
</rdf:RDF>''' | |
# MCP Server Tools (can be used independently) | |
def validate_rdf_tool(rdf_content: str, template: str = "monograph") -> dict: | |
""" | |
Validate RDF/XML content against SHACL templates. | |
This tool validates RDF/XML data against predefined SHACL shapes to ensure | |
compliance with metadata standards like BIBFRAME. Returns detailed validation | |
results with conformance status and specific violation information. | |
Args: | |
rdf_content (str): The RDF/XML content to validate | |
template (str): Validation template to use ('monograph' or 'custom') | |
Returns: | |
dict: Validation results with conformance status and detailed feedback | |
""" | |
if not rdf_content: | |
return {"error": "No RDF/XML content provided", "conforms": False} | |
if not VALIDATOR_AVAILABLE: | |
return { | |
"error": "Validator not available - ensure validator.py is present", | |
"conforms": False | |
} | |
try: | |
conforms, results_text = validate_rdf(rdf_content.encode('utf-8'), template) | |
return { | |
"conforms": conforms, | |
"results": results_text, | |
"template": template, | |
"status": "β Valid RDF" if conforms else "β Invalid RDF" | |
} | |
except Exception as e: | |
logger.error(f"Validation error: {str(e)}") | |
return { | |
"error": f"Validation failed: {str(e)}", | |
"conforms": False | |
} | |
def get_ai_suggestions(validation_results: str, rdf_content: str) -> str: | |
""" | |
Generate AI-powered fix suggestions for invalid RDF/XML. | |
This tool analyzes validation results and provides actionable suggestions | |
for fixing RDF/XML validation errors using AI or rule-based analysis. | |
Args: | |
validation_results (str): The validation error messages | |
rdf_content (str): The original RDF/XML content that failed validation | |
Returns: | |
str: Detailed suggestions for fixing the RDF validation issues | |
""" | |
if not OPENAI_AVAILABLE: | |
return generate_manual_suggestions(validation_results) | |
# Get API key dynamically at runtime | |
current_api_key = os.getenv('HF_API_KEY', '') | |
if not current_api_key: | |
return f""" | |
π **AI suggestions disabled**: Please set your Hugging Face API key as a Secret in your Space settings. | |
{generate_manual_suggestions(validation_results)} | |
""" | |
try: | |
# Use OpenAI client with your Hugging Face Inference Endpoint | |
print("π Attempting to get OpenAI client for suggestions...") | |
client = get_openai_client() | |
if not client: | |
print("β OpenAI client is None for suggestions.") | |
return f""" | |
π **AI suggestions disabled**: HF_API_KEY not configured or client creation failed. | |
{generate_manual_suggestions(validation_results)} | |
""" | |
print(f"β OpenAI client obtained for suggestions. Client timeout: {client.timeout}") | |
prompt = f"""You are an expert in RDF/XML and SHACL validation. Analyze the following validation results and provide clear, actionable suggestions for fixing the RDF issues. | |
Validation Results: | |
{validation_results} | |
Original RDF (first 1000 chars): | |
{rdf_content[:1000]}... | |
Please provide: | |
1. A clear summary of what's wrong | |
2. Specific step-by-step instructions to fix each issue | |
3. Example corrections where applicable | |
4. Best practices to prevent similar issues | |
Format your response in a helpful, structured way using markdown.""" | |
# Make API call using OpenAI client | |
print(f"π Making SUGGESTION API call to: {HF_ENDPOINT_URL} with model: {HF_MODEL}") | |
print(f"π Client base_url: {client.base_url}") | |
print("β³ Attempting client.chat.completions.create() for suggestions...") | |
chat_completion = client.chat.completions.create( | |
model=HF_MODEL, | |
messages=[ | |
{ | |
"role": "user", | |
"content": prompt | |
} | |
], | |
max_tokens=1500, | |
temperature=0.7, | |
top_p=0.9 | |
) | |
print(f"β client.chat.completions.create() returned for suggestions. Type: {type(chat_completion)}") | |
generated_text = chat_completion.choices[0].message.content | |
print("β Suggestion API call successful, content extracted.") | |
return f"π€ **AI-Powered Suggestions:**\n\n{generated_text}" | |
except Exception as e: | |
logger.error(f"OpenAI/HF Inference Endpoint error (suggestions): {str(e)}", exc_info=True) # Added exc_info for full traceback | |
return f""" | |
β **AI suggestions error**: {str(e)} | |
{generate_manual_suggestions(validation_results)} | |
""" | |
def get_ai_correction(validation_results: str, rdf_content: str) -> str: | |
""" | |
Generate AI-powered corrected RDF/XML based on validation errors. | |
This tool takes invalid RDF/XML and validation results, then generates | |
a corrected version that addresses all identified validation issues. | |
Args: | |
validation_results (str): The validation error messages | |
rdf_content (str): The original invalid RDF/XML content | |
Returns: | |
str: Corrected RDF/XML that should pass validation | |
""" | |
if not OPENAI_AVAILABLE: | |
return generate_manual_correction_hints(validation_results, rdf_content) | |
# Get API key dynamically at runtime | |
current_api_key = os.getenv('HF_API_KEY', '') | |
if not current_api_key: | |
return f"""<!-- AI correction disabled: Set HF_API_KEY as a Secret in your Space settings --> | |
{generate_manual_correction_hints(validation_results, rdf_content)}""" | |
try: | |
# Use OpenAI client with your Hugging Face Inference Endpoint | |
print("π Attempting to get OpenAI client for correction...") | |
client = get_openai_client() | |
if not client: | |
print("β OpenAI client is None for correction.") | |
return f"""<!-- AI correction disabled: HF_API_KEY not configured or client creation failed. --> | |
{generate_manual_correction_hints(validation_results, rdf_content)}""" | |
print(f"β OpenAI client obtained for correction. Client timeout: {client.timeout}") | |
prompt = f"""You are an expert in RDF/XML. Fix the following RDF/XML based on the validation errors provided. | |
Validation Errors: | |
{validation_results} | |
Original RDF/XML: | |
{rdf_content} | |
Please provide the corrected RDF/XML that addresses all validation issues. | |
- Return only the corrected XML without additional explanation | |
- Maintain the original structure as much as possible while fixing errors | |
- Ensure all namespace declarations are present | |
- Add any missing required properties | |
- Fix any syntax or structural issues""" | |
# Make API call using OpenAI client | |
print(f"π Making CORRECTION API call to: {HF_ENDPOINT_URL} with model: {HF_MODEL}") | |
print(f"π Client base_url: {client.base_url}") | |
print("β³ Attempting client.chat.completions.create() for correction...") | |
chat_completion = client.chat.completions.create( | |
model=HF_MODEL, | |
messages=[ | |
{ | |
"role": "user", | |
"content": prompt | |
} | |
], | |
max_tokens=2000, | |
temperature=0.3, | |
top_p=0.9 | |
) | |
print(f"β client.chat.completions.create() returned for correction. Type: {type(chat_completion)}") | |
corrected_text = chat_completion.choices[0].message.content | |
print("β Correction API call successful, content extracted.") | |
return corrected_text | |
except Exception as e: | |
logger.error(f"OpenAI/HF Inference Endpoint error (correction): {str(e)}", exc_info=True) # Added exc_info for full traceback | |
return f"""<!-- AI correction error: {str(e)} --> | |
{generate_manual_correction_hints(validation_results, rdf_content)}""" | |
def generate_manual_suggestions(validation_results: str) -> str: | |
"""Generate rule-based suggestions when AI is not available""" | |
suggestions = [] | |
if "Constraint Violation" in validation_results: | |
suggestions.append("β’ Fix SHACL constraint violations by ensuring required properties are present") | |
if "Missing property" in validation_results or "missing" in validation_results.lower(): | |
suggestions.append("β’ Add missing required properties (check template requirements)") | |
if "datatype" in validation_results.lower(): | |
suggestions.append("β’ Correct data type mismatches (ensure proper literal types)") | |
if "namespace" in validation_results.lower() or "prefix" in validation_results.lower(): | |
suggestions.append("β’ Add missing namespace declarations at the top of your RDF") | |
if "XML" in validation_results or "syntax" in validation_results.lower(): | |
suggestions.append("β’ Fix XML syntax errors (check for unclosed tags, invalid characters)") | |
if not suggestions: | |
suggestions.append("β’ Review detailed validation results for specific issues") | |
suggestions.append("β’ Ensure your RDF follows the selected template requirements") | |
suggestions_text = "\n".join(suggestions) | |
return f""" | |
π **Manual Analysis:** | |
{suggestions_text} | |
π‘ **General Tips:** | |
β’ Check namespace declarations at the top of your RDF | |
β’ Ensure all required properties are present | |
β’ Verify data types match expected formats | |
β’ Make sure XML structure is well-formed | |
π§ **Common Fixes:** | |
β’ Add missing namespace prefixes | |
β’ Include required properties like rdf:type | |
β’ Fix malformed URIs or literals | |
β’ Ensure proper XML syntax | |
""" | |
def generate_manual_correction_hints(validation_results: str, rdf_content: str) -> str: | |
"""Generate manual correction hints when AI is not available""" | |
return f"""<!-- Manual correction hints based on validation results --> | |
<!-- Set HF_API_KEY as a Secret in your Space settings for AI-powered corrections --> | |
{rdf_content} | |
<!-- | |
VALIDATION ISSUES FOUND: | |
{validation_results[:500]}... | |
MANUAL CORRECTION STEPS: | |
1. Add missing namespace declarations | |
2. Include required properties (rdf:type, etc.) | |
3. Fix XML syntax errors | |
4. Ensure proper URI formats | |
5. Validate data types | |
-->""" | |
def validate_rdf_interface(rdf_content: str, template: str, use_ai: bool = True): | |
"""Main validation function for Gradio interface""" | |
if not rdf_content.strip(): | |
return "β Error", "No RDF/XML data provided", "", "" | |
# Validate RDF | |
result = validate_rdf_tool(rdf_content, template) | |
if "error" in result: | |
return f"β Error: {result['error']}", "", "", "" | |
status = result["status"] | |
results_text = result["results"] | |
if result["conforms"]: | |
suggestions = "β No issues found! Your RDF/XML is valid according to the selected template." | |
corrected_rdf = "<!-- Already valid - no corrections needed -->\n" + rdf_content | |
else: | |
if use_ai: | |
suggestions = get_ai_suggestions(results_text, rdf_content) | |
corrected_rdf = get_ai_correction(results_text, rdf_content) | |
else: | |
suggestions = generate_manual_suggestions(results_text) | |
corrected_rdf = generate_manual_correction_hints(results_text, rdf_content) | |
return status, results_text, suggestions, corrected_rdf | |
def get_rdf_examples(example_type: str = "valid") -> str: | |
""" | |
Retrieve example RDF/XML snippets for testing and learning. | |
This tool provides sample RDF/XML content that can be used to test | |
the validation system or learn proper RDF structure. | |
Args: | |
example_type (str): Type of example ('valid', 'invalid', or 'bibframe') | |
Returns: | |
str: RDF/XML example content | |
""" | |
examples = { | |
"valid": SAMPLE_VALID_RDF, | |
"invalid": SAMPLE_INVALID_RDF, | |
"bibframe": '''<?xml version="1.0" encoding="UTF-8"?> | |
<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" | |
xmlns:bf="http://id.loc.gov/ontologies/bibframe/" | |
xmlns:rdfs="http://www.w3.org/2000/01/rdf-schema#"> | |
<bf:Instance rdf:about="http://example.org/instance/1"> | |
<rdf:type rdf:resource="http://id.loc.gov/ontologies/bibframe/Print"/> | |
<bf:instanceOf rdf:resource="http://example.org/work/1"/> | |
<bf:title> | |
<bf:Title> | |
<bf:mainTitle>Example Book Title</bf:mainTitle> | |
</bf:Title> | |
</bf:title> | |
<bf:provisionActivity> | |
<bf:Publication> | |
<bf:date>2024</bf:date> | |
<bf:place> | |
<bf:Place> | |
<rdfs:label>New York</rdfs:label> | |
</bf:Place> | |
</bf:place> | |
</bf:Publication> | |
</bf:provisionActivity> | |
</bf:Instance> | |
</rdf:RDF>''' | |
} | |
return examples.get(example_type, examples["valid"]) | |
# Create Gradio Interface | |
def create_interface(): | |
"""Create the main Gradio interface""" | |
# Check API key status dynamically | |
current_api_key = os.getenv('HF_API_KEY', '') | |
api_status = "π AI features enabled" if (OPENAI_AVAILABLE and current_api_key) else "β οΈ AI features disabled (set HF_API_KEY)" | |
with gr.Blocks( | |
title="RDF Validation Server with AI", | |
theme=gr.themes.Soft(), | |
css=""" | |
.status-box { | |
font-weight: bold; | |
padding: 10px; | |
border-radius: 5px; | |
} | |
.header-text { | |
text-align: center; | |
padding: 20px; | |
} | |
""" | |
) as demo: | |
# Header | |
debug_info = f""" | |
Debug Info: | |
- OPENAI_AVAILABLE: {OPENAI_AVAILABLE} | |
- HF_INFERENCE_AVAILABLE: {HF_INFERENCE_AVAILABLE} | |
- HF_API_KEY set: {'Yes' if current_api_key else 'No'} | |
- HF_API_KEY length: {len(current_api_key) if current_api_key else 0} | |
- HF_ENDPOINT_URL: {HF_ENDPOINT_URL} | |
- HF_MODEL: {HF_MODEL} | |
""" | |
gr.HTML(f""" | |
<div class="header-text"> | |
<h1>π RDF Validation Server with AI</h1> | |
<p>Validate RDF/XML against SHACL schemas with AI-powered suggestions and corrections</p> | |
<p><strong>Status:</strong> {api_status}</p> | |
<details><summary>Debug Info</summary><pre>{debug_info}</pre></details> | |
</div> | |
""") | |
# Main interface | |
with gr.Row(): | |
with gr.Column(scale=1): | |
gr.Markdown("### π Input") | |
rdf_input = gr.Textbox( | |
label="RDF/XML Content", | |
placeholder="Paste your RDF/XML content here...", | |
lines=15, | |
show_copy_button=True | |
) | |
with gr.Row(): | |
template_dropdown = gr.Dropdown( | |
label="Validation Template", | |
choices=["monograph", "custom"], | |
value="monograph", | |
info="Select the SHACL template to validate against" | |
) | |
use_ai_checkbox = gr.Checkbox( | |
label="Use AI Features", | |
value=True, | |
info="Enable AI-powered suggestions and corrections" | |
) | |
validate_btn = gr.Button("π Validate RDF", variant="primary", size="lg") | |
# Examples and controls | |
gr.Markdown("### π Examples & Tools") | |
with gr.Row(): | |
example1_btn = gr.Button("β Valid RDF Example", variant="secondary") | |
example2_btn = gr.Button("β Invalid RDF Example", variant="secondary") | |
example3_btn = gr.Button("π BibFrame Example", variant="secondary") | |
clear_btn = gr.Button("ποΈ Clear All", variant="stop") | |
# Results section | |
with gr.Row(): | |
with gr.Column(): | |
gr.Markdown("### π Results") | |
status_output = gr.Textbox( | |
label="Validation Status", | |
interactive=False, | |
lines=1, | |
elem_classes=["status-box"] | |
) | |
results_output = gr.Textbox( | |
label="Detailed Validation Results", | |
interactive=False, | |
lines=8, | |
show_copy_button=True | |
) | |
suggestions_output = gr.Textbox( | |
label="π‘ Fix Suggestions", | |
interactive=False, | |
lines=8, | |
show_copy_button=True | |
) | |
# Corrected RDF section | |
with gr.Row(): | |
with gr.Column(): | |
gr.Markdown("### π οΈ AI-Generated Corrections") | |
corrected_output = gr.Textbox( | |
label="Corrected RDF/XML", | |
interactive=False, | |
lines=15, | |
show_copy_button=True, | |
placeholder="Corrected RDF will appear here after validation..." | |
) | |
# Event handlers | |
validate_btn.click( | |
fn=validate_rdf_interface, | |
inputs=[rdf_input, template_dropdown, use_ai_checkbox], | |
outputs=[status_output, results_output, suggestions_output, corrected_output] | |
) | |
# Auto-validate on input change (debounced) | |
rdf_input.change( | |
fn=validate_rdf_interface, | |
inputs=[rdf_input, template_dropdown, use_ai_checkbox], | |
outputs=[status_output, results_output, suggestions_output, corrected_output] | |
) | |
# Example buttons | |
example1_btn.click( | |
lambda: get_rdf_examples("valid"), | |
outputs=[rdf_input] | |
) | |
example2_btn.click( | |
lambda: get_rdf_examples("invalid"), | |
outputs=[rdf_input] | |
) | |
example3_btn.click( | |
lambda: get_rdf_examples("bibframe"), | |
outputs=[rdf_input] | |
) | |
clear_btn.click( | |
lambda: ("", "", "", "", ""), | |
outputs=[rdf_input, status_output, results_output, suggestions_output, corrected_output] | |
) | |
# Footer with instructions | |
gr.Markdown(""" | |
--- | |
### π **Deployment Instructions for Hugging Face Spaces:** | |
1. **Create a new Space** on [Hugging Face](https://huggingface.co/spaces) | |
2. **Set up your Hugging Face Inference Endpoint** and get the endpoint URL | |
3. **Set your tokens** in Space settings (use Secrets for security): | |
- Go to Settings β Repository secrets | |
- Add: `HF_API_KEY` = `your_huggingface_api_key_here` | |
- Endpoint is now hardcoded to your specific Inference Endpoint | |
4. **Upload these files** to your Space repository | |
5. **Install requirements**: The Space will auto-install from `requirements.txt` | |
### π§ **MCP Server Mode:** | |
This app functions as both a web interface AND an MCP server for Claude Desktop and other MCP clients. | |
**Available MCP Tools (via SSE):** | |
- `validate_rdf_tool`: Validate RDF/XML against SHACL shapes | |
- `get_ai_suggestions`: Get AI-powered fix suggestions | |
- `get_ai_correction`: Generate corrected RDF/XML | |
- `get_rdf_examples`: Retrieve example RDF snippets | |
**MCP Connection:** | |
1. When deployed on Hugging Face Spaces, the MCP server is available at: | |
`https://your-space-id.hf.space/gradio_api/mcp/sse` | |
2. Use this URL in Claude Desktop's MCP configuration | |
3. The app automatically exposes functions with proper docstrings as MCP tools | |
### π‘ **Features:** | |
- β Real-time RDF/XML validation against SHACL schemas | |
- π€ AI-powered error suggestions and corrections (with HF Inference Endpoint) | |
- π Built-in examples and templates | |
- π Auto-validation as you type | |
- π Copy results with one click | |
**Note:** AI features require a valid Hugging Face API key (HF_API_KEY) set as a Secret. Manual suggestions are provided as fallback. | |
""") | |
return demo | |
# Launch configuration | |
if __name__ == "__main__": | |
# Force verify environment is clean | |
print("π FINAL CHECK: Verifying problematic environment variables are removed...") | |
for var in problematic_env_vars: | |
if var in os.environ: | |
print(f"β οΈ WARNING: {var} still exists! Value: {os.environ[var]}") | |
del os.environ[var] | |
print(f"ποΈ FORCE REMOVED: {var}") | |
else: | |
print(f"β {var} confirmed not in environment") | |
demo = create_interface() | |
# Configuration for different environments | |
port = int(os.getenv('PORT', 7860)) # Hugging Face uses PORT env variable | |
demo.launch( | |
server_name="0.0.0.0", # Important for external hosting | |
server_port=port, # Use environment PORT or default to 7860 | |
share=False, # Don't create gradio.live links in production | |
show_error=True, # Show errors in the interface | |
show_api=True, # Enable API endpoints | |
allowed_paths=["."] # Allow serving files from current directory | |
) | |