import type { AxiosRequestConfig } from 'axios' import { api } from '@/lib/api' import { getGroups as getUserGroups } from '@/features/users/api' import type { AddChannelRequest, BatchDeleteParams, BatchSetTagParams, Channel, ChannelBalanceResponse, ChannelTestResponse, CopyChannelParams, CopyChannelResponse, FetchModelsResponse, GetChannelResponse, GetChannelsParams, GetChannelsResponse, MultiKeyManageParams, MultiKeyStatusResponse, SearchChannelsParams, SearchChannelsResponse, TagOperationParams, } from './types' // Extended API config types interface ExtendedApiConfig extends AxiosRequestConfig { skipBusinessError?: boolean disableDuplicate?: boolean } export type CodexOAuthStartResponse = { success: boolean message?: string data?: { authorize_url?: string } } export type CodexOAuthCompleteResponse = { success: boolean message?: string data?: { key?: string account_id?: string email?: string expires_at?: string last_refresh?: string } } export type CodexUsageResponse = { success: boolean message?: string upstream_status?: number data?: Record } export type CodexCredentialRefreshResponse = { success: boolean message?: string data?: { expires_at?: string last_refresh?: string account_id?: string email?: string channel_id?: number channel_type?: number channel_name?: string } } // ============================================================================ // Base Channel CRUD Operations // ============================================================================ /** * Get paginated list of channels */ export async function getChannels( params: GetChannelsParams = {} ): Promise { const res = await api.get('/api/channel', { params }) return res.data } /** * Search channels with filters */ export async function searchChannels( params: SearchChannelsParams ): Promise { const res = await api.get('/api/channel/search', { params }) return res.data } /** * Get single channel by ID */ export async function getChannel(id: number): Promise { const res = await api.get(`/api/channel/${id}`) return res.data } /** * Create new channel(s) * Supports single, batch, and multi-key modes */ export async function createChannel( data: AddChannelRequest ): Promise<{ success: boolean; message?: string }> { const res = await api.post('/api/channel', data) return res.data } /** * Update existing channel */ export async function updateChannel( id: number, data: Partial ): Promise<{ success: boolean; message?: string; data?: Channel }> { const res = await api.put('/api/channel/', { id, ...data }) return res.data } /** * Delete single channel */ export async function deleteChannel( id: number ): Promise<{ success: boolean; message?: string }> { const res = await api.delete(`/api/channel/${id}`) return res.data } /** * Batch delete channels */ export async function batchDeleteChannels( data: BatchDeleteParams ): Promise<{ success: boolean; message?: string; data?: number }> { const res = await api.post('/api/channel/batch', data) return res.data } /** * Batch set tag for channels */ export async function batchSetChannelTag( data: BatchSetTagParams ): Promise<{ success: boolean; message?: string; data?: number }> { const res = await api.post('/api/channel/batch/tag', data) return res.data } // ============================================================================ // Channel Operations // ============================================================================ /** * Test channel connectivity */ export async function testChannel( id: number, params?: { model?: string; endpoint_type?: string; stream?: boolean } ): Promise { const res = await api.get(`/api/channel/test/${id}`, { params }) return res.data } /** * Update channel balance */ export async function updateChannelBalance( id: number ): Promise { const res = await api.get(`/api/channel/update_balance/${id}`) return res.data } /** * Fetch available models from upstream provider */ export async function fetchUpstreamModels( id: number ): Promise { const res = await api.get(`/api/channel/fetch_models/${id}`) return res.data } /** * Copy/clone a channel */ export async function copyChannel( id: number, params: CopyChannelParams = {} ): Promise { const res = await api.post(`/api/channel/copy/${id}`, null, { params }) return res.data } /** * Fix channel abilities */ export async function fixChannelAbilities(): Promise<{ success: boolean message?: string data?: { success: number; fails: number } }> { const res = await api.post('/api/channel/fix') return res.data } /** * Delete all disabled channels */ export async function deleteDisabledChannels(): Promise<{ success: boolean message?: string data?: number }> { const res = await api.delete('/api/channel/disabled') return res.data } /** * Get channel key (requires 2FA verification) */ export async function getChannelKey( id: number, code?: string ): Promise<{ success: boolean; message?: string; data?: { key: string } }> { const payload = code ? { code } : undefined const res = await api.post(`/api/channel/${id}/key`, payload) return res.data } // ============================================================================ // Codex Channel Operations // ============================================================================ export async function startCodexOAuth(): Promise { const config: ExtendedApiConfig = { skipBusinessError: true } const res = await api.post('/api/channel/codex/oauth/start', {}, config) return res.data } export async function completeCodexOAuth( input: string ): Promise { const config: ExtendedApiConfig = { skipBusinessError: true } const res = await api.post( '/api/channel/codex/oauth/complete', { input }, config ) return res.data } export async function refreshCodexCredential( channelId: number ): Promise { const config: ExtendedApiConfig = { skipBusinessError: true } const res = await api.post( `/api/channel/${channelId}/codex/refresh`, {}, config ) return res.data } export async function getCodexUsage( channelId: number ): Promise { const config: ExtendedApiConfig = { skipBusinessError: true, disableDuplicate: true, } const res = await api.get(`/api/channel/${channelId}/codex/usage`, config) return res.data } // ============================================================================ // Multi-Key Management // ============================================================================ /** * Manage multi-key channel operations */ export async function manageMultiKeys( params: MultiKeyManageParams ): Promise { const res = await api.post('/api/channel/multi_key/manage', params) return res.data } /** * Get key status for multi-key channel */ export async function getMultiKeyStatus( channelId: number, page = 1, pageSize = 50, status?: number ): Promise { return manageMultiKeys({ channel_id: channelId, action: 'get_key_status', page, page_size: pageSize, status, }) as Promise } /** * Enable a specific key in multi-key channel */ export async function enableMultiKey( channelId: number, keyIndex: number ): Promise<{ success: boolean; message?: string }> { return manageMultiKeys({ channel_id: channelId, action: 'enable_key', key_index: keyIndex, }) as Promise<{ success: boolean; message?: string }> } /** * Disable a specific key in multi-key channel */ export async function disableMultiKey( channelId: number, keyIndex: number ): Promise<{ success: boolean; message?: string }> { return manageMultiKeys({ channel_id: channelId, action: 'disable_key', key_index: keyIndex, }) as Promise<{ success: boolean; message?: string }> } /** * Delete a specific key in multi-key channel */ export async function deleteMultiKey( channelId: number, keyIndex: number ): Promise<{ success: boolean; message?: string }> { return manageMultiKeys({ channel_id: channelId, action: 'delete_key', key_index: keyIndex, }) as Promise<{ success: boolean; message?: string }> } /** * Enable all keys in multi-key channel */ export async function enableAllMultiKeys( channelId: number ): Promise<{ success: boolean; message?: string }> { return manageMultiKeys({ channel_id: channelId, action: 'enable_all_keys', }) as Promise<{ success: boolean; message?: string }> } /** * Disable all keys in multi-key channel */ export async function disableAllMultiKeys( channelId: number ): Promise<{ success: boolean; message?: string }> { return manageMultiKeys({ channel_id: channelId, action: 'disable_all_keys', }) as Promise<{ success: boolean; message?: string }> } /** * Delete all disabled keys in multi-key channel */ export async function deleteDisabledMultiKeys( channelId: number ): Promise<{ success: boolean; message?: string; data?: number }> { return manageMultiKeys({ channel_id: channelId, action: 'delete_disabled_keys', }) as Promise<{ success: boolean; message?: string; data?: number }> } // ============================================================================ // Tag Operations // ============================================================================ /** * Enable all channels with a specific tag */ export async function enableTagChannels( tag: string ): Promise<{ success: boolean; message?: string }> { const res = await api.post('/api/channel/tag/enabled', { tag }) return res.data } /** * Disable all channels with a specific tag */ export async function disableTagChannels( tag: string ): Promise<{ success: boolean; message?: string }> { const res = await api.post('/api/channel/tag/disabled', { tag }) return res.data } /** * Edit all channels with a specific tag */ export async function editTagChannels( params: TagOperationParams ): Promise<{ success: boolean; message?: string }> { const res = await api.put('/api/channel/tag', params) return res.data } /** * Get models for a specific tag */ export async function getTagModels( tag: string ): Promise<{ success: boolean; message?: string; data?: string }> { const res = await api.get('/api/channel/tag/models', { params: { tag } }) return res.data } // ============================================================================ // Utility Functions // ============================================================================ /** * Fetch models from a custom endpoint (for testing before creating channel) */ export async function fetchModels(data: { base_url: string type: number key: string }): Promise { const res = await api.post('/api/channel/fetch_models', data) return res.data } /** * Delete an Ollama model from a channel */ export async function deleteOllamaModel(params: { channel_id: number model_name: string }): Promise<{ success: boolean; message?: string }> { const res = await api.delete('/api/channel/ollama/delete', { data: params }) return res.data } /** * Test all enabled channels */ export async function testAllChannels(): Promise<{ success: boolean message?: string }> { const res = await api.get('/api/channel/test') return res.data } /** * Update balance for all enabled channels */ export async function updateAllChannelsBalance(): Promise<{ success: boolean message?: string }> { const res = await api.get('/api/channel/update_balance') return res.data } /** * Get all available models */ export async function getAllModels(): Promise<{ success: boolean message?: string data?: Array<{ id: string; [key: string]: unknown }> }> { const res = await api.get('/api/channel/models') return res.data } /** * Get all enabled models */ export async function getEnabledModels(): Promise<{ success: boolean message?: string data?: string[] }> { const res = await api.get('/api/channel/models_enabled') return res.data } // ============================================================================ // Ollama Utilities // ============================================================================ /** * Check Ollama version for a given channel */ export async function getOllamaVersion( channelId: number ): Promise<{ success: boolean; message?: string; data?: { version: string } }> { const res = await api.get(`/api/channel/ollama/version/${channelId}`) return res.data } // ============================================================================ // Group Management // ============================================================================ /** * Get all available groups (re-exported from users API for convenience) */ export const getGroups = getUserGroups // ============================================================================ // Prefill Groups (Model Groups) // ============================================================================ /** * Get prefill groups for quick model selection */ export async function getPrefillGroups( type: 'model' | 'group' = 'model' ): Promise<{ success: boolean message?: string data?: Array<{ id: number; name: string; items: string | string[] }> }> { const res = await api.get('/api/prefill_group', { params: { type } }) return res.data }