RedInk / frontend /src /composables /useProviderForm.ts
m19921414377's picture
Upload folder using huggingface_hub
6db48b4 verified
import { ref } from 'vue'
import { getConfig, updateConfig, testConnection, type Config } from '../api'
/**
* 服务商表单管理 Composable
*
* 提供服务商配置的完整管理功能:
* - 加载/保存配置
* - 添加/编辑/删除服务商
* - 测试连接
* - 激活服务商
*/
// 服务商数据类型
export interface Provider {
type: string
model: string
base_url?: string
api_key?: string
api_key_masked?: string
endpoint_type?: string
high_concurrency?: boolean
short_prompt?: boolean
}
// 服务商配置类型
export interface ProviderConfig {
active_provider: string
providers: Record<string, Provider>
}
// 文本服务商表单类型
export interface TextProviderForm {
name: string
type: string
api_key: string
api_key_masked: string
base_url: string
model: string
endpoint_type: string
_has_api_key: boolean
}
// 图片服务商表单类型
export interface ImageProviderForm {
name: string
type: string
api_key: string
api_key_masked: string
base_url: string
model: string
high_concurrency: boolean
short_prompt: boolean
endpoint_type: string
_has_api_key: boolean
}
// 文本服务商类型选项
export const textTypeOptions = [
{ value: 'google_gemini', label: 'Google Gemini' },
{ value: 'openai_compatible', label: 'OpenAI 兼容接口' }
]
// 图片服务商类型选项
export const imageTypeOptions = [
{ value: 'google_genai', label: 'Google GenAI' },
{ value: 'image_api', label: 'OpenAI 兼容接口' }
]
/**
* 服务商表单管理 Hook
*/
export function useProviderForm() {
// 加载状态
const loading = ref(true)
const saving = ref(false)
const testingText = ref(false)
const testingImage = ref(false)
// 配置数据
const textConfig = ref<ProviderConfig>({
active_provider: '',
providers: {}
})
const imageConfig = ref<ProviderConfig>({
active_provider: '',
providers: {}
})
// 文本服务商弹窗状态
const showTextModal = ref(false)
const editingTextProvider = ref<string | null>(null)
const textForm = ref<TextProviderForm>(createEmptyTextForm())
// 图片服务商弹窗状态
const showImageModal = ref(false)
const editingImageProvider = ref<string | null>(null)
const imageForm = ref<ImageProviderForm>(createEmptyImageForm())
/**
* 创建空的文本服务商表单
*/
function createEmptyTextForm(): TextProviderForm {
return {
name: '',
type: 'openai_compatible',
api_key: '',
api_key_masked: '',
base_url: '',
model: '',
endpoint_type: '/v1/chat/completions',
_has_api_key: false
}
}
/**
* 创建空的图片服务商表单
*/
function createEmptyImageForm(): ImageProviderForm {
return {
name: '',
type: 'image_api',
api_key: '',
api_key_masked: '',
base_url: '',
model: '',
high_concurrency: false,
short_prompt: false,
endpoint_type: '/v1/images/generations',
_has_api_key: false
}
}
/**
* 加载配置
*/
async function loadConfig() {
loading.value = true
try {
const result = await getConfig()
if (result.success && result.config) {
textConfig.value = {
active_provider: result.config.text_generation.active_provider,
providers: result.config.text_generation.providers
}
imageConfig.value = result.config.image_generation
} else {
alert('加载配置失败: ' + (result.error || '未知错误'))
}
} catch (e) {
alert('加载配置失败: ' + String(e))
} finally {
loading.value = false
}
}
/**
* 自动保存配置
*/
async function autoSaveConfig() {
try {
const config: Partial<Config> = {
text_generation: {
active_provider: textConfig.value.active_provider,
providers: textConfig.value.providers
},
image_generation: imageConfig.value
}
const result = await updateConfig(config)
if (result.success) {
// 重新加载配置以获取最新的脱敏 API Key
await loadConfig()
}
} catch (e) {
console.error('自动保存失败:', e)
}
}
// ==================== 文本服务商操作 ====================
/**
* 激活文本服务商
*/
async function activateTextProvider(name: string) {
textConfig.value.active_provider = name
await autoSaveConfig()
}
/**
* 打开添加文本服务商弹窗
*/
function openAddTextModal() {
editingTextProvider.value = null
textForm.value = createEmptyTextForm()
showTextModal.value = true
}
/**
* 打开编辑文本服务商弹窗
*/
function openEditTextModal(name: string, provider: Provider) {
editingTextProvider.value = name
textForm.value = {
name: name,
type: provider.type || 'openai_compatible',
api_key: '',
api_key_masked: provider.api_key_masked || '',
base_url: provider.base_url || '',
model: provider.model || '',
endpoint_type: provider.endpoint_type || '/v1/chat/completions',
_has_api_key: !!provider.api_key_masked
}
showTextModal.value = true
}
/**
* 关闭文本服务商弹窗
*/
function closeTextModal() {
showTextModal.value = false
editingTextProvider.value = null
}
/**
* 保存文本服务商
*/
async function saveTextProvider() {
const name = editingTextProvider.value || textForm.value.name
if (!name) {
alert('请填写服务商名称')
return
}
if (!textForm.value.type) {
alert('请选择服务商类型')
return
}
// 新增时必须填写 API Key
if (!editingTextProvider.value && !textForm.value.api_key) {
alert('请填写 API Key')
return
}
const existingProvider = textConfig.value.providers[name] || {}
const providerData: any = {
type: textForm.value.type,
model: textForm.value.model
}
// 如果填写了新的 API Key,使用新的;否则保留原有的
if (textForm.value.api_key) {
providerData.api_key = textForm.value.api_key
} else if (existingProvider.api_key) {
providerData.api_key = existingProvider.api_key
}
if (textForm.value.base_url) {
providerData.base_url = textForm.value.base_url
}
// 如果是 OpenAI 兼容接口,保存 endpoint_type
if (textForm.value.type === 'openai_compatible') {
providerData.endpoint_type = textForm.value.endpoint_type
}
textConfig.value.providers[name] = providerData
closeTextModal()
await autoSaveConfig()
}
/**
* 删除文本服务商
*/
async function deleteTextProvider(name: string) {
if (confirm(`确定要删除服务商 "${name}" 吗?`)) {
delete textConfig.value.providers[name]
if (textConfig.value.active_provider === name) {
textConfig.value.active_provider = ''
}
await autoSaveConfig()
}
}
/**
* 测试文本服务商连接(弹窗中)
*/
async function testTextConnection() {
testingText.value = true
try {
const result = await testConnection({
type: textForm.value.type,
provider_name: editingTextProvider.value || undefined,
api_key: textForm.value.api_key || undefined,
base_url: textForm.value.base_url,
model: textForm.value.model
})
if (result.success) {
alert('✅ ' + result.message)
}
} catch (e: any) {
alert('❌ 连接失败:' + (e.response?.data?.error || e.message))
} finally {
testingText.value = false
}
}
/**
* 测试列表中的文本服务商
*/
async function testTextProviderInList(name: string, provider: Provider) {
try {
const result = await testConnection({
type: provider.type,
provider_name: name,
api_key: undefined,
base_url: provider.base_url,
model: provider.model
})
if (result.success) {
alert('✅ ' + result.message)
}
} catch (e: any) {
alert('❌ 连接失败:' + (e.response?.data?.error || e.message))
}
}
// ==================== 图片服务商操作 ====================
/**
* 激活图片服务商
*/
async function activateImageProvider(name: string) {
imageConfig.value.active_provider = name
await autoSaveConfig()
}
/**
* 打开添加图片服务商弹窗
*/
function openAddImageModal() {
editingImageProvider.value = null
imageForm.value = createEmptyImageForm()
showImageModal.value = true
}
/**
* 打开编辑图片服务商弹窗
*/
function openEditImageModal(name: string, provider: Provider) {
editingImageProvider.value = name
imageForm.value = {
name: name,
type: provider.type || '',
api_key: '',
api_key_masked: provider.api_key_masked || '',
base_url: provider.base_url || '',
model: provider.model || '',
high_concurrency: provider.high_concurrency || false,
short_prompt: provider.short_prompt || false,
endpoint_type: provider.endpoint_type || '/v1/images/generations',
_has_api_key: !!provider.api_key_masked
}
showImageModal.value = true
}
/**
* 关闭图片服务商弹窗
*/
function closeImageModal() {
showImageModal.value = false
editingImageProvider.value = null
}
/**
* 保存图片服务商
*/
async function saveImageProvider() {
const name = editingImageProvider.value || imageForm.value.name
if (!name) {
alert('请填写服务商名称')
return
}
if (!imageForm.value.type) {
alert('请填写服务商类型')
return
}
// 新增时必须填写 API Key
if (!editingImageProvider.value && !imageForm.value.api_key) {
alert('请填写 API Key')
return
}
const existingProvider = imageConfig.value.providers[name] || {}
const providerData: any = {
type: imageForm.value.type,
model: imageForm.value.model,
high_concurrency: imageForm.value.high_concurrency,
short_prompt: imageForm.value.short_prompt
}
// 如果是 OpenAI 兼容接口,保存 endpoint_type
if (imageForm.value.type === 'image_api') {
providerData.endpoint_type = imageForm.value.endpoint_type
}
// 如果填写了新的 API Key,使用新的;否则保留原有的
if (imageForm.value.api_key) {
providerData.api_key = imageForm.value.api_key
} else if (existingProvider.api_key) {
providerData.api_key = existingProvider.api_key
}
if (imageForm.value.base_url) {
providerData.base_url = imageForm.value.base_url
}
imageConfig.value.providers[name] = providerData
closeImageModal()
await autoSaveConfig()
}
/**
* 删除图片服务商
*/
async function deleteImageProvider(name: string) {
if (confirm(`确定要删除服务商 "${name}" 吗?`)) {
delete imageConfig.value.providers[name]
if (imageConfig.value.active_provider === name) {
imageConfig.value.active_provider = ''
}
await autoSaveConfig()
}
}
/**
* 测试图片服务商连接(弹窗中)
*/
async function testImageConnection() {
testingImage.value = true
try {
const result = await testConnection({
type: imageForm.value.type,
provider_name: editingImageProvider.value || undefined,
api_key: imageForm.value.api_key || undefined,
base_url: imageForm.value.base_url,
model: imageForm.value.model
})
if (result.success) {
alert('✅ ' + result.message)
}
} catch (e: any) {
alert('❌ 连接失败:' + (e.response?.data?.error || e.message))
} finally {
testingImage.value = false
}
}
/**
* 测试列表中的图片服务商
*/
async function testImageProviderInList(name: string, provider: Provider) {
try {
const result = await testConnection({
type: provider.type,
provider_name: name,
api_key: undefined,
base_url: provider.base_url,
model: provider.model
})
if (result.success) {
alert('✅ ' + result.message)
}
} catch (e: any) {
alert('❌ 连接失败:' + (e.response?.data?.error || e.message))
}
}
/**
* 更新文本表单数据
*/
function updateTextForm(data: TextProviderForm) {
textForm.value = data
}
/**
* 更新图片表单数据
*/
function updateImageForm(data: ImageProviderForm) {
imageForm.value = data
}
return {
// 状态
loading,
saving,
testingText,
testingImage,
// 配置数据
textConfig,
imageConfig,
// 文本服务商弹窗
showTextModal,
editingTextProvider,
textForm,
// 图片服务商弹窗
showImageModal,
editingImageProvider,
imageForm,
// 方法
loadConfig,
// 文本服务商方法
activateTextProvider,
openAddTextModal,
openEditTextModal,
closeTextModal,
saveTextProvider,
deleteTextProvider,
testTextConnection,
testTextProviderInList,
updateTextForm,
// 图片服务商方法
activateImageProvider,
openAddImageModal,
openEditImageModal,
closeImageModal,
saveImageProvider,
deleteImageProvider,
testImageConnection,
testImageProviderInList,
updateImageForm
}
}