streamlit-nightly 1.52.3.dev20260108__py3-none-any.whl → 1.52.3.dev20260110__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.
Files changed (123) hide show
  1. streamlit/components/v2/__init__.py +3 -3
  2. streamlit/components/v2/types.py +4 -4
  3. streamlit/config.py +14 -0
  4. streamlit/elements/lib/options_selector_utils.py +98 -0
  5. streamlit/elements/widgets/multiselect.py +19 -9
  6. streamlit/elements/widgets/selectbox.py +12 -24
  7. streamlit/proto/MetricsEvent_pb2.py +4 -4
  8. streamlit/proto/MetricsEvent_pb2.pyi +4 -1
  9. streamlit/proto/PageProfile_pb2.py +6 -6
  10. streamlit/proto/PageProfile_pb2.pyi +11 -1
  11. streamlit/runtime/metrics_util.py +4 -0
  12. streamlit/runtime/runtime.py +3 -0
  13. streamlit/starlette.py +34 -0
  14. streamlit/static/index.html +1 -1
  15. streamlit/static/manifest.json +300 -300
  16. streamlit/static/static/js/{ErrorOutline.esm.j3b3OjAK.js → ErrorOutline.esm.BcqUpfNe.js} +1 -1
  17. streamlit/static/static/js/{FileDownload.esm.DCizXv6Q.js → FileDownload.esm.CtJWBuub.js} +1 -1
  18. streamlit/static/static/js/{FileHelper.EpMV5UVe.js → FileHelper.D0dQPhOs.js} +1 -1
  19. streamlit/static/static/js/{FormClearHelper.lF7Ran5M.js → FormClearHelper.Cm3GDSk6.js} +1 -1
  20. streamlit/static/static/js/{InputInstructions.CMvqhPhy.js → InputInstructions.D7Hxdzwv.js} +1 -1
  21. streamlit/static/static/js/{Particles.DsGe8psi.js → Particles.vAUDtAR8.js} +1 -1
  22. streamlit/static/static/js/{ProgressBar.DzoKn4D-.js → ProgressBar.Dp2CGRba.js} +2 -2
  23. streamlit/static/static/js/{StreamlitSyntaxHighlighter.CFab0b_b.js → StreamlitSyntaxHighlighter.DC0000nJ.js} +1 -1
  24. streamlit/static/static/js/{TableChart.esm.nZsTq1Sb.js → TableChart.esm.DDVoSKOT.js} +1 -1
  25. streamlit/static/static/js/{Toolbar.CFMvwQYl.js → Toolbar.CuMH-Gqe.js} +1 -1
  26. streamlit/static/static/js/{WidgetLabelHelpIconInline.D2EEUEQX.js → WidgetLabelHelpIconInline.WAReecol.js} +1 -1
  27. streamlit/static/static/js/{base-input.DKTA2QNz.js → base-input.BX9Jll5o.js} +4 -4
  28. streamlit/static/static/js/{checkbox.D9H9J-_W.js → checkbox.BzMHUSz1.js} +1 -1
  29. streamlit/static/static/js/{createDownloadLinkElement.DCk6EhPM.js → createDownloadLinkElement.CviG5BQx.js} +1 -1
  30. streamlit/static/static/js/{data-grid-overlay-editor.DExrGdqs.js → data-grid-overlay-editor.Dzo9A4l6.js} +1 -1
  31. streamlit/static/static/js/{downloader.CLJ7BreF.js → downloader.DIDvj0d5.js} +1 -1
  32. streamlit/static/static/js/{embed.CxOHZWx2.js → embed.C8qeQ38b.js} +6 -6
  33. streamlit/static/static/js/{es6.C99ebre4.js → es6.Dpcc-U7U.js} +2 -2
  34. streamlit/static/static/js/{formatNumber.D_w4fBsk.js → formatNumber.CPvuaBa8.js} +1 -1
  35. streamlit/static/static/js/{iconPosition.Cfhw1RkE.js → iconPosition.y0q-Rqem.js} +1 -1
  36. streamlit/static/static/js/{iframeResizer.contentWindow.BcWUIYOe.js → iframeResizer.contentWindow.DblExdXF.js} +1 -1
  37. streamlit/static/static/js/{index.BWK_h3IL.js → index.B-g6lwYa.js} +1 -1
  38. streamlit/static/static/js/{index.DoLorXMA.js → index.B10MmI2m.js} +1 -1
  39. streamlit/static/static/js/{index.Dx8TcTHV.js → index.B6vCS66f.js} +6 -6
  40. streamlit/static/static/js/{index.Bp_LrAiI.js → index.B9TG5Ah8.js} +1 -1
  41. streamlit/static/static/js/{index.CrJ9KZpt.js → index.BDb0PRvK.js} +1 -1
  42. streamlit/static/static/js/{index.1AemKTSK.js → index.BGufEmCz.js} +1 -1
  43. streamlit/static/static/js/{index.7Q3Iaebc.js → index.BItU4jMo.js} +1 -1
  44. streamlit/static/static/js/{index.D18KqoUa.js → index.BPMqWDef.js} +1 -1
  45. streamlit/static/static/js/index.BTHi5W25.js +1 -0
  46. streamlit/static/static/js/{index.BHx4Qw7z.js → index.BVN9cI-k.js} +1 -1
  47. streamlit/static/static/js/index.BWOP7HFT.js +1 -0
  48. streamlit/static/static/js/{index.DDx6TP95.js → index.BXYgO5B8.js} +1 -1
  49. streamlit/static/static/js/{index.DkSjHoXw.js → index.BZBWLU1C.js} +8 -8
  50. streamlit/static/static/js/{index.f_s01aPm.js → index.BfZdZpv-.js} +2 -2
  51. streamlit/static/static/js/{index.C7_5JMRC.js → index.Bxe7fKbw.js} +1 -1
  52. streamlit/static/static/js/{index.BcbR2mbc.js → index.C1ElSZEy.js} +1 -1
  53. streamlit/static/static/js/index.C26ZOVFL.js +1 -0
  54. streamlit/static/static/js/{index.aJ3XRx8R.js → index.C7lwRBvF.js} +1 -1
  55. streamlit/static/static/js/{index.CGX2fllG.js → index.C93QGPyk.js} +1 -1
  56. streamlit/static/static/js/{index.COjurlZk.js → index.CCDejIvL.js} +2 -2
  57. streamlit/static/static/js/index.CcMmNHAq.js +1 -0
  58. streamlit/static/static/js/index.D42y-GeO.js +1 -0
  59. streamlit/static/static/js/{index.C0VFHmJN.js → index.D69ULFWq.js} +1 -1
  60. streamlit/static/static/js/{index.V4C1Oi-F.js → index.DB4MbQ40.js} +3 -3
  61. streamlit/static/static/js/{index.DJ4GBc1k.js → index.DRFJgBf-.js} +1 -1
  62. streamlit/static/static/js/{index.BXQNt1hj.js → index.DTK-btqV.js} +1 -1
  63. streamlit/static/static/js/{index.CFE-yHdT.js → index.DZEQ0G7H.js} +1 -1
  64. streamlit/static/static/js/{index.Bu3Lto_G.js → index.DaU1ayM7.js} +1 -1
  65. streamlit/static/static/js/{index.DSSQzzPk.js → index.Dla9XiNe.js} +2 -2
  66. streamlit/static/static/js/{index.DiZfOR0A.js → index.DmQqT9OM.js} +1 -1
  67. streamlit/static/static/js/{index.DuFqxjbN.js → index.DppScppA.js} +1 -1
  68. streamlit/static/static/js/{index.Dqphk1ee.js → index.Dr8b3Vn6.js} +1 -1
  69. streamlit/static/static/js/{index.CPo5dtx7.js → index.DvQ7-afx.js} +1 -1
  70. streamlit/static/static/js/{index.ATP5607r.js → index.F-NmmwfK.js} +1 -1
  71. streamlit/static/static/js/{index.gnFSTAhI.js → index.MKI8t7l2.js} +1 -1
  72. streamlit/static/static/js/{index.BXnQdCa5.js → index.RRAKXgBZ.js} +1 -1
  73. streamlit/static/static/js/{index.CyVBY8PG.js → index.VSsf6tsu.js} +2 -2
  74. streamlit/static/static/js/{index.DcudoGfL.js → index.aEeM0ekc.js} +1 -1
  75. streamlit/static/static/js/{index.Ds-w0zIo.js → index.eweE9HKU.js} +1 -1
  76. streamlit/static/static/js/{index.CBZQ_6AF.js → index.gr6yGiCL.js} +1 -1
  77. streamlit/static/static/js/{index.mZ1qbnKs.js → index.kKkHk9Mc.js} +1 -1
  78. streamlit/static/static/js/index.pMvzHC7z.js +1 -0
  79. streamlit/static/static/js/{index.DIIdzDwK.js → index.pgifwCIr.js} +1 -1
  80. streamlit/static/static/js/index.q83b8_8b.js +1 -0
  81. streamlit/static/static/js/{index.BzQChe4y.js → index.u2AvcQQT.js} +1 -1
  82. streamlit/static/static/js/{index.CrzXL2V8.js → index.w2_VrtVw.js} +1 -1
  83. streamlit/static/static/js/{index.DbmtfcDm.js → index.wv1DYVsn.js} +1 -1
  84. streamlit/static/static/js/{index.COZICZL6.js → index.x4j6nnNb.js} +1 -1
  85. streamlit/static/static/js/{input.CZPD7mCu.js → input.BoJqOS7a.js} +1 -1
  86. streamlit/static/static/js/{main.CX1jAiMw.js → main.B5XmUwmQ.js} +1 -1
  87. streamlit/static/static/js/{memory.m0jC5ULx.js → memory.9izgq54V.js} +1 -1
  88. streamlit/static/static/js/{number-overlay-editor.Dy0iTeCo.js → number-overlay-editor.PqOGQcLn.js} +1 -1
  89. streamlit/static/static/js/{pandasStylerUtils.D9jj-wHU.js → pandasStylerUtils.DUtF2t3R.js} +1 -1
  90. streamlit/static/static/js/{sandbox.CbvG1iAz.js → sandbox.DgKTHPLO.js} +1 -1
  91. streamlit/static/static/js/{styled-components.Cw3ioniY.js → styled-components.D4x8jmOI.js} +1 -1
  92. streamlit/static/static/js/{throttle.CAwhGpn0.js → throttle.DxEHIIp7.js} +1 -1
  93. streamlit/static/static/js/{timepicker.Bh3m6Pjp.js → timepicker.CDks5DWI.js} +1 -1
  94. streamlit/static/static/js/{toConsumableArray.DM0o32JS.js → toConsumableArray.CvTQRsV-.js} +1 -1
  95. streamlit/static/static/js/uniqueId.RScLN3St.js +1 -0
  96. streamlit/static/static/js/{useBasicWidgetState.C9zOVP8a.js → useBasicWidgetState.D6_b0IqA.js} +1 -1
  97. streamlit/static/static/js/{useIntlLocale.Bo42aN1U.js → useIntlLocale.Ctz17A7g.js} +1 -1
  98. streamlit/static/static/js/{useTextInputAutoExpand.DmyHLDxl.js → useTextInputAutoExpand.PAFB5o1T.js} +1 -1
  99. streamlit/static/static/js/{useUpdateUiValue.aWXWpqmw.js → useUpdateUiValue.CcTvmGlb.js} +1 -1
  100. streamlit/static/static/js/{useWaveformController.DlE14M1X.js → useWaveformController.vLi36Ir4.js} +1 -1
  101. streamlit/static/static/js/{withCalculatedWidth.B5JFJSmG.js → withCalculatedWidth.BtA2jL5-.js} +1 -1
  102. streamlit/static/static/js/{withFullScreenWrapper.dgVioHk1.js → withFullScreenWrapper.CeeoYBpc.js} +1 -1
  103. streamlit/web/bootstrap.py +105 -10
  104. streamlit/web/cli.py +21 -4
  105. streamlit/web/server/app_discovery.py +421 -0
  106. streamlit/web/server/server.py +0 -13
  107. streamlit/web/server/starlette/__init__.py +2 -1
  108. streamlit/web/server/starlette/starlette_app.py +326 -3
  109. streamlit/web/server/starlette/starlette_routes.py +27 -8
  110. {streamlit_nightly-1.52.3.dev20260108.dist-info → streamlit_nightly-1.52.3.dev20260110.dist-info}/METADATA +1 -1
  111. {streamlit_nightly-1.52.3.dev20260108.dist-info → streamlit_nightly-1.52.3.dev20260110.dist-info}/RECORD +115 -113
  112. streamlit/static/static/js/index.BOGNGR9a.js +0 -1
  113. streamlit/static/static/js/index.C-lnh8pI.js +0 -1
  114. streamlit/static/static/js/index.C98anBCM.js +0 -1
  115. streamlit/static/static/js/index.CFtGP8pH.js +0 -1
  116. streamlit/static/static/js/index.Cg59Loqx.js +0 -1
  117. streamlit/static/static/js/index.CiU2Tdcl.js +0 -1
  118. streamlit/static/static/js/index.DpnqUQVD.js +0 -1
  119. streamlit/static/static/js/uniqueId.DtV_RZzG.js +0 -1
  120. {streamlit_nightly-1.52.3.dev20260108.data → streamlit_nightly-1.52.3.dev20260110.data}/scripts/streamlit.cmd +0 -0
  121. {streamlit_nightly-1.52.3.dev20260108.dist-info → streamlit_nightly-1.52.3.dev20260110.dist-info}/WHEEL +0 -0
  122. {streamlit_nightly-1.52.3.dev20260108.dist-info → streamlit_nightly-1.52.3.dev20260110.dist-info}/entry_points.txt +0 -0
  123. {streamlit_nightly-1.52.3.dev20260108.dist-info → streamlit_nightly-1.52.3.dev20260110.dist-info}/top_level.txt +0 -0
@@ -1 +1 @@
1
- import{l as Z,r as i,aQ as M,aR as $,aS as O}from"./index.DkSjHoXw.js";async function q(l,e=16e3){if(!l||l.size===0)throw new Error("Invalid or empty blob provided");if(!window.AudioContext)throw new Error("AudioContext not supported in this browser");const o=new AudioContext;try{const n=await l.arrayBuffer(),r=await o.decodeAudioData(n),d=e??r.sampleRate,s=await Q(r,d);return J(s,d)}finally{o.close()}}async function Q(l,e){const{duration:o,numberOfChannels:n,sampleRate:r}=l,d=Math.ceil(o*e);if(!window.OfflineAudioContext)throw new Error("OfflineAudioContext not supported");const s=new OfflineAudioContext(1,d,e),p=s.createBufferSource();if(p.buffer=l,n>1){const h=s.createChannelSplitter(n),m=s.createChannelMerger(1);p.connect(h);for(let c=0;c<n;c++){const u=s.createGain();u.gain.value=1/n,h.connect(u,c),u.connect(m,0,0)}m.connect(s.destination)}else p.connect(s.destination);p.start(0);try{return await s.startRendering()}catch(h){throw new Error(`Failed to resample audio from ${r}Hz to ${e}Hz: ${h instanceof Error?h.message:String(h)}`)}}function J(l,e){const n=l.length,r=n*2+44,d=new ArrayBuffer(r),s=new DataView(d),p=l.getChannelData(0),h=(c,u)=>{for(let y=0;y<u.length;y++)s.setUint8(c+y,u.charCodeAt(y))};h(0,"RIFF"),s.setUint32(4,r-8,!0),h(8,"WAVE"),h(12,"fmt "),s.setUint32(16,16,!0),s.setUint16(20,1,!0),s.setUint16(22,1,!0),s.setUint32(24,e,!0),s.setUint32(28,e*2,!0),s.setUint16(32,2,!0),s.setUint16(34,16,!0),h(36,"data"),s.setUint32(40,n*2,!0);let m=44;for(let c=0;c<n;c++){const u=Math.max(-1,Math.min(1,p[c]));s.setInt16(m,u*32767,!0),m+=2}return new Blob([d],{type:"audio/wav"})}class W{constructor(){this.wavesurfer=null,this.currentBlobUrl=null,this.events={},this.isPlaying=!1}initialize(e){this.wavesurfer=e,this.setupEventListeners()}setupEventListeners(){this.wavesurfer&&(this.teardownEventListeners(),this.handleTimeUpdate=e=>{this.events.onTimeUpdate?.(e*1e3)},this.handlePause=()=>{this.isPlaying=!1,this.events.onPause?.()},this.handlePlay=()=>{this.isPlaying=!0,this.events.onPlay?.()},this.handleFinish=()=>{this.isPlaying=!1,this.events.onFinish?.()},this.handleReady=()=>{this.events.onReady?.()},this.handleError=e=>{const o=e instanceof Error?e:new Error(String(e));this.events.onError?.(o)},this.wavesurfer.on("timeupdate",this.handleTimeUpdate),this.wavesurfer.on("pause",this.handlePause),this.wavesurfer.on("play",this.handlePlay),this.wavesurfer.on("finish",this.handleFinish),this.wavesurfer.on("ready",this.handleReady),this.wavesurfer.on("error",this.handleError))}setEventHandlers(e){this.events=e}async load(e){if(!this.wavesurfer)throw new Error("WaveSurfer not initialized");this.cleanupPreviousUrl();let o,n=null;try{if(e instanceof Blob)n=URL.createObjectURL(e),o=n;else if(e instanceof ArrayBuffer){const r=new Blob([e]);n=URL.createObjectURL(r),o=n}else o=e;this.currentBlobUrl=n,await this.wavesurfer.load(o)}catch(r){throw this.cleanupPreviousUrl(),r}}async play(){if(!this.wavesurfer)throw new Error("WaveSurfer not initialized");await this.wavesurfer.play()}pause(){this.wavesurfer&&this.wavesurfer.pause()}getDuration(){return this.wavesurfer?this.wavesurfer.getDuration()*1e3:0}getCurrentTime(){return this.wavesurfer?this.wavesurfer.getCurrentTime()*1e3:0}getIsPlaying(){return this.isPlaying}seekToStart(){this.wavesurfer&&this.wavesurfer.seekTo(0)}cleanupPreviousUrl(){this.currentBlobUrl&&(URL.revokeObjectURL(this.currentBlobUrl),this.currentBlobUrl=null)}destroy(){this.pause(),this.cleanupPreviousUrl(),this.wavesurfer&&(this.teardownEventListeners(),this.wavesurfer.empty(),this.wavesurfer=null),this.events={},this.isPlaying=!1,this.handleTimeUpdate=void 0,this.handlePause=void 0,this.handlePlay=void 0,this.handleFinish=void 0,this.handleReady=void 0,this.handleError=void 0}teardownEventListeners(){this.wavesurfer&&(this.handleTimeUpdate&&(this.wavesurfer.un("timeupdate",this.handleTimeUpdate),this.handleTimeUpdate=void 0),this.handlePause&&(this.wavesurfer.un("pause",this.handlePause),this.handlePause=void 0),this.handlePlay&&(this.wavesurfer.un("play",this.handlePlay),this.handlePlay=void 0),this.handleFinish&&(this.wavesurfer.un("finish",this.handleFinish),this.handleFinish=void 0),this.handleReady&&(this.wavesurfer.un("ready",this.handleReady),this.handleReady=void 0),this.handleError&&(this.wavesurfer.un("error",this.handleError),this.handleError=void 0))}}function I(l){return l.name==="NotAllowedError"||l.name==="PermissionDeniedError"||l.message?.toLowerCase().includes("permission denied")}class K{constructor(e={}){this.wavesurfer=null,this.recordPlugin=null,this.isRecording=!1,this.recordEndResolve=null,this.recordEndReject=null,this.events={},this.options=e}initialize(e,o){this.wavesurfer=e;try{const n={renderRecordedAudio:!1,mimeType:"audio/webm"};this.recordPlugin=e.registerPlugin(o.create(n)),this.setupEventListeners()}catch(n){const r=n instanceof Error?n:new Error(String(n));throw I(r)?(this.events.onPermissionDenied?.(),new Error("Microphone permission denied")):(this.events.onError?.(r),r)}}setupEventListeners(){this.recordPlugin&&(this.recordPlugin.on("record-start",()=>{this.isRecording=!0,this.events.onRecordStart?.()}),this.recordPlugin.on("record-end",e=>{this.isRecording=!1,this.events.onRecordEnd?.(e),this.recordEndResolve&&e&&e.size>0?(this.recordEndResolve(e),this.recordEndResolve=null,this.recordEndReject=null):this.recordEndReject?(this.recordEndReject(new Error("Invalid or empty recording")),this.recordEndResolve=null,this.recordEndReject=null):(this.recordEndResolve=null,this.recordEndReject=null)}),this.recordPlugin.on("record-progress",e=>{this.events.onRecordProgress?.(e)}))}setEventHandlers(e){this.events=e}async startRecording(){if(!this.recordPlugin)throw new Error("Record plugin not initialized");if(this.isRecording)return;const e=typeof this.options.sampleRate=="number"?this.options.sampleRate:void 0,o={};e!==void 0&&(o.sampleRate={ideal:e}),await this.startRecordingWithConstraints(o,e!==void 0)}async startRecordingWithConstraints(e,o){if(!this.recordPlugin)throw new Error("Record plugin not initialized");try{const n=Object.keys(e).length?e:void 0;await this.recordPlugin.startRecording(n)}catch(n){const r=n instanceof Error?n:new Error(String(n));if(I(r))throw this.events.onPermissionDenied?.(),new Error("Microphone permission denied");if(o&&(r.name==="OverconstrainedError"||r.name==="NotReadableError")){this.options.sampleRate=void 0,await this.startRecordingWithConstraints({},!1);return}throw this.events.onError?.(r),r}}async stopRecording(){if(!this.recordPlugin||!this.isRecording)throw new Error("Not currently recording");try{return await new Promise((e,o)=>{this.recordEndResolve=e,this.recordEndReject=o,this.recordPlugin?.stopRecording()})}catch(e){const o=e instanceof Error?e:new Error(String(e));throw this.events.onError?.(o),o}}cancelRecording(){this.recordPlugin&&this.isRecording&&(this.recordPlugin.stopRecording(),this.isRecording=!1,this.recordEndResolve=null,this.recordEndReject=null)}destroy(){this.cancelRecording(),this.recordPlugin&&(this.recordPlugin.destroy(),this.recordPlugin=null),this.wavesurfer=null,this.events={}}}const X=4,Y=4,ee=8,re=0,te=16e3;function se({containerRef:l,sampleRate:e,events:o,waveformPadding:n=0}){const r=Z(),[d,s]=i.useState("idle"),[p,h]=i.useState(null),[m,c]=i.useState(!1),u=i.useRef(null),y=i.useRef(null),a=i.useRef(null),f=i.useRef(o),U=i.useRef(!1),D=i.useRef(!1),E=i.useRef(new Set),P=i.useRef(!1),b=e===void 0?te:e,A=i.useCallback(()=>{E.current.clear(),c(!1),y.current&&(y.current.destroy(),y.current=null),a.current&&(a.current.destroy(),a.current=null),u.current&&(u.current.destroy(),u.current=null),U.current=!1,P.current=!1,s("idle"),h(null)},[]),x=i.useCallback(()=>{const t=Array.from(E.current);E.current.clear(),t.forEach(w=>{w.resolve()})},[]),_=i.useCallback(t=>{c(!1);const w=Array.from(E.current);E.current.clear(),w.forEach(v=>{v.reject(t)})},[]),T=i.useCallback(t=>{const w={onPlay:()=>{c(!0),f.current.onPlaybackPlay?.()},onPause:()=>{c(!1),f.current.onPlaybackPause?.()},onFinish:()=>{c(!1),f.current.onPlaybackFinish?.()},onReady:()=>{x()},onError:v=>{c(!1),_(v),f.current.onError?.(v)}};t.setEventHandlers(w)},[x,_]);i.useEffect(()=>{f.current=o,a.current&&T(a.current)},[o,T]);const S=i.useCallback(async()=>{if(!(U.current||D.current||!l.current)){D.current=!0;try{const[t,w]=await Promise.all([M(()=>import("./wavesurfer.esm.D1Sty35j.js"),[],import.meta.url),M(()=>import("./record.DytFsBUt.js"),[],import.meta.url)]),v=t.default,B=w.default,k=v.create({container:l.current,waveColor:r.colors.primary,progressColor:r.colors.bodyText,height:n>0?$(r.sizes.largestElementHeight)-2*n:"auto",barWidth:X,barGap:Y,barRadius:ee,cursorWidth:re,interact:!0});u.current=k,P.current=!1;const C=new K({sampleRate:b});C.initialize(k,B),C.setEventHandlers({onRecordProgress:R=>{f.current.onProgressMs?.(R)},onPermissionDenied:()=>{f.current.onPermissionDenied(),s("idle")},onError:R=>{f.current.onError(R),s("idle")}}),y.current=C;const g=new W;g.initialize(k),a.current=g,T(g),U.current=!0}catch(t){const w=t instanceof Error?t:new Error(String(t));f.current.onError?.(w)}finally{D.current=!1}}},[l,r,b,T,n]);i.useEffect(()=>(S(),()=>{A()}),[A,S]),i.useEffect(()=>{const t=u.current;if(t){if(d==="recording"){t.setOptions({waveColor:r.colors.primary,progressColor:r.colors.primary});return}if(P.current){t.setOptions({interact:!0,waveColor:O(r.colors.fadedText40,r.colors.secondaryBg),progressColor:r.colors.bodyText});return}t.setOptions({waveColor:r.colors.primary,progressColor:r.colors.bodyText})}},[d,r.colors.bodyText,r.colors.fadedText40,r.colors.primary,r.colors.secondaryBg]);const F=i.useCallback(async()=>{if(d!=="recording"){if(U.current||await S(),!y.current)throw new Error("Record backend not initialized");u.current&&u.current.setOptions({waveColor:r.colors.primary,progressColor:r.colors.primary}),P.current=!1,await y.current.startRecording(),s("recording"),h(null),c(!1),f.current.onRecordStart?.()}},[d,S,r.colors.primary]),L=i.useCallback(()=>{a.current&&u.current&&(a.current.destroy(),a.current=new W,a.current.initialize(u.current),E.current.clear(),c(!1),T(a.current)),P.current=!1},[T]),z=i.useCallback(()=>{a.current?.seekToStart(),c(!1),P.current=!0,u.current&&u.current.setOptions({interact:!0,waveColor:O(r.colors.fadedText40,r.colors.secondaryBg),progressColor:r.colors.bodyText})},[r.colors.bodyText,r.colors.fadedText40,r.colors.secondaryBg]),H=i.useCallback(async()=>{if(d!=="recording")throw new Error("Not currently recording");if(!y.current||!a.current)throw new Error("Backends not initialized");try{const t=await y.current.stopRecording();h(t),await new Promise((k,C)=>{if(!a.current){C(new Error("Player not initialized"));return}const g={resolve:()=>{E.current.delete(g),k()},reject:R=>{E.current.delete(g),C(R)}};E.current.add(g),a.current.load(t).catch(R=>{E.current.delete(g),C(R instanceof Error?R:new Error(String(R)))})}),s("idle"),c(!1),z();const v={durationMs:a.current?.getDuration()??0,sampleRate:typeof b=="number"?b:null,mimeType:t.type||"audio/webm",size:t.size},B={blob:t,meta:v};return f.current.onRecordReady?.(t),B}catch(t){const w=t instanceof Error?t:new Error(String(t));return c(!1),s("idle"),f.current.onError(w),{blob:new Blob,meta:{durationMs:0,sampleRate:null,mimeType:"audio/webm",size:0}}}},[d,z,b]),j=i.useCallback(async t=>{const w=t??p;if(!w){const v=new Error("No recorded audio to approve");f.current.onError(v);return}try{const v=await q(w,b);await f.current.onApprove?.(v),h(null),s("idle")}catch(v){const B=v instanceof Error?v:new Error(String(v));f.current.onError(B)}},[p,b]),N=i.useCallback(()=>{d==="recording"&&y.current?.cancelRecording(),L(),h(null),s("idle"),c(!1),P.current=!1,f.current.onCancel?.()},[d,L]),V=i.useMemo(()=>({isPlaying:()=>a.current?.getIsPlaying()??!1,play:async()=>{if(!a.current)throw new Error("Player not initialized");await a.current.play()},pause:()=>{a.current?.pause()},load:async t=>{if(U.current||await S(),!a.current)throw new Error("Player not initialized");await a.current.load(t),z()},getCurrentTimeMs:()=>a.current?.getCurrentTime()??0,getDurationMs:()=>a.current?.getDuration()??0}),[z,S]),G=i.useCallback(t=>{f.current=t},[]);return i.useEffect(()=>()=>{A()},[A]),{state:d,isPlaybackPlaying:m,mountRef:l,start:F,stop:H,approve:j,cancel:N,destroy:A,playback:V,setEventHandlers:G}}export{se as u};
1
+ import{l as Z,r as i,aR as M,ab as $,aS as O}from"./index.BZBWLU1C.js";async function q(l,e=16e3){if(!l||l.size===0)throw new Error("Invalid or empty blob provided");if(!window.AudioContext)throw new Error("AudioContext not supported in this browser");const o=new AudioContext;try{const n=await l.arrayBuffer(),r=await o.decodeAudioData(n),d=e??r.sampleRate,s=await J(r,d);return K(s,d)}finally{o.close()}}async function J(l,e){const{duration:o,numberOfChannels:n,sampleRate:r}=l,d=Math.ceil(o*e);if(!window.OfflineAudioContext)throw new Error("OfflineAudioContext not supported");const s=new OfflineAudioContext(1,d,e),p=s.createBufferSource();if(p.buffer=l,n>1){const h=s.createChannelSplitter(n),m=s.createChannelMerger(1);p.connect(h);for(let c=0;c<n;c++){const u=s.createGain();u.gain.value=1/n,h.connect(u,c),u.connect(m,0,0)}m.connect(s.destination)}else p.connect(s.destination);p.start(0);try{return await s.startRendering()}catch(h){throw new Error(`Failed to resample audio from ${r}Hz to ${e}Hz: ${h instanceof Error?h.message:String(h)}`)}}function K(l,e){const n=l.length,r=n*2+44,d=new ArrayBuffer(r),s=new DataView(d),p=l.getChannelData(0),h=(c,u)=>{for(let y=0;y<u.length;y++)s.setUint8(c+y,u.charCodeAt(y))};h(0,"RIFF"),s.setUint32(4,r-8,!0),h(8,"WAVE"),h(12,"fmt "),s.setUint32(16,16,!0),s.setUint16(20,1,!0),s.setUint16(22,1,!0),s.setUint32(24,e,!0),s.setUint32(28,e*2,!0),s.setUint16(32,2,!0),s.setUint16(34,16,!0),h(36,"data"),s.setUint32(40,n*2,!0);let m=44;for(let c=0;c<n;c++){const u=Math.max(-1,Math.min(1,p[c]));s.setInt16(m,u*32767,!0),m+=2}return new Blob([d],{type:"audio/wav"})}class W{constructor(){this.wavesurfer=null,this.currentBlobUrl=null,this.events={},this.isPlaying=!1}initialize(e){this.wavesurfer=e,this.setupEventListeners()}setupEventListeners(){this.wavesurfer&&(this.teardownEventListeners(),this.handleTimeUpdate=e=>{this.events.onTimeUpdate?.(e*1e3)},this.handlePause=()=>{this.isPlaying=!1,this.events.onPause?.()},this.handlePlay=()=>{this.isPlaying=!0,this.events.onPlay?.()},this.handleFinish=()=>{this.isPlaying=!1,this.events.onFinish?.()},this.handleReady=()=>{this.events.onReady?.()},this.handleError=e=>{const o=e instanceof Error?e:new Error(String(e));this.events.onError?.(o)},this.wavesurfer.on("timeupdate",this.handleTimeUpdate),this.wavesurfer.on("pause",this.handlePause),this.wavesurfer.on("play",this.handlePlay),this.wavesurfer.on("finish",this.handleFinish),this.wavesurfer.on("ready",this.handleReady),this.wavesurfer.on("error",this.handleError))}setEventHandlers(e){this.events=e}async load(e){if(!this.wavesurfer)throw new Error("WaveSurfer not initialized");this.cleanupPreviousUrl();let o,n=null;try{if(e instanceof Blob)n=URL.createObjectURL(e),o=n;else if(e instanceof ArrayBuffer){const r=new Blob([e]);n=URL.createObjectURL(r),o=n}else o=e;this.currentBlobUrl=n,await this.wavesurfer.load(o)}catch(r){throw this.cleanupPreviousUrl(),r}}async play(){if(!this.wavesurfer)throw new Error("WaveSurfer not initialized");await this.wavesurfer.play()}pause(){this.wavesurfer&&this.wavesurfer.pause()}getDuration(){return this.wavesurfer?this.wavesurfer.getDuration()*1e3:0}getCurrentTime(){return this.wavesurfer?this.wavesurfer.getCurrentTime()*1e3:0}getIsPlaying(){return this.isPlaying}seekToStart(){this.wavesurfer&&this.wavesurfer.seekTo(0)}cleanupPreviousUrl(){this.currentBlobUrl&&(URL.revokeObjectURL(this.currentBlobUrl),this.currentBlobUrl=null)}destroy(){this.pause(),this.cleanupPreviousUrl(),this.wavesurfer&&(this.teardownEventListeners(),this.wavesurfer.empty(),this.wavesurfer=null),this.events={},this.isPlaying=!1,this.handleTimeUpdate=void 0,this.handlePause=void 0,this.handlePlay=void 0,this.handleFinish=void 0,this.handleReady=void 0,this.handleError=void 0}teardownEventListeners(){this.wavesurfer&&(this.handleTimeUpdate&&(this.wavesurfer.un("timeupdate",this.handleTimeUpdate),this.handleTimeUpdate=void 0),this.handlePause&&(this.wavesurfer.un("pause",this.handlePause),this.handlePause=void 0),this.handlePlay&&(this.wavesurfer.un("play",this.handlePlay),this.handlePlay=void 0),this.handleFinish&&(this.wavesurfer.un("finish",this.handleFinish),this.handleFinish=void 0),this.handleReady&&(this.wavesurfer.un("ready",this.handleReady),this.handleReady=void 0),this.handleError&&(this.wavesurfer.un("error",this.handleError),this.handleError=void 0))}}function I(l){return l.name==="NotAllowedError"||l.name==="PermissionDeniedError"||l.message?.toLowerCase().includes("permission denied")}class Q{constructor(e={}){this.wavesurfer=null,this.recordPlugin=null,this.isRecording=!1,this.recordEndResolve=null,this.recordEndReject=null,this.events={},this.options=e}initialize(e,o){this.wavesurfer=e;try{const n={renderRecordedAudio:!1,mimeType:"audio/webm"};this.recordPlugin=e.registerPlugin(o.create(n)),this.setupEventListeners()}catch(n){const r=n instanceof Error?n:new Error(String(n));throw I(r)?(this.events.onPermissionDenied?.(),new Error("Microphone permission denied")):(this.events.onError?.(r),r)}}setupEventListeners(){this.recordPlugin&&(this.recordPlugin.on("record-start",()=>{this.isRecording=!0,this.events.onRecordStart?.()}),this.recordPlugin.on("record-end",e=>{this.isRecording=!1,this.events.onRecordEnd?.(e),this.recordEndResolve&&e&&e.size>0?(this.recordEndResolve(e),this.recordEndResolve=null,this.recordEndReject=null):this.recordEndReject?(this.recordEndReject(new Error("Invalid or empty recording")),this.recordEndResolve=null,this.recordEndReject=null):(this.recordEndResolve=null,this.recordEndReject=null)}),this.recordPlugin.on("record-progress",e=>{this.events.onRecordProgress?.(e)}))}setEventHandlers(e){this.events=e}async startRecording(){if(!this.recordPlugin)throw new Error("Record plugin not initialized");if(this.isRecording)return;const e=typeof this.options.sampleRate=="number"?this.options.sampleRate:void 0,o={};e!==void 0&&(o.sampleRate={ideal:e}),await this.startRecordingWithConstraints(o,e!==void 0)}async startRecordingWithConstraints(e,o){if(!this.recordPlugin)throw new Error("Record plugin not initialized");try{const n=Object.keys(e).length?e:void 0;await this.recordPlugin.startRecording(n)}catch(n){const r=n instanceof Error?n:new Error(String(n));if(I(r))throw this.events.onPermissionDenied?.(),new Error("Microphone permission denied");if(o&&(r.name==="OverconstrainedError"||r.name==="NotReadableError")){this.options.sampleRate=void 0,await this.startRecordingWithConstraints({},!1);return}throw this.events.onError?.(r),r}}async stopRecording(){if(!this.recordPlugin||!this.isRecording)throw new Error("Not currently recording");try{return await new Promise((e,o)=>{this.recordEndResolve=e,this.recordEndReject=o,this.recordPlugin?.stopRecording()})}catch(e){const o=e instanceof Error?e:new Error(String(e));throw this.events.onError?.(o),o}}cancelRecording(){this.recordPlugin&&this.isRecording&&(this.recordPlugin.stopRecording(),this.isRecording=!1,this.recordEndResolve=null,this.recordEndReject=null)}destroy(){this.cancelRecording(),this.recordPlugin&&(this.recordPlugin.destroy(),this.recordPlugin=null),this.wavesurfer=null,this.events={}}}const X=4,Y=4,ee=8,re=0,te=16e3;function se({containerRef:l,sampleRate:e,events:o,waveformPadding:n=0}){const r=Z(),[d,s]=i.useState("idle"),[p,h]=i.useState(null),[m,c]=i.useState(!1),u=i.useRef(null),y=i.useRef(null),a=i.useRef(null),f=i.useRef(o),U=i.useRef(!1),D=i.useRef(!1),E=i.useRef(new Set),P=i.useRef(!1),b=e===void 0?te:e,A=i.useCallback(()=>{E.current.clear(),c(!1),y.current&&(y.current.destroy(),y.current=null),a.current&&(a.current.destroy(),a.current=null),u.current&&(u.current.destroy(),u.current=null),U.current=!1,P.current=!1,s("idle"),h(null)},[]),x=i.useCallback(()=>{const t=Array.from(E.current);E.current.clear(),t.forEach(w=>{w.resolve()})},[]),_=i.useCallback(t=>{c(!1);const w=Array.from(E.current);E.current.clear(),w.forEach(v=>{v.reject(t)})},[]),T=i.useCallback(t=>{const w={onPlay:()=>{c(!0),f.current.onPlaybackPlay?.()},onPause:()=>{c(!1),f.current.onPlaybackPause?.()},onFinish:()=>{c(!1),f.current.onPlaybackFinish?.()},onReady:()=>{x()},onError:v=>{c(!1),_(v),f.current.onError?.(v)}};t.setEventHandlers(w)},[x,_]);i.useEffect(()=>{f.current=o,a.current&&T(a.current)},[o,T]);const S=i.useCallback(async()=>{if(!(U.current||D.current||!l.current)){D.current=!0;try{const[t,w]=await Promise.all([M(()=>import("./wavesurfer.esm.D1Sty35j.js"),[],import.meta.url),M(()=>import("./record.DytFsBUt.js"),[],import.meta.url)]),v=t.default,B=w.default,k=v.create({container:l.current,waveColor:r.colors.primary,progressColor:r.colors.bodyText,height:n>0?$(r.sizes.largestElementHeight)-2*n:"auto",barWidth:X,barGap:Y,barRadius:ee,cursorWidth:re,interact:!0});u.current=k,P.current=!1;const C=new Q({sampleRate:b});C.initialize(k,B),C.setEventHandlers({onRecordProgress:R=>{f.current.onProgressMs?.(R)},onPermissionDenied:()=>{f.current.onPermissionDenied(),s("idle")},onError:R=>{f.current.onError(R),s("idle")}}),y.current=C;const g=new W;g.initialize(k),a.current=g,T(g),U.current=!0}catch(t){const w=t instanceof Error?t:new Error(String(t));f.current.onError?.(w)}finally{D.current=!1}}},[l,r,b,T,n]);i.useEffect(()=>(S(),()=>{A()}),[A,S]),i.useEffect(()=>{const t=u.current;if(t){if(d==="recording"){t.setOptions({waveColor:r.colors.primary,progressColor:r.colors.primary});return}if(P.current){t.setOptions({interact:!0,waveColor:O(r.colors.fadedText40,r.colors.secondaryBg),progressColor:r.colors.bodyText});return}t.setOptions({waveColor:r.colors.primary,progressColor:r.colors.bodyText})}},[d,r.colors.bodyText,r.colors.fadedText40,r.colors.primary,r.colors.secondaryBg]);const F=i.useCallback(async()=>{if(d!=="recording"){if(U.current||await S(),!y.current)throw new Error("Record backend not initialized");u.current&&u.current.setOptions({waveColor:r.colors.primary,progressColor:r.colors.primary}),P.current=!1,await y.current.startRecording(),s("recording"),h(null),c(!1),f.current.onRecordStart?.()}},[d,S,r.colors.primary]),L=i.useCallback(()=>{a.current&&u.current&&(a.current.destroy(),a.current=new W,a.current.initialize(u.current),E.current.clear(),c(!1),T(a.current)),P.current=!1},[T]),z=i.useCallback(()=>{a.current?.seekToStart(),c(!1),P.current=!0,u.current&&u.current.setOptions({interact:!0,waveColor:O(r.colors.fadedText40,r.colors.secondaryBg),progressColor:r.colors.bodyText})},[r.colors.bodyText,r.colors.fadedText40,r.colors.secondaryBg]),H=i.useCallback(async()=>{if(d!=="recording")throw new Error("Not currently recording");if(!y.current||!a.current)throw new Error("Backends not initialized");try{const t=await y.current.stopRecording();h(t),await new Promise((k,C)=>{if(!a.current){C(new Error("Player not initialized"));return}const g={resolve:()=>{E.current.delete(g),k()},reject:R=>{E.current.delete(g),C(R)}};E.current.add(g),a.current.load(t).catch(R=>{E.current.delete(g),C(R instanceof Error?R:new Error(String(R)))})}),s("idle"),c(!1),z();const v={durationMs:a.current?.getDuration()??0,sampleRate:typeof b=="number"?b:null,mimeType:t.type||"audio/webm",size:t.size},B={blob:t,meta:v};return f.current.onRecordReady?.(t),B}catch(t){const w=t instanceof Error?t:new Error(String(t));return c(!1),s("idle"),f.current.onError(w),{blob:new Blob,meta:{durationMs:0,sampleRate:null,mimeType:"audio/webm",size:0}}}},[d,z,b]),j=i.useCallback(async t=>{const w=t??p;if(!w){const v=new Error("No recorded audio to approve");f.current.onError(v);return}try{const v=await q(w,b);await f.current.onApprove?.(v),h(null),s("idle")}catch(v){const B=v instanceof Error?v:new Error(String(v));f.current.onError(B)}},[p,b]),N=i.useCallback(()=>{d==="recording"&&y.current?.cancelRecording(),L(),h(null),s("idle"),c(!1),P.current=!1,f.current.onCancel?.()},[d,L]),V=i.useMemo(()=>({isPlaying:()=>a.current?.getIsPlaying()??!1,play:async()=>{if(!a.current)throw new Error("Player not initialized");await a.current.play()},pause:()=>{a.current?.pause()},load:async t=>{if(U.current||await S(),!a.current)throw new Error("Player not initialized");await a.current.load(t),z()},getCurrentTimeMs:()=>a.current?.getCurrentTime()??0,getDurationMs:()=>a.current?.getDuration()??0}),[z,S]),G=i.useCallback(t=>{f.current=t},[]);return i.useEffect(()=>()=>{A()},[A]),{state:d,isPlaybackPlaying:m,mountRef:l,start:F,stop:H,approve:j,cancel:N,destroy:A,playback:V,setEventHandlers:G}}export{se as u};
@@ -1 +1 @@
1
- import{h as l,k as h,j as s,d as n}from"./index.DkSjHoXw.js";const o=t=>{const a=e=>{const{width:i,elementRef:c}=h();return s(n,{ref:c,children:s(t,{...e,width:i})})};return a.displayName=`withCalculatedWidth(${t.displayName||t.name})`,l(a,t)};export{o as w};
1
+ import{h as l,k as h,j as s,d as n}from"./index.BZBWLU1C.js";const o=t=>{const a=e=>{const{width:i,elementRef:c}=h();return s(n,{ref:c,children:s(t,{...e,width:i})})};return a.displayName=`withCalculatedWidth(${t.displayName||t.name})`,l(a,t)};export{o as w};
@@ -1 +1 @@
1
- import{r as n,F as f,b6 as p,b7 as h,l as x,k as y,j as i,h as g}from"./index.DkSjHoXw.js";const m=n.createContext(null);m.displayName="ElementFullscreenContext";const w=f("div",{target:"e5bcvgj0"})(({theme:e,isExpanded:t})=>({width:"100%",height:"100%",...t?{position:"fixed",top:0,left:0,bottom:0,right:0,background:e.colors.bgColor,zIndex:e.zIndices.fullscreenWrapper,padding:e.spacing.md,paddingTop:e.sizes.fullScreenHeaderHeight,overflow:"auto",display:"flex",alignItems:"center",justifyContent:"center"}:{}})),C=()=>{const{setFullScreen:e}=n.useContext(p),[t,s]=n.useState(!1),{fullHeight:a,fullWidth:c}=h(),l=n.useCallback(r=>{s(r),e(r)},[e]),u=n.useCallback(()=>{document.body.style.overflow="hidden",l(!0)},[l]),o=n.useCallback(()=>{document.body.style.overflow="unset",l(!1)},[l]),d=n.useCallback(r=>{r.keyCode===27&&t&&o()},[o,t]);return n.useEffect(()=>(document.addEventListener("keydown",d,!1),()=>{document.removeEventListener("keydown",d,!1)}),[d]),n.useMemo(()=>({expanded:t,zoomIn:u,zoomOut:o,fullHeight:a,fullWidth:c}),[t,u,o,a,c])},F=({children:e})=>{const t=x(),{expanded:s,fullHeight:a,fullWidth:c,zoomIn:l,zoomOut:u}=C(),{width:o,elementRef:d}=y(),r=n.useMemo(()=>({width:s?c:o,height:s?a:void 0,expanded:s,expand:l,collapse:u}),[s,a,c,o,l,u]);return i(m.Provider,{value:r,children:i(w,{ref:d,isExpanded:s,"data-testid":"stFullScreenFrame",theme:t,children:e})})};function S(e){const t=s=>i(F,{children:i(e,{...s})});return t.displayName=`withFullScreenWrapper(${e.displayName||e.name})`,g(t,e)}export{m as E,S as w};
1
+ import{r as n,F as f,b7 as p,b8 as h,l as x,k as y,j as i,h as g}from"./index.BZBWLU1C.js";const m=n.createContext(null);m.displayName="ElementFullscreenContext";const w=f("div",{target:"e5bcvgj0"})(({theme:e,isExpanded:t})=>({width:"100%",height:"100%",...t?{position:"fixed",top:0,left:0,bottom:0,right:0,background:e.colors.bgColor,zIndex:e.zIndices.fullscreenWrapper,padding:e.spacing.md,paddingTop:e.sizes.fullScreenHeaderHeight,overflow:"auto",display:"flex",alignItems:"center",justifyContent:"center"}:{}})),C=()=>{const{setFullScreen:e}=n.useContext(p),[t,s]=n.useState(!1),{fullHeight:a,fullWidth:c}=h(),l=n.useCallback(r=>{s(r),e(r)},[e]),u=n.useCallback(()=>{document.body.style.overflow="hidden",l(!0)},[l]),o=n.useCallback(()=>{document.body.style.overflow="unset",l(!1)},[l]),d=n.useCallback(r=>{r.keyCode===27&&t&&o()},[o,t]);return n.useEffect(()=>(document.addEventListener("keydown",d,!1),()=>{document.removeEventListener("keydown",d,!1)}),[d]),n.useMemo(()=>({expanded:t,zoomIn:u,zoomOut:o,fullHeight:a,fullWidth:c}),[t,u,o,a,c])},F=({children:e})=>{const t=x(),{expanded:s,fullHeight:a,fullWidth:c,zoomIn:l,zoomOut:u}=C(),{width:o,elementRef:d}=y(),r=n.useMemo(()=>({width:s?c:o,height:s?a:void 0,expanded:s,expand:l,collapse:u}),[s,a,c,o,l,u]);return i(m.Provider,{value:r,children:i(w,{ref:d,isExpanded:s,"data-testid":"stFullScreenFrame",theme:t,children:e})})};function S(e){const t=s=>i(F,{children:i(e,{...s})});return t.displayName=`withFullScreenWrapper(${e.displayName||e.name})`,g(t,e)}export{m as E,S as w};
@@ -15,6 +15,7 @@
15
15
  from __future__ import annotations
16
16
 
17
17
  import asyncio
18
+ import mimetypes
18
19
  import os
19
20
  import signal
20
21
  import sys
@@ -123,18 +124,10 @@ def _fix_sys_argv(main_script_path: str, args: list[str]) -> None:
123
124
 
124
125
 
125
126
  def _on_server_start(server: Server) -> None:
126
- _maybe_print_static_folder_warning(server.main_script_path)
127
+ prepare_streamlit_environment(server.main_script_path)
127
128
  _print_url(server.is_running_hello)
128
129
  report_watchdog_availability()
129
130
 
130
- # Load secrets.toml if it exists. If the file doesn't exist, this
131
- # function will return without raising an exception. We catch any parse
132
- # errors and display them here.
133
- try:
134
- secrets.load_if_toml_exists()
135
- except Exception:
136
- _LOGGER.exception("Failed to load secrets.toml file")
137
-
138
131
  def maybe_open_browser() -> None:
139
132
  if config.get_option("server.headless"):
140
133
  # Don't open browser when in headless mode.
@@ -165,6 +158,55 @@ def _fix_pydeck_mapbox_api_warning() -> None:
165
158
  os.environ["MAPBOX_API_KEY"] = config.get_option("mapbox.token")
166
159
 
167
160
 
161
+ def _initialize_mimetypes() -> None:
162
+ """Ensure common MIME types are correctly registered.
163
+
164
+ Some systems may have misconfigured /etc/mime.types, so we explicitly
165
+ register the types we need for serving web assets correctly.
166
+ """
167
+ mimetypes.add_type("text/html", ".html")
168
+ mimetypes.add_type("application/javascript", ".js")
169
+ mimetypes.add_type("application/javascript", ".mjs")
170
+ mimetypes.add_type("text/css", ".css")
171
+ mimetypes.add_type("image/webp", ".webp")
172
+
173
+
174
+ def prepare_streamlit_environment(main_script_path: str) -> None:
175
+ """Prepare the Streamlit environment for running an app.
176
+
177
+ This function sets up the environment needed for Streamlit to run correctly.
178
+ It should be called before starting the runtime, whether using the CLI
179
+ (`streamlit run`) or an ASGI server (`uvicorn myapp:app`).
180
+
181
+ This function:
182
+ - Ensures common MIME types are correctly registered
183
+ - Sets the MAPBOX_API_KEY environment variable for PyDeck
184
+ - Loads secrets from secrets.toml if it exists
185
+ - Validates static folder configuration
186
+
187
+ Parameters
188
+ ----------
189
+ main_script_path
190
+ Path to the main Streamlit script.
191
+
192
+ Notes
193
+ -----
194
+ This function is automatically called by ``streamlit run``. When using
195
+ ``st.App`` with uvicorn directly, this is called during the ASGI lifespan
196
+ startup phase.
197
+ """
198
+ _initialize_mimetypes()
199
+ _fix_pydeck_mapbox_api_warning()
200
+
201
+ # Load secrets.toml if it exists
202
+ try:
203
+ secrets.load_if_toml_exists()
204
+ except Exception:
205
+ _LOGGER.exception("Failed to load secrets.toml file")
206
+
207
+ _maybe_print_static_folder_warning(main_script_path)
208
+
209
+
168
210
  def _maybe_print_static_folder_warning(main_script_path: str) -> None:
169
211
  """Prints a warning if the static folder is misconfigured."""
170
212
 
@@ -287,6 +329,53 @@ def _install_config_watchers(flag_options: dict[str, Any]) -> None:
287
329
  watch_file(filename, on_config_changed)
288
330
 
289
331
 
332
+ def run_asgi_app(
333
+ main_script_path: str,
334
+ app_import_string: str,
335
+ args: list[str],
336
+ flag_options: dict[str, Any],
337
+ ) -> None:
338
+ """Run a Streamlit st.App with uvicorn.
339
+
340
+ This function is called when `streamlit run` detects an st.App instance
341
+ in the script. It sets up the process environment and starts uvicorn.
342
+
343
+ The App instance handles its own Streamlit-specific setup via its lifespan
344
+ (e.g., loading secrets, preparing runtime), while this function handles
345
+ the process-level setup that the CLI is responsible for.
346
+
347
+ Parameters
348
+ ----------
349
+ main_script_path
350
+ Path to the main Streamlit script containing the st.App.
351
+ app_import_string
352
+ Import string for uvicorn (e.g., "myapp:app").
353
+ args
354
+ Arguments to pass to the script (sys.argv).
355
+ flag_options
356
+ Config options from CLI flags.
357
+ """
358
+ from streamlit.web.server.starlette.starlette_server import UvicornRunner
359
+
360
+ # Process-level setup (CLI responsibility)
361
+ _fix_sys_path(main_script_path)
362
+ _fix_sys_argv(main_script_path, args)
363
+ _install_config_watchers(flag_options)
364
+
365
+ # Set server mode for metrics tracking (CLI-managed st.App)
366
+ config._server_mode = "starlette-app"
367
+
368
+ # Report watchdog availability for file watching
369
+ report_watchdog_availability()
370
+
371
+ # Run the ASGI app using UvicornRunner
372
+ # UvicornRunner handles: port retry, SSL, WebSocket config, signal handling
373
+ # The st.App's lifespan will call prepare_streamlit_environment()
374
+ # Note: URL is printed inside UvicornRunner after port is finalized
375
+ runner = UvicornRunner(app_import_string)
376
+ runner.run()
377
+
378
+
290
379
  def run(
291
380
  main_script_path: str,
292
381
  is_hello: bool,
@@ -303,9 +392,15 @@ def run(
303
392
  _fix_sys_path(main_script_path)
304
393
  _fix_tornado_crash()
305
394
  _fix_sys_argv(main_script_path, args)
306
- _fix_pydeck_mapbox_api_warning()
307
395
  _install_config_watchers(flag_options)
308
396
 
397
+ # Set server mode for metrics tracking
398
+ # The Server class may use Starlette (via server.useStarlette config) or Tornado
399
+ if config.get_option("server.useStarlette"):
400
+ config._server_mode = "starlette-managed"
401
+ else:
402
+ config._server_mode = "tornado"
403
+
309
404
  # Create the server. It won't start running yet.
310
405
  server = Server(main_script_path, is_hello)
311
406
 
streamlit/web/cli.py CHANGED
@@ -292,7 +292,8 @@ def _main_run(
292
292
  # Set the main script path to use it for config & secret files
293
293
  # While its a bit suboptimal, we need to store this into a module-level
294
294
  # variable before we load the config options via `load_config_options`
295
- _config._main_script_path = os.path.abspath(file)
295
+ main_script_path = os.path.abspath(file)
296
+ _config._main_script_path = main_script_path
296
297
 
297
298
  bootstrap.load_config_options(flag_options=flag_options or {})
298
299
  if args is None:
@@ -301,11 +302,27 @@ def _main_run(
301
302
  if flag_options is None:
302
303
  flag_options = {}
303
304
 
304
- is_hello = _get_command_line_as_string() == "streamlit hello"
305
-
306
305
  check_credentials()
307
306
 
308
- bootstrap.run(file, is_hello, args, flag_options)
307
+ # Check if the script contains an ASGI app instance (st.App, FastAPI, Starlette).
308
+ # This intentionally supports non-Streamlit ASGI frameworks to enable `streamlit run`
309
+ # as a unified entry point for projects that combine Streamlit with other frameworks.
310
+ from streamlit.web.server.app_discovery import discover_asgi_app
311
+
312
+ discovery_result = discover_asgi_app(Path(main_script_path))
313
+
314
+ if discovery_result.is_asgi_app:
315
+ # Run as ASGI app with uvicorn
316
+ bootstrap.run_asgi_app(
317
+ main_script_path,
318
+ discovery_result.import_string, # type: ignore[arg-type]
319
+ args,
320
+ flag_options,
321
+ )
322
+ else:
323
+ # Run as traditional Streamlit app
324
+ is_hello = _get_command_line_as_string() == "streamlit hello"
325
+ bootstrap.run(main_script_path, is_hello, args, flag_options)
309
326
 
310
327
 
311
328
  # SUBCOMMAND cache