5.9 KiB
Node.js Python Binding Class Documentation
Overview
This project provides a Node.js interface (python_bindings.js) to interact with a Python backend. The Python backend exposes an API via a Controller class (controller.py) and communicates with Node.js via JSON messages over stdin/stdout using python-shell in Node.js.
The Node.js class Bindings wraps the interaction with the Python process and exposes asynchronous methods mapped dynamically to Python Controller methods. It supports property setting/getting, method calling with parameters, and streaming partial results via callbacks.
Files and Components
1. index.js
- Entry point example illustrating usage of the
ChatModel(the default export frompython_bindings.js). - Shows setting properties, calling methods, receiving streamed messages, and proper shutdown.
- This file is intended for customization by users for their use case.
Example usage:
import ChatModel from "./python_bindings.js";
const chat = new ChatModel({ "model": "something" });
await chat.setProperty("tokenizer", 123);
const modelResponse = await chat.getModelPath();
console.log(modelResponse); // { model: "something" }
const tokenizerResponse = await chat.getTokenizer();
console.log(tokenizerResponse); // { tokenizer: 123 }
let response = await chat.increment({ by: 5 });
console.log("Incremented counter:", response.counter);
chat.onMessage(function(data) {
console.log(data); // receives streamed partial results
});
chat.testStream();
chat.end();
2. python_bindings.js
- Implements
Bindingsclass which manages the Python subprocess usingpython-shell. - Sends JSON-formatted method calls with parameters to Python.
- Receives JSON responses asynchronously.
- Supports streaming JSON messages prefixed with
__STREAM__. - Uses Proxy to dynamically route method calls to Python backend methods.
- Provides:
.setProperty(name, value)to set Python controller properties..getProperty(name)to get Python controller properties..onMessage(callback)to register streaming data callback..end()to gracefully end the Python subprocess.
Key methods:
callMethod(method, ...args): sends a method call to Python and returns a promise resolving to the response.processSendQueue(): ensures requests are sent sequentially.onMessage(callback): sets a callback for streaming partial data.
3. python/controller.py
- Defines
Controllerclass that inherits fromBaseController. - Implements backend logic called by Node.js methods.
- Example methods:
getModelPath(params)getTokenizer(params)increment(params)reset(params)testStream(params)— emits streaming partial data viaself.send().
4. python/basecontroller.py
- Provides base class with common controller features:
setProperty(params): sets attributes dynamically on controller.getProperty(params): gets attributes dynamically.send(data): sends partial streaming data through injected stream function.set_stream_func(stream_func): used to inject the stream callback forsend().
5. python/router.py
- Acts as the Python message router.
- Reads JSON messages from
stdin, calls the appropriateControllermethod, and writes JSON responses tostdout. - Supports streaming partial responses with the
__STREAM__prefix. - Handles unknown methods gracefully by returning error JSON.
6. python/index.py
- Runs the
Routerinstance when executed as a script. - This is the Python entry point for the subprocess.
7. router.js
- Alternative Node.js approach (not used directly by
Bindings). - Spawns a Python process per method call.
- Supports streaming messages.
- More suited for stateless or separate process calls.
How It Works (Workflow)
-
Initialization
Bindingsstarts a persistent Python subprocess runningpython/index.pyviapython-shell.- The Python process reads JSON messages from stdin and sends JSON responses on stdout.
-
Method Calls
- Node.js sends JSON messages with
{ method: "methodName", params: { ... } }. - Python calls the matching method in
Controllerclass with params. - Python sends back
{ result: ... }or{ error: ... }.
- Node.js sends JSON messages with
-
Streaming
- Python can send partial results during long-running methods using the injected
send()function. - These partial messages are prefixed with
__STREAM__so Node.js can route them to the streaming callback.
- Python can send partial results during long-running methods using the injected
-
Dynamic Proxy
- The
Bindingsclass uses a JavaScript Proxy to make any method call on the object automatically send the request to Python and return a Promise with the result.
- The
-
Property Setting/Getting
- Properties like
modelandtokenizercan be set or fetched through dedicated calls or via.setProperty().
- Properties like
-
Shutdown
- Calling
.end()ends the Python process cleanly.
- Calling
Usage Summary
- Import
BindingsorChatModel. - Instantiate with initial properties if desired.
- Call any controller method asynchronously on the instance.
- Use
.onMessage()to handle streamed data. - Call
.end()to terminate the backend.
Notes for Customization
- Edit
controller.pyto add your own Python logic and methods. - Update
index.jsfor your application-specific flow. - Ensure Python methods return JSON serializable objects.
- Implement streaming with
send()and handle it in Node.js via.onMessage().
Example
import ChatModel from "./python_bindings.js";
const chat = new ChatModel({ model: "gpt" });
await chat.setProperty("tokenizer", 42);
const info = await chat.getModelPath();
console.log(info); // { model: "gpt" }
chat.onMessage(data => {
console.log("Streamed partial data:", data);
});
await chat.testStream();
await chat.end();
This documentation provides a comprehensive understanding of the binding class design and usage to integrate Python backend logic into a Node.js environment efficiently.