Spaces:
				
			
			
	
			
			
		Paused
		
	
	
	
			
			
	
	
	
	
		
		
		Paused
		
	| import { Injectable } from '@angular/core'; | |
| import { HttpClient, HttpHeaders } from '@angular/common/http'; | |
| import { Observable, throwError } from 'rxjs'; | |
| import { catchError, tap } from 'rxjs/operators'; | |
| import { Router } from '@angular/router'; | |
| import { AuthService } from './auth.service'; | |
| // Interfaces | |
| export interface API { | |
| name: string; | |
| url: string; | |
| method: string; | |
| headers?: any; | |
| body_template?: any; | |
| timeout_seconds: number; | |
| retry?: { | |
| retry_count: number; | |
| backoff_seconds: number; | |
| strategy: string; | |
| }; | |
| auth?: { | |
| enabled: boolean; | |
| token_endpoint?: string; | |
| response_token_path?: string; | |
| token_request_body?: any; | |
| token_refresh_endpoint?: string; | |
| token_refresh_body?: any; | |
| }; | |
| response_prompt?: string; | |
| response_mappings?: ResponseMapping[]; // Yeni alan | |
| deleted?: boolean; | |
| last_update_date?: string; | |
| last_update_user?: string; | |
| } | |
| export interface LocalizedCaption { | |
| locale_code: string; | |
| caption: string; | |
| } | |
| export interface LocalizedExample { | |
| locale_code: string; | |
| example: string; | |
| } | |
| export interface ResponseMapping { | |
| variable_name: string; | |
| type: 'str' | 'int' | 'float' | 'bool' | 'date'; | |
| json_path: string; | |
| caption: LocalizedCaption[]; | |
| } | |
| export interface IntentParameter { | |
| name: string; | |
| caption: LocalizedCaption[]; | |
| type: 'str' | 'int' | 'float' | 'bool' | 'date'; | |
| required: boolean; | |
| variable_name: string; | |
| extraction_prompt?: string; | |
| validation_regex?: string; | |
| invalid_prompt?: string; | |
| type_error_prompt?: string; | |
| } | |
| export interface Intent { | |
| name: string; | |
| caption: string; | |
| detection_prompt: string; | |
| examples: LocalizedExample[]; | |
| parameters: IntentParameter[]; | |
| action: string; | |
| fallback_timeout_prompt?: string; | |
| fallback_error_prompt?: string; | |
| } | |
| export interface GenerationConfig { | |
| max_new_tokens: number; | |
| temperature: number; | |
| top_p: number; | |
| top_k?: number; | |
| repetition_penalty?: number; | |
| do_sample?: boolean; | |
| num_beams?: number; | |
| length_penalty?: number; | |
| early_stopping?: boolean; | |
| } | |
| export interface LLMConfig { | |
| repo_id: string; | |
| generation_config: GenerationConfig; // any yerine GenerationConfig | |
| use_fine_tune: boolean; | |
| fine_tune_zip: string; | |
| } | |
| export interface Version { | |
| no: number; | |
| caption?: string; | |
| description?: string; | |
| published: boolean; | |
| general_prompt?: string; | |
| llm: LLMConfig; // inline yerine LLMConfig | |
| intents: Intent[]; | |
| parameters: any[]; | |
| last_update_date?: string; | |
| } | |
| export interface Project { | |
| id: number; | |
| name: string; | |
| caption: string; | |
| enabled: boolean; | |
| icon?: string; | |
| description?: string; | |
| default_locale?: string; | |
| supported_locales?: string[]; | |
| timezone?: string; | |
| region?: string; | |
| versions: Version[]; | |
| last_update_date?: string; | |
| deleted?: boolean; | |
| created_date?: string; | |
| created_by?: string; | |
| last_update_user?: string; | |
| } | |
| export interface ParameterCollectionConfig { | |
| max_params_per_question: number; | |
| smart_grouping: boolean; | |
| retry_unanswered: boolean; | |
| collection_prompt: string; | |
| } | |
| export interface ProviderConfig { | |
| type: 'llm' | 'tts' | 'stt'; | |
| name: string; | |
| display_name: string; | |
| requires_endpoint: boolean; | |
| requires_api_key: boolean; | |
| requires_repo_info?: boolean; | |
| description: string; | |
| } | |
| export interface ProviderSettings { | |
| name: string; | |
| api_key?: string; | |
| endpoint?: string | null; | |
| settings?: any; | |
| } | |
| export interface Environment { | |
| llm_provider: ProviderSettings; | |
| tts_provider: ProviderSettings; | |
| stt_provider: ProviderSettings; | |
| providers: ProviderConfig[]; | |
| parameter_collection_config?: ParameterCollectionConfig; | |
| } | |
| export interface STTSettings { | |
| speech_timeout_ms: number; | |
| noise_reduction_level: number; | |
| vad_sensitivity: number; | |
| language: string; | |
| model: string; | |
| use_enhanced: boolean; | |
| enable_punctuation: boolean; | |
| interim_results: boolean; | |
| } | |
| export interface TTSSettings { | |
| use_ssml: boolean; | |
| } | |
| ({ | |
| providedIn: 'root' | |
| }) | |
| export class ApiService { | |
| private apiUrl = '/api'; | |
| private adminUrl = `${this.apiUrl}/admin`; | |
| constructor( | |
| private http: HttpClient, | |
| private router: Router, | |
| private authService: AuthService | |
| ) {} | |
| // ===================== Utils ===================== | |
| private normalizeTimestamp(timestamp: string | null | undefined): string { | |
| if (!timestamp) return ''; | |
| // Remove milliseconds for comparison | |
| if (timestamp.includes('.') && timestamp.endsWith('Z')) { | |
| return timestamp.split('.')[0] + 'Z'; | |
| } | |
| return timestamp; | |
| } | |
| // ===================== Auth ===================== | |
| login(username: string, password: string): Observable<any> { | |
| return this.http.post(`${this.adminUrl}/login`, { username, password }).pipe( | |
| tap((response: any) => { | |
| this.authService.setToken(response.token); | |
| this.authService.setUsername(response.username); | |
| }) | |
| ); | |
| } | |
| logout(): void { | |
| this.authService.logout(); | |
| } | |
| private getAuthHeaders(): HttpHeaders { | |
| try { | |
| const token = this.authService.getToken(); | |
| if (!token) { | |
| console.warn('No auth token available'); | |
| // Token yoksa boş header dön veya login'e yönlendir | |
| return new HttpHeaders({ | |
| 'Content-Type': 'application/json' | |
| }); | |
| } | |
| return new HttpHeaders({ | |
| 'Authorization': `Bearer ${token}`, | |
| 'Content-Type': 'application/json' | |
| }); | |
| } catch (error) { | |
| console.error('Error getting auth headers:', error); | |
| return new HttpHeaders({ | |
| 'Content-Type': 'application/json' | |
| }); | |
| } | |
| } | |
| // ===================== User ===================== | |
| changePassword(currentPassword: string, newPassword: string): Observable<any> { | |
| return this.http.post( | |
| `${this.adminUrl}/change-password`, | |
| { current_password: currentPassword, new_password: newPassword }, | |
| { headers: this.getAuthHeaders() } | |
| ).pipe( | |
| catchError(this.handleError) | |
| ); | |
| } | |
| // ===================== Environment ===================== | |
| getEnvironment(): Observable<any> { | |
| return this.http.get(`${this.adminUrl}/environment`, { | |
| headers: this.getAuthHeaders() | |
| }); | |
| } | |
| updateEnvironment(data: Environment): Observable<any> { | |
| return this.http.put(`${this.adminUrl}/environment`, data, { | |
| headers: this.getAuthHeaders() | |
| }).pipe( | |
| catchError(this.handleError) | |
| ); | |
| } | |
| // ===================== Projects ===================== | |
| getProjects(includeDeleted = false): Observable<Project[]> { | |
| return this.http.get<Project[]>(`${this.adminUrl}/projects`, { | |
| headers: this.getAuthHeaders(), | |
| params: { include_deleted: includeDeleted.toString() } | |
| }).pipe( | |
| catchError(error => { | |
| // Race condition check | |
| if (error.status === 409) { | |
| console.warn('Race condition detected in getProjects:', error.error); | |
| // Component'ler bu hatayı handle edecek | |
| } | |
| return throwError(() => error); | |
| }) | |
| ); | |
| } | |
| getProject(id: number): Observable<Project> { | |
| return this.http.get<Project>(`${this.adminUrl}/projects/${id}`); | |
| } | |
| createProject(data: any): Observable<any> { | |
| console.log('createProject called with data:', data); | |
| let headers; | |
| try { | |
| headers = this.getAuthHeaders(); | |
| console.log('Headers obtained successfully'); | |
| } catch (error) { | |
| console.error('Error getting headers:', error); | |
| return throwError(() => ({ message: 'Authentication error' })); | |
| } | |
| console.log('Making POST request to:', `${this.adminUrl}/projects`); | |
| return this.http.post(`${this.adminUrl}/projects`, data, { headers }).pipe( | |
| tap(response => { | |
| console.log('Project creation successful:', response); | |
| }), | |
| catchError(error => { | |
| console.error('Project creation failed:', error); | |
| return this.handleError(error); | |
| }) | |
| ); | |
| } | |
| updateProject(id: number, data: any): Observable<any> { | |
| // Normalize the timestamp before sending | |
| if (data.last_update_date) { | |
| data.last_update_date = this.normalizeTimestamp(data.last_update_date); | |
| } | |
| return this.http.put(`${this.adminUrl}/projects/${id}`, data, { | |
| headers: this.getAuthHeaders() | |
| }).pipe( | |
| catchError(error => { | |
| // Race condition özel handling | |
| if (error.status === 409) { | |
| const details = error.error?.details || {}; | |
| return throwError(() => ({ | |
| ...error, | |
| raceCondition: true, | |
| lastUpdateUser: details.last_update_user, | |
| lastUpdateDate: details.last_update_date | |
| })); | |
| } | |
| return throwError(() => error); | |
| }) | |
| ); | |
| } | |
| deleteProject(id: number): Observable<any> { | |
| return this.http.delete(`${this.adminUrl}/projects/${id}`, { | |
| headers: this.getAuthHeaders() | |
| }).pipe( | |
| catchError(this.handleError) | |
| ); | |
| } | |
| toggleProject(id: number): Observable<any> { | |
| return this.http.patch(`${this.adminUrl}/projects/${id}/toggle`, {}, { | |
| headers: this.getAuthHeaders() | |
| }).pipe( | |
| catchError(this.handleError) | |
| ); | |
| } | |
| exportProject(id: number): Observable<any> { | |
| return this.http.get(`${this.adminUrl}/projects/${id}/export`, { | |
| headers: this.getAuthHeaders() | |
| }).pipe( | |
| catchError(this.handleError) | |
| ); | |
| } | |
| importProject(data: any): Observable<any> { | |
| return this.http.post(`${this.adminUrl}/projects/import`, data, { | |
| headers: this.getAuthHeaders() | |
| }).pipe( | |
| catchError(this.handleError) | |
| ); | |
| } | |
| // ===================== Versions ===================== | |
| createVersion(projectId: number, data: any): Observable<any> { | |
| return this.http.post(`${this.adminUrl}/projects/${projectId}/versions`, data, { | |
| headers: this.getAuthHeaders() | |
| }).pipe( | |
| catchError(error => { | |
| if (error.status === 409) { | |
| console.warn('Race condition in createVersion:', error.error); | |
| } | |
| return throwError(() => error); | |
| }) | |
| ); | |
| } | |
| updateVersion(projectId: number, versionNo: number, data: any, force: boolean = false): Observable<any> { | |
| // Normalize the timestamp before sending | |
| if (data.last_update_date) { | |
| data.last_update_date = this.normalizeTimestamp(data.last_update_date); | |
| } | |
| return this.http.put( | |
| `${this.adminUrl}/projects/${projectId}/versions/${versionNo}${force ? '?force=true' : ''}`, | |
| data, | |
| { headers: this.getAuthHeaders() } | |
| ).pipe( | |
| catchError(this.handleError) | |
| ); | |
| } | |
| deleteVersion(projectId: number, versionNo: number): Observable<any> { | |
| return this.http.delete(`${this.adminUrl}/projects/${projectId}/versions/${versionNo}`, { | |
| headers: this.getAuthHeaders() | |
| }).pipe( | |
| catchError(this.handleError) | |
| ); | |
| } | |
| publishVersion(projectId: number, versionNo: number): Observable<any> { | |
| return this.http.post(`${this.adminUrl}/projects/${projectId}/versions/${versionNo}/publish`, {}, { | |
| headers: this.getAuthHeaders() | |
| }).pipe( | |
| catchError(this.handleError) | |
| ); | |
| } | |
| // ===================== APIs ===================== | |
| getAPIs(includeDeleted = false): Observable<API[]> { | |
| return this.http.get<API[]>(`${this.adminUrl}/apis`, { | |
| headers: this.getAuthHeaders(), | |
| params: { include_deleted: includeDeleted.toString() } | |
| }).pipe( | |
| catchError(this.handleError) | |
| ); | |
| } | |
| createAPI(data: any): Observable<any> { | |
| return this.http.post(`${this.adminUrl}/apis`, data, { | |
| headers: this.getAuthHeaders() | |
| }).pipe( | |
| catchError(this.handleError) | |
| ); | |
| } | |
| updateAPI(name: string, data: any): Observable<any> { | |
| // Normalize the timestamp before sending | |
| if (data.last_update_date) { | |
| data.last_update_date = this.normalizeTimestamp(data.last_update_date); | |
| } | |
| return this.http.put(`${this.adminUrl}/apis/${name}`, data, { | |
| headers: this.getAuthHeaders() | |
| }).pipe( | |
| catchError(error => { | |
| if (error.status === 409) { | |
| const details = error.error?.details || {}; | |
| return throwError(() => ({ | |
| ...error, | |
| raceCondition: true, | |
| lastUpdateUser: details.last_update_user, | |
| lastUpdateDate: details.last_update_date | |
| })); | |
| } | |
| return throwError(() => error); | |
| }) | |
| ); | |
| } | |
| deleteAPI(name: string): Observable<any> { | |
| return this.http.delete(`${this.adminUrl}/apis/${name}`, { | |
| headers: this.getAuthHeaders() | |
| }).pipe( | |
| catchError(this.handleError) | |
| ); | |
| } | |
| testAPI(data: any): Observable<any> { | |
| return this.http.post(`${this.adminUrl}/apis/test`, data, { | |
| headers: this.getAuthHeaders() | |
| }).pipe( | |
| catchError(this.handleError) | |
| ); | |
| } | |
| // ===================== Spark Integration ===================== | |
| sparkStartup(projectName: string): Observable<any> { | |
| return this.http.post(`${this.adminUrl}/spark/startup`, | |
| { project_name: projectName }, | |
| { headers: this.getAuthHeaders() } | |
| ).pipe( | |
| catchError(this.handleError) | |
| ); | |
| } | |
| sparkGetProjects(): Observable<any> { | |
| return this.http.get(`${this.adminUrl}/spark/projects`, { | |
| headers: this.getAuthHeaders() | |
| }).pipe( | |
| catchError(this.handleError) | |
| ); | |
| } | |
| sparkEnableProject(projectName: string): Observable<any> { | |
| return this.http.post(`${this.adminUrl}/spark/project/enable`, | |
| { project_name: projectName }, | |
| { headers: this.getAuthHeaders() } | |
| ).pipe( | |
| catchError(this.handleError) | |
| ); | |
| } | |
| sparkDisableProject(projectName: string): Observable<any> { | |
| return this.http.post(`${this.adminUrl}/spark/project/disable`, | |
| { project_name: projectName }, | |
| { headers: this.getAuthHeaders() } | |
| ).pipe( | |
| catchError(this.handleError) | |
| ); | |
| } | |
| sparkDeleteProject(projectName: string): Observable<any> { | |
| return this.http.delete(`${this.adminUrl}/spark/project/${projectName}`, { | |
| headers: this.getAuthHeaders() | |
| }).pipe( | |
| catchError(this.handleError) | |
| ); | |
| } | |
| // ===================== Tests ===================== | |
| runTests(testType: string): Observable<any> { | |
| return this.http.post(`${this.adminUrl}/test/run-all`, { test_type: testType }, { | |
| headers: this.getAuthHeaders() | |
| }).pipe( | |
| catchError(this.handleError) | |
| ); | |
| } | |
| // ===================== Activity Log ===================== | |
| getActivityLog(limit = 50): Observable<any[]> { | |
| return this.http.get<any[]>(`${this.adminUrl}/activity-log`, { | |
| headers: this.getAuthHeaders(), | |
| params: { limit: limit.toString() } | |
| }).pipe( | |
| catchError(this.handleError) | |
| ); | |
| } | |
| // ===================== Validation ===================== | |
| validateRegex(pattern: string, testValue: string): Observable<any> { | |
| return this.http.post(`${this.adminUrl}/validate/regex`, | |
| { pattern, test_value: testValue }, | |
| { headers: this.getAuthHeaders() } | |
| ).pipe( | |
| catchError(this.handleError) | |
| ); | |
| } | |
| // ===================== Chat ===================== | |
| /* 1️⃣ Proje isimleri (combo’yu doldurmak için) */ | |
| getChatProjects() { | |
| return this.http.get<string[]>(`${this.adminUrl}/projects/names`); | |
| } | |
| /* 2️⃣ Oturum başlat */ | |
| startChat(projectName: string, isRealtime: boolean, locale?: string) { | |
| return this.http.post<{ | |
| session_id: string; | |
| answer: string; | |
| }>(`${this.apiUrl}/start_session`, { | |
| project_name: projectName, | |
| is_realtime: isRealtime, | |
| locale: locale || 'tr' | |
| }); | |
| } | |
| /* 3️⃣ Mesaj gönder/al */ | |
| chat(sessionId: string, text: string) { | |
| const headers = new HttpHeaders().set('X-Session-ID', sessionId); | |
| return this.http.post<{ | |
| response: string; | |
| intent?: string; | |
| state: string; | |
| }>( | |
| `${this.apiUrl}/chat`, | |
| { message: text }, | |
| { headers } | |
| ); | |
| } | |
| endSession(sessionId: string): Observable<any> { | |
| return this.http.post(`${this.apiUrl}/end-session`, | |
| { session_id: sessionId }, | |
| { headers: this.getAuthHeaders() } | |
| ); | |
| } | |
| // ===================== TTS ===================== | |
| generateTTS(text: string, voiceId?: string, modelId?: string, outputFormat: string = 'mp3_44100_128'): Observable<Blob> { | |
| const body = { | |
| text, | |
| voice_id: voiceId, | |
| model_id: modelId, | |
| output_format: outputFormat | |
| }; | |
| return this.http.post(`${this.apiUrl}/tts/generate`, body, { | |
| headers: this.getAuthHeaders(), | |
| responseType: 'blob' | |
| }).pipe( | |
| catchError(this.handleError) | |
| ); | |
| } | |
| // ===================== Locale ===================== | |
| getAvailableLocales(): Observable<any> { | |
| return this.http.get(`${this.adminUrl}/locales`, { headers: this.getAuthHeaders() }); | |
| } | |
| getLocaleDetails(code: string): Observable<any> { | |
| return this.http.get(`${this.adminUrl}/locales/${code}`, { headers: this.getAuthHeaders() }); | |
| } | |
| // ===================== Error Handler ===================== | |
| private handleError(error: any) { | |
| console.error('API Error:', error); | |
| if (error.status === 401) { | |
| // Token expired or invalid | |
| this.authService.logout(); | |
| } else if (error.status === 409) { | |
| // Race condition error | |
| const message = error.error?.detail || 'Resource was modified by another user'; | |
| return throwError(() => ({ | |
| ...error, | |
| userMessage: message, | |
| requiresReload: true | |
| })); | |
| } | |
| // Ensure error object has proper structure | |
| const errorResponse = { | |
| status: error.status, | |
| error: error.error || { detail: error.message || 'Unknown error' }, | |
| message: error.error?.detail || error.error?.message || error.message || 'Unknown error' | |
| }; | |
| return throwError(() => errorResponse); | |
| } | |
| } | 

