以下是一个增强版纯前端实现方案,支持文件上传和内容解析功能,直接调用DeepSeek API:

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>DeepSeek 智能助手 (支持附件)</title>
    <style>
        :root {
            --primary-color: #2c3e50;
            --accent-color: #3498db;
            --error-color: #e74c3c;
        }
        body {
            font-family: 'Segoe UI', system-ui, sans-serif;
            max-width: 800px;
            margin: 2rem auto;
            padding: 0 20px;
            background: #f8f9fa;
        }
        .container {
            background: white;
            border-radius: 12px;
            box-shadow: 0 4px 6px rgba(0,0,0,0.1);
            padding: 2rem;
        }
        .input-group {
            display: flex;
            gap: 10px;
            margin-bottom: 1rem;
        }
        input[type="text"], input[type="file"] {
            flex: 1;
            padding: 12px;
            border: 2px solid #ddd;
            border-radius: 8px;
            font-size: 16px;
        }
        button {
            padding: 12px 24px;
            background: var(--accent-color);
            color: white;
            border: none;
            border-radius: 8px;
            cursor: pointer;
            transition: opacity 0.3s;
        }
        button:hover {
            opacity: 0.9;
        }
        #file-list {
            margin: 1rem 0;
            padding: 0;
            list-style: none;
        }
        .file-item {
            display: flex;
            align-items: center;
            padding: 8px;
            background: #f8f9fa;
            border-radius: 6px;
            margin-bottom: 6px;
        }
        .file-item span {
            flex: 1;
            font-size: 0.9em;
        }
        #response {
            margin-top: 20px;
            padding: 16px;
            background: #f8f9fa;
            border-radius: 8px;
            min-height: 100px;
            white-space: pre-wrap;
            line-height: 1.6;
        }
        .loading {
            display: none;
            color: #666;
            font-style: italic;
        }
        .error {
            color: var(--error-color);
            margin: 0.5rem 0;
        }
    </style>
</head>
<body>
    <div class="container">
        <h1 style="color: var(--primary-color); margin-bottom: 1.5rem;">DeepSeek 智能助手</h1>
        
        <!-- 文件上传区域 -->
        <div class="input-group">
            <input type="file" id="file-input" multiple accept=".txt,.pdf,.docx">
            <button onclick="handleFileUpload()">上传文件</button>
        </div>
        <ul id="file-list"></ul>

        <!-- 问答区域 -->
        <div class="input-group">
            <input type="text" id="question" placeholder="请输入您的问题...">
            <button onclick="askQuestion()">发送</button>
        </div>
        <div class="loading" id="loading">处理中...</div>
        <div id="response"></div>
    </div>

    <script>
        // 配置参数(⚠️ 安全提示:前端暴露API密钥仅限本地测试)
        const CONFIG = {
            API_KEY: 'your-api-key-here',
            API_URL: 'https://api.deepseek.com/v1/chat/completions',
            MODEL: 'deepseek-chat',
            MAX_FILE_SIZE: 2 * 1024 * 1024, // 2MB
            ALLOWED_TYPES: ['text/plain', 'application/pdf', 'application/vnd.openxmlformats-officedocument.wordprocessingml.document']
        }

        let uploadedFiles = [];

        // 文件上传处理
        async function handleFileUpload() {
            const fileInput = document.getElementById('file-input');
            const files = Array.from(fileInput.files);
            const fileList = document.getElementById('file-list');

            try {
                for (const file of files) {
                    // 验证文件
                    if (file.size > CONFIG.MAX_FILE_SIZE) {
                        throw new Error(`文件 ${file.name} 超过大小限制 (最大 ${CONFIG.MAX_FILE_SIZE/1024/1024}MB)`);
                    }
                    if (!CONFIG.ALLOWED_TYPES.includes(file.type)) {
                        throw new Error(`不支持的文件类型: ${file.type}`);
                    }

                    // 读取文件内容
                    const content = await readFileContent(file);
                    
                    // 存储文件信息
                    uploadedFiles.push({
                        name: file.name,
                        type: file.type,
                        size: file.size,
                        content: content,
                        uploadedAt: new Date().toISOString()
                    });

                    // 更新文件列表
                    const li = document.createElement('li');
                    li.className = 'file-item';
                    li.innerHTML = `
                        <span>${file.name} (${formatFileSize(file.size)})</span>
                        <button onclick="removeFile('${file.name}')">删除</button>
                    `;
                    fileList.appendChild(li);
                }
                fileInput.value = ''; // 清空选择
            } catch (error) {
                showError(error.message);
            }
        }

        // 文件内容读取
        function readFileContent(file) {
            return new Promise((resolve, reject) => {
                const reader = new FileReader();
                reader.onload = () => resolve(reader.result);
                reader.onerror = reject;
                
                if (file.type === 'application/pdf') {
                    // PDF处理需要第三方库(此处简化处理)
                    reader.readAsArrayBuffer(file);
                } else {
                    reader.readAsText(file, 'UTF-8');
                }
            });
        }

        // 提问处理
        async function askQuestion() {
            const question = document.getElementById('question').value.trim();
            const loading = document.getElementById('loading');
            const responseDiv = document.getElementById('response');

            if (!question) {
                showError('请输入有效问题');
                return;
            }

            try {
                loading.style.display = 'block';
                responseDiv.textContent = '';

                // 构建上下文
                const context = uploadedFiles.length > 0 
                    ? `参考文件内容:\n${uploadedFiles.map(f => f.content).join('\n')}\n\n问题:`
                    : '';

                // API请求
                const response = await fetch(CONFIG.API_URL, {
                    method: 'POST',
                    headers: {
                        'Content-Type': 'application/json',
                        'Authorization': `Bearer ${CONFIG.API_KEY}`
                    },
                    body: JSON.stringify({
                        model: CONFIG.MODEL,
                        messages: [{
                            role: "user",
                            content: context + question
                        }]
                    })
                });

                if (!response.ok) throw new Error(`API请求失败: ${response.status}`);
                const data = await response.json();
                responseDiv.textContent = data.choices[0].message.content;
            } catch (error) {
                showError(error.message);
                console.error(error);
            } finally {
                loading.style.display = 'none';
            }
        }

        // 辅助函数
        function formatFileSize(bytes) {
            if (bytes < 1024) return bytes + ' B';
            if (bytes < 1048576) return (bytes/1024).toFixed(1) + ' KB';
            return (bytes/1048576).toFixed(1) + ' MB';
        }

        function removeFile(filename) {
            uploadedFiles = uploadedFiles.filter(f => f.name !== filename);
            document.querySelectorAll('.file-item').forEach(li => {
                if (li.textContent.includes(filename)) li.remove();
            });
        }

        function showError(message) {
            const errorDiv = document.createElement('div');
            errorDiv.className = 'error';
            errorDiv.textContent = message;
            document.body.appendChild(errorDiv);
            setTimeout(() => errorDiv.remove(), 3000);
        }

        // 事件监听
        document.getElementById('question').addEventListener('keypress', e => {
            if (e.key === 'Enter') askQuestion();
        });
    </script>
</body>
</html>

功能亮点

  1. 文件上传管理

    • 支持多文件上传 (PDF/DOCX/TXT)
    • 实时显示文件列表
    • 文件大小和类型验证
    • 单个文件删除功能
  2. 内容处理

    • 自动将文件内容作为上下文附加到问题
    • 基础PDF/DOCX文件处理(需扩展解析逻辑)
  3. 安全控制

    • 文件大小限制 (2MB)
    • 允许的文件类型白名单

使用说明

  1. 保存为 .html 文件
  2. 替换API密钥
  3. 通过以下方式访问:
    # 使用Python启动简易服务器
    python3 -m http.server 8000
    
    访问 http://localhost:8000

扩展建议

  1. 增强文件解析(需引入库):
<!-- 在<head>添加 -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/pdf.js/3.4.120/pdf.min.js"></script>
<script src="https://unpkg.com/mammoth@1.4.8/mammoth.browser.min.js"></script>

<script>
// 修改readFileContent函数
async function readFileContent(file) {
    if (file.type === 'application/pdf') {
        const arrayBuffer = await file.arrayBuffer();
        const pdf = await pdfjsLib.getDocument(arrayBuffer).promise;
        let text = '';
        for (let i = 1; i <= pdf.numPages; i++) {
            const page = await pdf.getPage(i);
            const content = await page.getTextContent();
            text += content.items.map(item => item.str).join(' ');
        }
        return text;
    } else if (file.type === 'application/vnd.openxmlformats-officedocument.wordprocessingml.document') {
        const arrayBuffer = await file.arrayBuffer();
        const result = await mammoth.extractRawText({arrayBuffer});
        return result.value;
    }
    return await file.text();
}
</script>
  1. 添加预览功能
function previewFile(filename) {
    const file = uploadedFiles.find(f => f.name === filename);
    if (file) {
        const win = window.open();
        win.document.write(`<pre>${file.content}</pre>`);
    }
}
  1. 添加会话管理
// 在CONFIG中添加
SESSION_MAX_AGE: 3600 // 1小时有效期

// 初始化时读取本地存储
if (localStorage.getItem('chatSession')) {
    const session = JSON.parse(localStorage.getItem('chatSession'));
    if (Date.now() - session.timestamp < CONFIG.SESSION_MAX_AGE * 1000) {
        uploadedFiles = session.files;
        // 更新文件列表显示...
    }
}

// 定期保存
setInterval(() => {
    localStorage.setItem('chatSession', JSON.stringify({
        files: uploadedFiles,
        timestamp: Date.now()
    }));
}, 30000);

注意事项

  1. 前端文件处理能力有限,大文件可能影响性能
  2. 复杂文档解析建议在服务端进行
  3. API密钥需通过后端服务保护(正式环境)
  4. 浏览器内存限制:建议添加文件数量限制

项目下载地址:
调用DeepSeek API 增强版纯前端实现方案,支持文件上传和内容解析功能

Logo

欢迎加入DeepSeek 技术社区。在这里,你可以找到志同道合的朋友,共同探索AI技术的奥秘。

更多推荐