/** * Brief Bench API Client * Взаимодействие с FastAPI backend */ class BriefBenchAPI { constructor() { this.baseURL = '/api/v1' } // ============================================ // Internal Helpers // ============================================ _getToken() { return localStorage.getItem('access_token') } _setToken(token) { localStorage.setItem('access_token', token) } _clearToken() { localStorage.removeItem('access_token') } _getHeaders(includeAuth = true) { const headers = { 'Content-Type': 'application/json' } if (includeAuth) { const token = this._getToken() if (token) { headers['Authorization'] = `Bearer ${token}` } } return headers } async _handleResponse(response) { // Handle 401 Unauthorized if (response.status === 401) { this._clearToken() throw new Error('Сессия истекла. Пожалуйста, войдите снова.') } // Handle 502 Bad Gateway (RAG backend error) if (response.status === 502) { throw new Error('RAG backend недоступен или вернул ошибку') } // Handle other errors if (!response.ok) { const errorData = await response.json().catch(() => ({})) throw new Error(errorData.detail || `HTTP ${response.status}: ${response.statusText}`) } // Handle 204 No Content if (response.status === 204) { return null } return await response.json() } async _request(endpoint, options = {}) { const url = `${this.baseURL}${endpoint}` try { const response = await fetch(url, options) return await this._handleResponse(response) } catch (error) { console.error(`API request failed: ${endpoint}`, error) throw error } } // ============================================ // Auth API // ============================================ /** * Авторизация с 8-значным логином * @param {string} login - 8-значный логин * @returns {Promise<{access_token: string, user: object}>} */ async login(login) { const response = await this._request(`/auth/login?login=${login}`, { method: 'POST', headers: this._getHeaders(false) }) // Сохранить токен this._setToken(response.access_token) return response } /** * Выход (очистка токена) */ logout() { this._clearToken() window.location.reload() } /** * Проверка авторизации * @returns {boolean} */ isAuthenticated() { return !!this._getToken() } // ============================================ // Settings API // ============================================ /** * Получить настройки пользователя для всех окружений * @returns {Promise<{user_id: string, settings: object, updated_at: string}>} */ async getSettings() { return await this._request('/settings', { method: 'GET', headers: this._getHeaders() }) } /** * Обновить настройки пользователя * @param {object} settings - Объект с настройками для окружений * @returns {Promise<{user_id: string, settings: object, updated_at: string}>} */ async updateSettings(settings) { return await this._request('/settings', { method: 'PATCH', headers: this._getHeaders(), body: JSON.stringify({ settings }) }) } // ============================================ // Query API // ============================================ /** * Отправить batch запрос (Bench mode) * @param {string} environment - Окружение (ift/psi/prod) * @param {Array<{body: string, with_docs: boolean}>} questions - Массив вопросов * @returns {Promise<{request_id: string, timestamp: string, environment: string, response: object}>} */ async benchQuery(environment, questions) { return await this._request('/query/bench', { method: 'POST', headers: this._getHeaders(), body: JSON.stringify({ environment, questions }) }) } /** * Отправить последовательные запросы (Backend mode) * @param {string} environment - Окружение (ift/psi/prod) * @param {Array<{body: string, with_docs: boolean}>} questions - Массив вопросов * @param {boolean} resetSession - Сбрасывать ли сессию после каждого вопроса * @returns {Promise<{request_id: string, timestamp: string, environment: string, response: object}>} */ async backendQuery(environment, questions, resetSession = true) { return await this._request('/query/backend', { method: 'POST', headers: this._getHeaders(), body: JSON.stringify({ environment, questions, reset_session: resetSession }) }) } // ============================================ // Analysis Sessions API // ============================================ /** * Сохранить сессию анализа * @param {object} sessionData - Данные сессии * @returns {Promise} */ async saveSession(sessionData) { return await this._request('/analysis/sessions', { method: 'POST', headers: this._getHeaders(), body: JSON.stringify(sessionData) }) } /** * Получить список сессий * @param {string|null} environment - Фильтр по окружению (опционально) * @param {number} limit - Лимит результатов * @param {number} offset - Смещение для пагинации * @returns {Promise<{sessions: Array, total: number}>} */ async getSessions(environment = null, limit = 50, offset = 0) { const params = new URLSearchParams({ limit, offset }) if (environment) { params.append('environment', environment) } return await this._request(`/analysis/sessions?${params}`, { method: 'GET', headers: this._getHeaders() }) } /** * Получить конкретную сессию * @param {string} sessionId - ID сессии * @returns {Promise} */ async getSession(sessionId) { return await this._request(`/analysis/sessions/${sessionId}`, { method: 'GET', headers: this._getHeaders() }) } /** * Удалить сессию * @param {string} sessionId - ID сессии * @returns {Promise} */ async deleteSession(sessionId) { return await this._request(`/analysis/sessions/${sessionId}`, { method: 'DELETE', headers: this._getHeaders() }) } } // Export API client instance const api = new BriefBenchAPI()