streamlit-nightly 1.43.2.dev20250307__py3-none-any.whl
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.
- streamlit/__init__.py +306 -0
- streamlit/__main__.py +20 -0
- streamlit/auth_util.py +218 -0
- streamlit/cli_util.py +105 -0
- streamlit/column_config.py +56 -0
- streamlit/commands/__init__.py +13 -0
- streamlit/commands/echo.py +126 -0
- streamlit/commands/execution_control.py +238 -0
- streamlit/commands/experimental_query_params.py +169 -0
- streamlit/commands/logo.py +189 -0
- streamlit/commands/navigation.py +385 -0
- streamlit/commands/page_config.py +311 -0
- streamlit/components/__init__.py +13 -0
- streamlit/components/lib/__init__.py +13 -0
- streamlit/components/lib/local_component_registry.py +84 -0
- streamlit/components/types/__init__.py +13 -0
- streamlit/components/types/base_component_registry.py +99 -0
- streamlit/components/types/base_custom_component.py +150 -0
- streamlit/components/v1/__init__.py +31 -0
- streamlit/components/v1/component_arrow.py +141 -0
- streamlit/components/v1/component_registry.py +130 -0
- streamlit/components/v1/components.py +38 -0
- streamlit/components/v1/custom_component.py +243 -0
- streamlit/config.py +1513 -0
- streamlit/config_option.py +311 -0
- streamlit/config_util.py +177 -0
- streamlit/connections/__init__.py +28 -0
- streamlit/connections/base_connection.py +174 -0
- streamlit/connections/snowflake_connection.py +562 -0
- streamlit/connections/snowpark_connection.py +213 -0
- streamlit/connections/sql_connection.py +425 -0
- streamlit/connections/util.py +97 -0
- streamlit/cursor.py +210 -0
- streamlit/dataframe_util.py +1416 -0
- streamlit/delta_generator.py +602 -0
- streamlit/delta_generator_singletons.py +204 -0
- streamlit/deprecation_util.py +209 -0
- streamlit/development.py +21 -0
- streamlit/elements/__init__.py +13 -0
- streamlit/elements/alert.py +234 -0
- streamlit/elements/arrow.py +962 -0
- streamlit/elements/balloons.py +47 -0
- streamlit/elements/bokeh_chart.py +133 -0
- streamlit/elements/code.py +114 -0
- streamlit/elements/deck_gl_json_chart.py +546 -0
- streamlit/elements/dialog_decorator.py +267 -0
- streamlit/elements/doc_string.py +558 -0
- streamlit/elements/empty.py +130 -0
- streamlit/elements/exception.py +331 -0
- streamlit/elements/form.py +354 -0
- streamlit/elements/graphviz_chart.py +150 -0
- streamlit/elements/heading.py +302 -0
- streamlit/elements/html.py +105 -0
- streamlit/elements/iframe.py +191 -0
- streamlit/elements/image.py +196 -0
- streamlit/elements/json.py +139 -0
- streamlit/elements/layouts.py +879 -0
- streamlit/elements/lib/__init__.py +13 -0
- streamlit/elements/lib/built_in_chart_utils.py +1157 -0
- streamlit/elements/lib/color_util.py +263 -0
- streamlit/elements/lib/column_config_utils.py +542 -0
- streamlit/elements/lib/column_types.py +2188 -0
- streamlit/elements/lib/dialog.py +147 -0
- streamlit/elements/lib/dicttools.py +154 -0
- streamlit/elements/lib/event_utils.py +37 -0
- streamlit/elements/lib/file_uploader_utils.py +66 -0
- streamlit/elements/lib/form_utils.py +77 -0
- streamlit/elements/lib/image_utils.py +441 -0
- streamlit/elements/lib/js_number.py +105 -0
- streamlit/elements/lib/mutable_status_container.py +183 -0
- streamlit/elements/lib/options_selector_utils.py +250 -0
- streamlit/elements/lib/pandas_styler_utils.py +274 -0
- streamlit/elements/lib/policies.py +194 -0
- streamlit/elements/lib/streamlit_plotly_theme.py +207 -0
- streamlit/elements/lib/subtitle_utils.py +176 -0
- streamlit/elements/lib/utils.py +250 -0
- streamlit/elements/map.py +508 -0
- streamlit/elements/markdown.py +277 -0
- streamlit/elements/media.py +793 -0
- streamlit/elements/metric.py +301 -0
- streamlit/elements/plotly_chart.py +546 -0
- streamlit/elements/progress.py +156 -0
- streamlit/elements/pyplot.py +194 -0
- streamlit/elements/snow.py +47 -0
- streamlit/elements/spinner.py +113 -0
- streamlit/elements/text.py +76 -0
- streamlit/elements/toast.py +98 -0
- streamlit/elements/vega_charts.py +1984 -0
- streamlit/elements/widgets/__init__.py +13 -0
- streamlit/elements/widgets/audio_input.py +310 -0
- streamlit/elements/widgets/button.py +1123 -0
- streamlit/elements/widgets/button_group.py +1008 -0
- streamlit/elements/widgets/camera_input.py +263 -0
- streamlit/elements/widgets/chat.py +647 -0
- streamlit/elements/widgets/checkbox.py +352 -0
- streamlit/elements/widgets/color_picker.py +265 -0
- streamlit/elements/widgets/data_editor.py +983 -0
- streamlit/elements/widgets/file_uploader.py +486 -0
- streamlit/elements/widgets/multiselect.py +338 -0
- streamlit/elements/widgets/number_input.py +545 -0
- streamlit/elements/widgets/radio.py +407 -0
- streamlit/elements/widgets/select_slider.py +437 -0
- streamlit/elements/widgets/selectbox.py +366 -0
- streamlit/elements/widgets/slider.py +880 -0
- streamlit/elements/widgets/text_widgets.py +628 -0
- streamlit/elements/widgets/time_widgets.py +970 -0
- streamlit/elements/write.py +574 -0
- streamlit/emojis.py +34 -0
- streamlit/env_util.py +61 -0
- streamlit/error_util.py +105 -0
- streamlit/errors.py +452 -0
- streamlit/external/__init__.py +13 -0
- streamlit/external/langchain/__init__.py +23 -0
- streamlit/external/langchain/streamlit_callback_handler.py +406 -0
- streamlit/file_util.py +247 -0
- streamlit/git_util.py +173 -0
- streamlit/hello/__init__.py +13 -0
- streamlit/hello/animation_demo.py +82 -0
- streamlit/hello/dataframe_demo.py +71 -0
- streamlit/hello/hello.py +37 -0
- streamlit/hello/mapping_demo.py +114 -0
- streamlit/hello/plotting_demo.py +55 -0
- streamlit/hello/streamlit_app.py +55 -0
- streamlit/hello/utils.py +28 -0
- streamlit/logger.py +130 -0
- streamlit/material_icon_names.py +25 -0
- streamlit/navigation/__init__.py +13 -0
- streamlit/navigation/page.py +302 -0
- streamlit/net_util.py +125 -0
- streamlit/platform.py +33 -0
- streamlit/proto/Alert_pb2.py +29 -0
- streamlit/proto/Alert_pb2.pyi +90 -0
- streamlit/proto/AppPage_pb2.py +27 -0
- streamlit/proto/AppPage_pb2.pyi +64 -0
- streamlit/proto/ArrowNamedDataSet_pb2.py +28 -0
- streamlit/proto/ArrowNamedDataSet_pb2.pyi +57 -0
- streamlit/proto/ArrowVegaLiteChart_pb2.py +29 -0
- streamlit/proto/ArrowVegaLiteChart_pb2.pyi +84 -0
- streamlit/proto/Arrow_pb2.py +33 -0
- streamlit/proto/Arrow_pb2.pyi +188 -0
- streamlit/proto/AudioInput_pb2.py +28 -0
- streamlit/proto/AudioInput_pb2.pyi +58 -0
- streamlit/proto/Audio_pb2.py +27 -0
- streamlit/proto/Audio_pb2.pyi +58 -0
- streamlit/proto/AuthRedirect_pb2.py +27 -0
- streamlit/proto/AuthRedirect_pb2.pyi +41 -0
- streamlit/proto/AutoRerun_pb2.py +27 -0
- streamlit/proto/AutoRerun_pb2.pyi +45 -0
- streamlit/proto/BackMsg_pb2.py +29 -0
- streamlit/proto/BackMsg_pb2.pyi +105 -0
- streamlit/proto/Balloons_pb2.py +27 -0
- streamlit/proto/Balloons_pb2.pyi +43 -0
- streamlit/proto/Block_pb2.py +53 -0
- streamlit/proto/Block_pb2.pyi +322 -0
- streamlit/proto/BokehChart_pb2.py +27 -0
- streamlit/proto/BokehChart_pb2.pyi +49 -0
- streamlit/proto/ButtonGroup_pb2.py +36 -0
- streamlit/proto/ButtonGroup_pb2.pyi +169 -0
- streamlit/proto/Button_pb2.py +27 -0
- streamlit/proto/Button_pb2.pyi +71 -0
- streamlit/proto/CameraInput_pb2.py +28 -0
- streamlit/proto/CameraInput_pb2.pyi +58 -0
- streamlit/proto/ChatInput_pb2.py +31 -0
- streamlit/proto/ChatInput_pb2.pyi +111 -0
- streamlit/proto/Checkbox_pb2.py +30 -0
- streamlit/proto/Checkbox_pb2.pyi +90 -0
- streamlit/proto/ClientState_pb2.py +30 -0
- streamlit/proto/ClientState_pb2.pyi +90 -0
- streamlit/proto/Code_pb2.py +27 -0
- streamlit/proto/Code_pb2.pyi +55 -0
- streamlit/proto/ColorPicker_pb2.py +28 -0
- streamlit/proto/ColorPicker_pb2.pyi +67 -0
- streamlit/proto/Common_pb2.py +51 -0
- streamlit/proto/Common_pb2.pyi +293 -0
- streamlit/proto/Components_pb2.py +35 -0
- streamlit/proto/Components_pb2.pyi +172 -0
- streamlit/proto/DataFrame_pb2.py +56 -0
- streamlit/proto/DataFrame_pb2.pyi +397 -0
- streamlit/proto/DateInput_pb2.py +28 -0
- streamlit/proto/DateInput_pb2.pyi +83 -0
- streamlit/proto/DeckGlJsonChart_pb2.py +29 -0
- streamlit/proto/DeckGlJsonChart_pb2.pyi +102 -0
- streamlit/proto/Delta_pb2.py +31 -0
- streamlit/proto/Delta_pb2.pyi +74 -0
- streamlit/proto/DocString_pb2.py +29 -0
- streamlit/proto/DocString_pb2.pyi +93 -0
- streamlit/proto/DownloadButton_pb2.py +27 -0
- streamlit/proto/DownloadButton_pb2.pyi +70 -0
- streamlit/proto/Element_pb2.py +78 -0
- streamlit/proto/Element_pb2.pyi +312 -0
- streamlit/proto/Empty_pb2.py +27 -0
- streamlit/proto/Empty_pb2.pyi +36 -0
- streamlit/proto/Exception_pb2.py +27 -0
- streamlit/proto/Exception_pb2.pyi +72 -0
- streamlit/proto/Favicon_pb2.py +27 -0
- streamlit/proto/Favicon_pb2.pyi +40 -0
- streamlit/proto/FileUploader_pb2.py +28 -0
- streamlit/proto/FileUploader_pb2.pyi +78 -0
- streamlit/proto/ForwardMsg_pb2.py +53 -0
- streamlit/proto/ForwardMsg_pb2.pyi +293 -0
- streamlit/proto/GitInfo_pb2.py +29 -0
- streamlit/proto/GitInfo_pb2.pyi +83 -0
- streamlit/proto/GraphVizChart_pb2.py +27 -0
- streamlit/proto/GraphVizChart_pb2.pyi +53 -0
- streamlit/proto/Heading_pb2.py +27 -0
- streamlit/proto/Heading_pb2.pyi +56 -0
- streamlit/proto/Html_pb2.py +27 -0
- streamlit/proto/Html_pb2.pyi +42 -0
- streamlit/proto/IFrame_pb2.py +27 -0
- streamlit/proto/IFrame_pb2.pyi +59 -0
- streamlit/proto/Image_pb2.py +29 -0
- streamlit/proto/Image_pb2.pyi +84 -0
- streamlit/proto/Json_pb2.py +27 -0
- streamlit/proto/Json_pb2.pyi +53 -0
- streamlit/proto/LabelVisibilityMessage_pb2.py +29 -0
- streamlit/proto/LabelVisibilityMessage_pb2.pyi +68 -0
- streamlit/proto/LinkButton_pb2.py +27 -0
- streamlit/proto/LinkButton_pb2.pyi +58 -0
- streamlit/proto/Logo_pb2.py +27 -0
- streamlit/proto/Logo_pb2.pyi +51 -0
- streamlit/proto/Markdown_pb2.py +29 -0
- streamlit/proto/Markdown_pb2.pyi +86 -0
- streamlit/proto/Metric_pb2.py +32 -0
- streamlit/proto/Metric_pb2.pyi +101 -0
- streamlit/proto/MetricsEvent_pb2.py +30 -0
- streamlit/proto/MetricsEvent_pb2.pyi +200 -0
- streamlit/proto/MultiSelect_pb2.py +28 -0
- streamlit/proto/MultiSelect_pb2.pyi +81 -0
- streamlit/proto/NamedDataSet_pb2.py +28 -0
- streamlit/proto/NamedDataSet_pb2.pyi +59 -0
- streamlit/proto/Navigation_pb2.py +30 -0
- streamlit/proto/Navigation_pb2.pyi +84 -0
- streamlit/proto/NewSession_pb2.py +51 -0
- streamlit/proto/NewSession_pb2.pyi +481 -0
- streamlit/proto/NumberInput_pb2.py +30 -0
- streamlit/proto/NumberInput_pb2.pyi +121 -0
- streamlit/proto/PageConfig_pb2.py +33 -0
- streamlit/proto/PageConfig_pb2.pyi +126 -0
- streamlit/proto/PageInfo_pb2.py +27 -0
- streamlit/proto/PageInfo_pb2.pyi +43 -0
- streamlit/proto/PageLink_pb2.py +27 -0
- streamlit/proto/PageLink_pb2.pyi +63 -0
- streamlit/proto/PageNotFound_pb2.py +27 -0
- streamlit/proto/PageNotFound_pb2.pyi +42 -0
- streamlit/proto/PageProfile_pb2.py +31 -0
- streamlit/proto/PageProfile_pb2.pyi +127 -0
- streamlit/proto/PagesChanged_pb2.py +28 -0
- streamlit/proto/PagesChanged_pb2.pyi +48 -0
- streamlit/proto/ParentMessage_pb2.py +27 -0
- streamlit/proto/ParentMessage_pb2.pyi +46 -0
- streamlit/proto/PlotlyChart_pb2.py +31 -0
- streamlit/proto/PlotlyChart_pb2.pyi +131 -0
- streamlit/proto/Progress_pb2.py +27 -0
- streamlit/proto/Progress_pb2.pyi +43 -0
- streamlit/proto/Radio_pb2.py +28 -0
- streamlit/proto/Radio_pb2.pyi +84 -0
- streamlit/proto/RootContainer_pb2.py +27 -0
- streamlit/proto/RootContainer_pb2.pyi +56 -0
- streamlit/proto/Selectbox_pb2.py +28 -0
- streamlit/proto/Selectbox_pb2.pyi +80 -0
- streamlit/proto/SessionEvent_pb2.py +28 -0
- streamlit/proto/SessionEvent_pb2.pyi +62 -0
- streamlit/proto/SessionStatus_pb2.py +27 -0
- streamlit/proto/SessionStatus_pb2.pyi +57 -0
- streamlit/proto/Skeleton_pb2.py +29 -0
- streamlit/proto/Skeleton_pb2.pyi +71 -0
- streamlit/proto/Slider_pb2.py +32 -0
- streamlit/proto/Slider_pb2.pyi +142 -0
- streamlit/proto/Snow_pb2.py +27 -0
- streamlit/proto/Snow_pb2.pyi +43 -0
- streamlit/proto/Spinner_pb2.py +27 -0
- streamlit/proto/Spinner_pb2.pyi +49 -0
- streamlit/proto/TextArea_pb2.py +28 -0
- streamlit/proto/TextArea_pb2.pyi +80 -0
- streamlit/proto/TextInput_pb2.py +30 -0
- streamlit/proto/TextInput_pb2.pyi +107 -0
- streamlit/proto/Text_pb2.py +27 -0
- streamlit/proto/Text_pb2.pyi +46 -0
- streamlit/proto/TimeInput_pb2.py +28 -0
- streamlit/proto/TimeInput_pb2.pyi +74 -0
- streamlit/proto/Toast_pb2.py +27 -0
- streamlit/proto/Toast_pb2.pyi +45 -0
- streamlit/proto/VegaLiteChart_pb2.py +29 -0
- streamlit/proto/VegaLiteChart_pb2.pyi +71 -0
- streamlit/proto/Video_pb2.py +31 -0
- streamlit/proto/Video_pb2.pyi +117 -0
- streamlit/proto/WidgetStates_pb2.py +31 -0
- streamlit/proto/WidgetStates_pb2.pyi +126 -0
- streamlit/proto/__init__.py +15 -0
- streamlit/proto/openmetrics_data_model_pb2.py +60 -0
- streamlit/proto/openmetrics_data_model_pb2.pyi +522 -0
- streamlit/py.typed +0 -0
- streamlit/runtime/__init__.py +50 -0
- streamlit/runtime/app_session.py +982 -0
- streamlit/runtime/caching/__init__.py +98 -0
- streamlit/runtime/caching/cache_data_api.py +665 -0
- streamlit/runtime/caching/cache_errors.py +142 -0
- streamlit/runtime/caching/cache_resource_api.py +527 -0
- streamlit/runtime/caching/cache_type.py +33 -0
- streamlit/runtime/caching/cache_utils.py +523 -0
- streamlit/runtime/caching/cached_message_replay.py +290 -0
- streamlit/runtime/caching/hashing.py +637 -0
- streamlit/runtime/caching/legacy_cache_api.py +169 -0
- streamlit/runtime/caching/storage/__init__.py +29 -0
- streamlit/runtime/caching/storage/cache_storage_protocol.py +239 -0
- streamlit/runtime/caching/storage/dummy_cache_storage.py +60 -0
- streamlit/runtime/caching/storage/in_memory_cache_storage_wrapper.py +145 -0
- streamlit/runtime/caching/storage/local_disk_cache_storage.py +223 -0
- streamlit/runtime/connection_factory.py +436 -0
- streamlit/runtime/context.py +280 -0
- streamlit/runtime/credentials.py +364 -0
- streamlit/runtime/forward_msg_cache.py +296 -0
- streamlit/runtime/forward_msg_queue.py +240 -0
- streamlit/runtime/fragment.py +477 -0
- streamlit/runtime/media_file_manager.py +234 -0
- streamlit/runtime/media_file_storage.py +143 -0
- streamlit/runtime/memory_media_file_storage.py +181 -0
- streamlit/runtime/memory_session_storage.py +77 -0
- streamlit/runtime/memory_uploaded_file_manager.py +138 -0
- streamlit/runtime/metrics_util.py +486 -0
- streamlit/runtime/pages_manager.py +165 -0
- streamlit/runtime/runtime.py +792 -0
- streamlit/runtime/runtime_util.py +106 -0
- streamlit/runtime/script_data.py +46 -0
- streamlit/runtime/scriptrunner/__init__.py +38 -0
- streamlit/runtime/scriptrunner/exec_code.py +159 -0
- streamlit/runtime/scriptrunner/magic.py +273 -0
- streamlit/runtime/scriptrunner/magic_funcs.py +32 -0
- streamlit/runtime/scriptrunner/script_cache.py +89 -0
- streamlit/runtime/scriptrunner/script_runner.py +756 -0
- streamlit/runtime/scriptrunner_utils/__init__.py +19 -0
- streamlit/runtime/scriptrunner_utils/exceptions.py +48 -0
- streamlit/runtime/scriptrunner_utils/script_requests.py +307 -0
- streamlit/runtime/scriptrunner_utils/script_run_context.py +287 -0
- streamlit/runtime/secrets.py +534 -0
- streamlit/runtime/session_manager.py +394 -0
- streamlit/runtime/state/__init__.py +41 -0
- streamlit/runtime/state/common.py +191 -0
- streamlit/runtime/state/query_params.py +205 -0
- streamlit/runtime/state/query_params_proxy.py +218 -0
- streamlit/runtime/state/safe_session_state.py +138 -0
- streamlit/runtime/state/session_state.py +772 -0
- streamlit/runtime/state/session_state_proxy.py +153 -0
- streamlit/runtime/state/widgets.py +135 -0
- streamlit/runtime/stats.py +109 -0
- streamlit/runtime/uploaded_file_manager.py +148 -0
- streamlit/runtime/websocket_session_manager.py +167 -0
- streamlit/source_util.py +98 -0
- streamlit/static/favicon.png +0 -0
- streamlit/static/index.html +61 -0
- streamlit/static/static/css/index.Bmkmz40k.css +1 -0
- streamlit/static/static/css/index.DpJG_94W.css +1 -0
- streamlit/static/static/css/index.DzuxGC_t.css +1 -0
- streamlit/static/static/js/FileDownload.esm.Bp9m5jrx.js +1 -0
- streamlit/static/static/js/FileHelper.D_3pbilj.js +5 -0
- streamlit/static/static/js/FormClearHelper.Ct2rwLXo.js +1 -0
- streamlit/static/static/js/Hooks.BKdzj5MJ.js +1 -0
- streamlit/static/static/js/InputInstructions.DB3QGNJP.js +1 -0
- streamlit/static/static/js/ProgressBar.D40A5xc2.js +2 -0
- streamlit/static/static/js/RenderInPortalIfExists.DLUCooTN.js +1 -0
- streamlit/static/static/js/Toolbar.BiGGIQun.js +1 -0
- streamlit/static/static/js/UploadFileInfo.C-jY39rj.js +1 -0
- streamlit/static/static/js/base-input.CQBQT24M.js +4 -0
- streamlit/static/static/js/checkbox.Buj8gd_M.js +9 -0
- streamlit/static/static/js/createDownloadLinkElement.DZMwyjvU.js +1 -0
- streamlit/static/static/js/createSuper.CesK3I23.js +1 -0
- streamlit/static/static/js/data-grid-overlay-editor.B69OOFM4.js +1 -0
- streamlit/static/static/js/downloader.BZQhlBNT.js +1 -0
- streamlit/static/static/js/es6.D9Zhqujy.js +2 -0
- streamlit/static/static/js/iframeResizer.contentWindow.CAzcBpCC.js +1 -0
- streamlit/static/static/js/index.08vcOOvb.js +1 -0
- streamlit/static/static/js/index.0uqKfJUS.js +1 -0
- streamlit/static/static/js/index.B02M5u69.js +203 -0
- streamlit/static/static/js/index.B7mcZKMx.js +1 -0
- streamlit/static/static/js/index.BAQDHFA_.js +1 -0
- streamlit/static/static/js/index.BI60cMVr.js +2 -0
- streamlit/static/static/js/index.BLug2inK.js +1 -0
- streamlit/static/static/js/index.BM6TMY8g.js +2 -0
- streamlit/static/static/js/index.BZ9p1t7G.js +1 -0
- streamlit/static/static/js/index.BZqa87a1.js +2 -0
- streamlit/static/static/js/index.BcsRUzZZ.js +1 -0
- streamlit/static/static/js/index.BgVMiY_P.js +197 -0
- streamlit/static/static/js/index.BtuGy7By.js +6 -0
- streamlit/static/static/js/index.BuDuBmrs.js +1 -0
- streamlit/static/static/js/index.BvXU2oKV.js +1 -0
- streamlit/static/static/js/index.BxcwPacT.js +73 -0
- streamlit/static/static/js/index.CWX8KB81.js +1 -0
- streamlit/static/static/js/index.CXzZTo_q.js +1 -0
- streamlit/static/static/js/index.CcRWp_KL.js +1 -0
- streamlit/static/static/js/index.Cd-_xe55.js +3 -0
- streamlit/static/static/js/index.CdG2PXln.js +4537 -0
- streamlit/static/static/js/index.CjXvXmcP.js +1 -0
- streamlit/static/static/js/index.D1HZENZx.js +776 -0
- streamlit/static/static/js/index.D21Efo64.js +1617 -0
- streamlit/static/static/js/index.D9WgGVBx.js +7 -0
- streamlit/static/static/js/index.DEcsHtvb.js +12 -0
- streamlit/static/static/js/index.DFeMfr_K.js +1 -0
- streamlit/static/static/js/index.DHFBoItz.js +1 -0
- streamlit/static/static/js/index.D_PrBKnJ.js +3 -0
- streamlit/static/static/js/index.DmuRkekN.js +3855 -0
- streamlit/static/static/js/index.Do6eY8sf.js +1 -0
- streamlit/static/static/js/index.Dz3lP2P-.js +1 -0
- streamlit/static/static/js/index.Dz_UqF-s.js +1 -0
- streamlit/static/static/js/index.GkSUsPhJ.js +1 -0
- streamlit/static/static/js/index.H1U1IC_d.js +3 -0
- streamlit/static/static/js/index.g6p_4DPr.js +1 -0
- streamlit/static/static/js/index.g9x_GKss.js +1 -0
- streamlit/static/static/js/index.zo9jm08y.js +1 -0
- streamlit/static/static/js/input.DnaFglHq.js +2 -0
- streamlit/static/static/js/inputUtils.CQWz5UKz.js +1 -0
- streamlit/static/static/js/memory.Crb9x4-F.js +1 -0
- streamlit/static/static/js/mergeWith.ouAz0sK3.js +1 -0
- streamlit/static/static/js/number-overlay-editor._UaN-O48.js +9 -0
- streamlit/static/static/js/possibleConstructorReturn.CtGjGFHz.js +1 -0
- streamlit/static/static/js/sandbox.CBybYOhV.js +1 -0
- streamlit/static/static/js/sprintf.D7DtBTRn.js +1 -0
- streamlit/static/static/js/textarea.Cb_uJt5U.js +2 -0
- streamlit/static/static/js/threshold.DjX0wlsa.js +1 -0
- streamlit/static/static/js/timepicker.DKT7pfoF.js +4 -0
- streamlit/static/static/js/timer.CAwTRJ_g.js +1 -0
- streamlit/static/static/js/toConsumableArray.05Ikp13-.js +3 -0
- streamlit/static/static/js/uniqueId.D2FMWUEI.js +1 -0
- streamlit/static/static/js/useBasicWidgetState.urnZLANY.js +1 -0
- streamlit/static/static/js/useOnInputChange.BOKIIdJ1.js +1 -0
- streamlit/static/static/js/value.CgPGBV_l.js +1 -0
- streamlit/static/static/js/withFullScreenWrapper.C_N8J0Xx.js +1 -0
- streamlit/static/static/media/KaTeX_AMS-Regular.BQhdFMY1.woff2 +0 -0
- streamlit/static/static/media/KaTeX_AMS-Regular.DMm9YOAa.woff +0 -0
- streamlit/static/static/media/KaTeX_AMS-Regular.DRggAlZN.ttf +0 -0
- streamlit/static/static/media/KaTeX_Caligraphic-Bold.ATXxdsX0.ttf +0 -0
- streamlit/static/static/media/KaTeX_Caligraphic-Bold.BEiXGLvX.woff +0 -0
- streamlit/static/static/media/KaTeX_Caligraphic-Bold.Dq_IR9rO.woff2 +0 -0
- streamlit/static/static/media/KaTeX_Caligraphic-Regular.CTRA-rTL.woff +0 -0
- streamlit/static/static/media/KaTeX_Caligraphic-Regular.Di6jR-x-.woff2 +0 -0
- streamlit/static/static/media/KaTeX_Caligraphic-Regular.wX97UBjC.ttf +0 -0
- streamlit/static/static/media/KaTeX_Fraktur-Bold.BdnERNNW.ttf +0 -0
- streamlit/static/static/media/KaTeX_Fraktur-Bold.BsDP51OF.woff +0 -0
- streamlit/static/static/media/KaTeX_Fraktur-Bold.CL6g_b3V.woff2 +0 -0
- streamlit/static/static/media/KaTeX_Fraktur-Regular.CB_wures.ttf +0 -0
- streamlit/static/static/media/KaTeX_Fraktur-Regular.CTYiF6lA.woff2 +0 -0
- streamlit/static/static/media/KaTeX_Fraktur-Regular.Dxdc4cR9.woff +0 -0
- streamlit/static/static/media/KaTeX_Main-Bold.Cx986IdX.woff2 +0 -0
- streamlit/static/static/media/KaTeX_Main-Bold.Jm3AIy58.woff +0 -0
- streamlit/static/static/media/KaTeX_Main-Bold.waoOVXN0.ttf +0 -0
- streamlit/static/static/media/KaTeX_Main-BoldItalic.DxDJ3AOS.woff2 +0 -0
- streamlit/static/static/media/KaTeX_Main-BoldItalic.DzxPMmG6.ttf +0 -0
- streamlit/static/static/media/KaTeX_Main-BoldItalic.SpSLRI95.woff +0 -0
- streamlit/static/static/media/KaTeX_Main-Italic.3WenGoN9.ttf +0 -0
- streamlit/static/static/media/KaTeX_Main-Italic.BMLOBm91.woff +0 -0
- streamlit/static/static/media/KaTeX_Main-Italic.NWA7e6Wa.woff2 +0 -0
- streamlit/static/static/media/KaTeX_Main-Regular.B22Nviop.woff2 +0 -0
- streamlit/static/static/media/KaTeX_Main-Regular.Dr94JaBh.woff +0 -0
- streamlit/static/static/media/KaTeX_Main-Regular.ypZvNtVU.ttf +0 -0
- streamlit/static/static/media/KaTeX_Math-BoldItalic.B3XSjfu4.ttf +0 -0
- streamlit/static/static/media/KaTeX_Math-BoldItalic.CZnvNsCZ.woff2 +0 -0
- streamlit/static/static/media/KaTeX_Math-BoldItalic.iY-2wyZ7.woff +0 -0
- streamlit/static/static/media/KaTeX_Math-Italic.DA0__PXp.woff +0 -0
- streamlit/static/static/media/KaTeX_Math-Italic.flOr_0UB.ttf +0 -0
- streamlit/static/static/media/KaTeX_Math-Italic.t53AETM-.woff2 +0 -0
- streamlit/static/static/media/KaTeX_SansSerif-Bold.CFMepnvq.ttf +0 -0
- streamlit/static/static/media/KaTeX_SansSerif-Bold.D1sUS0GD.woff2 +0 -0
- streamlit/static/static/media/KaTeX_SansSerif-Bold.DbIhKOiC.woff +0 -0
- streamlit/static/static/media/KaTeX_SansSerif-Italic.C3H0VqGB.woff2 +0 -0
- streamlit/static/static/media/KaTeX_SansSerif-Italic.DN2j7dab.woff +0 -0
- streamlit/static/static/media/KaTeX_SansSerif-Italic.YYjJ1zSn.ttf +0 -0
- streamlit/static/static/media/KaTeX_SansSerif-Regular.BNo7hRIc.ttf +0 -0
- streamlit/static/static/media/KaTeX_SansSerif-Regular.CS6fqUqJ.woff +0 -0
- streamlit/static/static/media/KaTeX_SansSerif-Regular.DDBCnlJ7.woff2 +0 -0
- streamlit/static/static/media/KaTeX_Script-Regular.C5JkGWo-.ttf +0 -0
- streamlit/static/static/media/KaTeX_Script-Regular.D3wIWfF6.woff2 +0 -0
- streamlit/static/static/media/KaTeX_Script-Regular.D5yQViql.woff +0 -0
- streamlit/static/static/media/KaTeX_Size1-Regular.C195tn64.woff +0 -0
- streamlit/static/static/media/KaTeX_Size1-Regular.Dbsnue_I.ttf +0 -0
- streamlit/static/static/media/KaTeX_Size1-Regular.mCD8mA8B.woff2 +0 -0
- streamlit/static/static/media/KaTeX_Size2-Regular.B7gKUWhC.ttf +0 -0
- streamlit/static/static/media/KaTeX_Size2-Regular.Dy4dx90m.woff2 +0 -0
- streamlit/static/static/media/KaTeX_Size2-Regular.oD1tc_U0.woff +0 -0
- streamlit/static/static/media/KaTeX_Size3-Regular.CTq5MqoE.woff +0 -0
- streamlit/static/static/media/KaTeX_Size3-Regular.DgpXs0kz.ttf +0 -0
- streamlit/static/static/media/KaTeX_Size4-Regular.BF-4gkZK.woff +0 -0
- streamlit/static/static/media/KaTeX_Size4-Regular.DWFBv043.ttf +0 -0
- streamlit/static/static/media/KaTeX_Size4-Regular.Dl5lxZxV.woff2 +0 -0
- streamlit/static/static/media/KaTeX_Typewriter-Regular.C0xS9mPB.woff +0 -0
- streamlit/static/static/media/KaTeX_Typewriter-Regular.CO6r4hn1.woff2 +0 -0
- streamlit/static/static/media/KaTeX_Typewriter-Regular.D3Ib7_Hf.ttf +0 -0
- streamlit/static/static/media/MaterialSymbols-Rounded.DcZbplWk.woff2 +0 -0
- streamlit/static/static/media/SourceCodePro-Bold.CFEfr7-q.woff2 +0 -0
- streamlit/static/static/media/SourceCodePro-BoldItalic.C-LkFXxa.woff2 +0 -0
- streamlit/static/static/media/SourceCodePro-Italic.CxFOx7N-.woff2 +0 -0
- streamlit/static/static/media/SourceCodePro-Regular.CBOlD63d.woff2 +0 -0
- streamlit/static/static/media/SourceCodePro-SemiBold.CFHwW3Wd.woff2 +0 -0
- streamlit/static/static/media/SourceCodePro-SemiBoldItalic.Cg2yRu82.woff2 +0 -0
- streamlit/static/static/media/SourceSansPro-Bold.-6c9oR8J.woff2 +0 -0
- streamlit/static/static/media/SourceSansPro-BoldItalic.DmM_grLY.woff2 +0 -0
- streamlit/static/static/media/SourceSansPro-Italic.I1ipWe7Q.woff2 +0 -0
- streamlit/static/static/media/SourceSansPro-Regular.DZLUzqI4.woff2 +0 -0
- streamlit/static/static/media/SourceSansPro-SemiBold.sKQIyTMz.woff2 +0 -0
- streamlit/static/static/media/SourceSansPro-SemiBoldItalic.C0wP0icr.woff2 +0 -0
- streamlit/static/static/media/SourceSerifPro-Bold.8TUnKj4x.woff2 +0 -0
- streamlit/static/static/media/SourceSerifPro-BoldItalic.CBVO7Ve7.woff2 +0 -0
- streamlit/static/static/media/SourceSerifPro-Italic.DkFgL2HZ.woff2 +0 -0
- streamlit/static/static/media/SourceSerifPro-Regular.CNJNET2S.woff2 +0 -0
- streamlit/static/static/media/SourceSerifPro-SemiBold.CHyh9GC5.woff2 +0 -0
- streamlit/static/static/media/SourceSerifPro-SemiBoldItalic.CBtz8sWN.woff2 +0 -0
- streamlit/static/static/media/balloon-0.Czj7AKwE.png +0 -0
- streamlit/static/static/media/balloon-1.CNvFFrND.png +0 -0
- streamlit/static/static/media/balloon-2.DTvC6B1t.png +0 -0
- streamlit/static/static/media/balloon-3.CgSk4tbL.png +0 -0
- streamlit/static/static/media/balloon-4.mbtFrzxf.png +0 -0
- streamlit/static/static/media/balloon-5.CSwkUfRA.png +0 -0
- streamlit/static/static/media/fireworks.B4d-_KUe.gif +0 -0
- streamlit/static/static/media/flake-0.DgWaVvm5.png +0 -0
- streamlit/static/static/media/flake-1.B2r5AHMK.png +0 -0
- streamlit/static/static/media/flake-2.BnWSExPC.png +0 -0
- streamlit/static/static/media/snowflake.JU2jBHL8.svg +11 -0
- streamlit/string_util.py +203 -0
- streamlit/temporary_directory.py +56 -0
- streamlit/testing/__init__.py +13 -0
- streamlit/testing/v1/__init__.py +17 -0
- streamlit/testing/v1/app_test.py +1050 -0
- streamlit/testing/v1/element_tree.py +2083 -0
- streamlit/testing/v1/local_script_runner.py +180 -0
- streamlit/testing/v1/util.py +53 -0
- streamlit/time_util.py +75 -0
- streamlit/type_util.py +460 -0
- streamlit/url_util.py +122 -0
- streamlit/user_info.py +519 -0
- streamlit/util.py +72 -0
- streamlit/vendor/__init__.py +0 -0
- streamlit/vendor/pympler/__init__.py +0 -0
- streamlit/vendor/pympler/asizeof.py +2869 -0
- streamlit/version.py +18 -0
- streamlit/watcher/__init__.py +28 -0
- streamlit/watcher/event_based_path_watcher.py +406 -0
- streamlit/watcher/folder_black_list.py +82 -0
- streamlit/watcher/local_sources_watcher.py +233 -0
- streamlit/watcher/path_watcher.py +185 -0
- streamlit/watcher/polling_path_watcher.py +124 -0
- streamlit/watcher/util.py +207 -0
- streamlit/web/__init__.py +13 -0
- streamlit/web/bootstrap.py +353 -0
- streamlit/web/cache_storage_manager_config.py +38 -0
- streamlit/web/cli.py +369 -0
- streamlit/web/server/__init__.py +26 -0
- streamlit/web/server/app_static_file_handler.py +93 -0
- streamlit/web/server/authlib_tornado_integration.py +60 -0
- streamlit/web/server/browser_websocket_handler.py +246 -0
- streamlit/web/server/component_request_handler.py +116 -0
- streamlit/web/server/media_file_handler.py +141 -0
- streamlit/web/server/oauth_authlib_routes.py +176 -0
- streamlit/web/server/oidc_mixin.py +108 -0
- streamlit/web/server/routes.py +295 -0
- streamlit/web/server/server.py +479 -0
- streamlit/web/server/server_util.py +161 -0
- streamlit/web/server/stats_request_handler.py +95 -0
- streamlit/web/server/upload_file_request_handler.py +137 -0
- streamlit/web/server/websocket_headers.py +56 -0
- streamlit_nightly-1.43.2.dev20250307.data/scripts/streamlit.cmd +16 -0
- streamlit_nightly-1.43.2.dev20250307.dist-info/METADATA +207 -0
- streamlit_nightly-1.43.2.dev20250307.dist-info/RECORD +563 -0
- streamlit_nightly-1.43.2.dev20250307.dist-info/WHEEL +5 -0
- streamlit_nightly-1.43.2.dev20250307.dist-info/entry_points.txt +2 -0
- streamlit_nightly-1.43.2.dev20250307.dist-info/top_level.txt +1 -0
@@ -0,0 +1,793 @@
|
|
1
|
+
# Copyright (c) Streamlit Inc. (2018-2022) Snowflake Inc. (2022-2025)
|
2
|
+
#
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
# you may not use this file except in compliance with the License.
|
5
|
+
# You may obtain a copy of the License at
|
6
|
+
#
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
#
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
# See the License for the specific language governing permissions and
|
13
|
+
# limitations under the License.
|
14
|
+
|
15
|
+
from __future__ import annotations
|
16
|
+
|
17
|
+
import io
|
18
|
+
import re
|
19
|
+
from datetime import timedelta
|
20
|
+
from pathlib import Path
|
21
|
+
from typing import TYPE_CHECKING, Final, Union, cast
|
22
|
+
|
23
|
+
from typing_extensions import TypeAlias
|
24
|
+
|
25
|
+
from streamlit import runtime, type_util, url_util
|
26
|
+
from streamlit.elements.lib.form_utils import current_form_id
|
27
|
+
from streamlit.elements.lib.subtitle_utils import process_subtitle_data
|
28
|
+
from streamlit.elements.lib.utils import compute_and_register_element_id
|
29
|
+
from streamlit.errors import StreamlitAPIException
|
30
|
+
from streamlit.proto.Audio_pb2 import Audio as AudioProto
|
31
|
+
from streamlit.proto.Video_pb2 import Video as VideoProto
|
32
|
+
from streamlit.runtime import caching
|
33
|
+
from streamlit.runtime.metrics_util import gather_metrics
|
34
|
+
from streamlit.time_util import time_to_seconds
|
35
|
+
from streamlit.type_util import NumpyShape
|
36
|
+
|
37
|
+
if TYPE_CHECKING:
|
38
|
+
from typing import Any
|
39
|
+
|
40
|
+
from numpy import typing as npt
|
41
|
+
|
42
|
+
from streamlit.delta_generator import DeltaGenerator
|
43
|
+
|
44
|
+
|
45
|
+
MediaData: TypeAlias = Union[
|
46
|
+
str,
|
47
|
+
Path,
|
48
|
+
bytes,
|
49
|
+
io.BytesIO,
|
50
|
+
io.RawIOBase,
|
51
|
+
io.BufferedReader,
|
52
|
+
"npt.NDArray[Any]",
|
53
|
+
None,
|
54
|
+
]
|
55
|
+
|
56
|
+
SubtitleData: TypeAlias = Union[
|
57
|
+
str, Path, bytes, io.BytesIO, dict[str, Union[str, Path, bytes, io.BytesIO]], None
|
58
|
+
]
|
59
|
+
|
60
|
+
MediaTime: TypeAlias = Union[int, float, timedelta, str]
|
61
|
+
|
62
|
+
TIMEDELTA_PARSE_ERROR_MESSAGE: Final = (
|
63
|
+
"Failed to convert '{param_name}' to a timedelta. "
|
64
|
+
"Please use a string in a format supported by "
|
65
|
+
"[Pandas Timedelta constructor]"
|
66
|
+
"(https://pandas.pydata.org/docs/reference/api/pandas.Timedelta.html), "
|
67
|
+
'e.g. `"10s"`, `"15 seconds"`, or `"1h23s"`. Got: {param_value}'
|
68
|
+
)
|
69
|
+
|
70
|
+
|
71
|
+
class MediaMixin:
|
72
|
+
@gather_metrics("audio")
|
73
|
+
def audio(
|
74
|
+
self,
|
75
|
+
data: MediaData,
|
76
|
+
format: str = "audio/wav",
|
77
|
+
start_time: MediaTime = 0,
|
78
|
+
*,
|
79
|
+
sample_rate: int | None = None,
|
80
|
+
end_time: MediaTime | None = None,
|
81
|
+
loop: bool = False,
|
82
|
+
autoplay: bool = False,
|
83
|
+
) -> DeltaGenerator:
|
84
|
+
"""Display an audio player.
|
85
|
+
|
86
|
+
Parameters
|
87
|
+
----------
|
88
|
+
data : str, Path, bytes, BytesIO, numpy.ndarray, or file
|
89
|
+
The audio to play. This can be one of the following:
|
90
|
+
|
91
|
+
- A URL (string) for a hosted audio file.
|
92
|
+
- A path to a local audio file. The path can be a ``str``
|
93
|
+
or ``Path`` object. Paths can be absolute or relative to the
|
94
|
+
working directory (where you execute ``streamlit run``).
|
95
|
+
- Raw audio data. Raw data formats must include all necessary file
|
96
|
+
headers to match the file format specified via ``format``.
|
97
|
+
|
98
|
+
If ``data`` is a NumPy array, it must either be a 1D array of the
|
99
|
+
waveform or a 2D array of shape (C, S) where C is the number of
|
100
|
+
channels and S is the number of samples. See the default channel
|
101
|
+
order at
|
102
|
+
http://msdn.microsoft.com/en-us/library/windows/hardware/dn653308(v=vs.85).aspx
|
103
|
+
|
104
|
+
format : str
|
105
|
+
The MIME type for the audio file. This defaults to ``"audio/wav"``.
|
106
|
+
For more information about MIME types, see
|
107
|
+
https://www.iana.org/assignments/media-types/media-types.xhtml.
|
108
|
+
|
109
|
+
start_time: int, float, timedelta, str, or None
|
110
|
+
The time from which the element should start playing. This can be
|
111
|
+
one of the following:
|
112
|
+
|
113
|
+
- ``None`` (default): The element plays from the beginning.
|
114
|
+
- An ``int`` or ``float`` specifying the time in seconds. ``float``
|
115
|
+
values are rounded down to whole seconds.
|
116
|
+
- A string specifying the time in a format supported by `Pandas'
|
117
|
+
Timedelta constructor <https://pandas.pydata.org/docs/reference/api/pandas.Timedelta.html>`_,
|
118
|
+
e.g. ``"2 minute"``, ``"20s"``, or ``"1m14s"``.
|
119
|
+
- A ``timedelta`` object from `Python's built-in datetime library
|
120
|
+
<https://docs.python.org/3/library/datetime.html#timedelta-objects>`_,
|
121
|
+
e.g. ``timedelta(seconds=70)``.
|
122
|
+
sample_rate: int or None
|
123
|
+
The sample rate of the audio data in samples per second. This is
|
124
|
+
only required if ``data`` is a NumPy array.
|
125
|
+
end_time: int, float, timedelta, str, or None
|
126
|
+
The time at which the element should stop playing. This can be
|
127
|
+
one of the following:
|
128
|
+
|
129
|
+
- ``None`` (default): The element plays through to the end.
|
130
|
+
- An ``int`` or ``float`` specifying the time in seconds. ``float``
|
131
|
+
values are rounded down to whole seconds.
|
132
|
+
- A string specifying the time in a format supported by `Pandas'
|
133
|
+
Timedelta constructor <https://pandas.pydata.org/docs/reference/api/pandas.Timedelta.html>`_,
|
134
|
+
e.g. ``"2 minute"``, ``"20s"``, or ``"1m14s"``.
|
135
|
+
- A ``timedelta`` object from `Python's built-in datetime library
|
136
|
+
<https://docs.python.org/3/library/datetime.html#timedelta-objects>`_,
|
137
|
+
e.g. ``timedelta(seconds=70)``.
|
138
|
+
loop: bool
|
139
|
+
Whether the audio should loop playback.
|
140
|
+
autoplay: bool
|
141
|
+
Whether the audio file should start playing automatically. This is
|
142
|
+
``False`` by default. Browsers will not autoplay audio files if the
|
143
|
+
user has not interacted with the page by clicking somewhere.
|
144
|
+
|
145
|
+
Examples
|
146
|
+
--------
|
147
|
+
To display an audio player for a local file, specify the file's string
|
148
|
+
path and format.
|
149
|
+
|
150
|
+
>>> import streamlit as st
|
151
|
+
>>>
|
152
|
+
>>> st.audio("cat-purr.mp3", format="audio/mpeg", loop=True)
|
153
|
+
|
154
|
+
.. output::
|
155
|
+
https://doc-audio-purr.streamlit.app/
|
156
|
+
height: 250px
|
157
|
+
|
158
|
+
You can also pass ``bytes`` or ``numpy.ndarray`` objects to ``st.audio``.
|
159
|
+
|
160
|
+
>>> import streamlit as st
|
161
|
+
>>> import numpy as np
|
162
|
+
>>>
|
163
|
+
>>> audio_file = open("myaudio.ogg", "rb")
|
164
|
+
>>> audio_bytes = audio_file.read()
|
165
|
+
>>>
|
166
|
+
>>> st.audio(audio_bytes, format="audio/ogg")
|
167
|
+
>>>
|
168
|
+
>>> sample_rate = 44100 # 44100 samples per second
|
169
|
+
>>> seconds = 2 # Note duration of 2 seconds
|
170
|
+
>>> frequency_la = 440 # Our played note will be 440 Hz
|
171
|
+
>>> # Generate array with seconds*sample_rate steps, ranging between 0 and seconds
|
172
|
+
>>> t = np.linspace(0, seconds, seconds * sample_rate, False)
|
173
|
+
>>> # Generate a 440 Hz sine wave
|
174
|
+
>>> note_la = np.sin(frequency_la * t * 2 * np.pi)
|
175
|
+
>>>
|
176
|
+
>>> st.audio(note_la, sample_rate=sample_rate)
|
177
|
+
|
178
|
+
.. output::
|
179
|
+
https://doc-audio.streamlit.app/
|
180
|
+
height: 865px
|
181
|
+
|
182
|
+
"""
|
183
|
+
start_time, end_time = _parse_start_time_end_time(start_time, end_time)
|
184
|
+
|
185
|
+
audio_proto = AudioProto()
|
186
|
+
|
187
|
+
is_data_numpy_array = type_util.is_type(data, "numpy.ndarray")
|
188
|
+
|
189
|
+
if is_data_numpy_array and sample_rate is None:
|
190
|
+
raise StreamlitAPIException(
|
191
|
+
"`sample_rate` must be specified when `data` is a numpy array."
|
192
|
+
)
|
193
|
+
if not is_data_numpy_array and sample_rate is not None:
|
194
|
+
self.dg.warning(
|
195
|
+
"Warning: `sample_rate` will be ignored since data is not a numpy "
|
196
|
+
"array."
|
197
|
+
)
|
198
|
+
coordinates = self.dg._get_delta_path_str()
|
199
|
+
marshall_audio(
|
200
|
+
coordinates,
|
201
|
+
audio_proto,
|
202
|
+
data,
|
203
|
+
format,
|
204
|
+
start_time,
|
205
|
+
sample_rate,
|
206
|
+
end_time,
|
207
|
+
loop,
|
208
|
+
autoplay,
|
209
|
+
form_id=current_form_id(self.dg),
|
210
|
+
)
|
211
|
+
return self.dg._enqueue("audio", audio_proto)
|
212
|
+
|
213
|
+
@gather_metrics("video")
|
214
|
+
def video(
|
215
|
+
self,
|
216
|
+
data: MediaData,
|
217
|
+
format: str = "video/mp4",
|
218
|
+
start_time: MediaTime = 0,
|
219
|
+
*, # keyword-only arguments:
|
220
|
+
subtitles: SubtitleData = None,
|
221
|
+
end_time: MediaTime | None = None,
|
222
|
+
loop: bool = False,
|
223
|
+
autoplay: bool = False,
|
224
|
+
muted: bool = False,
|
225
|
+
) -> DeltaGenerator:
|
226
|
+
"""Display a video player.
|
227
|
+
|
228
|
+
Parameters
|
229
|
+
----------
|
230
|
+
data : str, Path, bytes, io.BytesIO, numpy.ndarray, or file
|
231
|
+
The video to play. This can be one of the following:
|
232
|
+
|
233
|
+
- A URL (string) for a hosted video file, including YouTube URLs.
|
234
|
+
- A path to a local video file. The path can be a ``str``
|
235
|
+
or ``Path`` object. Paths can be absolute or relative to the
|
236
|
+
working directory (where you execute ``streamlit run``).
|
237
|
+
- Raw video data. Raw data formats must include all necessary file
|
238
|
+
headers to match the file format specified via ``format``.
|
239
|
+
|
240
|
+
format : str
|
241
|
+
The MIME type for the video file. This defaults to ``"video/mp4"``.
|
242
|
+
For more information about MIME types, see
|
243
|
+
https://www.iana.org/assignments/media-types/media-types.xhtml.
|
244
|
+
|
245
|
+
start_time: int, float, timedelta, str, or None
|
246
|
+
The time from which the element should start playing. This can be
|
247
|
+
one of the following:
|
248
|
+
|
249
|
+
- ``None`` (default): The element plays from the beginning.
|
250
|
+
- An ``int`` or ``float`` specifying the time in seconds. ``float``
|
251
|
+
values are rounded down to whole seconds.
|
252
|
+
- A string specifying the time in a format supported by `Pandas'
|
253
|
+
Timedelta constructor <https://pandas.pydata.org/docs/reference/api/pandas.Timedelta.html>`_,
|
254
|
+
e.g. ``"2 minute"``, ``"20s"``, or ``"1m14s"``.
|
255
|
+
- A ``timedelta`` object from `Python's built-in datetime library
|
256
|
+
<https://docs.python.org/3/library/datetime.html#timedelta-objects>`_,
|
257
|
+
e.g. ``timedelta(seconds=70)``.
|
258
|
+
subtitles: str, bytes, Path, io.BytesIO, or dict
|
259
|
+
Optional subtitle data for the video, supporting several input types:
|
260
|
+
|
261
|
+
- ``None`` (default): No subtitles.
|
262
|
+
|
263
|
+
- A string, bytes, or Path: File path to a subtitle file in
|
264
|
+
``.vtt`` or ``.srt`` formats, or the raw content of subtitles
|
265
|
+
conforming to these formats. Paths can be absolute or relative to
|
266
|
+
the working directory (where you execute ``streamlit run``).
|
267
|
+
If providing raw content, the string must adhere to the WebVTT or
|
268
|
+
SRT format specifications.
|
269
|
+
|
270
|
+
- io.BytesIO: A BytesIO stream that contains valid ``.vtt`` or ``.srt``
|
271
|
+
formatted subtitle data.
|
272
|
+
|
273
|
+
- A dictionary: Pairs of labels and file paths or raw subtitle content in
|
274
|
+
``.vtt`` or ``.srt`` formats to enable multiple subtitle tracks.
|
275
|
+
The label will be shown in the video player. Example:
|
276
|
+
``{"English": "path/to/english.vtt", "French": "path/to/french.srt"}``
|
277
|
+
|
278
|
+
When provided, subtitles are displayed by default. For multiple
|
279
|
+
tracks, the first one is displayed by default. If you don't want any
|
280
|
+
subtitles displayed by default, use an empty string for the value
|
281
|
+
in a dictrionary's first pair: ``{"None": "", "English": "path/to/english.vtt"}``
|
282
|
+
|
283
|
+
Not supported for YouTube videos.
|
284
|
+
end_time: int, float, timedelta, str, or None
|
285
|
+
The time at which the element should stop playing. This can be
|
286
|
+
one of the following:
|
287
|
+
|
288
|
+
- ``None`` (default): The element plays through to the end.
|
289
|
+
- An ``int`` or ``float`` specifying the time in seconds. ``float``
|
290
|
+
values are rounded down to whole seconds.
|
291
|
+
- A string specifying the time in a format supported by `Pandas'
|
292
|
+
Timedelta constructor <https://pandas.pydata.org/docs/reference/api/pandas.Timedelta.html>`_,
|
293
|
+
e.g. ``"2 minute"``, ``"20s"``, or ``"1m14s"``.
|
294
|
+
- A ``timedelta`` object from `Python's built-in datetime library
|
295
|
+
<https://docs.python.org/3/library/datetime.html#timedelta-objects>`_,
|
296
|
+
e.g. ``timedelta(seconds=70)``.
|
297
|
+
loop: bool
|
298
|
+
Whether the video should loop playback.
|
299
|
+
autoplay: bool
|
300
|
+
Whether the video should start playing automatically. This is
|
301
|
+
``False`` by default. Browsers will not autoplay unmuted videos
|
302
|
+
if the user has not interacted with the page by clicking somewhere.
|
303
|
+
To enable autoplay without user interaction, you must also set
|
304
|
+
``muted=True``.
|
305
|
+
muted: bool
|
306
|
+
Whether the video should play with the audio silenced. This is
|
307
|
+
``False`` by default. Use this in conjunction with ``autoplay=True``
|
308
|
+
to enable autoplay without user interaction.
|
309
|
+
|
310
|
+
Example
|
311
|
+
-------
|
312
|
+
>>> import streamlit as st
|
313
|
+
>>>
|
314
|
+
>>> video_file = open("myvideo.mp4", "rb")
|
315
|
+
>>> video_bytes = video_file.read()
|
316
|
+
>>>
|
317
|
+
>>> st.video(video_bytes)
|
318
|
+
|
319
|
+
.. output::
|
320
|
+
https://doc-video.streamlit.app/
|
321
|
+
height: 700px
|
322
|
+
|
323
|
+
When you include subtitles, they will be turned on by default. A viewer
|
324
|
+
can turn off the subtitles (or captions) from the browser's default video
|
325
|
+
control menu, usually located in the lower-right corner of the video.
|
326
|
+
|
327
|
+
Here is a simple VTT file (``subtitles.vtt``):
|
328
|
+
|
329
|
+
>>> WEBVTT
|
330
|
+
>>>
|
331
|
+
>>> 0:00:01.000 --> 0:00:02.000
|
332
|
+
>>> Look!
|
333
|
+
>>>
|
334
|
+
>>> 0:00:03.000 --> 0:00:05.000
|
335
|
+
>>> Look at the pretty stars!
|
336
|
+
|
337
|
+
If the above VTT file lives in the same directory as your app, you can
|
338
|
+
add subtitles like so:
|
339
|
+
|
340
|
+
>>> import streamlit as st
|
341
|
+
>>>
|
342
|
+
>>> VIDEO_URL = "https://example.com/not-youtube.mp4"
|
343
|
+
>>> st.video(VIDEO_URL, subtitles="subtitles.vtt")
|
344
|
+
|
345
|
+
.. output::
|
346
|
+
https://doc-video-subtitles.streamlit.app/
|
347
|
+
height: 700px
|
348
|
+
|
349
|
+
See additional examples of supported subtitle input types in our
|
350
|
+
`video subtitles feature demo <https://doc-video-subtitle-inputs.streamlit.app/>`_.
|
351
|
+
|
352
|
+
.. note::
|
353
|
+
Some videos may not display if they are encoded using MP4V (which is an export option in OpenCV), as this codec is
|
354
|
+
not widely supported by browsers. Converting your video to H.264 will allow the video to be displayed in Streamlit.
|
355
|
+
See this `StackOverflow post <https://stackoverflow.com/a/49535220/2394542>`_ or this
|
356
|
+
`Streamlit forum post <https://discuss.streamlit.io/t/st-video-doesnt-show-opencv-generated-mp4/3193/2>`_
|
357
|
+
for more information.
|
358
|
+
|
359
|
+
"""
|
360
|
+
start_time, end_time = _parse_start_time_end_time(start_time, end_time)
|
361
|
+
|
362
|
+
video_proto = VideoProto()
|
363
|
+
coordinates = self.dg._get_delta_path_str()
|
364
|
+
marshall_video(
|
365
|
+
coordinates,
|
366
|
+
video_proto,
|
367
|
+
data,
|
368
|
+
format,
|
369
|
+
start_time,
|
370
|
+
subtitles,
|
371
|
+
end_time,
|
372
|
+
loop,
|
373
|
+
autoplay,
|
374
|
+
muted,
|
375
|
+
form_id=current_form_id(self.dg),
|
376
|
+
)
|
377
|
+
return self.dg._enqueue("video", video_proto)
|
378
|
+
|
379
|
+
@property
|
380
|
+
def dg(self) -> DeltaGenerator:
|
381
|
+
"""Get our DeltaGenerator."""
|
382
|
+
return cast("DeltaGenerator", self)
|
383
|
+
|
384
|
+
|
385
|
+
# Regular expression from
|
386
|
+
# https://gist.github.com/rodrigoborgesdeoliveira/987683cfbfcc8d800192da1e73adc486?permalink_comment_id=4645864#gistcomment-4645864
|
387
|
+
# Covers any youtube URL (incl. shortlinks and embed links) and extracts its video code.
|
388
|
+
YOUTUBE_RE: Final = r"^((https?://(?:www\.)?(?:m\.)?youtube\.com))/((?:oembed\?url=https?%3A//(?:www\.)youtube.com/watch\?(?:v%3D)(?P<video_id_1>[\w\-]{10,20})&format=json)|(?:attribution_link\?a=.*watch(?:%3Fv%3D|%3Fv%3D)(?P<video_id_2>[\w\-]{10,20}))(?:%26feature.*))|(https?:)?(\/\/)?((www\.|m\.)?youtube(-nocookie)?\.com\/((watch)?\?(app=desktop&)?(feature=\w*&)?v=|embed\/|v\/|e\/)|youtu\.be\/)(?P<video_id_3>[\w\-]{10,20})"
|
389
|
+
|
390
|
+
|
391
|
+
def _reshape_youtube_url(url: str) -> str | None:
|
392
|
+
"""Return whether URL is any kind of YouTube embed or watch link. If so,
|
393
|
+
reshape URL into an embed link suitable for use in an iframe.
|
394
|
+
|
395
|
+
If not a YouTube URL, return None.
|
396
|
+
|
397
|
+
Parameters
|
398
|
+
----------
|
399
|
+
url : str
|
400
|
+
|
401
|
+
Example
|
402
|
+
-------
|
403
|
+
>>> print(_reshape_youtube_url("https://youtu.be/_T8LGqJtuGc"))
|
404
|
+
|
405
|
+
.. output::
|
406
|
+
https://www.youtube.com/embed/_T8LGqJtuGc
|
407
|
+
"""
|
408
|
+
match = re.match(YOUTUBE_RE, url)
|
409
|
+
if match:
|
410
|
+
code = (
|
411
|
+
match.group("video_id_1")
|
412
|
+
or match.group("video_id_2")
|
413
|
+
or match.group("video_id_3")
|
414
|
+
)
|
415
|
+
return f"https://www.youtube.com/embed/{code}"
|
416
|
+
return None
|
417
|
+
|
418
|
+
|
419
|
+
def _marshall_av_media(
|
420
|
+
coordinates: str,
|
421
|
+
proto: AudioProto | VideoProto,
|
422
|
+
data: MediaData,
|
423
|
+
mimetype: str,
|
424
|
+
) -> None:
|
425
|
+
"""Fill audio or video proto based on contents of data.
|
426
|
+
|
427
|
+
Given a string, check if it's a url; if so, send it out without modification.
|
428
|
+
Otherwise assume strings are filenames and let any OS errors raise.
|
429
|
+
|
430
|
+
Load data either from file or through bytes-processing methods into a
|
431
|
+
MediaFile object. Pack proto with generated Tornado-based URL.
|
432
|
+
|
433
|
+
(When running in "raw" mode, we won't actually load data into the
|
434
|
+
MediaFileManager, and we'll return an empty URL.)
|
435
|
+
"""
|
436
|
+
# Audio and Video methods have already checked if this is a URL by this point.
|
437
|
+
|
438
|
+
if data is None:
|
439
|
+
# Allow empty values so media players can be shown without media.
|
440
|
+
return
|
441
|
+
|
442
|
+
data_or_filename: bytes | str
|
443
|
+
if isinstance(data, (str, bytes)):
|
444
|
+
# Pass strings and bytes through unchanged
|
445
|
+
data_or_filename = data
|
446
|
+
elif isinstance(data, Path):
|
447
|
+
data_or_filename = str(data)
|
448
|
+
elif isinstance(data, io.BytesIO):
|
449
|
+
data.seek(0)
|
450
|
+
data_or_filename = data.getvalue()
|
451
|
+
elif isinstance(data, io.RawIOBase) or isinstance(data, io.BufferedReader):
|
452
|
+
data.seek(0)
|
453
|
+
read_data = data.read()
|
454
|
+
if read_data is None:
|
455
|
+
return
|
456
|
+
else:
|
457
|
+
data_or_filename = read_data
|
458
|
+
elif type_util.is_type(data, "numpy.ndarray"):
|
459
|
+
data_or_filename = data.tobytes()
|
460
|
+
else:
|
461
|
+
raise RuntimeError("Invalid binary data format: %s" % type(data))
|
462
|
+
|
463
|
+
if runtime.exists():
|
464
|
+
file_url = runtime.get_instance().media_file_mgr.add(
|
465
|
+
data_or_filename, mimetype, coordinates
|
466
|
+
)
|
467
|
+
caching.save_media_data(data_or_filename, mimetype, coordinates)
|
468
|
+
else:
|
469
|
+
# When running in "raw mode", we can't access the MediaFileManager.
|
470
|
+
file_url = ""
|
471
|
+
|
472
|
+
proto.url = file_url
|
473
|
+
|
474
|
+
|
475
|
+
def marshall_video(
|
476
|
+
coordinates: str,
|
477
|
+
proto: VideoProto,
|
478
|
+
data: MediaData,
|
479
|
+
mimetype: str = "video/mp4",
|
480
|
+
start_time: int = 0,
|
481
|
+
subtitles: SubtitleData = None,
|
482
|
+
end_time: int | None = None,
|
483
|
+
loop: bool = False,
|
484
|
+
autoplay: bool = False,
|
485
|
+
muted: bool = False,
|
486
|
+
form_id: str | None = None,
|
487
|
+
) -> None:
|
488
|
+
"""Marshalls a video proto, using url processors as needed.
|
489
|
+
|
490
|
+
Parameters
|
491
|
+
----------
|
492
|
+
coordinates : str
|
493
|
+
proto : the proto to fill. Must have a string field called "data".
|
494
|
+
data : str, Path, bytes, BytesIO, numpy.ndarray, or file opened with
|
495
|
+
io.open().
|
496
|
+
Raw video data or a string with a URL pointing to the video
|
497
|
+
to load. Includes support for YouTube URLs.
|
498
|
+
If passing the raw data, this must include headers and any other
|
499
|
+
bytes required in the actual file.
|
500
|
+
mimetype : str
|
501
|
+
The mime type for the video file. Defaults to 'video/mp4'.
|
502
|
+
See https://tools.ietf.org/html/rfc4281 for more info.
|
503
|
+
start_time : int
|
504
|
+
The time from which this element should start playing. (default: 0)
|
505
|
+
subtitles: str, dict, or io.BytesIO
|
506
|
+
Optional subtitle data for the video, supporting several input types:
|
507
|
+
- None (default): No subtitles.
|
508
|
+
- A string: File path to a subtitle file in '.vtt' or '.srt' formats, or the raw content of subtitles conforming to these formats.
|
509
|
+
If providing raw content, the string must adhere to the WebVTT or SRT format specifications.
|
510
|
+
- A dictionary: Pairs of labels and file paths or raw subtitle content in '.vtt' or '.srt' formats.
|
511
|
+
Enables multiple subtitle tracks. The label will be shown in the video player.
|
512
|
+
Example: {'English': 'path/to/english.vtt', 'French': 'path/to/french.srt'}
|
513
|
+
- io.BytesIO: A BytesIO stream that contains valid '.vtt' or '.srt' formatted subtitle data.
|
514
|
+
When provided, subtitles are displayed by default. For multiple tracks, the first one is displayed by default.
|
515
|
+
Not supported for YouTube videos.
|
516
|
+
end_time: int
|
517
|
+
The time at which this element should stop playing
|
518
|
+
loop: bool
|
519
|
+
Whether the video should loop playback.
|
520
|
+
autoplay: bool
|
521
|
+
Whether the video should start playing automatically.
|
522
|
+
Browsers will not autoplay video files if the user has not interacted with
|
523
|
+
the page yet, for example by clicking on the page while it loads.
|
524
|
+
To enable autoplay without user interaction, you can set muted=True.
|
525
|
+
Defaults to False.
|
526
|
+
muted: bool
|
527
|
+
Whether the video should play with the audio silenced. This can be used to
|
528
|
+
enable autoplay without user interaction. Defaults to False.
|
529
|
+
form_id: str | None
|
530
|
+
The ID of the form that this element is placed in. Provide None if
|
531
|
+
the element is not placed in a form.
|
532
|
+
"""
|
533
|
+
|
534
|
+
if start_time < 0 or (end_time is not None and end_time <= start_time):
|
535
|
+
raise StreamlitAPIException("Invalid start_time and end_time combination.")
|
536
|
+
|
537
|
+
proto.start_time = start_time
|
538
|
+
proto.muted = muted
|
539
|
+
|
540
|
+
if end_time is not None:
|
541
|
+
proto.end_time = end_time
|
542
|
+
proto.loop = loop
|
543
|
+
|
544
|
+
# "type" distinguishes between YouTube and non-YouTube links
|
545
|
+
proto.type = VideoProto.Type.NATIVE
|
546
|
+
|
547
|
+
if isinstance(data, Path):
|
548
|
+
data = str(data) # Convert Path to string
|
549
|
+
|
550
|
+
if isinstance(data, str) and url_util.is_url(
|
551
|
+
data, allowed_schemas=("http", "https", "data")
|
552
|
+
):
|
553
|
+
if youtube_url := _reshape_youtube_url(data):
|
554
|
+
proto.url = youtube_url
|
555
|
+
proto.type = VideoProto.Type.YOUTUBE_IFRAME
|
556
|
+
if subtitles:
|
557
|
+
raise StreamlitAPIException(
|
558
|
+
"Subtitles are not supported for YouTube videos."
|
559
|
+
)
|
560
|
+
else:
|
561
|
+
proto.url = data
|
562
|
+
else:
|
563
|
+
_marshall_av_media(coordinates, proto, data, mimetype)
|
564
|
+
|
565
|
+
if subtitles:
|
566
|
+
subtitle_items: list[tuple[str, str | Path | bytes | io.BytesIO]] = []
|
567
|
+
|
568
|
+
# Single subtitle
|
569
|
+
if isinstance(subtitles, (str, bytes, io.BytesIO, Path)):
|
570
|
+
subtitle_items.append(("default", subtitles))
|
571
|
+
# Multiple subtitles
|
572
|
+
elif isinstance(subtitles, dict):
|
573
|
+
subtitle_items.extend(subtitles.items())
|
574
|
+
else:
|
575
|
+
raise StreamlitAPIException(
|
576
|
+
f"Unsupported data type for subtitles: {type(subtitles)}. "
|
577
|
+
f"Only str (file paths) and dict are supported."
|
578
|
+
)
|
579
|
+
|
580
|
+
for label, subtitle_data in subtitle_items:
|
581
|
+
sub = proto.subtitles.add()
|
582
|
+
sub.label = label or ""
|
583
|
+
|
584
|
+
# Coordinates used in media_file_manager to identify the place of
|
585
|
+
# element, in case of subtitle, we use same video coordinates
|
586
|
+
# with suffix.
|
587
|
+
# It is not aligned with common coordinates format, but in
|
588
|
+
# media_file_manager we use it just as unique identifier, so it is fine.
|
589
|
+
subtitle_coordinates = f"{coordinates}[subtitle{label}]"
|
590
|
+
try:
|
591
|
+
sub.url = process_subtitle_data(
|
592
|
+
subtitle_coordinates, subtitle_data, label
|
593
|
+
)
|
594
|
+
except (TypeError, ValueError) as original_err:
|
595
|
+
raise StreamlitAPIException(
|
596
|
+
f"Failed to process the provided subtitle: {label}"
|
597
|
+
) from original_err
|
598
|
+
|
599
|
+
if autoplay:
|
600
|
+
proto.autoplay = autoplay
|
601
|
+
proto.id = compute_and_register_element_id(
|
602
|
+
"video",
|
603
|
+
# video does not yet allow setting a user-defined key
|
604
|
+
user_key=None,
|
605
|
+
form_id=form_id,
|
606
|
+
url=proto.url,
|
607
|
+
mimetype=mimetype,
|
608
|
+
start_time=start_time,
|
609
|
+
end_time=end_time,
|
610
|
+
loop=loop,
|
611
|
+
autoplay=autoplay,
|
612
|
+
muted=muted,
|
613
|
+
)
|
614
|
+
|
615
|
+
|
616
|
+
def _parse_start_time_end_time(
|
617
|
+
start_time: MediaTime, end_time: MediaTime | None
|
618
|
+
) -> tuple[int, int | None]:
|
619
|
+
"""Parse start_time and end_time and return them as int."""
|
620
|
+
|
621
|
+
try:
|
622
|
+
maybe_start_time = time_to_seconds(start_time, coerce_none_to_inf=False)
|
623
|
+
if maybe_start_time is None:
|
624
|
+
raise ValueError
|
625
|
+
start_time = int(maybe_start_time)
|
626
|
+
except (StreamlitAPIException, ValueError):
|
627
|
+
error_msg = TIMEDELTA_PARSE_ERROR_MESSAGE.format(
|
628
|
+
param_name="start_time", param_value=start_time
|
629
|
+
)
|
630
|
+
raise StreamlitAPIException(error_msg) from None
|
631
|
+
|
632
|
+
try:
|
633
|
+
end_time = time_to_seconds(end_time, coerce_none_to_inf=False)
|
634
|
+
if end_time is not None:
|
635
|
+
end_time = int(end_time)
|
636
|
+
except StreamlitAPIException:
|
637
|
+
error_msg = TIMEDELTA_PARSE_ERROR_MESSAGE.format(
|
638
|
+
param_name="end_time", param_value=end_time
|
639
|
+
)
|
640
|
+
raise StreamlitAPIException(error_msg) from None
|
641
|
+
|
642
|
+
return start_time, end_time
|
643
|
+
|
644
|
+
|
645
|
+
def _validate_and_normalize(data: npt.NDArray[Any]) -> tuple[bytes, int]:
|
646
|
+
"""Validates and normalizes numpy array data.
|
647
|
+
We validate numpy array shape (should be 1d or 2d)
|
648
|
+
We normalize input data to int16 [-32768, 32767] range.
|
649
|
+
|
650
|
+
Parameters
|
651
|
+
----------
|
652
|
+
data : numpy array
|
653
|
+
numpy array to be validated and normalized
|
654
|
+
|
655
|
+
Returns
|
656
|
+
-------
|
657
|
+
Tuple of (bytes, int)
|
658
|
+
(bytes, nchan)
|
659
|
+
where
|
660
|
+
- bytes : bytes of normalized numpy array converted to int16
|
661
|
+
- nchan : number of channels for audio signal. 1 for mono, or 2 for stereo.
|
662
|
+
"""
|
663
|
+
# we import numpy here locally to import it only when needed (when numpy array given
|
664
|
+
# to st.audio data)
|
665
|
+
import numpy as np
|
666
|
+
|
667
|
+
transformed_data: npt.NDArray[Any] = np.array(data, dtype=float)
|
668
|
+
|
669
|
+
if len(cast(NumpyShape, transformed_data.shape)) == 1:
|
670
|
+
nchan = 1
|
671
|
+
elif len(transformed_data.shape) == 2:
|
672
|
+
# In wave files,channels are interleaved. E.g.,
|
673
|
+
# "L1R1L2R2..." for stereo. See
|
674
|
+
# http://msdn.microsoft.com/en-us/library/windows/hardware/dn653308(v=vs.85).aspx
|
675
|
+
# for channel ordering
|
676
|
+
nchan = transformed_data.shape[0]
|
677
|
+
transformed_data = transformed_data.T.ravel()
|
678
|
+
else:
|
679
|
+
raise StreamlitAPIException("Numpy array audio input must be a 1D or 2D array.")
|
680
|
+
|
681
|
+
if transformed_data.size == 0:
|
682
|
+
return transformed_data.astype(np.int16).tobytes(), nchan
|
683
|
+
|
684
|
+
max_abs_value = np.max(np.abs(transformed_data))
|
685
|
+
# 16-bit samples are stored as 2's-complement signed integers,
|
686
|
+
# ranging from -32768 to 32767.
|
687
|
+
# scaled_data is PCM 16 bit numpy array, that's why we multiply [-1, 1] float
|
688
|
+
# values to 32_767 == 2 ** 15 - 1.
|
689
|
+
np_array = (transformed_data / max_abs_value) * 32767
|
690
|
+
scaled_data = np_array.astype(np.int16)
|
691
|
+
return scaled_data.tobytes(), nchan
|
692
|
+
|
693
|
+
|
694
|
+
def _make_wav(data: npt.NDArray[Any], sample_rate: int) -> bytes:
|
695
|
+
"""
|
696
|
+
Transform a numpy array to a PCM bytestring
|
697
|
+
We use code from IPython display module to convert numpy array to wave bytes
|
698
|
+
https://github.com/ipython/ipython/blob/1015c392f3d50cf4ff3e9f29beede8c1abfdcb2a/IPython/lib/display.py#L146
|
699
|
+
"""
|
700
|
+
# we import wave here locally to import it only when needed (when numpy array given
|
701
|
+
# to st.audio data)
|
702
|
+
import wave
|
703
|
+
|
704
|
+
scaled, nchan = _validate_and_normalize(data)
|
705
|
+
|
706
|
+
with io.BytesIO() as fp, wave.open(fp, mode="wb") as waveobj:
|
707
|
+
waveobj.setnchannels(nchan)
|
708
|
+
waveobj.setframerate(sample_rate)
|
709
|
+
waveobj.setsampwidth(2)
|
710
|
+
waveobj.setcomptype("NONE", "NONE")
|
711
|
+
waveobj.writeframes(scaled)
|
712
|
+
return fp.getvalue()
|
713
|
+
|
714
|
+
|
715
|
+
def _maybe_convert_to_wav_bytes(data: MediaData, sample_rate: int | None) -> MediaData:
|
716
|
+
"""Convert data to wav bytes if the data type is numpy array."""
|
717
|
+
if type_util.is_type(data, "numpy.ndarray") and sample_rate is not None:
|
718
|
+
data = _make_wav(cast("npt.NDArray[Any]", data), sample_rate)
|
719
|
+
return data
|
720
|
+
|
721
|
+
|
722
|
+
def marshall_audio(
|
723
|
+
coordinates: str,
|
724
|
+
proto: AudioProto,
|
725
|
+
data: MediaData,
|
726
|
+
mimetype: str = "audio/wav",
|
727
|
+
start_time: int = 0,
|
728
|
+
sample_rate: int | None = None,
|
729
|
+
end_time: int | None = None,
|
730
|
+
loop: bool = False,
|
731
|
+
autoplay: bool = False,
|
732
|
+
form_id: str | None = None,
|
733
|
+
) -> None:
|
734
|
+
"""Marshalls an audio proto, using data and url processors as needed.
|
735
|
+
|
736
|
+
Parameters
|
737
|
+
----------
|
738
|
+
coordinates : str
|
739
|
+
proto : The proto to fill. Must have a string field called "url".
|
740
|
+
data : str, Path, bytes, BytesIO, numpy.ndarray, or file opened with
|
741
|
+
io.open()
|
742
|
+
Raw audio data or a string with a URL pointing to the file to load.
|
743
|
+
If passing the raw data, this must include headers and any other bytes
|
744
|
+
required in the actual file.
|
745
|
+
mimetype : str
|
746
|
+
The mime type for the audio file. Defaults to "audio/wav".
|
747
|
+
See https://tools.ietf.org/html/rfc4281 for more info.
|
748
|
+
start_time : int
|
749
|
+
The time from which this element should start playing. (default: 0)
|
750
|
+
sample_rate: int or None
|
751
|
+
Optional param to provide sample_rate in case of numpy array
|
752
|
+
end_time: int
|
753
|
+
The time at which this element should stop playing
|
754
|
+
loop: bool
|
755
|
+
Whether the audio should loop playback.
|
756
|
+
autoplay : bool
|
757
|
+
Whether the audio should start playing automatically.
|
758
|
+
Browsers will not autoplay audio files if the user has not interacted with the page yet.
|
759
|
+
form_id: str | None
|
760
|
+
The ID of the form that this element is placed in. Provide None if
|
761
|
+
the element is not placed in a form.
|
762
|
+
"""
|
763
|
+
|
764
|
+
proto.start_time = start_time
|
765
|
+
if end_time is not None:
|
766
|
+
proto.end_time = end_time
|
767
|
+
proto.loop = loop
|
768
|
+
|
769
|
+
if isinstance(data, Path):
|
770
|
+
data = str(data) # Convert Path to string
|
771
|
+
|
772
|
+
if isinstance(data, str) and url_util.is_url(
|
773
|
+
data, allowed_schemas=("http", "https", "data")
|
774
|
+
):
|
775
|
+
proto.url = data
|
776
|
+
else:
|
777
|
+
data = _maybe_convert_to_wav_bytes(data, sample_rate)
|
778
|
+
_marshall_av_media(coordinates, proto, data, mimetype)
|
779
|
+
|
780
|
+
if autoplay:
|
781
|
+
proto.autoplay = autoplay
|
782
|
+
proto.id = compute_and_register_element_id(
|
783
|
+
"audio",
|
784
|
+
user_key=None,
|
785
|
+
form_id=form_id,
|
786
|
+
url=proto.url,
|
787
|
+
mimetype=mimetype,
|
788
|
+
start_time=start_time,
|
789
|
+
sample_rate=sample_rate,
|
790
|
+
end_time=end_time,
|
791
|
+
loop=loop,
|
792
|
+
autoplay=autoplay,
|
793
|
+
)
|