fix(graph-api): rewrite generate_ontology/import_ontology to use dict ProjectManager
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
ea9ac6a1cd
commit
284f962e17
|
|
@ -5,6 +5,7 @@ Uses project context mechanism with server-side persistent state
|
||||||
|
|
||||||
import os
|
import os
|
||||||
import json
|
import json
|
||||||
|
import tempfile
|
||||||
import traceback
|
import traceback
|
||||||
import threading
|
import threading
|
||||||
from flask import request, jsonify
|
from flask import request, jsonify
|
||||||
|
|
@ -149,70 +150,51 @@ def generate_ontology():
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
logger.info("=== Starting ontology generation ===")
|
logger.info("=== Starting ontology generation ===")
|
||||||
|
storage = get_storage()
|
||||||
|
|
||||||
# Get parameters
|
|
||||||
simulation_requirement = request.form.get('simulation_requirement', '')
|
simulation_requirement = request.form.get('simulation_requirement', '')
|
||||||
project_name = request.form.get('project_name', 'Unnamed Project')
|
project_name = request.form.get('project_name', 'Unnamed Project')
|
||||||
additional_context = request.form.get('additional_context', '')
|
additional_context = request.form.get('additional_context', '')
|
||||||
|
|
||||||
logger.debug(f"Project name: {project_name}")
|
|
||||||
logger.debug(f"Simulation requirement: {simulation_requirement[:100]}...")
|
|
||||||
|
|
||||||
if not simulation_requirement:
|
if not simulation_requirement:
|
||||||
return jsonify({
|
return jsonify({"success": False, "error": t('api.requireSimulationRequirement')}), 400
|
||||||
"success": False,
|
|
||||||
"error": t('api.requireSimulationRequirement')
|
|
||||||
}), 400
|
|
||||||
|
|
||||||
# Get uploaded files
|
|
||||||
uploaded_files = request.files.getlist('files')
|
uploaded_files = request.files.getlist('files')
|
||||||
if not uploaded_files or all(not f.filename for f in uploaded_files):
|
if not uploaded_files or all(not f.filename for f in uploaded_files):
|
||||||
return jsonify({
|
return jsonify({"success": False, "error": t('api.requireFileUpload')}), 400
|
||||||
"success": False,
|
|
||||||
"error": t('api.requireFileUpload')
|
|
||||||
}), 400
|
|
||||||
|
|
||||||
# Create project
|
project = ProjectManager.create_project(name=project_name, storage=storage)
|
||||||
project = ProjectManager.create_project(name=project_name)
|
project_id = project["project_id"]
|
||||||
project.simulation_requirement = simulation_requirement
|
logger.info(f"Project created: {project_id}")
|
||||||
logger.info(f"Project created: {project.project_id}")
|
|
||||||
|
|
||||||
# Save files and extract text
|
|
||||||
document_texts = []
|
document_texts = []
|
||||||
all_text = ""
|
all_text = ""
|
||||||
|
|
||||||
for file in uploaded_files:
|
for file in uploaded_files:
|
||||||
if file and file.filename and allowed_file(file.filename):
|
if file and file.filename and allowed_file(file.filename):
|
||||||
# Save file to project directory
|
|
||||||
file_info = ProjectManager.save_file_to_project(
|
file_info = ProjectManager.save_file_to_project(
|
||||||
project.project_id,
|
project_id, file, file.filename, storage
|
||||||
file,
|
|
||||||
file.filename
|
|
||||||
)
|
)
|
||||||
project.files.append({
|
raw = storage.download(file_info["storage_path"])
|
||||||
"filename": file_info["original_filename"],
|
ext = os.path.splitext(file.filename)[1].lower()
|
||||||
"size": file_info["size"]
|
with tempfile.NamedTemporaryFile(suffix=ext, delete=False) as tmp:
|
||||||
})
|
tmp.write(raw)
|
||||||
|
tmp_path = tmp.name
|
||||||
# Extract text
|
try:
|
||||||
text = FileParser.extract_text(file_info["path"])
|
text = FileParser.extract_text(tmp_path)
|
||||||
|
finally:
|
||||||
|
os.unlink(tmp_path)
|
||||||
text = TextProcessor.preprocess_text(text)
|
text = TextProcessor.preprocess_text(text)
|
||||||
document_texts.append(text)
|
document_texts.append(text)
|
||||||
all_text += f"\n\n=== {file_info['original_filename']} ===\n{text}"
|
all_text += f"\n\n=== {file.filename} ===\n{text}"
|
||||||
|
|
||||||
if not document_texts:
|
if not document_texts:
|
||||||
ProjectManager.delete_project(project.project_id)
|
ProjectManager.delete_project(project_id, storage=storage)
|
||||||
return jsonify({
|
return jsonify({"success": False, "error": t('api.noDocProcessed')}), 400
|
||||||
"success": False,
|
|
||||||
"error": t('api.noDocProcessed')
|
|
||||||
}), 400
|
|
||||||
|
|
||||||
# Save extracted text
|
ProjectManager.save_extracted_text(project_id, all_text, storage)
|
||||||
project.total_text_length = len(all_text)
|
|
||||||
ProjectManager.save_extracted_text(project.project_id, all_text)
|
|
||||||
logger.info(f"Text extraction complete, total {len(all_text)} characters")
|
logger.info(f"Text extraction complete, total {len(all_text)} characters")
|
||||||
|
|
||||||
# Generate ontology
|
|
||||||
logger.info("Calling LLM to generate ontology definition...")
|
logger.info("Calling LLM to generate ontology definition...")
|
||||||
generator = OntologyGenerator()
|
generator = OntologyGenerator()
|
||||||
ontology = generator.generate(
|
ontology = generator.generate(
|
||||||
|
|
@ -221,38 +203,34 @@ def generate_ontology():
|
||||||
additional_context=additional_context if additional_context else None
|
additional_context=additional_context if additional_context else None
|
||||||
)
|
)
|
||||||
|
|
||||||
# Save ontology to project
|
entity_types = ontology.get("entity_types", [])
|
||||||
entity_count = len(ontology.get("entity_types", []))
|
edge_types = ontology.get("edge_types", [])
|
||||||
edge_count = len(ontology.get("edge_types", []))
|
analysis_summary = ontology.get("analysis_summary", "")
|
||||||
logger.info(f"Ontology generation complete: {entity_count} entity types, {edge_count} relationship types")
|
logger.info(f"Ontology generation complete: {len(entity_types)} entity types, {len(edge_types)} relationship types")
|
||||||
|
|
||||||
|
ProjectManager.save_ontology(project_id, entity_types, edge_types)
|
||||||
|
ProjectManager.save_project({
|
||||||
|
"id": project_id,
|
||||||
|
"simulation_requirement": simulation_requirement,
|
||||||
|
"analysis_summary": analysis_summary,
|
||||||
|
"status": ProjectStatus.ONTOLOGY_GENERATED,
|
||||||
|
})
|
||||||
|
logger.info(f"=== Ontology generation complete === Project ID: {project_id}")
|
||||||
|
|
||||||
project.ontology = {
|
|
||||||
"entity_types": ontology.get("entity_types", []),
|
|
||||||
"edge_types": ontology.get("edge_types", [])
|
|
||||||
}
|
|
||||||
project.analysis_summary = ontology.get("analysis_summary", "")
|
|
||||||
project.status = ProjectStatus.ONTOLOGY_GENERATED
|
|
||||||
ProjectManager.save_project(project)
|
|
||||||
logger.info(f"=== Ontology generation complete === Project ID: {project.project_id}")
|
|
||||||
|
|
||||||
return jsonify({
|
return jsonify({
|
||||||
"success": True,
|
"success": True,
|
||||||
"data": {
|
"data": {
|
||||||
"project_id": project.project_id,
|
"project_id": project_id,
|
||||||
"project_name": project.name,
|
"project_name": project_name,
|
||||||
"ontology": project.ontology,
|
"ontology": {"entity_types": entity_types, "edge_types": edge_types},
|
||||||
"analysis_summary": project.analysis_summary,
|
"analysis_summary": analysis_summary,
|
||||||
"files": project.files,
|
"files": [],
|
||||||
"total_text_length": project.total_text_length
|
"total_text_length": len(all_text)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
return jsonify({
|
return jsonify({"success": False, "error": str(e), "traceback": traceback.format_exc()}), 500
|
||||||
"success": False,
|
|
||||||
"error": str(e),
|
|
||||||
"traceback": traceback.format_exc()
|
|
||||||
}), 500
|
|
||||||
|
|
||||||
|
|
||||||
# ============== Endpoint 1b: Import ontology ==============
|
# ============== Endpoint 1b: Import ontology ==============
|
||||||
|
|
@ -274,47 +252,30 @@ def import_ontology():
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
logger.info("=== Starting ontology import ===")
|
logger.info("=== Starting ontology import ===")
|
||||||
|
storage = get_storage()
|
||||||
|
|
||||||
simulation_requirement = request.form.get('simulation_requirement', '')
|
simulation_requirement = request.form.get('simulation_requirement', '')
|
||||||
project_name = request.form.get('project_name', 'Unnamed Project')
|
project_name = request.form.get('project_name', 'Unnamed Project')
|
||||||
ontology_json = request.form.get('ontology', '')
|
ontology_json = request.form.get('ontology', '')
|
||||||
|
|
||||||
if not simulation_requirement:
|
if not simulation_requirement:
|
||||||
return jsonify({
|
return jsonify({"success": False, "error": t('api.requireSimulationRequirement')}), 400
|
||||||
"success": False,
|
|
||||||
"error": t('api.requireSimulationRequirement')
|
|
||||||
}), 400
|
|
||||||
|
|
||||||
if not ontology_json:
|
if not ontology_json:
|
||||||
return jsonify({
|
return jsonify({"success": False, "error": t('api.requireOntologyJson')}), 400
|
||||||
"success": False,
|
|
||||||
"error": t('api.requireOntologyJson')
|
|
||||||
}), 400
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
ontology = json.loads(ontology_json)
|
ontology = json.loads(ontology_json)
|
||||||
except (ValueError, TypeError):
|
except (ValueError, TypeError):
|
||||||
return jsonify({
|
return jsonify({"success": False, "error": t('api.invalidOntologyJson')}), 400
|
||||||
"success": False,
|
|
||||||
"error": t('api.invalidOntologyJson')
|
|
||||||
}), 400
|
|
||||||
|
|
||||||
if not isinstance(ontology.get('entity_types'), list) or not isinstance(ontology.get('edge_types'), list):
|
if not isinstance(ontology.get('entity_types'), list) or not isinstance(ontology.get('edge_types'), list):
|
||||||
return jsonify({
|
return jsonify({"success": False, "error": t('api.invalidOntologyStructure')}), 400
|
||||||
"success": False,
|
|
||||||
"error": t('api.invalidOntologyStructure')
|
|
||||||
}), 400
|
|
||||||
|
|
||||||
uploaded_files = request.files.getlist('files')
|
uploaded_files = request.files.getlist('files')
|
||||||
if not uploaded_files or all(not f.filename for f in uploaded_files):
|
if not uploaded_files or all(not f.filename for f in uploaded_files):
|
||||||
return jsonify({
|
return jsonify({"success": False, "error": t('api.requireFileUpload')}), 400
|
||||||
"success": False,
|
|
||||||
"error": t('api.requireFileUpload')
|
|
||||||
}), 400
|
|
||||||
|
|
||||||
project = ProjectManager.create_project(name=project_name)
|
project = ProjectManager.create_project(name=project_name, storage=storage)
|
||||||
project.simulation_requirement = simulation_requirement
|
project_id = project["project_id"]
|
||||||
logger.info(f"Project created for import: {project.project_id}")
|
logger.info(f"Project created for import: {project_id}")
|
||||||
|
|
||||||
document_texts = []
|
document_texts = []
|
||||||
all_text = ""
|
all_text = ""
|
||||||
|
|
@ -322,57 +283,54 @@ def import_ontology():
|
||||||
for file in uploaded_files:
|
for file in uploaded_files:
|
||||||
if file and file.filename and allowed_file(file.filename):
|
if file and file.filename and allowed_file(file.filename):
|
||||||
file_info = ProjectManager.save_file_to_project(
|
file_info = ProjectManager.save_file_to_project(
|
||||||
project.project_id,
|
project_id, file, file.filename, storage
|
||||||
file,
|
|
||||||
file.filename
|
|
||||||
)
|
)
|
||||||
project.files.append({
|
raw = storage.download(file_info["storage_path"])
|
||||||
"filename": file_info["original_filename"],
|
ext = os.path.splitext(file.filename)[1].lower()
|
||||||
"size": file_info["size"]
|
with tempfile.NamedTemporaryFile(suffix=ext, delete=False) as tmp:
|
||||||
})
|
tmp.write(raw)
|
||||||
|
tmp_path = tmp.name
|
||||||
text = FileParser.extract_text(file_info["path"])
|
try:
|
||||||
|
text = FileParser.extract_text(tmp_path)
|
||||||
|
finally:
|
||||||
|
os.unlink(tmp_path)
|
||||||
text = TextProcessor.preprocess_text(text)
|
text = TextProcessor.preprocess_text(text)
|
||||||
document_texts.append(text)
|
document_texts.append(text)
|
||||||
all_text += f"\n\n=== {file_info['original_filename']} ===\n{text}"
|
all_text += f"\n\n=== {file.filename} ===\n{text}"
|
||||||
|
|
||||||
if not document_texts:
|
if not document_texts:
|
||||||
ProjectManager.delete_project(project.project_id)
|
ProjectManager.delete_project(project_id, storage=storage)
|
||||||
return jsonify({
|
return jsonify({"success": False, "error": t('api.noDocProcessed')}), 400
|
||||||
"success": False,
|
|
||||||
"error": t('api.noDocProcessed')
|
|
||||||
}), 400
|
|
||||||
|
|
||||||
project.total_text_length = len(all_text)
|
ProjectManager.save_extracted_text(project_id, all_text, storage)
|
||||||
ProjectManager.save_extracted_text(project.project_id, all_text)
|
|
||||||
|
|
||||||
project.ontology = {
|
entity_types = ontology.get("entity_types", [])
|
||||||
"entity_types": ontology.get("entity_types", []),
|
edge_types = ontology.get("edge_types", [])
|
||||||
"edge_types": ontology.get("edge_types", [])
|
analysis_summary = ontology.get("analysis_summary", "")
|
||||||
}
|
|
||||||
project.analysis_summary = ontology.get("analysis_summary", "")
|
ProjectManager.save_ontology(project_id, entity_types, edge_types)
|
||||||
project.status = ProjectStatus.ONTOLOGY_GENERATED
|
ProjectManager.save_project({
|
||||||
ProjectManager.save_project(project)
|
"id": project_id,
|
||||||
logger.info(f"=== Ontology import complete === Project ID: {project.project_id}")
|
"simulation_requirement": simulation_requirement,
|
||||||
|
"analysis_summary": analysis_summary,
|
||||||
|
"status": ProjectStatus.ONTOLOGY_GENERATED,
|
||||||
|
})
|
||||||
|
logger.info(f"=== Ontology import complete === Project ID: {project_id}")
|
||||||
|
|
||||||
return jsonify({
|
return jsonify({
|
||||||
"success": True,
|
"success": True,
|
||||||
"data": {
|
"data": {
|
||||||
"project_id": project.project_id,
|
"project_id": project_id,
|
||||||
"project_name": project.name,
|
"project_name": project_name,
|
||||||
"ontology": project.ontology,
|
"ontology": {"entity_types": entity_types, "edge_types": edge_types},
|
||||||
"analysis_summary": project.analysis_summary,
|
"analysis_summary": analysis_summary,
|
||||||
"files": project.files,
|
"files": [],
|
||||||
"total_text_length": project.total_text_length
|
"total_text_length": len(all_text)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
return jsonify({
|
return jsonify({"success": False, "error": str(e), "traceback": traceback.format_exc()}), 500
|
||||||
"success": False,
|
|
||||||
"error": str(e),
|
|
||||||
"traceback": traceback.format_exc()
|
|
||||||
}), 500
|
|
||||||
|
|
||||||
|
|
||||||
# ============== Endpoint 2: Build graph ==============
|
# ============== Endpoint 2: Build graph ==============
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue