Open xp1632 opened 5 months ago
generators/visual_program.ts
visual_program
in VP
code_generator.ts
fileThis is the visual summary of class and method in visual_program
and index.ts
:
FunctionCallsFunc
We search for FunctionCalls
Functions from startNode
by configType
of function call
generators/generation_result.ts
Set
to store imports
to avoid duliplication code_generator.ts
code_generator
is the basis of the following python_generator
main
node of flow nodes function calls and definition pair
functionToNode
method we defined in python_generator
for every node in sortedNodeList
python_generator.ts
:This file is more complex than I thought so I'll first write down the basic understanding to help sort it out
NodeToCode()
:
input
and output
of a node to python code we needresult
with NodeGenRes
type to store generation resultprerequisiteCodeOfInputs
to store the code should be executed before our current codeFor every Input
, we have getInputValueOfNode()
method to
valueNode
converter
between imageInput
and imageOutput
convertFunction
needsnodeToCode()
for its incomingNode
currentNode
's prerequisiteCode
incomingNode
's code's import Then we check the prerequisiteCode
of this input
prerequisiteCode
of current input
when it's not already in the main prerequisiteCodeOfInputs
output
:output
of node: getOutputValueOfNode()
and add the next exec
output node's code via this.nodeToCode(outgoingExecNode, program);
inputs
and outputs
of current nodewe add current externalImports
to result.imports
we add prerequisiteCode
of All Inputs into result.code
beWatched
captureImageCode()
:captureImageFunction
of this PythonGenerator
class is not defined. this.commInJupyterLab
is not defined, it defines a new Jupyter comm for capturing images and stores it in this.commInJupyterLab
. The comm's name is also based on the current timestamp.-Then it gets a conversion from the current data type of the image to a numpy array using the getConversion
method of this.imageTypeConvert
.
FunctionGenRes
object, along with any necessary import statements and the definitions of the capture image function and the Jupyter comm.In summary, the captureImageCode
function generates Python code that captures an image from a given variable, converts it to a base64 string, and sends it to a specific DOM element in a Jupyter notebook.
getInputValueOfNode
and getOutputValueOfNode
I checked the NodeTypeSpecification.md
again in https://github.com/c3di/Visual-Programming-Language/blob/main/doc/NodeTypeSpecification.md
And found something that I overlooked: In here: https://github.com/c3di/Visual-Programming-Language/blob/main/doc/NodeTypeSpecification.md#generating-a-codegenerator-for-python
/**
* Generates the Python code for an exec node given its inputs and outputs.
* The function can be adapted to handle more complex scenarios and various metadata types.
*
* @param inputs An array of strings representing literals or variable names e.g., '1', '"str"'.
* @param outputs An array of strings for variable names or subsequent Python code.
* @param node The node for which code is being generated.
* @param generator An object providing context and utility functions for code generation.
*
* @returns A string containing the generated Python code snippet.
*/
function code(inputs, outputs, node, generator) {
// 1. Read an image and assign it to an output variable.
// 2. Create a metadata dictionary and attach when dealing with image data.
// 3. Prepare the execution sequence for the subsequent code.
const code = `${outputs[1]} = io.read_image(${inputs[1]}, ${inputs[2]})
${outputs[1]} = {
'value': ${outputs[1]},
'dataType': 'torch.tensor',
'metadata': {
'colorChannel': 'rgb',
'channelOrder': 'channelFirst',
'isMiniBatched': false,
'intensityRange': '0-255',
'device': 'cpu'
}
}
${outputs[0]}`;
return code;
}
// Convert the code generation function to a string format for JSON configuration.
const codeGeneratorFunction = code; // Assign the function for conversion
const jsonFormattedString = JSON.stringify(codeGeneratorFunction.toString());
console.log(jsonFormattedString);
- @param inputs An array of strings representing literals or variable names e.g., '1', '"str"'.
- @param outputs An array of strings for variable names or subsequent Python code.
so in getInputValueOfNode()
result.code = this._getUniqueNameOfHandle(incomingNode, outputHandle!);
is actually adding literal of input value such as '1' (when the value we get from the outputHandle from previous node is 1) to InputGenRes.code
And this InputGenRes.code
for this input is added to inputs[]
in method nodeToCode()
when iterating the inputs of a node
Then inputs[]
is passed to nodeSourceGeneration()
nodeSourceGeneration(
node: Node,
inputs: string[],
outputs: string[]
): string {
const nodeGenerator: string = node.data.codeGenerator;
if (!nodeGenerator) {
console.warn(
`Node type:${node.data.configType as string} has no source code`
);
return '';
}
// eslint-disable-next-line no-eval
const func = eval(`(${nodeGenerator})`);
// remove the trailing new line
return func(inputs, outputs, node, this).replace(/\n+$/, '');
}
eval
function to make the nodeGenerator
into JS functioning code eval
let code = "console.log('Hello, World!')";
eval(code); // This will print "Hello, World!" to the console
nodeGenerator
nodeGenerator
is we get from a Node's JSON file's nodeGenerator itemlet nodeGenerator = "(inputs, outputs, node, context) => { /* function body here */ }";
let func = eval(
(${nodeGenerator}));
func
, func
with parameter inputs[]
, outputs[]
we get from NodeToCode()'s getInputValueOfNode
and getInputValueOfNode
in returnthis._getUniqueNameOfHandle(node, outputId)
, which is n_${node.id}_${handleId}
:
- @param inputs An array of strings representing literals or variable names e.g., '1', '"str"'.
- @param outputs An array of strings for variable names or subsequent Python code.
python_generator.ts
:
This file is more complex than I thought so I'll first write down the basic understanding to help sort it out
NodeToCode()
:
- This function processes the
input
andoutput
of a node to python code we need- we create
result
withNodeGenRes
type to store generation result- we create
prerequisiteCodeOfInputs
to store the code should be executed before our current codeFor every
Input
, we havegetInputValueOfNode()
method to- **For Node that input connects with no other handles** - indicates this node itself is a `valueNode` - we get its value and convert it to python format - details are in #57 - - **For ImageInput** - set `converter` between `imageInput` and `imageOutput` - add imports that `convertFunction` needs - - **For ValueInput** - We calls `nodeToCode()` for its `incomingNode` - And put the code we get to `currentNode`'s `prerequisiteCode` - add imports for `incomingNode`'s code's import
Then we check the
prerequisiteCode
of this input
- To avoid duplication, we only add the
prerequisiteCode
of currentinput
when it's not already in the mainprerequisiteCodeOfInputs
Now I'll do a final summary of
generator_related_code
in the VP project:visual_program
:Nodes
andEdges
.Nodes
andEdges
isConnected
,getIncomingNodes()
,getNodeById()
, etc.This is a quick recap of the structure and its terms:
generation result
This is a class we defined to store the generation result of code from the visual program
we have
GenResult
--Extends->FunctiongenRes
-->NodeGenRes
-->InputGenRes
Basic
GenResult
includesmessage
andcode
FuncGenResult
includes one moreimports
toGenResult
function that add imports back tocode
InputGenRes
includes one moreprerequisiteCode
that stores the required code that should be executed before current nodecode_generator
andpython generator
code_generator
---extends-->python generator
In
code_generator
, we define the method we need to generate codes fromVisualProgram
programToCode()
which do:checkEntryPoint
: check themain
start of a programtopoSortFuncsInProgram
: sort the order of nodes for correct dependency of each otherfunctionsToCode
: that check if the program is not recursive and callfunctionToCode
for everyNode
or functionthere are also abstract method we defined here that should be implemented in
python_generator
or other languages' generatorFor example, we implement the required methods of
code_generator
inpython_generator
nodeToCode
: this is the main function that do the generation from VP node to Python CodeInput
of current NodewidgetValue
if this Node is a valueNode byquote()
ImageConversion
if input isImage
Node
needs to current Node'sprerequisiteCode
Output
,beWatched
flagcaptureImageCode()