Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Does java embed runtime support typescript #709

Open
JoyfulAndSpeedyMan opened this issue Mar 3, 2023 · 7 comments
Open

Does java embed runtime support typescript #709

JoyfulAndSpeedyMan opened this issue Mar 3, 2023 · 7 comments
Assignees
Labels
question Further information is requested

Comments

@JoyfulAndSpeedyMan
Copy link

When I try to import the openai library, I throw syntax error exceptions
npm install openai

@oubidar-Abderrahim oubidar-Abderrahim self-assigned this Mar 8, 2023
@oubidar-Abderrahim oubidar-Abderrahim added the question Further information is requested label Mar 8, 2023
@oubidar-Abderrahim
Copy link
Member

Hi, can you share the stacktrace of the issue and how you import the library, for clarification

@JoyfulAndSpeedyMan
Copy link
Author

JoyfulAndSpeedyMan commented Mar 14, 2023

Hi, can you share the stacktrace of the issue and how you import the library, for clarification

I am sorry for the late reply.

graalVM version: 17.0.6

Here is the java code

package org.example;

import org.graalvm.polyglot.*;
import org.graalvm.polyglot.io.FileSystem;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.HashMap;
import java.util.Map;

public class HelloPolyglot {
    public static void main(String[] args) throws IOException {
        Map<String, String> options = new HashMap<>();
        options.put("js.commonjs-require", "true");
        String node_modules = Paths.get("node_modules").toAbsolutePath().toString();
        options.put("js.commonjs-require-cwd", node_modules);
        FileSystem fileSystem = FileSystem.newDefaultFileSystem();
        fileSystem.setCurrentWorkingDirectory(Paths.get("node_modules").toAbsolutePath());
        Context cx = Context.newBuilder("js")
                .allowExperimentalOptions(true)
                .allowIO(true)
                .fileSystem(fileSystem)
                .options(options)
                .build();
        String code = Files.readString(Paths.get("t.js"));
        Value module = cx.eval("js", code);
    }
}

node_modules is generated using npm install openai

package.json

{
  "dependencies": {
    "openai": "^3.2.1"
  }
}

t.js is stored in js code, in a separate file for easy editing

const { Configuration, OpenAIApi } = require("openai/common.ts");
const configuration = new Configuration({
    apiKey: ".....",
});
const openai = new OpenAIApi(configuration);
const response = await openai.createCompletion({
    model: "text-davinci-003",
    prompt: "Say this is a test",
    temperature: 0,
    max_tokens: 7,
});
print(response);

The running code throws the following exception message

Exception in thread "main" SyntaxError: Unnamed:6:23 Expected ; but found openai
const response = await openai.createCompletion({
                       ^
Unnamed:8:10 Expected ; but found :
    prompt: "Say this is a test",
          ^
Unnamed:10:14 Expected ; but found :
    max_tokens: 7,
              ^
Unnamed:11:0 Expected eof but found }
});
^

	at org.graalvm.sdk/org.graalvm.polyglot.Context.eval(Context.java:425)
	at org.example.HelloPolyglot.main(HelloPolyglot.java:27)

Process finished with exit code 1

@iamstolis
Copy link
Member

SyntaxError: Unnamed:6:23 Expected ; but found openai
const response = await openai.createCompletion({
                       ^

This syntax error is caused by the fact that you attempt to use await outside async function. Just put the whole source into an async function:

(async () => {
// your original t.js
})();

Also note that JavaScript engines (including v8/Node.js and graaljs) do not support TypeScript directly typically. TypeScript sources are usually transpiled into JavaScript sources during installation of the corresponding package and the resulting JavaScript sources are used instead. In other words, do not require openai/common.ts, this will not work. Require openai/dist/index.js instead.

@JoyfulAndSpeedyMan
Copy link
Author

JoyfulAndSpeedyMan commented Mar 15, 2023

(async () => {
// your original t.js
})();

After your guidance, I changed the code to the following form, but it doesn't seem to work as expected
HelloPolyglot.java

public class HelloPolyglot {
    public static void main(String[] args) throws IOException, InterruptedException {
        Map<String, String> options = new HashMap<>();
        options.put("js.commonjs-require", "true");
        String node_modules = Paths.get("node_modules").toAbsolutePath().toString();
        options.put("js.commonjs-require-cwd", node_modules);
        FileSystem fileSystem = FileSystem.newDefaultFileSystem();
        fileSystem.setCurrentWorkingDirectory(Paths.get("node_modules").toAbsolutePath());
        Context cx = Context.newBuilder("js")
                .allowExperimentalOptions(true)
                .allowIO(true)
                .fileSystem(fileSystem)
                .options(options)
                .build();
        String code = Files.readString(Paths.get("t.js"));
        Value v = cx.eval("js", code);
        System.out.println(v.toString());
        Thread.currentThread().join();
    }
}

t.js

const { Configuration, OpenAIApi } = require("openai/dist/index.js");
console.log("111")
const fun = (async () => {
    console.log("async in ")
    const configuration = new Configuration({
        apiKey: ".....",
    });
    console.log("configuration")
    const openai = new OpenAIApi(configuration);
    console.log("openai")
    const response = await openai.createCompletion({
        model: "text-davinci-003",
        prompt: "Say this is a test",
        temperature: 0,
        max_tokens: 7,
    });
    console.log("response")
    console.log(response)
});
fun();
console.log("222")

Console output

111
async in 
222
undefined

It seems that from the new Configuration onwards, the code does not execute properly, and the console does not see any error messages

@iamstolis
Copy link
Member

and the console does not see any error messages

Errors from async functions are not printed by default. They reject the promise returned by the async function. You have various options to see the error:

  • add catch handler to the returned promise (i.e. fun().catch(e => console.log(e));)
  • wrap the problematic code in the async function with try-catch block
  • set js.unhandled-rejections context option to warn

Note that the last alternative would print also unhandled promise rejections from other sources. This may be both helpful (when they are relevant) and confusing (when they are not relevant to you).

@JoyfulAndSpeedyMan
Copy link
Author

  • .catch(e => console.log(e))

Thanks, I can now print out the error message using fun().catch(e => console.log(e));

From the information, it seems that the import failed. The console information is as follows:

111
async in 
222
TypeError: Cannot load module: 'util'
undefined

@iamstolis
Copy link
Member

Node that ECMAScript (=JavaScript) specification does not define any object that would allow you to interact with the outer world, i.e., it does not have support for filesystem access, network access, input/output etc.

JavaScript engines (like graaljs) typically implement the specification and add very little support for the interaction with the outer world - like functions for reading from the standard input and writing to the standard output. They do not provide advanced stuff like filesystem or network access, for example.

It is on the embedder of the JavaScript engine to provide the needed stuff. Web browsers do so through various Web APIs (like XMLHttpRequest, WebSocket API etc.) Node.js does so through their core modules (fs, http etc.)

util is a core Node.js module. graals (being "only" a JavaScript engine) does not provide any replacement for this (or any other core Node.js) module. It is up to you (= the embedder of JavaScript engine) to provide the needed stuff.

Sometimes, you can use the replacements provided by browserify or webpack frameworks but if your application needs some non-trivial interaction with the outer world (for example, performs an HTTP request) then these replacements will not work in a plain JavaScript engine (as the replacement has to depend on features provided by the target environment i.e. browsers in this case).

In summary, our CommonJS support will allow out-of-the-box execution of Node.js applications that do not need non-trivial interaction with the outer world only. For other applications, it is up to you to provide the needed functionality (through Java/JavaScript interoperability, for example).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
question Further information is requested
Projects
None yet
Development

No branches or pull requests

3 participants