Spaces:
Sleeping
Sleeping
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 | |
| ) | |