ciyidogan commited on
Commit
5bd660e
·
verified ·
1 Parent(s): 12d1657

Create conversation-manager.service.ts

Browse files
flare-ui/src/app/services/conversation-manager.service.ts ADDED
@@ -0,0 +1,210 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { Injectable } from '@angular/core';
2
+ import { Subject, Observable, timer } from 'rxjs';
3
+ import { retry, tap } from 'rxjs/operators';
4
+
5
+ export interface WebSocketMessage {
6
+ type: string;
7
+ [key: string]: any;
8
+ }
9
+
10
+ export interface TranscriptionResult {
11
+ text: string;
12
+ is_final: boolean;
13
+ confidence: number;
14
+ }
15
+
16
+ export interface StateChangeMessage {
17
+ from: string;
18
+ to: string;
19
+ }
20
+
21
+ @Injectable({
22
+ providedIn: 'root'
23
+ })
24
+ export class WebSocketService {
25
+ private socket: WebSocket | null = null;
26
+ private url: string = '';
27
+ private reconnectAttempts = 0;
28
+ private maxReconnectAttempts = 5;
29
+ private reconnectDelay = 1000;
30
+
31
+ // Subjects for different message types
32
+ private messageSubject = new Subject<WebSocketMessage>();
33
+ private transcriptionSubject = new Subject<TranscriptionResult>();
34
+ private stateChangeSubject = new Subject<StateChangeMessage>();
35
+ private errorSubject = new Subject<string>();
36
+ private connectionSubject = new Subject<boolean>();
37
+
38
+ // Public observables
39
+ public message$ = this.messageSubject.asObservable();
40
+ public transcription$ = this.transcriptionSubject.asObservable();
41
+ public stateChange$ = this.stateChangeSubject.asObservable();
42
+ public error$ = this.errorSubject.asObservable();
43
+ public connection$ = this.connectionSubject.asObservable();
44
+
45
+ constructor() {}
46
+
47
+ connect(sessionId: string): Promise<void> {
48
+ return new Promise((resolve, reject) => {
49
+ try {
50
+ // Construct WebSocket URL
51
+ const protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:';
52
+ const host = window.location.host;
53
+ this.url = `${protocol}//${host}/ws/conversation/${sessionId}`;
54
+
55
+ console.log(`🔌 Connecting to WebSocket: ${this.url}`);
56
+
57
+ this.socket = new WebSocket(this.url);
58
+
59
+ this.socket.onopen = () => {
60
+ console.log('✅ WebSocket connected');
61
+ this.reconnectAttempts = 0;
62
+ this.connectionSubject.next(true);
63
+
64
+ // Start keep-alive ping
65
+ this.startKeepAlive();
66
+
67
+ resolve();
68
+ };
69
+
70
+ this.socket.onmessage = (event) => {
71
+ try {
72
+ const message: WebSocketMessage = JSON.parse(event.data);
73
+ this.handleMessage(message);
74
+ } catch (error) {
75
+ console.error('Failed to parse WebSocket message:', error);
76
+ }
77
+ };
78
+
79
+ this.socket.onerror = (error) => {
80
+ console.error('❌ WebSocket error:', error);
81
+ this.errorSubject.next('WebSocket bağlantı hatası');
82
+ reject(error);
83
+ };
84
+
85
+ this.socket.onclose = () => {
86
+ console.log('🔌 WebSocket disconnected');
87
+ this.connectionSubject.next(false);
88
+ this.stopKeepAlive();
89
+
90
+ // Attempt reconnection
91
+ if (this.reconnectAttempts < this.maxReconnectAttempts) {
92
+ this.attemptReconnect(sessionId);
93
+ }
94
+ };
95
+
96
+ } catch (error) {
97
+ console.error('Failed to create WebSocket:', error);
98
+ reject(error);
99
+ }
100
+ });
101
+ }
102
+
103
+ disconnect(): void {
104
+ this.stopKeepAlive();
105
+
106
+ if (this.socket) {
107
+ this.socket.close();
108
+ this.socket = null;
109
+ }
110
+
111
+ this.connectionSubject.next(false);
112
+ }
113
+
114
+ send(message: WebSocketMessage): void {
115
+ if (this.socket && this.socket.readyState === WebSocket.OPEN) {
116
+ this.socket.send(JSON.stringify(message));
117
+ } else {
118
+ console.warn('WebSocket is not connected');
119
+ this.errorSubject.next('WebSocket bağlantısı yok');
120
+ }
121
+ }
122
+
123
+ sendAudioChunk(audioData: string): void {
124
+ this.send({
125
+ type: 'audio_chunk',
126
+ data: audioData,
127
+ timestamp: Date.now()
128
+ });
129
+ }
130
+
131
+ sendControl(action: string, config?: any): void {
132
+ this.send({
133
+ type: 'control',
134
+ action: action,
135
+ config: config
136
+ });
137
+ }
138
+
139
+ private handleMessage(message: WebSocketMessage): void {
140
+ // Emit to general message stream
141
+ this.messageSubject.next(message);
142
+
143
+ // Handle specific message types
144
+ switch (message.type) {
145
+ case 'transcription':
146
+ this.transcriptionSubject.next({
147
+ text: message.text,
148
+ is_final: message.is_final,
149
+ confidence: message.confidence
150
+ });
151
+ break;
152
+
153
+ case 'state_change':
154
+ this.stateChangeSubject.next({
155
+ from: message.from,
156
+ to: message.to
157
+ });
158
+ break;
159
+
160
+ case 'error':
161
+ this.errorSubject.next(message.message);
162
+ break;
163
+
164
+ case 'tts_audio':
165
+ // Handle TTS audio chunks
166
+ this.messageSubject.next(message);
167
+ break;
168
+
169
+ case 'assistant_response':
170
+ // Handle assistant text response
171
+ this.messageSubject.next(message);
172
+ break;
173
+ }
174
+ }
175
+
176
+ private attemptReconnect(sessionId: string): void {
177
+ this.reconnectAttempts++;
178
+ const delay = this.reconnectDelay * Math.pow(2, this.reconnectAttempts - 1);
179
+
180
+ console.log(`🔄 Attempting reconnection ${this.reconnectAttempts}/${this.maxReconnectAttempts} in ${delay}ms`);
181
+
182
+ setTimeout(() => {
183
+ this.connect(sessionId).catch(error => {
184
+ console.error('Reconnection failed:', error);
185
+ });
186
+ }, delay);
187
+ }
188
+
189
+ // Keep-alive mechanism
190
+ private keepAliveInterval: any;
191
+
192
+ private startKeepAlive(): void {
193
+ this.keepAliveInterval = setInterval(() => {
194
+ if (this.socket && this.socket.readyState === WebSocket.OPEN) {
195
+ this.send({ type: 'ping' });
196
+ }
197
+ }, 30000); // Ping every 30 seconds
198
+ }
199
+
200
+ private stopKeepAlive(): void {
201
+ if (this.keepAliveInterval) {
202
+ clearInterval(this.keepAliveInterval);
203
+ this.keepAliveInterval = null;
204
+ }
205
+ }
206
+
207
+ isConnected(): boolean {
208
+ return this.socket !== null && this.socket.readyState === WebSocket.OPEN;
209
+ }
210
+ }