ciyidogan commited on
Commit
beae7f4
·
verified ·
1 Parent(s): 219d0f0

Update flare-ui/src/app/components/environment/environment.component.ts

Browse files
flare-ui/src/app/components/environment/environment.component.ts CHANGED
@@ -1,493 +1,541 @@
1
- import { Component, inject, OnInit } from '@angular/core';
2
- import { CommonModule } from '@angular/common';
3
- import { FormsModule } from '@angular/forms';
4
- import { MatCardModule } from '@angular/material/card';
5
- import { MatFormFieldModule } from '@angular/material/form-field';
6
- import { MatInputModule } from '@angular/material/input';
7
- import { MatSelectModule } from '@angular/material/select';
8
- import { MatButtonModule } from '@angular/material/button';
9
- import { MatIconModule } from '@angular/material/icon';
10
- import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
11
- import { MatSnackBar, MatSnackBarModule } from '@angular/material/snack-bar';
12
- import { MatExpansionModule } from '@angular/material/expansion';
13
- import { ApiService, Environment } from '../../services/api.service';
14
- import { EnvironmentService } from '../../services/environment.service';
15
-
16
- @Component({
17
- selector: 'app-environment',
18
- standalone: true,
19
- imports: [
20
- CommonModule,
21
- FormsModule,
22
- MatCardModule,
23
- MatFormFieldModule,
24
- MatInputModule,
25
- MatSelectModule,
26
- MatButtonModule,
27
- MatIconModule,
28
- MatProgressSpinnerModule,
29
- MatSnackBarModule,
30
- MatExpansionModule
31
- ],
32
- template: `
33
- <div class="environment-container">
34
- <mat-card>
35
- <mat-card-header>
36
- <mat-card-title>
37
- <mat-icon>settings</mat-icon>
38
- Environment Configuration
39
- </mat-card-title>
40
- </mat-card-header>
41
-
42
- <mat-card-content>
43
- @if (isGPTMode()) {
44
- <mat-card class="info-card">
45
- <mat-card-content>
46
- <mat-icon>info</mat-icon>
47
- <div>
48
- <strong>{{ environment.work_mode === 'gpt4o' ? 'GPT-4o' : 'GPT-4o Mini' }} Mode</strong>
49
- <p>This mode uses OpenAI's API which has usage-based pricing.</p>
50
- <p>Approximate cost: {{ environment.work_mode === 'gpt4o' ? '$0.01-0.03' : '$0.001-0.003' }} per conversation turn.</p>
51
- </div>
52
- </mat-card-content>
53
- </mat-card>
54
- }
55
-
56
- <form (ngSubmit)="save()" #envForm="ngForm">
57
- <mat-form-field appearance="outline" class="full-width">
58
- <mat-label>Work Mode</mat-label>
59
- <mat-select
60
- name="workMode"
61
- [(ngModel)]="environment.work_mode"
62
- (selectionChange)="onWorkModeChange()"
63
- required
64
- [disabled]="loading"
65
- >
66
- <mat-option value="hfcloud">HF Cloud</mat-option>
67
- <mat-option value="cloud">Cloud</mat-option>
68
- <mat-option value="on-premise">On-Premise</mat-option>
69
- <mat-option value="gpt4o">GPT-4o</mat-option>
70
- <mat-option value="gpt4o-mini">GPT-4o Mini</mat-option>
71
- </mat-select>
72
- <mat-icon matPrefix>cloud</mat-icon>
73
- </mat-form-field>
74
-
75
- <mat-form-field appearance="outline" class="full-width">
76
- <mat-label>{{ getTokenLabel() }}</mat-label>
77
- <input
78
- matInput
79
- type="password"
80
- name="cloudToken"
81
- [(ngModel)]="environment.cloud_token"
82
- [disabled]="loading || environment.work_mode === 'on-premise'"
83
- [placeholder]="getTokenPlaceholder()"
84
- >
85
- <mat-icon matPrefix>vpn_key</mat-icon>
86
- <mat-hint>{{ isGPTMode() ? 'Required for OpenAI API access' : 'Required for HF Cloud and Cloud modes' }}</mat-hint>
87
- </mat-form-field>
88
-
89
- <mat-form-field appearance="outline" class="full-width">
90
- <mat-label>Spark Endpoint</mat-label>
91
- <input
92
- matInput
93
- type="url"
94
- name="sparkEndpoint"
95
- [(ngModel)]="environment.spark_endpoint"
96
- [required]="!isGPTMode()"
97
- [disabled]="loading || isGPTMode()"
98
- placeholder="https://spark-service.example.com"
99
- >
100
- <mat-icon matPrefix>link</mat-icon>
101
- <button
102
- mat-icon-button
103
- matSuffix
104
- type="button"
105
- (click)="testConnection()"
106
- [disabled]="loading || !environment.spark_endpoint || isGPTMode()"
107
- matTooltip="Test Connection"
108
- >
109
- <mat-icon>wifi_tethering</mat-icon>
110
- </button>
111
- @if (isGPTMode()) {
112
- <mat-hint>Not required for GPT mode</mat-hint>
113
- }
114
- </mat-form-field>
115
-
116
- <!-- TTS Configuration -->
117
- <div class="engine-row">
118
- <mat-form-field appearance="outline" class="engine-field">
119
- <mat-label>TTS Engine</mat-label>
120
- <mat-select
121
- name="ttsEngine"
122
- [(ngModel)]="environment.tts_engine"
123
- (selectionChange)="onTTSEngineChange()"
124
- [disabled]="loading"
125
- >
126
- <mat-option value="no_tts">No TTS</mat-option>
127
- <mat-option value="elevenlabs">ElevenLabs</mat-option>
128
- <mat-option value="blaze">Blaze (Coming Soon)</mat-option>
129
- </mat-select>
130
- <mat-icon matPrefix>record_voice_over</mat-icon>
131
- </mat-form-field>
132
-
133
- <mat-form-field appearance="outline" class="api-key-field">
134
- <mat-label>TTS API Key</mat-label>
135
- <input
136
- matInput
137
- type="password"
138
- name="ttsApiKey"
139
- [(ngModel)]="environment.tts_engine_api_key"
140
- [disabled]="loading || environment.tts_engine === 'no_tts'"
141
- [required]="environment.tts_engine !== 'no_tts'"
142
- placeholder="Enter TTS API key"
143
- >
144
- <mat-icon matPrefix>key</mat-icon>
145
- </mat-form-field>
146
- </div>
147
-
148
- <!-- STT Configuration -->
149
- <div class="engine-row">
150
- <mat-form-field appearance="outline" class="engine-field">
151
- <mat-label>STT Engine</mat-label>
152
- <mat-select
153
- name="sttEngine"
154
- [(ngModel)]="environment.stt_engine"
155
- (selectionChange)="onSTTEngineChange()"
156
- [disabled]="loading"
157
- >
158
- <mat-option value="no_stt">No STT</mat-option>
159
- <mat-option value="elevenlabs">ElevenLabs</mat-option>
160
- <mat-option value="flicker">Flicker (Coming Soon)</mat-option>
161
- </mat-select>
162
- <mat-icon matPrefix>mic</mat-icon>
163
- </mat-form-field>
164
-
165
- <mat-form-field appearance="outline" class="api-key-field">
166
- <mat-label>STT API Key</mat-label>
167
- <input
168
- matInput
169
- type="password"
170
- name="sttApiKey"
171
- [(ngModel)]="environment.stt_engine_api_key"
172
- [disabled]="loading || environment.stt_engine === 'no_stt'"
173
- [required]="environment.stt_engine !== 'no_stt'"
174
- placeholder="Enter STT API key"
175
- >
176
- <mat-icon matPrefix>key</mat-icon>
177
- </mat-form-field>
178
- </div>
179
-
180
- <mat-expansion-panel class="prompt-panel">
181
- <mat-expansion-panel-header>
182
- <mat-panel-title>
183
- <mat-icon>psychology</mat-icon>
184
- Internal System Prompt
185
- </mat-panel-title>
186
- <mat-panel-description>
187
- Advanced configuration for LLM
188
- </mat-panel-description>
189
- </mat-expansion-panel-header>
190
-
191
- <mat-form-field appearance="outline" class="full-width">
192
- <mat-label>Internal Prompt</mat-label>
193
- <textarea
194
- matInput
195
- name="internalPrompt"
196
- [(ngModel)]="environment.internal_prompt"
197
- [disabled]="loading"
198
- rows="10"
199
- placeholder="Enter internal system prompt..."
200
- ></textarea>
201
- <mat-hint>This prompt will be prepended to all project prompts</mat-hint>
202
- </mat-form-field>
203
- </mat-expansion-panel>
204
-
205
- <div class="form-actions">
206
- <button
207
- mat-raised-button
208
- color="primary"
209
- type="submit"
210
- [disabled]="loading || !envForm.valid || saving"
211
- >
212
- @if (saving) {
213
- <mat-spinner diameter="20"></mat-spinner>
214
- Saving...
215
- } @else {
216
- <mat-icon>save</mat-icon>
217
- Save
218
- }
219
- </button>
220
-
221
- <button
222
- mat-raised-button
223
- type="button"
224
- (click)="reloadFromSpark()"
225
- [disabled]="loading || isGPTMode()"
226
- >
227
- <mat-icon>refresh</mat-icon>
228
- Reload from Spark
229
- </button>
230
- </div>
231
- </form>
232
- </mat-card-content>
233
- </mat-card>
234
- </div>
235
- `,
236
- styles: [`
237
- .environment-container {
238
- max-width: 800px;
239
- margin: 0 auto;
240
- }
241
-
242
- mat-card-header {
243
- margin-bottom: 24px;
244
-
245
- mat-card-title {
246
- display: flex;
247
- align-items: center;
248
- gap: 8px;
249
- font-size: 24px;
250
-
251
- mat-icon {
252
- font-size: 28px;
253
- width: 28px;
254
- height: 28px;
255
- }
256
- }
257
- }
258
-
259
- .info-card {
260
- margin-bottom: 20px;
261
- background-color: #e3f2fd;
262
-
263
- mat-card-content {
264
- display: flex;
265
- gap: 16px;
266
- align-items: flex-start;
267
-
268
- mat-icon {
269
- color: #1976d2;
270
- margin-top: 4px;
271
- }
272
-
273
- p {
274
- margin: 4px 0;
275
- font-size: 14px;
276
- }
277
- }
278
- }
279
-
280
- .full-width {
281
- width: 100%;
282
- margin-bottom: 20px;
283
- }
284
-
285
- .engine-row {
286
- display: flex;
287
- gap: 16px;
288
- align-items: flex-start;
289
- margin-bottom: 20px;
290
-
291
- .engine-field {
292
- flex: 1;
293
- }
294
-
295
- .api-key-field {
296
- flex: 1.5;
297
- }
298
- }
299
-
300
- .prompt-panel {
301
- margin-bottom: 20px;
302
-
303
- mat-expansion-panel-header {
304
- mat-panel-title {
305
- display: flex;
306
- align-items: center;
307
- gap: 8px;
308
-
309
- mat-icon {
310
- color: #666;
311
- }
312
- }
313
- }
314
- }
315
-
316
- .form-actions {
317
- display: flex;
318
- gap: 16px;
319
- margin-top: 24px;
320
- padding-top: 24px;
321
- border-top: 1px solid #e0e0e0;
322
-
323
- button {
324
-
325
- mat-spinner {
326
- margin-right: 8px;
327
- vertical-align: middle; // Spinner'ı hizalamak için ekleyin
328
- }
329
-
330
- mat-icon {
331
- vertical-align: middle; // Icon'u hizalamak için ekleyin
332
- margin-right: 4px; // Icon ile text arasına boşluk
333
- }
334
- }
335
- }
336
-
337
- ::ng-deep {
338
- .mat-mdc-form-field-icon-prefix {
339
- padding-right: 12px;
340
- }
341
-
342
- .mat-mdc-progress-spinner {
343
- --mdc-circular-progress-active-indicator-color: white;
344
- }
345
-
346
- .mat-expansion-panel-body {
347
- padding: 16px 0 !important;
348
- }
349
- }
350
- `]
351
- })
352
- export class EnvironmentComponent implements OnInit {
353
- private apiService = inject(ApiService);
354
- private snackBar = inject(MatSnackBar);
355
- private environmentService = inject(EnvironmentService);
356
-
357
- environment: Environment = {
358
- work_mode: 'hfcloud',
359
- cloud_token: '',
360
- spark_endpoint: '',
361
- internal_prompt: '',
362
- tts_engine: 'no_tts',
363
- tts_engine_api_key: '',
364
- stt_engine: 'no_stt',
365
- stt_engine_api_key: ''
366
- };
367
-
368
- loading = true;
369
- saving = false;
370
-
371
- ngOnInit() {
372
- this.loadEnvironment();
373
- }
374
-
375
- loadEnvironment() {
376
- this.loading = true;
377
- this.apiService.getEnvironment().subscribe({
378
- next: (env) => {
379
- this.environment = env;
380
- this.loading = false;
381
- },
382
- error: (err) => {
383
- this.snackBar.open('Failed to load environment configuration', 'Close', {
384
- duration: 5000,
385
- panelClass: 'error-snackbar'
386
- });
387
- this.loading = false;
388
- }
389
- });
390
- }
391
-
392
- getTokenLabel(): string {
393
- switch(this.environment.work_mode) {
394
- case 'gpt4o':
395
- case 'gpt4o-mini':
396
- return 'OpenAI API Key';
397
- case 'hfcloud':
398
- case 'cloud':
399
- return 'Cloud Token';
400
- default:
401
- return 'Cloud Token';
402
- }
403
- }
404
-
405
- getTokenPlaceholder(): string {
406
- switch(this.environment.work_mode) {
407
- case 'gpt4o':
408
- case 'gpt4o-mini':
409
- return 'Enter OpenAI API key (sk-...)';
410
- case 'hfcloud':
411
- case 'cloud':
412
- return 'Enter cloud token';
413
- default:
414
- return 'Enter cloud token';
415
- }
416
- }
417
-
418
- isGPTMode(): boolean {
419
- return this.environment.work_mode === 'gpt4o' || this.environment.work_mode === 'gpt4o-mini';
420
- }
421
-
422
- onWorkModeChange() {
423
- if (this.environment.work_mode === 'on-premise') {
424
- this.environment.cloud_token = '';
425
- }
426
- }
427
-
428
- onTTSEngineChange() {
429
- if (this.environment.tts_engine === 'no_tts') {
430
- this.environment.tts_engine_api_key = '';
431
- }
432
- }
433
-
434
- onSTTEngineChange() {
435
- if (this.environment.stt_engine === 'no_stt') {
436
- this.environment.stt_engine_api_key = '';
437
- }
438
- }
439
-
440
- save() {
441
- this.saving = true;
442
-
443
- this.apiService.updateEnvironment(this.environment).subscribe({
444
- next: () => {
445
- // Environment service'i güncelle
446
- this.environmentService.updateEnvironment(this.environment);
447
-
448
- this.snackBar.open('Environment configuration saved successfully', 'Close', {
449
- duration: 3000
450
- });
451
- this.saving = false;
452
- },
453
- error: (err) => {
454
- this.snackBar.open(
455
- err.error?.detail || 'Failed to save configuration',
456
- 'Close',
457
- { duration: 5000, panelClass: 'error-snackbar' }
458
- );
459
- this.saving = false;
460
- }
461
- });
462
- }
463
-
464
- testConnection() {
465
- this.snackBar.open('Testing connection to Spark endpoint...', undefined, {
466
- duration: 2000
467
- });
468
-
469
- // TODO: Implement actual connection test
470
- setTimeout(() => {
471
- this.snackBar.open('Connection successful!', 'Close', {
472
- duration: 3000
473
- });
474
- }, 2000);
475
- }
476
-
477
- reloadFromSpark() {
478
- if (this.isGPTMode()) {
479
- return;
480
- }
481
-
482
- this.snackBar.open('Reloading configuration from Spark...', undefined, {
483
- duration: 2000
484
- });
485
-
486
- setTimeout(() => {
487
- this.loadEnvironment();
488
- this.snackBar.open('Configuration reloaded', 'Close', {
489
- duration: 3000
490
- });
491
- }, 1000);
492
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
493
  }
 
1
+ import { Component, inject, OnInit } from '@angular/core';
2
+ import { CommonModule } from '@angular/common';
3
+ import { FormsModule } from '@angular/forms';
4
+ import { MatCardModule } from '@angular/material/card';
5
+ import { MatFormFieldModule } from '@angular/material/form-field';
6
+ import { MatInputModule } from '@angular/material/input';
7
+ import { MatSelectModule } from '@angular/material/select';
8
+ import { MatButtonModule } from '@angular/material/button';
9
+ import { MatIconModule } from '@angular/material/icon';
10
+ import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
11
+ import { MatSnackBar, MatSnackBarModule } from '@angular/material/snack-bar';
12
+ import { MatExpansionModule } from '@angular/material/expansion';
13
+ import { ApiService, Environment } from '../../services/api.service';
14
+ import { EnvironmentService } from '../../services/environment.service';
15
+
16
+ @Component({
17
+ selector: 'app-environment',
18
+ standalone: true,
19
+ imports: [
20
+ CommonModule,
21
+ FormsModule,
22
+ MatCardModule,
23
+ MatFormFieldModule,
24
+ MatInputModule,
25
+ MatSelectModule,
26
+ MatButtonModule,
27
+ MatIconModule,
28
+ MatProgressSpinnerModule,
29
+ MatSnackBarModule,
30
+ MatExpansionModule
31
+ ],
32
+ template: `
33
+ <div class="environment-container">
34
+ <mat-card>
35
+ <mat-card-header>
36
+ <mat-card-title>
37
+ <mat-icon>settings</mat-icon>
38
+ Environment Configuration
39
+ </mat-card-title>
40
+ </mat-card-header>
41
+
42
+ <mat-card-content>
43
+ @if (isGPTMode()) {
44
+ <mat-card class="info-card">
45
+ <mat-card-content>
46
+ <mat-icon>info</mat-icon>
47
+ <div>
48
+ <strong>{{ environment.work_mode === 'gpt4o' ? 'GPT-4o' : 'GPT-4o Mini' }} Mode</strong>
49
+ <p>This mode uses OpenAI's API which has usage-based pricing.</p>
50
+ <p>Approximate cost: {{ environment.work_mode === 'gpt4o' ? '$0.01-0.03' : '$0.001-0.003' }} per conversation turn.</p>
51
+ </div>
52
+ </mat-card-content>
53
+ </mat-card>
54
+ }
55
+
56
+ <form (ngSubmit)="save()" #envForm="ngForm">
57
+ <mat-form-field appearance="outline" class="full-width">
58
+ <mat-label>Work Mode</mat-label>
59
+ <mat-select
60
+ name="workMode"
61
+ [(ngModel)]="environment.work_mode"
62
+ (selectionChange)="onWorkModeChange()"
63
+ required
64
+ [disabled]="loading"
65
+ >
66
+ <mat-option value="hfcloud">HF Cloud</mat-option>
67
+ <mat-option value="cloud">Cloud</mat-option>
68
+ <mat-option value="on-premise">On-Premise</mat-option>
69
+ <mat-option value="gpt4o">GPT-4o</mat-option>
70
+ <mat-option value="gpt4o-mini">GPT-4o Mini</mat-option>
71
+ </mat-select>
72
+ <mat-icon matPrefix>cloud</mat-icon>
73
+ </mat-form-field>
74
+
75
+ <mat-form-field appearance="outline" class="full-width">
76
+ <mat-label>{{ getTokenLabel() }}</mat-label>
77
+ <input
78
+ matInput
79
+ type="password"
80
+ name="cloudToken"
81
+ [(ngModel)]="environment.cloud_token"
82
+ [disabled]="loading || environment.work_mode === 'on-premise'"
83
+ [placeholder]="getTokenPlaceholder()"
84
+ >
85
+ <mat-icon matPrefix>vpn_key</mat-icon>
86
+ <mat-hint>{{ isGPTMode() ? 'Required for OpenAI API access' : 'Required for HF Cloud and Cloud modes' }}</mat-hint>
87
+ </mat-form-field>
88
+
89
+ <mat-form-field appearance="outline" class="full-width">
90
+ <mat-label>Spark Endpoint</mat-label>
91
+ <input
92
+ matInput
93
+ type="url"
94
+ name="sparkEndpoint"
95
+ [(ngModel)]="environment.spark_endpoint"
96
+ [required]="!isGPTMode()"
97
+ [disabled]="loading || isGPTMode()"
98
+ placeholder="https://spark-service.example.com"
99
+ >
100
+ <mat-icon matPrefix>link</mat-icon>
101
+ <button
102
+ mat-icon-button
103
+ matSuffix
104
+ type="button"
105
+ (click)="testConnection()"
106
+ [disabled]="loading || !environment.spark_endpoint || isGPTMode()"
107
+ matTooltip="Test Connection"
108
+ >
109
+ <mat-icon>wifi_tethering</mat-icon>
110
+ </button>
111
+ @if (isGPTMode()) {
112
+ <mat-hint>Not required for GPT mode</mat-hint>
113
+ }
114
+ </mat-form-field>
115
+
116
+ <!-- TTS Configuration -->
117
+ <div class="engine-row">
118
+ <mat-form-field appearance="outline" class="engine-field">
119
+ <mat-label>TTS Engine</mat-label>
120
+ <mat-select
121
+ name="ttsEngine"
122
+ [(ngModel)]="environment.tts_engine"
123
+ (selectionChange)="onTTSEngineChange()"
124
+ [disabled]="loading"
125
+ >
126
+ <mat-option value="no_tts">No TTS</mat-option>
127
+ <mat-option value="elevenlabs">ElevenLabs</mat-option>
128
+ <mat-option value="blaze">Blaze (Coming Soon)</mat-option>
129
+ </mat-select>
130
+ <mat-icon matPrefix>record_voice_over</mat-icon>
131
+ </mat-form-field>
132
+
133
+ <mat-form-field appearance="outline" class="api-key-field">
134
+ <mat-label>TTS API Key</mat-label>
135
+ <input
136
+ matInput
137
+ type="password"
138
+ name="ttsApiKey"
139
+ [(ngModel)]="environment.tts_engine_api_key"
140
+ [disabled]="loading || environment.tts_engine === 'no_tts'"
141
+ [required]="environment.tts_engine !== 'no_tts'"
142
+ placeholder="Enter TTS API key"
143
+ >
144
+ <mat-icon matPrefix>key</mat-icon>
145
+ </mat-form-field>
146
+ </div>
147
+
148
+ <!-- STT Configuration -->
149
+ <div class="engine-row">
150
+ <mat-form-field appearance="outline" class="engine-field">
151
+ <mat-label>STT Engine</mat-label>
152
+ <mat-select
153
+ name="sttEngine"
154
+ [(ngModel)]="environment.stt_engine"
155
+ (selectionChange)="onSTTEngineChange()"
156
+ [disabled]="loading"
157
+ >
158
+ <mat-option value="no_stt">No STT</mat-option>
159
+ <mat-option value="google">Google Cloud Speech</mat-option>
160
+ <mat-option value="azure">Azure Speech (Coming Soon)</mat-option>
161
+ <mat-option value="amazon">Amazon Transcribe (Coming Soon)</mat-option>
162
+ <mat-option value="flicker">Flicker (Coming Soon)</mat-option>
163
+ </mat-select>
164
+ <mat-icon matPrefix>mic</mat-icon>
165
+ </mat-form-field>
166
+
167
+ <mat-form-field appearance="outline" class="api-key-field">
168
+ <mat-label>{{ getSTTKeyLabel() }}</mat-label>
169
+ <input
170
+ matInput
171
+ type="password"
172
+ name="sttApiKey"
173
+ [(ngModel)]="environment.stt_engine_api_key"
174
+ [disabled]="loading || environment.stt_engine === 'no_stt'"
175
+ [required]="environment.stt_engine !== 'no_stt'"
176
+ [placeholder]="getSTTKeyPlaceholder()"
177
+ >
178
+ <mat-icon matPrefix>key</mat-icon>
179
+ <mat-hint>{{ getSTTKeyHint() }}</mat-hint>
180
+ </mat-form-field>
181
+ </div>
182
+
183
+ <mat-expansion-panel class="prompt-panel">
184
+ <mat-expansion-panel-header>
185
+ <mat-panel-title>
186
+ <mat-icon>psychology</mat-icon>
187
+ Internal System Prompt
188
+ </mat-panel-title>
189
+ <mat-panel-description>
190
+ Advanced configuration for LLM
191
+ </mat-panel-description>
192
+ </mat-expansion-panel-header>
193
+
194
+ <mat-form-field appearance="outline" class="full-width">
195
+ <mat-label>Internal Prompt</mat-label>
196
+ <textarea
197
+ matInput
198
+ name="internalPrompt"
199
+ [(ngModel)]="environment.internal_prompt"
200
+ [disabled]="loading"
201
+ rows="10"
202
+ placeholder="Enter internal system prompt..."
203
+ ></textarea>
204
+ <mat-hint>This prompt will be prepended to all project prompts</mat-hint>
205
+ </mat-form-field>
206
+ </mat-expansion-panel>
207
+
208
+ <div class="form-actions">
209
+ <button
210
+ mat-raised-button
211
+ color="primary"
212
+ type="submit"
213
+ [disabled]="loading || !envForm.valid || saving"
214
+ >
215
+ @if (saving) {
216
+ <mat-spinner diameter="20"></mat-spinner>
217
+ Saving...
218
+ } @else {
219
+ <mat-icon>save</mat-icon>
220
+ Save
221
+ }
222
+ </button>
223
+
224
+ <button
225
+ mat-raised-button
226
+ type="button"
227
+ (click)="reloadFromSpark()"
228
+ [disabled]="loading || isGPTMode()"
229
+ >
230
+ <mat-icon>refresh</mat-icon>
231
+ Reload from Spark
232
+ </button>
233
+ </div>
234
+ </form>
235
+ </mat-card-content>
236
+ </mat-card>
237
+ </div>
238
+ `,
239
+ styles: [`
240
+ .environment-container {
241
+ max-width: 800px;
242
+ margin: 0 auto;
243
+ }
244
+
245
+ mat-card-header {
246
+ margin-bottom: 24px;
247
+
248
+ mat-card-title {
249
+ display: flex;
250
+ align-items: center;
251
+ gap: 8px;
252
+ font-size: 24px;
253
+
254
+ mat-icon {
255
+ font-size: 28px;
256
+ width: 28px;
257
+ height: 28px;
258
+ }
259
+ }
260
+ }
261
+
262
+ .info-card {
263
+ margin-bottom: 20px;
264
+ background-color: #e3f2fd;
265
+
266
+ mat-card-content {
267
+ display: flex;
268
+ gap: 16px;
269
+ align-items: flex-start;
270
+
271
+ mat-icon {
272
+ color: #1976d2;
273
+ margin-top: 4px;
274
+ }
275
+
276
+ p {
277
+ margin: 4px 0;
278
+ font-size: 14px;
279
+ }
280
+ }
281
+ }
282
+
283
+ .full-width {
284
+ width: 100%;
285
+ margin-bottom: 20px;
286
+ }
287
+
288
+ .engine-row {
289
+ display: flex;
290
+ gap: 16px;
291
+ align-items: flex-start;
292
+ margin-bottom: 20px;
293
+
294
+ .engine-field {
295
+ flex: 1;
296
+ }
297
+
298
+ .api-key-field {
299
+ flex: 1.5;
300
+ }
301
+ }
302
+
303
+ .prompt-panel {
304
+ margin-bottom: 20px;
305
+
306
+ mat-expansion-panel-header {
307
+ mat-panel-title {
308
+ display: flex;
309
+ align-items: center;
310
+ gap: 8px;
311
+
312
+ mat-icon {
313
+ color: #666;
314
+ }
315
+ }
316
+ }
317
+ }
318
+
319
+ .form-actions {
320
+ display: flex;
321
+ gap: 16px;
322
+ margin-top: 24px;
323
+ padding-top: 24px;
324
+ border-top: 1px solid #e0e0e0;
325
+
326
+ button {
327
+
328
+ mat-spinner {
329
+ margin-right: 8px;
330
+ vertical-align: middle; // Spinner'ı hizalamak için ekleyin
331
+ }
332
+
333
+ mat-icon {
334
+ vertical-align: middle; // Icon'u hizalamak için ekleyin
335
+ margin-right: 4px; // Icon ile text arasına boşluk
336
+ }
337
+ }
338
+ }
339
+
340
+ ::ng-deep {
341
+ .mat-mdc-form-field-icon-prefix {
342
+ padding-right: 12px;
343
+ }
344
+
345
+ .mat-mdc-progress-spinner {
346
+ --mdc-circular-progress-active-indicator-color: white;
347
+ }
348
+
349
+ .mat-expansion-panel-body {
350
+ padding: 16px 0 !important;
351
+ }
352
+ }
353
+ `]
354
+ })
355
+ export class EnvironmentComponent implements OnInit {
356
+ private apiService = inject(ApiService);
357
+ private snackBar = inject(MatSnackBar);
358
+ private environmentService = inject(EnvironmentService);
359
+
360
+ environment: Environment = {
361
+ work_mode: 'hfcloud',
362
+ cloud_token: '',
363
+ spark_endpoint: '',
364
+ internal_prompt: '',
365
+ tts_engine: 'no_tts',
366
+ tts_engine_api_key: '',
367
+ stt_engine: 'no_stt',
368
+ stt_engine_api_key: ''
369
+ };
370
+
371
+ loading = true;
372
+ saving = false;
373
+
374
+ ngOnInit() {
375
+ this.loadEnvironment();
376
+ }
377
+
378
+ loadEnvironment() {
379
+ this.loading = true;
380
+ this.apiService.getEnvironment().subscribe({
381
+ next: (env) => {
382
+ this.environment = env;
383
+ this.loading = false;
384
+ },
385
+ error: (err) => {
386
+ this.snackBar.open('Failed to load environment configuration', 'Close', {
387
+ duration: 5000,
388
+ panelClass: 'error-snackbar'
389
+ });
390
+ this.loading = false;
391
+ }
392
+ });
393
+ }
394
+
395
+ getTokenLabel(): string {
396
+ switch(this.environment.work_mode) {
397
+ case 'gpt4o':
398
+ case 'gpt4o-mini':
399
+ return 'OpenAI API Key';
400
+ case 'hfcloud':
401
+ case 'cloud':
402
+ return 'Cloud Token';
403
+ default:
404
+ return 'Cloud Token';
405
+ }
406
+ }
407
+
408
+ getTokenPlaceholder(): string {
409
+ switch(this.environment.work_mode) {
410
+ case 'gpt4o':
411
+ case 'gpt4o-mini':
412
+ return 'Enter OpenAI API key (sk-...)';
413
+ case 'hfcloud':
414
+ case 'cloud':
415
+ return 'Enter cloud token';
416
+ default:
417
+ return 'Enter cloud token';
418
+ }
419
+ }
420
+
421
+ isGPTMode(): boolean {
422
+ return this.environment.work_mode === 'gpt4o' || this.environment.work_mode === 'gpt4o-mini';
423
+ }
424
+
425
+ onWorkModeChange() {
426
+ if (this.environment.work_mode === 'on-premise') {
427
+ this.environment.cloud_token = '';
428
+ }
429
+ }
430
+
431
+ onTTSEngineChange() {
432
+ if (this.environment.tts_engine === 'no_tts') {
433
+ this.environment.tts_engine_api_key = '';
434
+ }
435
+ }
436
+
437
+ onSTTEngineChange() {
438
+ if (this.environment.stt_engine === 'no_stt') {
439
+ this.environment.stt_engine_api_key = '';
440
+ }
441
+ }
442
+
443
+ getSTTKeyLabel(): string {
444
+ switch(this.environment.stt_engine) {
445
+ case 'google':
446
+ return 'Google Credentials Path';
447
+ case 'azure':
448
+ return 'Azure Subscription Key';
449
+ case 'amazon':
450
+ return 'AWS Access Key';
451
+ case 'flicker':
452
+ return 'Flicker API Key';
453
+ default:
454
+ return 'STT API Key';
455
+ }
456
+ }
457
+
458
+ getSTTKeyPlaceholder(): string {
459
+ switch(this.environment.stt_engine) {
460
+ case 'google':
461
+ return 'Path to Google credentials JSON file';
462
+ case 'azure':
463
+ return 'Enter Azure subscription key';
464
+ case 'amazon':
465
+ return 'Enter AWS access key';
466
+ case 'flicker':
467
+ return 'Enter Flicker API key';
468
+ default:
469
+ return 'Enter STT API key';
470
+ }
471
+ }
472
+
473
+ getSTTKeyHint(): string {
474
+ switch(this.environment.stt_engine) {
475
+ case 'google':
476
+ return 'Path to service account JSON file for Google Cloud';
477
+ case 'azure':
478
+ return 'Subscription key from Azure portal';
479
+ case 'amazon':
480
+ return 'AWS IAM access key with Transcribe permissions';
481
+ case 'flicker':
482
+ return 'API key from Flicker dashboard';
483
+ default:
484
+ return '';
485
+ }
486
+ }
487
+
488
+ save() {
489
+ this.saving = true;
490
+
491
+ this.apiService.updateEnvironment(this.environment).subscribe({
492
+ next: () => {
493
+ // Environment service'i güncelle
494
+ this.environmentService.updateEnvironment(this.environment);
495
+
496
+ this.snackBar.open('Environment configuration saved successfully', 'Close', {
497
+ duration: 3000
498
+ });
499
+ this.saving = false;
500
+ },
501
+ error: (err) => {
502
+ this.snackBar.open(
503
+ err.error?.detail || 'Failed to save configuration',
504
+ 'Close',
505
+ { duration: 5000, panelClass: 'error-snackbar' }
506
+ );
507
+ this.saving = false;
508
+ }
509
+ });
510
+ }
511
+
512
+ testConnection() {
513
+ this.snackBar.open('Testing connection to Spark endpoint...', undefined, {
514
+ duration: 2000
515
+ });
516
+
517
+ // TODO: Implement actual connection test
518
+ setTimeout(() => {
519
+ this.snackBar.open('Connection successful!', 'Close', {
520
+ duration: 3000
521
+ });
522
+ }, 2000);
523
+ }
524
+
525
+ reloadFromSpark() {
526
+ if (this.isGPTMode()) {
527
+ return;
528
+ }
529
+
530
+ this.snackBar.open('Reloading configuration from Spark...', undefined, {
531
+ duration: 2000
532
+ });
533
+
534
+ setTimeout(() => {
535
+ this.loadEnvironment();
536
+ this.snackBar.open('Configuration reloaded', 'Close', {
537
+ duration: 3000
538
+ });
539
+ }, 1000);
540
+ }
541
  }