SpringBoot调用LangChain-ChatChat FastAPI上传文件

最近开发的系统的功能之一是要把前端上传的文件保存在MinIO的同时,还要用OCR识别存入ES和LangChain的知识库。LangChain在服务器上搭建好了,FastAPI也准备就绪,就差SpringBoot调用接口上传了,这个问题足足卡了我三四天,随着本地知识库的兴起,遇到这种问题的人应该会有很多,故写此文以供参考。

已知条件

使用Swagger调试FastAPI接口curl的传参结构为

rust 复制代码
curl -X 'POST' \
  'http://xxx/knowledge_base/upload_docs' \
  -H 'accept: application/json' \
  -H 'Content-Type: multipart/form-data' \
  -F 'to_vector_store=true' \
  -F 'override=true' \
  -F 'not_refresh_vs_cache=false' \
  -F 'chunk_size=1000' \
  -F 'chunk_overlap=50' \
  -F 'zh_title_enhance=true' \
  -F 'files=@XXXX.txt;type=text/plain' \
  -F 'knowledge_base_name=ganlan_guichengguifan' \
  -F 'docs='

参数释义:

  • to_vector_store指上传文件后是否进行向量化。
  • override指是否覆盖已有文件。
  • not_refresh_vs_cache指是否暂不保存向量库(用于FAISS)。
  • chunk_size指知识库中单段文本最大长度。
  • chunk_overlap指知识库中相邻文本重合长度。
  • zh_title_enhance指是否开启中文标题加强。
  • files指咱们要上传的文件。
  • docs指自定义的docs,可以为空。

因为传参结构是固定的,所以在SpringBoot中创建对象UploadKnowledgeEntity

java 复制代码
import lombok.Data;
import org.springframework.core.io.FileSystemResource;

@Data
public class UploadKnowledgeEntity {
    /**
     * 上传文件后是否进行向量化
     */
    private boolean to_vector_store;

    /**
     * 覆盖已有文件
     */
    private boolean override;

    /**
     * 暂不保存向量库(用于FAISS)
     */
    private boolean not_refresh_vs_cache;

    /**
     * 知识库中单段文本最大长度
     */
    private int  chunk_size;

    /**
     * 知识库中相邻文本重合长度
     */
    private int chunk_overlap;

    /**
     * 是否开启中文标题加强
     */
    private boolean zh_title_enhance;

    /**
     * 知识库名称
     */
    private String knowledge_base_name;

    /**
     * 文件
     */
    private FileSystemResource files;
}

注意看UploadKnowledgeEntity类中的文件的类型FileSystemResource,这个参数是SpringBoot发出的请求能否被FastAPI接受的关键,原因如下:

查看LangChain的upload_docs方法

python 复制代码
def upload_docs(
    files: List[UploadFile] = File(..., description="上传文件,支持多文件"),
    knowledge_base_name: str = Form(..., description="知识库名称", examples=["samples"]),
    override: bool = Form(False, description="覆盖已有文件"),
    to_vector_store: bool = Form(True, description="上传文件后是否进行向量化"),
    chunk_size: int = Form(CHUNK_SIZE, description="知识库中单段文本最大长度"),
    chunk_overlap: int = Form(OVERLAP_SIZE, description="知识库中相邻文本重合长度"),
    zh_title_enhance: bool = Form(ZH_TITLE_ENHANCE, description="是否开启中文标题加强"),
    docs: Json = Form({}, description="自定义的docs,需要转为json字符串",
                      examples=[{"test.txt": [Document(page_content="custom doc")]}]),
    not_refresh_vs_cache: bool = Form(False, description="暂不保存向量库(用于FAISS)"),

可以看到API的files类型是UploadFile,Python的UploadFile主要用于处理文件上传的场景。在使用requests库进行文件上传时,可以通过files参数来指定文件的位置和名称。

因为Java的FileSystemResource主要用于获取文件系统里面的资源。它既可以作为文件处理,也可以作为URL处理。

两者都可以用于处理文件上传和文件系统资源的获取。

这就是为什么UploadKnowledgeEntity实体里的files文件类型不是File,不是MultipartFile,不是File.getBytes()的原因,因为我他妈这几天都已经试过了,接口全都不认哈哈哈。

有了上述已知条件后,可求得核心代码如下:

java 复制代码
/**
 * 发送post请求
 * @param url
 * @param multipartFile
 * @param fileType
 * @return
 * @throws Exception
 */
public static String doPostJson(String url,MultipartFile multipartFile,String fileType) throws Exception {
    UploadKnowledgeEntity knowledgeEntity=new UploadKnowledgeEntity();
    knowledgeEntity.setOverride(false);
    knowledgeEntity.setTo_vector_store(true);
    knowledgeEntity.setNot_refresh_vs_cache(false);
    knowledgeEntity.setChunk_size(1000);
    knowledgeEntity.setChunk_overlap(50);
    knowledgeEntity.setZh_title_enhance(true);
    knowledgeEntity.setKnowledge_base_name("XXX");
    
    File file=multipartFileToFile(multipartFile);
    FileSystemResource fileSystemResource=new FileSystemResource(file);
    knowledgeEntity.setFiles(fileSystemResource);
    
    try {
        // 组装请求信息
        MultiValueMap<String,Object> param=new LinkedMultiValueMap<>();
        Map<String,Object> map=entityToMap(knowledgeEntity);
        for (Map.Entry<String, Object> entry : map.entrySet()) {
            param.add(entry.getKey(), entry.getValue());
        }

        HttpEntity<MultiValueMap<String,Object> > httpEntity=new HttpEntity<>(param);
        RestTemplate restTemplate=new RestTemplate();
        KnowledgeAnswer response=restTemplate.postForObject(url,httpEntity,KnowledgeAnswer.class);
        return "文件上传成功";
    } catch (Exception e) {
        throw new RuntimeException("[发送POST请求错误:]" + e.getMessage());
    }
}

测试文件上传,响应内容:

json 复制代码
{
  "success": true,
  "message": "文件上传成功",
  "code": 200,
  "result": "文件上传成功",
  "timestamp": 1702541585135
}
相关推荐
毕设源码-钟学长4 小时前
【开题答辩全过程】以 基于Springboot的扶贫众筹平台为例,包含答辩的问题和答案
java·spring boot·后端
ZH15455891314 小时前
Flutter for OpenHarmony Python学习助手实战:GUI桌面应用开发的实现
python·学习·flutter
B站计算机毕业设计超人4 小时前
计算机毕业设计Hadoop+Spark+Hive招聘推荐系统 招聘大数据分析 大数据毕业设计(源码+文档+PPT+ 讲解)
大数据·hive·hadoop·python·spark·毕业设计·课程设计
B站计算机毕业设计超人4 小时前
计算机毕业设计hadoop+spark+hive交通拥堵预测 交通流量预测 智慧城市交通大数据 交通客流量分析(源码+LW文档+PPT+讲解视频)
大数据·hive·hadoop·python·spark·毕业设计·课程设计
CodeSheep程序羊4 小时前
拼多多春节加班工资曝光,没几个敢给这个数的。
java·c语言·开发语言·c++·python·程序人生·职场和发展
独好紫罗兰4 小时前
对python的再认识-基于数据结构进行-a002-列表-列表推导式
开发语言·数据结构·python
机器学习之心HML5 小时前
多光伏电站功率预测新思路:当GCN遇见LSTM,解锁时空预测密码,python代码
人工智能·python·lstm
2401_841495645 小时前
【LeetCode刷题】二叉树的直径
数据结构·python·算法·leetcode·二叉树··递归
王大傻09285 小时前
python 读取文件可以使用open函数的 r 模式
python
JarryStudy5 小时前
HCCL与PyTorch集成 hccl_comm.cpp DDP后端注册全流程
人工智能·pytorch·python·cann