slm_open_api_package 0.2.12__tar.gz → 0.2.14__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.
- {slm_open_api_package-0.2.12 → slm_open_api_package-0.2.14}/PKG-INFO +5 -1
- {slm_open_api_package-0.2.12 → slm_open_api_package-0.2.14}/README.md +4 -0
- {slm_open_api_package-0.2.12 → slm_open_api_package-0.2.14}/pyproject.toml +1 -1
- {slm_open_api_package-0.2.12 → slm_open_api_package-0.2.14}/pyproject.toml.orig +1 -1
- {slm_open_api_package-0.2.12 → slm_open_api_package-0.2.14}/src/slm_api/fast_log_example.py +3 -3
- {slm_open_api_package-0.2.12 → slm_open_api_package-0.2.14}/src/slm_api/helpers/data_handler.py +22 -2
- {slm_open_api_package-0.2.12 → slm_open_api_package-0.2.14}/src/slm_api/helpers/stream_handlers.py +31 -4
- {slm_open_api_package-0.2.12 → slm_open_api_package-0.2.14}/src/slm_api/CPB_example.py +0 -0
- {slm_open_api_package-0.2.12 → slm_open_api_package-0.2.14}/src/slm_api/__init__.py +0 -0
- {slm_open_api_package-0.2.12 → slm_open_api_package-0.2.14}/src/slm_api/enums/fast_log_intervals_enum.py +0 -0
- {slm_open_api_package-0.2.12 → slm_open_api_package-0.2.14}/src/slm_api/enums/sequence_id_enum.py +0 -0
- {slm_open_api_package-0.2.12 → slm_open_api_package-0.2.14}/src/slm_api/example_multi.py +0 -0
- {slm_open_api_package-0.2.12 → slm_open_api_package-0.2.14}/src/slm_api/flac_example.py +0 -0
- {slm_open_api_package-0.2.12 → slm_open_api_package-0.2.14}/src/slm_api/helpers/FigureHandler.py +0 -0
- {slm_open_api_package-0.2.12 → slm_open_api_package-0.2.14}/src/slm_api/helpers/Leq.py +0 -0
- {slm_open_api_package-0.2.12 → slm_open_api_package-0.2.14}/src/slm_api/helpers/__init__.py +0 -0
- {slm_open_api_package-0.2.12 → slm_open_api_package-0.2.14}/src/slm_api/helpers/buffer.py +0 -0
- {slm_open_api_package-0.2.12 → slm_open_api_package-0.2.14}/src/slm_api/helpers/fft.py +0 -0
- {slm_open_api_package-0.2.12 → slm_open_api_package-0.2.14}/src/slm_api/helpers/flac_stream_2_samples.py +0 -0
- {slm_open_api_package-0.2.12 → slm_open_api_package-0.2.14}/src/slm_api/helpers/https_requests.py +0 -0
- {slm_open_api_package-0.2.12 → slm_open_api_package-0.2.14}/src/slm_api/helpers/measurment_handler.py +0 -0
- {slm_open_api_package-0.2.12 → slm_open_api_package-0.2.14}/src/slm_api/helpers/sequence_handler.py +0 -0
- {slm_open_api_package-0.2.12 → slm_open_api_package-0.2.14}/src/slm_api/helpers/stream_handler.py +0 -0
- {slm_open_api_package-0.2.12 → slm_open_api_package-0.2.14}/src/slm_api/helpers/tmpFileStateMachine.py +0 -0
- {slm_open_api_package-0.2.12 → slm_open_api_package-0.2.14}/src/slm_api/helpers/websocket_handler.py +0 -0
- {slm_open_api_package-0.2.12 → slm_open_api_package-0.2.14}/src/slm_api/helpers/webxi_helper_functions.py +0 -0
- {slm_open_api_package-0.2.12 → slm_open_api_package-0.2.14}/src/slm_api/helpers/webxi_root.pem +0 -0
- {slm_open_api_package-0.2.12 → slm_open_api_package-0.2.14}/src/slm_api/leq.py +0 -0
- {slm_open_api_package-0.2.12 → slm_open_api_package-0.2.14}/src/slm_api/mp3_example.py +0 -0
- {slm_open_api_package-0.2.12 → slm_open_api_package-0.2.14}/src/slm_api/multi_device_flac.py +0 -0
- {slm_open_api_package-0.2.12 → slm_open_api_package-0.2.14}/src/slm_api/multi_instrument_example.py +0 -0
- {slm_open_api_package-0.2.12 → slm_open_api_package-0.2.14}/src/slm_api/plot_saved_data_example.py +0 -0
- {slm_open_api_package-0.2.12 → slm_open_api_package-0.2.14}/src/slm_api/screen_record_example.py +0 -0
- {slm_open_api_package-0.2.12 → slm_open_api_package-0.2.14}/src/slm_api/webxi/README.md +0 -0
- {slm_open_api_package-0.2.12 → slm_open_api_package-0.2.14}/src/slm_api/webxi/__init__.py +0 -0
- {slm_open_api_package-0.2.12 → slm_open_api_package-0.2.14}/src/slm_api/webxi/webxi-header.ksy +0 -0
- {slm_open_api_package-0.2.12 → slm_open_api_package-0.2.14}/src/slm_api/webxi/webxi-stream.ksy +0 -0
- {slm_open_api_package-0.2.12 → slm_open_api_package-0.2.14}/src/slm_api/webxi/webxi_header.py +0 -0
- {slm_open_api_package-0.2.12 → slm_open_api_package-0.2.14}/src/slm_api/webxi/webxi_stream.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: slm_open_api_package
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.14
|
|
4
4
|
Summary: Add your description here
|
|
5
5
|
Author: Sofus Vingaard
|
|
6
6
|
Author-email: Sofus Vingaard <sofus.krebsvingaard@hbkworld.com>
|
|
@@ -82,6 +82,8 @@ except KeyboardInterrupt:
|
|
|
82
82
|
|
|
83
83
|
JSON and CSV publish complete snapshots in a background worker, at most once per second while new data arrives, rather than rewriting the file for every sample. They retain records in memory and preserve their existing layouts; full-history snapshot costs still grow with recording length. Construct `JsonDataHandler(path, snapshot_interval=2.0)` or `CsvDataHandler(path, snapshot_interval=2.0)` and attach it with `setDataHandler()` to use a different interval. `close()` waits for the worker and saves all remaining records; background write failures are reported on subsequent updates or during the final flush. WAV still appends each audio chunk without buffering the recording in memory. `stopStream()` stops the measurement, closes saving handlers, and removes the device stream. Measurement saving formats are `"csv"` and `"json"`; audio uses `"wav"`. File extensions are added automatically.
|
|
84
84
|
|
|
85
|
+
If snapshot replacement raises `PermissionError` (for example, Windows prevents replacing a CSV open in Excel), the worker warns once per failure episode, continues buffering records, and retries at the next snapshot interval. Close the program holding the output file open, or correct its permissions, to allow saving to resume. A lock still present at `close()` raises an error; unsaved records only remain in memory while the process is alive. Other write failures remain fatal to snapshot saving. `stopStream()` still attempts device cleanup if closing the saving handler fails.
|
|
86
|
+
|
|
85
87
|
## Multiple Sequences
|
|
86
88
|
|
|
87
89
|
Based on [example_multi.py](src/slm_api/example_multi.py), use `mode="multi"` for several enabled broadband sequences in a single stream:
|
|
@@ -161,6 +163,8 @@ except KeyboardInterrupt:
|
|
|
161
163
|
|
|
162
164
|
The matching `flac` form uses `SequenceIdEnums.FLACSignal.value` and `mode="flac"`. Audio setup is enabled by the handler. The SLM can take a few seconds to initialize audio recording when its quality setting changes.
|
|
163
165
|
|
|
166
|
+
For GUI plots, check the read-only `streamer.audio_ready` property in the plot's timer callback before reading `DataBuffer`. It becomes `True` after the first nonempty decoded audio has been written to the buffer, without requiring a custom `DataHandler` or event. It resets when the streaming session starts, when a stop is requested, and when the session exits. This is a startup gate, not a full-window availability check or a detector for stalled streams. Keep running the GUI event loop while waiting for audio.
|
|
167
|
+
|
|
164
168
|
WAV saving appends decoded mono samples as recording happens, updating the file header after each chunk so the file is readable before shutdown. Saving happens after decoding and calibration to pascals. Samples are divided by the fixed full-scale pressure `calibrationFactor * (2**23 - 1)` and saved as `PCM_24`, not peak-normalized per chunk. The filename includes `_fullscale-<value>Pa.wav`. To recover pressure values, multiply floating-point samples read from the WAV by that full-scale value (within 24-bit quantization accuracy). Samples outside the calibrated range produce a clipping warning; this scaling cannot repair upstream clipping. MP3 uses the decoded sample rate; the current FLAC decoder uses 65536 Hz. JSON and CSV saving are rejected for audio modes, and WAV saving is rejected for measurement modes. Run `uv sync` to install the `soundfile` dependency used for progressive WAV writing.
|
|
165
169
|
|
|
166
170
|
To attach the handler directly, use `WavDataHandler("saved_data/audio", sample_rate=65536, full_scale_pa=calibrationFactor * (2**23 - 1))` from `slm_api.helpers.data_handler`, using the device's actual calibration factor. You can instead supply `sample_rate` and `full_scale_pa` to `handle()`; the stream supplies both automatically. Call `close()` when finished. Use a separate WAV handler and output path for each device. Existing float32 pressure WAVs are unchanged; this format applies to new recordings.
|
|
@@ -60,6 +60,8 @@ except KeyboardInterrupt:
|
|
|
60
60
|
|
|
61
61
|
JSON and CSV publish complete snapshots in a background worker, at most once per second while new data arrives, rather than rewriting the file for every sample. They retain records in memory and preserve their existing layouts; full-history snapshot costs still grow with recording length. Construct `JsonDataHandler(path, snapshot_interval=2.0)` or `CsvDataHandler(path, snapshot_interval=2.0)` and attach it with `setDataHandler()` to use a different interval. `close()` waits for the worker and saves all remaining records; background write failures are reported on subsequent updates or during the final flush. WAV still appends each audio chunk without buffering the recording in memory. `stopStream()` stops the measurement, closes saving handlers, and removes the device stream. Measurement saving formats are `"csv"` and `"json"`; audio uses `"wav"`. File extensions are added automatically.
|
|
62
62
|
|
|
63
|
+
If snapshot replacement raises `PermissionError` (for example, Windows prevents replacing a CSV open in Excel), the worker warns once per failure episode, continues buffering records, and retries at the next snapshot interval. Close the program holding the output file open, or correct its permissions, to allow saving to resume. A lock still present at `close()` raises an error; unsaved records only remain in memory while the process is alive. Other write failures remain fatal to snapshot saving. `stopStream()` still attempts device cleanup if closing the saving handler fails.
|
|
64
|
+
|
|
63
65
|
## Multiple Sequences
|
|
64
66
|
|
|
65
67
|
Based on [example_multi.py](src/slm_api/example_multi.py), use `mode="multi"` for several enabled broadband sequences in a single stream:
|
|
@@ -139,6 +141,8 @@ except KeyboardInterrupt:
|
|
|
139
141
|
|
|
140
142
|
The matching `flac` form uses `SequenceIdEnums.FLACSignal.value` and `mode="flac"`. Audio setup is enabled by the handler. The SLM can take a few seconds to initialize audio recording when its quality setting changes.
|
|
141
143
|
|
|
144
|
+
For GUI plots, check the read-only `streamer.audio_ready` property in the plot's timer callback before reading `DataBuffer`. It becomes `True` after the first nonempty decoded audio has been written to the buffer, without requiring a custom `DataHandler` or event. It resets when the streaming session starts, when a stop is requested, and when the session exits. This is a startup gate, not a full-window availability check or a detector for stalled streams. Keep running the GUI event loop while waiting for audio.
|
|
145
|
+
|
|
142
146
|
WAV saving appends decoded mono samples as recording happens, updating the file header after each chunk so the file is readable before shutdown. Saving happens after decoding and calibration to pascals. Samples are divided by the fixed full-scale pressure `calibrationFactor * (2**23 - 1)` and saved as `PCM_24`, not peak-normalized per chunk. The filename includes `_fullscale-<value>Pa.wav`. To recover pressure values, multiply floating-point samples read from the WAV by that full-scale value (within 24-bit quantization accuracy). Samples outside the calibrated range produce a clipping warning; this scaling cannot repair upstream clipping. MP3 uses the decoded sample rate; the current FLAC decoder uses 65536 Hz. JSON and CSV saving are rejected for audio modes, and WAV saving is rejected for measurement modes. Run `uv sync` to install the `soundfile` dependency used for progressive WAV writing.
|
|
143
147
|
|
|
144
148
|
To attach the handler directly, use `WavDataHandler("saved_data/audio", sample_rate=65536, full_scale_pa=calibrationFactor * (2**23 - 1))` from `slm_api.helpers.data_handler`, using the device's actual calibration factor. You can instead supply `sample_rate` and `full_scale_pa` to `handle()`; the stream supplies both automatically. Call `close()` when finished. Use a separate WAV handler and output path for each device. Existing float32 pressure WAVs are unchanged; this format applies to new recordings.
|
|
@@ -53,8 +53,8 @@ FAST_LOGGING_INTERVAL_MS = FastLogInterval.interval_1000ms.value
|
|
|
53
53
|
SEQUENCE_ID = SequenceIdEnums.FastLAF.value
|
|
54
54
|
|
|
55
55
|
class PrintDataHandler(DataHandler):
|
|
56
|
-
def handle(self, timestamp, name, local, value,
|
|
57
|
-
print(f"{timestamp} {name} ({local}): {value:7.2f}
|
|
56
|
+
def handle(self, timestamp, name, local, value, **data):
|
|
57
|
+
print(f"{timestamp} {name} ({local}): {value:7.2f}")
|
|
58
58
|
|
|
59
59
|
|
|
60
60
|
|
|
@@ -170,7 +170,7 @@ if __name__ == "__main__":
|
|
|
170
170
|
sequenceID = SEQUENCE_ID,
|
|
171
171
|
mode="fast_logging",
|
|
172
172
|
fast_logging_interval=FAST_LOGGING_INTERVAL_MS,
|
|
173
|
-
saving="
|
|
173
|
+
saving="csv",
|
|
174
174
|
saving_path=f"./saved_data/{filename}",
|
|
175
175
|
time=True)
|
|
176
176
|
streamer.setDataHandler(PrintDataHandler())
|
{slm_open_api_package-0.2.12 → slm_open_api_package-0.2.14}/src/slm_api/helpers/data_handler.py
RENAMED
|
@@ -53,7 +53,10 @@ class _BufferedFileDataHandler(DataHandler):
|
|
|
53
53
|
if self._closed:
|
|
54
54
|
return
|
|
55
55
|
if self._write_error is not None:
|
|
56
|
-
raise RuntimeError(
|
|
56
|
+
raise RuntimeError(
|
|
57
|
+
f"Background snapshot saving failed for {self._path}: "
|
|
58
|
+
f"{type(self._write_error).__name__}: {self._write_error}"
|
|
59
|
+
) from self._write_error
|
|
57
60
|
if "values" in data:
|
|
58
61
|
data["values"] = [float(v) for v in data["values"]]
|
|
59
62
|
elif "samples" in data:
|
|
@@ -67,9 +70,20 @@ class _BufferedFileDataHandler(DataHandler):
|
|
|
67
70
|
self._worker.start()
|
|
68
71
|
|
|
69
72
|
def _run_snapshots(self):
|
|
73
|
+
permission_error_reported = False
|
|
70
74
|
while not self._stop_event.wait(self._snapshot_interval):
|
|
71
75
|
try:
|
|
72
76
|
self._flush_snapshot()
|
|
77
|
+
permission_error_reported = False
|
|
78
|
+
except PermissionError as error:
|
|
79
|
+
if not permission_error_reported:
|
|
80
|
+
warnings.warn(
|
|
81
|
+
f"Cannot replace snapshot {self._path}: {error}. "
|
|
82
|
+
"Close any program holding the file open. Records remain "
|
|
83
|
+
"buffered in memory and saving will retry automatically.",
|
|
84
|
+
RuntimeWarning,
|
|
85
|
+
)
|
|
86
|
+
permission_error_reported = True
|
|
73
87
|
except Exception as error:
|
|
74
88
|
with self._lock:
|
|
75
89
|
self._write_error = error
|
|
@@ -110,8 +124,14 @@ class _BufferedFileDataHandler(DataHandler):
|
|
|
110
124
|
self._closed = True
|
|
111
125
|
self._stop_event.set()
|
|
112
126
|
worker = self._worker
|
|
127
|
+
|
|
113
128
|
if worker is not None:
|
|
114
|
-
worker.join()
|
|
129
|
+
worker.join(timeout=5.0)
|
|
130
|
+
if worker.is_alive():
|
|
131
|
+
raise TimeoutError(
|
|
132
|
+
f"Snapshot writer did not stop: {self._path}"
|
|
133
|
+
)
|
|
134
|
+
|
|
115
135
|
self._flush_snapshot()
|
|
116
136
|
|
|
117
137
|
def _group_records(self, records=None):
|
{slm_open_api_package-0.2.12 → slm_open_api_package-0.2.14}/src/slm_api/helpers/stream_handlers.py
RENAMED
|
@@ -221,6 +221,7 @@ class WebXiStreamHandler(stream.StreamHandler):
|
|
|
221
221
|
self.time = time
|
|
222
222
|
self.screen_record = self.mode == "screen_record"
|
|
223
223
|
self.image_bytes = None
|
|
224
|
+
self._audio_ready = threading.Event()
|
|
224
225
|
self.fast_logging_interval = fast_logging_interval
|
|
225
226
|
self.max_input = 15.6263 / np.sqrt(2)
|
|
226
227
|
self._saving_handler = None
|
|
@@ -237,6 +238,22 @@ class WebXiStreamHandler(stream.StreamHandler):
|
|
|
237
238
|
self.tmpFileSM = TmpfileStateMachine()
|
|
238
239
|
self.streamInit()
|
|
239
240
|
|
|
241
|
+
@property
|
|
242
|
+
def audio_ready(self):
|
|
243
|
+
"""Whether nonempty decoded audio has reached the buffer in this session."""
|
|
244
|
+
return self._audio_ready.is_set()
|
|
245
|
+
|
|
246
|
+
async def runStream(self):
|
|
247
|
+
self._audio_ready.clear()
|
|
248
|
+
try:
|
|
249
|
+
await super().runStream()
|
|
250
|
+
finally:
|
|
251
|
+
self._audio_ready.clear()
|
|
252
|
+
|
|
253
|
+
def request_stop(self):
|
|
254
|
+
super().request_stop()
|
|
255
|
+
self._audio_ready.clear()
|
|
256
|
+
|
|
240
257
|
def setDataHandler(self, data_handler):
|
|
241
258
|
"""Attach a DataHandler (see data_handler.py) before calling startStream().
|
|
242
259
|
Without one, WebXiStreamHandler stays silent and does nothing with decoded values.
|
|
@@ -263,6 +280,10 @@ class WebXiStreamHandler(stream.StreamHandler):
|
|
|
263
280
|
raise ValueError(
|
|
264
281
|
"FLAC and MP3 streams must be saved as WAV, not JSON or CSV."
|
|
265
282
|
)
|
|
283
|
+
if (self.mp3 or self.flac) and self.time == True:
|
|
284
|
+
raise ValueError(
|
|
285
|
+
"Time is not supported for flac and mp3."
|
|
286
|
+
)
|
|
266
287
|
if self.mp3 or self.flac:
|
|
267
288
|
quality_setting = "AudioRecordingListenQuality" if self.mp3 else "AudioRecordingAnalysisQuality"
|
|
268
289
|
response = https_requests.put(self.host, f"/WebXi/Applications/SLM/setup/{quality_setting}", json=1)
|
|
@@ -421,7 +442,7 @@ class WebXiStreamHandler(stream.StreamHandler):
|
|
|
421
442
|
unit = self.sequence.get("Unit", "dB re 20uPa")
|
|
422
443
|
for sample_index, value in enumerate(samples):
|
|
423
444
|
timestamp = self._time_prefix(start + sample_index * self.fast_logging_interval_s)
|
|
424
|
-
self._handle_data(timestamp=timestamp, name=name, local=local, value=value
|
|
445
|
+
self._handle_data(timestamp=timestamp, name=name, local=local, value=value)
|
|
425
446
|
|
|
426
447
|
def _msg_func_screen_record(self, message):
|
|
427
448
|
package = webxi_stream.WebxiStream.from_bytes(message)
|
|
@@ -447,7 +468,11 @@ class WebXiStreamHandler(stream.StreamHandler):
|
|
|
447
468
|
else:
|
|
448
469
|
decoded = flac2samples.decode(block, self.calibrationFactor)
|
|
449
470
|
sample_rate = 2 ** 16
|
|
471
|
+
if len(decoded) == 0:
|
|
472
|
+
continue
|
|
450
473
|
DataBuffer.append(decoded)
|
|
474
|
+
if not self._stop_requested:
|
|
475
|
+
self._audio_ready.set()
|
|
451
476
|
self._handle_data(
|
|
452
477
|
samples=decoded, sample_rate=sample_rate,
|
|
453
478
|
full_scale_pa=self.calibrationFactor * (2 ** 23 - 1),
|
|
@@ -457,6 +482,8 @@ class WebXiStreamHandler(stream.StreamHandler):
|
|
|
457
482
|
print(f"TotalTime: {total}")
|
|
458
483
|
|
|
459
484
|
def stopStream(self):
|
|
460
|
-
|
|
461
|
-
self.data_handler.close
|
|
462
|
-
|
|
485
|
+
try:
|
|
486
|
+
if self.data_handler is not None and hasattr(self.data_handler, "close"):
|
|
487
|
+
self.data_handler.close()
|
|
488
|
+
finally:
|
|
489
|
+
super().stopStream()
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{slm_open_api_package-0.2.12 → slm_open_api_package-0.2.14}/src/slm_api/enums/sequence_id_enum.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{slm_open_api_package-0.2.12 → slm_open_api_package-0.2.14}/src/slm_api/helpers/FigureHandler.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{slm_open_api_package-0.2.12 → slm_open_api_package-0.2.14}/src/slm_api/helpers/https_requests.py
RENAMED
|
File without changes
|
|
File without changes
|
{slm_open_api_package-0.2.12 → slm_open_api_package-0.2.14}/src/slm_api/helpers/sequence_handler.py
RENAMED
|
File without changes
|
{slm_open_api_package-0.2.12 → slm_open_api_package-0.2.14}/src/slm_api/helpers/stream_handler.py
RENAMED
|
File without changes
|
|
File without changes
|
{slm_open_api_package-0.2.12 → slm_open_api_package-0.2.14}/src/slm_api/helpers/websocket_handler.py
RENAMED
|
File without changes
|
|
File without changes
|
{slm_open_api_package-0.2.12 → slm_open_api_package-0.2.14}/src/slm_api/helpers/webxi_root.pem
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{slm_open_api_package-0.2.12 → slm_open_api_package-0.2.14}/src/slm_api/multi_device_flac.py
RENAMED
|
File without changes
|
{slm_open_api_package-0.2.12 → slm_open_api_package-0.2.14}/src/slm_api/multi_instrument_example.py
RENAMED
|
File without changes
|
{slm_open_api_package-0.2.12 → slm_open_api_package-0.2.14}/src/slm_api/plot_saved_data_example.py
RENAMED
|
File without changes
|
{slm_open_api_package-0.2.12 → slm_open_api_package-0.2.14}/src/slm_api/screen_record_example.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{slm_open_api_package-0.2.12 → slm_open_api_package-0.2.14}/src/slm_api/webxi/webxi-header.ksy
RENAMED
|
File without changes
|
{slm_open_api_package-0.2.12 → slm_open_api_package-0.2.14}/src/slm_api/webxi/webxi-stream.ksy
RENAMED
|
File without changes
|
{slm_open_api_package-0.2.12 → slm_open_api_package-0.2.14}/src/slm_api/webxi/webxi_header.py
RENAMED
|
File without changes
|
{slm_open_api_package-0.2.12 → slm_open_api_package-0.2.14}/src/slm_api/webxi/webxi_stream.py
RENAMED
|
File without changes
|