brief-rags-bench/static/js/services/api-client.js

258 lines
7.0 KiB
JavaScript
Raw Normal View History

2025-12-25 09:39:58 +01:00
/**
* Brief Bench API Client
*
* Взаимодействие с FastAPI backend.
*/
import { saveToken, loadToken, clearToken } from '../data/storage.js'
import { API_CONFIG } from '../config.js'
/**
* BriefBenchAPI class - handles all API communication with FastAPI backend
*/
class BriefBenchAPI {
constructor() {
this.baseURL = API_CONFIG.baseURL
}
// ============================================
// Internal Helpers
// ============================================
_getToken() {
return loadToken()
}
_setToken(token) {
saveToken(token)
}
_clearToken() {
clearToken()
}
_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<object>}
*/
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<object>}
*/
async getSession(sessionId) {
return await this._request(`/analysis/sessions/${sessionId}`, {
method: 'GET',
headers: this._getHeaders()
})
}
/**
* Удалить сессию
* @param {string} sessionId - ID сессии
* @returns {Promise<null>}
*/
async deleteSession(sessionId) {
return await this._request(`/analysis/sessions/${sessionId}`, {
method: 'DELETE',
headers: this._getHeaders()
})
}
}
// Export singleton instance as default export
export default new BriefBenchAPI()
// Export class for testing purposes
export { BriefBenchAPI }