const readme = `# Python Binding for Node.js ## Description This project enables seamless integration of a Python backend with a Node.js application by maintaining a persistent Python subprocess. It allows calling Python methods asynchronously from Node.js using a dynamic JavaScript class interface, supports setting and getting Python-side properties, and enables receiving streamed partial results from long-running Python operations. ## How to Use ### JavaScript Usage Example \`\`\`js import ChatModel from "./python_bindings.js"; async function runExample() { const chat = new ChatModel({ model: "something" }); // Set properties dynamically await chat.setProperty("model", "something"); await chat.setProperty("tokenizer", 123); // Get properties from Python backend const modelResponse = await chat.getModelPath(); console.log(modelResponse); // { Model: "something" } const tokenizerResponse = await chat.getTokenizer(); console.log(tokenizerResponse); // { Tokenizer: 123 } // Call Python methods asynchronously let response = await chat.increment({ by: 5 }); console.log("Incremented counter:", response.counter); response = await chat.increment({ by: 2 }); console.log("Incremented counter:", response.counter); response = await chat.increment({ by: 2 }); console.log("Incremented counter:", response.counter); // Listen for streamed partial results chat.onMessage(function(data) { console.log("Streamed data:", data); }); // Call method that streams partial results await chat.testStream(); // Cleanly terminate Python subprocess chat.end(); } runExample(); \`\`\` ## How to Write the Python Controller The Python controller defines the backend logic and exposes methods callable from Node.js. It should extend the provided \`BaseController\` class and implement any methods you want to call from Node.js. ### Controller Structure Example \`\`\`python # python/controller.py import time from baseController import BaseController class Controller(BaseController): model = None tokenizer = None counter = 0 def getModelPath(self, params): return {"Model": self.model} def getTokenizer(self, params): return {"Tokenizer": self.tokenizer} def increment(self, params): self.counter += params.get("by", 1) return {"counter": self.counter} def reset(self, params): self.counter = 0 return {"counter": self.counter} def testStream(self, params): for i in range(5): time.sleep(0.5) self.send({"partial": f"step {i+1} complete"}) return {"counter": self.counter} \`\`\` ### Important Details - **Inheritance:** Your controller must inherit from \`BaseController\`. - **Methods:** Each method takes a single \`params\` dictionary argument containing parameters passed from Node.js. - **Return Value:** Methods return a JSON-serializable dictionary as a response. - **Streaming:** Use \`self.send(data)\` within methods to send partial streaming data back to Node.js. The JavaScript side will receive these via the registered stream callback. - **Properties:** Define class properties to maintain state accessible from both Python and Node.js via dynamic \`setProperty\` and \`getProperty\` calls. ## Summary - Extend the Python \`Controller\` class to implement your backend logic. - Methods receive parameters and return JSON-serializable results. - Use \`self.send()\` to stream intermediate results when needed. - From Node.js, call these methods via the binding class, passing parameters as objects and receiving results asynchronously. - The binding handles JSON serialization, communication, and a persistent Python process lifecycle. This design allows flexible and efficient integration between Node.js and Python for complex applications. `; console.log(readme); import { writeFileSync } from "fs"; writeFileSync("README.md", readme);