Skip to content

Commit

Permalink
Merge pull request #96 from MyersResearchGroup/clean-download-auto
Browse files Browse the repository at this point in the history
Clean SBOL upon edit
  • Loading branch information
doublergreer authored Aug 22, 2024
2 parents f36649a + 6deda66 commit 9de197f
Show file tree
Hide file tree
Showing 8 changed files with 282,859 additions and 81 deletions.
282,690 changes: 282,690 additions & 0 deletions apps/server/SynBio2Easy.jar

Large diffs are not rendered by default.

39 changes: 37 additions & 2 deletions apps/server/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -302,6 +302,32 @@ def convert_genbank_to_sbol2(genbank_content, uri_prefix):

return result_sbol_content

def run_synbio2easy(sbol_content):
namespace = 'https://seqimprove.synbiohub.org'

try:
with tempfile.NamedTemporaryFile() as input_file:
input_file.write(bytes(sbol_content, 'utf-8'))
input_file.flush()
with tempfile.NamedTemporaryFile() as output_file:

command = [
'java', '-jar', 'SynBio2Easy.jar', 'clean',
f'--input-file={input_file.name}',
f'--output-file={output_file.name}',
f'--namespace={namespace}',
f'--remove-collections=Y'
]
print(command)
output = subprocess.check_output(command, universal_newlines=True, stderr=subprocess.STDOUT)
print(output)
cleaned_data = output_file.read().decode('utf-8')
return cleaned_data

except Exception as e:
print(e)
return sbol_content

# _______ _______ _________ _______ _______ _________ _______ _______
# ( ___ )( ____ )\__ __/ ( ____ )( ___ )|\ /|\__ __/( ____ \( ____ \
# | ( ) || ( )| ) ( | ( )|| ( ) || ) ( | ) ( | ( \/| ( \/
Expand Down Expand Up @@ -345,14 +371,24 @@ def genbank_to_sbol2():

return {"sbol2_content": "", "err": error_message };


@app.post("/api/cleanSBOL")
def clean_SBOL():
request_data = request.get_json()
sbol_content = request_data['completeSbolContent']

return {"sbol": run_synbio2easy(sbol_content)}



@app.post("/api/annotateSequence")
def annotate_sequence():
request_data = request.get_json()
sbol_content = request_data['completeSbolContent']
part_library_file_names = request_data['partLibraries']
clean_document = request_data['cleanDocument']

if clean_document:
sbol_content = run_synbio2easy(sbol_content)

print("Running SYNBICT...")
# Run SYNBICT
Expand All @@ -372,7 +408,6 @@ def annotate_sequence():
print(str(e))
return {"sbol": sbol_content}, status.HTTP_500_INTERNAL_SERVER_ERROR
else:
# return {"annotations": annotations}
return {"annotations": anno_lib_assoc}

@app.post("/api/findSimilarParts")
Expand Down
27 changes: 25 additions & 2 deletions apps/web/src/App.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,35 @@ export default function App() {
bootAPIserver();
const loadSBOL = useStore(s => s.loadSBOL)
const documentLoaded = useStore(s => !!s.document)
const isFileEdited = useStore((s) => s.isFileEdited);
const cleanSBOLDocument = useStore((s) => s.cleanSBOLDocument);
const isUriCleaned = useStore((s => s.isUriCleaned))
const nameChanged = useStore((s => s.nameChanged))

//add variable to keep track of name change

// load SBOL into store if we have a complete_sbol parameter
useEffect(() => {
// && !nameChanged
if (isFileEdited && !isUriCleaned) {
cleanSBOLDocument();
}
const paramsUri = getSearchParams().complete_sbol
paramsUri && loadSBOL(paramsUri)
}, [])
}, [isFileEdited]);

//name change effect
useEffect(() => {
if (nameChanged && !isUriCleaned) {
cleanSBOLDocument();
}
}, [nameChanged])


// load SBOL into store if we have a complete_sbol parameter
// useEffect(() => {
// const paramsUri = getSearchParams().complete_sbol
// paramsUri && loadSBOL(paramsUri)
// }, [])

return (
<MantineProvider theme={theme} withNormalizeCSS withGlobalStyles>
Expand Down
11 changes: 7 additions & 4 deletions apps/web/src/components/CurationForm.jsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Container, Title, Tabs, Text, Space, LoadingOverlay, Button, Group, Header, List, ActionIcon, Tooltip, Textarea, Menu, Modal, TextInput, PasswordInput, Loader, Center, Select, SegmentedControl, Checkbox } from '@mantine/core'
import { useStore, mutateDocument } from '../modules/store'
import { useStore, mutateDocument, mutateDocumentForDisplayID } from '../modules/store'
import { useCyclicalColors } from "../hooks/misc"
import SimilarParts from './SimilarParts'
import RoleSelection from "./RoleSelection"
Expand All @@ -17,6 +17,8 @@ import References from './References'
import { FaHome, FaPencilAlt, FaTimes, FaCheck } from 'react-icons/fa'
import { useState } from "react"
import { showErrorNotification, showNotificationSuccess } from "../modules/util"
import { Graph, SBOL2GraphView } from "sbolgraph"
import { createSBOLDocument } from '../modules/sbol'

function validDisplayID(displayID) {
return displayID.match(/^[a-z_]\w+$/i);
Expand Down Expand Up @@ -231,6 +233,7 @@ function SynBioHubClientUpload({ setIsInteractingWithSynBioHub }) {
}}
error={inputError != false}
/>
<Checkbox checked={overwrite} label="Overwrite?" description="Overwrite if submission exists" onChange={(event) => setOverwrite(event.currentTarget.checked)} />
<Button onClick={async () => {
if (inputErrorID || inputErrorVersion) {
showErrorNotification("Invalid Input", "Please address the issue and then submit.");
Expand Down Expand Up @@ -374,7 +377,7 @@ export default function CurationForm({ }) {
setIsEditingDisplayID(true);
setWorkingDisplayID(displayId);
};

const handleEndDisplayIDEdit = (cancelled = false) => {
if (cancelled) {
setIsEditingDisplayID(false);
Expand All @@ -388,7 +391,7 @@ export default function CurationForm({ }) {

setIsEditingDisplayID(false);

mutateDocument(useStore.setState, state => {
mutateDocumentForDisplayID(useStore.setState, async state => {
// updateChildURIDisplayIDs(workingDisplayID, state.document.root.displayId, state.document);

// Replace displayId in URIs in xml
Expand Down Expand Up @@ -426,7 +429,7 @@ export default function CurationForm({ }) {

const newSBOLcontent = xmlChunks.concat(remainingXML).join('');

state.loadSBOL(newSBOLcontent);
await state.replaceDocumentForIDChange(newSBOLcontent);
});
};

Expand Down
6 changes: 4 additions & 2 deletions apps/web/src/components/SequenceSection.jsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { useState, useEffect, forwardRef, createElement } from "react"
import { useForceUpdate } from "@mantine/hooks"
import { Checkbox } from '@mantine/core';
import { Button, Center, Group, Loader, NavLink, Space, CopyButton, ActionIcon, Tooltip, Textarea, MultiSelect, Text, Highlight} from "@mantine/core"
import { FiDownloadCloud } from "react-icons/fi"
import { FaCheck, FaPencilAlt, FaPlus, FaTimes, FaArrowRight } from "react-icons/fa"
Expand Down Expand Up @@ -321,7 +322,7 @@ function Annotations({ colors }) {
setSequencePartLibrariesSelected(...librariesSelected);
})}
/>

{loading ?
<Center>
<Loader my={30} size="sm" variant="dots" /> :
Expand All @@ -334,7 +335,8 @@ function Annotations({ colors }) {
color="blue"
onClick={handleAnalyzeSequenceClick}
sx={{ borderRadius: 6 }}
/>}
/>
}
</FormSection>
)
}
Expand Down
37 changes: 36 additions & 1 deletion apps/web/src/modules/api.js
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,41 @@ export async function fetchSBOL(url) {
}
}

export async function fetchAnnotateSequence({ sbolContent, selectedLibraryFileNames }) {
export async function cleanSBOL(sbolContent) {
try {
var response = await fetchWithTimeout(`${import.meta.env.VITE_API_LOCATION}/api/cleanSBOL`, {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify({
completeSbolContent: sbolContent,
}),
timeout: 120000,
});
}
catch (err) {
console.error("Failed to fetch.");
showServerErrorNotification();
return;
}

try {
var result = await response.json();
}
catch (err) {
console.error("Couldn't parse JSON.");
showServerErrorNotification();
return;
}

if (response.status == 200) {
console.log("Clean SBOL fetched.");
return result.sbol
}
}

export async function fetchAnnotateSequence({ sbolContent, selectedLibraryFileNames, isUriCleaned }) {
console.log("Annotating sequence...")

// Fetch
Expand All @@ -84,6 +118,7 @@ export async function fetchAnnotateSequence({ sbolContent, selectedLibraryFileNa
body: JSON.stringify({
completeSbolContent: sbolContent,
partLibraries: selectedLibraryFileNames,
cleanDocument: !isUriCleaned,
}),
timeout: 120000,
});
Expand Down
14 changes: 14 additions & 0 deletions apps/web/src/modules/sbol.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { Graph, S2ComponentDefinition, S2ComponentInstance, SBOL2GraphView } fro
import { TextBuffer } from "text-ranger"
import { mutateDocument, useAsyncLoader, useStore } from "./store"

//change to seqimprove.synbiohub.org?
const Prefix = "https://seqimprove.org/"

const Predicates = {
Expand Down Expand Up @@ -134,6 +135,13 @@ export async function createSBOLDocument(sbolContent) {
return document
}

export function isfromSynBioHub(componentDefinition) {
//expand to include every sbh instance
if (componentDefinition.uriChain.includes('https://synbiohub.org')) return true

return false
}

/**
* Return the active status of any annotation in the sequenceAnnotations array
*
Expand Down Expand Up @@ -239,6 +247,12 @@ export function removeAnnotationWithDefinition(componentDefinition, id) {
definition.destroy()
}

export function incrementVersion(componentDefinition) {
const version = Number(componentDefinition.version)

componentDefinition.version = version + 1
}

/**
* Finds existing SequenceAnnotations on a ComponentDefinition and returns
* them in a form suitable for the store.
Expand Down
Loading

0 comments on commit 9de197f

Please sign in to comment.