multimodalsim-viewer 0.1.2.0__tar.gz → 0.1.4.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (64) hide show
  1. {multimodalsim_viewer-0.1.2.0 → multimodalsim_viewer-0.1.4.0}/PKG-INFO +1 -1
  2. {multimodalsim_viewer-0.1.2.0 → multimodalsim_viewer-0.1.4.0}/multimodalsim_viewer/common/utils.py +1 -10
  3. {multimodalsim_viewer-0.1.2.0 → multimodalsim_viewer-0.1.4.0}/multimodalsim_viewer/server/data_manager.py +0 -28
  4. multimodalsim_viewer-0.1.4.0/multimodalsim_viewer/server/http_routes.py +156 -0
  5. {multimodalsim_viewer-0.1.2.0 → multimodalsim_viewer-0.1.4.0}/multimodalsim_viewer/server/scripts.py +1 -5
  6. {multimodalsim_viewer-0.1.2.0 → multimodalsim_viewer-0.1.4.0}/multimodalsim_viewer/server/server.py +8 -12
  7. multimodalsim_viewer-0.1.4.0/multimodalsim_viewer/server/simulation_manager.py +781 -0
  8. multimodalsim_viewer-0.1.4.0/multimodalsim_viewer/ui/static/chunk-IILFIRWZ.js +7 -0
  9. multimodalsim_viewer-0.1.2.0/multimodalsim_viewer/ui/static/chunk-RHGMGEGM.js → multimodalsim_viewer-0.1.4.0/multimodalsim_viewer/ui/static/chunk-L2ZL6Q4W.js +1 -1
  10. {multimodalsim_viewer-0.1.2.0 → multimodalsim_viewer-0.1.4.0}/multimodalsim_viewer/ui/static/index.html +2 -2
  11. multimodalsim_viewer-0.1.2.0/multimodalsim_viewer/ui/static/main-APJ3N7UX.js → multimodalsim_viewer-0.1.4.0/multimodalsim_viewer/ui/static/main-XYH7FCFC.js +172 -171
  12. multimodalsim_viewer-0.1.4.0/multimodalsim_viewer/ui/static/styles-2KWGWV5P.css +1 -0
  13. {multimodalsim_viewer-0.1.2.0 → multimodalsim_viewer-0.1.4.0}/multimodalsim_viewer.egg-info/PKG-INFO +1 -1
  14. {multimodalsim_viewer-0.1.2.0 → multimodalsim_viewer-0.1.4.0}/multimodalsim_viewer.egg-info/SOURCES.txt +4 -4
  15. multimodalsim_viewer-0.1.2.0/multimodalsim_viewer/server/http_routes.py +0 -132
  16. multimodalsim_viewer-0.1.2.0/multimodalsim_viewer/server/simulation_manager.py +0 -569
  17. multimodalsim_viewer-0.1.2.0/multimodalsim_viewer/ui/static/chunk-BQ2VC5TN.js +0 -7
  18. multimodalsim_viewer-0.1.2.0/multimodalsim_viewer/ui/static/styles-257KETL3.css +0 -1
  19. {multimodalsim_viewer-0.1.2.0 → multimodalsim_viewer-0.1.4.0}/MANIFEST.in +0 -0
  20. {multimodalsim_viewer-0.1.2.0 → multimodalsim_viewer-0.1.4.0}/README.md +0 -0
  21. {multimodalsim_viewer-0.1.2.0 → multimodalsim_viewer-0.1.4.0}/multimodalsim_viewer/__init__.py +0 -0
  22. {multimodalsim_viewer-0.1.2.0 → multimodalsim_viewer-0.1.4.0}/multimodalsim_viewer/common/__init__.py +0 -0
  23. {multimodalsim_viewer-0.1.2.0 → multimodalsim_viewer-0.1.4.0}/multimodalsim_viewer/common/environments/.env +0 -0
  24. {multimodalsim_viewer-0.1.2.0 → multimodalsim_viewer-0.1.4.0}/multimodalsim_viewer/models/__init__.py +0 -0
  25. {multimodalsim_viewer-0.1.2.0 → multimodalsim_viewer-0.1.4.0}/multimodalsim_viewer/models/environment.py +0 -0
  26. {multimodalsim_viewer-0.1.2.0 → multimodalsim_viewer-0.1.4.0}/multimodalsim_viewer/models/leg.py +0 -0
  27. {multimodalsim_viewer-0.1.2.0 → multimodalsim_viewer-0.1.4.0}/multimodalsim_viewer/models/passenger.py +0 -0
  28. {multimodalsim_viewer-0.1.2.0 → multimodalsim_viewer-0.1.4.0}/multimodalsim_viewer/models/serializable.py +0 -0
  29. {multimodalsim_viewer-0.1.2.0 → multimodalsim_viewer-0.1.4.0}/multimodalsim_viewer/models/simulation_information.py +0 -0
  30. {multimodalsim_viewer-0.1.2.0 → multimodalsim_viewer-0.1.4.0}/multimodalsim_viewer/models/state.py +0 -0
  31. {multimodalsim_viewer-0.1.2.0 → multimodalsim_viewer-0.1.4.0}/multimodalsim_viewer/models/stop.py +0 -0
  32. {multimodalsim_viewer-0.1.2.0 → multimodalsim_viewer-0.1.4.0}/multimodalsim_viewer/models/update.py +0 -0
  33. {multimodalsim_viewer-0.1.2.0 → multimodalsim_viewer-0.1.4.0}/multimodalsim_viewer/models/vehicle.py +0 -0
  34. {multimodalsim_viewer-0.1.2.0 → multimodalsim_viewer-0.1.4.0}/multimodalsim_viewer/server/__init__.py +0 -0
  35. {multimodalsim_viewer-0.1.2.0 → multimodalsim_viewer-0.1.4.0}/multimodalsim_viewer/server/data_collector.py +0 -0
  36. {multimodalsim_viewer-0.1.2.0 → multimodalsim_viewer-0.1.4.0}/multimodalsim_viewer/server/log_manager.py +0 -0
  37. {multimodalsim_viewer-0.1.2.0 → multimodalsim_viewer-0.1.4.0}/multimodalsim_viewer/server/simulation.py +0 -0
  38. {multimodalsim_viewer-0.1.2.0 → multimodalsim_viewer-0.1.4.0}/multimodalsim_viewer/ui/__init__.py +0 -0
  39. {multimodalsim_viewer-0.1.2.0 → multimodalsim_viewer-0.1.4.0}/multimodalsim_viewer/ui/angular_app.py +0 -0
  40. {multimodalsim_viewer-0.1.2.0 → multimodalsim_viewer-0.1.4.0}/multimodalsim_viewer/ui/static/bitmap-fonts/custom-sans-serif.png +0 -0
  41. {multimodalsim_viewer-0.1.2.0 → multimodalsim_viewer-0.1.4.0}/multimodalsim_viewer/ui/static/bitmap-fonts/custom-sans-serif.xml +0 -0
  42. {multimodalsim_viewer-0.1.2.0 → multimodalsim_viewer-0.1.4.0}/multimodalsim_viewer/ui/static/environment.json +0 -0
  43. {multimodalsim_viewer-0.1.2.0 → multimodalsim_viewer-0.1.4.0}/multimodalsim_viewer/ui/static/favicon.ico +0 -0
  44. {multimodalsim_viewer-0.1.2.0 → multimodalsim_viewer-0.1.4.0}/multimodalsim_viewer/ui/static/images/control-bar.png +0 -0
  45. {multimodalsim_viewer-0.1.2.0 → multimodalsim_viewer-0.1.4.0}/multimodalsim_viewer/ui/static/images/passenger.png +0 -0
  46. {multimodalsim_viewer-0.1.2.0 → multimodalsim_viewer-0.1.4.0}/multimodalsim_viewer/ui/static/images/simulation-control-bar.png +0 -0
  47. {multimodalsim_viewer-0.1.2.0 → multimodalsim_viewer-0.1.4.0}/multimodalsim_viewer/ui/static/images/stop.png +0 -0
  48. {multimodalsim_viewer-0.1.2.0 → multimodalsim_viewer-0.1.4.0}/multimodalsim_viewer/ui/static/images/undefined-texture.png +0 -0
  49. {multimodalsim_viewer-0.1.2.0 → multimodalsim_viewer-0.1.4.0}/multimodalsim_viewer/ui/static/images/vehicle.png +0 -0
  50. {multimodalsim_viewer-0.1.2.0 → multimodalsim_viewer-0.1.4.0}/multimodalsim_viewer/ui/static/images/zoomed-out-passenger.png +0 -0
  51. {multimodalsim_viewer-0.1.2.0 → multimodalsim_viewer-0.1.4.0}/multimodalsim_viewer/ui/static/images/zoomed-out-stop.png +0 -0
  52. {multimodalsim_viewer-0.1.2.0 → multimodalsim_viewer-0.1.4.0}/multimodalsim_viewer/ui/static/images/zoomed-out-vehicle.png +0 -0
  53. {multimodalsim_viewer-0.1.2.0 → multimodalsim_viewer-0.1.4.0}/multimodalsim_viewer/ui/static/media/layers-2x-TBM42ERR.png +0 -0
  54. {multimodalsim_viewer-0.1.2.0 → multimodalsim_viewer-0.1.4.0}/multimodalsim_viewer/ui/static/media/layers-55W3Q4RM.png +0 -0
  55. {multimodalsim_viewer-0.1.2.0 → multimodalsim_viewer-0.1.4.0}/multimodalsim_viewer/ui/static/media/marker-icon-2V3QKKVC.png +0 -0
  56. {multimodalsim_viewer-0.1.2.0 → multimodalsim_viewer-0.1.4.0}/multimodalsim_viewer/ui/static/polyfills-FFHMD2TL.js +0 -0
  57. {multimodalsim_viewer-0.1.2.0 → multimodalsim_viewer-0.1.4.0}/multimodalsim_viewer/ui/static/scripts/load-environment.script.js +0 -0
  58. {multimodalsim_viewer-0.1.2.0 → multimodalsim_viewer-0.1.4.0}/multimodalsim_viewer.egg-info/dependency_links.txt +0 -0
  59. {multimodalsim_viewer-0.1.2.0 → multimodalsim_viewer-0.1.4.0}/multimodalsim_viewer.egg-info/entry_points.txt +0 -0
  60. {multimodalsim_viewer-0.1.2.0 → multimodalsim_viewer-0.1.4.0}/multimodalsim_viewer.egg-info/requires.txt +0 -0
  61. {multimodalsim_viewer-0.1.2.0 → multimodalsim_viewer-0.1.4.0}/multimodalsim_viewer.egg-info/top_level.txt +0 -0
  62. {multimodalsim_viewer-0.1.2.0 → multimodalsim_viewer-0.1.4.0}/pyproject.toml +0 -0
  63. {multimodalsim_viewer-0.1.2.0 → multimodalsim_viewer-0.1.4.0}/setup.cfg +0 -0
  64. {multimodalsim_viewer-0.1.2.0 → multimodalsim_viewer-0.1.4.0}/setup.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: multimodalsim_viewer
3
- Version: 0.1.2.0
3
+ Version: 0.1.4.0
4
4
  Summary: Multimodal simulation viewer
5
5
  Keywords: flask angular ui multimodal server
6
6
  Requires-Python: >=3.10
@@ -9,7 +9,6 @@ from json import dumps
9
9
  from dotenv import dotenv_values
10
10
  from filelock import FileLock
11
11
  from flask import request
12
- from flask_socketio import emit
13
12
 
14
13
  environment = {}
15
14
 
@@ -147,19 +146,11 @@ def build_simulation_id(name: str) -> tuple[str, str]:
147
146
  return simulation_id, start_time
148
147
 
149
148
 
150
- def log(message: str, auth_type: str, level=logging.INFO, should_emit=True) -> None:
149
+ def log(message: str, auth_type: str, level=logging.INFO) -> None:
151
150
  if auth_type == "server":
152
151
  logging.log(level, "[%s] %s", auth_type, message)
153
- if should_emit:
154
- emit("log", f"{level} [{auth_type}] {message}", to=CLIENT_ROOM)
155
152
  else:
156
153
  logging.log(level, "[%s] %s %s", auth_type, get_session_id(), message)
157
- if should_emit:
158
- emit(
159
- "log",
160
- f"{level} [{auth_type}] {get_session_id()} {message}",
161
- to=CLIENT_ROOM,
162
- )
163
154
 
164
155
 
165
156
  def verify_simulation_name(name: str | None) -> str | None:
@@ -499,34 +499,6 @@ class SimulationVisualizationDataManager: # pylint: disable=too-many-public-met
499
499
 
500
500
  return polylines, version
501
501
 
502
- @staticmethod
503
- def get_all_simulation_states(simulation_id: str) -> tuple[list[str], dict[list[str]]]:
504
- states = []
505
- updates = {}
506
-
507
- sorted_states = SimulationVisualizationDataManager.get_sorted_states(simulation_id)
508
-
509
- for update_index, timestamp in sorted_states:
510
- file_path = SimulationVisualizationDataManager.get_saved_simulation_state_file_path(
511
- simulation_id, update_index, timestamp
512
- )
513
-
514
- lock = FileLock(f"{file_path}.lock")
515
-
516
- with lock:
517
- with open(file_path, "r", encoding="utf-8") as file:
518
- state_data = file.readline()
519
- states.append(state_data)
520
-
521
- updates_data = file.readlines()
522
- current_state_updates = []
523
- for update_data in updates_data:
524
- current_state_updates.append(update_data)
525
-
526
- updates[update_index] = current_state_updates
527
-
528
- return states, updates
529
-
530
502
  # MARK: +- Simulation Data
531
503
  @staticmethod
532
504
  def get_output_data_directory_path() -> str:
@@ -0,0 +1,156 @@
1
+ import logging
2
+ import os
3
+ import shutil
4
+ import tempfile
5
+ import zipfile
6
+ from typing import Callable
7
+
8
+ from flask import Blueprint, jsonify, request, send_file
9
+
10
+ from multimodalsim_viewer.server.data_manager import SimulationVisualizationDataManager
11
+ from multimodalsim_viewer.server.simulation_manager import SimulationManager
12
+
13
+
14
+ class InvalidFilesRequestError(Exception):
15
+ def __init__(self, error_message: str) -> None:
16
+ self.error_message = error_message
17
+
18
+
19
+ def http_routes(simulation_manager: SimulationManager): # pylint: disable=too-many-statements
20
+ blueprint = Blueprint("http_routes", __name__)
21
+
22
+ # MARK: Helpers
23
+ def get_unique_folder_name(base_path, folder_name):
24
+ counter = 1
25
+ original_name = folder_name
26
+ while os.path.exists(os.path.join(base_path, folder_name)):
27
+ folder_name = f"{original_name}_({counter})"
28
+ counter += 1
29
+ return folder_name
30
+
31
+ def zip_folder(folder_path, zip_name):
32
+ if not os.path.isdir(folder_path):
33
+ return None
34
+
35
+ zip_path = os.path.join(tempfile.gettempdir(), f"{zip_name}.zip")
36
+ with zipfile.ZipFile(zip_path, "w", zipfile.ZIP_DEFLATED) as zip_file:
37
+ for root, _, files in os.walk(folder_path):
38
+ for file in files:
39
+ file_path = os.path.join(root, file)
40
+ zip_file.write(file_path, os.path.relpath(file_path, folder_path))
41
+
42
+ return zip_path
43
+
44
+ def save_and_extract_zip(path: str, files):
45
+ try:
46
+ if "file" not in files:
47
+ raise InvalidFilesRequestError("No file part")
48
+
49
+ file = files["file"]
50
+ if file.filename == "":
51
+ raise InvalidFilesRequestError("No selected file")
52
+
53
+ # Create temporary zip file
54
+ zip_path = os.path.join(tempfile.gettempdir(), file.filename)
55
+ file.save(zip_path)
56
+
57
+ # Extract files
58
+ with zipfile.ZipFile(zip_path, "r") as zip_ref:
59
+ zip_ref.extractall(path)
60
+ logging.info("Extracted files: %s", zip_ref.namelist())
61
+
62
+ # Let the exception propagate
63
+ finally:
64
+ # Remove temporary zip file
65
+ if os.path.exists(zip_path):
66
+ os.remove(zip_path)
67
+
68
+ def handle_zip_upload(folder_path, on_success: Callable | None = None):
69
+ parent_dir = os.path.dirname(folder_path)
70
+ base_folder_name = os.path.basename(folder_path)
71
+
72
+ unique_folder_name = get_unique_folder_name(parent_dir, base_folder_name)
73
+ actual_folder_path = os.path.join(parent_dir, unique_folder_name)
74
+
75
+ os.makedirs(actual_folder_path, exist_ok=True)
76
+
77
+ try:
78
+ save_and_extract_zip(actual_folder_path, request.files)
79
+ except InvalidFilesRequestError as error:
80
+ return jsonify({"error": error.error_message}), 400
81
+ except zipfile.BadZipFile:
82
+ return jsonify({"error": "Invalid ZIP file"}), 400
83
+
84
+ response_message = f"Folder '{unique_folder_name}' uploaded successfully"
85
+ if unique_folder_name != base_folder_name:
86
+ response_message += f" (renamed from '{base_folder_name}')"
87
+
88
+ if on_success:
89
+ on_success()
90
+
91
+ return (
92
+ jsonify({"message": response_message, "folderName": unique_folder_name}),
93
+ 201,
94
+ )
95
+
96
+ # MARK: Instances
97
+ @blueprint.route("/api/input_data/<folder_name>", methods=["GET"])
98
+ def export_input_data(folder_name):
99
+ folder_path = SimulationVisualizationDataManager.get_input_data_directory_path(folder_name)
100
+ logging.info("Requested folder: %s", folder_path)
101
+
102
+ zip_path = zip_folder(folder_path, folder_name)
103
+ if not zip_path:
104
+ return jsonify({"error": "Folder not found"}), 404
105
+
106
+ return send_file(zip_path, as_attachment=True)
107
+
108
+ @blueprint.route("/api/input_data/<folder_name>", methods=["POST"])
109
+ def import_input_data(folder_name):
110
+ folder_path = SimulationVisualizationDataManager.get_input_data_directory_path(folder_name)
111
+ return handle_zip_upload(folder_path)
112
+
113
+ @blueprint.route("/api/input_data/<folder_name>", methods=["DELETE"])
114
+ def delete_input_data(folder_name):
115
+ folder_path = SimulationVisualizationDataManager.get_input_data_directory_path(folder_name)
116
+ if not os.path.isdir(folder_path):
117
+ return jsonify({"error": "Folder not found"}), 404
118
+
119
+ shutil.rmtree(folder_path)
120
+ return jsonify({"message": f"Folder '{folder_name}' deleted successfully"})
121
+
122
+ # MARK: Visualizations
123
+ @blueprint.route("/api/simulation/<folder_name>", methods=["GET"])
124
+ def export_saved_simulation(folder_name):
125
+ folder_path = SimulationVisualizationDataManager.get_saved_simulation_directory_path(folder_name)
126
+ logging.info("Requested folder: %s", folder_path)
127
+
128
+ zip_path = zip_folder(folder_path, folder_name)
129
+ if not zip_path:
130
+ return jsonify({"error": "Folder not found"}), 404
131
+
132
+ return send_file(zip_path, as_attachment=True)
133
+
134
+ @blueprint.route("/api/simulation/<folder_name>", methods=["POST"])
135
+ def import_saved_simulation(folder_name):
136
+ folder_path = SimulationVisualizationDataManager.get_saved_simulation_directory_path(folder_name)
137
+
138
+ def on_success():
139
+ simulation_manager.emit_simulation(folder_name)
140
+
141
+ return handle_zip_upload(folder_path, on_success)
142
+
143
+ @blueprint.route("/api/simulation/<folder_name>", methods=["DELETE"])
144
+ def delete_saved_simulation(folder_name):
145
+ folder_path = SimulationVisualizationDataManager.get_saved_simulation_directory_path(folder_name)
146
+
147
+ if not os.path.isdir(folder_path):
148
+ return jsonify({"error": "Folder not found"}), 404
149
+
150
+ shutil.rmtree(folder_path)
151
+
152
+ simulation_manager.on_simulation_delete(folder_name)
153
+
154
+ return jsonify({"message": f"Folder '{folder_name}' deleted successfully"})
155
+
156
+ return blueprint
@@ -7,11 +7,7 @@ from requests.exceptions import ConnectionError as RequestsConnectionError
7
7
  from socketio import Client
8
8
  from socketio.exceptions import ConnectionError as SocketIOConnectionError
9
9
 
10
- from multimodalsim_viewer.common.utils import (
11
- CLIENT_PORT,
12
- HOST,
13
- SERVER_PORT,
14
- )
10
+ from multimodalsim_viewer.common.utils import CLIENT_PORT, HOST, SERVER_PORT
15
11
  from multimodalsim_viewer.server.server import configure_server
16
12
  from multimodalsim_viewer.server.simulation import (
17
13
  configure_simulation_parser,
@@ -14,17 +14,17 @@ from multimodalsim_viewer.server.simulation_manager import SimulationManager
14
14
  def configure_server() -> tuple[Flask, SocketIO]: # pylint: disable=too-many-statements, too-many-locals
15
15
  app = Flask(__name__)
16
16
 
17
+ socketio = SocketIO(app, cors_allowed_origins="*")
18
+
19
+ simulation_manager = SimulationManager(socketio)
20
+
17
21
  # Register HTTP routes
18
22
  CORS(app)
19
- app.register_blueprint(http_routes)
20
-
21
- socketio = SocketIO(app, cors_allowed_origins="*")
23
+ app.register_blueprint(http_routes(simulation_manager))
22
24
 
23
25
  # key = session id, value = auth type
24
26
  sockets_types_by_session_id = {}
25
27
 
26
- simulation_manager = SimulationManager()
27
-
28
28
  # MARK: Main events
29
29
  @socketio.on("connect")
30
30
  def on_connect(auth):
@@ -69,9 +69,9 @@ def configure_server() -> tuple[Flask, SocketIO]: # pylint: disable=too-many-st
69
69
  simulation_manager.resume_simulation(simulation_id)
70
70
 
71
71
  @socketio.on("get-simulations")
72
- def on_client_get_simulations():
73
- log("getting simulations", "client")
74
- simulation_manager.emit_simulations()
72
+ def on_client_get_simulations(loaded_simulations_ids: list[str]):
73
+ log(f"getting simulations with already loaded ids {loaded_simulations_ids}", "client")
74
+ simulation_manager.emit_simulations(loaded_simulations_ids)
75
75
 
76
76
  @socketio.on("get-available-data")
77
77
  def on_client_get_data():
@@ -136,10 +136,6 @@ def configure_server() -> tuple[Flask, SocketIO]: # pylint: disable=too-many-st
136
136
  log(f"simulation {simulation_id} resumed", "simulation")
137
137
  simulation_manager.on_simulation_resume(simulation_id)
138
138
 
139
- @socketio.on("log")
140
- def on_simulation_log(simulation_id, message):
141
- log(f"simulation {simulation_id}: {message}", "simulation", logging.DEBUG)
142
-
143
139
  @socketio.on("simulation-update-time")
144
140
  def on_simulation_update_time(simulation_id, timestamp):
145
141
  log(