Spaces:
Running
Running
owenkaplinsky
commited on
Commit
·
809b5f4
1
Parent(s):
be7ef2c
Add make_json, weather ex, comment
Browse files- project/src/blocks/text.js +212 -2
- project/src/generators/python.js +23 -2
- project/src/index.html +3 -1
- project/src/index.js +14 -2
- project/src/toolbox.js +14 -0
project/src/blocks/text.js
CHANGED
|
@@ -1,5 +1,9 @@
|
|
| 1 |
import * as Blockly from 'blockly';
|
| 2 |
import { pythonGenerator } from 'blockly/python';
|
|
|
|
|
|
|
|
|
|
|
|
|
| 3 |
|
| 4 |
// Utility to create a unique input reference block type
|
| 5 |
function createInputRefBlockType(inputName) {
|
|
@@ -540,12 +544,26 @@ const llm_call = {
|
|
| 540 |
|
| 541 |
const call_api = {
|
| 542 |
"type": "call_api",
|
| 543 |
-
"message0": "call API with url %
|
| 544 |
"args0": [
|
| 545 |
{
|
| 546 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 547 |
"name": "URL",
|
| 548 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
| 549 |
],
|
| 550 |
"output": ["String", "Integer", "List"],
|
| 551 |
"colour": 165,
|
|
@@ -570,6 +588,38 @@ const in_json = {
|
|
| 570 |
"inputsInline": true
|
| 571 |
}
|
| 572 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 573 |
// Dynamic function call block
|
| 574 |
const func_call = {
|
| 575 |
type: "func_call",
|
|
@@ -651,6 +701,142 @@ Blockly.Extensions.register('test_cleanup_extension', function () {
|
|
| 651 |
};
|
| 652 |
});
|
| 653 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 654 |
// Extension for dynamic function call blocks
|
| 655 |
Blockly.Extensions.register('func_call_dynamic', function () {
|
| 656 |
const block = this;
|
|
@@ -911,6 +1097,30 @@ Blockly.Blocks['func_call'] = {
|
|
| 911 |
}
|
| 912 |
};
|
| 913 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 914 |
export const blocks = Blockly.common.createBlockDefinitionsFromJsonArray([
|
| 915 |
container,
|
| 916 |
container_input,
|
|
|
|
| 1 |
import * as Blockly from 'blockly';
|
| 2 |
import { pythonGenerator } from 'blockly/python';
|
| 3 |
+
import { registerFieldMultilineInput } from '@blockly/field-multilineinput';
|
| 4 |
+
|
| 5 |
+
registerFieldMultilineInput();
|
| 6 |
+
|
| 7 |
|
| 8 |
// Utility to create a unique input reference block type
|
| 9 |
function createInputRefBlockType(inputName) {
|
|
|
|
| 544 |
|
| 545 |
const call_api = {
|
| 546 |
"type": "call_api",
|
| 547 |
+
"message0": "call API with method %1 url %2 headers %3",
|
| 548 |
"args0": [
|
| 549 |
{
|
| 550 |
+
type: "field_dropdown",
|
| 551 |
+
name: "METHOD",
|
| 552 |
+
options: [
|
| 553 |
+
["GET", "GET"],
|
| 554 |
+
["POST", "POST"],
|
| 555 |
+
["PUT", "PUT"],
|
| 556 |
+
["DELETE", "DELETE"],
|
| 557 |
+
]
|
| 558 |
+
},
|
| 559 |
+
{
|
| 560 |
+
"type": "input_value",
|
| 561 |
"name": "URL",
|
| 562 |
},
|
| 563 |
+
{
|
| 564 |
+
"type": "input_value",
|
| 565 |
+
"name": "HEADERS",
|
| 566 |
+
},
|
| 567 |
],
|
| 568 |
"output": ["String", "Integer", "List"],
|
| 569 |
"colour": 165,
|
|
|
|
| 588 |
"inputsInline": true
|
| 589 |
}
|
| 590 |
|
| 591 |
+
const json_field = {
|
| 592 |
+
type: "json_field",
|
| 593 |
+
message0: "field",
|
| 594 |
+
args0: [],
|
| 595 |
+
previousStatement: null,
|
| 596 |
+
nextStatement: null,
|
| 597 |
+
colour: 165,
|
| 598 |
+
};
|
| 599 |
+
|
| 600 |
+
const make_json_container = {
|
| 601 |
+
type: "make_json_container",
|
| 602 |
+
message0: "fields %1",
|
| 603 |
+
args0: [
|
| 604 |
+
{ type: "input_statement", name: "STACK" },
|
| 605 |
+
],
|
| 606 |
+
colour: 165,
|
| 607 |
+
inputsInline: false
|
| 608 |
+
};
|
| 609 |
+
|
| 610 |
+
const make_json = {
|
| 611 |
+
type: "make_json",
|
| 612 |
+
message0: "make JSON %1",
|
| 613 |
+
args0: [
|
| 614 |
+
{ type: "input_dummy" },
|
| 615 |
+
],
|
| 616 |
+
colour: 165,
|
| 617 |
+
inputsInline: false,
|
| 618 |
+
output: ["String", "Integer"],
|
| 619 |
+
mutator: "json_mutator",
|
| 620 |
+
fieldCount_: 1,
|
| 621 |
+
};
|
| 622 |
+
|
| 623 |
// Dynamic function call block
|
| 624 |
const func_call = {
|
| 625 |
type: "func_call",
|
|
|
|
| 701 |
};
|
| 702 |
});
|
| 703 |
|
| 704 |
+
// JSON mutator for dynamic field creation
|
| 705 |
+
Blockly.Extensions.registerMutator(
|
| 706 |
+
'json_mutator',
|
| 707 |
+
{
|
| 708 |
+
|
| 709 |
+
decompose: function (workspace) {
|
| 710 |
+
const containerBlock = workspace.newBlock('make_json_container');
|
| 711 |
+
containerBlock.initSvg();
|
| 712 |
+
let connection = containerBlock.getInput('STACK').connection;
|
| 713 |
+
|
| 714 |
+
// Initialize defaults if not set
|
| 715 |
+
if (this.fieldCount_ === undefined) {
|
| 716 |
+
this.fieldCount_ = 0;
|
| 717 |
+
this.fieldKeys_ = [];
|
| 718 |
+
}
|
| 719 |
+
|
| 720 |
+
// Restore dynamically added field items
|
| 721 |
+
for (let i = 0; i < this.fieldCount_; i++) {
|
| 722 |
+
const itemBlock = workspace.newBlock('json_field');
|
| 723 |
+
itemBlock.initSvg();
|
| 724 |
+
// Store the connection for compose
|
| 725 |
+
const input = this.getInput('FIELD' + i);
|
| 726 |
+
if (input && input.connection && input.connection.targetConnection) {
|
| 727 |
+
itemBlock.valueConnection_ = input.connection.targetConnection;
|
| 728 |
+
}
|
| 729 |
+
|
| 730 |
+
connection.connect(itemBlock.previousConnection);
|
| 731 |
+
connection = itemBlock.nextConnection;
|
| 732 |
+
}
|
| 733 |
+
|
| 734 |
+
return containerBlock;
|
| 735 |
+
},
|
| 736 |
+
|
| 737 |
+
compose: function (containerBlock) {
|
| 738 |
+
Blockly.Events.disable();
|
| 739 |
+
try {
|
| 740 |
+
// Initialize defaults if not set
|
| 741 |
+
if (this.fieldCount_ === undefined) {
|
| 742 |
+
this.fieldCount_ = 0;
|
| 743 |
+
this.fieldKeys_ = [];
|
| 744 |
+
}
|
| 745 |
+
|
| 746 |
+
const connections = [];
|
| 747 |
+
let itemBlock = containerBlock.getInputTargetBlock('STACK');
|
| 748 |
+
|
| 749 |
+
// Collect all child connections from mutator stack
|
| 750 |
+
while (itemBlock) {
|
| 751 |
+
connections.push(itemBlock.valueConnection_);
|
| 752 |
+
itemBlock = itemBlock.nextConnection && itemBlock.nextConnection.targetBlock();
|
| 753 |
+
}
|
| 754 |
+
|
| 755 |
+
const newCount = connections.length;
|
| 756 |
+
const oldCount = this.fieldCount_;
|
| 757 |
+
this.fieldCount_ = newCount;
|
| 758 |
+
|
| 759 |
+
// Preserve old keys and extend array if needed
|
| 760 |
+
if (!this.fieldKeys_) {
|
| 761 |
+
this.fieldKeys_ = [];
|
| 762 |
+
}
|
| 763 |
+
|
| 764 |
+
// Remove all dynamic inputs before reconstruction
|
| 765 |
+
let i = 0;
|
| 766 |
+
while (this.getInput('FIELD' + i)) this.removeInput('FIELD' + i++);
|
| 767 |
+
|
| 768 |
+
// Add each dynamic field input with editable key name
|
| 769 |
+
for (let j = 0; j < newCount; j++) {
|
| 770 |
+
// Use existing key or create new one
|
| 771 |
+
if (!this.fieldKeys_[j]) {
|
| 772 |
+
this.fieldKeys_[j] = 'key' + j;
|
| 773 |
+
}
|
| 774 |
+
const key = this.fieldKeys_[j];
|
| 775 |
+
const input = this.appendValueInput('FIELD' + j);
|
| 776 |
+
const field = new Blockly.FieldTextInput(key);
|
| 777 |
+
field.setValidator((newValue) => {
|
| 778 |
+
// Update the stored key when user edits it
|
| 779 |
+
this.fieldKeys_[j] = newValue || 'key' + j;
|
| 780 |
+
return newValue;
|
| 781 |
+
});
|
| 782 |
+
input.appendField(field, 'KEY' + j);
|
| 783 |
+
input.appendField(':');
|
| 784 |
+
this.moveInputBefore('FIELD' + j, null);
|
| 785 |
+
}
|
| 786 |
+
|
| 787 |
+
// Trim fieldKeys array if fields were removed
|
| 788 |
+
if (newCount < oldCount) {
|
| 789 |
+
this.fieldKeys_.length = newCount;
|
| 790 |
+
}
|
| 791 |
+
|
| 792 |
+
// Reconnect preserved connections to new structure
|
| 793 |
+
for (let k = 0; k < newCount; k++) {
|
| 794 |
+
const conn = connections[k];
|
| 795 |
+
if (conn) {
|
| 796 |
+
try {
|
| 797 |
+
this.getInput('FIELD' + k).connection.connect(conn);
|
| 798 |
+
} catch { }
|
| 799 |
+
}
|
| 800 |
+
}
|
| 801 |
+
|
| 802 |
+
this.workspace.render();
|
| 803 |
+
} finally {
|
| 804 |
+
Blockly.Events.enable();
|
| 805 |
+
}
|
| 806 |
+
},
|
| 807 |
+
|
| 808 |
+
saveExtraState: function () {
|
| 809 |
+
return {
|
| 810 |
+
fieldCount: this.fieldCount_,
|
| 811 |
+
fieldKeys: this.fieldKeys_,
|
| 812 |
+
};
|
| 813 |
+
},
|
| 814 |
+
|
| 815 |
+
loadExtraState: function (state) {
|
| 816 |
+
this.fieldCount_ = state.fieldCount || 0;
|
| 817 |
+
this.fieldKeys_ = state.fieldKeys || [];
|
| 818 |
+
|
| 819 |
+
// Immediately rebuild the inputs structure so they exist when connections are loaded
|
| 820 |
+
if (this.fieldCount_ > 0) {
|
| 821 |
+
for (let j = 0; j < this.fieldCount_; j++) {
|
| 822 |
+
const key = this.fieldKeys_[j] || ('key' + j);
|
| 823 |
+
const input = this.appendValueInput('FIELD' + j);
|
| 824 |
+
const field = new Blockly.FieldTextInput(key);
|
| 825 |
+
field.setValidator((newValue) => {
|
| 826 |
+
// Update the stored key when user edits it
|
| 827 |
+
this.fieldKeys_[j] = newValue || 'key' + j;
|
| 828 |
+
return newValue;
|
| 829 |
+
});
|
| 830 |
+
input.appendField(field, 'KEY' + j);
|
| 831 |
+
input.appendField(':');
|
| 832 |
+
}
|
| 833 |
+
}
|
| 834 |
+
}
|
| 835 |
+
},
|
| 836 |
+
null,
|
| 837 |
+
['json_field']
|
| 838 |
+
);
|
| 839 |
+
|
| 840 |
// Extension for dynamic function call blocks
|
| 841 |
Blockly.Extensions.register('func_call_dynamic', function () {
|
| 842 |
const block = this;
|
|
|
|
| 1097 |
}
|
| 1098 |
};
|
| 1099 |
|
| 1100 |
+
// Register json_field block (internal mutator block, not user-visible)
|
| 1101 |
+
Blockly.Blocks['json_field'] = {
|
| 1102 |
+
init: function () {
|
| 1103 |
+
this.jsonInit(json_field);
|
| 1104 |
+
}
|
| 1105 |
+
};
|
| 1106 |
+
|
| 1107 |
+
// Register make_json_container block (internal mutator block, not user-visible)
|
| 1108 |
+
Blockly.Blocks['make_json_container'] = {
|
| 1109 |
+
init: function () {
|
| 1110 |
+
this.jsonInit(make_json_container);
|
| 1111 |
+
}
|
| 1112 |
+
};
|
| 1113 |
+
|
| 1114 |
+
// Register make_json block separately to include custom init logic
|
| 1115 |
+
Blockly.Blocks['make_json'] = {
|
| 1116 |
+
init: function () {
|
| 1117 |
+
this.jsonInit(make_json);
|
| 1118 |
+
// Initialize with no fields by default
|
| 1119 |
+
this.fieldCount_ = 0;
|
| 1120 |
+
this.fieldKeys_ = [];
|
| 1121 |
+
}
|
| 1122 |
+
};
|
| 1123 |
+
|
| 1124 |
export const blocks = Blockly.common.createBlockDefinitionsFromJsonArray([
|
| 1125 |
container,
|
| 1126 |
container_input,
|
project/src/generators/python.js
CHANGED
|
@@ -283,10 +283,12 @@ forBlock['func_call'] = function (block, generator) {
|
|
| 283 |
};
|
| 284 |
|
| 285 |
forBlock['call_api'] = function (block, generator) {
|
| 286 |
-
const url =
|
|
|
|
|
|
|
| 287 |
|
| 288 |
// Generate code to call an LLM model with a prompt
|
| 289 |
-
const code = `call_api(url="${
|
| 290 |
return [code, Order.NONE];
|
| 291 |
};
|
| 292 |
|
|
@@ -297,4 +299,23 @@ forBlock['in_json'] = function (block, generator) {
|
|
| 297 |
// Generate code to call an LLM model with a prompt
|
| 298 |
const code = `${json}["${name}"]`;
|
| 299 |
return [code, Order.NONE];
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 300 |
};
|
|
|
|
| 283 |
};
|
| 284 |
|
| 285 |
forBlock['call_api'] = function (block, generator) {
|
| 286 |
+
const url = generator.valueToCode(block, 'URL', Order.NONE) || "''";
|
| 287 |
+
const method = block.getFieldValue('METHOD');
|
| 288 |
+
const headers = generator.valueToCode(block, 'HEADERS', Order.NONE) || "''";
|
| 289 |
|
| 290 |
// Generate code to call an LLM model with a prompt
|
| 291 |
+
const code = `call_api(url=${url}, method="${method}", headers=${headers})`;
|
| 292 |
return [code, Order.NONE];
|
| 293 |
};
|
| 294 |
|
|
|
|
| 299 |
// Generate code to call an LLM model with a prompt
|
| 300 |
const code = `${json}["${name}"]`;
|
| 301 |
return [code, Order.NONE];
|
| 302 |
+
};
|
| 303 |
+
|
| 304 |
+
forBlock['make_json'] = function (block, generator) {
|
| 305 |
+
const pairs = [];
|
| 306 |
+
let i = 0;
|
| 307 |
+
|
| 308 |
+
// Collect all key-value pairs
|
| 309 |
+
while (block.getInput('FIELD' + i)) {
|
| 310 |
+
// Get the key from the text field on the block
|
| 311 |
+
const keyField = block.getField('KEY' + i);
|
| 312 |
+
const key = keyField ? keyField.getValue() : (block.fieldKeys_[i] || ('key' + i));
|
| 313 |
+
const value = generator.valueToCode(block, 'FIELD' + i, Order.NONE) || "''";
|
| 314 |
+
pairs.push(`"${key}": ${value}`);
|
| 315 |
+
i++;
|
| 316 |
+
}
|
| 317 |
+
|
| 318 |
+
// Generate valid Python dict syntax
|
| 319 |
+
const code = pairs.length > 0 ? `{${pairs.join(', ')}}` : '{}';
|
| 320 |
+
return [code, Order.ATOMIC];
|
| 321 |
};
|
project/src/index.html
CHANGED
|
@@ -33,7 +33,9 @@
|
|
| 33 |
|
| 34 |
<div class="menuGroup">
|
| 35 |
<button class="menuButton">Examples</button>
|
| 36 |
-
<div class="dropdown"
|
|
|
|
|
|
|
| 37 |
</div>
|
| 38 |
</div>
|
| 39 |
<div id="githubLink">
|
|
|
|
| 33 |
|
| 34 |
<div class="menuGroup">
|
| 35 |
<button class="menuButton">Examples</button>
|
| 36 |
+
<div class="dropdown">
|
| 37 |
+
<a href="#" id="weatherButton" class="dropdownItem" data-action="undo">Weather API</a>
|
| 38 |
+
</div>
|
| 39 |
</div>
|
| 40 |
</div>
|
| 41 |
<div id="githubLink">
|
project/src/index.js
CHANGED
|
@@ -41,6 +41,8 @@ const ws = Blockly.inject(blocklyDiv, {
|
|
| 41 |
|
| 42 |
window.workspace = ws;
|
| 43 |
|
|
|
|
|
|
|
| 44 |
const newButton = document.querySelector('#newButton');
|
| 45 |
|
| 46 |
newButton.addEventListener("click", () => {
|
|
@@ -89,6 +91,16 @@ saveButton.addEventListener("click", () => {
|
|
| 89 |
document.body.removeChild(element);
|
| 90 |
});
|
| 91 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 92 |
undoButton.addEventListener("click", () => {
|
| 93 |
ws.undo(false);
|
| 94 |
});
|
|
@@ -124,10 +136,10 @@ const updateCode = () => {
|
|
| 124 |
|
| 125 |
`;
|
| 126 |
|
| 127 |
-
const API = `def call_api(url):
|
| 128 |
import requests
|
| 129 |
|
| 130 |
-
response = requests.
|
| 131 |
data = response.json()
|
| 132 |
return data
|
| 133 |
|
|
|
|
| 41 |
|
| 42 |
window.workspace = ws;
|
| 43 |
|
| 44 |
+
Blockly.ContextMenuItems.registerCommentOptions();
|
| 45 |
+
|
| 46 |
const newButton = document.querySelector('#newButton');
|
| 47 |
|
| 48 |
newButton.addEventListener("click", () => {
|
|
|
|
| 91 |
document.body.removeChild(element);
|
| 92 |
});
|
| 93 |
|
| 94 |
+
const weatherText = `{"workspaceComments":[{"height":120,"width":479,"id":"XI5[EHp-Ow+kinXf6n5y","x":51.234375,"y":-83,"text":"Gets temperature of location with a latitude and a longitude.\\n\\nThe API requires a minimum of one decimal point to work."}],"blocks":{"languageVersion":0,"blocks":[{"type":"create_mcp","id":")N.HEG1x]Z/,k#TeWr,S","x":50,"y":50,"deletable":false,"extraState":{"inputCount":2,"inputNames":["latitude","longitude"],"inputTypes":["integer","integer"],"outputCount":1,"outputNames":["output0"],"outputTypes":["string"],"toolCount":0},"inputs":{"X0":{"block":{"type":"input_reference_latitude","id":"]3mj!y}qfRt+!okheU7L","deletable":false,"extraState":{"ownerBlockId":")N.HEG1x]Z/,k#TeWr,S"},"fields":{"VARNAME":"latitude"}}},"X1":{"block":{"type":"input_reference_longitude","id":"Do/{HFNGSd.!;POiKS?D","deletable":false,"extraState":{"ownerBlockId":")N.HEG1x]Z/,k#TeWr,S"},"fields":{"VARNAME":"longitude"}}},"R0":{"block":{"type":"in_json","id":"R|j?_8s^H{l0;UZ-oQt3","fields":{"NAME":"temperature_2m"},"inputs":{"JSON":{"block":{"type":"in_json","id":"X=M,R1@7bRjJVZIPi[qD","fields":{"NAME":"current"},"inputs":{"JSON":{"block":{"type":"call_api","id":"^(.vyM.yni08S~c1EBm=","fields":{"METHOD":"GET"},"inputs":{"URL":{"shadow":{"type":"text","id":"}.T;_U_OsRS)B_y09p % { ","fields":{"TEXT":""}},"block":{"type":"text_replace","id":"OwH9uERJPTGQG!UER#ch","inputs":{"FROM":{"shadow":{"type":"text","id":"ya05#^ 7 % UbUeXX#eDSmH","fields":{"TEXT":"{latitude}"}}},"TO":{"shadow":{"type":"text","id":": _ZloQuh9c-MNf-U]!k5","fields":{"TEXT":""}},"block":{"type":"input_reference_latitude","id":"?%@)3sErZ)}=#4ags#gu","extraState":{"ownerBlockId":")N.HEG1x]Z/,k#TeWr,S"},"fields":{"VARNAME":"latitude"}}},"TEXT":{"shadow":{"type":"text","id":"w@zsP)m6:WjkUp,ln3$x","fields":{"TEXT":""}},"block":{"type":"text_replace","id":"ImNPsvzD7r^+1MJ%IirV","inputs":{"FROM":{"shadow":{"type":"text","id":"%o(3rro?WLIFpmE0#MMM","fields":{"TEXT":"{longitude}"}}},"TO":{"shadow":{"type":"text","id":"Zpql-%oJ_sdSi | r |* er | ","fields":{"TEXT":""}},"block":{"type":"input_reference_longitude","id":"WUgiJP$X + zY#f$5nhnTX","extraState":{"ownerBlockId":") N.HEG1x]Z /, k#TeWr, S"},"fields":{"VARNAME":"longitude"}}},"TEXT":{"shadow":{"type":"text","id":", (vw$o_s7P = b4P; 8]}yj","fields":{"TEXT":"https://api.open-meteo.com/v1/forecast?latitude={latitude}&longitude={longitude}¤t=temperature_2m,wind_speed_10m"}}}}}}}}}}}}}}}}}}}}]}}`;
|
| 95 |
+
weatherButton.addEventListener("click", () => {
|
| 96 |
+
try {
|
| 97 |
+
const fileContent = JSON.parse(weatherText);
|
| 98 |
+
Blockly.serialization.workspaces.load(fileContent, ws);
|
| 99 |
+
} catch (error) {
|
| 100 |
+
console.error("Error loading weather.txt contents:", error);
|
| 101 |
+
}
|
| 102 |
+
});
|
| 103 |
+
|
| 104 |
undoButton.addEventListener("click", () => {
|
| 105 |
ws.undo(false);
|
| 106 |
});
|
|
|
|
| 136 |
|
| 137 |
`;
|
| 138 |
|
| 139 |
+
const API = `def call_api(url, method="GET", headers={}):
|
| 140 |
import requests
|
| 141 |
|
| 142 |
+
response = requests.request(method, url, headers=headers)
|
| 143 |
data = response.json()
|
| 144 |
return data
|
| 145 |
|
project/src/toolbox.js
CHANGED
|
@@ -43,11 +43,25 @@ export const toolbox = {
|
|
| 43 |
{
|
| 44 |
kind: 'block',
|
| 45 |
type: 'call_api',
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 46 |
},
|
| 47 |
{
|
| 48 |
kind: 'block',
|
| 49 |
type: 'in_json',
|
| 50 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
| 51 |
]
|
| 52 |
},
|
| 53 |
{
|
|
|
|
| 43 |
{
|
| 44 |
kind: 'block',
|
| 45 |
type: 'call_api',
|
| 46 |
+
inputs: {
|
| 47 |
+
URL: {
|
| 48 |
+
shadow: {
|
| 49 |
+
type: 'text',
|
| 50 |
+
fields: {
|
| 51 |
+
text: "10",
|
| 52 |
+
},
|
| 53 |
+
},
|
| 54 |
+
},
|
| 55 |
+
},
|
| 56 |
},
|
| 57 |
{
|
| 58 |
kind: 'block',
|
| 59 |
type: 'in_json',
|
| 60 |
},
|
| 61 |
+
{
|
| 62 |
+
kind: 'block',
|
| 63 |
+
type: 'make_json',
|
| 64 |
+
},
|
| 65 |
]
|
| 66 |
},
|
| 67 |
{
|