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:
Ubuntu 2026-05-03 01:20:32 +00:00
parent ea9ac6a1cd
commit 284f962e17
1 changed files with 85 additions and 127 deletions

View File

@ -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 ==============