Spaces:
Running
Running
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"]:
|