Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
|
@@ -26,6 +26,7 @@ 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):
|
|
@@ -740,6 +741,68 @@ def clean_base64_for_model(raw_b64):
|
|
| 740 |
# Return both prefixed and clean reduced versions
|
| 741 |
return f"data:image/jpeg;base64,{reduced_b64}"
|
| 742 |
return f"data:image/jpeg;base64,{clean_b64}"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 743 |
|
| 744 |
def format_scratch_pseudo_code(code_string):
|
| 745 |
"""
|
|
@@ -1796,7 +1859,7 @@ Example output:
|
|
| 1796 |
|
| 1797 |
# Directly use the 'opcode_counts' list from the LLM's output
|
| 1798 |
plan["opcode_counts"] = llm_json.get("opcode_counts", [])
|
| 1799 |
-
|
| 1800 |
# Optionally, you can remove the individual category lists from the plan
|
| 1801 |
# if they are no longer needed after the LLM provides the consolidated list.
|
| 1802 |
# for key in ["motion", "control", "operator", "sensing", "looks", "sounds", "events", "data"]:
|
|
|
|
| 26 |
from langchain.chat_models import ChatOpenAI
|
| 27 |
from langchain_openai import ChatOpenAI
|
| 28 |
from pydantic import Field, SecretStr
|
| 29 |
+
from difflib import get_close_matches
|
| 30 |
|
| 31 |
os.environ["OPENROUTER_API_KEY"] = os.getenv("OPENROUTER_API_KEY", "default_key_or_placeholder")
|
| 32 |
class ChatOpenRouter(ChatOpenAI):
|
|
|
|
| 741 |
# Return both prefixed and clean reduced versions
|
| 742 |
return f"data:image/jpeg;base64,{reduced_b64}"
|
| 743 |
return f"data:image/jpeg;base64,{clean_b64}"
|
| 744 |
+
|
| 745 |
+
SCRATCH_OPCODES = [
|
| 746 |
+
'motion_movesteps', 'motion_turnright', 'motion_turnleft', 'motion_goto',
|
| 747 |
+
'motion_gotoxy', 'motion_glideto', 'motion_glidesecstoxy', 'motion_pointindirection',
|
| 748 |
+
'motion_pointtowards', 'motion_changexby', 'motion_setx', 'motion_changeyby',
|
| 749 |
+
'motion_sety', 'motion_ifonedgebounce', 'motion_setrotationstyle', 'looks_sayforsecs',
|
| 750 |
+
'looks_say', 'looks_thinkforsecs', 'looks_think', 'looks_switchcostumeto',
|
| 751 |
+
'looks_nextcostume', 'looks_switchbackdropto', 'looks_switchbackdroptowait',
|
| 752 |
+
'looks_nextbackdrop', 'looks_changesizeby', 'looks_setsizeto', 'looks_changeeffectby',
|
| 753 |
+
'looks_seteffectto', 'looks_cleargraphiceffects', 'looks_show', 'looks_hide',
|
| 754 |
+
'looks_gotofrontback', 'looks_goforwardbackwardlayers', 'sound_playuntildone',
|
| 755 |
+
'sound_play', 'sound_stopallsounds', 'sound_changevolumeby', 'sound_setvolumeto',
|
| 756 |
+
'event_broadcast', 'event_broadcastandwait', 'control_wait', 'control_wait_until',
|
| 757 |
+
'control_stop', 'control_create_clone_of', 'control_delete_this_clone',
|
| 758 |
+
'data_setvariableto', 'data_changevariableby', 'data_addtolist', 'data_deleteoflist',
|
| 759 |
+
'data_insertatlist', 'data_replaceitemoflist', 'data_showvariable', 'data_hidevariable',
|
| 760 |
+
'data_showlist', 'data_hidelist', 'sensing_askandwait', 'sensing_resettimer',
|
| 761 |
+
'sensing_setdragmode', 'procedures_call', 'operator_lt', 'operator_equals',
|
| 762 |
+
'operator_gt', 'operator_and', 'operator_or', 'operator_not', 'operator_contains',
|
| 763 |
+
'sensing_touchingobject', 'sensing_touchingcolor', 'sensing_coloristouchingcolor',
|
| 764 |
+
'sensing_keypressed', 'sensing_mousedown', 'data_listcontainsitem', 'control_repeat',
|
| 765 |
+
'control_forever', 'control_if', 'control_if_else', 'control_repeat_until',
|
| 766 |
+
'motion_xposition', 'motion_yposition', 'motion_direction', 'looks_costumenumbername',
|
| 767 |
+
'looks_size', 'looks_backdropnumbername', 'sound_volume', 'sensing_distanceto',
|
| 768 |
+
'sensing_answer', 'sensing_mousex', 'sensing_mousey', 'sensing_loudness',
|
| 769 |
+
'sensing_timer', 'sensing_of', 'sensing_current', 'sensing_dayssince2000',
|
| 770 |
+
'sensing_username', 'operator_add', 'operator_subtract', 'operator_multiply',
|
| 771 |
+
'operator_divide', 'operator_random', 'operator_join', 'operator_letterof',
|
| 772 |
+
'operator_length', 'operator_mod', 'operator_round', 'operator_mathop',
|
| 773 |
+
'data_variable', 'data_list', 'data_itemoflist', 'data_lengthoflist',
|
| 774 |
+
'data_itemnumoflist', 'event_whenflagclicked', 'event_whenkeypressed',
|
| 775 |
+
'event_whenthisspriteclicked', 'event_whenbackdropswitchesto', 'event_whengreaterthan',
|
| 776 |
+
'event_whenbroadcastreceived', 'control_start_as_clone', 'procedures_definition'
|
| 777 |
+
]
|
| 778 |
+
|
| 779 |
+
def validate_and_fix_opcodes(opcode_counts):
|
| 780 |
+
"""
|
| 781 |
+
Ensures all opcodes are valid. If an opcode is invalid, replace with closest match.
|
| 782 |
+
"""
|
| 783 |
+
corrected_list = []
|
| 784 |
+
for item in opcode_counts:
|
| 785 |
+
opcode = item.get("opcode")
|
| 786 |
+
count = item.get("count", 1)
|
| 787 |
+
|
| 788 |
+
if opcode not in SCRATCH_OPCODES:
|
| 789 |
+
# Find closest match (case-sensitive)
|
| 790 |
+
match = get_close_matches(opcode, SCRATCH_OPCODES, n=1, cutoff=0.6)
|
| 791 |
+
if match:
|
| 792 |
+
print(f"Opcode '{opcode}' not found. Replacing with '{match[0]}'")
|
| 793 |
+
opcode = match[0]
|
| 794 |
+
else:
|
| 795 |
+
print(f"Opcode '{opcode}' not recognized and no close match found. Skipping.")
|
| 796 |
+
continue
|
| 797 |
+
|
| 798 |
+
corrected_list.append({"opcode": opcode, "count": count})
|
| 799 |
+
|
| 800 |
+
# Merge duplicates after correction
|
| 801 |
+
merged = {}
|
| 802 |
+
for item in corrected_list:
|
| 803 |
+
merged[item["opcode"]] = merged.get(item["opcode"], 0) + item["count"]
|
| 804 |
+
|
| 805 |
+
return [{"opcode": k, "count": v} for k, v in merged.items()]
|
| 806 |
|
| 807 |
def format_scratch_pseudo_code(code_string):
|
| 808 |
"""
|
|
|
|
| 1859 |
|
| 1860 |
# Directly use the 'opcode_counts' list from the LLM's output
|
| 1861 |
plan["opcode_counts"] = llm_json.get("opcode_counts", [])
|
| 1862 |
+
plan["opcode_counts"] = validate_and_fix_opcodes(plan["opcode_counts"])
|
| 1863 |
# Optionally, you can remove the individual category lists from the plan
|
| 1864 |
# if they are no longer needed after the LLM provides the consolidated list.
|
| 1865 |
# for key in ["motion", "control", "operator", "sensing", "looks", "sounds", "events", "data"]:
|