AIClient-2-API/static/app/file-upload.js
hex2077 f8faee93fc Revert "add letta"
This reverts commit 3faa599b95523160232df3d5483840b56d5a4702.
2026-01-19 21:55:44 +08:00

220 lines
No EOL
7.3 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// 文件上传功能模块
import { showToast } from './utils.js';
import { t } from './i18n.js';
/**
* 文件上传处理器类
*/
class FileUploadHandler {
constructor() {
this.currentProvider = 'gemini'; // 默认提供商
this.initEventListeners();
}
/**
* 初始化事件监听器
*/
initEventListeners() {
// 监听所有上传按钮的点击事件
document.addEventListener('click', (event) => {
if (event.target.closest('.upload-btn')) {
const button = event.target.closest('.upload-btn');
const targetInputId = button.getAttribute('data-target');
if (targetInputId) {
// 尝试从模态框获取 providerType
const modal = button.closest('.provider-modal');
const providerType = modal ? modal.getAttribute('data-provider-type') : null;
this.handleFileUpload(button, targetInputId, providerType);
}
}
});
// 监听提供商切换事件
const modelProvider = document.getElementById('modelProvider');
if (modelProvider) {
modelProvider.addEventListener('change', (event) => {
this.updateCurrentProvider(event.target.value);
});
}
}
/**
* 更新当前提供商
* @param {string} provider - 选择的提供商
*/
updateCurrentProvider(provider) {
this.currentProvider = this.getProviderKey(provider);
}
/**
* 获取提供商对应的键名
* @param {string} provider - 提供商名称
* @returns {string} - 提供商标识
*/
getProviderKey(provider) {
const providerMap = {
'gemini-cli-oauth': 'gemini',
'gemini-antigravity': 'antigravity',
'claude-kiro-oauth': 'kiro',
'openai-qwen-oauth': 'qwen',
'openai-iflow': 'iflow'
};
return providerMap[provider] || 'gemini';
}
/**
* 处理文件上传
* @param {HTMLElement} button - 上传按钮元素
* @param {string} targetInputId - 目标输入框ID
* @param {string} providerType - 提供商类型
*/
async handleFileUpload(button, targetInputId, providerType) {
// 创建隐藏的文件输入元素
const fileInput = this.createFileInput();
// 设置文件选择回调
fileInput.onchange = async (event) => {
const file = event.target.files[0];
if (file) {
// 只有文件被实际选择后才显示加载状态并上传
this.setButtonLoading(button, true);
await this.uploadFile(file, targetInputId, button, providerType);
}
// 清理临时文件输入元素
fileInput.remove();
};
// 触发文件选择
fileInput.click();
}
/**
* 创建文件输入元素
* @returns {HTMLInputElement} - 文件输入元素
*/
createFileInput() {
const fileInput = document.createElement('input');
fileInput.type = 'file';
fileInput.accept = '.json,.txt,.key,.pem,.p12,.pfx';
fileInput.style.display = 'none';
document.body.appendChild(fileInput);
return fileInput;
}
/**
* 上传文件到服务器
* @param {File} file - 要上传的文件
* @param {string} targetInputId - 目标输入框ID
* @param {HTMLElement} button - 上传按钮
* @param {string} providerType - 提供商类型
*/
async uploadFile(file, targetInputId, button, providerType) {
try {
// 验证文件类型
if (!this.validateFileType(file)) {
showToast(t('common.error'), t('common.fileType'), 'error');
this.setButtonLoading(button, false);
return;
}
// 验证文件大小 (5MB 限制)
if (file.size > 5 * 1024 * 1024) {
showToast(t('common.error'), t('common.fileSize'), 'error');
this.setButtonLoading(button, false);
return;
}
// 使用传入的 providerType 或回退到 currentProvider
const provider = providerType ? this.getProviderKey(providerType) : this.currentProvider;
// 创建 FormData
const formData = new FormData();
formData.append('file', file);
formData.append('provider', provider);
formData.append('targetInputId', targetInputId);
// 使用封装接口发送上传请求
const result = await window.apiClient.upload('/upload-oauth-credentials', formData);
// 成功上传,设置文件路径到输入框
this.setFilePathToInput(targetInputId, result.filePath);
showToast(t('common.success'), t('common.uploadSuccess'), 'success');
} catch (error) {
console.error('文件上传错误:', error);
showToast(t('common.error'), t('common.uploadFailed') + ': ' + error.message, 'error');
} finally {
this.setButtonLoading(button, false);
}
}
/**
* 验证文件类型
* @param {File} file - 要验证的文件
* @returns {boolean} - 是否为有效文件类型
*/
validateFileType(file) {
const allowedExtensions = ['.json', '.txt', '.key', '.pem', '.p12', '.pfx'];
const fileName = file.name.toLowerCase();
return allowedExtensions.some(ext => fileName.endsWith(ext));
}
/**
* 设置按钮加载状态
* @param {HTMLElement} button - 按钮元素
* @param {boolean} isLoading - 是否加载中
*/
setButtonLoading(button, isLoading) {
const icon = button.querySelector('i');
if (isLoading) {
button.disabled = true;
icon.className = 'fas fa-spinner fa-spin';
} else {
button.disabled = false;
icon.className = 'fas fa-upload';
}
}
/**
* 设置文件路径到输入框
* @param {string} inputId - 输入框ID
* @param {string} filePath - 文件路径
*/
setFilePathToInput(inputId, filePath) {
// console.log('设置文件路径到输入框:', inputId, filePath);
let input = document.getElementById(inputId);
if (input) {
// console.log('输入框元素存在,设置文件路径:', filePath);
input.value = filePath;
// 同时更新data-config-value属性用于编辑模式
if (input.hasAttribute('data-config-value')) {
input.setAttribute('data-config-value', filePath);
console.log('更新data-config-value属性:', filePath);
}
// 触发输入事件,通知其他监听器
input.dispatchEvent(new Event('input', { bubbles: true }));
} else {
console.error('无法找到输入框:', inputId);
}
}
}
/**
* 初始化文件上传功能
*/
function initFileUpload() {
// 文件上传功能是自初始化的单例
console.log('文件上传功能已初始化');
}
// 导出单例实例
const fileUploadHandler = new FileUploadHandler();
export {
fileUploadHandler,
FileUploadHandler,
initFileUpload
};