streamlit-nightly 1.52.3.dev20260113__py3-none-any.whl → 1.53.1.dev20260115__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 +0 -26
- streamlit/commands/logo.py +2 -0
- streamlit/commands/page_config.py +16 -16
- streamlit/components/v2/__init__.py +2 -2
- streamlit/config.py +29 -0
- streamlit/connections/base_connection.py +16 -4
- streamlit/connections/snowflake_connection.py +254 -205
- streamlit/elements/form.py +2 -2
- streamlit/elements/lib/streamlit_plotly_theme.py +9 -11
- streamlit/elements/metric.py +49 -48
- streamlit/elements/widgets/button.py +9 -9
- streamlit/elements/widgets/chat.py +5 -9
- streamlit/elements/widgets/data_editor.py +3 -3
- streamlit/elements/widgets/file_uploader.py +10 -11
- streamlit/elements/widgets/select_slider.py +4 -0
- streamlit/proto/NewSession_pb2.py +18 -18
- streamlit/proto/NewSession_pb2.pyi +5 -1
- streamlit/runtime/app_session.py +78 -58
- streamlit/runtime/caching/cache_data_api.py +25 -21
- streamlit/runtime/caching/cache_resource_api.py +69 -41
- streamlit/runtime/connection_factory.py +67 -41
- streamlit/runtime/scriptrunner_utils/script_run_context.py +0 -21
- streamlit/runtime/state/query_params.py +0 -19
- streamlit/static/index.html +1 -1
- streamlit/static/manifest.json +296 -296
- streamlit/static/static/js/{ErrorOutline.esm.BjVqd_6R.js → ErrorOutline.esm.CiSfK8ht.js} +1 -1
- streamlit/static/static/js/{FileDownload.esm.DJCSsghl.js → FileDownload.esm.ItNjcEfs.js} +1 -1
- streamlit/static/static/js/{FileHelper.C---TH7o.js → FileHelper.xS7f19FE.js} +1 -1
- streamlit/static/static/js/{FormClearHelper.C-6BC487.js → FormClearHelper.N8_BCinn.js} +1 -1
- streamlit/static/static/js/{InputInstructions.sxc3InCI.js → InputInstructions.CrsdK7CQ.js} +1 -1
- streamlit/static/static/js/Particles.BDlTHC3I.js +1 -0
- streamlit/static/static/js/{ProgressBar.BiYsyZCC.js → ProgressBar.Bk2qeHfS.js} +2 -2
- streamlit/static/static/js/{StreamlitSyntaxHighlighter.9jZF8jX1.js → StreamlitSyntaxHighlighter.BcuPrPcw.js} +1 -1
- streamlit/static/static/js/{TableChart.esm.BdA4Q1rZ.js → TableChart.esm.CP7XPz8I.js} +1 -1
- streamlit/static/static/js/Toolbar.DCJcLwve.js +1 -0
- streamlit/static/static/js/{WidgetLabelHelpIconInline.DxODTLS2.js → WidgetLabelHelpIconInline.BPqxu1b-.js} +1 -1
- streamlit/static/static/js/{base-input.Gf1cKuQR.js → base-input.x4muJJ13.js} +4 -4
- streamlit/static/static/js/{checkbox.CnoNruf3.js → checkbox.C5r4AIaH.js} +1 -1
- streamlit/static/static/js/{createDownloadLinkElement.B48AepiL.js → createDownloadLinkElement.C83kkEeT.js} +1 -1
- streamlit/static/static/js/{data-grid-overlay-editor.Cmdq9aqU.js → data-grid-overlay-editor.0sOWm4IB.js} +1 -1
- streamlit/static/static/js/{downloader.CQLoQdMX.js → downloader.C_6FfoEv.js} +1 -1
- streamlit/static/static/js/{embed.oKwocwU8.js → embed.BnJ6-SK4.js} +14 -14
- streamlit/static/static/js/{es6.BRxlY_y5.js → es6.44_BWfFd.js} +2 -2
- streamlit/static/static/js/{formatNumber.DaagZyZe.js → formatNumber.DhHZAosz.js} +1 -1
- streamlit/static/static/js/{iconPosition.Q3hNvmK4.js → iconPosition.shOoQuRR.js} +1 -1
- streamlit/static/static/js/{iframeResizer.contentWindow.B6EBvI9L.js → iframeResizer.contentWindow.savEE5Vs.js} +1 -1
- streamlit/static/static/js/{index.BF23fbfs.js → index.AdijUi9Z.js} +1 -1
- streamlit/static/static/js/{index.OpATzEaW.js → index.B5HlOnvq.js} +1 -1
- streamlit/static/static/js/{index.Ca7MUNWJ.js → index.B6ewTTej.js} +1 -1
- streamlit/static/static/js/{index.CP-hoxJM.js → index.B8Of3XXR.js} +1 -1
- streamlit/static/static/js/{index.whRT3Vm3.js → index.BCaCSVj6.js} +1 -1
- streamlit/static/static/js/index.BE7Rhig1.js +1 -0
- streamlit/static/static/js/{index.BkSwGJoh.js → index.BHpLZ7X6.js} +2 -2
- streamlit/static/static/js/{index.na9UBuse.js → index.BNvP8E5Q.js} +1 -1
- streamlit/static/static/js/{index.CYE7b5Du.js → index.BNzuyXeN.js} +2 -2
- streamlit/static/static/js/{index.slgxPafU.js → index.BT7o4A9V.js} +1 -1
- streamlit/static/static/js/{index.BXEC4cf3.js → index.BYY3iuVE.js} +1 -1
- streamlit/static/static/js/index.BZI7jTDf.js +1 -0
- streamlit/static/static/js/{index.19_qtO6t.js → index.BZXk3Qxq.js} +1 -1
- streamlit/static/static/js/{index.B03eQZoH.js → index.BhQvq6YD.js} +1 -1
- streamlit/static/static/js/{index.WXybx2Xq.js → index.BkIReLGJ.js} +3 -3
- streamlit/static/static/js/{index.BoX8d5rK.js → index.Bl7SMZUw.js} +1 -1
- streamlit/static/static/js/{index.BGBTkulf.js → index.BqtgAGnG.js} +2 -2
- streamlit/static/static/js/{index.KtjGDGY5.js → index.BwnLQnAk.js} +1 -1
- streamlit/static/static/js/index.C1coXTgf.js +2 -0
- streamlit/static/static/js/{index.CVlg41MB.js → index.C6uOmY9O.js} +1 -1
- streamlit/static/static/js/index.CF88nImM.js +1 -0
- streamlit/static/static/js/{index.CFCBhOfx.js → index.CFlGfFvq.js} +1 -1
- streamlit/static/static/js/{index.Xg-Qttib.js → index.CQgiNpC7.js} +1 -1
- streamlit/static/static/js/{index.CCFwVy90.js → index.CZJkiRFm.js} +1 -1
- streamlit/static/static/js/index.Ch1TdQMG.js +1 -0
- streamlit/static/static/js/{index.CvIqsWy1.js → index.Ck2mQvBi.js} +1 -1
- streamlit/static/static/js/{index.BAI9aHCq.js → index.CrD2lwZG.js} +1 -1
- streamlit/static/static/js/index.CySNwKoN.js +2 -0
- streamlit/static/static/js/index.D3LEkXqN.js +1 -0
- streamlit/static/static/js/{index.QTaWooav.js → index.D8BQH06Z.js} +1 -1
- streamlit/static/static/js/{index.B9kZB0o1.js → index.DBtWixG1.js} +1 -1
- streamlit/static/static/js/{index.BzwlrgZO.js → index.DIsNrJpC.js} +1 -1
- streamlit/static/static/js/{index.Fu73QtkD.js → index.DO3HICut.js} +1 -1
- streamlit/static/static/js/{index.KN1VmyYN.js → index.D_ziFad8.js} +1 -1
- streamlit/static/static/js/{index.pU9mQeVC.js → index.Dblsdn8d.js} +1 -1
- streamlit/static/static/js/{index.Boa0Egng.js → index.DcdD0ROn.js} +2 -2
- streamlit/static/static/js/{index.CvB9JBqS.js → index.DfHm3P22.js} +51 -51
- streamlit/static/static/js/{index.BRfGUOQ-.js → index.DiwhD0Ic.js} +46 -46
- streamlit/static/static/js/index.DvZDNiBV.js +11 -0
- streamlit/static/static/js/{index.CJ4oJe0V.js → index.HjydQ4bj.js} +1 -1
- streamlit/static/static/js/{index.BbSFVZ3p.js → index.HsxzYHNf.js} +1 -1
- streamlit/static/static/js/{index.BVT89mQw.js → index.SVJGpnpy.js} +1 -1
- streamlit/static/static/js/index.SjKkVSL7.js +1 -0
- streamlit/static/static/js/index.hX8_3tMP.js +1 -0
- streamlit/static/static/js/{index.CCQ5p_WC.js → index.jZin0w6_.js} +1 -1
- streamlit/static/static/js/{index.BnfTPrHb.js → index.pQvPlPcA.js} +4 -4
- streamlit/static/static/js/index.pzQTLx9j.js +1 -0
- streamlit/static/static/js/{index.D6X2coHR.js → index.s44_OVd6.js} +33 -33
- streamlit/static/static/js/{input.CPzINTl-.js → input.jAD-v9D6.js} +2 -2
- streamlit/static/static/js/{main.DSPn8dUe.js → main.Cas0fuOs.js} +1 -1
- streamlit/static/static/js/{memory.CfD8IGoU.js → memory.ENruL8Qk.js} +1 -1
- streamlit/static/static/js/{number-overlay-editor.4Ae0qegV.js → number-overlay-editor.DAOTdulh.js} +2 -2
- streamlit/static/static/js/{pandasStylerUtils.D2EjZ7k6.js → pandasStylerUtils.DChYgcPq.js} +1 -1
- streamlit/static/static/js/{sandbox.C6vcPIm0.js → sandbox.DWZYRCm0.js} +1 -1
- streamlit/static/static/js/{styled-components.BBmp8buj.js → styled-components.3lwVqgRW.js} +1 -1
- streamlit/static/static/js/{throttle.BPcPpy-S.js → throttle.DfOW1Cns.js} +1 -1
- streamlit/static/static/js/{timepicker.ryzkTs2C.js → timepicker.CXHgL5f9.js} +1 -1
- streamlit/static/static/js/{toConsumableArray.Dg1nDaB_.js → toConsumableArray.DiW0GSDV.js} +1 -1
- streamlit/static/static/js/uniqueId.Dfi3SGKZ.js +1 -0
- streamlit/static/static/js/{useBasicWidgetState.A4U5lzAm.js → useBasicWidgetState.DnPEt_f3.js} +1 -1
- streamlit/static/static/js/{useIntlLocale.DWJgLlNz.js → useIntlLocale.BZEGSOVD.js} +8 -8
- streamlit/static/static/js/{useTextInputAutoExpand.BrBonw8t.js → useTextInputAutoExpand.MGVZMqyt.js} +1 -1
- streamlit/static/static/js/useUpdateUiValue.CPl6CEx3.js +1 -0
- streamlit/static/static/js/{useWaveformController.CBlvXlgZ.js → useWaveformController.DOpzDyZu.js} +1 -1
- streamlit/static/static/js/{withCalculatedWidth.D4cpOyNe.js → withCalculatedWidth.DgKFTeif.js} +1 -1
- streamlit/static/static/js/{withFullScreenWrapper.BMim3w94.js → withFullScreenWrapper.K1jkwhPu.js} +1 -1
- streamlit/user_info.py +225 -166
- {streamlit_nightly-1.52.3.dev20260113.dist-info → streamlit_nightly-1.53.1.dev20260115.dist-info}/METADATA +1 -1
- {streamlit_nightly-1.52.3.dev20260113.dist-info → streamlit_nightly-1.53.1.dev20260115.dist-info}/RECORD +119 -120
- streamlit/commands/experimental_query_params.py +0 -169
- streamlit/static/static/js/Particles.S8yD7iW-.js +0 -1
- streamlit/static/static/js/Toolbar.B9DaaDfN.js +0 -1
- streamlit/static/static/js/index.43b777iP.js +0 -1
- streamlit/static/static/js/index.C0fSEz-3.js +0 -1
- streamlit/static/static/js/index.CIbgt5wY.js +0 -1
- streamlit/static/static/js/index.CSfsEKCF.js +0 -2
- streamlit/static/static/js/index.CrPjcPY1.js +0 -1
- streamlit/static/static/js/index.D1pK_Vw2.js +0 -1
- streamlit/static/static/js/index.DGYHxruh.js +0 -1
- streamlit/static/static/js/index.DJ7P09eb.js +0 -2
- streamlit/static/static/js/index.Dh5SAThV.js +0 -11
- streamlit/static/static/js/index.QHnxuesF.js +0 -1
- streamlit/static/static/js/index.j4fnjyHo.js +0 -1
- streamlit/static/static/js/uniqueId.BFHzT5KQ.js +0 -1
- streamlit/static/static/js/useUpdateUiValue.BkOWyNVX.js +0 -1
- {streamlit_nightly-1.52.3.dev20260113.data → streamlit_nightly-1.53.1.dev20260115.data}/scripts/streamlit.cmd +0 -0
- {streamlit_nightly-1.52.3.dev20260113.dist-info → streamlit_nightly-1.53.1.dev20260115.dist-info}/WHEEL +0 -0
- {streamlit_nightly-1.52.3.dev20260113.dist-info → streamlit_nightly-1.53.1.dev20260115.dist-info}/entry_points.txt +0 -0
- {streamlit_nightly-1.52.3.dev20260113.dist-info → streamlit_nightly-1.53.1.dev20260115.dist-info}/top_level.txt +0 -0
streamlit/static/static/js/{useWaveformController.CBlvXlgZ.js → useWaveformController.DOpzDyZu.js}
RENAMED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{l as Z,r as i,aR as M,ab as $,aS as O}from"./index.BRfGUOQ-.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
|
+
import{l as Z,r as i,aP as M,aa as $,aQ as O}from"./index.DiwhD0Ic.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),S=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),S.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 U=i.useCallback(async()=>{if(!(S.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),S.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(()=>(U(),()=>{A()}),[A,U]),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(S.current||await U(),!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,U,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(S.current||await U(),!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,U]),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};
|
streamlit/static/static/js/{withCalculatedWidth.D4cpOyNe.js → withCalculatedWidth.DgKFTeif.js}
RENAMED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{h as l,k as h,j as s,d as n}from"./index.
|
|
1
|
+
import{h as l,k as h,j as s,d as n}from"./index.DiwhD0Ic.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};
|
streamlit/static/static/js/{withFullScreenWrapper.BMim3w94.js → withFullScreenWrapper.K1jkwhPu.js}
RENAMED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{r as n,
|
|
1
|
+
import{r as n,z as f,b5 as p,b6 as h,l as x,k as y,j as i,h as g}from"./index.DiwhD0Ic.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])},b=({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(b,{children:i(e,{...s})});return t.displayName=`withFullScreenWrapper(${e.displayName||e.name})`,g(t,e)}export{m as E,S as w};
|
streamlit/user_info.py
CHANGED
|
@@ -70,15 +70,19 @@ def login(provider: str | None = None) -> None:
|
|
|
70
70
|
``st.user``. If the provider returns an access token, that
|
|
71
71
|
token is ignored unless you explicitly expose it.
|
|
72
72
|
|
|
73
|
-
For all providers, there are
|
|
74
|
-
``cookie_secret``, which you must specify in an
|
|
75
|
-
in ``secrets.toml``. Other settings must be defined
|
|
76
|
-
``provider`` parameter.
|
|
73
|
+
For all providers, there are three shared settings, ``redirect_uri``,
|
|
74
|
+
``cookie_secret``, and ``expose_tokens``, which you must specify in an
|
|
75
|
+
``[auth]`` dictionary in ``secrets.toml``. Other settings must be defined
|
|
76
|
+
as described in the ``provider`` parameter.
|
|
77
77
|
|
|
78
78
|
- ``redirect_uri`` is your app's absolute URL with the pathname
|
|
79
79
|
``oauth2callback``. For local development using the default port, this is
|
|
80
80
|
``http://localhost:8501/oauth2callback``.
|
|
81
81
|
- ``cookie_secret`` should be a strong, randomly generated secret.
|
|
82
|
+
- ``expose_tokens`` is a list of token types to expose. The supported token
|
|
83
|
+
types are ``"id"`` and ``"access"``. This is an optional setting, and no
|
|
84
|
+
tokens are exposed by default. For information and examples about exposing
|
|
85
|
+
tokens, see |st.user|_.
|
|
82
86
|
|
|
83
87
|
In addition to the shared settings, the following settings are required:
|
|
84
88
|
|
|
@@ -148,26 +152,28 @@ def login(provider: str | None = None) -> None:
|
|
|
148
152
|
using OIDC with Google, see `Google Identity
|
|
149
153
|
<https://developers.google.com/identity/openid-connect/openid-connect>`_.
|
|
150
154
|
|
|
151
|
-
|
|
155
|
+
.. code-block:: toml
|
|
156
|
+
:filename: .streamlit/secrets.toml
|
|
152
157
|
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
158
|
+
[auth]
|
|
159
|
+
redirect_uri = "http://localhost:8501/oauth2callback"
|
|
160
|
+
cookie_secret = "xxx"
|
|
161
|
+
client_id = "xxx"
|
|
162
|
+
client_secret = "xxx"
|
|
163
|
+
server_metadata_url = "https://accounts.google.com/.well-known/openid-configuration" # fmt: skip
|
|
159
164
|
|
|
160
|
-
|
|
165
|
+
.. code-block:: python
|
|
166
|
+
:filename: streamlit_app.py
|
|
161
167
|
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
168
|
+
import streamlit as st
|
|
169
|
+
|
|
170
|
+
if not st.user.is_logged_in:
|
|
171
|
+
if st.button("Log in"):
|
|
172
|
+
st.login()
|
|
173
|
+
else:
|
|
174
|
+
if st.button("Log out"):
|
|
175
|
+
st.logout()
|
|
176
|
+
st.write(f"Hello, {st.user.name}!")
|
|
171
177
|
|
|
172
178
|
**Example 2: Use a named identity provider**
|
|
173
179
|
|
|
@@ -184,25 +190,27 @@ def login(provider: str | None = None) -> None:
|
|
|
184
190
|
`Microsoft identity platform
|
|
185
191
|
<https://learn.microsoft.com/en-us/entra/identity-platform/v2-protocols-oidc#find-your-apps-openid-configuration-document-uri>`_.
|
|
186
192
|
|
|
187
|
-
|
|
193
|
+
.. code-block:: toml
|
|
194
|
+
:filename: .streamlit/secrets.toml
|
|
188
195
|
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
>>>
|
|
193
|
-
>>> [auth.microsoft]
|
|
194
|
-
>>> client_id = "xxx"
|
|
195
|
-
>>> client_secret = "xxx"
|
|
196
|
-
>>> server_metadata_url = "https://login.microsoftonline.com/{tenant}/v2.0/.well-known/openid-configuration"
|
|
196
|
+
[auth]
|
|
197
|
+
redirect_uri = "http://localhost:8501/oauth2callback"
|
|
198
|
+
cookie_secret = "xxx"
|
|
197
199
|
|
|
198
|
-
|
|
200
|
+
[auth.microsoft]
|
|
201
|
+
client_id = "xxx"
|
|
202
|
+
client_secret = "xxx"
|
|
203
|
+
server_metadata_url = "https://login.microsoftonline.com/{tenant}/v2.0/.well-known/openid-configuration"
|
|
199
204
|
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
205
|
+
.. code-block:: python
|
|
206
|
+
:filename: streamlit_app.py
|
|
207
|
+
|
|
208
|
+
import streamlit as st
|
|
209
|
+
|
|
210
|
+
if not st.user.is_logged_in:
|
|
211
|
+
st.login("microsoft")
|
|
212
|
+
else:
|
|
213
|
+
st.write(f"Hello, {st.user.name}!")
|
|
206
214
|
|
|
207
215
|
**Example 3: Use multiple, named providers**
|
|
208
216
|
|
|
@@ -214,34 +222,38 @@ def login(provider: str | None = None) -> None:
|
|
|
214
222
|
set ``{tenant}`` and ``{subdomain}`` in ``server_metadata_url`` for
|
|
215
223
|
Microsoft and Okta, respectively.
|
|
216
224
|
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
>>> cookie_secret = "xxx"
|
|
220
|
-
>>>
|
|
221
|
-
>>> [auth.microsoft]
|
|
222
|
-
>>> client_id = "xxx"
|
|
223
|
-
>>> client_secret = "xxx"
|
|
224
|
-
>>> server_metadata_url = "https://login.microsoftonline.com/{tenant}/v2.0/.well-known/openid-configuration"
|
|
225
|
-
>>>
|
|
226
|
-
>>> [auth.okta]
|
|
227
|
-
>>> client_id = "xxx"
|
|
228
|
-
>>> client_secret = "xxx"
|
|
229
|
-
>>> server_metadata_url = "https://{subdomain}.okta.com/.well-known/openid-configuration" # fmt: skip
|
|
225
|
+
.. code-block:: toml
|
|
226
|
+
:filename: .streamlit/secrets.toml
|
|
230
227
|
|
|
231
|
-
|
|
228
|
+
[auth]
|
|
229
|
+
redirect_uri = "http://localhost:8501/oauth2callback"
|
|
230
|
+
cookie_secret = "xxx"
|
|
232
231
|
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
232
|
+
[auth.microsoft]
|
|
233
|
+
client_id = "xxx"
|
|
234
|
+
client_secret = "xxx"
|
|
235
|
+
server_metadata_url = "https://login.microsoftonline.com/{tenant}/v2.0/.well-known/openid-configuration"
|
|
236
|
+
|
|
237
|
+
[auth.okta]
|
|
238
|
+
client_id = "xxx"
|
|
239
|
+
client_secret = "xxx"
|
|
240
|
+
server_metadata_url = "https://{subdomain}.okta.com/.well-known/openid-configuration"
|
|
241
|
+
|
|
242
|
+
.. code-block:: python
|
|
243
|
+
:filename: streamlit_app.py
|
|
244
|
+
|
|
245
|
+
import streamlit as st
|
|
246
|
+
|
|
247
|
+
if not st.user.is_logged_in:
|
|
248
|
+
st.header("Log in:")
|
|
249
|
+
if st.button("Microsoft"):
|
|
250
|
+
st.login("microsoft")
|
|
251
|
+
if st.button("Okta"):
|
|
252
|
+
st.login("okta")
|
|
253
|
+
else:
|
|
254
|
+
if st.button("Log out"):
|
|
255
|
+
st.logout()
|
|
256
|
+
st.write(f"Hello, {st.user.name}!")
|
|
245
257
|
|
|
246
258
|
**Example 4: Change the default connection settings**
|
|
247
259
|
|
|
@@ -256,28 +268,30 @@ def login(provider: str | None = None) -> None:
|
|
|
256
268
|
`Customize Signup and Login Prompts
|
|
257
269
|
<https://auth0.com/docs/customize/login-pages/universal-login/customize-signup-and-login-prompts>`_.
|
|
258
270
|
|
|
259
|
-
|
|
271
|
+
.. code-block:: toml
|
|
272
|
+
:filename: .streamlit/secrets.toml
|
|
260
273
|
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
>>>
|
|
265
|
-
>>> [auth.auth0]
|
|
266
|
-
>>> client_id = "xxx"
|
|
267
|
-
>>> client_secret = "xxx"
|
|
268
|
-
>>> server_metadata_url = "https://{account}.{region}.auth0.com/.well-known/openid-configuration" # fmt: skip
|
|
269
|
-
>>> client_kwargs = { "prompt" = "login" }
|
|
274
|
+
[auth]
|
|
275
|
+
redirect_uri = "http://localhost:8501/oauth2callback"
|
|
276
|
+
cookie_secret = "xxx"
|
|
270
277
|
|
|
271
|
-
|
|
278
|
+
[auth.auth0]
|
|
279
|
+
client_id = "xxx"
|
|
280
|
+
client_secret = "xxx"
|
|
281
|
+
server_metadata_url = "https://{account}.{region}.auth0.com/.well-known/openid-configuration"
|
|
282
|
+
client_kwargs = { "prompt" = "login" }
|
|
272
283
|
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
284
|
+
.. code-block:: python
|
|
285
|
+
:filename: streamlit_app.py
|
|
286
|
+
|
|
287
|
+
import streamlit as st
|
|
288
|
+
|
|
289
|
+
if st.button("Log in"):
|
|
290
|
+
st.login("auth0")
|
|
291
|
+
if st.user.is_logged_in:
|
|
292
|
+
if st.button("Log out"):
|
|
293
|
+
st.logout()
|
|
294
|
+
st.write(f"Hello, {st.user.name}!)
|
|
281
295
|
|
|
282
296
|
"""
|
|
283
297
|
if provider is None:
|
|
@@ -382,37 +396,38 @@ def _get_user_info() -> UserInfoType:
|
|
|
382
396
|
|
|
383
397
|
class TokensProxy(Mapping[str, str]):
|
|
384
398
|
"""
|
|
385
|
-
A read-only, dict-like object for accessing exposed tokens from the
|
|
399
|
+
A read-only, dict-like object for accessing exposed tokens from the\
|
|
386
400
|
identity provider.
|
|
387
401
|
|
|
388
402
|
This class provides access to tokens that have been explicitly exposed via
|
|
389
403
|
the ``expose_tokens`` setting in your authentication configuration. Tokens
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
type as a string or multiple token types as a list. Streamlit
|
|
397
|
-
exposing ``"id"`` tokens
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
.. Warning::
|
|
404
|
+
contain sensitive credentials that your app can use to authenticate with
|
|
405
|
+
external services on behalf of the logged-in user.
|
|
406
|
+
|
|
407
|
+
To expose tokens in ``st.user.tokens``, add the ``expose_tokens`` parameter to your authentication
|
|
408
|
+
configuration in ``.streamlit/secrets.toml``. ``expose_tokens`` must be in
|
|
409
|
+
the ``[auth]`` section and can't be a nested dictionary. You can specify a
|
|
410
|
+
single token type as a string or multiple token types as a list. Streamlit
|
|
411
|
+
supports exposing ``"id"`` tokens and ``"access"`` tokens. If
|
|
412
|
+
``expose_tokens`` isn't configured, ``st.user.tokens`` is an empty dict.
|
|
413
|
+
|
|
414
|
+
.. warning::
|
|
402
415
|
Tokens are sensitive credentials that should be handled securely. Never
|
|
403
416
|
expose tokens in your app's UI, logs, or error messages. Only use tokens
|
|
404
417
|
for server-side API calls, and be mindful of token expiration times.
|
|
405
418
|
Only expose tokens if your app needs them for specific API integrations.
|
|
406
419
|
|
|
407
|
-
You can access token values using either key notation
|
|
408
|
-
|
|
409
|
-
prevent accidental modification of sensitive
|
|
420
|
+
You can access token values using either key or attribute notation. For
|
|
421
|
+
example, use ``st.user.tokens["id"]`` or ``st.user.tokens.id`` to access
|
|
422
|
+
the ``id`` token. The object is read-only to prevent accidental modification of sensitive
|
|
423
|
+
credentials.
|
|
410
424
|
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
425
|
+
Attributes
|
|
426
|
+
----------
|
|
427
|
+
id : str
|
|
428
|
+
The identity token. This is only available if ``"id"`` is in ``expose_tokens``.
|
|
429
|
+
access : str
|
|
430
|
+
The access token. This is only available if ``"access"`` is in ``expose_tokens``.
|
|
416
431
|
|
|
417
432
|
Examples
|
|
418
433
|
--------
|
|
@@ -421,27 +436,59 @@ class TokensProxy(Mapping[str, str]):
|
|
|
421
436
|
To expose only the identity token, add ``expose_tokens`` to your
|
|
422
437
|
authentication configuration. This example uses an unnamed default provider.
|
|
423
438
|
|
|
424
|
-
|
|
439
|
+
.. code-block:: toml
|
|
440
|
+
:filename: .streamlit/secrets.toml
|
|
425
441
|
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
442
|
+
[auth]
|
|
443
|
+
redirect_uri = "http://localhost:8501/oauth2callback"
|
|
444
|
+
cookie_secret = "xxx"
|
|
445
|
+
client_id = "xxx"
|
|
446
|
+
client_secret = "xxx"
|
|
447
|
+
server_metadata_url = "https://accounts.google.com/.well-known/openid-configuration"
|
|
448
|
+
expose_tokens = "id"
|
|
433
449
|
|
|
434
|
-
|
|
450
|
+
.. code-block:: python
|
|
451
|
+
:filename: streamlit_app.py
|
|
435
452
|
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
453
|
+
import streamlit as st
|
|
454
|
+
|
|
455
|
+
if st.user.is_logged_in:
|
|
456
|
+
id_token = st.user.tokens["id"]
|
|
457
|
+
# Use the token for API verification
|
|
458
|
+
|
|
459
|
+
**Example 2: Expose both ID and access tokens**
|
|
460
|
+
|
|
461
|
+
You can use a list to expose multiple tokens. If you use one or more named
|
|
462
|
+
identity providers, the same tokens must be exposed for all providers in
|
|
463
|
+
the shared ``[auth]`` section.
|
|
464
|
+
|
|
465
|
+
.. code-block:: toml
|
|
466
|
+
:filename: .streamlit/secrets.toml
|
|
467
|
+
|
|
468
|
+
[auth]
|
|
469
|
+
redirect_uri = "http://localhost:8501/oauth2callback"
|
|
470
|
+
cookie_secret = "xxx"
|
|
471
|
+
expose_tokens = ["id", "access"]
|
|
472
|
+
|
|
473
|
+
[auth.google]
|
|
474
|
+
client_id = "xxx"
|
|
475
|
+
client_secret = "xxx"
|
|
476
|
+
server_metadata_url = "https://accounts.google.com/.well-known/openid-configuration"
|
|
477
|
+
|
|
478
|
+
[auth.microsoft]
|
|
479
|
+
client_id = "xxx"
|
|
480
|
+
client_secret = "xxx"
|
|
481
|
+
server_metadata_url = "https://login.microsoftonline.com/{tenant}/v2.0/.well-known/openid-configuration"
|
|
482
|
+
|
|
483
|
+
.. code-block:: python
|
|
484
|
+
:filename: streamlit_app.py
|
|
485
|
+
|
|
486
|
+
import streamlit as st
|
|
487
|
+
|
|
488
|
+
if st.user.is_logged_in:
|
|
489
|
+
id_token = st.user.tokens["id"]
|
|
490
|
+
access_token = st.user.tokens["access"]
|
|
491
|
+
# Use the tokens for API verification
|
|
445
492
|
"""
|
|
446
493
|
|
|
447
494
|
def __init__(self, tokens: dict[str, str]) -> None:
|
|
@@ -511,11 +558,15 @@ class UserInfoProxy(Mapping[str, str | bool | TokensProxy | None]):
|
|
|
511
558
|
|
|
512
559
|
Attributes
|
|
513
560
|
----------
|
|
514
|
-
is_logged_in: bool
|
|
561
|
+
is_logged_in : bool
|
|
515
562
|
Whether a user is logged in. For a locally running app, this attribute
|
|
516
563
|
is only available when authentication (``st.login()``) is configured in
|
|
517
564
|
``secrets.toml``. Otherwise, it does not exist.
|
|
518
565
|
|
|
566
|
+
tokens: TokensProxy
|
|
567
|
+
A read-only, dict-like object for accessing exposed tokens from the
|
|
568
|
+
identity provider.
|
|
569
|
+
|
|
519
570
|
Examples
|
|
520
571
|
--------
|
|
521
572
|
**Example 1: Google's identity token**
|
|
@@ -529,32 +580,36 @@ class UserInfoProxy(Mapping[str, str | bool | TokensProxy | None]):
|
|
|
529
580
|
<https://developers.google.com/identity/openid-connect/openid-connect#obtainuserinfo>`_
|
|
530
581
|
in Google's docs.
|
|
531
582
|
|
|
532
|
-
|
|
583
|
+
.. code-block:: python
|
|
584
|
+
:filename: streamlit_app.py
|
|
533
585
|
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
586
|
+
import streamlit as st
|
|
587
|
+
|
|
588
|
+
if st.user.is_logged_in:
|
|
589
|
+
st.write(st.user)
|
|
538
590
|
|
|
539
591
|
Displayed data when a user is logged in:
|
|
540
592
|
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
593
|
+
.. code-block:: json
|
|
594
|
+
|
|
595
|
+
{
|
|
596
|
+
"is_logged_in":true
|
|
597
|
+
"iss":"https://accounts.google.com"
|
|
598
|
+
"azp":"{client_id}.apps.googleusercontent.com"
|
|
599
|
+
"aud":"{client_id}.apps.googleusercontent.com"
|
|
600
|
+
"sub":"{unique_user_id}"
|
|
601
|
+
"email":"{user}@gmail.com"
|
|
602
|
+
"email_verified":true
|
|
603
|
+
"at_hash":"{access_token_hash}"
|
|
604
|
+
"nonce":"{nonce_string}"
|
|
605
|
+
"name":"{full_name}"
|
|
606
|
+
"picture":"https://lh3.googleusercontent.com/a/{content_path}"
|
|
607
|
+
"given_name":"{given_name}"
|
|
608
|
+
"family_name":"{family_name}"
|
|
609
|
+
"iat":{issued_time}
|
|
610
|
+
"exp":{expiration_time}
|
|
611
|
+
"tokens":{}
|
|
612
|
+
}
|
|
558
613
|
|
|
559
614
|
**Example 2: Microsoft's identity token**
|
|
560
615
|
|
|
@@ -565,32 +620,36 @@ class UserInfoProxy(Mapping[str, str | bool | TokensProxy | None]):
|
|
|
565
620
|
<https://learn.microsoft.com/en-us/entra/identity-platform/id-token-claims-reference>`_
|
|
566
621
|
in Microsoft's docs.
|
|
567
622
|
|
|
568
|
-
|
|
623
|
+
.. code-block:: python
|
|
624
|
+
:filename: streamlit_app.py
|
|
569
625
|
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
626
|
+
import streamlit as st
|
|
627
|
+
|
|
628
|
+
if st.user.is_logged_in:
|
|
629
|
+
st.write(st.user)
|
|
574
630
|
|
|
575
631
|
Displayed data when a user is logged in:
|
|
576
632
|
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
633
|
+
.. code-block:: json
|
|
634
|
+
|
|
635
|
+
{
|
|
636
|
+
"is_logged_in":true
|
|
637
|
+
"ver":"2.0"
|
|
638
|
+
"iss":"https://login.microsoftonline.com/{tenant_id}/v2.0"
|
|
639
|
+
"sub":"{application_user_id}"
|
|
640
|
+
"aud":"{application_id}"
|
|
641
|
+
"exp":{expiration_time}
|
|
642
|
+
"iat":{issued_time}
|
|
643
|
+
"nbf":{start_time}
|
|
644
|
+
"name":"{full_name}"
|
|
645
|
+
"preferred_username":"{username}"
|
|
646
|
+
"oid":"{user_GUID}"
|
|
647
|
+
"email":"{email}"
|
|
648
|
+
"tid":"{tenant_id}"
|
|
649
|
+
"nonce":"{nonce_string}"
|
|
650
|
+
"aio":"{opaque_string}"
|
|
651
|
+
"tokens":{}
|
|
652
|
+
}
|
|
594
653
|
"""
|
|
595
654
|
|
|
596
655
|
def __getitem__(self, key: str) -> str | bool | None | TokensProxy:
|