diff --git a/src/api/ai-content-generator.ts b/src/api/ai-content-generator.ts new file mode 100644 index 0000000..13ae9f5 --- /dev/null +++ b/src/api/ai-content-generator.ts @@ -0,0 +1,64 @@ +export interface ContentGenerationRequest { + inputs: { + user_input: string + files?: any[] + } + query: string + response_mode: string + preview_url?: string + transfer_method?: string + user?: string +} + +export interface DifyResponse { + message: { + content: string + } +} + +/** + * 生成AI内容 + * @param userInput 用户输入的文本 + * @param files 可选的文件数组 + * @returns Promise + */ +export function generateContent(userInput: string, files?: any[]) { + const requestBody: ContentGenerationRequest = { + inputs: { + user_input: userInput, + files: files || [] + }, + query: '1', + response_mode: 'streaming', + preview_url: files && files.length > 0 ? '1' : undefined, + transfer_method: files && files.length > 0 ? 'local_file' : undefined, + user: files && files.length > 0 ? 'admin' : undefined + } + + return fetch('https://copilot.sino-bridge.com/v1/chat-messages', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'Authorization': 'Bearer app-YG1qx3qGCPsgqMIyBr8tCmJ7' + }, + body: JSON.stringify(requestBody) + }) +} + +/** + * 上传文件到Dify平台 + * @param file 文件对象 + * @returns Promise + */ +export function uploadFile(file: File) { + const formData = new FormData() + formData.append('file', file) + + return fetch('https://copilot.sino-bridge.com/v1/files/upload', { + method: 'POST', + headers: { + 'Authorization': 'Bearer app-YG1qx3qGCPsgqMIyBr8tCmJ7' + }, + body: formData + }) +} \ No newline at end of file diff --git a/src/pages/ai-content-generator/index.tsx b/src/pages/ai-content-generator/index.tsx new file mode 100644 index 0000000..2086931 --- /dev/null +++ b/src/pages/ai-content-generator/index.tsx @@ -0,0 +1,295 @@ +import React, { useState } from 'react' +import { + Card, + Form, + Input, + Button, + Typography, + Space, + Upload, + message, + Spin +} from 'antd' +import { + RocketOutlined, + ReloadOutlined, + UploadOutlined +} from '@ant-design/icons' +import type { UploadFile, UploadProps } from 'antd' + +const { Title, Text } = Typography +const { TextArea } = Input + +const AIContentGenerator: React.FC = () => { + const [form] = Form.useForm() + const [generatedResult, setGeneratedResult] = useState('') + const [isGenerating, setIsGenerating] = useState(false) + const [fileList, setFileList] = useState([]) + + // 处理文件上传 + const handleUpload: UploadProps['customRequest'] = async ({ file, onSuccess, onError }) => { + try { + const fileObj = file as File + const response = await fetch('https://copilot.sino-bridge.com/v1/files/upload', { + method: 'POST', + headers: { + 'Authorization': 'Bearer app-YG1qx3qGCPsgqMIyBr8tCmJ7' + }, + body: (() => { + const formData = new FormData() + formData.append('file', fileObj) + return formData + })() + }) + + if (response.ok) { + const data = await response.json() + message.success('文件上传成功') + onSuccess && onSuccess(data, {} as any) + } else { + throw new Error('文件上传失败') + } + } catch (error) { + console.error('文件上传错误:', error) + message.error('文件上传失败') + onError && onError(error as any) + } + } + + // 处理文件变化 + const handleFileChange: UploadProps['onChange'] = (info) => { + let newFileList = [...info.fileList] + + // 限制上传文件数量为 3 个 + newFileList = newFileList.slice(-3) + + setFileList(newFileList) + } + + // 生成内容 + const handleGenerate = async () => { + try { + const values = await form.validateFields() + const userInput = values.user_input?.trim() + + if (!userInput) { + message.warning('请输入需要生成内容的描述') + return + } + + setIsGenerating(true) + setGeneratedResult('') + + // 准备文件数据 + const files = fileList.map(file => { + if (file.response) { + return file.response + } + return null + }).filter(Boolean) + + const requestBody = { + inputs: { + user_input: userInput, + files: files + }, + query: '1', + response_mode: 'streaming', + ...(files.length > 0 && { + preview_url: '1', + transfer_method: 'local_file', + user: 'admin' + }) + } + + const response = await fetch('https://copilot.sino-bridge.com/v1/chat-messages', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'Authorization': 'Bearer app-YG1qx3qGCPsgqMIyBr8tCmJ7' + }, + body: JSON.stringify(requestBody) + }) + + if (!response.ok) { + throw new Error(`请求失败: ${response.status}`) + } + + const reader = response.body?.getReader() + if (!reader) { + throw new Error('无法读取响应流') + } + + const decoder = new TextDecoder() + let content = '' + + while (true) { + const { done, value } = await reader.read() + if (done) break + + const chunk = decoder.decode(value, { stream: true }) + const lines = chunk.split('\n') + + for (const line of lines) { + if (line.startsWith('data: ')) { + const dataStr = line.slice(6) + if (dataStr === '[DONE]') { + continue + } + try { + const data = JSON.parse(dataStr) + if (data.event === 'message' && data.answer) { + content += data.answer + setGeneratedResult(content) + } + } catch (e) { + // 忽略解析错误的行 + } + } + } + } + + message.success('内容生成完成') + } catch (error) { + console.error('生成内容错误:', error) + message.error('生成内容失败,请稍后重试') + } finally { + setIsGenerating(false) + } + } + + // 清空重置 + const handleReset = () => { + form.resetFields() + setGeneratedResult('') + setFileList([]) + } + + return ( +
+ {/* 页面标题区 */} +
+ + AI内容生成工具 + + + 输入您的需求,AI将为您生成高质量内容 + +
+ +
+ {/* 参数输入区 */} + +
+ +