Upload app.py
Browse files
app.py
CHANGED
@@ -53,8 +53,8 @@ HF_ENDPOINT_URL = "https://evxgv66ksxjlfrts.us-east-1.aws.endpoints.huggingface.
|
|
53 |
HF_MODEL = "lmstudio-community/Llama-3.3-70B-Instruct-GGUF" # Correct model name for your endpoint
|
54 |
|
55 |
# AI Correction Configuration
|
56 |
-
MAX_CORRECTION_ATTEMPTS =
|
57 |
-
ENABLE_VALIDATION_LOOP =
|
58 |
|
59 |
# OpenAI client configuration for the endpoint
|
60 |
def get_openai_client():
|
@@ -168,7 +168,7 @@ def validate_rdf_tool(rdf_content: str, template: str = "monograph") -> dict:
|
|
168 |
"conforms": False
|
169 |
}
|
170 |
|
171 |
-
def get_ai_suggestions(validation_results: str, rdf_content: str) -> str:
|
172 |
"""
|
173 |
Generate AI-powered fix suggestions for invalid RDF/XML.
|
174 |
|
@@ -178,6 +178,7 @@ def get_ai_suggestions(validation_results: str, rdf_content: str) -> str:
|
|
178 |
Args:
|
179 |
validation_results (str): The validation error messages
|
180 |
rdf_content (str): The original RDF/XML content that failed validation
|
|
|
181 |
|
182 |
Returns:
|
183 |
str: Detailed suggestions for fixing the RDF validation issues
|
@@ -205,8 +206,12 @@ def get_ai_suggestions(validation_results: str, rdf_content: str) -> str:
|
|
205 |
{generate_manual_suggestions(validation_results)}
|
206 |
"""
|
207 |
|
|
|
|
|
208 |
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.
|
209 |
|
|
|
|
|
210 |
Validation Results:
|
211 |
{validation_results}
|
212 |
|
@@ -224,7 +229,7 @@ Format your response in a helpful, structured way using markdown."""
|
|
224 |
# Make API call using OpenAI client
|
225 |
print(f"π Making API call to: {HF_ENDPOINT_URL}")
|
226 |
print(f"π Using model: {HF_MODEL}")
|
227 |
-
print(f"π
|
228 |
|
229 |
chat_completion = client.chat.completions.create(
|
230 |
model=HF_MODEL,
|
@@ -241,7 +246,7 @@ Format your response in a helpful, structured way using markdown."""
|
|
241 |
|
242 |
print("β
API call successful")
|
243 |
generated_text = chat_completion.choices[0].message.content
|
244 |
-
return f"π€ **AI-Powered Suggestions:**\n\n{generated_text}"
|
245 |
|
246 |
except Exception as e:
|
247 |
logger.error(f"OpenAI/HF Inference Endpoint error: {str(e)}")
|
@@ -280,7 +285,7 @@ def extract_rdf_from_response(response: str) -> str:
|
|
280 |
# If no code blocks found, return the response as-is
|
281 |
return response
|
282 |
|
283 |
-
def get_ai_correction(validation_results: str, rdf_content: str, template: str = 'monograph', max_attempts: int = None) -> str:
|
284 |
"""
|
285 |
Generate AI-powered corrected RDF/XML based on validation errors.
|
286 |
|
@@ -293,6 +298,7 @@ def get_ai_correction(validation_results: str, rdf_content: str, template: str =
|
|
293 |
rdf_content (str): The original invalid RDF/XML content
|
294 |
template (str): The validation template to use
|
295 |
max_attempts (int): Maximum number of attempts to generate valid RDF (uses MAX_CORRECTION_ATTEMPTS if None)
|
|
|
296 |
|
297 |
Returns:
|
298 |
str: Corrected RDF/XML that should pass validation
|
@@ -323,10 +329,26 @@ def get_ai_correction(validation_results: str, rdf_content: str, template: str =
|
|
323 |
|
324 |
{generate_manual_correction_hints(validation_results, rdf_content)}"""
|
325 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
326 |
# Try multiple attempts to generate valid RDF
|
327 |
for attempt in range(max_attempts):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
328 |
prompt = f"""You are an expert in RDF/XML. Fix the following RDF/XML based on the validation errors provided.
|
329 |
|
|
|
|
|
330 |
Validation Errors:
|
331 |
{validation_results}
|
332 |
|
@@ -342,53 +364,59 @@ Please provide the corrected RDF/XML that addresses all validation issues.
|
|
342 |
- Add any missing required properties
|
343 |
- Fix any syntax or structural issues"""
|
344 |
|
345 |
-
|
346 |
-
|
347 |
-
|
348 |
-
|
349 |
-
|
350 |
-
|
351 |
-
|
352 |
-
|
353 |
-
|
354 |
-
|
355 |
-
|
356 |
-
|
357 |
-
|
358 |
-
|
359 |
-
|
360 |
-
|
361 |
-
|
362 |
-
|
363 |
-
|
364 |
-
|
365 |
-
|
366 |
-
|
367 |
-
|
368 |
-
|
369 |
-
# Validate the corrected RDF using the same template
|
370 |
-
conforms, new_results = validate_rdf(corrected_rdf.encode('utf-8'), template)
|
371 |
-
|
372 |
-
if conforms:
|
373 |
-
print(f"β
Correction validated successfully on attempt {attempt + 1}")
|
374 |
-
return f"""<!-- AI-generated correction validated successfully -->
|
375 |
-
{corrected_rdf}"""
|
376 |
-
else:
|
377 |
-
print(f"β Correction attempt {attempt + 1} still has validation errors")
|
378 |
-
# Update validation_results for next attempt
|
379 |
-
validation_results = new_results
|
380 |
|
381 |
-
|
382 |
-
|
383 |
-
|
384 |
-
|
385 |
-
|
386 |
-
|
387 |
-
|
388 |
-
|
389 |
-
|
390 |
-
|
391 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
392 |
<!-- Please correct manually using the validation results as a guide -->
|
393 |
|
394 |
{generate_manual_correction_hints(validation_results, rdf_content)}"""
|
@@ -461,7 +489,7 @@ MANUAL CORRECTION STEPS:
|
|
461 |
5. Validate data types
|
462 |
-->"""
|
463 |
|
464 |
-
def validate_rdf_interface(rdf_content: str, template: str, use_ai: bool = True):
|
465 |
"""
|
466 |
Main validation function for Gradio interface and MCP server.
|
467 |
|
@@ -473,6 +501,7 @@ def validate_rdf_interface(rdf_content: str, template: str, use_ai: bool = True)
|
|
473 |
rdf_content (str): The RDF/XML content to validate
|
474 |
template (str): Validation template to use ('monograph' or 'custom')
|
475 |
use_ai (bool): Whether to enable AI-powered suggestions and corrections
|
|
|
476 |
|
477 |
Returns:
|
478 |
tuple: (status, results_text, suggestions, corrected_rdf) containing:
|
@@ -493,16 +522,36 @@ def validate_rdf_interface(rdf_content: str, template: str, use_ai: bool = True)
|
|
493 |
status = result["status"]
|
494 |
results_text = result["results"]
|
495 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
496 |
if result["conforms"]:
|
497 |
suggestions = "β
No issues found! Your RDF/XML is valid according to the selected template."
|
498 |
corrected_rdf = "β
Your RDF/XML is already valid - no corrections needed!"
|
499 |
else:
|
500 |
if use_ai:
|
501 |
-
|
502 |
-
|
|
|
503 |
else:
|
504 |
-
suggestions = generate_manual_suggestions(
|
505 |
-
corrected_rdf = generate_manual_correction_hints(
|
506 |
|
507 |
return status, results_text, suggestions, corrected_rdf
|
508 |
|
@@ -626,6 +675,12 @@ def create_interface():
|
|
626 |
value=True,
|
627 |
info="Enable AI-powered suggestions and corrections"
|
628 |
)
|
|
|
|
|
|
|
|
|
|
|
|
|
629 |
|
630 |
validate_btn = gr.Button("π Validate RDF", variant="primary", size="lg")
|
631 |
|
@@ -679,16 +734,16 @@ def create_interface():
|
|
679 |
# Event handlers
|
680 |
validate_btn.click(
|
681 |
fn=validate_rdf_interface,
|
682 |
-
inputs=[rdf_input, template_dropdown, use_ai_checkbox],
|
683 |
outputs=[status_output, results_output, suggestions_output, corrected_output]
|
684 |
)
|
685 |
|
686 |
-
#
|
687 |
-
rdf_input.change(
|
688 |
-
|
689 |
-
|
690 |
-
|
691 |
-
)
|
692 |
|
693 |
# Example buttons
|
694 |
example1_btn.click(
|
@@ -758,7 +813,7 @@ def create_interface():
|
|
758 |
- β
Real-time RDF/XML validation against SHACL schemas
|
759 |
- π€ AI-powered error suggestions and corrections (with HF Inference Endpoint)
|
760 |
- π Built-in examples and templates
|
761 |
-
-
|
762 |
- π Copy results with one click
|
763 |
|
764 |
**Note:** AI features require a valid Hugging Face API key (HF_API_KEY) set as a Secret. Manual suggestions are provided as fallback.
|
|
|
53 |
HF_MODEL = "lmstudio-community/Llama-3.3-70B-Instruct-GGUF" # Correct model name for your endpoint
|
54 |
|
55 |
# AI Correction Configuration
|
56 |
+
MAX_CORRECTION_ATTEMPTS = 2 # Reduced from 3 to speed up processing
|
57 |
+
ENABLE_VALIDATION_LOOP = False # Disable validation loop to prevent hanging
|
58 |
|
59 |
# OpenAI client configuration for the endpoint
|
60 |
def get_openai_client():
|
|
|
168 |
"conforms": False
|
169 |
}
|
170 |
|
171 |
+
def get_ai_suggestions(validation_results: str, rdf_content: str, include_warnings: bool = False) -> str:
|
172 |
"""
|
173 |
Generate AI-powered fix suggestions for invalid RDF/XML.
|
174 |
|
|
|
178 |
Args:
|
179 |
validation_results (str): The validation error messages
|
180 |
rdf_content (str): The original RDF/XML content that failed validation
|
181 |
+
include_warnings (bool): Whether to include warnings in suggestions
|
182 |
|
183 |
Returns:
|
184 |
str: Detailed suggestions for fixing the RDF validation issues
|
|
|
206 |
{generate_manual_suggestions(validation_results)}
|
207 |
"""
|
208 |
|
209 |
+
severity_instruction = "Focus only on violations (errors) and ignore any warnings." if not include_warnings else "Address both violations and warnings."
|
210 |
+
|
211 |
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.
|
212 |
|
213 |
+
{severity_instruction}
|
214 |
+
|
215 |
Validation Results:
|
216 |
{validation_results}
|
217 |
|
|
|
229 |
# Make API call using OpenAI client
|
230 |
print(f"π Making API call to: {HF_ENDPOINT_URL}")
|
231 |
print(f"π Using model: {HF_MODEL}")
|
232 |
+
print(f"π Include warnings: {include_warnings}")
|
233 |
|
234 |
chat_completion = client.chat.completions.create(
|
235 |
model=HF_MODEL,
|
|
|
246 |
|
247 |
print("β
API call successful")
|
248 |
generated_text = chat_completion.choices[0].message.content
|
249 |
+
return f"π€ **AI-Powered Suggestions ({('Violations + Warnings' if include_warnings else 'Violations Only')}):**\n\n{generated_text}"
|
250 |
|
251 |
except Exception as e:
|
252 |
logger.error(f"OpenAI/HF Inference Endpoint error: {str(e)}")
|
|
|
285 |
# If no code blocks found, return the response as-is
|
286 |
return response
|
287 |
|
288 |
+
def get_ai_correction(validation_results: str, rdf_content: str, template: str = 'monograph', max_attempts: int = None, include_warnings: bool = False) -> str:
|
289 |
"""
|
290 |
Generate AI-powered corrected RDF/XML based on validation errors.
|
291 |
|
|
|
298 |
rdf_content (str): The original invalid RDF/XML content
|
299 |
template (str): The validation template to use
|
300 |
max_attempts (int): Maximum number of attempts to generate valid RDF (uses MAX_CORRECTION_ATTEMPTS if None)
|
301 |
+
include_warnings (bool): Whether to fix warnings in addition to violations
|
302 |
|
303 |
Returns:
|
304 |
str: Corrected RDF/XML that should pass validation
|
|
|
329 |
|
330 |
{generate_manual_correction_hints(validation_results, rdf_content)}"""
|
331 |
|
332 |
+
# Add timeout protection
|
333 |
+
import time
|
334 |
+
start_time = time.time()
|
335 |
+
timeout = 60 # 60 second timeout
|
336 |
+
|
337 |
+
severity_instruction = "Fix only the violations (errors) and ignore any warnings." if not include_warnings else "Fix both violations and warnings."
|
338 |
+
|
339 |
# Try multiple attempts to generate valid RDF
|
340 |
for attempt in range(max_attempts):
|
341 |
+
# Check timeout
|
342 |
+
if time.time() - start_time > timeout:
|
343 |
+
print(f"β° Timeout reached after {timeout} seconds")
|
344 |
+
break
|
345 |
+
|
346 |
+
print(f"π Correction attempt {attempt + 1}/{max_attempts}")
|
347 |
+
|
348 |
prompt = f"""You are an expert in RDF/XML. Fix the following RDF/XML based on the validation errors provided.
|
349 |
|
350 |
+
{severity_instruction}
|
351 |
+
|
352 |
Validation Errors:
|
353 |
{validation_results}
|
354 |
|
|
|
364 |
- Add any missing required properties
|
365 |
- Fix any syntax or structural issues"""
|
366 |
|
367 |
+
try:
|
368 |
+
chat_completion = client.chat.completions.create(
|
369 |
+
model=HF_MODEL,
|
370 |
+
messages=[
|
371 |
+
{
|
372 |
+
"role": "user",
|
373 |
+
"content": prompt
|
374 |
+
}
|
375 |
+
],
|
376 |
+
max_tokens=2000,
|
377 |
+
temperature=0.3,
|
378 |
+
timeout=30 # 30 second timeout per API call
|
379 |
+
)
|
380 |
+
|
381 |
+
corrected_rdf = chat_completion.choices[0].message.content.strip()
|
382 |
+
|
383 |
+
# Extract RDF content if it's wrapped in code blocks
|
384 |
+
corrected_rdf = extract_rdf_from_response(corrected_rdf)
|
385 |
+
|
386 |
+
# Only validate if we have the validator and haven't hit timeout
|
387 |
+
if VALIDATOR_AVAILABLE and (time.time() - start_time < timeout - 10):
|
388 |
+
try:
|
389 |
+
# Quick validation check
|
390 |
+
conforms, new_results = validate_rdf(corrected_rdf.encode('utf-8'), template)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
391 |
|
392 |
+
if conforms:
|
393 |
+
print(f"β
Correction validated successfully on attempt {attempt + 1}")
|
394 |
+
return f"""<!-- AI-generated correction validated successfully -->
|
395 |
+
{corrected_rdf}"""
|
396 |
+
else:
|
397 |
+
print(f"β Correction attempt {attempt + 1} still has validation errors")
|
398 |
+
# Update validation_results for next attempt
|
399 |
+
validation_results = new_results
|
400 |
+
|
401 |
+
except Exception as e:
|
402 |
+
print(f"β οΈ Error validating correction attempt {attempt + 1}: {str(e)}")
|
403 |
+
# If validation fails, return the correction anyway
|
404 |
+
return f"""<!-- AI-generated correction (validation check failed) -->
|
405 |
+
{corrected_rdf}"""
|
406 |
+
else:
|
407 |
+
# If validator not available or timeout approaching, return the correction
|
408 |
+
print("β οΈ Returning correction without validation")
|
409 |
+
return f"""<!-- AI-generated correction (validation skipped) -->
|
410 |
+
{corrected_rdf}"""
|
411 |
+
|
412 |
+
except Exception as api_error:
|
413 |
+
print(f"β API error on attempt {attempt + 1}: {str(api_error)}")
|
414 |
+
if attempt == max_attempts - 1: # Last attempt
|
415 |
+
raise api_error
|
416 |
+
continue
|
417 |
+
|
418 |
+
# All attempts failed or timed out
|
419 |
+
return f"""<!-- AI correction failed after {max_attempts} attempts or timeout -->
|
420 |
<!-- Please correct manually using the validation results as a guide -->
|
421 |
|
422 |
{generate_manual_correction_hints(validation_results, rdf_content)}"""
|
|
|
489 |
5. Validate data types
|
490 |
-->"""
|
491 |
|
492 |
+
def validate_rdf_interface(rdf_content: str, template: str, use_ai: bool = True, include_warnings: bool = False):
|
493 |
"""
|
494 |
Main validation function for Gradio interface and MCP server.
|
495 |
|
|
|
501 |
rdf_content (str): The RDF/XML content to validate
|
502 |
template (str): Validation template to use ('monograph' or 'custom')
|
503 |
use_ai (bool): Whether to enable AI-powered suggestions and corrections
|
504 |
+
include_warnings (bool): Whether to include warnings in AI corrections (violations only by default)
|
505 |
|
506 |
Returns:
|
507 |
tuple: (status, results_text, suggestions, corrected_rdf) containing:
|
|
|
522 |
status = result["status"]
|
523 |
results_text = result["results"]
|
524 |
|
525 |
+
# Filter results if warnings should be excluded
|
526 |
+
filtered_results = results_text
|
527 |
+
if not include_warnings and "Warning" in results_text:
|
528 |
+
# Split results into lines and filter out warnings
|
529 |
+
lines = results_text.split('\n')
|
530 |
+
filtered_lines = []
|
531 |
+
skip_until_next_section = False
|
532 |
+
|
533 |
+
for line in lines:
|
534 |
+
if "Warning" in line and ("Constraint Violation" in line or "sh:Warning" in line):
|
535 |
+
skip_until_next_section = True
|
536 |
+
elif "Constraint Violation" in line and "Warning" not in line:
|
537 |
+
skip_until_next_section = False
|
538 |
+
filtered_lines.append(line)
|
539 |
+
elif not skip_until_next_section:
|
540 |
+
filtered_lines.append(line)
|
541 |
+
|
542 |
+
filtered_results = '\n'.join(filtered_lines)
|
543 |
+
|
544 |
if result["conforms"]:
|
545 |
suggestions = "β
No issues found! Your RDF/XML is valid according to the selected template."
|
546 |
corrected_rdf = "β
Your RDF/XML is already valid - no corrections needed!"
|
547 |
else:
|
548 |
if use_ai:
|
549 |
+
# Pass filtered results to AI functions
|
550 |
+
suggestions = get_ai_suggestions(filtered_results, rdf_content, include_warnings)
|
551 |
+
corrected_rdf = get_ai_correction(filtered_results, rdf_content, template, include_warnings=include_warnings)
|
552 |
else:
|
553 |
+
suggestions = generate_manual_suggestions(filtered_results)
|
554 |
+
corrected_rdf = generate_manual_correction_hints(filtered_results, rdf_content)
|
555 |
|
556 |
return status, results_text, suggestions, corrected_rdf
|
557 |
|
|
|
675 |
value=True,
|
676 |
info="Enable AI-powered suggestions and corrections"
|
677 |
)
|
678 |
+
|
679 |
+
include_warnings_checkbox = gr.Checkbox(
|
680 |
+
label="Include Warnings",
|
681 |
+
value=False,
|
682 |
+
info="Include warnings in AI corrections (violations only by default)"
|
683 |
+
)
|
684 |
|
685 |
validate_btn = gr.Button("π Validate RDF", variant="primary", size="lg")
|
686 |
|
|
|
734 |
# Event handlers
|
735 |
validate_btn.click(
|
736 |
fn=validate_rdf_interface,
|
737 |
+
inputs=[rdf_input, template_dropdown, use_ai_checkbox, include_warnings_checkbox],
|
738 |
outputs=[status_output, results_output, suggestions_output, corrected_output]
|
739 |
)
|
740 |
|
741 |
+
# Remove auto-validation to prevent processing loops
|
742 |
+
# rdf_input.change(
|
743 |
+
# fn=validate_rdf_interface,
|
744 |
+
# inputs=[rdf_input, template_dropdown, use_ai_checkbox],
|
745 |
+
# outputs=[status_output, results_output, suggestions_output, corrected_output]
|
746 |
+
# )
|
747 |
|
748 |
# Example buttons
|
749 |
example1_btn.click(
|
|
|
813 |
- β
Real-time RDF/XML validation against SHACL schemas
|
814 |
- π€ AI-powered error suggestions and corrections (with HF Inference Endpoint)
|
815 |
- π Built-in examples and templates
|
816 |
+
- οΏ½ Manual validation on-demand (click to validate)
|
817 |
- π Copy results with one click
|
818 |
|
819 |
**Note:** AI features require a valid Hugging Face API key (HF_API_KEY) set as a Secret. Manual suggestions are provided as fallback.
|