加载中
🤖
AI审核中

通意千应如何“读懂“你的文件?一文拆解多模态上传全链路

  Java   58分钟   109浏览   0评论
AI
AI智能摘要
正在分析文章内容

在现代AI对话系统中,支持附件上传已成为一项核心功能。本文将深入剖析通意千应——一个基于Spring Boot + Vue.js的AI对话系统中,附件上传功能的完整技术实现方案。通意千应支持多类型文件(PDF、Word、Excel、PPT、图片、文本)的上传、解析和多模态AI交互,具有完整的文件存储、内容提取和AI集成能力。

一、系统架构概览

1.1 通意千应整体架构设计

通意千应的附件上传功能采用分层架构设计:

┌─────────────────────────────────────────────────────────┐
│                    前端层 (Vue.js)                       │
│  ┌─────────────┐  ┌─────────────┐  ┌─────────────────┐  │
│  │ 文件选择组件 │  │ 预览渲染组件 │  │   上传管理组件   │  │
│  └─────────────┘  └─────────────┘  └─────────────────┘  │
├─────────────────────────────────────────────────────────┤
│                   控制层 (Spring Boot)                   │
│  ┌─────────────┐  ┌─────────────┐  ┌─────────────────┐  │
│  │ ChatController│ │ 文件上传API  │  │  文件下载API    │  │
│  └─────────────┘  └─────────────┘  └─────────────────┘  │
├─────────────────────────────────────────────────────────┤
│                   服务层 (Service Layer)                 │
│  ┌─────────────┐  ┌─────────────┐  ┌─────────────────┐  │
│  │ChatFileService│ │FileParseService│ │  QiNiuService  │  │
│  └─────────────┘  └─────────────┘  └─────────────────┘  │
├─────────────────────────────────────────────────────────┤
│                   数据层 (Data Layer)                    │
│  ┌─────────────┐  ┌─────────────┐  ┌─────────────────┐  │
│  │  ChatFile   │  │   MyBatis   │  │   七牛云OSS     │  │
│  │   Entity    │  │    Mapper   │  │                 │  │
│  └─────────────┘  └─────────────┘  └─────────────────┘  │
└─────────────────────────────────────────────────────────┘

1.2 通意千应核心功能模块

  1. 文件上传管理:支持多文件批量上传,单文件最大100MB
  2. 文件内容解析:支持PDF、Word、Excel、PPT、TXT等格式的文本提取
  3. 图片多模态处理:支持图片上传和Base64编码,供通意千应AI视觉分析
  4. 云存储集成:使用七牛云OSS进行文件存储和CDN加速
  5. 文件关联管理:文件与消息的关联存储和查询

二、数据模型设计

2.1 文件实体类设计

通意千应的文件实体类设计如下:

@Data
@TableName("chat_file")
public class ChatFile {
    @TableId(type = IdType.AUTO)
    private Long id;              // 文件ID,主键自增

    private Long messageId;       // 关联的消息ID

    private String originalName;  // 原始文件名
    private String storedName;    // 存储文件名(UUID生成)
    private String filePath;      // 文件存储路径
    private String fileUrl;       // 七牛云访问URL

    private String fileType;      // 文件类型(PDF文档、Word文档等)
    private Long fileSize;        // 文件大小(字节)

    private String extractedText; // 提取的文本内容

    private LocalDateTime createTime; // 创建时间
}

通意千应设计要点分析:

  1. UUID存储命名:使用generateStoredName()方法生成UUID作为存储文件名,避免文件名冲突和安全问题
  2. 日期路径组织:采用yyyy/MM/dd的层级目录结构,便于文件管理和清理
  3. 双存储策略:同时保存本地路径和云存储URL,支持灵活的文件访问方式
  4. 文本预提取:在文件上传时即完成文本内容提取,避免重复解析,提升通意千应AI响应速度

三、文件上传流程实现

3.1 前端文件选择与预处理

通意千应前端使用Vue.js实现文件选择和预览功能:

// 文件选择处理
handleFileSelect(event) {
    const files = Array.from(event.target.files);
    const validFiles = [];

    files.forEach((file, index) => {
        const ext = '.' + file.name.split('.').pop().toLowerCase();

        // 1. 文件类型校验
        if (!allAllowedExts.includes(ext)) {
            errors.push(`${file.name}: 不支持的文件格式`);
            return;
        }

        // 2. 文件大小校验(100MB限制)
        if (file.size > this.maxFileSize) {
            errors.push(`${file.name}: 文件大小超过100MB限制`);
            return;
        }

        // 3. 图片数量限制(最多3张)
        if (fileType === 'image') {
            if (currentImageCount + newImageCount >= 3) {
                errors.push(`图片识别最多支持3张,已跳过 ${file.name}`);
                return;
            }
        }

        // 4. 重复文件检测
        const isDuplicate = this.selectedFiles.some(selectedFile => 
            selectedFile.name === file.name && selectedFile.size === file.size
        );

        // 图片类型创建本地预览URL
        let previewUrl = null;
        if (fileType === 'image') {
            previewUrl = URL.createObjectURL(file);
        }

        validFiles.push({
            file: file,
            name: file.name,
            size: file.size,
            type: fileType,
            previewUrl: previewUrl,
            isUploading: fileType === 'image'
        });
    });
}

通意千应关键设计决策:

  1. 即时预览体验:图片文件使用URL.createObjectURL()创建本地预览,无需等待上传完成
  2. 多维度校验:类型、大小、数量、重复性四层校验,确保上传质量
  3. 渐进式上传:图片文件先上传到临时目录,提升用户体验

3.2 后端文件上传接口

通意千应后端文件上传接口实现:

@PostMapping("/api/chat/upload")
@ResponseBody
public Result<List<Map<String, Object>>> uploadFiles(
        @RequestParam("files") List<MultipartFile> files) {

    // 1. 用户认证检查
    User user = userService.getCurrentUser();
    if (user == null) {
        return Result.error(401, "未登录");
    }

    // 2. 基础校验
    if (files == null || files.isEmpty()) {
        return Result.error("请选择要上传的文件");
    }
    if (files.size() > 10) {
        return Result.error("最多只能上传10个文件");
    }

    // 3. 单文件大小校验
    for (MultipartFile file : files) {
        if (file.getSize() > 100 * 1024 * 1024) {
            return Result.error("文件大小不能超过100MB");
        }
    }

    // 4. 执行上传
    List<ChatFile> uploadedFiles = chatFileService.uploadFiles(files);

    // 5. 返回文件信息
    List<Map<String, Object>> result = new ArrayList<>();
    for (ChatFile chatFile : uploadedFiles) {
        Map<String, Object> fileInfo = new HashMap<>();
        fileInfo.put("id", chatFile.getId());
        fileInfo.put("name", chatFile.getOriginalName());
        fileInfo.put("type", chatFile.getFileType());
        fileInfo.put("size", chatFile.getFileSize());
        result.add(fileInfo);
    }
    return Result.success("上传成功", result);
}

3.3 核心上传服务实现

通意千应的核心上传服务:

@Service
public class ChatFileServiceImpl implements ChatFileService {

    @Override
    public ChatFile uploadFile(MultipartFile file, Long messageId) {
        String originalName = file.getOriginalFilename();

        // 1. 文件类型支持性检查
        if (!fileParseService.isSupported(originalName)) {
            throw new RuntimeException("不支持的文件类型: " + originalName);
        }

        // 2. 生成存储路径
        String storedName = generateStoredName(originalName);  // UUID命名
        String datePath = getDatePath();                        // 日期分层
        String fileKey = datePath + "/" + storedName;

        // 3. 文件内容解析(关键步骤)
        Map<String, Object> parseResult = fileParseService.parseFile(file);
        String extractedText = (String) parseResult.get("extractedText");

        // 4. 上传到七牛云OSS
        String fileUrl = qiNiuService.uploadFile(file, fileKey);

        // 5. 保存文件元数据到数据库
        ChatFile chatFile = new ChatFile();
        chatFile.setMessageId(messageId);
        chatFile.setOriginalName(originalName);
        chatFile.setStoredName(storedName);
        chatFile.setFilePath(fileKey);
        chatFile.setFileUrl(fileUrl);
        chatFile.setFileType(fileParseService.getFileType(originalName));
        chatFile.setFileSize(file.getSize());
        chatFile.setExtractedText(extractedText);  // 预提取的文本内容
        chatFile.setCreateTime(LocalDateTime.now());

        chatFileMapper.insert(chatFile);
        return chatFile;
    }
}

通意千应技术亮点:

  1. 预解析策略:文件上传时即完成内容解析,将extractedText保存到数据库,避免通意千应AI对话时的重复解析
  2. 云存储优先:使用七牛云OSS存储文件,提供CDN加速和可靠的文件访问
  3. 事务一致性:文件上传、内容解析、数据库存储形成完整事务链

四、多类型文件解析实现

4.1 文件解析服务架构

通意千应支持7种文件类型的解析,采用策略模式设计:

@Service
public class FileParseServiceImpl implements FileParseService {

    // 文件类型映射配置
    private static final Map<String, String> FILE_TYPE_MAP = new LinkedHashMap<>();

    static {
        FILE_TYPE_MAP.put("pdf", "PDF文档");
        FILE_TYPE_MAP.put("doc", "Word文档");
        FILE_TYPE_MAP.put("docx", "Word文档");
        FILE_TYPE_MAP.put("xls", "Excel表格");
        FILE_TYPE_MAP.put("xlsx", "Excel表格");
        FILE_TYPE_MAP.put("ppt", "PowerPoint演示文稿");
        FILE_TYPE_MAP.put("pptx", "PowerPoint演示文稿");
        FILE_TYPE_MAP.put("png", "图片");
        FILE_TYPE_MAP.put("jpg", "图片");
        FILE_TYPE_MAP.put("txt", "文本文件");
        // ...
    }

    @Override
    public Map<String, Object> parseFile(MultipartFile file) {
        String fileName = file.getOriginalFilename();
        String fileType = getFileType(fileName);

        byte[] content = file.getBytes();
        String extractedText = "";

        // 根据文件类型选择解析策略
        switch (fileType) {
            case "PDF文档":
                extractedText = parsePdf(content, fileName);
                break;
            case "Word文档":
                extractedText = parseWord(content, fileName);
                break;
            case "Excel表格":
                extractedText = parseExcel(content, fileName);
                break;
            case "PowerPoint演示文稿":
                extractedText = parsePpt(content, fileName);
                break;
            case "文本文件":
                extractedText = parseText(content, fileName);
                break;
            case "图片":
                // 图片不解析文本,通过多模态方式处理
                extractedText = "";
                break;
        }

        result.put("extractedText", extractedText);
        return result;
    }
}

4.2 PDF文档解析

通意千应使用Apache PDFBox库进行PDF文本提取:

@Override
public String parsePdf(byte[] content, String fileName) {
    try (PDDocument document = PDDocument.load(new ByteArrayInputStream(content))) {
        PDFTextStripper stripper = new PDFTextStripper();
        String text = stripper.getText(document);

        // 扫描版PDF检测
        if (result.isEmpty() && document.getNumberOfPages() > 0) {
            result = "[此PDF文件无法提取文本内容,可能是扫描版PDF或图片型PDF]";
        }

        return result;
    }
}

4.3 Office文档解析

通意千应使用Apache POI库处理Word、Excel、PPT:

// Word文档解析(支持doc和docx)
@Override
public String parseWord(byte[] content, String fileName) {
    String ext = getExtension(fileName);
    if ("docx".equals(ext)) {
        // 新版Word格式
        try (XWPFDocument document = new XWPFDocument(new ByteArrayInputStream(content))) {
            XWPFWordExtractor extractor = new XWPFWordExtractor(document);
            return extractor.getText();
        }
    } else {
        // 旧版Word格式
        try (HWPFDocument document = new HWPFDocument(new ByteArrayInputStream(content))) {
            WordExtractor extractor = new WordExtractor(document);
            return extractor.getText();
        }
    }
}

// Excel解析(保留表格结构)
@Override
public String parseExcel(byte[] content, String fileName) {
    Workbook workbook = "xlsx".equals(ext) ? 
        new XSSFWorkbook(new ByteArrayInputStream(content)) :
        new HSSFWorkbook(new ByteArrayInputStream(content));

    StringBuilder result = new StringBuilder();
    DataFormatter formatter = new DataFormatter();

    for (int i = 0; i < workbook.getNumberOfSheets(); i++) {
        Sheet sheet = workbook.getSheetAt(i);
        result.append("【工作表: ").append(sheet.getSheetName()).append("】\n");

        for (Row row : sheet) {
            StringBuilder rowText = new StringBuilder();
            for (Cell cell : row) {
                String cellValue = formatter.formatCellValue(cell);
                if (cellValue != null && !cellValue.trim().isEmpty()) {
                    rowText.append(" | ").append(cellValue);
                }
            }
            result.append(rowText).append("\n");
        }
    }
    return result.toString();
}

4.4 文本文件智能编码检测

通意千应支持多种编码格式的文本文件:

@Override
public String parseText(byte[] content, String fileName) {
    // 尝试多种编码方式读取
    String[] charsets = {"UTF-8", "GBK", "GB2312", "ISO-8859-1", "UTF-16"};
    String text = null;

    for (String charset : charsets) {
        try {
            text = new String(content, charset);

            // 乱码检测:检查替换字符比例
            int replacementCharCount = 0;
            for (int i = 0; i < Math.min(text.length(), 1000); i++) {
                if (text.charAt(i) == '\uFFFD') {
                    replacementCharCount++;
                }
            }

            // 如果替换字符比例超过10%,尝试下一个编码
            if (replacementCharCount > Math.min(text.length(), 1000) * 0.1) {
                continue;
            }
            break;
        } catch (Exception e) {
            continue;
        }
    }

    return text != null ? text.trim() : "[文本解析失败]";
}

五、图片多模态处理

5.1 图片Base64编码

为了实现通意千应AI的视觉理解能力,系统需要将图片转换为Base64编码:

@Override
public String getImageBase64(Long fileId) {
    ChatFile chatFile = chatFileMapper.selectById(fileId);

    // 类型检查
    if (!"图片".equals(chatFile.getFileType())) {
        return null;
    }

    byte[] fileContent = null;

    // 优先从七牛云URL下载
    if (chatFile.getFileUrl() != null && !chatFile.getFileUrl().isEmpty()) {
        String fileUrl = chatFile.getFileUrl();
        // HTTP转HTTPS处理
        if (fileUrl.startsWith("http://")) {
            fileUrl = fileUrl.replace("http://", "https://");
        }

        // 下载图片内容
        java.net.URL url = new java.net.URL(fileUrl);
        java.net.HttpURLConnection connection = (java.net.HttpURLConnection) url.openConnection();
        connection.setConnectTimeout(10000);
        connection.setReadTimeout(30000);

        try (InputStream is = connection.getInputStream();
             ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
            byte[] buffer = new byte[8192];
            int bytesRead;
            while ((bytesRead = is.read(buffer)) != -1) {
                baos.write(buffer, 0, bytesRead);
            }
            fileContent = baos.toByteArray();
        }

        // 文件头检查,防止下载到错误内容
        if (fileContent.length > 10) {
            String header = new String(fileContent, 0, Math.min(100, fileContent.length), "UTF-8");
            if (header.startsWith("<!DOCTYPE") || header.startsWith("<html")) {
                // 下载的是HTML而非图片,尝试本地文件
                fileContent = null;
            }
        }
    }

    // 本地文件回退(兼容旧数据)
    if (fileContent == null) {
        Path filePath = Paths.get(uploadPath, chatFile.getFilePath());
        fileContent = Files.readAllBytes(filePath);
    }

    // 转换为Base64 Data URI
    String base64 = Base64.getEncoder().encodeToString(fileContent);
    String mimeType = getImageMimeType(chatFile.getOriginalName());
    return "data:" + mimeType + ";base64," + base64;
}

5.2 图片数量限制策略

通意千应对图片数量进行限制,确保系统稳定性:

// 在ChatController中限制图片数量
List<String> imageBase64List = new ArrayList<>();
if (fileIds != null && !fileIds.isEmpty()) {
    int imageCount = 0;
    for (Long fileId : fileIds) {
        String imageBase64 = chatFileService.getImageBase64(fileId);
        if (imageBase64 != null) {
            // 限制最多3张图片,避免内存溢出和Token超限
            if (imageCount >= 3) {
                log.warn("图片数量超过3张,跳过剩余图片");
                break;
            }
            imageBase64List.add(imageBase64);
            imageCount++;
        }
    }
}

六、AI集成与内容传递

6.1 文件内容整合到AI请求

通意千应将文件内容整合到AI请求中:

@PostMapping("/api/chat/send")
@ResponseBody
public Result<Map<String, Object>> sendMessage(@Validated @RequestBody ChatRequest chatRequest) {
    // 1. 过滤空值fileId
    List<Long> fileIds = chatRequest.getFileIds();
    if (fileIds != null) {
        fileIds = fileIds.stream()
            .filter(id -> id != null)
            .collect(Collectors.toList());
    }

    // 2. 获取图片Base64(用于多模态)
    List<String> imageBase64List = new ArrayList<>();
    if (fileIds != null && !fileIds.isEmpty()) {
        for (Long fileId : fileIds) {
            String imageBase64 = chatFileService.getImageBase64(fileId);
            if (imageBase64 != null) {
                imageBase64List.add(imageBase64);
            }
        }
    }

    // 3. 获取文件文本内容
    String contentForAI = content;
    if (fileIds != null && !fileIds.isEmpty()) {
        String fileContent = chatFileService.getFileContentForAI(fileIds);
        // 整合文件内容和用户问题
        contentForAI = fileContent + "\n\n用户问题:" + content;
    }

    // 4. 构建AI请求
    ChatRequest aiRequest = new ChatRequest();
    aiRequest.setContent(contentForAI);
    aiRequest.setImageBase64List(imageBase64List);  // 多模态图片
    aiRequest.setUserQuery(content);  // 保存原始问题用于网络搜索

    // 5. 调用通意千应AI服务
    String aiResponse = chatMessageService.sendMessageToAI(aiRequest, history);

    // 6. 关联文件到消息
    if (fileIds != null && !fileIds.isEmpty()) {
        for (Long fileId : fileIds) {
            chatFileService.updateFileMessageId(fileId, userMessage.getId());
        }
    }
}

6.2 文件内容格式化

通意千应的文件内容格式化服务:

@Override
public String getFileContentForAI(List<Long> fileIds) {
    List<ChatFile> files = getByIds(fileIds);

    StringBuilder content = new StringBuilder();
    content.append("以下是用户上传的文件内容:\n\n");

    for (ChatFile file : files) {
        content.append("=== 文件: ").append(file.getOriginalName())
               .append(" (").append(file.getFileType()).append(") ===\n");

        // 图片类型特殊处理
        if ("图片".equals(file.getFileType())) {
            content.append("[图片文件,将通过视觉能力分析]");
        } else {
            // 使用预提取的文本内容
            String extractedText = file.getExtractedText();
            if (extractedText != null && !extractedText.isEmpty()) {
                content.append(extractedText);
            } else {
                content.append("[无法提取文件内容]");
            }
        }
        content.append("\n\n");
    }

    return content.toString();
}

七、七牛云OSS集成

7.1 云存储服务实现

通意千应使用七牛云OSS进行文件存储:

@Service
public class QiNiuServiceImpl implements QiNiuService {

    @Value("${qiniu.access-key}")
    private String accessKey;

    @Value("${qiniu.secret-key}")
    private String secretKey;

    @Value("${qiniu.bucket}")
    private String bucket;

    @Value("${qiniu.domain}")
    private String domain;

    private UploadManager uploadManager;
    private BucketManager bucketManager;
    private Auth auth;

    @PostConstruct
    public void init() {
        auth = Auth.create(accessKey, secretKey);
        Configuration cfg = new Configuration(getRegion(region));
        uploadManager = new UploadManager(cfg);
        bucketManager = new BucketManager(auth, cfg);
    }

    @Override
    public String uploadFile(MultipartFile file, String fileName) {
        String key = filePrefix + fileName;
        String upToken = auth.uploadToken(bucket, key);

        Response response = uploadManager.put(
            file.getInputStream(), key, upToken, null, null);

        DefaultPutRet putRet = response.jsonToObject(DefaultPutRet.class);
        return getFileUrl(putRet.key);
    }
}

7.2 临时文件管理

通意千应支持临时文件上传(用于图片预览):

// 上传临时图片
@PostMapping("/api/chat/upload/temp")
@ResponseBody
public Result<Map<String, Object>> uploadTempImage(@RequestParam("file") MultipartFile file) {
    // 只允许图片格式
    List<String> allowedExts = Arrays.asList(".png", ".jpg", ".jpeg", ".gif", ".bmp", ".webp");

    String tempFileName = UUID.randomUUID().toString().replace("-", "") + ext;
    String tempUrl = qiNiuService.uploadTempFile(file, tempFileName);

    Map<String, Object> result = new HashMap<>();
    result.put("fileName", tempFileName);
    result.put("url", tempUrl);
    return Result.success("上传成功", result);
}

// 删除临时图片
@DeleteMapping("/api/chat/upload/temp/{fileName}")
@ResponseBody
public Result<Void> deleteTempImage(@PathVariable String fileName) {
    boolean deleted = qiNiuService.deleteTempFile(fileName);
    return Result.success("删除成功");
}

八、前端文件展示与交互

8.1 消息中的文件展示

通意千应前端消息中的文件展示:

<!-- 用户消息中的文件预览 -->
<div v-if="message.files && message.files.length > 0" class="message-files-preview">
    <div v-for="file in message.files" :key="file.id" 
         class="message-file-item"
         :class="{ 'is-image': file.fileType === '图片' }">

        <!-- 图片类型:直接显示 -->
        <template v-if="file.fileType === '图片'">
            <div class="message-image-preview" @click="openMessageImagePreview(file)">
                <img :src="'/api/chat/file/' + file.id" class="message-image-thumb">
            </div>
        </template>

        <!-- 非图片类型:显示文件卡片 -->
        <template v-else>
            <div class="message-file-card" @click="previewFile(file)">
                <div class="message-file-card-icon" :class="getFilePreviewClass(file.fileType)">
                    <i :class="getFileIconByType(file.fileType)"></i>
                </div>
                <div class="message-file-card-info">
                    <div class="message-file-card-name">{{ file.originalName }}</div>
                    <div class="message-file-card-size">{{ formatFileSize(file.fileSize) }}</div>
                </div>
            </div>
        </template>
    </div>
</div>

九、性能优化策略

9.1 文本预提取优化

通意千应的文本预提取优化策略:

// 上传时预提取文本,避免重复解析
chatFile.setExtractedText(extractedText);

// AI对话时直接使用预提取内容
String extractedText = file.getExtractedText();
if (extractedText != null && !extractedText.isEmpty()) {
    content.append(extractedText);
}

9.2 图片懒加载与压缩

通意千应图片优化策略:

  • 图片上传时生成缩略图预览
  • 使用七牛云图片处理参数进行动态压缩
  • 大图预览时支持缩放和拖拽

9.3 并发控制

// 限制同时处理的文件数量
if (files.size() > 10) {
    return Result.error("最多只能上传10个文件");
}

// 限制图片数量,避免AI Token超限
if (imageCount >= 3) {
    break;
}

十、安全考虑

10.1 文件类型白名单

通意千应的文件类型白名单机制:

private static final Map<String, String> FILE_TYPE_MAP = new LinkedHashMap<>();

static {
    FILE_TYPE_MAP.put("pdf", "PDF文档");
    FILE_TYPE_MAP.put("doc", "Word文档");
    // ... 只允许特定类型
}

public boolean isSupported(String fileName) {
    String ext = getExtension(fileName);
    return ext != null && SUPPORTED_EXTENSIONS.contains(ext.toLowerCase());
}

10.2 文件大小限制

// 单文件100MB限制
if (file.getSize() > 100 * 1024 * 1024) {
    return Result.error("文件大小不能超过100MB");
}

// 图片单独限制10MB
if (file.getSize() > 10 * 1024 * 1024) {
    return Result.error("图片大小不能超过10MB");
}

10.3 用户认证与授权

User user = userService.getCurrentUser();
if (user == null) {
    return Result.error(401, "未登录");
}

// 会话所有权验证
ChatSession session = chatSessionService.getSessionById(sessionId, user.getId());
if (session == null) {
    return Result.error("会话不存在");
}

十一、总结

本文深入剖析了通意千应——一个完整的AI对话系统附件上传功能的实现方案。通意千应具有以下技术特点:

  1. 多类型文件支持:支持PDF、Word、Excel、PPT、图片、TXT等常见格式
  2. 智能内容解析:使用Apache PDFBox、Apache POI等库进行文档解析,支持编码自动检测
  3. 多模态AI集成:图片文件通过Base64编码支持通意千应AI视觉理解能力
  4. 云存储架构:使用七牛云OSS提供可靠的文件存储和CDN加速
  5. 预提取优化:文件上传时即完成内容提取,提升通意千应AI响应速度
  6. 完整的用户体验:支持文件预览、图片缩放、进度显示等交互功能

通意千应的实现方案可为构建企业级AI对话系统的附件功能提供参考。

如果你觉得文章对你有帮助,那就请作者喝杯咖啡吧☕
微信
支付宝
  0 条评论
AI助手
召田最帅boy的小助手
🤖
我是召田最帅boy的小助手
我已经阅读了这篇文章,可以帮您:
理解文章内容 · 解答细节问题 · 分析核心观点