@medc-com-br/ngx-jaimes-scribe 0.1.2 → 0.1.4

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.
@@ -0,0 +1 @@
1
+ {"version":3,"file":"medc-com-br-ngx-jaimes-scribe.mjs","sources":["../../../libs/ngx-jaimes-scribe/src/lib/services/vad.service.ts","../../../libs/ngx-jaimes-scribe/src/lib/services/audio-capture.service.ts","../../../libs/ngx-jaimes-scribe/src/lib/services/scribe-socket.service.ts","../../../libs/ngx-jaimes-scribe/src/lib/utils/pcm-to-wav.ts","../../../libs/ngx-jaimes-scribe/src/lib/components/recorder/recorder.component.ts","../../../libs/ngx-jaimes-scribe/src/medc-com-br-ngx-jaimes-scribe.ts"],"sourcesContent":["import { Injectable } from '@angular/core';\nimport { BehaviorSubject } from 'rxjs';\n\nexport type VadState = 'idle' | 'speech' | 'silence_pending' | 'silence';\n\nexport interface VadConfig {\n speechThreshold: number;\n silenceThreshold: number;\n silenceDebounceMs: number;\n}\n\nconst DEFAULT_CONFIG: VadConfig = {\n speechThreshold: 8,\n silenceThreshold: 3,\n silenceDebounceMs: 1500,\n};\n\n@Injectable({ providedIn: 'root' })\nexport class VadService {\n private state: VadState = 'idle';\n private silenceStartTime: number | null = null;\n private config = { ...DEFAULT_CONFIG };\n\n readonly state$ = new BehaviorSubject<VadState>('idle');\n\n analyzeLevel(level: number): { isSilence: boolean } {\n const now = Date.now();\n\n if (level >= this.config.speechThreshold) {\n this.state = 'speech';\n this.silenceStartTime = null;\n this.state$.next('speech');\n return { isSilence: false };\n }\n\n if (level < this.config.silenceThreshold) {\n if (this.state === 'speech') {\n this.silenceStartTime = now;\n this.state = 'silence_pending';\n } else if (this.state === 'silence_pending' && this.silenceStartTime) {\n if (now - this.silenceStartTime >= this.config.silenceDebounceMs) {\n this.state = 'silence';\n this.state$.next('silence');\n }\n }\n } else {\n if (this.state === 'silence_pending') {\n this.state = 'speech';\n this.silenceStartTime = null;\n }\n }\n\n return { isSilence: this.state === 'silence' };\n }\n\n reset(): void {\n this.state = 'idle';\n this.silenceStartTime = null;\n this.state$.next('idle');\n }\n\n getState(): VadState {\n return this.state;\n }\n}\n","import { Injectable, InjectionToken, inject, NgZone } from '@angular/core';\nimport { Subject, Observable, BehaviorSubject } from 'rxjs';\nimport { VadService } from './vad.service';\n\nexport interface AudioCaptureConfig {\n workletUrl: string;\n levelUpdateInterval: number;\n}\n\nexport const AUDIO_CAPTURE_CONFIG = new InjectionToken<AudioCaptureConfig>('AUDIO_CAPTURE_CONFIG');\n\nconst DEFAULT_CONFIG: AudioCaptureConfig = {\n workletUrl: '/assets/pcm-processor.js',\n levelUpdateInterval: 50,\n};\n\nexport interface AudioChunk {\n data: ArrayBuffer;\n isSilence: boolean;\n}\n\n@Injectable({ providedIn: 'root' })\nexport class AudioCaptureService {\n private config: AudioCaptureConfig;\n private ngZone: NgZone;\n private vadService: VadService;\n private audioContext: AudioContext | null = null;\n private workletNode: AudioWorkletNode | null = null;\n private analyserNode: AnalyserNode | null = null;\n private source: MediaStreamAudioSourceNode | null = null;\n private stream: MediaStream | null = null;\n private workletRegistered = false;\n private levelInterval: ReturnType<typeof setInterval> | null = null;\n private paused = false;\n\n private audioChunkSubject = new Subject<AudioChunk>();\n private audioLevelSubject = new BehaviorSubject<number>(0);\n private errorSubject = new Subject<Error>();\n\n audioChunk$: Observable<AudioChunk> = this.audioChunkSubject.asObservable();\n audioLevel$: Observable<number> = this.audioLevelSubject.asObservable();\n error$: Observable<Error> = this.errorSubject.asObservable();\n\n constructor() {\n const injectedConfig = inject(AUDIO_CAPTURE_CONFIG, { optional: true });\n this.config = injectedConfig ?? DEFAULT_CONFIG;\n this.ngZone = inject(NgZone);\n this.vadService = inject(VadService);\n }\n\n async startCapture(): Promise<void> {\n try {\n this.stream = await navigator.mediaDevices.getUserMedia({\n audio: {\n channelCount: 1,\n echoCancellation: true,\n noiseSuppression: true,\n },\n });\n\n this.audioContext = new AudioContext();\n\n if (!this.workletRegistered) {\n await this.audioContext.audioWorklet.addModule(this.config.workletUrl);\n this.workletRegistered = true;\n }\n\n this.workletNode = new AudioWorkletNode(this.audioContext, 'pcm-processor', {\n processorOptions: {\n inputSampleRate: this.audioContext.sampleRate,\n },\n });\n\n this.workletNode.port.onmessage = (event: MessageEvent<ArrayBuffer>) => {\n if (!this.paused) {\n const level = this.getAudioLevel();\n const { isSilence } = this.vadService.analyzeLevel(level);\n this.audioChunkSubject.next({ data: event.data, isSilence });\n }\n };\n\n this.analyserNode = this.audioContext.createAnalyser();\n this.analyserNode.fftSize = 256;\n this.analyserNode.smoothingTimeConstant = 0.8;\n\n this.source = this.audioContext.createMediaStreamSource(this.stream);\n this.source.connect(this.analyserNode);\n this.source.connect(this.workletNode);\n\n this.startLevelMonitoring();\n } catch (error) {\n const err = error instanceof Error ? error : new Error('Failed to start audio capture');\n this.errorSubject.next(err);\n throw err;\n }\n }\n\n async stopCapture(): Promise<void> {\n this.stopLevelMonitoring();\n this.paused = false;\n this.vadService.reset();\n\n if (this.workletNode) {\n this.workletNode.port.close();\n this.workletNode.disconnect();\n this.workletNode = null;\n }\n\n if (this.analyserNode) {\n this.analyserNode.disconnect();\n this.analyserNode = null;\n }\n\n if (this.source) {\n this.source.disconnect();\n this.source = null;\n }\n\n if (this.audioContext) {\n await this.audioContext.close();\n this.audioContext = null;\n this.workletRegistered = false;\n }\n\n if (this.stream) {\n this.stream.getTracks().forEach((track) => track.stop());\n this.stream = null;\n }\n\n this.audioLevelSubject.next(0);\n }\n\n pauseCapture(): void {\n if (this.isCapturing() && !this.paused) {\n this.paused = true;\n }\n }\n\n resumeCapture(): void {\n if (this.isCapturing() && this.paused) {\n this.paused = false;\n }\n }\n\n isCapturing(): boolean {\n return this.workletNode !== null && this.stream !== null;\n }\n\n isPaused(): boolean {\n return this.paused;\n }\n\n getSampleRate(): number | null {\n return this.audioContext?.sampleRate ?? null;\n }\n\n private startLevelMonitoring(): void {\n this.stopLevelMonitoring();\n\n this.ngZone.runOutsideAngular(() => {\n this.levelInterval = setInterval(() => {\n const level = this.getAudioLevel();\n this.ngZone.run(() => {\n this.audioLevelSubject.next(level);\n });\n }, this.config.levelUpdateInterval);\n });\n }\n\n private stopLevelMonitoring(): void {\n if (this.levelInterval) {\n clearInterval(this.levelInterval);\n this.levelInterval = null;\n }\n }\n\n private getAudioLevel(): number {\n if (!this.analyserNode) {\n return 0;\n }\n\n const dataArray = new Uint8Array(this.analyserNode.frequencyBinCount);\n this.analyserNode.getByteFrequencyData(dataArray);\n\n const sum = dataArray.reduce((acc, val) => acc + val, 0);\n const average = sum / dataArray.length;\n\n return Math.round((average / 255) * 100);\n }\n}\n","import { Injectable, InjectionToken, inject, NgZone } from '@angular/core';\nimport { BehaviorSubject, Subject, Observable } from 'rxjs';\nimport type { TranscriptionEvent } from '@medc-com-br/jaimes-shared';\n\nexport type ConnectionState = 'disconnected' | 'connecting' | 'connected' | 'reconnecting';\n\nexport interface ScribeSocketConfig {\n reconnectAttempts: number;\n reconnectBaseDelay: number;\n chunkBufferInterval: number;\n}\n\nexport const SCRIBE_SOCKET_CONFIG = new InjectionToken<ScribeSocketConfig>('SCRIBE_SOCKET_CONFIG');\n\nconst DEFAULT_CONFIG: ScribeSocketConfig = {\n reconnectAttempts: 5,\n reconnectBaseDelay: 1000,\n chunkBufferInterval: 250,\n};\n\n@Injectable({ providedIn: 'root' })\nexport class ScribeSocketService {\n private config: ScribeSocketConfig;\n private ngZone: NgZone;\n private ws: WebSocket | null = null;\n private wsUrl: string | null = null;\n private token: string | null = null;\n private premium = false;\n private reconnectAttempt = 0;\n private reconnectTimeout: ReturnType<typeof setTimeout> | null = null;\n private intentionalClose = false;\n\n private chunkBuffer: string[] = [];\n private sendInterval: ReturnType<typeof setInterval> | null = null;\n private keepaliveInterval: ReturnType<typeof setInterval> | null = null;\n private currentlyInSilence = false;\n\n private connectionStateSubject = new BehaviorSubject<ConnectionState>('disconnected');\n private transcriptionSubject = new Subject<TranscriptionEvent>();\n private errorSubject = new Subject<Error>();\n private sessionIdSubject = new BehaviorSubject<string | null>(null);\n\n connectionState$: Observable<ConnectionState> = this.connectionStateSubject.asObservable();\n transcription$: Observable<TranscriptionEvent> = this.transcriptionSubject.asObservable();\n error$: Observable<Error> = this.errorSubject.asObservable();\n sessionId$: Observable<string | null> = this.sessionIdSubject.asObservable();\n\n constructor() {\n const injectedConfig = inject(SCRIBE_SOCKET_CONFIG, { optional: true });\n this.config = injectedConfig ?? DEFAULT_CONFIG;\n this.ngZone = inject(NgZone);\n }\n\n async connect(url: string, token: string, premium = false): Promise<void> {\n if (this.connectionStateSubject.getValue() === 'connecting') {\n throw new Error('Connection already in progress');\n }\n\n if (this.isConnected()) {\n this.disconnect();\n }\n\n this.clearReconnectTimeout();\n this.wsUrl = url;\n this.token = token;\n this.premium = premium;\n this.intentionalClose = false;\n this.reconnectAttempt = 0;\n\n return this.createConnection();\n }\n\n disconnect(): void {\n this.intentionalClose = true;\n this.flushAndStopBuffering();\n this.clearReconnectTimeout();\n\n if (this.ws && this.ws.readyState === WebSocket.OPEN) {\n this.ws.close(1000, 'Client disconnect');\n }\n this.ws = null;\n\n this.connectionStateSubject.next('disconnected');\n this.sessionIdSubject.next(null);\n }\n\n sendAudioChunk(chunk: ArrayBuffer, isSilence: boolean): void {\n const message = JSON.stringify({\n type: 'audio',\n isSilence,\n data: this.arrayBufferToBase64(chunk),\n });\n this.chunkBuffer.push(message);\n\n if (isSilence && !this.currentlyInSilence) {\n this.currentlyInSilence = true;\n this.startKeepaliveInterval();\n } else if (!isSilence && this.currentlyInSilence) {\n this.currentlyInSilence = false;\n this.stopKeepaliveInterval();\n }\n }\n\n private startKeepaliveInterval(): void {\n this.stopKeepaliveInterval();\n this.keepaliveInterval = setInterval(() => {\n if (this.isConnected()) {\n this.ws!.send(JSON.stringify({ type: 'keepalive' }));\n }\n }, 3000);\n }\n\n private stopKeepaliveInterval(): void {\n if (this.keepaliveInterval) {\n clearInterval(this.keepaliveInterval);\n this.keepaliveInterval = null;\n }\n }\n\n private arrayBufferToBase64(buffer: ArrayBuffer): string {\n const bytes = new Uint8Array(buffer);\n let binary = '';\n for (let i = 0; i < bytes.byteLength; i++) {\n binary += String.fromCharCode(bytes[i]);\n }\n return btoa(binary);\n }\n\n isConnected(): boolean {\n return this.ws?.readyState === WebSocket.OPEN;\n }\n\n getSessionId(): string | null {\n return this.sessionIdSubject.getValue();\n }\n\n private createConnection(): Promise<void> {\n return new Promise((resolve, reject) => {\n if (!this.wsUrl) {\n reject(new Error('WebSocket URL is required'));\n return;\n }\n\n this.connectionStateSubject.next('connecting');\n const params = new URLSearchParams({ premium: String(this.premium) });\n if (this.token) {\n params.set('token', this.token);\n }\n const url = `${this.wsUrl}?${params.toString()}`;\n\n this.ws = new WebSocket(url);\n this.ws.binaryType = 'arraybuffer';\n\n this.ws.onopen = () => {\n this.ngZone.run(() => {\n this.reconnectAttempt = 0;\n this.connectionStateSubject.next('connected');\n this.startBuffering();\n resolve();\n });\n };\n\n this.ws.onerror = () => {\n this.ngZone.run(() => {\n const error = new Error('WebSocket connection error');\n this.errorSubject.next(error);\n if (this.connectionStateSubject.getValue() === 'connecting') {\n reject(error);\n }\n });\n };\n\n this.ws.onmessage = (event) => {\n this.ngZone.run(() => {\n try {\n const data = JSON.parse(event.data);\n if (data.type === 'connected' && data.sessionId) {\n this.sessionIdSubject.next(data.sessionId);\n }\n this.transcriptionSubject.next(data as TranscriptionEvent);\n } catch (e) {\n const error = new Error(`Failed to parse WebSocket message: ${e instanceof Error ? e.message : String(e)}`);\n console.error(error.message);\n this.errorSubject.next(error);\n }\n });\n };\n\n this.ws.onclose = (event) => {\n this.ngZone.run(() => {\n this.stopBuffering();\n\n if (!this.intentionalClose && event.code !== 1000) {\n this.attemptReconnect();\n } else {\n this.connectionStateSubject.next('disconnected');\n this.sessionIdSubject.next(null);\n }\n });\n };\n });\n }\n\n private attemptReconnect(): void {\n if (this.reconnectAttempt >= this.config.reconnectAttempts) {\n this.connectionStateSubject.next('disconnected');\n this.errorSubject.next(new Error('Max reconnection attempts reached'));\n return;\n }\n\n this.connectionStateSubject.next('reconnecting');\n const delay = this.config.reconnectBaseDelay * Math.pow(2, this.reconnectAttempt);\n this.reconnectAttempt++;\n\n this.reconnectTimeout = setTimeout(() => {\n this.createConnection().catch(() => {});\n }, delay);\n }\n\n private clearReconnectTimeout(): void {\n if (this.reconnectTimeout) {\n clearTimeout(this.reconnectTimeout);\n this.reconnectTimeout = null;\n }\n }\n\n private startBuffering(): void {\n this.stopBuffering();\n\n this.sendInterval = setInterval(() => {\n if (this.chunkBuffer.length > 0 && this.isConnected()) {\n for (const msg of this.chunkBuffer) {\n this.ws!.send(msg);\n }\n this.chunkBuffer = [];\n }\n }, this.config.chunkBufferInterval);\n }\n\n private flushAndStopBuffering(): void {\n if (this.sendInterval) {\n clearInterval(this.sendInterval);\n this.sendInterval = null;\n }\n\n if (this.chunkBuffer.length > 0 && this.isConnected()) {\n for (const msg of this.chunkBuffer) {\n this.ws!.send(msg);\n }\n }\n this.chunkBuffer = [];\n this.stopKeepaliveInterval();\n this.currentlyInSilence = false;\n }\n\n private stopBuffering(): void {\n if (this.sendInterval) {\n clearInterval(this.sendInterval);\n this.sendInterval = null;\n }\n this.chunkBuffer = [];\n }\n\n}\n","const SAMPLE_RATE = 16000;\nconst NUM_CHANNELS = 1;\nconst BITS_PER_SAMPLE = 16;\n\nfunction writeString(view: DataView, offset: number, str: string): void {\n for (let i = 0; i < str.length; i++) {\n view.setUint8(offset + i, str.charCodeAt(i));\n }\n}\n\nfunction concatBuffers(buffer1: ArrayBuffer, buffer2: ArrayBuffer): ArrayBuffer {\n const combined = new Uint8Array(buffer1.byteLength + buffer2.byteLength);\n combined.set(new Uint8Array(buffer1), 0);\n combined.set(new Uint8Array(buffer2), buffer1.byteLength);\n return combined.buffer;\n}\n\nexport function pcmToWav(pcmData: ArrayBuffer, sampleRate = SAMPLE_RATE): ArrayBuffer {\n const header = new ArrayBuffer(44);\n const view = new DataView(header);\n\n const byteRate = sampleRate * NUM_CHANNELS * (BITS_PER_SAMPLE / 8);\n const blockAlign = NUM_CHANNELS * (BITS_PER_SAMPLE / 8);\n\n // RIFF chunk descriptor\n writeString(view, 0, 'RIFF');\n view.setUint32(4, 36 + pcmData.byteLength, true);\n writeString(view, 8, 'WAVE');\n\n // fmt sub-chunk\n writeString(view, 12, 'fmt ');\n view.setUint32(16, 16, true); // SubChunk1Size (16 for PCM)\n view.setUint16(20, 1, true); // AudioFormat (1 = PCM)\n view.setUint16(22, NUM_CHANNELS, true); // NumChannels\n view.setUint32(24, sampleRate, true); // SampleRate\n view.setUint32(28, byteRate, true); // ByteRate\n view.setUint16(32, blockAlign, true); // BlockAlign\n view.setUint16(34, BITS_PER_SAMPLE, true); // BitsPerSample\n\n // data sub-chunk\n writeString(view, 36, 'data');\n view.setUint32(40, pcmData.byteLength, true);\n\n return concatBuffers(header, pcmData);\n}\n\nexport function createAudioBlobUrl(wavData: ArrayBuffer): string {\n const blob = new Blob([wavData], { type: 'audio/wav' });\n return URL.createObjectURL(blob);\n}\n\nexport function formatTime(seconds: number): string {\n const mins = Math.floor(seconds / 60);\n const secs = Math.floor(seconds % 60);\n return `${mins}:${secs.toString().padStart(2, '0')}`;\n}\n","import { Component, inject, signal, input, output, OnDestroy, computed, HostListener, ElementRef, effect } from '@angular/core';\nimport { CommonModule } from '@angular/common';\nimport { Subscription } from 'rxjs';\nimport { AudioCaptureService } from '../../services/audio-capture.service';\nimport { ScribeSocketService, ConnectionState } from '../../services/scribe-socket.service';\nimport { pcmToWav, createAudioBlobUrl, formatTime } from '../../utils/pcm-to-wav';\nimport type { TranscriptionEvent, TemplateOption, GeneratedDocument, SessionPlaybackData, TranscriptSegment, TranscriptionWord } from '@medc-com-br/jaimes-shared';\n\ninterface TranscriptEntry {\n id: number;\n text: string;\n speaker?: number;\n isFinal: boolean;\n startTime?: number;\n endTime?: number;\n}\n\nexport type RecorderMode = 'recording' | 'playback';\n\ninterface SpeakerGroup {\n speaker?: number;\n entries: TranscriptEntry[];\n}\n\nconst SPEAKER_LABELS: Record<number, string> = {\n 0: 'Pessoa 1',\n 1: 'Pessoa 2',\n 2: 'Pessoa 3',\n 3: 'Pessoa 4',\n};\n\n@Component({\n selector: 'ngx-jaimes-scribe-recorder',\n standalone: true,\n imports: [CommonModule],\n template: `\n <div class=\"scribe-recorder\">\n @if (mode() === 'playback') {\n <!-- Playback Mode -->\n <div class=\"scribe-playback\">\n @if (isLoadingSession()) {\n <div class=\"scribe-loading\">\n <svg class=\"scribe-icon scribe-icon--spinner\" viewBox=\"0 0 24 24\" width=\"24\" height=\"24\">\n <circle cx=\"12\" cy=\"12\" r=\"10\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-dasharray=\"32\" stroke-linecap=\"round\"/>\n </svg>\n <span>Carregando sessão...</span>\n </div>\n } @else if (sessionData()) {\n <!-- Audio Player -->\n <div class=\"scribe-player\">\n <button\n class=\"scribe-btn scribe-btn--play\"\n (click)=\"togglePlayback()\"\n [attr.aria-label]=\"isPlaying() ? 'Pausar' : 'Reproduzir'\"\n >\n @if (isPlaying()) {\n <svg class=\"scribe-icon\" viewBox=\"0 0 24 24\" width=\"24\" height=\"24\" fill=\"currentColor\">\n <path d=\"M6 19h4V5H6v14zm8-14v14h4V5h-4z\"/>\n </svg>\n } @else {\n <svg class=\"scribe-icon\" viewBox=\"0 0 24 24\" width=\"24\" height=\"24\" fill=\"currentColor\">\n <path d=\"M8 5v14l11-7z\"/>\n </svg>\n }\n </button>\n\n <div class=\"scribe-timeline\">\n <input\n type=\"range\"\n class=\"scribe-timeline-slider\"\n [min]=\"0\"\n [max]=\"audioDuration()\"\n [value]=\"audioCurrentTime()\"\n step=\"0.1\"\n (input)=\"seekTo($event)\"\n aria-label=\"Posição do áudio\"\n />\n <div class=\"scribe-time\">\n {{ formatTimeDisplay(audioCurrentTime()) }} / {{ formatTimeDisplay(audioDuration()) }}\n </div>\n </div>\n\n <select\n class=\"scribe-speed\"\n [value]=\"playbackRate()\"\n (change)=\"setPlaybackRate($event)\"\n aria-label=\"Velocidade de reprodução\"\n >\n <option value=\"0.5\">0.5x</option>\n <option value=\"0.75\">0.75x</option>\n <option value=\"1\">1x</option>\n <option value=\"1.25\">1.25x</option>\n <option value=\"1.5\">1.5x</option>\n <option value=\"2\">2x</option>\n </select>\n </div>\n\n <!-- Transcription with Highlight -->\n <div class=\"scribe-transcript-playback\">\n @for (segment of segments(); track segment.id; let idx = $index) {\n <div\n class=\"scribe-segment\"\n [class.scribe-segment--active]=\"activeSegmentId() === segment.id\"\n [style.--speaker-color]=\"getSpeakerColor(segment.speaker)\"\n [attr.data-segment-id]=\"segment.id\"\n (click)=\"seekToSegment(segment)\"\n >\n @if (segment.speaker !== undefined && shouldShowSpeakerLabel(idx)) {\n <span class=\"scribe-speaker-label\" [class]=\"'scribe-speaker--' + segment.speaker\">\n {{ getSpeakerLabel(segment.speaker) }}\n </span>\n }\n\n <p class=\"scribe-segment-text\">\n @if (segment.words?.length) {\n @for (word of segment.words; track $index; let i = $index) {\n <span\n class=\"scribe-word\"\n [class.scribe-word--active]=\"activeSegmentId() === segment.id && activeWordIndex() === i\"\n (click)=\"seekToWord(word, $event)\"\n >{{ word.word }}</span>{{ ' ' }}\n }\n } @else {\n {{ segment.text }}\n }\n </p>\n </div>\n }\n @if (segments().length === 0) {\n <span class=\"scribe-placeholder\">Nenhuma transcrição disponível.</span>\n }\n </div>\n } @else {\n <div class=\"scribe-error\">\n <span>Não foi possível carregar a sessão.</span>\n </div>\n }\n </div>\n } @else {\n <!-- Recording Mode -->\n <div class=\"scribe-controls\">\n @if (!hasFinishedSession()) {\n <button\n class=\"scribe-btn scribe-btn--mic\"\n [class.scribe-btn--active]=\"isRecording() && !isPaused()\"\n [class.scribe-btn--paused]=\"isPaused()\"\n [class.scribe-btn--connecting]=\"connectionState() === 'connecting'\"\n [disabled]=\"connectionState() === 'connecting'\"\n (click)=\"toggleRecording()\"\n [attr.aria-label]=\"getMicButtonLabel()\"\n >\n @if (connectionState() === 'connecting') {\n <svg class=\"scribe-icon scribe-icon--spinner\" viewBox=\"0 0 24 24\" width=\"24\" height=\"24\">\n <circle cx=\"12\" cy=\"12\" r=\"10\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-dasharray=\"32\" stroke-linecap=\"round\"/>\n </svg>\n } @else if (isPaused()) {\n <!-- Play icon when paused -->\n <svg class=\"scribe-icon\" viewBox=\"0 0 24 24\" width=\"24\" height=\"24\" fill=\"currentColor\">\n <path d=\"M8 5v14l11-7z\"/>\n </svg>\n } @else if (isRecording()) {\n <!-- Pause icon when recording -->\n <svg class=\"scribe-icon\" viewBox=\"0 0 24 24\" width=\"24\" height=\"24\" fill=\"currentColor\">\n <path d=\"M6 19h4V5H6v14zm8-14v14h4V5h-4z\"/>\n </svg>\n } @else {\n <!-- Mic icon when idle -->\n <svg class=\"scribe-icon\" viewBox=\"0 0 24 24\" width=\"24\" height=\"24\" fill=\"currentColor\">\n <path d=\"M12 14c1.66 0 3-1.34 3-3V5c0-1.66-1.34-3-3-3S9 3.34 9 5v6c0 1.66 1.34 3 3 3zm-1-9c0-.55.45-1 1-1s1 .45 1 1v6c0 .55-.45 1-1 1s-1-.45-1-1V5z\"/>\n <path d=\"M17 11c0 2.76-2.24 5-5 5s-5-2.24-5-5H5c0 3.53 2.61 6.43 6 6.92V21h2v-3.08c3.39-.49 6-3.39 6-6.92h-2z\"/>\n </svg>\n }\n </button>\n\n <div class=\"scribe-level\" [class.scribe-level--active]=\"isRecording() && !isPaused()\">\n <div class=\"scribe-level__fill\" [style.width.%]=\"isPaused() ? 0 : audioLevel()\"></div>\n </div>\n\n <button\n class=\"scribe-btn scribe-btn--finish\"\n [disabled]=\"!isRecording() && !isPaused()\"\n (click)=\"finishSession()\"\n aria-label=\"Finalizar gravação\"\n >\n <svg class=\"scribe-icon\" viewBox=\"0 0 24 24\" width=\"20\" height=\"20\" fill=\"currentColor\">\n <path d=\"M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41z\"/>\n </svg>\n <span>Finalizar</span>\n </button>\n }\n\n @if (hasFinishedSession() && templates().length > 0) {\n <div class=\"scribe-generate-container\">\n <button\n class=\"scribe-btn scribe-btn--generate\"\n [disabled]=\"isGenerating()\"\n [attr.aria-expanded]=\"showTemplateMenu()\"\n aria-haspopup=\"menu\"\n (click)=\"toggleTemplateMenu()\"\n aria-label=\"Gerar resumo\"\n >\n @if (isGenerating()) {\n <svg class=\"scribe-icon scribe-icon--spinner\" viewBox=\"0 0 24 24\" width=\"20\" height=\"20\">\n <circle cx=\"12\" cy=\"12\" r=\"10\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-dasharray=\"32\" stroke-linecap=\"round\"/>\n </svg>\n <span>Gerando...</span>\n } @else {\n <svg class=\"scribe-icon\" viewBox=\"0 0 24 24\" width=\"20\" height=\"20\" fill=\"currentColor\">\n <path d=\"M14 2H6c-1.1 0-2 .9-2 2v16c0 1.1.9 2 2 2h12c1.1 0 2-.9 2-2V8l-6-6zm4 18H6V4h7v5h5v11zm-3-7h-2v2h-2v-2H9v-2h2V9h2v2h2v2z\"/>\n </svg>\n <span>Gerar Resumo</span>\n }\n </button>\n\n @if (showTemplateMenu()) {\n <div class=\"scribe-template-menu\" role=\"menu\">\n @for (template of templates(); track template.id) {\n <button\n class=\"scribe-template-item\"\n role=\"menuitem\"\n (click)=\"selectTemplate(template)\"\n >\n <span class=\"scribe-template-name\">{{ template.name }}</span>\n @if (template.description) {\n <span class=\"scribe-template-desc\">{{ template.description }}</span>\n }\n </button>\n }\n </div>\n }\n </div>\n }\n </div>\n\n <div class=\"scribe-transcript\" [class.scribe-transcript--empty]=\"speakerGroups().length === 0 && !partialText()\">\n @if (speakerGroups().length === 0 && !partialText()) {\n <span class=\"scribe-placeholder\">A transcrição aparecerá aqui...</span>\n } @else {\n @for (group of speakerGroups(); track $index) {\n <div class=\"scribe-speaker-block\" [attr.data-speaker]=\"group.speaker\">\n @if (group.speaker !== undefined && group.speaker !== null) {\n <span class=\"scribe-speaker-label\" [class]=\"'scribe-speaker--' + group.speaker\">\n {{ getSpeakerLabel(group.speaker) }}\n </span>\n }\n <div class=\"scribe-speaker-text\">\n @for (entry of group.entries; track entry.id) {\n <span class=\"scribe-text scribe-text--final\">{{ entry.text }} </span>\n }\n </div>\n </div>\n }\n @if (partialText()) {\n <div class=\"scribe-speaker-block scribe-speaker-block--partial\">\n @if (currentSpeaker() !== undefined && currentSpeaker() !== null) {\n <span class=\"scribe-speaker-label\" [class]=\"'scribe-speaker--' + currentSpeaker()\">\n {{ getSpeakerLabel(currentSpeaker()!) }}\n </span>\n }\n <div class=\"scribe-speaker-text\">\n <span class=\"scribe-text scribe-text--partial\">{{ partialText() }}</span>\n </div>\n </div>\n }\n }\n </div>\n }\n </div>\n `,\n styles: [`\n :host {\n --scribe-primary: #4caf50;\n --scribe-primary-dark: #388e3c;\n --scribe-primary-light: #81c784;\n --scribe-danger: #f44336;\n --scribe-danger-dark: #d32f2f;\n --scribe-text-color: #212121;\n --scribe-text-partial: #9e9e9e;\n --scribe-font-family: inherit;\n --scribe-font-size: 1rem;\n --scribe-bg: #ffffff;\n --scribe-bg-transcript: #f5f5f5;\n --scribe-border-radius: 8px;\n --scribe-border-color: #e0e0e0;\n --scribe-level-bg: #e0e0e0;\n --scribe-level-fill: #4caf50;\n\n --scribe-speaker-0: #2196f3;\n --scribe-speaker-1: #9c27b0;\n --scribe-speaker-2: #ff9800;\n --scribe-speaker-3: #009688;\n\n display: block;\n font-family: var(--scribe-font-family);\n font-size: var(--scribe-font-size);\n }\n\n .scribe-recorder {\n background: var(--scribe-bg);\n border-radius: var(--scribe-border-radius);\n }\n\n .scribe-controls {\n display: flex;\n align-items: center;\n gap: 1rem;\n padding: 1rem;\n }\n\n .scribe-btn {\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 0.5rem;\n padding: 0.75rem;\n border: none;\n border-radius: var(--scribe-border-radius);\n font-family: var(--scribe-font-family);\n font-size: 0.875rem;\n font-weight: 500;\n cursor: pointer;\n transition: all 0.2s ease;\n }\n\n .scribe-btn:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n }\n\n .scribe-btn--mic {\n width: 48px;\n height: 48px;\n border-radius: 50%;\n background: var(--scribe-bg-transcript);\n color: var(--scribe-text-color);\n }\n\n .scribe-btn--mic:hover:not(:disabled) {\n background: var(--scribe-border-color);\n }\n\n .scribe-btn--mic.scribe-btn--active {\n background: var(--scribe-danger);\n color: white;\n animation: pulse-recording 1.5s ease-in-out infinite;\n }\n\n .scribe-btn--mic.scribe-btn--paused {\n background: var(--scribe-primary);\n color: white;\n }\n\n .scribe-btn--mic.scribe-btn--paused:hover:not(:disabled) {\n background: var(--scribe-primary-dark);\n }\n\n .scribe-btn--mic.scribe-btn--connecting {\n background: var(--scribe-primary-light);\n color: white;\n }\n\n .scribe-btn--finish {\n padding: 0.75rem 1.25rem;\n background: var(--scribe-primary);\n color: white;\n }\n\n .scribe-btn--finish:hover:not(:disabled) {\n background: var(--scribe-primary-dark);\n }\n\n .scribe-icon {\n flex-shrink: 0;\n }\n\n .scribe-icon--spinner {\n animation: spin 1s linear infinite;\n }\n\n .scribe-level {\n flex: 1;\n height: 8px;\n background: var(--scribe-level-bg);\n border-radius: 4px;\n overflow: hidden;\n opacity: 0.5;\n transition: opacity 0.2s ease;\n }\n\n .scribe-level--active {\n opacity: 1;\n }\n\n .scribe-level__fill {\n height: 100%;\n background: var(--scribe-level-fill);\n border-radius: 4px;\n transition: width 0.05s ease-out;\n }\n\n .scribe-transcript {\n min-height: 120px;\n max-height: 400px;\n overflow-y: auto;\n padding: 1rem;\n margin: 0 1rem 1rem;\n background: var(--scribe-bg-transcript);\n border-radius: var(--scribe-border-radius);\n line-height: 1.6;\n }\n\n .scribe-transcript--empty {\n display: flex;\n align-items: center;\n justify-content: center;\n }\n\n .scribe-placeholder {\n color: var(--scribe-text-partial);\n font-style: italic;\n }\n\n .scribe-speaker-block {\n margin-bottom: 0.75rem;\n padding-left: 0.5rem;\n border-left: 3px solid var(--scribe-border-color);\n }\n\n .scribe-speaker-block--partial {\n opacity: 0.7;\n }\n\n .scribe-speaker-block[data-speaker=\"0\"] {\n border-left-color: var(--scribe-speaker-0);\n }\n\n .scribe-speaker-block[data-speaker=\"1\"] {\n border-left-color: var(--scribe-speaker-1);\n }\n\n .scribe-speaker-block[data-speaker=\"2\"] {\n border-left-color: var(--scribe-speaker-2);\n }\n\n .scribe-speaker-block[data-speaker=\"3\"] {\n border-left-color: var(--scribe-speaker-3);\n }\n\n .scribe-speaker-label {\n display: inline-block;\n font-size: 0.75rem;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.5px;\n padding: 0.125rem 0.5rem;\n border-radius: 4px;\n margin-bottom: 0.25rem;\n color: white;\n background: var(--scribe-border-color);\n }\n\n .scribe-speaker--0 {\n background: var(--scribe-speaker-0);\n }\n\n .scribe-speaker--1 {\n background: var(--scribe-speaker-1);\n }\n\n .scribe-speaker--2 {\n background: var(--scribe-speaker-2);\n }\n\n .scribe-speaker--3 {\n background: var(--scribe-speaker-3);\n }\n\n .scribe-speaker-text {\n margin-top: 0.25rem;\n }\n\n .scribe-text {\n word-wrap: break-word;\n }\n\n .scribe-text--final {\n color: var(--scribe-text-color);\n }\n\n .scribe-text--partial {\n color: var(--scribe-text-partial);\n font-style: italic;\n }\n\n .scribe-generate-container {\n position: relative;\n margin-left: 0.5rem;\n }\n\n .scribe-btn--generate {\n display: flex;\n align-items: center;\n gap: 0.5rem;\n padding: 0.75rem 1.25rem;\n background: var(--scribe-primary);\n color: white;\n border: none;\n border-radius: var(--scribe-border-radius);\n font-family: var(--scribe-font-family);\n font-size: 0.875rem;\n font-weight: 500;\n cursor: pointer;\n transition: all 0.2s ease;\n }\n\n .scribe-btn--generate:hover:not(:disabled) {\n background: var(--scribe-primary-dark);\n }\n\n .scribe-btn--generate:disabled {\n opacity: 0.7;\n cursor: not-allowed;\n }\n\n .scribe-template-menu {\n position: absolute;\n top: 100%;\n left: 0;\n margin-top: 0.25rem;\n min-width: 220px;\n background: var(--scribe-bg);\n border: 1px solid var(--scribe-border-color);\n border-radius: var(--scribe-border-radius);\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);\n z-index: 100;\n overflow: hidden;\n }\n\n .scribe-template-item {\n display: flex;\n flex-direction: column;\n align-items: flex-start;\n width: 100%;\n padding: 0.75rem 1rem;\n border: none;\n background: transparent;\n cursor: pointer;\n text-align: left;\n transition: background 0.15s ease;\n }\n\n .scribe-template-item:hover {\n background: var(--scribe-bg-transcript);\n }\n\n .scribe-template-item:not(:last-child) {\n border-bottom: 1px solid var(--scribe-border-color);\n }\n\n .scribe-template-name {\n font-weight: 500;\n color: var(--scribe-text-color);\n }\n\n .scribe-template-desc {\n font-size: 0.75rem;\n color: var(--scribe-text-partial);\n margin-top: 0.25rem;\n }\n\n @keyframes pulse-recording {\n 0%, 100% { box-shadow: 0 0 0 0 rgba(244, 67, 54, 0.4); }\n 50% { box-shadow: 0 0 0 8px rgba(244, 67, 54, 0); }\n }\n\n @keyframes spin {\n from { transform: rotate(0deg); }\n to { transform: rotate(360deg); }\n }\n\n /* Playback Mode Styles */\n .scribe-playback {\n padding: 1rem;\n }\n\n .scribe-loading,\n .scribe-error {\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 0.5rem;\n padding: 2rem;\n color: var(--scribe-text-partial);\n }\n\n .scribe-player {\n display: flex;\n align-items: center;\n gap: 1rem;\n padding: 1rem;\n background: var(--scribe-bg-transcript);\n border-radius: var(--scribe-border-radius);\n margin-bottom: 1rem;\n }\n\n .scribe-btn--play {\n width: 48px;\n height: 48px;\n border-radius: 50%;\n background: var(--scribe-primary);\n color: white;\n border: none;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n transition: background 0.2s ease;\n flex-shrink: 0;\n }\n\n .scribe-btn--play:hover {\n background: var(--scribe-primary-dark);\n }\n\n .scribe-timeline {\n flex: 1;\n display: flex;\n flex-direction: column;\n gap: 0.25rem;\n }\n\n .scribe-timeline-slider {\n width: 100%;\n cursor: pointer;\n height: 6px;\n -webkit-appearance: none;\n appearance: none;\n background: var(--scribe-level-bg);\n border-radius: 3px;\n outline: none;\n }\n\n .scribe-timeline-slider::-webkit-slider-thumb {\n -webkit-appearance: none;\n appearance: none;\n width: 14px;\n height: 14px;\n background: var(--scribe-primary);\n border-radius: 50%;\n cursor: pointer;\n }\n\n .scribe-timeline-slider::-moz-range-thumb {\n width: 14px;\n height: 14px;\n background: var(--scribe-primary);\n border-radius: 50%;\n cursor: pointer;\n border: none;\n }\n\n .scribe-time {\n font-size: 0.75rem;\n color: var(--scribe-text-partial);\n }\n\n .scribe-speed {\n padding: 0.375rem 0.5rem;\n border-radius: 4px;\n border: 1px solid var(--scribe-border-color);\n background: var(--scribe-bg);\n font-size: 0.875rem;\n cursor: pointer;\n }\n\n .scribe-transcript-playback {\n max-height: 400px;\n overflow-y: auto;\n scroll-behavior: smooth;\n padding: 0.5rem;\n }\n\n .scribe-segment {\n padding: 0.75rem 1rem;\n margin-bottom: 0.5rem;\n border-left: 3px solid var(--speaker-color, var(--scribe-border-color));\n background: var(--scribe-bg);\n border-radius: 0 var(--scribe-border-radius) var(--scribe-border-radius) 0;\n cursor: pointer;\n transition: background 0.2s ease;\n }\n\n .scribe-segment:hover {\n background: var(--scribe-bg-transcript);\n }\n\n .scribe-segment--active {\n background: rgba(76, 175, 80, 0.1);\n border-left-color: var(--scribe-primary);\n }\n\n .scribe-segment-text {\n margin: 0.25rem 0 0 0;\n line-height: 1.6;\n }\n\n .scribe-word {\n transition: background 0.15s ease, color 0.15s ease;\n padding: 0 1px;\n border-radius: 2px;\n }\n\n .scribe-word:hover {\n background: rgba(0, 0, 0, 0.05);\n cursor: pointer;\n }\n\n .scribe-word--active {\n background: var(--scribe-primary);\n color: white;\n }\n `],\n})\nexport class RecorderComponent implements OnDestroy {\n private audioCapture = inject(AudioCaptureService);\n private socket = inject(ScribeSocketService);\n private elementRef = inject(ElementRef);\n private subscriptions: Subscription[] = [];\n private entryIdCounter = 0;\n private generateAbortController: AbortController | null = null;\n\n @HostListener('document:click', ['$event'])\n onDocumentClick(event: MouseEvent): void {\n if (!this.showTemplateMenu()) return;\n const target = event.target as HTMLElement;\n if (!this.elementRef.nativeElement.contains(target)) {\n this.showTemplateMenu.set(false);\n }\n }\n\n wsUrl = input<string>('');\n token = input<string>('');\n speakerLabels = input<Record<number, string>>({});\n premium = input<boolean>(false);\n templates = input<TemplateOption[]>([]);\n lambdaUrl = input<string>('');\n\n sessionId = input<string | undefined>();\n apiUrl = input<string>('');\n\n sessionStarted = output<string>();\n sessionFinished = output<{ transcript: string; entries: TranscriptEntry[] }>();\n error = output<Error>();\n documentGenerated = output<GeneratedDocument>();\n generationError = output<Error>();\n\n isRecording = signal(false);\n isPaused = signal(false);\n audioLevel = signal(0);\n connectionState = signal<ConnectionState>('disconnected');\n entries = signal<TranscriptEntry[]>([]);\n partialText = signal('');\n currentSpeaker = signal<number | undefined>(undefined);\n showTemplateMenu = signal(false);\n isGenerating = signal(false);\n lastSessionId = signal<string | null>(null);\n\n isPlaying = signal(false);\n isLoadingSession = signal(false);\n audioCurrentTime = signal(0);\n audioDuration = signal(0);\n playbackRate = signal(1);\n sessionData = signal<SessionPlaybackData | null>(null);\n activeSegmentId = signal<string | null>(null);\n activeWordIndex = signal<number | null>(null);\n\n private audioElement: HTMLAudioElement | null = null;\n private audioBlobUrl: string | null = null;\n\n mode = computed<RecorderMode>(() =>\n this.sessionId() ? 'playback' : 'recording'\n );\n\n segments = computed(() =>\n this.sessionData()?.transcription.segments ?? []\n );\n\n hasFinishedSession = computed(() =>\n this.lastSessionId() !== null &&\n !this.isRecording() &&\n !this.isPaused()\n );\n\n speakerGroups = computed<SpeakerGroup[]>(() => {\n const allEntries = this.entries();\n if (allEntries.length === 0) return [];\n\n const groups: SpeakerGroup[] = [];\n let currentGroup: SpeakerGroup | null = null;\n\n for (const entry of allEntries) {\n if (!currentGroup || currentGroup.speaker !== entry.speaker) {\n currentGroup = { speaker: entry.speaker, entries: [] };\n groups.push(currentGroup);\n }\n currentGroup.entries.push(entry);\n }\n\n return groups;\n });\n\n constructor() {\n this.subscriptions.push(\n this.audioCapture.audioLevel$.subscribe((level) => {\n this.audioLevel.set(level);\n }),\n this.socket.connectionState$.subscribe((state) => {\n this.connectionState.set(state);\n }),\n this.socket.transcription$.subscribe((event) => {\n this.handleTranscription(event);\n }),\n this.socket.error$.subscribe((err) => {\n this.error.emit(err);\n }),\n this.audioCapture.error$.subscribe((err) => {\n this.error.emit(err);\n }),\n this.audioCapture.audioChunk$.subscribe(({ data, isSilence }) => {\n this.socket.sendAudioChunk(data, isSilence);\n })\n );\n\n effect(() => {\n const sid = this.sessionId();\n const api = this.apiUrl();\n const tok = this.token();\n if (sid && api && this.mode() === 'playback') {\n this.loadSession();\n }\n });\n }\n\n ngOnDestroy(): void {\n this.subscriptions.forEach((sub) => sub.unsubscribe());\n this.generateAbortController?.abort();\n this.cleanup();\n this.cleanupPlayback();\n }\n\n private audioEventHandlers: {\n loadedmetadata?: () => void;\n timeupdate?: () => void;\n ended?: () => void;\n } = {};\n\n private cleanupPlayback(): void {\n if (this.audioElement) {\n this.audioElement.pause();\n if (this.audioEventHandlers.loadedmetadata) {\n this.audioElement.removeEventListener('loadedmetadata', this.audioEventHandlers.loadedmetadata);\n }\n if (this.audioEventHandlers.timeupdate) {\n this.audioElement.removeEventListener('timeupdate', this.audioEventHandlers.timeupdate);\n }\n if (this.audioEventHandlers.ended) {\n this.audioElement.removeEventListener('ended', this.audioEventHandlers.ended);\n }\n this.audioEventHandlers = {};\n this.audioElement = null;\n }\n if (this.audioBlobUrl) {\n URL.revokeObjectURL(this.audioBlobUrl);\n this.audioBlobUrl = null;\n }\n }\n\n getSpeakerLabel(speaker: number): string {\n const customLabels = this.speakerLabels();\n if (customLabels[speaker]) {\n return customLabels[speaker];\n }\n return SPEAKER_LABELS[speaker] || `Pessoa ${speaker + 1}`;\n }\n\n shouldShowSpeakerLabel(segmentIndex: number): boolean {\n const segs = this.segments();\n if (segmentIndex === 0) return true;\n const currentSpeaker = segs[segmentIndex]?.speaker;\n const previousSpeaker = segs[segmentIndex - 1]?.speaker;\n return currentSpeaker !== previousSpeaker;\n }\n\n getMicButtonLabel(): string {\n if (this.isPaused()) {\n return 'Retomar gravação';\n }\n if (this.isRecording()) {\n return 'Pausar gravação';\n }\n return 'Iniciar gravação';\n }\n\n async toggleRecording(): Promise<void> {\n if (this.isPaused()) {\n this.resumeRecording();\n } else if (this.isRecording()) {\n this.pauseRecording();\n } else {\n await this.startRecording();\n }\n }\n\n pauseRecording(): void {\n if (!this.isRecording() || this.isPaused()) return;\n this.audioCapture.pauseCapture();\n this.isPaused.set(true);\n }\n\n resumeRecording(): void {\n if (!this.isPaused()) return;\n this.audioCapture.resumeCapture();\n this.isPaused.set(false);\n }\n\n async finishSession(): Promise<void> {\n if (!this.isRecording() && !this.isPaused()) return;\n\n const sessionId = this.socket.getSessionId();\n\n await this.stopRecording();\n\n const allEntries = this.entries();\n const fullTranscript = allEntries.map((e) => e.text).join(' ');\n\n this.sessionFinished.emit({ transcript: fullTranscript, entries: allEntries });\n\n this.partialText.set('');\n this.currentSpeaker.set(undefined);\n\n this.lastSessionId.set(sessionId);\n }\n\n toggleTemplateMenu(): void {\n this.showTemplateMenu.update((v) => !v);\n }\n\n async selectTemplate(template: TemplateOption): Promise<void> {\n if (this.isGenerating()) return;\n\n this.showTemplateMenu.set(false);\n\n const lambdaUrl = this.lambdaUrl();\n if (!lambdaUrl) {\n this.generationError.emit(new Error('Lambda URL not provided'));\n return;\n }\n\n const sessionId = this.lastSessionId();\n if (!sessionId) {\n this.generationError.emit(new Error('No session available'));\n return;\n }\n\n this.generateAbortController?.abort();\n this.generateAbortController = new AbortController();\n\n this.isGenerating.set(true);\n\n try {\n const headers: Record<string, string> = { 'Content-Type': 'application/json' };\n const token = this.token();\n if (token) {\n headers['Authorization'] = `Bearer ${token}`;\n }\n\n const response = await fetch(`${lambdaUrl}/generate`, {\n method: 'POST',\n headers,\n signal: this.generateAbortController.signal,\n body: JSON.stringify({\n sessionId,\n outputSchema: template.content,\n }),\n });\n\n if (!response.ok) {\n const errorData = await response.json().catch(() => ({}));\n throw new Error(errorData.error || `HTTP ${response.status}`);\n }\n\n const result = await response.json();\n\n this.documentGenerated.emit({\n sessionId,\n templateId: template.id,\n content: result.content,\n generatedAt: result.generatedAt,\n });\n } catch (err) {\n if (err instanceof Error && err.name === 'AbortError') return;\n this.generationError.emit(err instanceof Error ? err : new Error(String(err)));\n } finally {\n this.isGenerating.set(false);\n }\n }\n\n async loadSession(): Promise<void> {\n const sid = this.sessionId();\n const api = this.apiUrl();\n\n if (!sid || !api) return;\n\n this.isLoadingSession.set(true);\n\n try {\n const headers: Record<string, string> = {};\n const token = this.token();\n if (token) {\n headers['Authorization'] = `Bearer ${token}`;\n }\n\n const response = await fetch(`${api}/session/${sid}`, { headers });\n\n if (!response.ok) {\n throw new Error(`HTTP ${response.status}`);\n }\n\n const data: SessionPlaybackData = await response.json();\n this.sessionData.set(data);\n\n await this.loadAudio(data.audioUrl);\n } catch (err) {\n this.error.emit(err instanceof Error ? err : new Error(String(err)));\n } finally {\n this.isLoadingSession.set(false);\n }\n }\n\n private async loadAudio(pcmUrl: string): Promise<void> {\n this.cleanupPlayback();\n\n const response = await fetch(pcmUrl);\n if (!response.ok) {\n throw new Error(`Failed to load audio: HTTP ${response.status}`);\n }\n\n const pcmData = await response.arrayBuffer();\n\n const wavData = pcmToWav(pcmData);\n this.audioBlobUrl = createAudioBlobUrl(wavData);\n\n this.audioElement = new Audio(this.audioBlobUrl);\n\n this.audioEventHandlers.loadedmetadata = () => {\n this.audioDuration.set(this.audioElement!.duration);\n };\n this.audioEventHandlers.timeupdate = () => {\n this.audioCurrentTime.set(this.audioElement!.currentTime);\n this.updateActiveSegment();\n };\n this.audioEventHandlers.ended = () => {\n this.isPlaying.set(false);\n };\n\n this.audioElement.addEventListener('loadedmetadata', this.audioEventHandlers.loadedmetadata);\n this.audioElement.addEventListener('timeupdate', this.audioEventHandlers.timeupdate);\n this.audioElement.addEventListener('ended', this.audioEventHandlers.ended);\n }\n\n togglePlayback(): void {\n if (!this.audioElement) return;\n\n if (this.isPlaying()) {\n this.audioElement.pause();\n this.isPlaying.set(false);\n } else {\n this.audioElement.play();\n this.isPlaying.set(true);\n }\n }\n\n seekTo(event: Event): void {\n const input = event.target as HTMLInputElement | null;\n if (!input) return;\n const time = parseFloat(input.value);\n if (this.audioElement && !isNaN(time)) {\n this.audioElement.currentTime = time;\n this.audioCurrentTime.set(time);\n }\n }\n\n setPlaybackRate(event: Event): void {\n const select = event.target as HTMLSelectElement | null;\n if (!select) return;\n const rate = parseFloat(select.value);\n if (isNaN(rate)) return;\n this.playbackRate.set(rate);\n if (this.audioElement) {\n this.audioElement.playbackRate = rate;\n }\n }\n\n seekToSegment(segment: TranscriptSegment): void {\n if (this.audioElement) {\n this.audioElement.currentTime = segment.startTime;\n this.audioCurrentTime.set(segment.startTime);\n if (!this.isPlaying()) {\n this.togglePlayback();\n }\n }\n }\n\n seekToWord(word: TranscriptionWord, event: Event): void {\n event.stopPropagation();\n if (this.audioElement) {\n this.audioElement.currentTime = word.start;\n this.audioCurrentTime.set(word.start);\n if (!this.isPlaying()) {\n this.togglePlayback();\n }\n }\n }\n\n formatTimeDisplay(seconds: number): string {\n return formatTime(seconds);\n }\n\n getSpeakerColor(speaker: number | undefined): string {\n if (speaker === undefined) return 'var(--scribe-border-color)';\n const colors = [\n 'var(--scribe-speaker-0)',\n 'var(--scribe-speaker-1)',\n 'var(--scribe-speaker-2)',\n 'var(--scribe-speaker-3)',\n ];\n return colors[speaker % colors.length];\n }\n\n private updateActiveSegment(): void {\n const time = this.audioCurrentTime();\n const segs = this.segments();\n\n const seg = segs.find((s) => time >= s.startTime && time <= s.endTime);\n this.activeSegmentId.set(seg?.id ?? null);\n\n if (seg?.words) {\n const wordIdx = seg.words.findIndex((w) => time >= w.start && time <= w.end);\n this.activeWordIndex.set(wordIdx >= 0 ? wordIdx : null);\n } else {\n this.activeWordIndex.set(null);\n }\n\n this.scrollToActiveSegment();\n }\n\n private scrollToActiveSegment(): void {\n const activeId = this.activeSegmentId();\n if (!activeId) return;\n\n const container = this.elementRef.nativeElement.querySelector('.scribe-transcript-playback');\n const activeEl = container?.querySelector(`[data-segment-id=\"${activeId}\"]`);\n\n if (activeEl && container) {\n const containerRect = container.getBoundingClientRect();\n const activeRect = activeEl.getBoundingClientRect();\n\n if (activeRect.top < containerRect.top || activeRect.bottom > containerRect.bottom) {\n activeEl.scrollIntoView({ behavior: 'smooth', block: 'center' });\n }\n }\n }\n\n private async startRecording(): Promise<void> {\n try {\n await this.socket.connect(this.wsUrl(), this.token(), this.premium());\n await this.audioCapture.startCapture();\n this.isRecording.set(true);\n this.isPaused.set(false);\n\n const sessionId = this.socket.getSessionId();\n if (sessionId) {\n this.sessionStarted.emit(sessionId);\n }\n } catch (err) {\n this.error.emit(err instanceof Error ? err : new Error('Failed to start recording'));\n await this.cleanup();\n }\n }\n\n private async stopRecording(): Promise<void> {\n await this.audioCapture.stopCapture();\n this.socket.disconnect();\n this.isRecording.set(false);\n this.isPaused.set(false);\n }\n\n private async cleanup(): Promise<void> {\n await this.audioCapture.stopCapture();\n this.socket.disconnect();\n this.isRecording.set(false);\n this.isPaused.set(false);\n }\n\n private handleTranscription(event: TranscriptionEvent): void {\n if (!event.transcript) return;\n\n if (event.type === 'final') {\n const entry: TranscriptEntry = {\n id: ++this.entryIdCounter,\n text: event.transcript,\n speaker: event.speaker,\n isFinal: true,\n startTime: event.start,\n endTime: event.end,\n };\n\n this.entries.update((entries) => [...entries, entry]);\n this.partialText.set('');\n this.currentSpeaker.set(undefined);\n } else if (event.type === 'partial') {\n this.partialText.set(event.transcript);\n this.currentSpeaker.set(event.speaker);\n }\n }\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":["DEFAULT_CONFIG"],"mappings":";;;;;AAWA,MAAMA,gBAAc,GAAc;AAChC,IAAA,eAAe,EAAE,CAAC;AAClB,IAAA,gBAAgB,EAAE,CAAC;AACnB,IAAA,iBAAiB,EAAE,IAAI;CACxB;MAGY,UAAU,CAAA;IACb,KAAK,GAAa,MAAM;IACxB,gBAAgB,GAAkB,IAAI;AACtC,IAAA,MAAM,GAAG,EAAE,GAAGA,gBAAc,EAAE;AAE7B,IAAA,MAAM,GAAG,IAAI,eAAe,CAAW,MAAM,CAAC;AAEvD,IAAA,YAAY,CAAC,KAAa,EAAA;AACxB,QAAA,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE;QAEtB,IAAI,KAAK,IAAI,IAAI,CAAC,MAAM,CAAC,eAAe,EAAE;AACxC,YAAA,IAAI,CAAC,KAAK,GAAG,QAAQ;AACrB,YAAA,IAAI,CAAC,gBAAgB,GAAG,IAAI;AAC5B,YAAA,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC;AAC1B,YAAA,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE;QAC7B;QAEA,IAAI,KAAK,GAAG,IAAI,CAAC,MAAM,CAAC,gBAAgB,EAAE;AACxC,YAAA,IAAI,IAAI,CAAC,KAAK,KAAK,QAAQ,EAAE;AAC3B,gBAAA,IAAI,CAAC,gBAAgB,GAAG,GAAG;AAC3B,gBAAA,IAAI,CAAC,KAAK,GAAG,iBAAiB;YAChC;iBAAO,IAAI,IAAI,CAAC,KAAK,KAAK,iBAAiB,IAAI,IAAI,CAAC,gBAAgB,EAAE;AACpE,gBAAA,IAAI,GAAG,GAAG,IAAI,CAAC,gBAAgB,IAAI,IAAI,CAAC,MAAM,CAAC,iBAAiB,EAAE;AAChE,oBAAA,IAAI,CAAC,KAAK,GAAG,SAAS;AACtB,oBAAA,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC;gBAC7B;YACF;QACF;aAAO;AACL,YAAA,IAAI,IAAI,CAAC,KAAK,KAAK,iBAAiB,EAAE;AACpC,gBAAA,IAAI,CAAC,KAAK,GAAG,QAAQ;AACrB,gBAAA,IAAI,CAAC,gBAAgB,GAAG,IAAI;YAC9B;QACF;QAEA,OAAO,EAAE,SAAS,EAAE,IAAI,CAAC,KAAK,KAAK,SAAS,EAAE;IAChD;IAEA,KAAK,GAAA;AACH,QAAA,IAAI,CAAC,KAAK,GAAG,MAAM;AACnB,QAAA,IAAI,CAAC,gBAAgB,GAAG,IAAI;AAC5B,QAAA,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC;IAC1B;IAEA,QAAQ,GAAA;QACN,OAAO,IAAI,CAAC,KAAK;IACnB;wGA7CW,UAAU,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,UAAA,EAAA,CAAA;AAAV,IAAA,OAAA,KAAA,GAAA,EAAA,CAAA,qBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,SAAA,EAAA,QAAA,EAAA,EAAA,EAAA,IAAA,EAAA,UAAU,cADG,MAAM,EAAA,CAAA;;4FACnB,UAAU,EAAA,UAAA,EAAA,CAAA;kBADtB,UAAU;mBAAC,EAAE,UAAU,EAAE,MAAM,EAAE;;;MCRrB,oBAAoB,GAAG,IAAI,cAAc,CAAqB,sBAAsB;AAEjG,MAAMA,gBAAc,GAAuB;AACzC,IAAA,UAAU,EAAE,0BAA0B;AACtC,IAAA,mBAAmB,EAAE,EAAE;CACxB;MAQY,mBAAmB,CAAA;AACtB,IAAA,MAAM;AACN,IAAA,MAAM;AACN,IAAA,UAAU;IACV,YAAY,GAAwB,IAAI;IACxC,WAAW,GAA4B,IAAI;IAC3C,YAAY,GAAwB,IAAI;IACxC,MAAM,GAAsC,IAAI;IAChD,MAAM,GAAuB,IAAI;IACjC,iBAAiB,GAAG,KAAK;IACzB,aAAa,GAA0C,IAAI;IAC3D,MAAM,GAAG,KAAK;AAEd,IAAA,iBAAiB,GAAG,IAAI,OAAO,EAAc;AAC7C,IAAA,iBAAiB,GAAG,IAAI,eAAe,CAAS,CAAC,CAAC;AAClD,IAAA,YAAY,GAAG,IAAI,OAAO,EAAS;AAE3C,IAAA,WAAW,GAA2B,IAAI,CAAC,iBAAiB,CAAC,YAAY,EAAE;AAC3E,IAAA,WAAW,GAAuB,IAAI,CAAC,iBAAiB,CAAC,YAAY,EAAE;AACvE,IAAA,MAAM,GAAsB,IAAI,CAAC,YAAY,CAAC,YAAY,EAAE;AAE5D,IAAA,WAAA,GAAA;AACE,QAAA,MAAM,cAAc,GAAG,MAAM,CAAC,oBAAoB,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;AACvE,QAAA,IAAI,CAAC,MAAM,GAAG,cAAc,IAAIA,gBAAc;AAC9C,QAAA,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC;AAC5B,QAAA,IAAI,CAAC,UAAU,GAAG,MAAM,CAAC,UAAU,CAAC;IACtC;AAEA,IAAA,MAAM,YAAY,GAAA;AAChB,QAAA,IAAI;YACF,IAAI,CAAC,MAAM,GAAG,MAAM,SAAS,CAAC,YAAY,CAAC,YAAY,CAAC;AACtD,gBAAA,KAAK,EAAE;AACL,oBAAA,YAAY,EAAE,CAAC;AACf,oBAAA,gBAAgB,EAAE,IAAI;AACtB,oBAAA,gBAAgB,EAAE,IAAI;AACvB,iBAAA;AACF,aAAA,CAAC;AAEF,YAAA,IAAI,CAAC,YAAY,GAAG,IAAI,YAAY,EAAE;AAEtC,YAAA,IAAI,CAAC,IAAI,CAAC,iBAAiB,EAAE;AAC3B,gBAAA,MAAM,IAAI,CAAC,YAAY,CAAC,YAAY,CAAC,SAAS,CAAC,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC;AACtE,gBAAA,IAAI,CAAC,iBAAiB,GAAG,IAAI;YAC/B;YAEA,IAAI,CAAC,WAAW,GAAG,IAAI,gBAAgB,CAAC,IAAI,CAAC,YAAY,EAAE,eAAe,EAAE;AAC1E,gBAAA,gBAAgB,EAAE;AAChB,oBAAA,eAAe,EAAE,IAAI,CAAC,YAAY,CAAC,UAAU;AAC9C,iBAAA;AACF,aAAA,CAAC;YAEF,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,SAAS,GAAG,CAAC,KAAgC,KAAI;AACrE,gBAAA,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE;AAChB,oBAAA,MAAM,KAAK,GAAG,IAAI,CAAC,aAAa,EAAE;AAClC,oBAAA,MAAM,EAAE,SAAS,EAAE,GAAG,IAAI,CAAC,UAAU,CAAC,YAAY,CAAC,KAAK,CAAC;AACzD,oBAAA,IAAI,CAAC,iBAAiB,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,SAAS,EAAE,CAAC;gBAC9D;AACF,YAAA,CAAC;YAED,IAAI,CAAC,YAAY,GAAG,IAAI,CAAC,YAAY,CAAC,cAAc,EAAE;AACtD,YAAA,IAAI,CAAC,YAAY,CAAC,OAAO,GAAG,GAAG;AAC/B,YAAA,IAAI,CAAC,YAAY,CAAC,qBAAqB,GAAG,GAAG;AAE7C,YAAA,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,YAAY,CAAC,uBAAuB,CAAC,IAAI,CAAC,MAAM,CAAC;YACpE,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,YAAY,CAAC;YACtC,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,WAAW,CAAC;YAErC,IAAI,CAAC,oBAAoB,EAAE;QAC7B;QAAE,OAAO,KAAK,EAAE;AACd,YAAA,MAAM,GAAG,GAAG,KAAK,YAAY,KAAK,GAAG,KAAK,GAAG,IAAI,KAAK,CAAC,+BAA+B,CAAC;AACvF,YAAA,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,GAAG,CAAC;AAC3B,YAAA,MAAM,GAAG;QACX;IACF;AAEA,IAAA,MAAM,WAAW,GAAA;QACf,IAAI,CAAC,mBAAmB,EAAE;AAC1B,QAAA,IAAI,CAAC,MAAM,GAAG,KAAK;AACnB,QAAA,IAAI,CAAC,UAAU,CAAC,KAAK,EAAE;AAEvB,QAAA,IAAI,IAAI,CAAC,WAAW,EAAE;AACpB,YAAA,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,KAAK,EAAE;AAC7B,YAAA,IAAI,CAAC,WAAW,CAAC,UAAU,EAAE;AAC7B,YAAA,IAAI,CAAC,WAAW,GAAG,IAAI;QACzB;AAEA,QAAA,IAAI,IAAI,CAAC,YAAY,EAAE;AACrB,YAAA,IAAI,CAAC,YAAY,CAAC,UAAU,EAAE;AAC9B,YAAA,IAAI,CAAC,YAAY,GAAG,IAAI;QAC1B;AAEA,QAAA,IAAI,IAAI,CAAC,MAAM,EAAE;AACf,YAAA,IAAI,CAAC,MAAM,CAAC,UAAU,EAAE;AACxB,YAAA,IAAI,CAAC,MAAM,GAAG,IAAI;QACpB;AAEA,QAAA,IAAI,IAAI,CAAC,YAAY,EAAE;AACrB,YAAA,MAAM,IAAI,CAAC,YAAY,CAAC,KAAK,EAAE;AAC/B,YAAA,IAAI,CAAC,YAAY,GAAG,IAAI;AACxB,YAAA,IAAI,CAAC,iBAAiB,GAAG,KAAK;QAChC;AAEA,QAAA,IAAI,IAAI,CAAC,MAAM,EAAE;AACf,YAAA,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,OAAO,CAAC,CAAC,KAAK,KAAK,KAAK,CAAC,IAAI,EAAE,CAAC;AACxD,YAAA,IAAI,CAAC,MAAM,GAAG,IAAI;QACpB;AAEA,QAAA,IAAI,CAAC,iBAAiB,CAAC,IAAI,CAAC,CAAC,CAAC;IAChC;IAEA,YAAY,GAAA;QACV,IAAI,IAAI,CAAC,WAAW,EAAE,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE;AACtC,YAAA,IAAI,CAAC,MAAM,GAAG,IAAI;QACpB;IACF;IAEA,aAAa,GAAA;QACX,IAAI,IAAI,CAAC,WAAW,EAAE,IAAI,IAAI,CAAC,MAAM,EAAE;AACrC,YAAA,IAAI,CAAC,MAAM,GAAG,KAAK;QACrB;IACF;IAEA,WAAW,GAAA;QACT,OAAO,IAAI,CAAC,WAAW,KAAK,IAAI,IAAI,IAAI,CAAC,MAAM,KAAK,IAAI;IAC1D;IAEA,QAAQ,GAAA;QACN,OAAO,IAAI,CAAC,MAAM;IACpB;IAEA,aAAa,GAAA;AACX,QAAA,OAAO,IAAI,CAAC,YAAY,EAAE,UAAU,IAAI,IAAI;IAC9C;IAEQ,oBAAoB,GAAA;QAC1B,IAAI,CAAC,mBAAmB,EAAE;AAE1B,QAAA,IAAI,CAAC,MAAM,CAAC,iBAAiB,CAAC,MAAK;AACjC,YAAA,IAAI,CAAC,aAAa,GAAG,WAAW,CAAC,MAAK;AACpC,gBAAA,MAAM,KAAK,GAAG,IAAI,CAAC,aAAa,EAAE;AAClC,gBAAA,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,MAAK;AACnB,oBAAA,IAAI,CAAC,iBAAiB,CAAC,IAAI,CAAC,KAAK,CAAC;AACpC,gBAAA,CAAC,CAAC;AACJ,YAAA,CAAC,EAAE,IAAI,CAAC,MAAM,CAAC,mBAAmB,CAAC;AACrC,QAAA,CAAC,CAAC;IACJ;IAEQ,mBAAmB,GAAA;AACzB,QAAA,IAAI,IAAI,CAAC,aAAa,EAAE;AACtB,YAAA,aAAa,CAAC,IAAI,CAAC,aAAa,CAAC;AACjC,YAAA,IAAI,CAAC,aAAa,GAAG,IAAI;QAC3B;IACF;IAEQ,aAAa,GAAA;AACnB,QAAA,IAAI,CAAC,IAAI,CAAC,YAAY,EAAE;AACtB,YAAA,OAAO,CAAC;QACV;QAEA,MAAM,SAAS,GAAG,IAAI,UAAU,CAAC,IAAI,CAAC,YAAY,CAAC,iBAAiB,CAAC;AACrE,QAAA,IAAI,CAAC,YAAY,CAAC,oBAAoB,CAAC,SAAS,CAAC;AAEjD,QAAA,MAAM,GAAG,GAAG,SAAS,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,GAAG,KAAK,GAAG,GAAG,GAAG,EAAE,CAAC,CAAC;AACxD,QAAA,MAAM,OAAO,GAAG,GAAG,GAAG,SAAS,CAAC,MAAM;AAEtC,QAAA,OAAO,IAAI,CAAC,KAAK,CAAC,CAAC,OAAO,GAAG,GAAG,IAAI,GAAG,CAAC;IAC1C;wGAtKW,mBAAmB,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,UAAA,EAAA,CAAA;AAAnB,IAAA,OAAA,KAAA,GAAA,EAAA,CAAA,qBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,SAAA,EAAA,QAAA,EAAA,EAAA,EAAA,IAAA,EAAA,mBAAmB,cADN,MAAM,EAAA,CAAA;;4FACnB,mBAAmB,EAAA,UAAA,EAAA,CAAA;kBAD/B,UAAU;mBAAC,EAAE,UAAU,EAAE,MAAM,EAAE;;;MCTrB,oBAAoB,GAAG,IAAI,cAAc,CAAqB,sBAAsB;AAEjG,MAAM,cAAc,GAAuB;AACzC,IAAA,iBAAiB,EAAE,CAAC;AACpB,IAAA,kBAAkB,EAAE,IAAI;AACxB,IAAA,mBAAmB,EAAE,GAAG;CACzB;MAGY,mBAAmB,CAAA;AACtB,IAAA,MAAM;AACN,IAAA,MAAM;IACN,EAAE,GAAqB,IAAI;IAC3B,KAAK,GAAkB,IAAI;IAC3B,KAAK,GAAkB,IAAI;IAC3B,OAAO,GAAG,KAAK;IACf,gBAAgB,GAAG,CAAC;IACpB,gBAAgB,GAAyC,IAAI;IAC7D,gBAAgB,GAAG,KAAK;IAExB,WAAW,GAAa,EAAE;IAC1B,YAAY,GAA0C,IAAI;IAC1D,iBAAiB,GAA0C,IAAI;IAC/D,kBAAkB,GAAG,KAAK;AAE1B,IAAA,sBAAsB,GAAG,IAAI,eAAe,CAAkB,cAAc,CAAC;AAC7E,IAAA,oBAAoB,GAAG,IAAI,OAAO,EAAsB;AACxD,IAAA,YAAY,GAAG,IAAI,OAAO,EAAS;AACnC,IAAA,gBAAgB,GAAG,IAAI,eAAe,CAAgB,IAAI,CAAC;AAEnE,IAAA,gBAAgB,GAAgC,IAAI,CAAC,sBAAsB,CAAC,YAAY,EAAE;AAC1F,IAAA,cAAc,GAAmC,IAAI,CAAC,oBAAoB,CAAC,YAAY,EAAE;AACzF,IAAA,MAAM,GAAsB,IAAI,CAAC,YAAY,CAAC,YAAY,EAAE;AAC5D,IAAA,UAAU,GAA8B,IAAI,CAAC,gBAAgB,CAAC,YAAY,EAAE;AAE5E,IAAA,WAAA,GAAA;AACE,QAAA,MAAM,cAAc,GAAG,MAAM,CAAC,oBAAoB,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;AACvE,QAAA,IAAI,CAAC,MAAM,GAAG,cAAc,IAAI,cAAc;AAC9C,QAAA,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC;IAC9B;IAEA,MAAM,OAAO,CAAC,GAAW,EAAE,KAAa,EAAE,OAAO,GAAG,KAAK,EAAA;QACvD,IAAI,IAAI,CAAC,sBAAsB,CAAC,QAAQ,EAAE,KAAK,YAAY,EAAE;AAC3D,YAAA,MAAM,IAAI,KAAK,CAAC,gCAAgC,CAAC;QACnD;AAEA,QAAA,IAAI,IAAI,CAAC,WAAW,EAAE,EAAE;YACtB,IAAI,CAAC,UAAU,EAAE;QACnB;QAEA,IAAI,CAAC,qBAAqB,EAAE;AAC5B,QAAA,IAAI,CAAC,KAAK,GAAG,GAAG;AAChB,QAAA,IAAI,CAAC,KAAK,GAAG,KAAK;AAClB,QAAA,IAAI,CAAC,OAAO,GAAG,OAAO;AACtB,QAAA,IAAI,CAAC,gBAAgB,GAAG,KAAK;AAC7B,QAAA,IAAI,CAAC,gBAAgB,GAAG,CAAC;AAEzB,QAAA,OAAO,IAAI,CAAC,gBAAgB,EAAE;IAChC;IAEA,UAAU,GAAA;AACR,QAAA,IAAI,CAAC,gBAAgB,GAAG,IAAI;QAC5B,IAAI,CAAC,qBAAqB,EAAE;QAC5B,IAAI,CAAC,qBAAqB,EAAE;AAE5B,QAAA,IAAI,IAAI,CAAC,EAAE,IAAI,IAAI,CAAC,EAAE,CAAC,UAAU,KAAK,SAAS,CAAC,IAAI,EAAE;YACpD,IAAI,CAAC,EAAE,CAAC,KAAK,CAAC,IAAI,EAAE,mBAAmB,CAAC;QAC1C;AACA,QAAA,IAAI,CAAC,EAAE,GAAG,IAAI;AAEd,QAAA,IAAI,CAAC,sBAAsB,CAAC,IAAI,CAAC,cAAc,CAAC;AAChD,QAAA,IAAI,CAAC,gBAAgB,CAAC,IAAI,CAAC,IAAI,CAAC;IAClC;IAEA,cAAc,CAAC,KAAkB,EAAE,SAAkB,EAAA;AACnD,QAAA,MAAM,OAAO,GAAG,IAAI,CAAC,SAAS,CAAC;AAC7B,YAAA,IAAI,EAAE,OAAO;YACb,SAAS;AACT,YAAA,IAAI,EAAE,IAAI,CAAC,mBAAmB,CAAC,KAAK,CAAC;AACtC,SAAA,CAAC;AACF,QAAA,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,OAAO,CAAC;AAE9B,QAAA,IAAI,SAAS,IAAI,CAAC,IAAI,CAAC,kBAAkB,EAAE;AACzC,YAAA,IAAI,CAAC,kBAAkB,GAAG,IAAI;YAC9B,IAAI,CAAC,sBAAsB,EAAE;QAC/B;AAAO,aAAA,IAAI,CAAC,SAAS,IAAI,IAAI,CAAC,kBAAkB,EAAE;AAChD,YAAA,IAAI,CAAC,kBAAkB,GAAG,KAAK;YAC/B,IAAI,CAAC,qBAAqB,EAAE;QAC9B;IACF;IAEQ,sBAAsB,GAAA;QAC5B,IAAI,CAAC,qBAAqB,EAAE;AAC5B,QAAA,IAAI,CAAC,iBAAiB,GAAG,WAAW,CAAC,MAAK;AACxC,YAAA,IAAI,IAAI,CAAC,WAAW,EAAE,EAAE;AACtB,gBAAA,IAAI,CAAC,EAAG,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,CAAC,CAAC;YACtD;QACF,CAAC,EAAE,IAAI,CAAC;IACV;IAEQ,qBAAqB,GAAA;AAC3B,QAAA,IAAI,IAAI,CAAC,iBAAiB,EAAE;AAC1B,YAAA,aAAa,CAAC,IAAI,CAAC,iBAAiB,CAAC;AACrC,YAAA,IAAI,CAAC,iBAAiB,GAAG,IAAI;QAC/B;IACF;AAEQ,IAAA,mBAAmB,CAAC,MAAmB,EAAA;AAC7C,QAAA,MAAM,KAAK,GAAG,IAAI,UAAU,CAAC,MAAM,CAAC;QACpC,IAAI,MAAM,GAAG,EAAE;AACf,QAAA,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,UAAU,EAAE,CAAC,EAAE,EAAE;YACzC,MAAM,IAAI,MAAM,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;QACzC;AACA,QAAA,OAAO,IAAI,CAAC,MAAM,CAAC;IACrB;IAEA,WAAW,GAAA;QACT,OAAO,IAAI,CAAC,EAAE,EAAE,UAAU,KAAK,SAAS,CAAC,IAAI;IAC/C;IAEA,YAAY,GAAA;AACV,QAAA,OAAO,IAAI,CAAC,gBAAgB,CAAC,QAAQ,EAAE;IACzC;IAEQ,gBAAgB,GAAA;QACtB,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,KAAI;AACrC,YAAA,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE;AACf,gBAAA,MAAM,CAAC,IAAI,KAAK,CAAC,2BAA2B,CAAC,CAAC;gBAC9C;YACF;AAEA,YAAA,IAAI,CAAC,sBAAsB,CAAC,IAAI,CAAC,YAAY,CAAC;AAC9C,YAAA,MAAM,MAAM,GAAG,IAAI,eAAe,CAAC,EAAE,OAAO,EAAE,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC;AACrE,YAAA,IAAI,IAAI,CAAC,KAAK,EAAE;gBACd,MAAM,CAAC,GAAG,CAAC,OAAO,EAAE,IAAI,CAAC,KAAK,CAAC;YACjC;AACA,YAAA,MAAM,GAAG,GAAG,CAAA,EAAG,IAAI,CAAC,KAAK,CAAA,CAAA,EAAI,MAAM,CAAC,QAAQ,EAAE,CAAA,CAAE;YAEhD,IAAI,CAAC,EAAE,GAAG,IAAI,SAAS,CAAC,GAAG,CAAC;AAC5B,YAAA,IAAI,CAAC,EAAE,CAAC,UAAU,GAAG,aAAa;AAElC,YAAA,IAAI,CAAC,EAAE,CAAC,MAAM,GAAG,MAAK;AACpB,gBAAA,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,MAAK;AACnB,oBAAA,IAAI,CAAC,gBAAgB,GAAG,CAAC;AACzB,oBAAA,IAAI,CAAC,sBAAsB,CAAC,IAAI,CAAC,WAAW,CAAC;oBAC7C,IAAI,CAAC,cAAc,EAAE;AACrB,oBAAA,OAAO,EAAE;AACX,gBAAA,CAAC,CAAC;AACJ,YAAA,CAAC;AAED,YAAA,IAAI,CAAC,EAAE,CAAC,OAAO,GAAG,MAAK;AACrB,gBAAA,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,MAAK;AACnB,oBAAA,MAAM,KAAK,GAAG,IAAI,KAAK,CAAC,4BAA4B,CAAC;AACrD,oBAAA,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,KAAK,CAAC;oBAC7B,IAAI,IAAI,CAAC,sBAAsB,CAAC,QAAQ,EAAE,KAAK,YAAY,EAAE;wBAC3D,MAAM,CAAC,KAAK,CAAC;oBACf;AACF,gBAAA,CAAC,CAAC;AACJ,YAAA,CAAC;YAED,IAAI,CAAC,EAAE,CAAC,SAAS,GAAG,CAAC,KAAK,KAAI;AAC5B,gBAAA,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,MAAK;AACnB,oBAAA,IAAI;wBACF,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC;wBACnC,IAAI,IAAI,CAAC,IAAI,KAAK,WAAW,IAAI,IAAI,CAAC,SAAS,EAAE;4BAC/C,IAAI,CAAC,gBAAgB,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC;wBAC5C;AACA,wBAAA,IAAI,CAAC,oBAAoB,CAAC,IAAI,CAAC,IAA0B,CAAC;oBAC5D;oBAAE,OAAO,CAAC,EAAE;wBACV,MAAM,KAAK,GAAG,IAAI,KAAK,CAAC,sCAAsC,CAAC,YAAY,KAAK,GAAG,CAAC,CAAC,OAAO,GAAG,MAAM,CAAC,CAAC,CAAC,CAAA,CAAE,CAAC;AAC3G,wBAAA,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,OAAO,CAAC;AAC5B,wBAAA,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,KAAK,CAAC;oBAC/B;AACF,gBAAA,CAAC,CAAC;AACJ,YAAA,CAAC;YAED,IAAI,CAAC,EAAE,CAAC,OAAO,GAAG,CAAC,KAAK,KAAI;AAC1B,gBAAA,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,MAAK;oBACnB,IAAI,CAAC,aAAa,EAAE;oBAEpB,IAAI,CAAC,IAAI,CAAC,gBAAgB,IAAI,KAAK,CAAC,IAAI,KAAK,IAAI,EAAE;wBACjD,IAAI,CAAC,gBAAgB,EAAE;oBACzB;yBAAO;AACL,wBAAA,IAAI,CAAC,sBAAsB,CAAC,IAAI,CAAC,cAAc,CAAC;AAChD,wBAAA,IAAI,CAAC,gBAAgB,CAAC,IAAI,CAAC,IAAI,CAAC;oBAClC;AACF,gBAAA,CAAC,CAAC;AACJ,YAAA,CAAC;AACH,QAAA,CAAC,CAAC;IACJ;IAEQ,gBAAgB,GAAA;QACtB,IAAI,IAAI,CAAC,gBAAgB,IAAI,IAAI,CAAC,MAAM,CAAC,iBAAiB,EAAE;AAC1D,YAAA,IAAI,CAAC,sBAAsB,CAAC,IAAI,CAAC,cAAc,CAAC;YAChD,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,IAAI,KAAK,CAAC,mCAAmC,CAAC,CAAC;YACtE;QACF;AAEA,QAAA,IAAI,CAAC,sBAAsB,CAAC,IAAI,CAAC,cAAc,CAAC;AAChD,QAAA,MAAM,KAAK,GAAG,IAAI,CAAC,MAAM,CAAC,kBAAkB,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,gBAAgB,CAAC;QACjF,IAAI,CAAC,gBAAgB,EAAE;AAEvB,QAAA,IAAI,CAAC,gBAAgB,GAAG,UAAU,CAAC,MAAK;YACtC,IAAI,CAAC,gBAAgB,EAAE,CAAC,KAAK,CAAC,MAAK,EAAE,CAAC,CAAC;QACzC,CAAC,EAAE,KAAK,CAAC;IACX;IAEQ,qBAAqB,GAAA;AAC3B,QAAA,IAAI,IAAI,CAAC,gBAAgB,EAAE;AACzB,YAAA,YAAY,CAAC,IAAI,CAAC,gBAAgB,CAAC;AACnC,YAAA,IAAI,CAAC,gBAAgB,GAAG,IAAI;QAC9B;IACF;IAEQ,cAAc,GAAA;QACpB,IAAI,CAAC,aAAa,EAAE;AAEpB,QAAA,IAAI,CAAC,YAAY,GAAG,WAAW,CAAC,MAAK;AACnC,YAAA,IAAI,IAAI,CAAC,WAAW,CAAC,MAAM,GAAG,CAAC,IAAI,IAAI,CAAC,WAAW,EAAE,EAAE;AACrD,gBAAA,KAAK,MAAM,GAAG,IAAI,IAAI,CAAC,WAAW,EAAE;AAClC,oBAAA,IAAI,CAAC,EAAG,CAAC,IAAI,CAAC,GAAG,CAAC;gBACpB;AACA,gBAAA,IAAI,CAAC,WAAW,GAAG,EAAE;YACvB;AACF,QAAA,CAAC,EAAE,IAAI,CAAC,MAAM,CAAC,mBAAmB,CAAC;IACrC;IAEQ,qBAAqB,GAAA;AAC3B,QAAA,IAAI,IAAI,CAAC,YAAY,EAAE;AACrB,YAAA,aAAa,CAAC,IAAI,CAAC,YAAY,CAAC;AAChC,YAAA,IAAI,CAAC,YAAY,GAAG,IAAI;QAC1B;AAEA,QAAA,IAAI,IAAI,CAAC,WAAW,CAAC,MAAM,GAAG,CAAC,IAAI,IAAI,CAAC,WAAW,EAAE,EAAE;AACrD,YAAA,KAAK,MAAM,GAAG,IAAI,IAAI,CAAC,WAAW,EAAE;AAClC,gBAAA,IAAI,CAAC,EAAG,CAAC,IAAI,CAAC,GAAG,CAAC;YACpB;QACF;AACA,QAAA,IAAI,CAAC,WAAW,GAAG,EAAE;QACrB,IAAI,CAAC,qBAAqB,EAAE;AAC5B,QAAA,IAAI,CAAC,kBAAkB,GAAG,KAAK;IACjC;IAEQ,aAAa,GAAA;AACnB,QAAA,IAAI,IAAI,CAAC,YAAY,EAAE;AACrB,YAAA,aAAa,CAAC,IAAI,CAAC,YAAY,CAAC;AAChC,YAAA,IAAI,CAAC,YAAY,GAAG,IAAI;QAC1B;AACA,QAAA,IAAI,CAAC,WAAW,GAAG,EAAE;IACvB;wGAhPW,mBAAmB,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,UAAA,EAAA,CAAA;AAAnB,IAAA,OAAA,KAAA,GAAA,EAAA,CAAA,qBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,SAAA,EAAA,QAAA,EAAA,EAAA,EAAA,IAAA,EAAA,mBAAmB,cADN,MAAM,EAAA,CAAA;;4FACnB,mBAAmB,EAAA,UAAA,EAAA,CAAA;kBAD/B,UAAU;mBAAC,EAAE,UAAU,EAAE,MAAM,EAAE;;;ACpBlC,MAAM,WAAW,GAAG,KAAK;AACzB,MAAM,YAAY,GAAG,CAAC;AACtB,MAAM,eAAe,GAAG,EAAE;AAE1B,SAAS,WAAW,CAAC,IAAc,EAAE,MAAc,EAAE,GAAW,EAAA;AAC9D,IAAA,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,GAAG,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE;AACnC,QAAA,IAAI,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;IAC9C;AACF;AAEA,SAAS,aAAa,CAAC,OAAoB,EAAE,OAAoB,EAAA;AAC/D,IAAA,MAAM,QAAQ,GAAG,IAAI,UAAU,CAAC,OAAO,CAAC,UAAU,GAAG,OAAO,CAAC,UAAU,CAAC;IACxE,QAAQ,CAAC,GAAG,CAAC,IAAI,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;AACxC,IAAA,QAAQ,CAAC,GAAG,CAAC,IAAI,UAAU,CAAC,OAAO,CAAC,EAAE,OAAO,CAAC,UAAU,CAAC;IACzD,OAAO,QAAQ,CAAC,MAAM;AACxB;SAEgB,QAAQ,CAAC,OAAoB,EAAE,UAAU,GAAG,WAAW,EAAA;AACrE,IAAA,MAAM,MAAM,GAAG,IAAI,WAAW,CAAC,EAAE,CAAC;AAClC,IAAA,MAAM,IAAI,GAAG,IAAI,QAAQ,CAAC,MAAM,CAAC;IAEjC,MAAM,QAAQ,GAAG,UAAU,GAAG,YAAY,IAAI,eAAe,GAAG,CAAC,CAAC;IAClE,MAAM,UAAU,GAAG,YAAY,IAAI,eAAe,GAAG,CAAC,CAAC;;AAGvD,IAAA,WAAW,CAAC,IAAI,EAAE,CAAC,EAAE,MAAM,CAAC;AAC5B,IAAA,IAAI,CAAC,SAAS,CAAC,CAAC,EAAE,EAAE,GAAG,OAAO,CAAC,UAAU,EAAE,IAAI,CAAC;AAChD,IAAA,WAAW,CAAC,IAAI,EAAE,CAAC,EAAE,MAAM,CAAC;;AAG5B,IAAA,WAAW,CAAC,IAAI,EAAE,EAAE,EAAE,MAAM,CAAC;IAC7B,IAAI,CAAC,SAAS,CAAC,EAAE,EAAE,EAAE,EAAE,IAAI,CAAC,CAAC;IAC7B,IAAI,CAAC,SAAS,CAAC,EAAE,EAAE,CAAC,EAAE,IAAI,CAAC,CAAC;IAC5B,IAAI,CAAC,SAAS,CAAC,EAAE,EAAE,YAAY,EAAE,IAAI,CAAC,CAAC;IACvC,IAAI,CAAC,SAAS,CAAC,EAAE,EAAE,UAAU,EAAE,IAAI,CAAC,CAAC;IACrC,IAAI,CAAC,SAAS,CAAC,EAAE,EAAE,QAAQ,EAAE,IAAI,CAAC,CAAC;IACnC,IAAI,CAAC,SAAS,CAAC,EAAE,EAAE,UAAU,EAAE,IAAI,CAAC,CAAC;IACrC,IAAI,CAAC,SAAS,CAAC,EAAE,EAAE,eAAe,EAAE,IAAI,CAAC,CAAC;;AAG1C,IAAA,WAAW,CAAC,IAAI,EAAE,EAAE,EAAE,MAAM,CAAC;IAC7B,IAAI,CAAC,SAAS,CAAC,EAAE,EAAE,OAAO,CAAC,UAAU,EAAE,IAAI,CAAC;AAE5C,IAAA,OAAO,aAAa,CAAC,MAAM,EAAE,OAAO,CAAC;AACvC;AAEM,SAAU,kBAAkB,CAAC,OAAoB,EAAA;AACrD,IAAA,MAAM,IAAI,GAAG,IAAI,IAAI,CAAC,CAAC,OAAO,CAAC,EAAE,EAAE,IAAI,EAAE,WAAW,EAAE,CAAC;AACvD,IAAA,OAAO,GAAG,CAAC,eAAe,CAAC,IAAI,CAAC;AAClC;AAEM,SAAU,UAAU,CAAC,OAAe,EAAA;IACxC,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,GAAG,EAAE,CAAC;IACrC,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,GAAG,EAAE,CAAC;AACrC,IAAA,OAAO,CAAA,EAAG,IAAI,CAAA,CAAA,EAAI,IAAI,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE;AACtD;;AC/BA,MAAM,cAAc,GAA2B;AAC7C,IAAA,CAAC,EAAE,UAAU;AACb,IAAA,CAAC,EAAE,UAAU;AACb,IAAA,CAAC,EAAE,UAAU;AACb,IAAA,CAAC,EAAE,UAAU;CACd;MAsrBY,iBAAiB,CAAA;AACpB,IAAA,YAAY,GAAG,MAAM,CAAC,mBAAmB,CAAC;AAC1C,IAAA,MAAM,GAAG,MAAM,CAAC,mBAAmB,CAAC;AACpC,IAAA,UAAU,GAAG,MAAM,CAAC,UAAU,CAAC;IAC/B,aAAa,GAAmB,EAAE;IAClC,cAAc,GAAG,CAAC;IAClB,uBAAuB,GAA2B,IAAI;AAG9D,IAAA,eAAe,CAAC,KAAiB,EAAA;AAC/B,QAAA,IAAI,CAAC,IAAI,CAAC,gBAAgB,EAAE;YAAE;AAC9B,QAAA,MAAM,MAAM,GAAG,KAAK,CAAC,MAAqB;AAC1C,QAAA,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,aAAa,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE;AACnD,YAAA,IAAI,CAAC,gBAAgB,CAAC,GAAG,CAAC,KAAK,CAAC;QAClC;IACF;AAEA,IAAA,KAAK,GAAG,KAAK,CAAS,EAAE,CAAC;AACzB,IAAA,KAAK,GAAG,KAAK,CAAS,EAAE,CAAC;AACzB,IAAA,aAAa,GAAG,KAAK,CAAyB,EAAE,CAAC;AACjD,IAAA,OAAO,GAAG,KAAK,CAAU,KAAK,CAAC;AAC/B,IAAA,SAAS,GAAG,KAAK,CAAmB,EAAE,CAAC;AACvC,IAAA,SAAS,GAAG,KAAK,CAAS,EAAE,CAAC;IAE7B,SAAS,GAAG,KAAK,EAAsB;AACvC,IAAA,MAAM,GAAG,KAAK,CAAS,EAAE,CAAC;IAE1B,cAAc,GAAG,MAAM,EAAU;IACjC,eAAe,GAAG,MAAM,EAAsD;IAC9E,KAAK,GAAG,MAAM,EAAS;IACvB,iBAAiB,GAAG,MAAM,EAAqB;IAC/C,eAAe,GAAG,MAAM,EAAS;AAEjC,IAAA,WAAW,GAAG,MAAM,CAAC,KAAK,CAAC;AAC3B,IAAA,QAAQ,GAAG,MAAM,CAAC,KAAK,CAAC;AACxB,IAAA,UAAU,GAAG,MAAM,CAAC,CAAC,CAAC;AACtB,IAAA,eAAe,GAAG,MAAM,CAAkB,cAAc,CAAC;AACzD,IAAA,OAAO,GAAG,MAAM,CAAoB,EAAE,CAAC;AACvC,IAAA,WAAW,GAAG,MAAM,CAAC,EAAE,CAAC;AACxB,IAAA,cAAc,GAAG,MAAM,CAAqB,SAAS,CAAC;AACtD,IAAA,gBAAgB,GAAG,MAAM,CAAC,KAAK,CAAC;AAChC,IAAA,YAAY,GAAG,MAAM,CAAC,KAAK,CAAC;AAC5B,IAAA,aAAa,GAAG,MAAM,CAAgB,IAAI,CAAC;AAE3C,IAAA,SAAS,GAAG,MAAM,CAAC,KAAK,CAAC;AACzB,IAAA,gBAAgB,GAAG,MAAM,CAAC,KAAK,CAAC;AAChC,IAAA,gBAAgB,GAAG,MAAM,CAAC,CAAC,CAAC;AAC5B,IAAA,aAAa,GAAG,MAAM,CAAC,CAAC,CAAC;AACzB,IAAA,YAAY,GAAG,MAAM,CAAC,CAAC,CAAC;AACxB,IAAA,WAAW,GAAG,MAAM,CAA6B,IAAI,CAAC;AACtD,IAAA,eAAe,GAAG,MAAM,CAAgB,IAAI,CAAC;AAC7C,IAAA,eAAe,GAAG,MAAM,CAAgB,IAAI,CAAC;IAErC,YAAY,GAA4B,IAAI;IAC5C,YAAY,GAAkB,IAAI;AAE1C,IAAA,IAAI,GAAG,QAAQ,CAAe,MAC5B,IAAI,CAAC,SAAS,EAAE,GAAG,UAAU,GAAG,WAAW,CAC5C;AAED,IAAA,QAAQ,GAAG,QAAQ,CAAC,MAClB,IAAI,CAAC,WAAW,EAAE,EAAE,aAAa,CAAC,QAAQ,IAAI,EAAE,CACjD;IAED,kBAAkB,GAAG,QAAQ,CAAC,MAC5B,IAAI,CAAC,aAAa,EAAE,KAAK,IAAI;QAC7B,CAAC,IAAI,CAAC,WAAW,EAAE;AACnB,QAAA,CAAC,IAAI,CAAC,QAAQ,EAAE,CACjB;AAED,IAAA,aAAa,GAAG,QAAQ,CAAiB,MAAK;AAC5C,QAAA,MAAM,UAAU,GAAG,IAAI,CAAC,OAAO,EAAE;AACjC,QAAA,IAAI,UAAU,CAAC,MAAM,KAAK,CAAC;AAAE,YAAA,OAAO,EAAE;QAEtC,MAAM,MAAM,GAAmB,EAAE;QACjC,IAAI,YAAY,GAAwB,IAAI;AAE5C,QAAA,KAAK,MAAM,KAAK,IAAI,UAAU,EAAE;YAC9B,IAAI,CAAC,YAAY,IAAI,YAAY,CAAC,OAAO,KAAK,KAAK,CAAC,OAAO,EAAE;AAC3D,gBAAA,YAAY,GAAG,EAAE,OAAO,EAAE,KAAK,CAAC,OAAO,EAAE,OAAO,EAAE,EAAE,EAAE;AACtD,gBAAA,MAAM,CAAC,IAAI,CAAC,YAAY,CAAC;YAC3B;AACA,YAAA,YAAY,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC;QAClC;AAEA,QAAA,OAAO,MAAM;AACf,IAAA,CAAC,CAAC;AAEF,IAAA,WAAA,GAAA;AACE,QAAA,IAAI,CAAC,aAAa,CAAC,IAAI,CACrB,IAAI,CAAC,YAAY,CAAC,WAAW,CAAC,SAAS,CAAC,CAAC,KAAK,KAAI;AAChD,YAAA,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,KAAK,CAAC;AAC5B,QAAA,CAAC,CAAC,EACF,IAAI,CAAC,MAAM,CAAC,gBAAgB,CAAC,SAAS,CAAC,CAAC,KAAK,KAAI;AAC/C,YAAA,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,KAAK,CAAC;AACjC,QAAA,CAAC,CAAC,EACF,IAAI,CAAC,MAAM,CAAC,cAAc,CAAC,SAAS,CAAC,CAAC,KAAK,KAAI;AAC7C,YAAA,IAAI,CAAC,mBAAmB,CAAC,KAAK,CAAC;AACjC,QAAA,CAAC,CAAC,EACF,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,GAAG,KAAI;AACnC,YAAA,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC;AACtB,QAAA,CAAC,CAAC,EACF,IAAI,CAAC,YAAY,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,GAAG,KAAI;AACzC,YAAA,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC;AACtB,QAAA,CAAC,CAAC,EACF,IAAI,CAAC,YAAY,CAAC,WAAW,CAAC,SAAS,CAAC,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,KAAI;YAC9D,IAAI,CAAC,MAAM,CAAC,cAAc,CAAC,IAAI,EAAE,SAAS,CAAC;QAC7C,CAAC,CAAC,CACH;QAED,MAAM,CAAC,MAAK;AACV,YAAA,MAAM,GAAG,GAAG,IAAI,CAAC,SAAS,EAAE;AAC5B,YAAA,MAAM,GAAG,GAAG,IAAI,CAAC,MAAM,EAAE;AACzB,YAAA,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,EAAE;YACxB,IAAI,GAAG,IAAI,GAAG,IAAI,IAAI,CAAC,IAAI,EAAE,KAAK,UAAU,EAAE;gBAC5C,IAAI,CAAC,WAAW,EAAE;YACpB;AACF,QAAA,CAAC,CAAC;IACJ;IAEA,WAAW,GAAA;AACT,QAAA,IAAI,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC,GAAG,KAAK,GAAG,CAAC,WAAW,EAAE,CAAC;AACtD,QAAA,IAAI,CAAC,uBAAuB,EAAE,KAAK,EAAE;QACrC,IAAI,CAAC,OAAO,EAAE;QACd,IAAI,CAAC,eAAe,EAAE;IACxB;IAEQ,kBAAkB,GAItB,EAAE;IAEE,eAAe,GAAA;AACrB,QAAA,IAAI,IAAI,CAAC,YAAY,EAAE;AACrB,YAAA,IAAI,CAAC,YAAY,CAAC,KAAK,EAAE;AACzB,YAAA,IAAI,IAAI,CAAC,kBAAkB,CAAC,cAAc,EAAE;AAC1C,gBAAA,IAAI,CAAC,YAAY,CAAC,mBAAmB,CAAC,gBAAgB,EAAE,IAAI,CAAC,kBAAkB,CAAC,cAAc,CAAC;YACjG;AACA,YAAA,IAAI,IAAI,CAAC,kBAAkB,CAAC,UAAU,EAAE;AACtC,gBAAA,IAAI,CAAC,YAAY,CAAC,mBAAmB,CAAC,YAAY,EAAE,IAAI,CAAC,kBAAkB,CAAC,UAAU,CAAC;YACzF;AACA,YAAA,IAAI,IAAI,CAAC,kBAAkB,CAAC,KAAK,EAAE;AACjC,gBAAA,IAAI,CAAC,YAAY,CAAC,mBAAmB,CAAC,OAAO,EAAE,IAAI,CAAC,kBAAkB,CAAC,KAAK,CAAC;YAC/E;AACA,YAAA,IAAI,CAAC,kBAAkB,GAAG,EAAE;AAC5B,YAAA,IAAI,CAAC,YAAY,GAAG,IAAI;QAC1B;AACA,QAAA,IAAI,IAAI,CAAC,YAAY,EAAE;AACrB,YAAA,GAAG,CAAC,eAAe,CAAC,IAAI,CAAC,YAAY,CAAC;AACtC,YAAA,IAAI,CAAC,YAAY,GAAG,IAAI;QAC1B;IACF;AAEA,IAAA,eAAe,CAAC,OAAe,EAAA;AAC7B,QAAA,MAAM,YAAY,GAAG,IAAI,CAAC,aAAa,EAAE;AACzC,QAAA,IAAI,YAAY,CAAC,OAAO,CAAC,EAAE;AACzB,YAAA,OAAO,YAAY,CAAC,OAAO,CAAC;QAC9B;QACA,OAAO,cAAc,CAAC,OAAO,CAAC,IAAI,UAAU,OAAO,GAAG,CAAC,CAAA,CAAE;IAC3D;AAEA,IAAA,sBAAsB,CAAC,YAAoB,EAAA;AACzC,QAAA,MAAM,IAAI,GAAG,IAAI,CAAC,QAAQ,EAAE;QAC5B,IAAI,YAAY,KAAK,CAAC;AAAE,YAAA,OAAO,IAAI;QACnC,MAAM,cAAc,GAAG,IAAI,CAAC,YAAY,CAAC,EAAE,OAAO;QAClD,MAAM,eAAe,GAAG,IAAI,CAAC,YAAY,GAAG,CAAC,CAAC,EAAE,OAAO;QACvD,OAAO,cAAc,KAAK,eAAe;IAC3C;IAEA,iBAAiB,GAAA;AACf,QAAA,IAAI,IAAI,CAAC,QAAQ,EAAE,EAAE;AACnB,YAAA,OAAO,kBAAkB;QAC3B;AACA,QAAA,IAAI,IAAI,CAAC,WAAW,EAAE,EAAE;AACtB,YAAA,OAAO,iBAAiB;QAC1B;AACA,QAAA,OAAO,kBAAkB;IAC3B;AAEA,IAAA,MAAM,eAAe,GAAA;AACnB,QAAA,IAAI,IAAI,CAAC,QAAQ,EAAE,EAAE;YACnB,IAAI,CAAC,eAAe,EAAE;QACxB;AAAO,aAAA,IAAI,IAAI,CAAC,WAAW,EAAE,EAAE;YAC7B,IAAI,CAAC,cAAc,EAAE;QACvB;aAAO;AACL,YAAA,MAAM,IAAI,CAAC,cAAc,EAAE;QAC7B;IACF;IAEA,cAAc,GAAA;QACZ,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,IAAI,IAAI,CAAC,QAAQ,EAAE;YAAE;AAC5C,QAAA,IAAI,CAAC,YAAY,CAAC,YAAY,EAAE;AAChC,QAAA,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC;IACzB;IAEA,eAAe,GAAA;AACb,QAAA,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE;YAAE;AACtB,QAAA,IAAI,CAAC,YAAY,CAAC,aAAa,EAAE;AACjC,QAAA,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC;IAC1B;AAEA,IAAA,MAAM,aAAa,GAAA;QACjB,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE;YAAE;QAE7C,MAAM,SAAS,GAAG,IAAI,CAAC,MAAM,CAAC,YAAY,EAAE;AAE5C,QAAA,MAAM,IAAI,CAAC,aAAa,EAAE;AAE1B,QAAA,MAAM,UAAU,GAAG,IAAI,CAAC,OAAO,EAAE;QACjC,MAAM,cAAc,GAAG,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC;AAE9D,QAAA,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC,EAAE,UAAU,EAAE,cAAc,EAAE,OAAO,EAAE,UAAU,EAAE,CAAC;AAE9E,QAAA,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,EAAE,CAAC;AACxB,QAAA,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,SAAS,CAAC;AAElC,QAAA,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,SAAS,CAAC;IACnC;IAEA,kBAAkB,GAAA;AAChB,QAAA,IAAI,CAAC,gBAAgB,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC;IACzC;IAEA,MAAM,cAAc,CAAC,QAAwB,EAAA;QAC3C,IAAI,IAAI,CAAC,YAAY,EAAE;YAAE;AAEzB,QAAA,IAAI,CAAC,gBAAgB,CAAC,GAAG,CAAC,KAAK,CAAC;AAEhC,QAAA,MAAM,SAAS,GAAG,IAAI,CAAC,SAAS,EAAE;QAClC,IAAI,CAAC,SAAS,EAAE;YACd,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC,IAAI,KAAK,CAAC,yBAAyB,CAAC,CAAC;YAC/D;QACF;AAEA,QAAA,MAAM,SAAS,GAAG,IAAI,CAAC,aAAa,EAAE;QACtC,IAAI,CAAC,SAAS,EAAE;YACd,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC,IAAI,KAAK,CAAC,sBAAsB,CAAC,CAAC;YAC5D;QACF;AAEA,QAAA,IAAI,CAAC,uBAAuB,EAAE,KAAK,EAAE;AACrC,QAAA,IAAI,CAAC,uBAAuB,GAAG,IAAI,eAAe,EAAE;AAEpD,QAAA,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,IAAI,CAAC;AAE3B,QAAA,IAAI;AACF,YAAA,MAAM,OAAO,GAA2B,EAAE,cAAc,EAAE,kBAAkB,EAAE;AAC9E,YAAA,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,EAAE;YAC1B,IAAI,KAAK,EAAE;AACT,gBAAA,OAAO,CAAC,eAAe,CAAC,GAAG,CAAA,OAAA,EAAU,KAAK,EAAE;YAC9C;YAEA,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,CAAA,EAAG,SAAS,WAAW,EAAE;AACpD,gBAAA,MAAM,EAAE,MAAM;gBACd,OAAO;AACP,gBAAA,MAAM,EAAE,IAAI,CAAC,uBAAuB,CAAC,MAAM;AAC3C,gBAAA,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC;oBACnB,SAAS;oBACT,YAAY,EAAE,QAAQ,CAAC,OAAO;iBAC/B,CAAC;AACH,aAAA,CAAC;AAEF,YAAA,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE;AAChB,gBAAA,MAAM,SAAS,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC;AACzD,gBAAA,MAAM,IAAI,KAAK,CAAC,SAAS,CAAC,KAAK,IAAI,CAAA,KAAA,EAAQ,QAAQ,CAAC,MAAM,CAAA,CAAE,CAAC;YAC/D;AAEA,YAAA,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE;AAEpC,YAAA,IAAI,CAAC,iBAAiB,CAAC,IAAI,CAAC;gBAC1B,SAAS;gBACT,UAAU,EAAE,QAAQ,CAAC,EAAE;gBACvB,OAAO,EAAE,MAAM,CAAC,OAAO;gBACvB,WAAW,EAAE,MAAM,CAAC,WAAW;AAChC,aAAA,CAAC;QACJ;QAAE,OAAO,GAAG,EAAE;YACZ,IAAI,GAAG,YAAY,KAAK,IAAI,GAAG,CAAC,IAAI,KAAK,YAAY;gBAAE;YACvD,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC,GAAG,YAAY,KAAK,GAAG,GAAG,GAAG,IAAI,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;QAChF;gBAAU;AACR,YAAA,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,KAAK,CAAC;QAC9B;IACF;AAEA,IAAA,MAAM,WAAW,GAAA;AACf,QAAA,MAAM,GAAG,GAAG,IAAI,CAAC,SAAS,EAAE;AAC5B,QAAA,MAAM,GAAG,GAAG,IAAI,CAAC,MAAM,EAAE;AAEzB,QAAA,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG;YAAE;AAElB,QAAA,IAAI,CAAC,gBAAgB,CAAC,GAAG,CAAC,IAAI,CAAC;AAE/B,QAAA,IAAI;YACF,MAAM,OAAO,GAA2B,EAAE;AAC1C,YAAA,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,EAAE;YAC1B,IAAI,KAAK,EAAE;AACT,gBAAA,OAAO,CAAC,eAAe,CAAC,GAAG,CAAA,OAAA,EAAU,KAAK,EAAE;YAC9C;AAEA,YAAA,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,CAAA,EAAG,GAAG,CAAA,SAAA,EAAY,GAAG,EAAE,EAAE,EAAE,OAAO,EAAE,CAAC;AAElE,YAAA,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE;gBAChB,MAAM,IAAI,KAAK,CAAC,CAAA,KAAA,EAAQ,QAAQ,CAAC,MAAM,CAAA,CAAE,CAAC;YAC5C;AAEA,YAAA,MAAM,IAAI,GAAwB,MAAM,QAAQ,CAAC,IAAI,EAAE;AACvD,YAAA,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,IAAI,CAAC;YAE1B,MAAM,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,QAAQ,CAAC;QACrC;QAAE,OAAO,GAAG,EAAE;YACZ,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,YAAY,KAAK,GAAG,GAAG,GAAG,IAAI,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;QACtE;gBAAU;AACR,YAAA,IAAI,CAAC,gBAAgB,CAAC,GAAG,CAAC,KAAK,CAAC;QAClC;IACF;IAEQ,MAAM,SAAS,CAAC,MAAc,EAAA;QACpC,IAAI,CAAC,eAAe,EAAE;AAEtB,QAAA,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,MAAM,CAAC;AACpC,QAAA,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE;YAChB,MAAM,IAAI,KAAK,CAAC,CAAA,2BAAA,EAA8B,QAAQ,CAAC,MAAM,CAAA,CAAE,CAAC;QAClE;AAEA,QAAA,MAAM,OAAO,GAAG,MAAM,QAAQ,CAAC,WAAW,EAAE;AAE5C,QAAA,MAAM,OAAO,GAAG,QAAQ,CAAC,OAAO,CAAC;AACjC,QAAA,IAAI,CAAC,YAAY,GAAG,kBAAkB,CAAC,OAAO,CAAC;QAE/C,IAAI,CAAC,YAAY,GAAG,IAAI,KAAK,CAAC,IAAI,CAAC,YAAY,CAAC;AAEhD,QAAA,IAAI,CAAC,kBAAkB,CAAC,cAAc,GAAG,MAAK;YAC5C,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,IAAI,CAAC,YAAa,CAAC,QAAQ,CAAC;AACrD,QAAA,CAAC;AACD,QAAA,IAAI,CAAC,kBAAkB,CAAC,UAAU,GAAG,MAAK;YACxC,IAAI,CAAC,gBAAgB,CAAC,GAAG,CAAC,IAAI,CAAC,YAAa,CAAC,WAAW,CAAC;YACzD,IAAI,CAAC,mBAAmB,EAAE;AAC5B,QAAA,CAAC;AACD,QAAA,IAAI,CAAC,kBAAkB,CAAC,KAAK,GAAG,MAAK;AACnC,YAAA,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC;AAC3B,QAAA,CAAC;AAED,QAAA,IAAI,CAAC,YAAY,CAAC,gBAAgB,CAAC,gBAAgB,EAAE,IAAI,CAAC,kBAAkB,CAAC,cAAc,CAAC;AAC5F,QAAA,IAAI,CAAC,YAAY,CAAC,gBAAgB,CAAC,YAAY,EAAE,IAAI,CAAC,kBAAkB,CAAC,UAAU,CAAC;AACpF,QAAA,IAAI,CAAC,YAAY,CAAC,gBAAgB,CAAC,OAAO,EAAE,IAAI,CAAC,kBAAkB,CAAC,KAAK,CAAC;IAC5E;IAEA,cAAc,GAAA;QACZ,IAAI,CAAC,IAAI,CAAC,YAAY;YAAE;AAExB,QAAA,IAAI,IAAI,CAAC,SAAS,EAAE,EAAE;AACpB,YAAA,IAAI,CAAC,YAAY,CAAC,KAAK,EAAE;AACzB,YAAA,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC;QAC3B;aAAO;AACL,YAAA,IAAI,CAAC,YAAY,CAAC,IAAI,EAAE;AACxB,YAAA,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC;QAC1B;IACF;AAEA,IAAA,MAAM,CAAC,KAAY,EAAA;AACjB,QAAA,MAAM,KAAK,GAAG,KAAK,CAAC,MAAiC;AACrD,QAAA,IAAI,CAAC,KAAK;YAAE;QACZ,MAAM,IAAI,GAAG,UAAU,CAAC,KAAK,CAAC,KAAK,CAAC;QACpC,IAAI,IAAI,CAAC,YAAY,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE;AACrC,YAAA,IAAI,CAAC,YAAY,CAAC,WAAW,GAAG,IAAI;AACpC,YAAA,IAAI,CAAC,gBAAgB,CAAC,GAAG,CAAC,IAAI,CAAC;QACjC;IACF;AAEA,IAAA,eAAe,CAAC,KAAY,EAAA;AAC1B,QAAA,MAAM,MAAM,GAAG,KAAK,CAAC,MAAkC;AACvD,QAAA,IAAI,CAAC,MAAM;YAAE;QACb,MAAM,IAAI,GAAG,UAAU,CAAC,MAAM,CAAC,KAAK,CAAC;QACrC,IAAI,KAAK,CAAC,IAAI,CAAC;YAAE;AACjB,QAAA,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,IAAI,CAAC;AAC3B,QAAA,IAAI,IAAI,CAAC,YAAY,EAAE;AACrB,YAAA,IAAI,CAAC,YAAY,CAAC,YAAY,GAAG,IAAI;QACvC;IACF;AAEA,IAAA,aAAa,CAAC,OAA0B,EAAA;AACtC,QAAA,IAAI,IAAI,CAAC,YAAY,EAAE;YACrB,IAAI,CAAC,YAAY,CAAC,WAAW,GAAG,OAAO,CAAC,SAAS;YACjD,IAAI,CAAC,gBAAgB,CAAC,GAAG,CAAC,OAAO,CAAC,SAAS,CAAC;AAC5C,YAAA,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,EAAE;gBACrB,IAAI,CAAC,cAAc,EAAE;YACvB;QACF;IACF;IAEA,UAAU,CAAC,IAAuB,EAAE,KAAY,EAAA;QAC9C,KAAK,CAAC,eAAe,EAAE;AACvB,QAAA,IAAI,IAAI,CAAC,YAAY,EAAE;YACrB,IAAI,CAAC,YAAY,CAAC,WAAW,GAAG,IAAI,CAAC,KAAK;YAC1C,IAAI,CAAC,gBAAgB,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC;AACrC,YAAA,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,EAAE;gBACrB,IAAI,CAAC,cAAc,EAAE;YACvB;QACF;IACF;AAEA,IAAA,iBAAiB,CAAC,OAAe,EAAA;AAC/B,QAAA,OAAO,UAAU,CAAC,OAAO,CAAC;IAC5B;AAEA,IAAA,eAAe,CAAC,OAA2B,EAAA;QACzC,IAAI,OAAO,KAAK,SAAS;AAAE,YAAA,OAAO,4BAA4B;AAC9D,QAAA,MAAM,MAAM,GAAG;YACb,yBAAyB;YACzB,yBAAyB;YACzB,yBAAyB;YACzB,yBAAyB;SAC1B;QACD,OAAO,MAAM,CAAC,OAAO,GAAG,MAAM,CAAC,MAAM,CAAC;IACxC;IAEQ,mBAAmB,GAAA;AACzB,QAAA,MAAM,IAAI,GAAG,IAAI,CAAC,gBAAgB,EAAE;AACpC,QAAA,MAAM,IAAI,GAAG,IAAI,CAAC,QAAQ,EAAE;QAE5B,MAAM,GAAG,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,IAAI,IAAI,CAAC,CAAC,SAAS,IAAI,IAAI,IAAI,CAAC,CAAC,OAAO,CAAC;QACtE,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,GAAG,EAAE,EAAE,IAAI,IAAI,CAAC;AAEzC,QAAA,IAAI,GAAG,EAAE,KAAK,EAAE;YACd,MAAM,OAAO,GAAG,GAAG,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,KAAK,IAAI,IAAI,CAAC,CAAC,KAAK,IAAI,IAAI,IAAI,CAAC,CAAC,GAAG,CAAC;AAC5E,YAAA,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,OAAO,IAAI,CAAC,GAAG,OAAO,GAAG,IAAI,CAAC;QACzD;aAAO;AACL,YAAA,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,IAAI,CAAC;QAChC;QAEA,IAAI,CAAC,qBAAqB,EAAE;IAC9B;IAEQ,qBAAqB,GAAA;AAC3B,QAAA,MAAM,QAAQ,GAAG,IAAI,CAAC,eAAe,EAAE;AACvC,QAAA,IAAI,CAAC,QAAQ;YAAE;AAEf,QAAA,MAAM,SAAS,GAAG,IAAI,CAAC,UAAU,CAAC,aAAa,CAAC,aAAa,CAAC,6BAA6B,CAAC;QAC5F,MAAM,QAAQ,GAAG,SAAS,EAAE,aAAa,CAAC,CAAA,kBAAA,EAAqB,QAAQ,CAAA,EAAA,CAAI,CAAC;AAE5E,QAAA,IAAI,QAAQ,IAAI,SAAS,EAAE;AACzB,YAAA,MAAM,aAAa,GAAG,SAAS,CAAC,qBAAqB,EAAE;AACvD,YAAA,MAAM,UAAU,GAAG,QAAQ,CAAC,qBAAqB,EAAE;AAEnD,YAAA,IAAI,UAAU,CAAC,GAAG,GAAG,aAAa,CAAC,GAAG,IAAI,UAAU,CAAC,MAAM,GAAG,aAAa,CAAC,MAAM,EAAE;AAClF,gBAAA,QAAQ,CAAC,cAAc,CAAC,EAAE,QAAQ,EAAE,QAAQ,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC;YAClE;QACF;IACF;AAEQ,IAAA,MAAM,cAAc,GAAA;AAC1B,QAAA,IAAI;YACF,MAAM,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,EAAE,EAAE,IAAI,CAAC,KAAK,EAAE,EAAE,IAAI,CAAC,OAAO,EAAE,CAAC;AACrE,YAAA,MAAM,IAAI,CAAC,YAAY,CAAC,YAAY,EAAE;AACtC,YAAA,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,IAAI,CAAC;AAC1B,YAAA,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC;YAExB,MAAM,SAAS,GAAG,IAAI,CAAC,MAAM,CAAC,YAAY,EAAE;YAC5C,IAAI,SAAS,EAAE;AACb,gBAAA,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,SAAS,CAAC;YACrC;QACF;QAAE,OAAO,GAAG,EAAE;YACZ,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,YAAY,KAAK,GAAG,GAAG,GAAG,IAAI,KAAK,CAAC,2BAA2B,CAAC,CAAC;AACpF,YAAA,MAAM,IAAI,CAAC,OAAO,EAAE;QACtB;IACF;AAEQ,IAAA,MAAM,aAAa,GAAA;AACzB,QAAA,MAAM,IAAI,CAAC,YAAY,CAAC,WAAW,EAAE;AACrC,QAAA,IAAI,CAAC,MAAM,CAAC,UAAU,EAAE;AACxB,QAAA,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,KAAK,CAAC;AAC3B,QAAA,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC;IAC1B;AAEQ,IAAA,MAAM,OAAO,GAAA;AACnB,QAAA,MAAM,IAAI,CAAC,YAAY,CAAC,WAAW,EAAE;AACrC,QAAA,IAAI,CAAC,MAAM,CAAC,UAAU,EAAE;AACxB,QAAA,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,KAAK,CAAC;AAC3B,QAAA,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC;IAC1B;AAEQ,IAAA,mBAAmB,CAAC,KAAyB,EAAA;QACnD,IAAI,CAAC,KAAK,CAAC,UAAU;YAAE;AAEvB,QAAA,IAAI,KAAK,CAAC,IAAI,KAAK,OAAO,EAAE;AAC1B,YAAA,MAAM,KAAK,GAAoB;AAC7B,gBAAA,EAAE,EAAE,EAAE,IAAI,CAAC,cAAc;gBACzB,IAAI,EAAE,KAAK,CAAC,UAAU;gBACtB,OAAO,EAAE,KAAK,CAAC,OAAO;AACtB,gBAAA,OAAO,EAAE,IAAI;gBACb,SAAS,EAAE,KAAK,CAAC,KAAK;gBACtB,OAAO,EAAE,KAAK,CAAC,GAAG;aACnB;AAED,YAAA,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,OAAO,KAAK,CAAC,GAAG,OAAO,EAAE,KAAK,CAAC,CAAC;AACrD,YAAA,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,EAAE,CAAC;AACxB,YAAA,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,SAAS,CAAC;QACpC;AAAO,aAAA,IAAI,KAAK,CAAC,IAAI,KAAK,SAAS,EAAE;YACnC,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,KAAK,CAAC,UAAU,CAAC;YACtC,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC;QACxC;IACF;wGArfW,iBAAiB,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA;AAAjB,IAAA,OAAA,IAAA,GAAA,EAAA,CAAA,oBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,SAAA,EAAA,IAAA,EAAA,iBAAiB,EAAA,YAAA,EAAA,IAAA,EAAA,QAAA,EAAA,4BAAA,EAAA,MAAA,EAAA,EAAA,KAAA,EAAA,EAAA,iBAAA,EAAA,OAAA,EAAA,UAAA,EAAA,OAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,KAAA,EAAA,EAAA,iBAAA,EAAA,OAAA,EAAA,UAAA,EAAA,OAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,aAAA,EAAA,EAAA,iBAAA,EAAA,eAAA,EAAA,UAAA,EAAA,eAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,OAAA,EAAA,EAAA,iBAAA,EAAA,SAAA,EAAA,UAAA,EAAA,SAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,SAAA,EAAA,EAAA,iBAAA,EAAA,WAAA,EAAA,UAAA,EAAA,WAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,SAAA,EAAA,EAAA,iBAAA,EAAA,WAAA,EAAA,UAAA,EAAA,WAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,SAAA,EAAA,EAAA,iBAAA,EAAA,WAAA,EAAA,UAAA,EAAA,WAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,MAAA,EAAA,EAAA,iBAAA,EAAA,QAAA,EAAA,UAAA,EAAA,QAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,EAAA,OAAA,EAAA,EAAA,cAAA,EAAA,gBAAA,EAAA,eAAA,EAAA,iBAAA,EAAA,KAAA,EAAA,OAAA,EAAA,iBAAA,EAAA,mBAAA,EAAA,eAAA,EAAA,iBAAA,EAAA,EAAA,IAAA,EAAA,EAAA,SAAA,EAAA,EAAA,gBAAA,EAAA,yBAAA,EAAA,EAAA,EAAA,QAAA,EAAA,EAAA,EAAA,QAAA,EAhrBlB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAyOT,EAAA,CAAA,EAAA,QAAA,EAAA,IAAA,EAAA,MAAA,EAAA,CAAA,wsOAAA,CAAA,EAAA,YAAA,EAAA,CAAA,EAAA,IAAA,EAAA,UAAA,EAAA,IAAA,EA1OS,YAAY,EAAA,CAAA,EAAA,CAAA;;4FAirBX,iBAAiB,EAAA,UAAA,EAAA,CAAA;kBAprB7B,SAAS;AACE,YAAA,IAAA,EAAA,CAAA,EAAA,QAAA,EAAA,4BAA4B,cAC1B,IAAI,EAAA,OAAA,EACP,CAAC,YAAY,CAAC,EAAA,QAAA,EACb;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAyOT,EAAA,CAAA,EAAA,MAAA,EAAA,CAAA,wsOAAA,CAAA,EAAA;wDAgdD,eAAe,EAAA,CAAA;sBADd,YAAY;uBAAC,gBAAgB,EAAE,CAAC,QAAQ,CAAC;;;AC3tB5C;;AAEG;;;;"}
package/index.d.ts ADDED
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Generated bundle index. Do not edit.
3
+ */
4
+ /// <amd-module name="@medc-com-br/ngx-jaimes-scribe" />
5
+ export * from './public-api';
@@ -0,0 +1,97 @@
1
+ import { OnDestroy } from '@angular/core';
2
+ import { ConnectionState } from '../../services/scribe-socket.service';
3
+ import type { TemplateOption, GeneratedDocument, SessionPlaybackData, TranscriptSegment, TranscriptionWord } from '@medc-com-br/jaimes-shared';
4
+ import * as i0 from "@angular/core";
5
+ interface TranscriptEntry {
6
+ id: number;
7
+ text: string;
8
+ speaker?: number;
9
+ isFinal: boolean;
10
+ startTime?: number;
11
+ endTime?: number;
12
+ }
13
+ export type RecorderMode = 'recording' | 'playback';
14
+ interface SpeakerGroup {
15
+ speaker?: number;
16
+ entries: TranscriptEntry[];
17
+ }
18
+ export declare class RecorderComponent implements OnDestroy {
19
+ private audioCapture;
20
+ private socket;
21
+ private elementRef;
22
+ private subscriptions;
23
+ private entryIdCounter;
24
+ private generateAbortController;
25
+ onDocumentClick(event: MouseEvent): void;
26
+ wsUrl: import("@angular/core").InputSignal<string>;
27
+ token: import("@angular/core").InputSignal<string>;
28
+ speakerLabels: import("@angular/core").InputSignal<Record<number, string>>;
29
+ premium: import("@angular/core").InputSignal<boolean>;
30
+ templates: import("@angular/core").InputSignal<TemplateOption[]>;
31
+ lambdaUrl: import("@angular/core").InputSignal<string>;
32
+ sessionId: import("@angular/core").InputSignal<string>;
33
+ apiUrl: import("@angular/core").InputSignal<string>;
34
+ sessionStarted: import("@angular/core").OutputEmitterRef<string>;
35
+ sessionFinished: import("@angular/core").OutputEmitterRef<{
36
+ transcript: string;
37
+ entries: TranscriptEntry[];
38
+ }>;
39
+ error: import("@angular/core").OutputEmitterRef<Error>;
40
+ documentGenerated: import("@angular/core").OutputEmitterRef<GeneratedDocument>;
41
+ generationError: import("@angular/core").OutputEmitterRef<Error>;
42
+ isRecording: import("@angular/core").WritableSignal<boolean>;
43
+ isPaused: import("@angular/core").WritableSignal<boolean>;
44
+ audioLevel: import("@angular/core").WritableSignal<number>;
45
+ connectionState: import("@angular/core").WritableSignal<ConnectionState>;
46
+ entries: import("@angular/core").WritableSignal<TranscriptEntry[]>;
47
+ partialText: import("@angular/core").WritableSignal<string>;
48
+ currentSpeaker: import("@angular/core").WritableSignal<number>;
49
+ showTemplateMenu: import("@angular/core").WritableSignal<boolean>;
50
+ isGenerating: import("@angular/core").WritableSignal<boolean>;
51
+ lastSessionId: import("@angular/core").WritableSignal<string>;
52
+ isPlaying: import("@angular/core").WritableSignal<boolean>;
53
+ isLoadingSession: import("@angular/core").WritableSignal<boolean>;
54
+ audioCurrentTime: import("@angular/core").WritableSignal<number>;
55
+ audioDuration: import("@angular/core").WritableSignal<number>;
56
+ playbackRate: import("@angular/core").WritableSignal<number>;
57
+ sessionData: import("@angular/core").WritableSignal<SessionPlaybackData>;
58
+ activeSegmentId: import("@angular/core").WritableSignal<string>;
59
+ activeWordIndex: import("@angular/core").WritableSignal<number>;
60
+ private audioElement;
61
+ private audioBlobUrl;
62
+ mode: import("@angular/core").Signal<RecorderMode>;
63
+ segments: import("@angular/core").Signal<TranscriptSegment[]>;
64
+ hasFinishedSession: import("@angular/core").Signal<boolean>;
65
+ speakerGroups: import("@angular/core").Signal<SpeakerGroup[]>;
66
+ constructor();
67
+ ngOnDestroy(): void;
68
+ private audioEventHandlers;
69
+ private cleanupPlayback;
70
+ getSpeakerLabel(speaker: number): string;
71
+ shouldShowSpeakerLabel(segmentIndex: number): boolean;
72
+ getMicButtonLabel(): string;
73
+ toggleRecording(): Promise<void>;
74
+ pauseRecording(): void;
75
+ resumeRecording(): void;
76
+ finishSession(): Promise<void>;
77
+ toggleTemplateMenu(): void;
78
+ selectTemplate(template: TemplateOption): Promise<void>;
79
+ loadSession(): Promise<void>;
80
+ private loadAudio;
81
+ togglePlayback(): void;
82
+ seekTo(event: Event): void;
83
+ setPlaybackRate(event: Event): void;
84
+ seekToSegment(segment: TranscriptSegment): void;
85
+ seekToWord(word: TranscriptionWord, event: Event): void;
86
+ formatTimeDisplay(seconds: number): string;
87
+ getSpeakerColor(speaker: number | undefined): string;
88
+ private updateActiveSegment;
89
+ private scrollToActiveSegment;
90
+ private startRecording;
91
+ private stopRecording;
92
+ private cleanup;
93
+ private handleTranscription;
94
+ static ɵfac: i0.ɵɵFactoryDeclaration<RecorderComponent, never>;
95
+ static ɵcmp: i0.ɵɵComponentDeclaration<RecorderComponent, "ngx-jaimes-scribe-recorder", never, { "wsUrl": { "alias": "wsUrl"; "required": false; "isSignal": true; }; "token": { "alias": "token"; "required": false; "isSignal": true; }; "speakerLabels": { "alias": "speakerLabels"; "required": false; "isSignal": true; }; "premium": { "alias": "premium"; "required": false; "isSignal": true; }; "templates": { "alias": "templates"; "required": false; "isSignal": true; }; "lambdaUrl": { "alias": "lambdaUrl"; "required": false; "isSignal": true; }; "sessionId": { "alias": "sessionId"; "required": false; "isSignal": true; }; "apiUrl": { "alias": "apiUrl"; "required": false; "isSignal": true; }; }, { "sessionStarted": "sessionStarted"; "sessionFinished": "sessionFinished"; "error": "error"; "documentGenerated": "documentGenerated"; "generationError": "generationError"; }, never, never, true, never>;
96
+ }
97
+ export {};
@@ -0,0 +1,44 @@
1
+ import { InjectionToken } from '@angular/core';
2
+ import { Observable } from 'rxjs';
3
+ import * as i0 from "@angular/core";
4
+ export interface AudioCaptureConfig {
5
+ workletUrl: string;
6
+ levelUpdateInterval: number;
7
+ }
8
+ export declare const AUDIO_CAPTURE_CONFIG: InjectionToken<AudioCaptureConfig>;
9
+ export interface AudioChunk {
10
+ data: ArrayBuffer;
11
+ isSilence: boolean;
12
+ }
13
+ export declare class AudioCaptureService {
14
+ private config;
15
+ private ngZone;
16
+ private vadService;
17
+ private audioContext;
18
+ private workletNode;
19
+ private analyserNode;
20
+ private source;
21
+ private stream;
22
+ private workletRegistered;
23
+ private levelInterval;
24
+ private paused;
25
+ private audioChunkSubject;
26
+ private audioLevelSubject;
27
+ private errorSubject;
28
+ audioChunk$: Observable<AudioChunk>;
29
+ audioLevel$: Observable<number>;
30
+ error$: Observable<Error>;
31
+ constructor();
32
+ startCapture(): Promise<void>;
33
+ stopCapture(): Promise<void>;
34
+ pauseCapture(): void;
35
+ resumeCapture(): void;
36
+ isCapturing(): boolean;
37
+ isPaused(): boolean;
38
+ getSampleRate(): number | null;
39
+ private startLevelMonitoring;
40
+ private stopLevelMonitoring;
41
+ private getAudioLevel;
42
+ static ɵfac: i0.ɵɵFactoryDeclaration<AudioCaptureService, never>;
43
+ static ɵprov: i0.ɵɵInjectableDeclaration<AudioCaptureService>;
44
+ }
@@ -0,0 +1,51 @@
1
+ import { InjectionToken } from '@angular/core';
2
+ import { Observable } from 'rxjs';
3
+ import type { TranscriptionEvent } from '@medc-com-br/jaimes-shared';
4
+ import * as i0 from "@angular/core";
5
+ export type ConnectionState = 'disconnected' | 'connecting' | 'connected' | 'reconnecting';
6
+ export interface ScribeSocketConfig {
7
+ reconnectAttempts: number;
8
+ reconnectBaseDelay: number;
9
+ chunkBufferInterval: number;
10
+ }
11
+ export declare const SCRIBE_SOCKET_CONFIG: InjectionToken<ScribeSocketConfig>;
12
+ export declare class ScribeSocketService {
13
+ private config;
14
+ private ngZone;
15
+ private ws;
16
+ private wsUrl;
17
+ private token;
18
+ private premium;
19
+ private reconnectAttempt;
20
+ private reconnectTimeout;
21
+ private intentionalClose;
22
+ private chunkBuffer;
23
+ private sendInterval;
24
+ private keepaliveInterval;
25
+ private currentlyInSilence;
26
+ private connectionStateSubject;
27
+ private transcriptionSubject;
28
+ private errorSubject;
29
+ private sessionIdSubject;
30
+ connectionState$: Observable<ConnectionState>;
31
+ transcription$: Observable<TranscriptionEvent>;
32
+ error$: Observable<Error>;
33
+ sessionId$: Observable<string | null>;
34
+ constructor();
35
+ connect(url: string, token: string, premium?: boolean): Promise<void>;
36
+ disconnect(): void;
37
+ sendAudioChunk(chunk: ArrayBuffer, isSilence: boolean): void;
38
+ private startKeepaliveInterval;
39
+ private stopKeepaliveInterval;
40
+ private arrayBufferToBase64;
41
+ isConnected(): boolean;
42
+ getSessionId(): string | null;
43
+ private createConnection;
44
+ private attemptReconnect;
45
+ private clearReconnectTimeout;
46
+ private startBuffering;
47
+ private flushAndStopBuffering;
48
+ private stopBuffering;
49
+ static ɵfac: i0.ɵɵFactoryDeclaration<ScribeSocketService, never>;
50
+ static ɵprov: i0.ɵɵInjectableDeclaration<ScribeSocketService>;
51
+ }
@@ -0,0 +1,21 @@
1
+ import { BehaviorSubject } from 'rxjs';
2
+ import * as i0 from "@angular/core";
3
+ export type VadState = 'idle' | 'speech' | 'silence_pending' | 'silence';
4
+ export interface VadConfig {
5
+ speechThreshold: number;
6
+ silenceThreshold: number;
7
+ silenceDebounceMs: number;
8
+ }
9
+ export declare class VadService {
10
+ private state;
11
+ private silenceStartTime;
12
+ private config;
13
+ readonly state$: BehaviorSubject<VadState>;
14
+ analyzeLevel(level: number): {
15
+ isSilence: boolean;
16
+ };
17
+ reset(): void;
18
+ getState(): VadState;
19
+ static ɵfac: i0.ɵɵFactoryDeclaration<VadService, never>;
20
+ static ɵprov: i0.ɵɵInjectableDeclaration<VadService>;
21
+ }
@@ -0,0 +1,3 @@
1
+ export declare function pcmToWav(pcmData: ArrayBuffer, sampleRate?: number): ArrayBuffer;
2
+ export declare function createAudioBlobUrl(wavData: ArrayBuffer): string;
3
+ export declare function formatTime(seconds: number): string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@medc-com-br/ngx-jaimes-scribe",
3
- "version": "0.1.2",
3
+ "version": "0.1.4",
4
4
  "description": "Angular library for real-time medical transcription",
5
5
  "repository": {
6
6
  "type": "git",
@@ -13,7 +13,13 @@
13
13
  },
14
14
  "license": "UNLICENSED",
15
15
  "author": "MEDC Sistemas de Saúde",
16
- "keywords": ["angular", "transcription", "medical", "speech-to-text", "healthcare"],
16
+ "keywords": [
17
+ "angular",
18
+ "transcription",
19
+ "medical",
20
+ "speech-to-text",
21
+ "healthcare"
22
+ ],
17
23
  "peerDependencies": {
18
24
  "@angular/common": "^19.0.0",
19
25
  "@angular/core": "^19.0.0",
@@ -23,19 +29,16 @@
23
29
  "dependencies": {
24
30
  "tslib": "^2.8.0"
25
31
  },
26
- "devDependencies": {
27
- "@angular/compiler": "^19.0.0",
28
- "@angular/compiler-cli": "^19.0.0",
29
- "@angular/common": "^19.0.0",
30
- "@angular/core": "^19.0.0",
31
- "ng-packagr": "^19.0.0",
32
- "rxjs": "^7.8.0",
33
- "typescript": "~5.6.0",
34
- "zone.js": "~0.15.0"
35
- },
36
- "scripts": {
37
- "build": "ng-packagr -p ng-package.json",
38
- "clean": "rm -rf dist"
39
- },
40
- "sideEffects": false
41
- }
32
+ "sideEffects": false,
33
+ "module": "fesm2022/medc-com-br-ngx-jaimes-scribe.mjs",
34
+ "typings": "index.d.ts",
35
+ "exports": {
36
+ "./package.json": {
37
+ "default": "./package.json"
38
+ },
39
+ ".": {
40
+ "types": "./index.d.ts",
41
+ "default": "./fesm2022/medc-com-br-ngx-jaimes-scribe.mjs"
42
+ }
43
+ }
44
+ }
@@ -1,28 +0,0 @@
1
-
2
- > @jaimes/ngx-jaimes-scribe@0.0.1 build /Users/thiago/git/medc/jaimes/libs/ngx-jaimes-scribe
3
- > ng-packagr -p ng-package.json
4
-
5
- Building Angular Package
6
-
7
- ------------------------------------------------------------------------------
8
- Building entry point '@jaimes/ngx-jaimes-scribe'
9
- ------------------------------------------------------------------------------
10
- - Compiling with Angular sources in Ivy partial compilation mode.
11
- ✔ Compiling with Angular sources in Ivy partial compilation mode.
12
- ✔ Generating FESM bundles
13
- - Copying assets
14
- ✔ Copying assets
15
- - Writing package manifest
16
- ℹ Removing scripts section in package.json as it's considered a potential security vulnerability.
17
- ℹ Removing devDependencies section in package.json.
18
- ✔ Writing package manifest
19
- ✔ Built @jaimes/ngx-jaimes-scribe
20
-
21
- ------------------------------------------------------------------------------
22
- Built Angular Package
23
- - from: /Users/thiago/git/medc/jaimes/libs/ngx-jaimes-scribe
24
- - to: /Users/thiago/git/medc/jaimes/dist/ngx-jaimes-scribe
25
- ------------------------------------------------------------------------------
26
-
27
- Build at: 2026-01-22T17:21:18.786Z - Time: 3961ms
28
-
package/ng-package.json DELETED
@@ -1,10 +0,0 @@
1
- {
2
- "$schema": "../../node_modules/ng-packagr/ng-package.schema.json",
3
- "dest": "../../dist/ngx-jaimes-scribe",
4
- "lib": {
5
- "entryFile": "src/public-api.ts"
6
- },
7
- "assets": [
8
- "src/assets"
9
- ]
10
- }