prthm11 commited on
Commit
ea87f78
·
verified ·
1 Parent(s): 3134223

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +27 -58
app.py CHANGED
@@ -2106,17 +2106,14 @@ def create_sb3_archive(project_folder: Path, project_id: str) -> Path | None:
2106
  Returns:
2107
  Path: The path to the created .sb3 file, or None if an error occurred.
2108
  """
2109
- # Use Path objects for consistency
2110
  output_base_name = GEN_PROJECT_DIR / project_id
2111
  zip_path = None
2112
  sb3_path = None
2113
  try:
2114
- # shutil.make_archive automatically adds .zip extension
2115
  zip_path_str = shutil.make_archive(str(output_base_name), 'zip', root_dir=str(project_folder))
2116
- zip_path = Path(zip_path_str) # Convert back to Path object
2117
  logger.info(f"Project folder zipped to: {zip_path}")
2118
 
2119
- # 2. Rename the .zip file to .sb3
2120
  sb3_path = GEN_PROJECT_DIR / f"{project_id}.sb3"
2121
  os.rename(zip_path, sb3_path)
2122
  logger.info(f"Renamed {zip_path} to {sb3_path}")
@@ -2124,7 +2121,6 @@ def create_sb3_archive(project_folder: Path, project_id: str) -> Path | None:
2124
  return sb3_path
2125
  except Exception as e:
2126
  logger.error(f"Error creating SB3 archive for {project_id}: {e}", exc_info=True)
2127
- # Clean up any partial files if an error occurs
2128
  if zip_path and zip_path.exists():
2129
  os.remove(zip_path)
2130
  if sb3_path and sb3_path.exists():
@@ -2142,13 +2138,13 @@ def download_sb3(project_id):
2142
  Allows users to download the generated .sb3 Scratch project file.
2143
  """
2144
  sb3_filename = f"{project_id}.sb3"
2145
- sb3_filepath = GEN_PROJECT_DIR / sb3_filename # Use Path object consistent with creation
2146
 
2147
  try:
2148
  if sb3_filepath.exists():
2149
  logger.info(f"Serving SB3 file for project ID: {project_id}")
2150
  return send_from_directory(
2151
- directory=GEN_PROJECT_DIR, # Pass the Path object here
2152
  path=sb3_filename,
2153
  as_attachment=True,
2154
  download_name=sb3_filename
@@ -2160,11 +2156,11 @@ def download_sb3(project_id):
2160
  logger.error(f"Error serving SB3 file for ID {project_id}: {e}", exc_info=True)
2161
  return jsonify({"error": "Failed to retrieve Scratch project file"}), 500
2162
 
2163
- # API endpoint
2164
  @app.route('/process_pdf', methods=['POST'])
2165
  def process_pdf():
2166
- project_id = None # Initialize project_id outside try-block for error logging
2167
  project_folder = None
 
2168
  try:
2169
  logger.info("Received request to process PDF.")
2170
  if 'pdf_file' not in request.files:
@@ -2175,45 +2171,28 @@ def process_pdf():
2175
  if pdf_file.filename == '':
2176
  return jsonify({"error": "Empty filename"}), 400
2177
 
2178
- # ================================================= #
2179
- # Generate Random UUID for project folder name #
2180
- # ================================================= #
2181
  project_id = str(uuid.uuid4()).replace('-', '')
2182
- project_folder = OUTPUT_DIR / project_id # Use Path object
2183
 
2184
- # =========================================================================== #
2185
- # Create empty json in project_{random_id} folder #
2186
- # =========================================================================== #
2187
- # THIS WAS COMMENTED OUT - CRITICAL FIX!
2188
  project_folder.mkdir(parents=True, exist_ok=True)
2189
  logger.info(f"Created project folder: {project_folder}")
2190
 
2191
- # Save the uploaded PDF temporarily
2192
  filename = secure_filename(pdf_file.filename)
2193
- temp_dir = Path(tempfile.mkdtemp()) # Use Path for temp dir
2194
  saved_pdf_path = temp_dir / filename
2195
  pdf_file.save(saved_pdf_path)
2196
 
2197
  logger.info(f"Saved uploaded PDF to: {saved_pdf_path}")
2198
 
2199
- # Extract & process
2200
- # Ensure extract_images_from_pdf can handle Path objects or convert before passing
2201
- json_path = None # As per original code, json_path is None
2202
  extracted_output_dir, result = extract_images_from_pdf(saved_pdf_path, json_path)
2203
 
2204
- # Check extracted_sprites.json for "scratch block" in any 'name'
2205
- # Ensure JSON_DIR is a Path object or use os.path.join consistently
2206
- extracted_sprites_json = JSON_DIR / Path(filename).stem / "extracted_sprites.json"
2207
-
2208
- # NOTE: The original `extracted_dir = os.path.join(JSON_DIR, os.path.splitext(filename)[0])`
2209
- # and `extracted_sprites_json = os.path.join(extracted_dir, "extracted_sprites.json")`
2210
- # implies `extract_images_from_pdf` puts stuff in JSON_DIR.
2211
- # Ensure `extract_images_from_pdf` actually creates this path.
2212
- # For this example, I'm assuming `extracted_output_dir` (from `extract_images_from_pdf`)
2213
- # contains the `extracted_sprites.json`. Adjust based on your `extract_images_from_pdf`
2214
- # implementation. Let's use `extracted_output_dir` if it's correct.
2215
- extracted_sprites_json_path = extracted_output_dir / "extracted_sprites.json"
2216
 
 
2217
 
2218
  if not extracted_sprites_json_path.exists():
2219
  logger.error(f"No extracted_sprites.json found at {extracted_sprites_json_path}")
@@ -2222,45 +2201,41 @@ def process_pdf():
2222
  with open(extracted_sprites_json_path, 'r') as f:
2223
  sprite_data = json.load(f)
2224
 
2225
- # similarity_matching should return the path to the project.json within project_folder
2226
  project_output = similarity_matching(extracted_output_dir, project_folder)
2227
- logger.info("Similarity matching completed.") # Removed duplicate "Received request to process PDF."
2228
 
2229
  with open(project_output, 'r') as f:
2230
  project_skeleton = json.load(f)
2231
 
2232
  images = convert_from_path(saved_pdf_path, dpi=300)
2233
- # print(type) # This `print(type)` line seems like a leftover debug statement and will print the `type` built-in function.
2234
  page = images[0]
2235
  buf = BytesIO()
2236
  page.save(buf, format="PNG")
2237
  img_bytes = buf.getvalue()
2238
  img_b64 = base64.b64encode(img_bytes).decode("utf-8")
2239
 
2240
- # initial_state_dict = {
2241
- # "project_json": project_skeleton,
2242
- # "description": "The pseudo code for the script",
2243
- # "project_id": project_id,
2244
- # "project_image": img_b64,
2245
- # "action_plan": {},
2246
- # "pseudo_code": {},
2247
- # "temporary_node": {},
2248
- # }
2249
 
2250
- # final_state_dict = app_graph.invoke(initial_state_dict)
2251
 
2252
- final_project_json = project_skeleton#final_state_dict['project_json']
2253
 
2254
- # Save the *final* filled project JSON, overwriting the skeleton
2255
  with open(project_output, "w") as f:
2256
  json.dump(final_project_json, f, indent=2)
2257
  logger.info(f"Final project JSON saved to {project_output}")
2258
 
2259
- # --- Call the new function to create the .sb3 file ---
2260
  sb3_file_path = create_sb3_archive(project_folder, project_id)
2261
  if sb3_file_path:
2262
  logger.info(f"Successfully created SB3 file: {sb3_file_path}")
2263
- download_url = f"/download_sb3/{project_id}" # Use relative path for internal Flask app
2264
  print(f"DOWNLOAD_URL: {download_url}")
2265
  return jsonify({"message": "Processed PDF and Game sb3 generated successfully", "project_id": project_id, "download_url": download_url})
2266
  else:
@@ -2270,15 +2245,9 @@ def process_pdf():
2270
  logger.error(f"Error during processing the pdf workflow for project ID {project_id}: {e}", exc_info=True)
2271
  return jsonify({"error": f"❌ Failed to process PDF: {str(e)}"}), 500
2272
  finally:
2273
- # Clean up temporary PDF directory
2274
- if 'temp_dir' in locals() and temp_dir.exists():
2275
  shutil.rmtree(temp_dir)
2276
  logger.info(f"Cleaned up temporary directory: {temp_dir}")
2277
- # Optionally, clean up the main project_folder if an error occurred before SB3 creation
2278
- # (Be careful with this if you want to inspect failed project folders)
2279
- # if project_folder and project_folder.exists() and sb3_file_path is None:
2280
- # shutil.rmtree(project_folder)
2281
- # logger.info(f"Cleaned up partial project folder: {project_folder}")
2282
 
2283
  @app.route('/list_projects', methods=['GET'])
2284
  def list_projects():
 
2106
  Returns:
2107
  Path: The path to the created .sb3 file, or None if an error occurred.
2108
  """
 
2109
  output_base_name = GEN_PROJECT_DIR / project_id
2110
  zip_path = None
2111
  sb3_path = None
2112
  try:
 
2113
  zip_path_str = shutil.make_archive(str(output_base_name), 'zip', root_dir=str(project_folder))
2114
+ zip_path = Path(zip_path_str)
2115
  logger.info(f"Project folder zipped to: {zip_path}")
2116
 
 
2117
  sb3_path = GEN_PROJECT_DIR / f"{project_id}.sb3"
2118
  os.rename(zip_path, sb3_path)
2119
  logger.info(f"Renamed {zip_path} to {sb3_path}")
 
2121
  return sb3_path
2122
  except Exception as e:
2123
  logger.error(f"Error creating SB3 archive for {project_id}: {e}", exc_info=True)
 
2124
  if zip_path and zip_path.exists():
2125
  os.remove(zip_path)
2126
  if sb3_path and sb3_path.exists():
 
2138
  Allows users to download the generated .sb3 Scratch project file.
2139
  """
2140
  sb3_filename = f"{project_id}.sb3"
2141
+ sb3_filepath = GEN_PROJECT_DIR / sb3_filename
2142
 
2143
  try:
2144
  if sb3_filepath.exists():
2145
  logger.info(f"Serving SB3 file for project ID: {project_id}")
2146
  return send_from_directory(
2147
+ directory=GEN_PROJECT_DIR,
2148
  path=sb3_filename,
2149
  as_attachment=True,
2150
  download_name=sb3_filename
 
2156
  logger.error(f"Error serving SB3 file for ID {project_id}: {e}", exc_info=True)
2157
  return jsonify({"error": "Failed to retrieve Scratch project file"}), 500
2158
 
 
2159
  @app.route('/process_pdf', methods=['POST'])
2160
  def process_pdf():
2161
+ project_id = None
2162
  project_folder = None
2163
+ temp_dir = None # Initialize temp_dir for finally block
2164
  try:
2165
  logger.info("Received request to process PDF.")
2166
  if 'pdf_file' not in request.files:
 
2171
  if pdf_file.filename == '':
2172
  return jsonify({"error": "Empty filename"}), 400
2173
 
 
 
 
2174
  project_id = str(uuid.uuid4()).replace('-', '')
2175
+ project_folder = OUTPUT_DIR / project_id
2176
 
 
 
 
 
2177
  project_folder.mkdir(parents=True, exist_ok=True)
2178
  logger.info(f"Created project folder: {project_folder}")
2179
 
 
2180
  filename = secure_filename(pdf_file.filename)
2181
+ temp_dir = Path(tempfile.mkdtemp())
2182
  saved_pdf_path = temp_dir / filename
2183
  pdf_file.save(saved_pdf_path)
2184
 
2185
  logger.info(f"Saved uploaded PDF to: {saved_pdf_path}")
2186
 
2187
+ json_path = None
 
 
2188
  extracted_output_dir, result = extract_images_from_pdf(saved_pdf_path, json_path)
2189
 
2190
+ # Ensure extracted_output_dir is a Path object for the '/' operator
2191
+ # This was the source of the TypeError
2192
+ if not isinstance(extracted_output_dir, Path):
2193
+ extracted_output_dir = Path(extracted_output_dir)
 
 
 
 
 
 
 
 
2194
 
2195
+ extracted_sprites_json_path = extracted_output_dir / "extracted_sprites.json"
2196
 
2197
  if not extracted_sprites_json_path.exists():
2198
  logger.error(f"No extracted_sprites.json found at {extracted_sprites_json_path}")
 
2201
  with open(extracted_sprites_json_path, 'r') as f:
2202
  sprite_data = json.load(f)
2203
 
 
2204
  project_output = similarity_matching(extracted_output_dir, project_folder)
2205
+ logger.info("Similarity matching completed.")
2206
 
2207
  with open(project_output, 'r') as f:
2208
  project_skeleton = json.load(f)
2209
 
2210
  images = convert_from_path(saved_pdf_path, dpi=300)
 
2211
  page = images[0]
2212
  buf = BytesIO()
2213
  page.save(buf, format="PNG")
2214
  img_bytes = buf.getvalue()
2215
  img_b64 = base64.b64encode(img_bytes).decode("utf-8")
2216
 
2217
+ initial_state_dict = {
2218
+ "project_json": project_skeleton,
2219
+ "description": "The pseudo code for the script",
2220
+ "project_id": project_id,
2221
+ "project_image": img_b64,
2222
+ "action_plan": {},
2223
+ "pseudo_code": {},
2224
+ "temporary_node": {},
2225
+ }
2226
 
2227
+ final_state_dict = app_graph.invoke(initial_state_dict)
2228
 
2229
+ final_project_json = final_state_dict['project_json']
2230
 
 
2231
  with open(project_output, "w") as f:
2232
  json.dump(final_project_json, f, indent=2)
2233
  logger.info(f"Final project JSON saved to {project_output}")
2234
 
 
2235
  sb3_file_path = create_sb3_archive(project_folder, project_id)
2236
  if sb3_file_path:
2237
  logger.info(f"Successfully created SB3 file: {sb3_file_path}")
2238
+ download_url = f"/download_sb3/{project_id}"
2239
  print(f"DOWNLOAD_URL: {download_url}")
2240
  return jsonify({"message": "Processed PDF and Game sb3 generated successfully", "project_id": project_id, "download_url": download_url})
2241
  else:
 
2245
  logger.error(f"Error during processing the pdf workflow for project ID {project_id}: {e}", exc_info=True)
2246
  return jsonify({"error": f"❌ Failed to process PDF: {str(e)}"}), 500
2247
  finally:
2248
+ if temp_dir and temp_dir.exists():
 
2249
  shutil.rmtree(temp_dir)
2250
  logger.info(f"Cleaned up temporary directory: {temp_dir}")
 
 
 
 
 
2251
 
2252
  @app.route('/list_projects', methods=['GET'])
2253
  def list_projects():