1.16.5 Cannot run Deep Java Library (DJL) in a plugin

Discussion in 'Spigot Plugin Development' started by hasunemiku2015, Jun 29, 2021.

  1. I am developing a plugin that requires the use of Deep Java Library.

    Code (Java):
    private static Model encoder,decoder,merger,refiner;

        public static void init(){
            Path modelDir = Paths.get("./saved_model/");
            try {
                encoder = Model.newInstance("encoder.pt");
                encoder.load(modelDir);

                decoder = Model.newInstance("decoder.pt");
                decoder.load(modelDir);

                merger = Model.newInstance("merger.pt");
                merger.load(modelDir);

                refiner = Model.newInstance("refiner.pt");
                refiner.load(modelDir);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    The following code worked fine (No Exceptions) if its in a separate java executable (built with maven).

    However, if I ran the same set of code in a spigot plugin, it results in the following error:

    Code (Text):
    [09:19:30] [Thread-38/WARN]: ai.djl.engine.EngineException: No deep learning engine found.

    [09:19:30] [Thread-38/WARN]: Please refer to https://github.com/deepjavalibrary/djl/blob/master/docs/development/troubleshooting.md for more details.
    [09:19:30] [Thread-38/WARN]:     at ai.djl.engine.Engine.getInstance(Engine.java:114)
    [09:19:30] [Thread-38/WARN]:     at ai.djl.Model.newInstance(Model.java:71)
    [09:19:30] [Thread-38/WARN]:     at ai.djl.Model.newInstance(Model.java:60)
    [09:19:30] [Thread-38/WARN]:     at me.hasunemiku2015.buildingai.DataHandling.MLProcessor.lambda$init$0(MLProcessor.java:27)
    [09:19:30] [Thread-38/WARN]:     at java.lang.Thread.run(Unknown Source)
    I have tried everything in the md file in the error, and the error still persists. Does anyone know why and could anyone provide a solution for that?

    My maven build path is provided below:
    https://pastebin.com/sUzQyani
     
    #1 hasunemiku2015, Jun 29, 2021
    Last edited: Jun 29, 2021
  2. I tried that and its not working, thats why I post here
     
  3. Do you build the plugin the same as the executable jar?
    Maybe try and unzip the plugin.jar and check if the required libraries are inside.
     
  4. I used a maven shade plugin to shade everything in, so theoretically everything should be inside?

    upload_2021-6-29_12-57-40.png
     
  5. The problem here I think is that it will look for the server's META-INF since that is the executable in this case.
    So I'm curious if there is a workaround to dynamically add services
     
  6. You might not like it but I think this is your best shot.
    Adding this at the begin of your application (before everything, including the Enginge).

    Code (Java):
    Field field = ai.djl.engine.Engine.class.getDeclaredField("ALL_ENGINES");
    field.setAccessible(true);

    Map<String, EngineProvider> providers = field.get(null);

    PtEngineProvider provider = new PtEngineProvider();
    providers.put(provider.getEngineName(), provider);
    That will hopefully do the job for you
     
  7. Nope, it didn't work....

    I guess the only way for it to work is modding the spigot jar, adding all the classes for DJL into it and add the services into the META-INF folders.
     
  8. Dont give up yet.
    https://www.spigotmc.org/threads/need-help-using-serviceloader.401261/
    Put
    Code (Java):
    Engine.getInstance()
    inside the main Plugin class constructor or onenable()
     
  9. Like this?

    Code (Java):
    public final class RoboArchitect extends JavaPlugin {
        public static RoboArchitect plugin;

        @Override
        public void onEnable() {
            try {
                Field field = Engine.class.getDeclaredField("ALL_ENGINES");
                field.setAccessible(true);

                Map<String, EngineProvider> providers = (Map<String, EngineProvider>) field.get(null);

                PtEngineProvider provider = new PtEngineProvider();
                providers.put(provider.getEngineName(), provider);
            } catch (NoSuchFieldException | IllegalAccessException ignored) {}

            Engine.getInstance();
            plugin = this;

            //Copy files from resource folder
            if (!plugin.getDataFolder().exists()) plugin.getDataFolder().mkdir();
            createModelIfNotExist("encoder.pt");
            createModelIfNotExist("decoder.pt");
            createModelIfNotExist("merger.pt");
            createModelIfNotExist("refiner.pt");

            MLProcessor.init();
            Objects.requireNonNull(this.getServer().getPluginCommand("/infer")).setExecutor(new CommandListener());
        }

        private void createModelIfNotExist(String name) {
            if (!new File(plugin.getDataFolder(), name).exists()) {
                InputStream stream = plugin.getResource(name);
                assert stream != null;
                try {
                    FileUtils.copyInputStreamToFile(stream, new File(plugin.getDataFolder(), name));
                } catch (IOException ex) {
                    plugin.getLogger().warning("Cannot create file " + name + " from resource!");
                }
            }
        }
    }
    Sadly it doesn't work...
    I know nothing about fields and such