diff --git a/src/main/java/qupath/ext/instanseg/core/InstanSegModel.java b/src/main/java/qupath/ext/instanseg/core/InstanSegModel.java index 4322924..1dc15e4 100644 --- a/src/main/java/qupath/ext/instanseg/core/InstanSegModel.java +++ b/src/main/java/qupath/ext/instanseg/core/InstanSegModel.java @@ -79,22 +79,13 @@ public static InstanSegModel fromURL(String name, String version, URL browserDow * Check if the model has been downloaded already. * @return True if the model has a known path that exists and is valid, or if a suitable directory can be found in the localModelPath */ - public boolean isDownloaded(Path localModelPath) { + public boolean isValid() { // Check path first - *sometimes* the model might be downloaded, but have a name // that doesn't match with the filename (although we'd prefer this didn't happen...) if (path != null && model != null && isValidModel(path)) return true; - if (!Files.exists(localModelPath.resolve(getFolderName(name, version)))) { - // The model may have been deleted or renamed - we won't be able to load it - return false; - } - - try { - download(localModelPath); - } catch (IOException e) { - logger.error("Model directory exists but is not valid", e); - } - return path != null && model != null; + // The model may have been deleted or renamed - we won't be able to load it + return false; } /** @@ -276,7 +267,8 @@ private Optional getModel() { } private static Path downloadZipIfNeeded(URL url, Path localDirectory, String filename) throws IOException { - var zipFile = localDirectory.resolve(Path.of(filename + ".zip")); + Files.createDirectories(localDirectory); // just in case... + var zipFile = localDirectory.resolve(filename + ".zip"); if (!isDownloadedAlready(zipFile)) { try (InputStream stream = url.openStream()) { try (ReadableByteChannel readableByteChannel = Channels.newChannel(stream)) { @@ -290,8 +282,16 @@ private static Path downloadZipIfNeeded(URL url, Path localDirectory, String fil } private static boolean isDownloadedAlready(Path zipFile) { - // todo: validate contents somehow - return Files.exists(zipFile); + if (!Files.exists(zipFile)) { + return false; + } + try { + BioimageIoSpec.parseModel(zipFile.toFile()); + } catch (IOException e) { + logger.warn("Invalid zip file", e); + return false; + } + return true; } private Path unzipIfNeeded(Path zipFile) throws IOException { diff --git a/src/main/java/qupath/ext/instanseg/ui/InstanSegController.java b/src/main/java/qupath/ext/instanseg/ui/InstanSegController.java index 99e8412..5fec72a 100644 --- a/src/main/java/qupath/ext/instanseg/ui/InstanSegController.java +++ b/src/main/java/qupath/ext/instanseg/ui/InstanSegController.java @@ -375,7 +375,7 @@ private void updateInputChannels(ImageData imageData) { comboInputChannels.getCheckModel().checkIndices(IntStream.range(0, 3).toArray()); var modelDir = InstanSegUtils.getModelDirectory().orElse(null); // todo: not clear why this is needed. is this handling the checkcombobox weirdness on clearing checks, or? - if (model != null && modelDir != null && model.isDownloaded(modelDir)) { + if (model != null && modelDir != null && model.isValid()) { var modelChannels = model.getNumChannels(); if (modelChannels.isPresent()) { int nModelChannels = modelChannels.get(); @@ -464,7 +464,7 @@ private void configureRunning() { return true; } var modelDir = InstanSegUtils.getModelDirectory().orElse(null); - if (modelDir != null && !model.isDownloaded(modelDir)) { + if (modelDir != null && !model.isValid()) { return false; // to enable "download and run" } return false; @@ -488,7 +488,7 @@ private void refreshModelChoice() { return; var modelDir = InstanSegUtils.getModelDirectory().orElse(null); - boolean isDownloaded = modelDir != null && model.isDownloaded(modelDir); + boolean isDownloaded = modelDir != null && model.isValid(); if (!isDownloaded || qupath.getImageData() == null) { return; } @@ -545,7 +545,7 @@ private InstanSegModel downloadModel(InstanSegModel model, Path modelDir) { try { Dialogs.showInfoNotification(resources.getString("title"), String.format(resources.getString("ui.popup.fetching"), model.getName())); - model.download(modelDir); + model.download(modelDir.resolve("downloaded")); Dialogs.showInfoNotification(resources.getString("title"), String.format(resources.getString("ui.popup.available"), model.getName())); FXUtils.runOnApplicationThread(() -> { @@ -767,12 +767,12 @@ private void runInstanSeg(InstanSegModel model) { return; } - if (!model.isDownloaded(modelPath)) { + if (!model.isValid()) { if (!Dialogs.showYesNoDialog(resources.getString("title"), resources.getString("ui.model-popup"))) return; downloadModelAsync(model) .thenAccept((InstanSegModel suppliedModel) -> { - if (suppliedModel == null || !suppliedModel.isDownloaded(modelPath)) { + if (suppliedModel == null || !suppliedModel.isValid()) { Dialogs.showErrorNotification(resources.getString("title"), String.format(resources.getString("error.localModel"))); } else { runInstanSeg(suppliedModel); diff --git a/src/main/java/qupath/ext/instanseg/ui/InstanSegUtils.java b/src/main/java/qupath/ext/instanseg/ui/InstanSegUtils.java index 2535b5d..e057abd 100644 --- a/src/main/java/qupath/ext/instanseg/ui/InstanSegUtils.java +++ b/src/main/java/qupath/ext/instanseg/ui/InstanSegUtils.java @@ -70,7 +70,7 @@ public static BooleanBinding createModelDownloadedBinding(ObservableValue