Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
|
@@ -17,11 +17,45 @@ from langgraph.graph import StateGraph, END
|
|
| 17 |
import uuid
|
| 18 |
import shutil, time, functools
|
| 19 |
from langchain_experimental.open_clip.open_clip import OpenCLIPEmbeddings
|
|
|
|
| 20 |
# from matplotlib.offsetbox import OffsetImage, AnnotationBbox
|
| 21 |
from io import BytesIO
|
| 22 |
from pathlib import Path
|
| 23 |
import os
|
| 24 |
from utils.block_relation_builder import block_builder, variable_adder_main
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 25 |
|
| 26 |
def log_execution_time(func):
|
| 27 |
@functools.wraps(func)
|
|
@@ -233,6 +267,11 @@ agent = create_react_agent(
|
|
| 233 |
prompt=SYSTEM_PROMPT
|
| 234 |
)
|
| 235 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 236 |
agent_json_resolver = create_react_agent(
|
| 237 |
model=llm,
|
| 238 |
tools=[], # No specific tools are defined here, but could be added later
|
|
@@ -489,6 +528,56 @@ def clean_base64_for_model(raw_b64):
|
|
| 489 |
# 6. Return with the correct data URI prefix
|
| 490 |
return f"data:image/png;base64,{clean_b64}"
|
| 491 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 492 |
|
| 493 |
# Node 1: Logic updating if any issue here
|
| 494 |
def pseudo_generator_node(state: GameState):
|
|
@@ -562,7 +651,7 @@ If you find any "Code-Blocks" then,
|
|
| 562 |
|
| 563 |
3. **Pseudo‑code formatting**:
|
| 564 |
- Represent each block or nested block on its own line.
|
| 565 |
-
- Indent nested blocks by 4 spaces under their parent (`forever`, `if`, etc.).
|
| 566 |
- No comments or explanatory text—just the block sequence.
|
| 567 |
- a natural language breakdown of each step taken after the event, formatted as a multi-line string representing pseudo-code. Ensure clarity and granularity—each described action should map closely to a Scratch block or tight sequence.
|
| 568 |
|
|
@@ -573,71 +662,57 @@ If you find any "Code-Blocks" then,
|
|
| 573 |
|
| 574 |
5. **Examples for reference**:
|
| 575 |
**Correct** pattern for a simple start script:
|
| 576 |
-
|
| 577 |
-
|
| 578 |
-
|
| 579 |
-
|
| 580 |
-
|
| 581 |
-
|
| 582 |
-
|
| 583 |
-
|
| 584 |
**Correct** pattern for updating the high score variable handling:
|
| 585 |
-
|
| 586 |
-
|
| 587 |
-
|
| 588 |
-
|
| 589 |
-
|
| 590 |
-
|
| 591 |
-
|
| 592 |
-
|
| 593 |
**Correct** pattern for level up and increase difficulty use:
|
| 594 |
-
|
| 595 |
-
|
| 596 |
-
|
| 597 |
-
|
| 598 |
-
|
| 599 |
-
|
| 600 |
**Correct** pattern for jumping mechanics use:
|
| 601 |
-
|
| 602 |
-
|
| 603 |
-
|
| 604 |
-
|
| 605 |
-
|
| 606 |
-
|
| 607 |
-
|
| 608 |
-
|
| 609 |
-
|
| 610 |
-
|
| 611 |
-
|
| 612 |
-
|
| 613 |
-
**Correct** pattern for continuos moving objects use:
|
| 614 |
-
```
|
| 615 |
-
when green flag clicked
|
| 616 |
-
go to x: (240) y: (-100)
|
| 617 |
-
set [speed v] to (-5)
|
| 618 |
-
show variable [speed v]
|
| 619 |
-
forever
|
| 620 |
-
change x by ([speed v])
|
| 621 |
-
if <((x position)) < (-240)> then
|
| 622 |
-
go to x: (240) y: (-100)
|
| 623 |
-
end
|
| 624 |
-
end
|
| 625 |
-
end
|
| 626 |
-
```
|
| 627 |
**Correct** pattern for continuos moving objects use:
|
| 628 |
-
|
| 629 |
-
|
| 630 |
-
|
| 631 |
-
|
| 632 |
-
|
| 633 |
-
|
| 634 |
-
|
| 635 |
-
|
| 636 |
-
|
| 637 |
-
|
| 638 |
-
|
| 639 |
-
|
| 640 |
-
|
| 641 |
6. **Donot** add any explaination of logic or comments to justify or explain just put the logic content in the json.
|
| 642 |
7. **Output**:
|
| 643 |
Return **only** a JSON object, using double quotes everywhere:
|
|
@@ -799,40 +874,41 @@ Each plan must include a **single Scratch Hat Block** (e.g., 'event_whenflagclic
|
|
| 799 |
(([ballSpeed v]) * (1.1))
|
| 800 |
```
|
| 801 |
- **Every hat block script must end** with a final `end` on its own line.
|
|
|
|
| 802 |
3. **Opcode Lists**: include relevant Scratch opcodes grouped under `motion`, `control`, `operator`, `sensing`, `looks`, `sounds`, `events`, and `data`. List only the non-empty categories. Use exact opcodes.
|
| 803 |
4. Few Example of content of logics inside for a specific plan as scratch pseudo-code:
|
| 804 |
- example 1[continues moving objects]:
|
| 805 |
```
|
| 806 |
when green flag clicked
|
| 807 |
-
|
| 808 |
-
|
| 809 |
-
|
| 810 |
-
|
| 811 |
-
|
| 812 |
-
|
| 813 |
-
|
| 814 |
-
|
| 815 |
-
|
| 816 |
end
|
| 817 |
```
|
| 818 |
- example 2[jumping script of an plan]:
|
| 819 |
```
|
| 820 |
when [space v] key pressed
|
| 821 |
-
|
| 822 |
-
|
| 823 |
-
|
| 824 |
-
|
| 825 |
-
|
| 826 |
-
|
| 827 |
-
|
| 828 |
-
|
| 829 |
end
|
| 830 |
```
|
| 831 |
- example 3 [pattern for level up and increase difficulty]:
|
| 832 |
```
|
| 833 |
when I receive [Level Up v]
|
| 834 |
-
|
| 835 |
-
|
| 836 |
end
|
| 837 |
```
|
| 838 |
5. Use target names exactly as listed in `Targets in Game`. Do NOT rename or invent new targets.
|
|
@@ -846,7 +922,7 @@ Each plan must include a **single Scratch Hat Block** (e.g., 'event_whenflagclic
|
|
| 846 |
"plans": [
|
| 847 |
{{
|
| 848 |
"event": "event_whenflagclicked",
|
| 849 |
-
"logic": "when green flag clicked\n switch backdrop to [backdrop1 v]\n set [score v] to 0\n show variable [score v]\n broadcast [Game Start v]",
|
| 850 |
"motion": [],
|
| 851 |
"control": [],
|
| 852 |
"operator": [],
|
|
@@ -865,7 +941,7 @@ Each plan must include a **single Scratch Hat Block** (e.g., 'event_whenflagclic
|
|
| 865 |
}},
|
| 866 |
{{
|
| 867 |
"event": "event_whenbroadcastreceived",
|
| 868 |
-
"logic": "when I receive [Game Over v]\n if <(score) > (High Score)> then\n set [High Score v] to (score)\n end\n switch backdrop to [HighScore v]",
|
| 869 |
"motion": [],
|
| 870 |
"control": [
|
| 871 |
"control_if"
|
|
@@ -890,7 +966,7 @@ Each plan must include a **single Scratch Hat Block** (e.g., 'event_whenflagclic
|
|
| 890 |
"plans": [
|
| 891 |
{{
|
| 892 |
"event": "event_whenflagclicked",
|
| 893 |
-
"logic": "when green flag clicked\n go to x: 240 y: -100\
|
| 894 |
"motion": [
|
| 895 |
"motion_gotoxy"
|
| 896 |
],
|
|
@@ -904,7 +980,7 @@ Each plan must include a **single Scratch Hat Block** (e.g., 'event_whenflagclic
|
|
| 904 |
}},
|
| 905 |
{{
|
| 906 |
"event": "event_whenkeypressed",
|
| 907 |
-
"logic": "when [space v] key pressed\n repeat (10)\n change y by (20)\n wait (0.1) seconds\n change y by (-20)\n end",
|
| 908 |
"motion": [
|
| 909 |
"motion_changeyby"
|
| 910 |
],
|
|
@@ -926,7 +1002,7 @@ Each plan must include a **single Scratch Hat Block** (e.g., 'event_whenflagclic
|
|
| 926 |
"plans": [
|
| 927 |
{{
|
| 928 |
"event": "event_whenflagclicked",
|
| 929 |
-
"logic": "when green flag clicked\n go to x: 240 y: -135\n forever\n glide 2 seconds to x: -240 y: -135\n if <(x position) < -235> then\n set x to 240\n end\n if <touching [Sprite1 v]?> then\n broadcast [Game Over v]\n stop [all v]\n end\n end",
|
| 930 |
"motion": [
|
| 931 |
"motion_gotoxy",
|
| 932 |
"motion_glidesecstoxy",
|
|
@@ -1108,35 +1184,35 @@ Use sprite names exactly as provided in `sprite_names` (e.g., 'Sprite1', 'soccer
|
|
| 1108 |
- example 1[continues moving objects]:
|
| 1109 |
```
|
| 1110 |
when green flag clicked
|
| 1111 |
-
|
| 1112 |
-
|
| 1113 |
-
|
| 1114 |
-
|
| 1115 |
-
|
| 1116 |
-
|
| 1117 |
-
|
| 1118 |
-
|
| 1119 |
-
|
| 1120 |
end
|
| 1121 |
```
|
| 1122 |
- example 2[jumping script of an plan]:
|
| 1123 |
```
|
| 1124 |
when [space v] key pressed
|
| 1125 |
-
|
| 1126 |
-
|
| 1127 |
-
|
| 1128 |
-
|
| 1129 |
-
|
| 1130 |
-
|
| 1131 |
-
|
| 1132 |
-
|
| 1133 |
end
|
| 1134 |
```
|
| 1135 |
- example 3 [pattern for level up and increase difficulty]:
|
| 1136 |
```
|
| 1137 |
when I receive [Level Up v]
|
| 1138 |
-
|
| 1139 |
-
|
| 1140 |
end
|
| 1141 |
```
|
| 1142 |
6. Use target names exactly as listed in `Targets in Game`. Do NOT rename or invent new targets.
|
|
@@ -1150,7 +1226,7 @@ Use sprite names exactly as provided in `sprite_names` (e.g., 'Sprite1', 'soccer
|
|
| 1150 |
"plans": [
|
| 1151 |
{{
|
| 1152 |
"event": "event_whenflagclicked",
|
| 1153 |
-
"logic": "when green flag clicked\n switch backdrop to [backdrop1 v]\n set [score v] to 0\n show variable [score v]\n broadcast [Game Start v]",
|
| 1154 |
"motion": [],
|
| 1155 |
"control": [],
|
| 1156 |
"operator": [],
|
|
@@ -1169,7 +1245,7 @@ Use sprite names exactly as provided in `sprite_names` (e.g., 'Sprite1', 'soccer
|
|
| 1169 |
}},
|
| 1170 |
{{
|
| 1171 |
"event": "event_whenbroadcastreceived",
|
| 1172 |
-
"logic": "when I receive [Game Over v]\n if <(score) > (High Score)> then\n set [High Score v] to (score)\n end\n switch backdrop to [HighScore v]",
|
| 1173 |
"motion": [],
|
| 1174 |
"control": [
|
| 1175 |
"control_if"
|
|
@@ -1194,7 +1270,7 @@ Use sprite names exactly as provided in `sprite_names` (e.g., 'Sprite1', 'soccer
|
|
| 1194 |
"plans": [
|
| 1195 |
{{
|
| 1196 |
"event": "event_whenflagclicked",
|
| 1197 |
-
"logic": "when green flag clicked\n go to x: 240 y: -100\
|
| 1198 |
"motion": [
|
| 1199 |
"motion_gotoxy"
|
| 1200 |
],
|
|
@@ -1208,7 +1284,7 @@ Use sprite names exactly as provided in `sprite_names` (e.g., 'Sprite1', 'soccer
|
|
| 1208 |
}},
|
| 1209 |
{{
|
| 1210 |
"event": "event_whenkeypressed",
|
| 1211 |
-
"logic": "when [space v] key pressed\n repeat (10)\n change y by (20)\n wait (0.1) seconds\n change y by (-20)\n end",
|
| 1212 |
"motion": [
|
| 1213 |
"motion_changeyby"
|
| 1214 |
],
|
|
@@ -1230,7 +1306,7 @@ Use sprite names exactly as provided in `sprite_names` (e.g., 'Sprite1', 'soccer
|
|
| 1230 |
"plans": [
|
| 1231 |
{{
|
| 1232 |
"event": "event_whenflagclicked",
|
| 1233 |
-
"logic": "when green flag clicked\n go to x: 240 y: -135\n forever\n glide 2 seconds to x: -240 y: -135\n if <(x position) < -235> then\n set x to 240\n end\n if <touching [Sprite1 v]?> then\n broadcast [Game Over v]\n stop [all v]\n end\n end",
|
| 1234 |
"motion": [
|
| 1235 |
"motion_gotoxy",
|
| 1236 |
"motion_glidesecstoxy",
|
|
@@ -1649,9 +1725,10 @@ def overall_block_builder_node_2(state: dict):
|
|
| 1649 |
for plan_entry in sprite_actions_data.get("plans", []):
|
| 1650 |
logic_sequence = str(plan_entry["logic"])
|
| 1651 |
opcode_counts = plan_entry.get("opcode_counts", {})
|
| 1652 |
-
|
|
|
|
| 1653 |
try:
|
| 1654 |
-
generated_blocks = block_builder(opcode_counts,
|
| 1655 |
|
| 1656 |
# Ensure generated_blocks is a dictionary
|
| 1657 |
if not isinstance(generated_blocks, dict):
|
|
@@ -2241,6 +2318,61 @@ def similarity_matching(sprites_data: str, project_folder: str) -> str:
|
|
| 2241 |
"textToSpeechLanguage": None
|
| 2242 |
}
|
| 2243 |
final_project["targets"].insert(0, stage_obj)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2244 |
|
| 2245 |
with open(project_json_path, 'w') as f:
|
| 2246 |
json.dump(final_project, f, indent=2)
|
|
@@ -2400,7 +2532,7 @@ def convert_pdf_stream_to_images(pdf_stream: io.BytesIO, dpi=300):
|
|
| 2400 |
|
| 2401 |
def delay_for_tpm_node(state: GameState):
|
| 2402 |
logger.info("--- Running DelayForTPMNode ---")
|
| 2403 |
-
time.sleep(
|
| 2404 |
logger.info("Delay completed.")
|
| 2405 |
return state
|
| 2406 |
|
|
@@ -2419,19 +2551,19 @@ workflow.add_node("plan_generator", overall_planner_node)
|
|
| 2419 |
workflow.add_node("refined_planner", refined_planner_node) # Refines the action plan
|
| 2420 |
workflow.add_node("opcode_counter", plan_opcode_counter_node)
|
| 2421 |
workflow.add_node("block_builder", overall_block_builder_node_2)
|
| 2422 |
-
|
| 2423 |
|
| 2424 |
workflow.set_entry_point("pseudo_generator")
|
| 2425 |
workflow.add_edge("pseudo_generator","time_delay_1")
|
| 2426 |
workflow.add_edge("time_delay_1","plan_generator")
|
| 2427 |
workflow.add_edge("plan_generator","time_delay_2")
|
| 2428 |
-
workflow.add_edge("time_delay_2",END)
|
| 2429 |
workflow.add_edge("time_delay_2","refined_planner")
|
| 2430 |
workflow.add_edge("refined_planner","time_delay_3")
|
| 2431 |
workflow.add_edge("time_delay_3","opcode_counter")
|
| 2432 |
workflow.add_edge("opcode_counter","block_builder")
|
| 2433 |
-
workflow.add_edge("block_builder",
|
| 2434 |
-
|
| 2435 |
app_graph = workflow.compile()
|
| 2436 |
|
| 2437 |
# ============== Helper function to Upscale an Image ============== #
|
|
|
|
| 17 |
import uuid
|
| 18 |
import shutil, time, functools
|
| 19 |
from langchain_experimental.open_clip.open_clip import OpenCLIPEmbeddings
|
| 20 |
+
from langchain_core.utils.utils import secret_from_env
|
| 21 |
# from matplotlib.offsetbox import OffsetImage, AnnotationBbox
|
| 22 |
from io import BytesIO
|
| 23 |
from pathlib import Path
|
| 24 |
import os
|
| 25 |
from utils.block_relation_builder import block_builder, variable_adder_main
|
| 26 |
+
from langchain.chat_models import ChatOpenAI
|
| 27 |
+
from langchain_openai import ChatOpenAI
|
| 28 |
+
from pydantic import Field, SecretStr
|
| 29 |
+
|
| 30 |
+
os.environ["OPENROUTER_API_KEY"] = os.getenv("OPENROUTER_API_KEY", "default_key_or_placeholder")
|
| 31 |
+
class ChatOpenRouter(ChatOpenAI):
|
| 32 |
+
openai_api_key: Optional[SecretStr] = Field(
|
| 33 |
+
alias="api_key",
|
| 34 |
+
default_factory=secret_from_env("OPENROUTER_API_KEY", default=None),
|
| 35 |
+
)
|
| 36 |
+
@property
|
| 37 |
+
def lc_secrets(self) -> dict[str, str]:
|
| 38 |
+
return {"openai_api_key": "OPENROUTER_API_KEY"}
|
| 39 |
+
|
| 40 |
+
def __init__(self,
|
| 41 |
+
openai_api_key: Optional[str] = None,
|
| 42 |
+
**kwargs):
|
| 43 |
+
openai_api_key = (
|
| 44 |
+
openai_api_key or os.environ.get("OPENROUTER_API_KEY")
|
| 45 |
+
)
|
| 46 |
+
super().__init__(
|
| 47 |
+
base_url="https://openrouter.ai/api/v1",
|
| 48 |
+
openai_api_key=openai_api_key,
|
| 49 |
+
**kwargs
|
| 50 |
+
)
|
| 51 |
+
|
| 52 |
+
llm2 = ChatOpenRouter(
|
| 53 |
+
#model_name="deepseek/deepseek-r1-0528:free",
|
| 54 |
+
#model_name="google/gemini-2.0-flash-exp:free",
|
| 55 |
+
#model_name="deepseek/deepseek-v3-base:free",
|
| 56 |
+
model_name="deepseek/deepseek-r1:free"
|
| 57 |
+
)
|
| 58 |
+
|
| 59 |
|
| 60 |
def log_execution_time(func):
|
| 61 |
@functools.wraps(func)
|
|
|
|
| 267 |
prompt=SYSTEM_PROMPT
|
| 268 |
)
|
| 269 |
|
| 270 |
+
agent_2 = create_react_agent(
|
| 271 |
+
model=llm2,
|
| 272 |
+
tools=[], # No specific tools are defined here, but could be added later
|
| 273 |
+
prompt=SYSTEM_PROMPT
|
| 274 |
+
)
|
| 275 |
agent_json_resolver = create_react_agent(
|
| 276 |
model=llm,
|
| 277 |
tools=[], # No specific tools are defined here, but could be added later
|
|
|
|
| 528 |
# 6. Return with the correct data URI prefix
|
| 529 |
return f"data:image/png;base64,{clean_b64}"
|
| 530 |
|
| 531 |
+
def format_scratch_pseudo_code(code_string):
|
| 532 |
+
"""
|
| 533 |
+
Parses and formats Scratch pseudo-code with correct indentation,
|
| 534 |
+
specifically handling if/else/end structures correctly.
|
| 535 |
+
|
| 536 |
+
Args:
|
| 537 |
+
code_string (str): A string containing Scratch pseudo-code with
|
| 538 |
+
potentially inconsistent indentation.
|
| 539 |
+
|
| 540 |
+
Returns:
|
| 541 |
+
str: The correctly formatted and indented pseudo-code string.
|
| 542 |
+
"""
|
| 543 |
+
lines = code_string.strip().split('\n')
|
| 544 |
+
formatted_lines = []
|
| 545 |
+
indent_level = 0
|
| 546 |
+
|
| 547 |
+
# Keywords that increase indentation for the NEXT line
|
| 548 |
+
indent_keywords = ['when', 'forever', 'if', 'repeat', 'else']
|
| 549 |
+
|
| 550 |
+
# Keywords that decrease indentation for the CURRENT line
|
| 551 |
+
unindent_keywords = ['end', 'else']
|
| 552 |
+
|
| 553 |
+
for line in lines:
|
| 554 |
+
stripped_line = line.strip()
|
| 555 |
+
if not stripped_line:
|
| 556 |
+
continue
|
| 557 |
+
|
| 558 |
+
# Check for keywords that should un-indent the current line
|
| 559 |
+
if any(keyword in stripped_line for keyword in unindent_keywords):
|
| 560 |
+
# Special case for 'else': it should align with its 'if'
|
| 561 |
+
if 'else' in stripped_line:
|
| 562 |
+
# Decrease indentation for 'else' and its following lines
|
| 563 |
+
indentation = ' ' * (indent_level -1)
|
| 564 |
+
formatted_lines.append(indentation + stripped_line)
|
| 565 |
+
continue
|
| 566 |
+
|
| 567 |
+
# For 'end', decrease the level before formatting
|
| 568 |
+
indent_level = max(0, indent_level - 1)
|
| 569 |
+
|
| 570 |
+
indentation = ' ' * indent_level
|
| 571 |
+
formatted_lines.append(indentation + stripped_line)
|
| 572 |
+
|
| 573 |
+
# Check for keywords that should indent the next line
|
| 574 |
+
if any(keyword in stripped_line for keyword in indent_keywords):
|
| 575 |
+
# 'else' both un-indents and indents, so the level remains the same for the next block
|
| 576 |
+
if 'else' not in stripped_line:
|
| 577 |
+
indent_level += 1
|
| 578 |
+
|
| 579 |
+
return '\n'.join(formatted_lines)
|
| 580 |
+
|
| 581 |
|
| 582 |
# Node 1: Logic updating if any issue here
|
| 583 |
def pseudo_generator_node(state: GameState):
|
|
|
|
| 651 |
|
| 652 |
3. **Pseudo‑code formatting**:
|
| 653 |
- Represent each block or nested block on its own line.
|
| 654 |
+
- **Indent nested blocks by 4 spaces under their parent (`forever`, `if`, etc.).This is a critical requirement.**
|
| 655 |
- No comments or explanatory text—just the block sequence.
|
| 656 |
- a natural language breakdown of each step taken after the event, formatted as a multi-line string representing pseudo-code. Ensure clarity and granularity—each described action should map closely to a Scratch block or tight sequence.
|
| 657 |
|
|
|
|
| 662 |
|
| 663 |
5. **Examples for reference**:
|
| 664 |
**Correct** pattern for a simple start script:
|
| 665 |
+
```
|
| 666 |
+
when green flag clicked
|
| 667 |
+
switch backdrop to [blue sky v]
|
| 668 |
+
set [score v] to (0)
|
| 669 |
+
show variable [score v]
|
| 670 |
+
broadcast [Game Start v]
|
| 671 |
+
end
|
| 672 |
+
```
|
| 673 |
**Correct** pattern for updating the high score variable handling:
|
| 674 |
+
```
|
| 675 |
+
when I receive [Game Over v]
|
| 676 |
+
if <((score)) > (([High Score v]))> then
|
| 677 |
+
set [High Score v] to ([score v])
|
| 678 |
+
end
|
| 679 |
+
switch backdrop to [Game Over v]
|
| 680 |
+
end
|
| 681 |
+
```
|
| 682 |
**Correct** pattern for level up and increase difficulty use:
|
| 683 |
+
```
|
| 684 |
+
when I receive [Level Up v]
|
| 685 |
+
change [level v] by (1)
|
| 686 |
+
set [ballSpeed v] to ((([ballSpeed v]) * (1.1)))
|
| 687 |
+
end
|
| 688 |
+
```
|
| 689 |
**Correct** pattern for jumping mechanics use:
|
| 690 |
+
```
|
| 691 |
+
when [space v] key pressed
|
| 692 |
+
if <((y position)) = (-100)> then
|
| 693 |
+
repeat (5)
|
| 694 |
+
change y by (100)
|
| 695 |
+
wait (0.1) seconds
|
| 696 |
+
change y by (-100)
|
| 697 |
+
wait (0.1) seconds
|
| 698 |
+
end
|
| 699 |
+
end
|
| 700 |
+
end
|
| 701 |
+
```
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 702 |
**Correct** pattern for continuos moving objects use:
|
| 703 |
+
```
|
| 704 |
+
when green flag clicked
|
| 705 |
+
go to x: (240) y: (-100)
|
| 706 |
+
set [speed v] to (-5)
|
| 707 |
+
show variable [speed v]
|
| 708 |
+
forever
|
| 709 |
+
change x by ([speed v])
|
| 710 |
+
if <((x position)) < (-240)> then
|
| 711 |
+
go to x: (240) y: (-100)
|
| 712 |
+
end
|
| 713 |
+
end
|
| 714 |
+
end
|
| 715 |
+
```
|
| 716 |
6. **Donot** add any explaination of logic or comments to justify or explain just put the logic content in the json.
|
| 717 |
7. **Output**:
|
| 718 |
Return **only** a JSON object, using double quotes everywhere:
|
|
|
|
| 874 |
(([ballSpeed v]) * (1.1))
|
| 875 |
```
|
| 876 |
- **Every hat block script must end** with a final `end` on its own line.
|
| 877 |
+
- **Indent nested blocks by 4 spaces under their parent (`forever`, `if`, etc.).This is a critical requirement.**
|
| 878 |
3. **Opcode Lists**: include relevant Scratch opcodes grouped under `motion`, `control`, `operator`, `sensing`, `looks`, `sounds`, `events`, and `data`. List only the non-empty categories. Use exact opcodes.
|
| 879 |
4. Few Example of content of logics inside for a specific plan as scratch pseudo-code:
|
| 880 |
- example 1[continues moving objects]:
|
| 881 |
```
|
| 882 |
when green flag clicked
|
| 883 |
+
go to x: (240) y: (-100)
|
| 884 |
+
set [speed v] to (-5)
|
| 885 |
+
show variable [speed v]
|
| 886 |
+
forever
|
| 887 |
+
change x by ([speed v])
|
| 888 |
+
if <((x position)) < (-240)> then
|
| 889 |
+
go to x: (240) y: (-100)
|
| 890 |
+
end
|
| 891 |
+
end
|
| 892 |
end
|
| 893 |
```
|
| 894 |
- example 2[jumping script of an plan]:
|
| 895 |
```
|
| 896 |
when [space v] key pressed
|
| 897 |
+
if <((y position)) = (-100)> then
|
| 898 |
+
repeat (5)
|
| 899 |
+
change y by (100)
|
| 900 |
+
wait (0.1) seconds
|
| 901 |
+
change y by (-100)
|
| 902 |
+
wait (0.1) seconds
|
| 903 |
+
end
|
| 904 |
+
end
|
| 905 |
end
|
| 906 |
```
|
| 907 |
- example 3 [pattern for level up and increase difficulty]:
|
| 908 |
```
|
| 909 |
when I receive [Level Up v]
|
| 910 |
+
change [level v] by (1)
|
| 911 |
+
set [ballSpeed v] to ((([ballSpeed v]) * (1.1)))
|
| 912 |
end
|
| 913 |
```
|
| 914 |
5. Use target names exactly as listed in `Targets in Game`. Do NOT rename or invent new targets.
|
|
|
|
| 922 |
"plans": [
|
| 923 |
{{
|
| 924 |
"event": "event_whenflagclicked",
|
| 925 |
+
"logic": "when green flag clicked\n switch backdrop to [backdrop1 v]\n set [score v] to 0\n show variable [score v]\n broadcast [Game Start v]\nend",
|
| 926 |
"motion": [],
|
| 927 |
"control": [],
|
| 928 |
"operator": [],
|
|
|
|
| 941 |
}},
|
| 942 |
{{
|
| 943 |
"event": "event_whenbroadcastreceived",
|
| 944 |
+
"logic": "when I receive [Game Over v]\n if <(score) > (High Score)> then\n set [High Score v] to (score)\n end\n switch backdrop to [HighScore v]\nend",
|
| 945 |
"motion": [],
|
| 946 |
"control": [
|
| 947 |
"control_if"
|
|
|
|
| 966 |
"plans": [
|
| 967 |
{{
|
| 968 |
"event": "event_whenflagclicked",
|
| 969 |
+
"logic": "when green flag clicked\n go to x: 240 y: -100\nend",
|
| 970 |
"motion": [
|
| 971 |
"motion_gotoxy"
|
| 972 |
],
|
|
|
|
| 980 |
}},
|
| 981 |
{{
|
| 982 |
"event": "event_whenkeypressed",
|
| 983 |
+
"logic": "when [space v] key pressed\n repeat (10)\n change y by (20)\n wait (0.1) seconds\n change y by (-20)\n end\nend",
|
| 984 |
"motion": [
|
| 985 |
"motion_changeyby"
|
| 986 |
],
|
|
|
|
| 1002 |
"plans": [
|
| 1003 |
{{
|
| 1004 |
"event": "event_whenflagclicked",
|
| 1005 |
+
"logic": "when green flag clicked\n go to x: 240 y: -135\n forever\n glide 2 seconds to x: -240 y: -135\n if <(x position) < -235> then\n set x to 240\n end\n if <touching [Sprite1 v]?> then\n broadcast [Game Over v]\n stop [all v]\n end\n end\nend",
|
| 1006 |
"motion": [
|
| 1007 |
"motion_gotoxy",
|
| 1008 |
"motion_glidesecstoxy",
|
|
|
|
| 1184 |
- example 1[continues moving objects]:
|
| 1185 |
```
|
| 1186 |
when green flag clicked
|
| 1187 |
+
go to x: (240) y: (-100)
|
| 1188 |
+
set [speed v] to (-5)
|
| 1189 |
+
show variable [speed v]
|
| 1190 |
+
forever
|
| 1191 |
+
change x by ([speed v])
|
| 1192 |
+
if <((x position)) < (-240)> then
|
| 1193 |
+
go to x: (240) y: (-100)
|
| 1194 |
+
end
|
| 1195 |
+
end
|
| 1196 |
end
|
| 1197 |
```
|
| 1198 |
- example 2[jumping script of an plan]:
|
| 1199 |
```
|
| 1200 |
when [space v] key pressed
|
| 1201 |
+
if <((y position)) = (-100)> then
|
| 1202 |
+
repeat (5)
|
| 1203 |
+
change y by (100)
|
| 1204 |
+
wait (0.1) seconds
|
| 1205 |
+
change y by (-100)
|
| 1206 |
+
wait (0.1) seconds
|
| 1207 |
+
end
|
| 1208 |
+
end
|
| 1209 |
end
|
| 1210 |
```
|
| 1211 |
- example 3 [pattern for level up and increase difficulty]:
|
| 1212 |
```
|
| 1213 |
when I receive [Level Up v]
|
| 1214 |
+
change [level v] by (1)
|
| 1215 |
+
set [ballSpeed v] to ((([ballSpeed v]) * (1.1)))
|
| 1216 |
end
|
| 1217 |
```
|
| 1218 |
6. Use target names exactly as listed in `Targets in Game`. Do NOT rename or invent new targets.
|
|
|
|
| 1226 |
"plans": [
|
| 1227 |
{{
|
| 1228 |
"event": "event_whenflagclicked",
|
| 1229 |
+
"logic": "when green flag clicked\n switch backdrop to [backdrop1 v]\n set [score v] to 0\n show variable [score v]\n broadcast [Game Start v]\nend",
|
| 1230 |
"motion": [],
|
| 1231 |
"control": [],
|
| 1232 |
"operator": [],
|
|
|
|
| 1245 |
}},
|
| 1246 |
{{
|
| 1247 |
"event": "event_whenbroadcastreceived",
|
| 1248 |
+
"logic": "when I receive [Game Over v]\n if <(score) > (High Score)> then\n set [High Score v] to (score)\n end\n switch backdrop to [HighScore v]\nend",
|
| 1249 |
"motion": [],
|
| 1250 |
"control": [
|
| 1251 |
"control_if"
|
|
|
|
| 1270 |
"plans": [
|
| 1271 |
{{
|
| 1272 |
"event": "event_whenflagclicked",
|
| 1273 |
+
"logic": "when green flag clicked\n go to x: 240 y: -100\nend\n",
|
| 1274 |
"motion": [
|
| 1275 |
"motion_gotoxy"
|
| 1276 |
],
|
|
|
|
| 1284 |
}},
|
| 1285 |
{{
|
| 1286 |
"event": "event_whenkeypressed",
|
| 1287 |
+
"logic": "when [space v] key pressed\n repeat (10)\n change y by (20)\n wait (0.1) seconds\n change y by (-20)\n end\nend",
|
| 1288 |
"motion": [
|
| 1289 |
"motion_changeyby"
|
| 1290 |
],
|
|
|
|
| 1306 |
"plans": [
|
| 1307 |
{{
|
| 1308 |
"event": "event_whenflagclicked",
|
| 1309 |
+
"logic": "when green flag clicked\n go to x: 240 y: -135\n forever\n glide 2 seconds to x: -240 y: -135\n if <(x position) < -235> then\n set x to 240\n end\n if <touching [Sprite1 v]?> then\n broadcast [Game Over v]\n stop [all v]\n end\n end\nend",
|
| 1310 |
"motion": [
|
| 1311 |
"motion_gotoxy",
|
| 1312 |
"motion_glidesecstoxy",
|
|
|
|
| 1725 |
for plan_entry in sprite_actions_data.get("plans", []):
|
| 1726 |
logic_sequence = str(plan_entry["logic"])
|
| 1727 |
opcode_counts = plan_entry.get("opcode_counts", {})
|
| 1728 |
+
refined_indent_logic = format_scratch_pseudo_code(logic_sequence)
|
| 1729 |
+
print(f"\n--------------------------- refined indent logic: {refined_indent_logic}-------------------------------\n")
|
| 1730 |
try:
|
| 1731 |
+
generated_blocks = block_builder(opcode_counts, refined_indent_logic)
|
| 1732 |
|
| 1733 |
# Ensure generated_blocks is a dictionary
|
| 1734 |
if not isinstance(generated_blocks, dict):
|
|
|
|
| 2318 |
"textToSpeechLanguage": None
|
| 2319 |
}
|
| 2320 |
final_project["targets"].insert(0, stage_obj)
|
| 2321 |
+
else:
|
| 2322 |
+
logger.warning("⚠️ No backdrop matched. Using default static backdrop.")
|
| 2323 |
+
default_backdrop_path = BACKDROP_DIR / "cd21514d0531fdffb22204e0ec5ed84a.svg"
|
| 2324 |
+
default_backdrop_name = "cd21514d0531fdffb22204e0ec5ed84a.svg"
|
| 2325 |
+
|
| 2326 |
+
default_backdrop_sound = BACKDROP_DIR / "83a9787d4cb6f3b7632b4ddfebf74367.wav"
|
| 2327 |
+
default_backdrop_sound_name = "cd21514d0531fdffb22204e0ec5ed84a.svg"
|
| 2328 |
+
try:
|
| 2329 |
+
shutil.copy2(default_backdrop_path, os.path.join(project_folder, default_backdrop_name))
|
| 2330 |
+
logger.info(f"✅ Default backdrop copied to project: {default_backdrop_name}")
|
| 2331 |
+
|
| 2332 |
+
shutil.copy2(default_backdrop_sound, os.path.join(project_folder, default_backdrop_sound_name))
|
| 2333 |
+
logger.info(f"✅ Default backdrop sound copied to project: {default_backdrop_sound_name}")
|
| 2334 |
+
except Exception as e:
|
| 2335 |
+
logger.error(f"❌ Failed to copy default backdrop: {e}")
|
| 2336 |
+
|
| 2337 |
+
stage_obj={
|
| 2338 |
+
"isStage": True,
|
| 2339 |
+
"name": "Stage",
|
| 2340 |
+
"objName": "Stage",
|
| 2341 |
+
"variables": {},
|
| 2342 |
+
"lists": {},
|
| 2343 |
+
"broadcasts": {},
|
| 2344 |
+
"blocks": {},
|
| 2345 |
+
"comments": {},
|
| 2346 |
+
"currentCostume": 0,
|
| 2347 |
+
"costumes": [
|
| 2348 |
+
{
|
| 2349 |
+
"assetId": default_backdrop_name.split(".")[0],
|
| 2350 |
+
"name": "defaultBackdrop",
|
| 2351 |
+
"md5ext": default_backdrop_name,
|
| 2352 |
+
"dataFormat": "png",
|
| 2353 |
+
"rotationCenterX": 240,
|
| 2354 |
+
"rotationCenterY": 180
|
| 2355 |
+
}
|
| 2356 |
+
],
|
| 2357 |
+
"sounds": [
|
| 2358 |
+
{
|
| 2359 |
+
"name": "pop",
|
| 2360 |
+
"assetId": "83a9787d4cb6f3b7632b4ddfebf74367",
|
| 2361 |
+
"dataFormat": "wav",
|
| 2362 |
+
"format": "",
|
| 2363 |
+
"rate": 48000,
|
| 2364 |
+
"sampleCount": 1123,
|
| 2365 |
+
"md5ext": "83a9787d4cb6f3b7632b4ddfebf74367.wav"
|
| 2366 |
+
}
|
| 2367 |
+
],
|
| 2368 |
+
"volume": 100,
|
| 2369 |
+
"layerOrder": 0,
|
| 2370 |
+
"tempo": 60,
|
| 2371 |
+
"videoTransparency": 50,
|
| 2372 |
+
"videoState": "on",
|
| 2373 |
+
"textToSpeechLanguage": None
|
| 2374 |
+
}
|
| 2375 |
+
final_project["targets"].insert(0, stage_obj)
|
| 2376 |
|
| 2377 |
with open(project_json_path, 'w') as f:
|
| 2378 |
json.dump(final_project, f, indent=2)
|
|
|
|
| 2532 |
|
| 2533 |
def delay_for_tpm_node(state: GameState):
|
| 2534 |
logger.info("--- Running DelayForTPMNode ---")
|
| 2535 |
+
time.sleep(1) # Adjust the delay as needed
|
| 2536 |
logger.info("Delay completed.")
|
| 2537 |
return state
|
| 2538 |
|
|
|
|
| 2551 |
workflow.add_node("refined_planner", refined_planner_node) # Refines the action plan
|
| 2552 |
workflow.add_node("opcode_counter", plan_opcode_counter_node)
|
| 2553 |
workflow.add_node("block_builder", overall_block_builder_node_2)
|
| 2554 |
+
workflow.add_node("variable_initializer", variable_adder_node)
|
| 2555 |
|
| 2556 |
workflow.set_entry_point("pseudo_generator")
|
| 2557 |
workflow.add_edge("pseudo_generator","time_delay_1")
|
| 2558 |
workflow.add_edge("time_delay_1","plan_generator")
|
| 2559 |
workflow.add_edge("plan_generator","time_delay_2")
|
| 2560 |
+
# workflow.add_edge("time_delay_2",END)
|
| 2561 |
workflow.add_edge("time_delay_2","refined_planner")
|
| 2562 |
workflow.add_edge("refined_planner","time_delay_3")
|
| 2563 |
workflow.add_edge("time_delay_3","opcode_counter")
|
| 2564 |
workflow.add_edge("opcode_counter","block_builder")
|
| 2565 |
+
workflow.add_edge("block_builder",variable_initializer)
|
| 2566 |
+
workflow.add_edge("variable_initializer", END)
|
| 2567 |
app_graph = workflow.compile()
|
| 2568 |
|
| 2569 |
# ============== Helper function to Upscale an Image ============== #
|