Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
@@ -141,27 +141,16 @@ for d in (
|
|
141 |
# JSON_DIR,
|
142 |
):
|
143 |
d.mkdir(parents=True, exist_ok=True)
|
144 |
-
# def classify_image_type(description_or_name: str) -> str:
|
145 |
-
# desc = description_or_name.lower()
|
146 |
-
|
147 |
-
# sprite_keywords = ["sprite", "character", "animal", "person", "creature", "robot", "figure"]
|
148 |
-
# backdrop_keywords = ["background", "scene", "forest", "city", "room", "sky", "mountain", "village"]
|
149 |
-
# code_block_keywords = [
|
150 |
-
# "move", "turn", "wait", "repeat", "if", "else", "broadcast",
|
151 |
-
# "glide", "change", "forever", "when", "switch", "costume",
|
152 |
-
# "say", "think", "stop", "clone", "touching", "sensing",
|
153 |
-
# "scratch", "block", "code", "set", "variable"
|
154 |
-
# ]
|
155 |
-
|
156 |
-
# if any(kw in desc for kw in code_block_keywords):
|
157 |
-
# return "code-block"
|
158 |
-
# elif any(kw in desc for kw in sprite_keywords):
|
159 |
-
# return "sprite"
|
160 |
-
# elif any(kw in desc for kw in backdrop_keywords):
|
161 |
-
# return "backdrop"
|
162 |
-
# else:
|
163 |
-
# return "unknown"
|
164 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
165 |
class GameState(TypedDict):
|
166 |
project_json: dict
|
167 |
description: str
|
@@ -170,10 +159,9 @@ class GameState(TypedDict):
|
|
170 |
pseudo_code: dict
|
171 |
action_plan: Optional[Dict]
|
172 |
temporary_node: Optional[Dict]
|
173 |
-
|
174 |
-
|
175 |
-
|
176 |
-
# pseudo_node: Optional[Dict]
|
177 |
|
178 |
# Refined SYSTEM_PROMPT with more explicit Scratch JSON rules, especially for variables
|
179 |
SYSTEM_PROMPT = """
|
@@ -278,25 +266,6 @@ agent_json_resolver = create_react_agent(
|
|
278 |
prompt=SYSTEM_PROMPT_JSON_CORRECTOR
|
279 |
)
|
280 |
|
281 |
-
# # Helper function to load the block catalog from a JSON file
|
282 |
-
# def _load_block_catalog(file_path: str) -> Dict:
|
283 |
-
# """Loads the Scratch block catalog from a specified JSON file."""
|
284 |
-
# try:
|
285 |
-
# with open(file_path, 'r') as f:
|
286 |
-
# catalog = json.load(f)
|
287 |
-
# logger.info(f"Successfully loaded block catalog from {file_path}")
|
288 |
-
# return catalog
|
289 |
-
# except FileNotFoundError:
|
290 |
-
# logger.error(f"Error: Block catalog file not found at {file_path}")
|
291 |
-
# # Return an empty dict or raise an error, depending on desired behavior
|
292 |
-
# return {}
|
293 |
-
# except json.JSONDecodeError as e:
|
294 |
-
# logger.error(f"Error decoding JSON from {file_path}: {e}")
|
295 |
-
# return {}
|
296 |
-
# except Exception as e:
|
297 |
-
# logger.error(f"An unexpected error occurred while loading {file_path}: {e}")
|
298 |
-
# return {}
|
299 |
-
|
300 |
# Helper function to load the block catalog from a JSON file
|
301 |
def _load_block_catalog(block_type: str) -> Dict:
|
302 |
"""
|
@@ -696,7 +665,6 @@ def extract_json_from_llm_response(raw_response: str) -> dict:
|
|
696 |
# # 6. Return with the correct data URI prefix
|
697 |
# return f"data:image/png;base64,{clean_b64}"
|
698 |
|
699 |
-
# reducing imagebase64 size if greater than something
|
700 |
def reduce_image_size_to_limit(clean_b64_str, max_kb=4000):
|
701 |
"""
|
702 |
Reduce an image's size to be as close as possible to max_kb without exceeding it.
|
@@ -762,7 +730,7 @@ def clean_base64_for_model(raw_b64):
|
|
762 |
# Log original size
|
763 |
original_size = len(clean_b64.encode("utf-8"))
|
764 |
print(f"Original Base64 size (bytes): {original_size}")
|
765 |
-
if original_size> 4000000:
|
766 |
# Reduce size to under 4 MB
|
767 |
reduced_b64 = reduce_image_size_to_limit(clean_b64, max_kb=4000)
|
768 |
clean_b64_2 = re.sub(r"^data:image\/[a-zA-Z]+;base64,", "", reduced_b64)
|
@@ -772,7 +740,7 @@ def clean_base64_for_model(raw_b64):
|
|
772 |
# Return both prefixed and clean reduced versions
|
773 |
return f"data:image/jpeg;base64,{reduced_b64}"
|
774 |
return f"data:image/jpeg;base64,{clean_b64}"
|
775 |
-
|
776 |
def format_scratch_pseudo_code(code_string):
|
777 |
"""
|
778 |
Parses and formats Scratch pseudo-code with correct indentation,
|
@@ -823,16 +791,24 @@ def format_scratch_pseudo_code(code_string):
|
|
823 |
|
824 |
return '\n'.join(formatted_lines)
|
825 |
|
826 |
-
|
827 |
# Node 1: Logic updating if any issue here
|
828 |
def pseudo_generator_node(state: GameState):
|
829 |
logger.info("--- Running plan_logic_aligner_node ---")
|
830 |
image = state.get("project_image", "")
|
831 |
project_json = state["project_json"]
|
832 |
-
|
|
|
833 |
# MODIFICATION 1: Include 'Stage' in the list of names to plan for.
|
834 |
# It's crucial to ensure 'Stage' is always present for its global role.
|
835 |
target_names = [t["name"] for t in project_json["targets"]]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
836 |
|
837 |
refinement_prompt = f"""
|
838 |
You are an expert in Scratch 3.0 game development, specializing in understanding block relationships (stacked, nested).
|
@@ -840,8 +816,15 @@ You are an expert in Scratch 3.0 game development, specializing in understanding
|
|
840 |
From Image, you also have to detect a value of Key given in Text form "Script for: ". Below is the example
|
841 |
Example: "Script for: Bear", "Script for:" is a key and "Bear" is value and check if there is related target name available.
|
842 |
|
843 |
-
**
|
|
|
|
|
844 |
|
|
|
|
|
|
|
|
|
|
|
845 |
--- Scratch 3.0 Block Reference ---
|
846 |
### Hat Blocks
|
847 |
Description: {hat_description}
|
@@ -974,7 +957,7 @@ If you find any "Code-Blocks" then,
|
|
974 |
"type": "image_url",
|
975 |
"image_url": {
|
976 |
# "url": f"data:image/png;base64,{image}"
|
977 |
-
"url": clean_base64_for_model(image)
|
978 |
}
|
979 |
}
|
980 |
|
@@ -1018,10 +1001,12 @@ If you find any "Code-Blocks" then,
|
|
1018 |
|
1019 |
# Update the original action_plan in the state with the refined version
|
1020 |
state["pseudo_code"] = result
|
1021 |
-
|
|
|
1022 |
# with open("debug_state.json", "w", encoding="utf-8") as f:
|
1023 |
# json.dump(state, f, indent=2, ensure_ascii=False)
|
1024 |
print(f"[OVREALL REFINED PSEUDO CODE LOGIC]: {result}")
|
|
|
1025 |
logger.info("Plan refinement and block relation analysis completed for all plans.")
|
1026 |
return state
|
1027 |
# Node 2: planner node
|
@@ -1929,6 +1914,7 @@ def overall_block_builder_node_2(state: GameState):
|
|
1929 |
|
1930 |
# Node 6: variable adder node
|
1931 |
def variable_adder_node(state: GameState):
|
|
|
1932 |
project_json = state["project_json"]
|
1933 |
try:
|
1934 |
updated_project_json = variable_adder_main(project_json)
|
@@ -1938,239 +1924,23 @@ def variable_adder_node(state: GameState):
|
|
1938 |
else:
|
1939 |
print("Variable adder unable to add any variable inside the project!")
|
1940 |
state["project_json"]=project_json
|
|
|
1941 |
return state
|
1942 |
except Exception as e:
|
1943 |
logger.error(f"Error in variable adder node while updating project_json': {e}")
|
1944 |
raise
|
1945 |
|
1946 |
-
|
1947 |
-
|
1948 |
-
|
1949 |
-
|
1950 |
-
|
1951 |
-
|
1952 |
-
|
1953 |
-
|
1954 |
-
|
1955 |
-
|
1956 |
-
|
1957 |
-
# def plan_logic_aligner_node(state: GameState):
|
1958 |
-
# logger.info("--- Running plan_logic_aligner_node ---")
|
1959 |
-
|
1960 |
-
# image = state.get("image", "")
|
1961 |
-
|
1962 |
-
# refinement_prompt = f"""
|
1963 |
-
# You are an expert in Scratch 3.0 game development, specializing in understanding block relationships (stacked, nested).
|
1964 |
-
# "Analyze the Scratch code-block image and generate Pseudo-Code for what this logic appears to be doing."
|
1965 |
-
# From Image, you also have to detect a value of Key given in Text form "Script for: ". Below is the example
|
1966 |
-
# Example: "Script for: Bear", "Script for:" is a key and "Bear" is value.
|
1967 |
-
# --- Scratch 3.0 Block Reference ---
|
1968 |
-
# ### Hat Blocks
|
1969 |
-
# Description: {hat_description}
|
1970 |
-
# Blocks:
|
1971 |
-
# {hat_opcodes_functionalities}
|
1972 |
-
|
1973 |
-
# ### Boolean Blocks
|
1974 |
-
# Description: {boolean_description}
|
1975 |
-
# Blocks:
|
1976 |
-
# {boolean_opcodes_functionalities}
|
1977 |
-
|
1978 |
-
# ### C Blocks
|
1979 |
-
# Description: {c_description}
|
1980 |
-
# Blocks:
|
1981 |
-
# {c_opcodes_functionalities}
|
1982 |
-
|
1983 |
-
# ### Cap Blocks
|
1984 |
-
# Description: {cap_description}
|
1985 |
-
# Blocks:
|
1986 |
-
# {cap_opcodes_functionalities}
|
1987 |
-
|
1988 |
-
# ### Reporter Blocks
|
1989 |
-
# Description: {reporter_description}
|
1990 |
-
# Blocks:
|
1991 |
-
# {reporter_opcodes_functionalities}
|
1992 |
-
|
1993 |
-
# ### Stack Blocks
|
1994 |
-
# Description: {stack_description}
|
1995 |
-
# Blocks:
|
1996 |
-
# {stack_opcodes_functionalities}
|
1997 |
-
# -----------------------------------
|
1998 |
-
|
1999 |
-
# Your task is to:
|
2000 |
-
# If you don't find any "Code-Blocks" then,
|
2001 |
-
# **Don't generate Pseudo Code, and pass the message "No Code-blocks" find...
|
2002 |
-
# If you find any "Code-Blocks" then,
|
2003 |
-
# 1. **Refine the 'logic'**: Make it precise, accurate, and fully aligned with the Game Description. Use Scratch‑consistent verbs and phrasing. **Do NOT** use raw double‑quotes inside the logic string.
|
2004 |
-
|
2005 |
-
# 2. **Structural requirements**:
|
2006 |
-
# - **Numeric values** `(e.g., 0, 5, 0.2, -130)` **must** be in parentheses: `(0)`, `(5)`, `(0.2)`, `(-130)`.
|
2007 |
-
# - **AlphaNumeric values** `(e.g., hello, say 5, 4, hi!)` **must** be in parentheses: `(hello)`, `(say 5)`, `(4)`, `(hi!)`.
|
2008 |
-
# - **Variables** must be in the form `[variable v]` (e.g., `[score v]`), even when used inside expressions two example use `set [score v] to (1)` or `show variable ([speed v])`.
|
2009 |
-
# - **Dropdown options** must be in the form `[option v]` (e.g., `[Game Start v]`, `[blue sky v]`). example use `when [space v] key pressed`.
|
2010 |
-
# - **Reporter blocks** used as inputs must be double‑wrapped: `((x position))`, `((y position))`. example use `if <((y position)) = (-130)> then` or `(((x position)) * (1))`.
|
2011 |
-
# - **Boolean blocks** in conditions must be inside `< >`, including nested ones: `<not <condition>>`, `<<cond1> and <cond2>>`,`<<cond1> or <cond2>>`.
|
2012 |
-
# - **Other Boolean blocks** in conditions must be inside `< >`, including nested ones or values or variables: `<(block/value/variable) * (block/value/variable)>`,`<(block/value/variable) < (block/value/variable)>`, and example of another variable`<[apple v] contains [a v]?>`.
|
2013 |
-
# - **Operator expressions** must use explicit Scratch operator blocks, e.g.:
|
2014 |
-
# ```
|
2015 |
-
# (([ballSpeed v]) * (1.1))
|
2016 |
-
# ```
|
2017 |
-
# - **Every hat block script must end** with a final `end` on its own line.
|
2018 |
-
|
2019 |
-
# 3. **Pseudo‑code formatting**:
|
2020 |
-
# - Represent each block or nested block on its own line.
|
2021 |
-
# - Indent nested blocks by 4 spaces under their parent (`forever`, `if`, etc.).
|
2022 |
-
# - No comments or explanatory text—just the block sequence.
|
2023 |
-
# - 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.
|
2024 |
-
|
2025 |
-
# 4. **Logic content**:
|
2026 |
-
# - Build clear flow for mechanics (movement, jumping, flying, scoring, collisions).
|
2027 |
-
# - Match each action closely to a Scratch block or tight sequence.
|
2028 |
-
# - Do **NOT** include any justification or comments—only the raw logic.
|
2029 |
-
|
2030 |
-
# 5. **Examples for reference**:
|
2031 |
-
# **Correct** pattern for a simple start script:
|
2032 |
-
# ```
|
2033 |
-
# when green flag clicked
|
2034 |
-
# switch backdrop to [blue sky v]
|
2035 |
-
# set [score v] to (0)
|
2036 |
-
# show variable [score v]
|
2037 |
-
# broadcast [Game Start v]
|
2038 |
-
# end
|
2039 |
-
# ```
|
2040 |
-
# **Correct** pattern for updating the high score variable handling:
|
2041 |
-
# ```
|
2042 |
-
# when I receive [Game Over v]
|
2043 |
-
# if <((score)) > (([High Score v]))> then
|
2044 |
-
# set [High Score v] to ([score v])
|
2045 |
-
# end
|
2046 |
-
# switch backdrop to [Game Over v]
|
2047 |
-
# end
|
2048 |
-
# ```
|
2049 |
-
# **Correct** pattern for level up and increase difficulty use:
|
2050 |
-
# ```
|
2051 |
-
# when I receive [Level Up v]
|
2052 |
-
# change [level v] by (1)
|
2053 |
-
# set [ballSpeed v] to ((([ballSpeed v]) * (1.1)))
|
2054 |
-
# end
|
2055 |
-
# ```
|
2056 |
-
# **Correct** pattern for jumping mechanics use:
|
2057 |
-
# ```
|
2058 |
-
# when [space v] key pressed
|
2059 |
-
# if <((y position)) = (-100)> then
|
2060 |
-
# repeat (5)
|
2061 |
-
# change y by (100)
|
2062 |
-
# wait (0.1) seconds
|
2063 |
-
# change y by (-100)
|
2064 |
-
# wait (0.1) seconds
|
2065 |
-
# end
|
2066 |
-
# end
|
2067 |
-
# end
|
2068 |
-
# ```
|
2069 |
-
# **Correct** pattern for continuos moving objects use:
|
2070 |
-
# ```
|
2071 |
-
# when green flag clicked
|
2072 |
-
# go to x: (240) y: (-100)
|
2073 |
-
# set [speed v] to (-5)
|
2074 |
-
# show variable [speed v]
|
2075 |
-
# forever
|
2076 |
-
# change x by ([speed v])
|
2077 |
-
# if <((x position)) < (-240)> then
|
2078 |
-
# go to x: (240) y: (-100)
|
2079 |
-
# end
|
2080 |
-
# end
|
2081 |
-
# end
|
2082 |
-
# ```
|
2083 |
-
# **Correct** pattern for continuos moving objects use:
|
2084 |
-
# ```
|
2085 |
-
# when green flag clicked
|
2086 |
-
# go to x: (240) y: (-100)
|
2087 |
-
# set [speed v] to (-5)
|
2088 |
-
# show variable [speed v]
|
2089 |
-
# forever
|
2090 |
-
# change x by ([speed v])
|
2091 |
-
# if <((x position)) < (-240)> then
|
2092 |
-
# go to x: (240) y: (-100)
|
2093 |
-
# end
|
2094 |
-
# end
|
2095 |
-
# end
|
2096 |
-
# ```
|
2097 |
-
# 6. **Donot** add any explaination of logic or comments to justify or explain just put the logic content in the json.
|
2098 |
-
# 7. **Output**:
|
2099 |
-
# Return **only** a JSON object, using double quotes everywhere:
|
2100 |
-
# ```json
|
2101 |
-
# {{
|
2102 |
-
# "refined_logic":{{
|
2103 |
-
# "name_variable": 'Value of "Sript for: "',
|
2104 |
-
# "pseudocode":"…your fully‑formatted pseudo‑code here…",
|
2105 |
-
# }}
|
2106 |
-
# }}
|
2107 |
-
# ```
|
2108 |
-
# """
|
2109 |
-
# image_input = {
|
2110 |
-
# "type": "image_url",
|
2111 |
-
# "image_url": {
|
2112 |
-
# "url": f"data:image/png;base64,{image}"
|
2113 |
-
# }
|
2114 |
-
# }
|
2115 |
-
|
2116 |
-
# content = [
|
2117 |
-
# {"type": "text", "text": refinement_prompt},
|
2118 |
-
# image_input
|
2119 |
-
# ]
|
2120 |
-
|
2121 |
-
# try:
|
2122 |
-
# # Invoke the main agent for logic refinement and relationship identification
|
2123 |
-
# response = agent.invoke({"messages": [{"role": "user", "content": content}]})
|
2124 |
-
# llm_output_raw = response["messages"][-1].content.strip()
|
2125 |
-
|
2126 |
-
# parsed_llm_output = extract_json_from_llm_response(llm_output_raw)
|
2127 |
-
|
2128 |
-
# # result = parsed_llm_output
|
2129 |
-
# # Extract needed values directly
|
2130 |
-
# logic_data = parsed_llm_output.get("refined_logic", {})
|
2131 |
-
# name_variable = logic_data.get("name_variable", "Unknown")
|
2132 |
-
# pseudocode = logic_data.get("pseudocode", "No logic extracted")
|
2133 |
-
|
2134 |
-
# result = {"pseudo_node": {
|
2135 |
-
# "name_variable": name_variable,
|
2136 |
-
# "pseudocode": pseudocode
|
2137 |
-
# }}
|
2138 |
-
|
2139 |
-
# print(f"result:\n\n {result}")
|
2140 |
-
# return result
|
2141 |
-
# except Exception as e:
|
2142 |
-
# logger.error(f"❌ plan_logic_aligner_node failed: {str(e)}")
|
2143 |
-
# return {"error": str(e)}
|
2144 |
-
# except json.JSONDecodeError as error_json:
|
2145 |
-
# # If JSON parsing fails, use the json resolver agent
|
2146 |
-
# correction_prompt = (
|
2147 |
-
# "Your task is to correct the provided JSON string to ensure it is **syntactically perfect and adheres strictly to JSON rules**.\n"
|
2148 |
-
# "It must be a JSON object with `refined_logic` (string) and `block_relationships` (array of objects).\n"
|
2149 |
-
# f"- **Error Details**: {error_json}\n\n"
|
2150 |
-
# "**Strict Instructions for your response:**\n"
|
2151 |
-
# "1. **ONLY** output the corrected JSON. Do not include any other text or explanations.\n"
|
2152 |
-
# "2. Ensure all keys and string values are enclosed in **double quotes**. Escape internal quotes (`\\`).\n"
|
2153 |
-
# "3. No trailing commas. Correct nesting.\n\n"
|
2154 |
-
# "Here is the problematic JSON string to correct:\n"
|
2155 |
-
# f"```json\n{llm_output_raw}\n```\n"
|
2156 |
-
# "Corrected JSON:\n"
|
2157 |
-
# )
|
2158 |
-
# try:
|
2159 |
-
# correction_response = agent_json_resolver.invoke({"messages": [{"role": "user", "content": correction_prompt}]})
|
2160 |
-
# corrected_output = extract_json_from_llm_response(correction_response["messages"][-1].content)
|
2161 |
-
|
2162 |
-
# result = {
|
2163 |
-
# #"image_path": image_path,
|
2164 |
-
# "pseudo_code": corrected_output
|
2165 |
-
# }
|
2166 |
-
|
2167 |
-
# return result
|
2168 |
-
|
2169 |
-
# except Exception as e_corr:
|
2170 |
-
# logger.error(f"Failed to correct JSON output for even after retry: {e_corr}")
|
2171 |
-
|
2172 |
-
#def extract_images_from_pdf(pdf_path: Path, json_base_dir: Path, image_base_dir: Path):
|
2173 |
-
#def extract_images_from_pdf(pdf_path: Path, json_base_dir: Path):
|
2174 |
|
2175 |
# Prepare manipulated sprite JSON structure
|
2176 |
manipulated_json = {}
|
@@ -2395,7 +2165,7 @@ def similarity_matching(sprites_data: str, project_folder: str) -> str:
|
|
2395 |
# Copy matched backdrop assets + collect
|
2396 |
# =========================================
|
2397 |
backdrop_data = []
|
2398 |
-
|
2399 |
for backdrop_idx, matched_idx in enumerate(most_similar_indices):
|
2400 |
matched_image_path = folder_image_paths[matched_idx]
|
2401 |
matched_folder = os.path.dirname(matched_image_path)
|
@@ -2405,6 +2175,11 @@ def similarity_matching(sprites_data: str, project_folder: str) -> str:
|
|
2405 |
if not matched_folder.startswith(backdrop_base_path):
|
2406 |
continue
|
2407 |
|
|
|
|
|
|
|
|
|
|
|
2408 |
logger.info(f"Matched backdrop: {matched_image_path}")
|
2409 |
|
2410 |
# 1) Copy the matched backdrop image itself
|
@@ -2464,8 +2239,15 @@ def similarity_matching(sprites_data: str, project_folder: str) -> str:
|
|
2464 |
# then backdrop as the Stage
|
2465 |
if backdrop_data:
|
2466 |
all_costumes, sounds = [], []
|
|
|
2467 |
for i, bd in enumerate(backdrop_data):
|
2468 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
2469 |
if i == 0:
|
2470 |
sounds = bd.get("sounds", [])
|
2471 |
stage_obj={
|
@@ -2548,145 +2330,6 @@ def similarity_matching(sprites_data: str, project_folder: str) -> str:
|
|
2548 |
json.dump(final_project, f, indent=2)
|
2549 |
|
2550 |
return project_json_path
|
2551 |
-
# for sprite_idx, matched_idx in enumerate(most_similar_indices):
|
2552 |
-
# matched_image_path = folder_image_paths[matched_idx]
|
2553 |
-
# matched_image_path = os.path.normpath(matched_image_path)
|
2554 |
-
# print(" --------------------------------------1- matched_image_path ---------------------------------------",matched_image_path)
|
2555 |
-
# matched_folder = os.path.dirname(matched_image_path)
|
2556 |
-
# #folder_name = os.path.basename(matched_folder)
|
2557 |
-
# print(" --------------------------------------1- matched_folder ---------------------------------------",matched_folder)
|
2558 |
-
# if matched_folder in copied_folders:
|
2559 |
-
# continue
|
2560 |
-
# copied_folders.add(matched_folder)
|
2561 |
-
# logger.info(f"Matched image path: {matched_image_path}")
|
2562 |
-
|
2563 |
-
# sprite_json_path = os.path.join(matched_folder, 'sprite.json')
|
2564 |
-
# print(" --------------------------------------- sprite_json_path ---------------------------------------",sprite_json_path)
|
2565 |
-
# if not os.path.exists(sprite_json_path):
|
2566 |
-
# logger.warning(f"sprite.json not found in: {matched_folder}")
|
2567 |
-
# continue
|
2568 |
-
|
2569 |
-
# with open(sprite_json_path, 'r') as f:
|
2570 |
-
# sprite_data = json.load(f)
|
2571 |
-
# # print(f"SPRITE DATA: \n{sprite_data}")
|
2572 |
-
# # # Copy only non-matched files
|
2573 |
-
# # for fname in os.listdir(matched_folder):
|
2574 |
-
# # fpath = os.path.join(matched_folder, fname)
|
2575 |
-
# # if os.path.isfile(fpath) and fname not in {os.path.basename(matched_image_path), 'sprite.json'}:
|
2576 |
-
# # shutil.copy2(fpath, os.path.join(project_folder, fname))
|
2577 |
-
# # # logger.info(f"Copied Sprite asset: {fname}")
|
2578 |
-
# project_data.append(sprite_data)
|
2579 |
-
# print(" --------------------------------------1- project_data ---------------------------------------",project_data)
|
2580 |
-
# for fname in os.listdir(matched_folder):
|
2581 |
-
# fpath = os.path.join(matched_folder, fname)
|
2582 |
-
# dest_path = os.path.join(project_folder, fname)
|
2583 |
-
# if os.path.isfile(fpath) and fname not in {os.path.basename(matched_image_path), 'sprite.json'}:
|
2584 |
-
# shutil.copy2(fpath, dest_path)
|
2585 |
-
# logger.info(f"🟢 Copied Sprite Asset: {fpath} → {dest_path}")
|
2586 |
-
|
2587 |
-
# # ================================================================== #
|
2588 |
-
# # Loop through most similar images from Backdrops folder #
|
2589 |
-
# # → Copy Backdrop assets (excluding matched image + project.json) #
|
2590 |
-
# # → Load project.json and append its data to project_data #
|
2591 |
-
# # ================================================================== #
|
2592 |
-
# backdrop_data = [] # for backdrop-related entries
|
2593 |
-
|
2594 |
-
# for backdrop_idx, matched_idx in enumerate(most_similar_indices):
|
2595 |
-
# matched_image_path = os.path.normpath(folder_image_paths[matched_idx])
|
2596 |
-
# print(" --------------------------------------2- matched_image_path ---------------------------------------",matched_image_path)
|
2597 |
-
# # Check if the match is from the Backdrops folder
|
2598 |
-
# if matched_image_path.startswith(os.path.normpath(backdrop_images_path)):
|
2599 |
-
# matched_folder = os.path.dirname(matched_image_path)
|
2600 |
-
# print(" --------------------------------------2- matched_folder ---------------------------------------",matched_folder)
|
2601 |
-
# folder_name = os.path.basename(matched_folder)
|
2602 |
-
|
2603 |
-
# logger.info(f"Backdrop matched image: {matched_image_path}")
|
2604 |
-
|
2605 |
-
# # Copy only non-matched files
|
2606 |
-
# # for fname in os.listdir(matched_folder):
|
2607 |
-
# # fpath = os.path.join(matched_folder, fname)
|
2608 |
-
# # if os.path.isfile(fpath) and fname not in {os.path.basename(matched_image_path), 'project.json'}:
|
2609 |
-
# # shutil.copy2(fpath, os.path.join(project_folder, fname))
|
2610 |
-
# # # logger.info(f"Copied Backdrop asset: {fname}")
|
2611 |
-
# for fname in os.listdir(matched_folder):
|
2612 |
-
# fpath = os.path.join(matched_folder, fname)
|
2613 |
-
# dest_path = os.path.join(project_folder, fname)
|
2614 |
-
# if os.path.isfile(fpath) and fname not in {os.path.basename(matched_image_path), 'project.json'}:
|
2615 |
-
# shutil.copy2(fpath, dest_path)
|
2616 |
-
# logger.info(f"🟡 Copied Backdrop Asset: {fpath} → {dest_path}")
|
2617 |
-
|
2618 |
-
|
2619 |
-
# # Append backdrop's project.json
|
2620 |
-
# backdrop_json_path = os.path.join(matched_folder, 'project.json')
|
2621 |
-
# print(" --------------------------------------2- backdrop_json_path ---------------------------------------",backdrop_json_path)
|
2622 |
-
# if os.path.exists(backdrop_json_path):
|
2623 |
-
# with open(backdrop_json_path, 'r') as f:
|
2624 |
-
# backdrop_json_data = json.load(f)
|
2625 |
-
# # print(f"SPRITE DATA: \n{backdrop_json_data}")
|
2626 |
-
# if "targets" in backdrop_json_data:
|
2627 |
-
# for target in backdrop_json_data["targets"]:
|
2628 |
-
# if target.get("isStage") == True:
|
2629 |
-
# backdrop_data.append(target)
|
2630 |
-
# else:
|
2631 |
-
# logger.warning(f"project.json not found in: {matched_folder}")
|
2632 |
-
|
2633 |
-
# # Merge JSON structure
|
2634 |
-
# final_project = {
|
2635 |
-
# "targets": [],
|
2636 |
-
# "monitors": [],
|
2637 |
-
# "extensions": [],
|
2638 |
-
# "meta": {
|
2639 |
-
# "semver": "3.0.0",
|
2640 |
-
# "vm": "11.3.0",
|
2641 |
-
# "agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Safari/537.36"
|
2642 |
-
# }
|
2643 |
-
# }
|
2644 |
-
|
2645 |
-
# for sprite in project_data:
|
2646 |
-
# if not sprite.get("isStage", False):
|
2647 |
-
# final_project["targets"].append(sprite)
|
2648 |
-
|
2649 |
-
# if backdrop_data:
|
2650 |
-
# all_costumes, sounds = [], []
|
2651 |
-
# for idx, bd in enumerate(backdrop_data):
|
2652 |
-
# all_costumes.extend(bd.get("costumes", []))
|
2653 |
-
# if idx == 0 and "sounds" in bd:
|
2654 |
-
# sounds = bd["sounds"]
|
2655 |
-
# final_project["targets"].append({
|
2656 |
-
# "isStage": True,
|
2657 |
-
# "name": "Stage",
|
2658 |
-
# "variables": {},
|
2659 |
-
# "lists": {},
|
2660 |
-
# "broadcasts": {},
|
2661 |
-
# "blocks": {},
|
2662 |
-
# "comments": {},
|
2663 |
-
# "currentCostume": 1 if len(all_costumes) > 1 else 0,
|
2664 |
-
# "costumes": all_costumes,
|
2665 |
-
# "sounds": sounds,
|
2666 |
-
# "volume": 100,
|
2667 |
-
# "layerOrder": 0,
|
2668 |
-
# "tempo": 60,
|
2669 |
-
# "videoTransparency": 50,
|
2670 |
-
# "videoState": "on",
|
2671 |
-
# "textToSpeechLanguage": None
|
2672 |
-
# })
|
2673 |
-
|
2674 |
-
# with open(project_json_path, 'w') as f:
|
2675 |
-
# json.dump(final_project, f, indent=2)
|
2676 |
-
|
2677 |
-
# # logger.info(f"🎉 Final project saved: {project_json_path}")
|
2678 |
-
# return project_json_path
|
2679 |
-
|
2680 |
-
# def convert_bytes_to_image(pdf_bytes: bytes, dpi: int):
|
2681 |
-
# images = convert_from_bytes(pdf_bytes, dpi=dpi, poppler_path=poppler_path)
|
2682 |
-
# # Save each page to an in-memory BytesIO and return a list of BytesIOs
|
2683 |
-
# buffers = []
|
2684 |
-
# for img in images:
|
2685 |
-
# buf = BytesIO()
|
2686 |
-
# img.save(buf, format="PNG")
|
2687 |
-
# buf.seek(0)
|
2688 |
-
# buffers.append(buf)
|
2689 |
-
# return buffers
|
2690 |
|
2691 |
def convert_pdf_stream_to_images(pdf_stream: io.BytesIO, dpi=300):
|
2692 |
# Ensure we are at the start of the stream
|
@@ -2702,7 +2345,7 @@ def convert_pdf_stream_to_images(pdf_stream: io.BytesIO, dpi=300):
|
|
2702 |
|
2703 |
def delay_for_tpm_node(state: GameState):
|
2704 |
logger.info("--- Running DelayForTPMNode ---")
|
2705 |
-
time.sleep(
|
2706 |
logger.info("Delay completed.")
|
2707 |
return state
|
2708 |
|
@@ -2722,18 +2365,37 @@ workflow.add_node("refined_planner", refined_planner_node) # Refines the action
|
|
2722 |
workflow.add_node("opcode_counter", plan_opcode_counter_node)
|
2723 |
workflow.add_node("block_builder", overall_block_builder_node_2)
|
2724 |
workflow.add_node("variable_initializer", variable_adder_node)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2725 |
|
2726 |
-
workflow.set_entry_point("pseudo_generator")
|
2727 |
-
workflow.add_edge("pseudo_generator","time_delay_1")
|
2728 |
-
workflow.add_edge("time_delay_1","plan_generator")
|
2729 |
-
workflow.add_edge("plan_generator","time_delay_2")
|
2730 |
-
# workflow.add_edge("time_delay_2",END)
|
2731 |
-
workflow.add_edge("time_delay_2","refined_planner")
|
2732 |
-
workflow.add_edge("refined_planner","time_delay_3")
|
2733 |
-
workflow.add_edge("time_delay_3","opcode_counter")
|
2734 |
-
workflow.add_edge("opcode_counter","block_builder")
|
2735 |
-
workflow.add_edge("block_builder","variable_initializer")
|
2736 |
-
workflow.add_edge("variable_initializer", END)
|
2737 |
app_graph = workflow.compile()
|
2738 |
|
2739 |
# ============== Helper function to Upscale an Image ============== #
|
@@ -2911,6 +2573,11 @@ def process_pdf():
|
|
2911 |
print(f"-----------------------------Execution Time save_pdf_to_generated_dir() : {total_time}-----------------------------\n")
|
2912 |
# }
|
2913 |
|
|
|
|
|
|
|
|
|
|
|
2914 |
# {
|
2915 |
# Extract & process
|
2916 |
# output_path, result = extract_images_from_pdf(saved_pdf_path)
|
@@ -2956,23 +2623,26 @@ def process_pdf():
|
|
2956 |
images = convert_pdf_stream_to_images(pdf_stream, dpi=300)
|
2957 |
else:
|
2958 |
images = convert_from_path(pdf_stream, dpi=300)
|
2959 |
-
|
2960 |
#updating logic here [Dev Patel]
|
2961 |
-
|
2962 |
-
|
2963 |
-
|
2964 |
-
|
2965 |
-
|
2966 |
-
|
2967 |
-
|
2968 |
-
|
2969 |
-
|
2970 |
-
|
|
|
|
|
|
|
2971 |
|
2972 |
-
#
|
2973 |
-
|
2974 |
-
|
2975 |
-
final_project_json = project_skeleton
|
2976 |
|
2977 |
# Save the *final* filled project JSON, overwriting the skeleton
|
2978 |
with open(project_output, "w") as f:
|
|
|
141 |
# JSON_DIR,
|
142 |
):
|
143 |
d.mkdir(parents=True, exist_ok=True)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
144 |
|
145 |
+
# class GameState(TypedDict):
|
146 |
+
# project_json: dict
|
147 |
+
# description: str
|
148 |
+
# project_id: str
|
149 |
+
# project_image: str
|
150 |
+
# pseudo_code: dict
|
151 |
+
# action_plan: Optional[Dict]
|
152 |
+
# temporary_node: Optional[Dict]
|
153 |
+
|
154 |
class GameState(TypedDict):
|
155 |
project_json: dict
|
156 |
description: str
|
|
|
159 |
pseudo_code: dict
|
160 |
action_plan: Optional[Dict]
|
161 |
temporary_node: Optional[Dict]
|
162 |
+
page_count: int
|
163 |
+
processing: bool
|
164 |
+
temp_pseudo_code: list
|
|
|
165 |
|
166 |
# Refined SYSTEM_PROMPT with more explicit Scratch JSON rules, especially for variables
|
167 |
SYSTEM_PROMPT = """
|
|
|
266 |
prompt=SYSTEM_PROMPT_JSON_CORRECTOR
|
267 |
)
|
268 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
269 |
# Helper function to load the block catalog from a JSON file
|
270 |
def _load_block_catalog(block_type: str) -> Dict:
|
271 |
"""
|
|
|
665 |
# # 6. Return with the correct data URI prefix
|
666 |
# return f"data:image/png;base64,{clean_b64}"
|
667 |
|
|
|
668 |
def reduce_image_size_to_limit(clean_b64_str, max_kb=4000):
|
669 |
"""
|
670 |
Reduce an image's size to be as close as possible to max_kb without exceeding it.
|
|
|
730 |
# Log original size
|
731 |
original_size = len(clean_b64.encode("utf-8"))
|
732 |
print(f"Original Base64 size (bytes): {original_size}")
|
733 |
+
if original_size > 4000000:
|
734 |
# Reduce size to under 4 MB
|
735 |
reduced_b64 = reduce_image_size_to_limit(clean_b64, max_kb=4000)
|
736 |
clean_b64_2 = re.sub(r"^data:image\/[a-zA-Z]+;base64,", "", reduced_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 |
"""
|
746 |
Parses and formats Scratch pseudo-code with correct indentation,
|
|
|
791 |
|
792 |
return '\n'.join(formatted_lines)
|
793 |
|
|
|
794 |
# Node 1: Logic updating if any issue here
|
795 |
def pseudo_generator_node(state: GameState):
|
796 |
logger.info("--- Running plan_logic_aligner_node ---")
|
797 |
image = state.get("project_image", "")
|
798 |
project_json = state["project_json"]
|
799 |
+
cnt =state["page_count"]
|
800 |
+
print(f"The page number recived at the pseudo_generator node:-----> {cnt}")
|
801 |
# MODIFICATION 1: Include 'Stage' in the list of names to plan for.
|
802 |
# It's crucial to ensure 'Stage' is always present for its global role.
|
803 |
target_names = [t["name"] for t in project_json["targets"]]
|
804 |
+
stage_names = [t["name"] for t in project_json["targets"] if t.get("isStage")]
|
805 |
+
sprite_names = [t["name"] for t in project_json["targets"] if not t.get("isStage")]
|
806 |
+
# Get costumes separately for Stage and Sprites
|
807 |
+
stage_costumes = [
|
808 |
+
c["name"]
|
809 |
+
for t in project_json["targets"] if t.get("isStage")
|
810 |
+
for c in t.get("costumes", [])
|
811 |
+
]
|
812 |
|
813 |
refinement_prompt = f"""
|
814 |
You are an expert in Scratch 3.0 game development, specializing in understanding block relationships (stacked, nested).
|
|
|
816 |
From Image, you also have to detect a value of Key given in Text form "Script for: ". Below is the example
|
817 |
Example: "Script for: Bear", "Script for:" is a key and "Bear" is value and check if there is related target name available.
|
818 |
|
819 |
+
**Special Rule for Stage Costumes:**
|
820 |
+
If the value of "Script for:" exactly matches ANY costume name in the Stage_costumes list given below,
|
821 |
+
then the `"name_variable"` in the output JSON must be set to `"Stage"` (not the costume name).
|
822 |
|
823 |
+
**Targets in Game (Sprites and Stage) available in project_json:**
|
824 |
+
Sprite_name:{', '.join(sprite_names)}
|
825 |
+
Stage_name: Stage
|
826 |
+
Stage_costumes: {', '.join(stage_costumes)}
|
827 |
+
|
828 |
--- Scratch 3.0 Block Reference ---
|
829 |
### Hat Blocks
|
830 |
Description: {hat_description}
|
|
|
957 |
"type": "image_url",
|
958 |
"image_url": {
|
959 |
# "url": f"data:image/png;base64,{image}"
|
960 |
+
"url": clean_base64_for_model(image[cnt])
|
961 |
}
|
962 |
}
|
963 |
|
|
|
1001 |
|
1002 |
# Update the original action_plan in the state with the refined version
|
1003 |
state["pseudo_code"] = result
|
1004 |
+
state["temp_pseudo_code"] += [result]
|
1005 |
+
Data = state["temp_pseudo_code"]
|
1006 |
# with open("debug_state.json", "w", encoding="utf-8") as f:
|
1007 |
# json.dump(state, f, indent=2, ensure_ascii=False)
|
1008 |
print(f"[OVREALL REFINED PSEUDO CODE LOGIC]: {result}")
|
1009 |
+
print(f"[OVREALL LISTS OF LOGICS]: {Data}")
|
1010 |
logger.info("Plan refinement and block relation analysis completed for all plans.")
|
1011 |
return state
|
1012 |
# Node 2: planner node
|
|
|
1914 |
|
1915 |
# Node 6: variable adder node
|
1916 |
def variable_adder_node(state: GameState):
|
1917 |
+
logger.info("--- Running Variable Adder Node ---")
|
1918 |
project_json = state["project_json"]
|
1919 |
try:
|
1920 |
updated_project_json = variable_adder_main(project_json)
|
|
|
1924 |
else:
|
1925 |
print("Variable adder unable to add any variable inside the project!")
|
1926 |
state["project_json"]=project_json
|
1927 |
+
state["page_count"] +=1
|
1928 |
return state
|
1929 |
except Exception as e:
|
1930 |
logger.error(f"Error in variable adder node while updating project_json': {e}")
|
1931 |
raise
|
1932 |
|
1933 |
+
# Node 7: variable adder node
|
1934 |
+
def processed_page_node(state: GameState):
|
1935 |
+
logger.info("--- Processing the Pages Node ---")
|
1936 |
+
image = state.get("project_image", "")
|
1937 |
+
cnt =state["page_count"]
|
1938 |
+
print(f"The page processed for page:--------------> {cnt}")
|
1939 |
+
if cnt<len(image):
|
1940 |
+
state["processing"]= True
|
1941 |
+
else:
|
1942 |
+
state["processing"]= False
|
1943 |
+
return state
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1944 |
|
1945 |
# Prepare manipulated sprite JSON structure
|
1946 |
manipulated_json = {}
|
|
|
2165 |
# Copy matched backdrop assets + collect
|
2166 |
# =========================================
|
2167 |
backdrop_data = []
|
2168 |
+
copied_backdrop_folders = set()
|
2169 |
for backdrop_idx, matched_idx in enumerate(most_similar_indices):
|
2170 |
matched_image_path = folder_image_paths[matched_idx]
|
2171 |
matched_folder = os.path.dirname(matched_image_path)
|
|
|
2175 |
if not matched_folder.startswith(backdrop_base_path):
|
2176 |
continue
|
2177 |
|
2178 |
+
# skip if backdrop folder already processed
|
2179 |
+
if matched_folder in copied_backdrop_folders:
|
2180 |
+
continue
|
2181 |
+
copied_backdrop_folders.add(matched_folder)
|
2182 |
+
|
2183 |
logger.info(f"Matched backdrop: {matched_image_path}")
|
2184 |
|
2185 |
# 1) Copy the matched backdrop image itself
|
|
|
2239 |
# then backdrop as the Stage
|
2240 |
if backdrop_data:
|
2241 |
all_costumes, sounds = [], []
|
2242 |
+
seen_costumes = set()
|
2243 |
for i, bd in enumerate(backdrop_data):
|
2244 |
+
for costume in bd.get("costumes", []):
|
2245 |
+
# Create a unique key for the costume
|
2246 |
+
key = (costume.get("name"), costume.get("assetId"))
|
2247 |
+
if key not in seen_costumes:
|
2248 |
+
seen_costumes.add(key)
|
2249 |
+
all_costumes.append(costume)
|
2250 |
+
|
2251 |
if i == 0:
|
2252 |
sounds = bd.get("sounds", [])
|
2253 |
stage_obj={
|
|
|
2330 |
json.dump(final_project, f, indent=2)
|
2331 |
|
2332 |
return project_json_path
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2333 |
|
2334 |
def convert_pdf_stream_to_images(pdf_stream: io.BytesIO, dpi=300):
|
2335 |
# Ensure we are at the start of the stream
|
|
|
2345 |
|
2346 |
def delay_for_tpm_node(state: GameState):
|
2347 |
logger.info("--- Running DelayForTPMNode ---")
|
2348 |
+
time.sleep(10) # Adjust the delay as needed
|
2349 |
logger.info("Delay completed.")
|
2350 |
return state
|
2351 |
|
|
|
2365 |
workflow.add_node("opcode_counter", plan_opcode_counter_node)
|
2366 |
workflow.add_node("block_builder", overall_block_builder_node_2)
|
2367 |
workflow.add_node("variable_initializer", variable_adder_node)
|
2368 |
+
workflow.add_node("page_processed", processed_page_node)
|
2369 |
+
|
2370 |
+
workflow.set_entry_point("page_processed")
|
2371 |
+
# Conditional branching from the start
|
2372 |
+
def decide_next_step(state: GameState):
|
2373 |
+
if state.get("processing", False):
|
2374 |
+
return "pseudo_generator"
|
2375 |
+
else:
|
2376 |
+
return END
|
2377 |
+
|
2378 |
+
workflow.add_conditional_edges(
|
2379 |
+
"page_processed",
|
2380 |
+
decide_next_step,
|
2381 |
+
{
|
2382 |
+
"pseudo_generator": "pseudo_generator",
|
2383 |
+
str(END): END # str(END) is '__end__'
|
2384 |
+
}
|
2385 |
+
)
|
2386 |
+
# Main chain
|
2387 |
+
workflow.add_edge("pseudo_generator", "time_delay_1")
|
2388 |
+
workflow.add_edge("time_delay_1", "plan_generator")
|
2389 |
+
workflow.add_edge("plan_generator", "time_delay_2")
|
2390 |
+
workflow.add_edge("time_delay_2", "refined_planner")
|
2391 |
+
workflow.add_edge("refined_planner", "time_delay_3")
|
2392 |
+
workflow.add_edge("time_delay_3", "opcode_counter")
|
2393 |
+
workflow.add_edge("opcode_counter", "block_builder")
|
2394 |
+
workflow.add_edge("block_builder", "variable_initializer")
|
2395 |
+
|
2396 |
+
# After last node, check again
|
2397 |
+
workflow.add_edge("variable_initializer", "page_processed")
|
2398 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2399 |
app_graph = workflow.compile()
|
2400 |
|
2401 |
# ============== Helper function to Upscale an Image ============== #
|
|
|
2573 |
print(f"-----------------------------Execution Time save_pdf_to_generated_dir() : {total_time}-----------------------------\n")
|
2574 |
# }
|
2575 |
|
2576 |
+
# Save uploaded file to disk
|
2577 |
+
# pdf_path = os.path.join("/tmp", secure_filename(file.filename))
|
2578 |
+
# file.save(pdf_path)
|
2579 |
+
# compressed_pages = pdf_to_images_with_size_check(pdf_path, "/tmp/compressed_pages", size_limit_mb=4)
|
2580 |
+
|
2581 |
# {
|
2582 |
# Extract & process
|
2583 |
# output_path, result = extract_images_from_pdf(saved_pdf_path)
|
|
|
2623 |
images = convert_pdf_stream_to_images(pdf_stream, dpi=300)
|
2624 |
else:
|
2625 |
images = convert_from_path(pdf_stream, dpi=300)
|
2626 |
+
|
2627 |
#updating logic here [Dev Patel]
|
2628 |
+
initial_state_dict = {
|
2629 |
+
"project_json": project_skeleton,
|
2630 |
+
"description": "The pseudo code for the script",
|
2631 |
+
"project_id": project_id,
|
2632 |
+
# "project_image": img_b64,
|
2633 |
+
"project_image": images,
|
2634 |
+
"action_plan": {},
|
2635 |
+
"pseudo_code": {},
|
2636 |
+
"temporary_node": {},
|
2637 |
+
"processing":True,
|
2638 |
+
"page_count": 0,
|
2639 |
+
"temp_pseudo_code":[],
|
2640 |
+
}
|
2641 |
|
2642 |
+
#final_state_dict = app_graph.invoke(initial_state_dict) # Pass dictionary
|
2643 |
+
final_state_dict = app_graph.invoke(initial_state_dict,config={"recursion_limit": 200})
|
2644 |
+
final_project_json = final_state_dict['project_json'] # Access as dict
|
2645 |
+
# final_project_json = project_skeleton
|
2646 |
|
2647 |
# Save the *final* filled project JSON, overwriting the skeleton
|
2648 |
with open(project_output, "w") as f:
|