ciyidogan commited on
Commit
e5e4952
·
verified ·
1 Parent(s): e12fd54

Update flare-ui/src/app/components/chat/realtime-chat.component.ts

Browse files
flare-ui/src/app/components/chat/realtime-chat.component.ts CHANGED
@@ -27,287 +27,8 @@ import { AudioStreamService } from '../../services/audio-stream.service';
27
  MatChipsModule,
28
  MatSnackBarModule
29
  ],
30
- template: `
31
- <mat-card class="realtime-chat-container">
32
- <mat-card-header>
33
- <mat-icon mat-card-avatar>voice_chat</mat-icon>
34
- <mat-card-title>Real-time Conversation</mat-card-title>
35
- <mat-card-subtitle>
36
- <mat-chip-listbox>
37
- <mat-chip [class.active]="currentState === state"
38
- *ngFor="let state of conversationStates">
39
- {{ getStateLabel(state) }}
40
- </mat-chip>
41
- </mat-chip-listbox>
42
- </mat-card-subtitle>
43
- <button mat-icon-button class="close-button" (click)="closeDialog()">
44
- <mat-icon>close</mat-icon>
45
- </button>
46
- </mat-card-header>
47
-
48
- <mat-divider></mat-divider>
49
-
50
- <mat-card-content>
51
- <!-- Error State -->
52
- <div class="error-banner" *ngIf="error">
53
- <mat-icon>error_outline</mat-icon>
54
- <span>{{ error }}</span>
55
- <button mat-icon-button (click)="retryConnection()">
56
- <mat-icon>refresh</mat-icon>
57
- </button>
58
- </div>
59
-
60
- <!-- Transcription Display -->
61
- <div class="transcription-area" *ngIf="currentTranscription">
62
- <div class="transcription-label">Dinleniyor...</div>
63
- <div class="transcription-text">{{ currentTranscription }}</div>
64
- </div>
65
-
66
- <!-- Chat Messages -->
67
- <div class="chat-messages" #scrollContainer>
68
- <div *ngFor="let msg of messages; trackBy: trackByIndex"
69
- [class]="'message ' + msg.role">
70
- <mat-icon class="message-icon">
71
- {{ msg.role === 'user' ? 'person' : 'smart_toy' }}
72
- </mat-icon>
73
- <div class="message-content">
74
- <div class="message-text">{{ msg.text }}</div>
75
- <div class="message-time">{{ msg.timestamp | date:'HH:mm:ss' }}</div>
76
- <button *ngIf="msg.audioUrl"
77
- mat-icon-button
78
- (click)="playAudio(msg.audioUrl)"
79
- class="audio-button"
80
- [disabled]="isPlayingAudio">
81
- <mat-icon>{{ isPlayingAudio ? 'stop' : 'volume_up' }}</mat-icon>
82
- </button>
83
- </div>
84
- </div>
85
-
86
- <!-- Empty State -->
87
- <div class="empty-state" *ngIf="messages.length === 0 && !isConversationActive">
88
- <mat-icon>mic_off</mat-icon>
89
- <p>Konuşmaya başlamak için aşağıdaki butona tıklayın</p>
90
- </div>
91
- </div>
92
-
93
- <!-- Audio Visualizer -->
94
- <canvas #audioVisualizer
95
- class="audio-visualizer"
96
- width="600"
97
- height="100"
98
- [class.active]="isRecording">
99
- </canvas>
100
- </mat-card-content>
101
-
102
- <mat-card-actions>
103
- <button mat-raised-button
104
- color="primary"
105
- (click)="toggleConversation()"
106
- [disabled]="!sessionId || loading">
107
- @if (loading) {
108
- <mat-spinner diameter="20"></mat-spinner>
109
- } @else {
110
- <mat-icon>{{ isConversationActive ? 'stop' : 'mic' }}</mat-icon>
111
- {{ isConversationActive ? 'Konuşmayı Bitir' : 'Konuşmaya Başla' }}
112
- }
113
- </button>
114
-
115
- <button mat-button
116
- (click)="clearChat()"
117
- [disabled]="messages.length === 0">
118
- <mat-icon>clear</mat-icon>
119
- Temizle
120
- </button>
121
-
122
- <button mat-button
123
- (click)="performBargeIn()"
124
- [disabled]="!isConversationActive || currentState === 'idle' || currentState === 'listening'">
125
- <mat-icon>pan_tool</mat-icon>
126
- Kesme (Barge-in)
127
- </button>
128
- </mat-card-actions>
129
- </mat-card>
130
- `,
131
- styles: [`
132
- .realtime-chat-container {
133
- max-width: 800px;
134
- margin: 20px auto;
135
- height: 80vh;
136
- display: flex;
137
- flex-direction: column;
138
- position: relative;
139
- }
140
-
141
- mat-card-header {
142
- position: relative;
143
-
144
- .close-button {
145
- position: absolute;
146
- top: 8px;
147
- right: 8px;
148
- }
149
- }
150
-
151
- .error-banner {
152
- background-color: #ffebee;
153
- color: #c62828;
154
- padding: 12px;
155
- border-radius: 4px;
156
- display: flex;
157
- align-items: center;
158
- gap: 8px;
159
- margin-bottom: 16px;
160
-
161
- mat-icon {
162
- font-size: 20px;
163
- width: 20px;
164
- height: 20px;
165
- }
166
-
167
- span {
168
- flex: 1;
169
- }
170
- }
171
-
172
- .transcription-area {
173
- background: #f5f5f5;
174
- padding: 16px;
175
- border-radius: 8px;
176
- margin-bottom: 16px;
177
- min-height: 60px;
178
- animation: pulse 2s infinite;
179
- }
180
-
181
- @keyframes pulse {
182
- 0% { opacity: 1; }
183
- 50% { opacity: 0.7; }
184
- 100% { opacity: 1; }
185
- }
186
-
187
- .transcription-label {
188
- font-size: 12px;
189
- color: #666;
190
- margin-bottom: 4px;
191
- }
192
-
193
- .transcription-text {
194
- font-size: 16px;
195
- color: #333;
196
- min-height: 24px;
197
- }
198
-
199
- .chat-messages {
200
- flex: 1;
201
- overflow-y: auto;
202
- padding: 16px;
203
- background: #fafafa;
204
- border-radius: 8px;
205
- min-height: 200px;
206
- max-height: 400px;
207
- }
208
-
209
- .message {
210
- display: flex;
211
- align-items: flex-start;
212
- margin-bottom: 16px;
213
- animation: slideIn 0.3s ease-out;
214
- }
215
-
216
- @keyframes slideIn {
217
- from {
218
- opacity: 0;
219
- transform: translateY(10px);
220
- }
221
- to {
222
- opacity: 1;
223
- transform: translateY(0);
224
- }
225
- }
226
-
227
- .message.user {
228
- flex-direction: row-reverse;
229
- }
230
-
231
- .message-icon {
232
- margin: 0 8px;
233
- color: #666;
234
- }
235
-
236
- .message-content {
237
- max-width: 70%;
238
- background: white;
239
- padding: 12px 16px;
240
- border-radius: 12px;
241
- box-shadow: 0 1px 2px rgba(0,0,0,0.1);
242
- position: relative;
243
- }
244
-
245
- .message.user .message-content {
246
- background: #3f51b5;
247
- color: white;
248
- }
249
-
250
- .message-text {
251
- margin-bottom: 4px;
252
- }
253
-
254
- .message-time {
255
- font-size: 11px;
256
- opacity: 0.7;
257
- }
258
-
259
- .audio-button {
260
- margin-top: 8px;
261
- }
262
-
263
- .empty-state {
264
- text-align: center;
265
- padding: 60px 20px;
266
- color: #999;
267
-
268
- mat-icon {
269
- font-size: 48px;
270
- width: 48px;
271
- height: 48px;
272
- margin-bottom: 16px;
273
- }
274
- }
275
-
276
- .audio-visualizer {
277
- width: 100%;
278
- height: 100px;
279
- background: #333;
280
- border-radius: 8px;
281
- margin-top: 16px;
282
- opacity: 0.3;
283
- transition: opacity 0.3s;
284
- }
285
-
286
- .audio-visualizer.active {
287
- opacity: 1;
288
- }
289
-
290
- mat-chip {
291
- font-size: 12px;
292
- }
293
-
294
- mat-chip.active {
295
- background-color: #3f51b5 !important;
296
- color: white !important;
297
- }
298
-
299
- mat-card-actions {
300
- padding: 16px;
301
- display: flex;
302
- gap: 16px;
303
- justify-content: flex-start;
304
-
305
- mat-spinner {
306
- display: inline-block;
307
- margin-right: 8px;
308
- }
309
- }
310
- `]
311
  })
312
  export class RealtimeChatComponent implements OnInit, OnDestroy, AfterViewChecked {
313
  @ViewChild('scrollContainer') private scrollContainer!: ElementRef;
 
27
  MatChipsModule,
28
  MatSnackBarModule
29
  ],
30
+ templateUrl: './realtime-chat.component.html',
31
+ styleUrls: ['./realtime-chat.component.scss']
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
32
  })
33
  export class RealtimeChatComponent implements OnInit, OnDestroy, AfterViewChecked {
34
  @ViewChild('scrollContainer') private scrollContainer!: ElementRef;