258 lines
7.0 KiB
JavaScript
258 lines
7.0 KiB
JavaScript
|
|
/**
|
|||
|
|
* 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 }
|