diff --git a/sbs_server/app/utils.py b/sbs_server/app/utils.py new file mode 100644 index 0000000..54a1556 --- /dev/null +++ b/sbs_server/app/utils.py @@ -0,0 +1,57 @@ +import sbol2 +import sbol2build as s2b +from sbol2build import abstract_translator as at + +from typing import List, Tuple + +def abstract_design_2_plasmids(abstract_design_uri: str, plasmid_collection_uri: str, plasmid_vector_uri: str, sbh: sbol2.PartShop) -> Tuple[List[sbol2.Document], sbol2.Document, str]: + abstract_design_doc = sbol2.Document() + sbh.pull( + abstract_design_uri, + abstract_design_doc + ) + + abstract_design_id = at.extract_toplevel_definition(abstract_design_doc).displayId + + plasmid_collection_doc = sbol2.Document() + sbh.pull( + plasmid_collection_uri, + plasmid_collection_doc + ) + + backbone_doc = sbol2.Document() + sbh.pull( + plasmid_vector_uri, + backbone_doc, + ) + + mocloplasmid_list = at.translate_abstract_to_plasmids( + abstract_design_doc, plasmid_collection_doc, backbone_doc + ) + + part_documents = [] + for mocloPlasmid in mocloplasmid_list: + temp_doc = sbol2.Document() + mocloPlasmid.definition.copy(temp_doc) + at.copy_sequences( + mocloPlasmid.definition, + temp_doc, + plasmid_collection_doc + ) + part_documents.append(temp_doc) + + return part_documents, backbone_doc, abstract_design_id + +def sbol2build_moclo(part_documents: List[sbol2.Document], backbone_doc: sbol2.Document, abstract_design_id: str) -> sbol2.Document: + assembly_doc = sbol2.Document() + assembly_obj = s2b.golden_gate_assembly_plan( + f"{abstract_design_id}_assembly_plan", + part_documents, + backbone_doc, + "BsaI", + assembly_doc + ) + + composite_list = assembly_obj.run() + + return assembly_doc \ No newline at end of file diff --git a/sbs_server/app/views.py b/sbs_server/app/views.py index 892b4e5..167a360 100644 --- a/sbs_server/app/views.py +++ b/sbs_server/app/views.py @@ -2,12 +2,12 @@ from flask import Flask, render_template, request, jsonify from flask_cors import CORS from .main import app +from .utils import abstract_design_2_plasmids, sbol2build_moclo import sys import os import json import xml.etree.ElementTree as ET -import sbol2build import tricahue import sbol2 as sb2 import pudu @@ -132,24 +132,6 @@ def upload_file_from_sbs_post_up(): "status": "success" } return jsonify(sbs_upload_response_dict) - - - -@app.route('/sbol_2_build_golden_gate', methods=['POST']) -def sbol_2_build_golden_gate(): - # Error checking in the request - print("request", request.files) - - if 'plasmid_backbone' not in request.files: - return jsonify({"error": "Missing plasmid backbone"}), 400 - if 'insert_parts' not in request.files: - return jsonify({"error": "Missing insert parts"}), 400 - if 'wizard_selections' not in request.form: - return jsonify({"error": "Missing wizard selections"}), 400 - - wizard_selection = request.form.get('wizard_selections') - plasmid_backbone = request.files.get('plasmid_backbone') - insert_parts = request.files.getlist('insert_parts') # Parse the json @@ -177,16 +159,24 @@ def sbol_2_build_golden_gate(): assembly_obj = sbol2build.golden_gate_assembly_plan('testassem', part_docs, bb_doc, restriction_enzyme, assembly_doc) try: - composites = assembly_obj.run() + # Run abstract translator to get plasmids + plasmid_documents, vector_doc, design_id = abstract_design_2_plasmids(abstract_design_uri, plasmid_collection_uri, plasmid_vector_uri, sbh) + + # Run plasmids through sbol2build to generate assembly plan + assembly_plan_doc = sbol2build_moclo(plasmid_documents, vector_doc, design_id) + assembly_plan_doc.displayId = f"{design_id}_assembly" - return_string = assembly_doc.writeString() - - # Return the file as a response - return return_string + + sbh_response = sbh.submit( + doc=assembly_plan_doc, + collection=recipient_collection_uri, + overwrite=2 + ) + return sbh_response.text, sbh_response.status_code except ValueError as e: - # catch sbol2build errors and return to frontend return jsonify({"error": str(e)}), 400 + except Exception as e: return jsonify({"error": f"Unexpected server error: {str(e)}"}), 500