streamlit-bar-visualizer 0.1.2__tar.gz → 0.1.3__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (16) hide show
  1. {streamlit_bar_visualizer-0.1.2/streamlit_bar_visualizer.egg-info → streamlit_bar_visualizer-0.1.3}/PKG-INFO +1 -1
  2. {streamlit_bar_visualizer-0.1.2 → streamlit_bar_visualizer-0.1.3}/pyproject.toml +1 -1
  3. {streamlit_bar_visualizer-0.1.2 → streamlit_bar_visualizer-0.1.3}/setup.py +1 -1
  4. {streamlit_bar_visualizer-0.1.2 → streamlit_bar_visualizer-0.1.3}/streamlit_bar_visualizer/frontend/build/static/js/index.js +1 -1
  5. {streamlit_bar_visualizer-0.1.2 → streamlit_bar_visualizer-0.1.3/streamlit_bar_visualizer.egg-info}/PKG-INFO +1 -1
  6. {streamlit_bar_visualizer-0.1.2 → streamlit_bar_visualizer-0.1.3}/LICENSE +0 -0
  7. {streamlit_bar_visualizer-0.1.2 → streamlit_bar_visualizer-0.1.3}/MANIFEST.in +0 -0
  8. {streamlit_bar_visualizer-0.1.2 → streamlit_bar_visualizer-0.1.3}/README.md +0 -0
  9. {streamlit_bar_visualizer-0.1.2 → streamlit_bar_visualizer-0.1.3}/setup.cfg +0 -0
  10. {streamlit_bar_visualizer-0.1.2 → streamlit_bar_visualizer-0.1.3}/streamlit_bar_visualizer/__init__.py +0 -0
  11. {streamlit_bar_visualizer-0.1.2 → streamlit_bar_visualizer-0.1.3}/streamlit_bar_visualizer/frontend/build/index.html +0 -0
  12. {streamlit_bar_visualizer-0.1.2 → streamlit_bar_visualizer-0.1.3}/streamlit_bar_visualizer/frontend/build/static/css/index.css +0 -0
  13. {streamlit_bar_visualizer-0.1.2 → streamlit_bar_visualizer-0.1.3}/streamlit_bar_visualizer.egg-info/SOURCES.txt +0 -0
  14. {streamlit_bar_visualizer-0.1.2 → streamlit_bar_visualizer-0.1.3}/streamlit_bar_visualizer.egg-info/dependency_links.txt +0 -0
  15. {streamlit_bar_visualizer-0.1.2 → streamlit_bar_visualizer-0.1.3}/streamlit_bar_visualizer.egg-info/requires.txt +0 -0
  16. {streamlit_bar_visualizer-0.1.2 → streamlit_bar_visualizer-0.1.3}/streamlit_bar_visualizer.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: streamlit-bar-visualizer
3
- Version: 0.1.2
3
+ Version: 0.1.3
4
4
  Summary: Beautiful audio frequency visualizer component for Streamlit with multiple state animations
5
5
  Home-page: https://github.com/bensonbs/streamlit-bar-visualizer
6
6
  Author: Benson Sung
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "streamlit-bar-visualizer"
7
- version = "0.1.2"
7
+ version = "0.1.3"
8
8
  description = "Beautiful audio frequency visualizer component for Streamlit with multiple state animations"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.8"
@@ -6,7 +6,7 @@ long_description = (this_directory / "README.md").read_text()
6
6
 
7
7
  setuptools.setup(
8
8
  name="streamlit-bar-visualizer",
9
- version="0.1.2",
9
+ version="0.1.3",
10
10
  author="Benson Sung",
11
11
  author_email="benson.bs.sung@gmail.com",
12
12
  description="Beautiful audio frequency visualizer component for Streamlit with multiple state animations",
@@ -60,4 +60,4 @@ Error generating stack: `+s.message+`
60
60
  background-color: var(--background-color);
61
61
  color: var(--text-color);
62
62
  }
63
- `)};function j1(e){var t=!1;try{t=e instanceof BigInt64Array||e instanceof BigUint64Array}catch{}return e instanceof Int8Array||e instanceof Uint8Array||e instanceof Uint8ClampedArray||e instanceof Int16Array||e instanceof Uint16Array||e instanceof Int32Array||e instanceof Uint32Array||e instanceof Float32Array||e instanceof Float64Array||t}var sg=function(){var e=function(t,n){return e=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(r,i){r.__proto__=i}||function(r,i){for(var s in i)Object.prototype.hasOwnProperty.call(i,s)&&(r[s]=i[s])},e(t,n)};return function(t,n){if(typeof n!="function"&&n!==null)throw new TypeError("Class extends value "+String(n)+" is not a constructor or null");e(t,n);function r(){this.constructor=t}t.prototype=n===null?Object.create(n):(r.prototype=n.prototype,new r)}}(),V1=function(e){sg(t,e);function t(){return e!==null&&e.apply(this,arguments)||this}return t.prototype.componentDidMount=function(){$e.setFrameHeight()},t.prototype.componentDidUpdate=function(){$e.setFrameHeight()},t}(fr.PureComponent);function $1(e){var t=function(n){sg(r,n);function r(i){var s=n.call(this,i)||this;return s.componentDidMount=function(){$e.events.addEventListener($e.RENDER_EVENT,s.onRenderEvent),$e.setComponentReady()},s.componentDidUpdate=function(){s.state.componentError!=null&&$e.setFrameHeight()},s.componentWillUnmount=function(){$e.events.removeEventListener($e.RENDER_EVENT,s.onRenderEvent)},s.onRenderEvent=function(o){s.setState({renderData:o.detail})},s.state={renderData:void 0,componentError:void 0},s}return r.prototype.render=function(){return this.state.componentError!=null?fr.createElement("div",null,fr.createElement("h1",null,"Component Error"),fr.createElement("span",null,this.state.componentError.message)):this.state.renderData==null?null:fr.createElement(e,{width:window.innerWidth,disabled:this.state.renderData.disabled,args:this.state.renderData.args,theme:this.state.renderData.theme})},r.getDerivedStateFromError=function(i){return{componentError:i}},r}(fr.PureComponent);return ew(t,e)}function og(e){var t,n,r="";if(typeof e=="string"||typeof e=="number")r+=e;else if(typeof e=="object")if(Array.isArray(e)){var i=e.length;for(t=0;t<i;t++)e[t]&&(n=og(e[t]))&&(r&&(r+=" "),r+=n)}else for(n in e)e[n]&&(r&&(r+=" "),r+=n);return r}function W1(){for(var e,t,n=0,r="",i=arguments.length;n<i;n++)(e=arguments[n])&&(t=og(e))&&(r&&(r+=" "),r+=t);return r}function lg(...e){return W1(e)}function H1(e,t={}){const n=new(window.AudioContext||window.webkitAudioContext),r=n.createMediaStreamSource(e),i=n.createAnalyser();return t.fftSize&&(i.fftSize=t.fftSize),t.smoothingTimeConstant!==void 0&&(i.smoothingTimeConstant=t.smoothingTimeConstant),t.minDecibels!==void 0&&(i.minDecibels=t.minDecibels),t.maxDecibels!==void 0&&(i.maxDecibels=t.maxDecibels),r.connect(i),{analyser:i,audioContext:n,cleanup:()=>{r.disconnect(),n.close()}}}const Y1={bands:5,loPass:100,hiPass:600,updateInterval:32,analyserOptions:{fftSize:2048}},Q1=e=>{if(e===-1/0)return 0;const r=1-Math.max(-100,Math.min(-10,e))*-1/100;return Math.sqrt(r)};function K1(e,t={}){var l,a,u,c;const n=ht.useMemo(()=>({...Y1,...t}),[t.bands,t.loPass,t.hiPass,t.updateInterval,(l=t.analyserOptions)==null?void 0:l.fftSize,(a=t.analyserOptions)==null?void 0:a.smoothingTimeConstant,(u=t.analyserOptions)==null?void 0:u.minDecibels,(c=t.analyserOptions)==null?void 0:c.maxDecibels]),[r,i]=ht.useState(()=>new Array(n.bands).fill(0)),s=ht.useRef(new Array(n.bands).fill(0)),o=ht.useRef(void 0);return ht.useEffect(()=>{if(!e){const b=new Array(n.bands).fill(0);i(b),s.current=b;return}const{analyser:f,cleanup:m}=H1(e,n.analyserOptions),g=f.frequencyBinCount,v=new Float32Array(g),S=n.loPass,Q=n.hiPass,h=Q-S,d=Math.ceil(h/n.bands);let y=0;const w=n.updateInterval,I=b=>{if(b-y>=w){f.getFloatFrequencyData(v);const E=new Array(n.bands);for(let W=0;W<n.bands;W++){let A=0,Nt=0;const sn=S+W*d,on=Math.min(S+(W+1)*d,Q);for(let Mr=sn;Mr<on;Mr++)A+=Q1(v[Mr]),Nt++;E[W]=Nt>0?A/Nt:0}let O=!1;for(let W=0;W<E.length;W++)if(Math.abs(E[W]-s.current[W])>.01){O=!0;break}O&&(s.current=E,i(E)),y=b}o.current=requestAnimationFrame(I)};return o.current=requestAnimationFrame(I),()=>{m(),o.current&&cancelAnimationFrame(o.current)}},[e,n]),r}const J1=(e,t,n)=>{const r=ht.useRef(0),[i,s]=ht.useState([]),o=ht.useRef(null),l=ht.useMemo(()=>e==="thinking"||e==="listening"?X1(t):e==="connecting"||e==="initializing"?G1(t):e===void 0||e==="speaking"?[new Array(t).fill(0).map((a,u)=>u)]:[[]],[e,t]);return ht.useEffect(()=>{r.current=0,s(l[0]||[])},[l]),ht.useEffect(()=>{let a=performance.now();const u=c=>{c-a>=n&&(r.current=(r.current+1)%l.length,s(l[r.current]||[]),a=c),o.current=requestAnimationFrame(u)};return o.current=requestAnimationFrame(u),()=>{o.current!==null&&cancelAnimationFrame(o.current)}},[n,l]),i},G1=e=>{const t=[];for(let n=0;n<e;n++)t.push([n,e-1-n]);return t},X1=e=>[[Math.floor(e/2)],[-1]],ag=ht.forwardRef(({state:e,barCount:t=15,mediaStream:n,minHeight:r=20,maxHeight:i=100,demo:s=!1,centerAlign:o=!1,className:l,style:a,...u},c)=>{const f=K1(n,{bands:t,loPass:100,hiPass:200}),m=ht.useRef(new Array(t).fill(.2)),[g,v]=ht.useState(()=>new Array(t).fill(.2)),S=ht.useRef(void 0);ht.useEffect(()=>{if(!s)return;if(e!=="speaking"&&e!=="listening"){const b=new Array(t).fill(.2);m.current=b,v(b);return}let d=0;const y=50,w=Date.now()/1e3,I=b=>{if(b-d>=y){const E=Date.now()/1e3-w,O=new Array(t);for(let A=0;A<t;A++){const Nt=A*.5,sn=Math.sin(E*2+Nt)*.3+.5,on=Math.random()*.2;O[A]=Math.max(.1,Math.min(1,sn+on))}let W=!1;for(let A=0;A<t;A++)if(Math.abs(O[A]-m.current[A])>.05){W=!0;break}W&&(m.current=O,v(O)),d=b}S.current=requestAnimationFrame(I)};return S.current=requestAnimationFrame(I),()=>{S.current&&cancelAnimationFrame(S.current)}},[s,e,t]);const Q=ht.useMemo(()=>s?g:f,[s,g,f]),h=J1(e,t,e==="connecting"?2e3/t:e==="thinking"?150:e==="listening"?500:1e3);return Un.jsx("div",{ref:c,"data-state":e,className:lg("relative flex justify-center gap-1.5",o?"items-center":"items-end","bg-muted h-28 w-full overflow-hidden rounded-lg",l),style:{...a},...u,children:Q.map((d,y)=>{const w=Math.min(i,Math.max(r,d*100+5)),I=(h==null?void 0:h.includes(y))??!1;return Un.jsx(ug,{heightPct:w,isHighlighted:I,state:e},y)})})}),ug=ht.memo(({heightPct:e,isHighlighted:t,state:n})=>Un.jsx("div",{"data-highlighted":t,className:lg("max-w-[12px] min-w-[8px] flex-1 transition-all duration-150","rounded-full","bg-border data-[highlighted=true]:bg-primary",n==="speaking"&&"bg-primary",n==="thinking"&&t&&"animate-pulse"),style:{height:`${e}%`,animationDuration:n==="thinking"?"300ms":void 0}}));ug.displayName="Bar";const cg=ht.memo(ag,(e,t)=>e.state===t.state&&e.barCount===t.barCount&&e.mediaStream===t.mediaStream&&e.minHeight===t.minHeight&&e.maxHeight===t.maxHeight&&e.demo===t.demo&&e.centerAlign===t.centerAlign&&e.className===t.className&&JSON.stringify(e.style)===JSON.stringify(t.style));ag.displayName="BarVisualizerComponent";cg.displayName="BarVisualizer";class Z1 extends V1{constructor(){super(...arguments);Re(this,"state",{mediaStream:null,audioState:"idle"});Re(this,"audioRef",ht.createRef());Re(this,"render",()=>{const n=this.props.args.state||"listening",r=this.props.args.barCount||20,i=this.props.args.minHeight||15,s=this.props.args.maxHeight||90,o=this.props.args.demo!==!1,l=this.props.args.centerAlign||!1,a=this.props.args.streamUrl;let u;if(n==="auto"){switch(this.state.audioState){case"loading":u="thinking";break;case"playing":u="speaking";break;case"ended":u="initializing";break;case"idle":default:u="listening";break}console.log("🤖 Auto mode: audioState =",this.state.audioState,"→ displayState =",u)}else u=n;const c=o||a&&!this.state.mediaStream;return a&&!this.state.mediaStream&&console.log("⏳ 音頻加載中... (UI 已顯示,使用假數據動畫,狀態:",u,")"),Un.jsxs("div",{className:"streamlit-bar-visualizer",children:[a&&Un.jsx("audio",{ref:this.audioRef,src:a,controls:!1,autoPlay:!0,crossOrigin:"anonymous",style:{display:"none"}}),Un.jsx(cg,{mediaStream:this.state.mediaStream,state:u,barCount:r,minHeight:i,maxHeight:s,demo:c,centerAlign:l})]})});Re(this,"componentDidMount",async()=>{const n=this.props.args.streamUrl;if(this.props.args.demo,n&&this.audioRef.current){console.log("🎵 Attempting to load audio stream:",n);const r=this.audioRef.current;this.setState({audioState:"loading"}),r.addEventListener("loadstart",this.handleLoadStart),r.addEventListener("playing",this.handlePlaying),r.addEventListener("ended",this.handleEnded);try{await new Promise((s,o)=>{const l=setTimeout(()=>o(new Error("Audio load timeout")),1e4);r.oncanplay=()=>{clearTimeout(l),s(!0)},r.onerror=a=>{var u,c,f;clearTimeout(l),console.error("❌ Audio element error event:",a),console.error(" Error code:",(u=r.error)==null?void 0:u.code),console.error(" Error message:",(c=r.error)==null?void 0:c.message),console.error(" Network state:",r.networkState),console.error(" Ready state:",r.readyState),o(new Error(`Audio load error: ${((f=r.error)==null?void 0:f.message)||"Unknown error"}`))}}),r.muted=!0,await r.play(),console.log("✅ Audio stream is playing (initially muted)"),await new Promise(s=>setTimeout(s,100));const i=r;if(typeof i.captureStream=="function"){const s=i.captureStream();this.setState({mediaStream:s}),console.log("✅ Audio stream captured successfully via captureStream()"),r.muted=!1,console.log("🔊 Audio unmuted - you should now hear the sound")}else if(typeof i.mozCaptureStream=="function"){const s=i.mozCaptureStream();this.setState({mediaStream:s}),console.log("✅ Audio stream captured successfully via mozCaptureStream() (Firefox)"),r.muted=!1,console.log("🔊 Audio unmuted - you should now hear the sound")}else console.error("❌ HTMLAudioElement.captureStream() is not supported in this browser.")}catch(i){console.error("❌ Error playing or capturing audio stream:",i),console.warn("⚠️ Audio stream failed. Not falling back to microphone. Check console for errors.")}}else console.log("🎭 No audio stream provided - running in demo mode (using fake audio data)");$e.setFrameHeight()});Re(this,"componentWillUnmount",()=>{if(this.state.mediaStream&&!this.props.args.streamUrl&&this.state.mediaStream.getTracks().forEach(n=>n.stop()),this.audioRef.current){const n=this.audioRef.current;n.pause(),n.removeEventListener("loadstart",this.handleLoadStart),n.removeEventListener("playing",this.handlePlaying),n.removeEventListener("ended",this.handleEnded)}});Re(this,"componentDidUpdate",async n=>{const r=n.args.streamUrl,i=this.props.args.streamUrl;if(i&&r!==i&&this.audioRef.current){console.log("🔄 Stream URL changed, updating audio source..."),this.setState({mediaStream:null,audioState:"loading"});const s=this.audioRef.current;s.removeEventListener("loadstart",this.handleLoadStart),s.removeEventListener("playing",this.handlePlaying),s.removeEventListener("ended",this.handleEnded),s.addEventListener("loadstart",this.handleLoadStart),s.addEventListener("playing",this.handlePlaying),s.addEventListener("ended",this.handleEnded),s.src=i;try{s.muted=!0,await s.play();const o=s;if(typeof o.captureStream=="function"){const l=o.captureStream();this.setState({mediaStream:l}),console.log("✅ Audio stream updated and captured successfully"),s.muted=!1,console.log("🔊 Audio unmuted")}else if(typeof o.mozCaptureStream=="function"){const l=o.mozCaptureStream();this.setState({mediaStream:l}),console.log("✅ Audio stream updated and captured successfully (Firefox)"),s.muted=!1,console.log("🔊 Audio unmuted")}}catch(o){console.error("❌ Error updating audio stream:",o)}}$e.setFrameHeight()});Re(this,"handleLoadStart",()=>{console.log("📥 Audio loadstart"),this.setState({audioState:"loading"})});Re(this,"handlePlaying",()=>{console.log("▶️ Audio playing"),this.setState({audioState:"playing"})});Re(this,"handleEnded",()=>{console.log("⏹️ Audio ended"),this.setState({audioState:"ended"})})}}const q1=$1(Z1);zv.render(Un.jsx(fr.StrictMode,{children:Un.jsx(q1,{})}),document.getElementById("root"));
63
+ `)};function j1(e){var t=!1;try{t=e instanceof BigInt64Array||e instanceof BigUint64Array}catch{}return e instanceof Int8Array||e instanceof Uint8Array||e instanceof Uint8ClampedArray||e instanceof Int16Array||e instanceof Uint16Array||e instanceof Int32Array||e instanceof Uint32Array||e instanceof Float32Array||e instanceof Float64Array||t}var sg=function(){var e=function(t,n){return e=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(r,i){r.__proto__=i}||function(r,i){for(var s in i)Object.prototype.hasOwnProperty.call(i,s)&&(r[s]=i[s])},e(t,n)};return function(t,n){if(typeof n!="function"&&n!==null)throw new TypeError("Class extends value "+String(n)+" is not a constructor or null");e(t,n);function r(){this.constructor=t}t.prototype=n===null?Object.create(n):(r.prototype=n.prototype,new r)}}(),V1=function(e){sg(t,e);function t(){return e!==null&&e.apply(this,arguments)||this}return t.prototype.componentDidMount=function(){$e.setFrameHeight()},t.prototype.componentDidUpdate=function(){$e.setFrameHeight()},t}(fr.PureComponent);function $1(e){var t=function(n){sg(r,n);function r(i){var s=n.call(this,i)||this;return s.componentDidMount=function(){$e.events.addEventListener($e.RENDER_EVENT,s.onRenderEvent),$e.setComponentReady()},s.componentDidUpdate=function(){s.state.componentError!=null&&$e.setFrameHeight()},s.componentWillUnmount=function(){$e.events.removeEventListener($e.RENDER_EVENT,s.onRenderEvent)},s.onRenderEvent=function(o){s.setState({renderData:o.detail})},s.state={renderData:void 0,componentError:void 0},s}return r.prototype.render=function(){return this.state.componentError!=null?fr.createElement("div",null,fr.createElement("h1",null,"Component Error"),fr.createElement("span",null,this.state.componentError.message)):this.state.renderData==null?null:fr.createElement(e,{width:window.innerWidth,disabled:this.state.renderData.disabled,args:this.state.renderData.args,theme:this.state.renderData.theme})},r.getDerivedStateFromError=function(i){return{componentError:i}},r}(fr.PureComponent);return ew(t,e)}function og(e){var t,n,r="";if(typeof e=="string"||typeof e=="number")r+=e;else if(typeof e=="object")if(Array.isArray(e)){var i=e.length;for(t=0;t<i;t++)e[t]&&(n=og(e[t]))&&(r&&(r+=" "),r+=n)}else for(n in e)e[n]&&(r&&(r+=" "),r+=n);return r}function W1(){for(var e,t,n=0,r="",i=arguments.length;n<i;n++)(e=arguments[n])&&(t=og(e))&&(r&&(r+=" "),r+=t);return r}function lg(...e){return W1(e)}function H1(e,t={}){const n=new(window.AudioContext||window.webkitAudioContext),r=n.createMediaStreamSource(e),i=n.createAnalyser();return t.fftSize&&(i.fftSize=t.fftSize),t.smoothingTimeConstant!==void 0&&(i.smoothingTimeConstant=t.smoothingTimeConstant),t.minDecibels!==void 0&&(i.minDecibels=t.minDecibels),t.maxDecibels!==void 0&&(i.maxDecibels=t.maxDecibels),r.connect(i),{analyser:i,audioContext:n,cleanup:()=>{r.disconnect(),n.close()}}}const Y1={bands:5,loPass:100,hiPass:600,updateInterval:32,analyserOptions:{fftSize:2048}},Q1=e=>{if(e===-1/0)return 0;const r=1-Math.max(-100,Math.min(-10,e))*-1/100;return Math.sqrt(r)};function K1(e,t={}){var l,a,u,c;const n=ht.useMemo(()=>({...Y1,...t}),[t.bands,t.loPass,t.hiPass,t.updateInterval,(l=t.analyserOptions)==null?void 0:l.fftSize,(a=t.analyserOptions)==null?void 0:a.smoothingTimeConstant,(u=t.analyserOptions)==null?void 0:u.minDecibels,(c=t.analyserOptions)==null?void 0:c.maxDecibels]),[r,i]=ht.useState(()=>new Array(n.bands).fill(0)),s=ht.useRef(new Array(n.bands).fill(0)),o=ht.useRef(void 0);return ht.useEffect(()=>{if(!e){const b=new Array(n.bands).fill(0);i(b),s.current=b;return}const{analyser:f,cleanup:m}=H1(e,n.analyserOptions),g=f.frequencyBinCount,v=new Float32Array(g),S=n.loPass,Q=n.hiPass,h=Q-S,d=Math.ceil(h/n.bands);let y=0;const w=n.updateInterval,I=b=>{if(b-y>=w){f.getFloatFrequencyData(v);const E=new Array(n.bands);for(let W=0;W<n.bands;W++){let A=0,Nt=0;const sn=S+W*d,on=Math.min(S+(W+1)*d,Q);for(let Mr=sn;Mr<on;Mr++)A+=Q1(v[Mr]),Nt++;E[W]=Nt>0?A/Nt:0}let O=!1;for(let W=0;W<E.length;W++)if(Math.abs(E[W]-s.current[W])>.01){O=!0;break}O&&(s.current=E,i(E)),y=b}o.current=requestAnimationFrame(I)};return o.current=requestAnimationFrame(I),()=>{m(),o.current&&cancelAnimationFrame(o.current)}},[e,n]),r}const J1=(e,t,n)=>{const r=ht.useRef(0),[i,s]=ht.useState([]),o=ht.useRef(null),l=ht.useMemo(()=>e==="thinking"||e==="listening"?X1(t):e==="connecting"||e==="initializing"?G1(t):e===void 0||e==="speaking"?[new Array(t).fill(0).map((a,u)=>u)]:[[]],[e,t]);return ht.useEffect(()=>{r.current=0,s(l[0]||[])},[l]),ht.useEffect(()=>{let a=performance.now();const u=c=>{c-a>=n&&(r.current=(r.current+1)%l.length,s(l[r.current]||[]),a=c),o.current=requestAnimationFrame(u)};return o.current=requestAnimationFrame(u),()=>{o.current!==null&&cancelAnimationFrame(o.current)}},[n,l]),i},G1=e=>{const t=[];for(let n=0;n<e;n++)t.push([n,e-1-n]);return t},X1=e=>[[Math.floor(e/2)],[-1]],ag=ht.forwardRef(({state:e,barCount:t=15,mediaStream:n,minHeight:r=20,maxHeight:i=100,demo:s=!1,centerAlign:o=!1,className:l,style:a,...u},c)=>{const f=K1(n,{bands:t,loPass:100,hiPass:200}),m=ht.useRef(new Array(t).fill(.2)),[g,v]=ht.useState(()=>new Array(t).fill(.2)),S=ht.useRef(void 0);ht.useEffect(()=>{if(!s)return;if(e!=="speaking"&&e!=="listening"){const b=new Array(t).fill(.2);m.current=b,v(b);return}let d=0;const y=50,w=Date.now()/1e3,I=b=>{if(b-d>=y){const E=Date.now()/1e3-w,O=new Array(t);for(let A=0;A<t;A++){const Nt=A*.5,sn=Math.sin(E*2+Nt)*.3+.5,on=Math.random()*.2;O[A]=Math.max(.1,Math.min(1,sn+on))}let W=!1;for(let A=0;A<t;A++)if(Math.abs(O[A]-m.current[A])>.05){W=!0;break}W&&(m.current=O,v(O)),d=b}S.current=requestAnimationFrame(I)};return S.current=requestAnimationFrame(I),()=>{S.current&&cancelAnimationFrame(S.current)}},[s,e,t]);const Q=ht.useMemo(()=>s?g:f,[s,g,f]),h=J1(e,t,e==="connecting"?2e3/t:e==="thinking"?150:e==="listening"?500:1e3);return Un.jsx("div",{ref:c,"data-state":e,className:lg("relative flex justify-center gap-1.5",o?"items-center":"items-end","bg-muted h-28 w-full overflow-hidden rounded-lg",l),style:{...a},...u,children:Q.map((d,y)=>{const w=Math.min(i,Math.max(r,d*100+5)),I=(h==null?void 0:h.includes(y))??!1;return Un.jsx(ug,{heightPct:w,isHighlighted:I,state:e},y)})})}),ug=ht.memo(({heightPct:e,isHighlighted:t,state:n})=>Un.jsx("div",{"data-highlighted":t,className:lg("max-w-[12px] min-w-[8px] flex-1 transition-all duration-150","rounded-full","bg-border data-[highlighted=true]:bg-primary",n==="speaking"&&"bg-primary",n==="thinking"&&t&&"animate-pulse"),style:{height:`${e}%`,animationDuration:n==="thinking"?"300ms":void 0}}));ug.displayName="Bar";const cg=ht.memo(ag,(e,t)=>e.state===t.state&&e.barCount===t.barCount&&e.mediaStream===t.mediaStream&&e.minHeight===t.minHeight&&e.maxHeight===t.maxHeight&&e.demo===t.demo&&e.centerAlign===t.centerAlign&&e.className===t.className&&JSON.stringify(e.style)===JSON.stringify(t.style));ag.displayName="BarVisualizerComponent";cg.displayName="BarVisualizer";class Z1 extends V1{constructor(){super(...arguments);Re(this,"state",{mediaStream:null,audioState:"idle"});Re(this,"audioRef",ht.createRef());Re(this,"render",()=>{const n=this.props.args.state||"listening",r=this.props.args.barCount||20,i=this.props.args.minHeight||15,s=this.props.args.maxHeight||90,o=this.props.args.demo!==!1,l=this.props.args.centerAlign||!1,a=this.props.args.streamUrl;let u;if(n==="auto"){switch(this.state.audioState){case"loading":u="thinking";break;case"playing":u="speaking";break;case"ended":u="initializing";break;case"idle":default:u="listening";break}console.log("🤖 Auto mode: audioState =",this.state.audioState,"→ displayState =",u)}else u=n;const c=o||a&&!this.state.mediaStream;return a&&!this.state.mediaStream&&console.log("⏳ 音頻加載中... (UI 已顯示,使用假數據動畫,狀態:",u,")"),Un.jsxs("div",{className:"streamlit-bar-visualizer",children:[a&&Un.jsx("audio",{ref:this.audioRef,src:a,controls:!1,autoPlay:!0,crossOrigin:"anonymous",style:{display:"none"}}),Un.jsx(cg,{mediaStream:this.state.mediaStream,state:u,barCount:r,minHeight:i,maxHeight:s,demo:c,centerAlign:l})]})});Re(this,"componentDidMount",async()=>{const n=this.props.args.streamUrl;if(this.props.args.demo,n&&this.audioRef.current){console.log("🎵 Attempting to load audio stream:",n);const r=this.audioRef.current;this.setState({audioState:"loading"}),r.addEventListener("loadstart",this.handleLoadStart),r.addEventListener("playing",this.handlePlaying),r.addEventListener("ended",this.handleEnded);try{await new Promise((s,o)=>{const l=setTimeout(()=>o(new Error("Audio load timeout")),1e4);r.oncanplay=()=>{clearTimeout(l),s(!0)},r.onerror=a=>{var u,c,f;clearTimeout(l),console.error("❌ Audio element error event:",a),console.error(" Error code:",(u=r.error)==null?void 0:u.code),console.error(" Error message:",(c=r.error)==null?void 0:c.message),console.error(" Network state:",r.networkState),console.error(" Ready state:",r.readyState),o(new Error(`Audio load error: ${((f=r.error)==null?void 0:f.message)||"Unknown error"}`))}}),r.muted=!0,await r.play(),console.log("✅ Audio stream is playing (initially muted)"),await new Promise(s=>setTimeout(s,100));const i=r;if(typeof i.captureStream=="function"){const s=i.captureStream();this.setState({mediaStream:s}),console.log("✅ Audio stream captured successfully via captureStream()"),r.muted=!1,console.log("🔊 Audio unmuted - you should now hear the sound")}else if(typeof i.mozCaptureStream=="function"){const s=i.mozCaptureStream();this.setState({mediaStream:s}),console.log("✅ Audio stream captured successfully via mozCaptureStream() (Firefox)"),r.muted=!1,console.log("🔊 Audio unmuted - you should now hear the sound")}else console.error("❌ HTMLAudioElement.captureStream() is not supported in this browser.")}catch(i){console.error("❌ Error playing or capturing audio stream:",i),console.warn("⚠️ Audio stream failed. Not falling back to microphone. Check console for errors.")}}else console.log("🎭 No audio stream provided - running in demo mode (using fake audio data)");$e.setFrameHeight()});Re(this,"componentWillUnmount",()=>{if(this.state.mediaStream&&!this.props.args.streamUrl&&this.state.mediaStream.getTracks().forEach(n=>n.stop()),this.audioRef.current){const n=this.audioRef.current;n.pause(),n.removeEventListener("loadstart",this.handleLoadStart),n.removeEventListener("playing",this.handlePlaying),n.removeEventListener("ended",this.handleEnded)}});Re(this,"componentDidUpdate",async n=>{const r=n.args.streamUrl,i=this.props.args.streamUrl,s=r!==i;if(i&&this.audioRef.current&&(s||this.state.audioState==="ended")){console.log("🔄 Reloading audio:",s?"URL changed":"Replay same URL"),this.setState({mediaStream:null,audioState:"loading"});const l=this.audioRef.current;l.removeEventListener("loadstart",this.handleLoadStart),l.removeEventListener("playing",this.handlePlaying),l.removeEventListener("ended",this.handleEnded),l.addEventListener("loadstart",this.handleLoadStart),l.addEventListener("playing",this.handlePlaying),l.addEventListener("ended",this.handleEnded),s?l.src=i:l.load();try{l.muted=!0,await l.play();const a=l;if(typeof a.captureStream=="function"){const u=a.captureStream();this.setState({mediaStream:u}),console.log("✅ Audio stream updated and captured successfully"),l.muted=!1,console.log("🔊 Audio unmuted")}else if(typeof a.mozCaptureStream=="function"){const u=a.mozCaptureStream();this.setState({mediaStream:u}),console.log("✅ Audio stream updated and captured successfully (Firefox)"),l.muted=!1,console.log("🔊 Audio unmuted")}}catch(a){console.error("❌ Error updating audio stream:",a)}}$e.setFrameHeight()});Re(this,"handleLoadStart",()=>{console.log("📥 Audio loadstart"),this.setState({audioState:"loading"})});Re(this,"handlePlaying",()=>{console.log("▶️ Audio playing"),this.setState({audioState:"playing"})});Re(this,"handleEnded",()=>{console.log("⏹️ Audio ended"),this.setState({audioState:"ended"})})}}const q1=$1(Z1);zv.render(Un.jsx(fr.StrictMode,{children:Un.jsx(q1,{})}),document.getElementById("root"));
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: streamlit-bar-visualizer
3
- Version: 0.1.2
3
+ Version: 0.1.3
4
4
  Summary: Beautiful audio frequency visualizer component for Streamlit with multiple state animations
5
5
  Home-page: https://github.com/bensonbs/streamlit-bar-visualizer
6
6
  Author: Benson Sung