diff --git a/ruoyi-admin/src/main/resources/application-dev.yml b/ruoyi-admin/src/main/resources/application-dev.yml
index 8abf1a68..e51f0019 100644
--- a/ruoyi-admin/src/main/resources/application-dev.yml
+++ b/ruoyi-admin/src/main/resources/application-dev.yml
@@ -85,4 +85,15 @@ sms:
# 腾讯专用
sdkAppId:
+pdf:
+ extract:
+ service:
+ url: http://localhost:8080
+ ai-api:
+ url: https://api.pandarobot.chat/v1/chat/completions
+ key: sk-xxxx
+#百炼模型配置
+dashscope:
+ key: sk-xxxx
+ model: qvq-max
diff --git a/ruoyi-admin/src/main/resources/application-local.yml b/ruoyi-admin/src/main/resources/application-local.yml
new file mode 100644
index 00000000..95bb3a93
--- /dev/null
+++ b/ruoyi-admin/src/main/resources/application-local.yml
@@ -0,0 +1,111 @@
+--- # 监控中心配置
+spring.boot.admin.client:
+ # 增加客户端开关
+ enabled: false
+ url: http://localhost:9090/admin
+ instance:
+ service-host-type: IP
+ username: ruoyi
+ password: 123456
+
+--- # 数据源配置
+spring:
+ datasource:
+ type: com.zaxxer.hikari.HikariDataSource
+ # 动态数据源文档 https://www.kancloud.cn/tracy5546/dynamic-datasource/content
+ dynamic:
+ # 性能分析插件(有性能损耗 不建议生产环境使用)
+ p6spy: true
+ # 设置默认的数据源或者数据源组,默认值即为 master
+ primary: master
+ # 严格模式 匹配不到数据源则报错
+ strict: true
+ datasource:
+ # 主库数据源
+ master:
+ type: ${spring.datasource.type}
+ driverClassName: com.mysql.cj.jdbc.Driver
+ url: jdbc:mysql://localhost:3306/ruoyi-ai?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true
+ username: root
+ password: root
+
+
+ hikari:
+ # 最大连接池数量
+ maxPoolSize: 20
+ # 最小空闲线程数量
+ minIdle: 10
+ # 配置获取连接等待超时的时间
+ connectionTimeout: 30000
+ # 校验超时时间
+ validationTimeout: 5000
+ # 空闲连接存活最大时间,默认10分钟
+ idleTimeout: 600000
+ # 此属性控制池中连接的最长生命周期,值0表示无限生命周期,默认30分钟
+ maxLifetime: 1800000
+ # 连接测试query(配置检测连接是否有效)
+ connectionTestQuery: SELECT 1
+ # 多久检查一次连接的活性
+ keepaliveTime: 30000
+
+--- # redis 单机配置(单机与集群只能开启一个另一个需要注释掉)
+spring.data:
+ redis:
+ # 地址
+ host: 127.0.0.1
+ # 端口,默认为6379
+ port: 6379
+ # 数据库索引
+ database: 0
+ # 密码(如没有密码请注释掉)
+ password: root
+ # 连接超时时间
+ timeout: 10S
+ # 是否开启ssl
+ ssl: false
+
+redisson:
+ # redis key前缀
+ keyPrefix:
+ # 线程池数量
+ threads: 4
+ # Netty线程池数量
+ nettyThreads: 8
+ # 单节点配置
+ singleServerConfig:
+ # 客户端名称
+ clientName: ${ruoyi.name}
+ # 最小空闲连接数
+ connectionMinimumIdleSize: 8
+ # 连接池大小
+ connectionPoolSize: 32
+ # 连接空闲超时,单位:毫秒
+ idleConnectionTimeout: 10000
+ # 命令等待超时,单位:毫秒
+ timeout: 3000
+ # 发布和订阅连接池大小
+ subscriptionConnectionPoolSize: 50
+
+--- # sms 短信
+sms:
+ enabled: false
+ # 阿里云 dysmsapi.aliyuncs.com
+ # 腾讯云 sms.tencentcloudapi.com
+ endpoint: "dysmsapi.aliyuncs.com"
+ accessKeyId: xxxxxxx
+ accessKeySecret: xxxxxx
+ signName: 测试
+ # 腾讯专用
+ sdkAppId:
+
+pdf:
+ extract:
+ service:
+ url: http://localhost:8080
+ ai-api:
+ url: https://api.pandarobot.chat/v1/chat/completions
+ key: sk-xxxx
+#百炼模型配置
+dashscope:
+ key: sk-xxxx
+ model: qvq-max
\ No newline at end of file
diff --git a/ruoyi-modules-api/ruoyi-knowledge-api/pom.xml b/ruoyi-modules-api/ruoyi-knowledge-api/pom.xml
index f7e91879..2a3e634c 100644
--- a/ruoyi-modules-api/ruoyi-knowledge-api/pom.xml
+++ b/ruoyi-modules-api/ruoyi-knowledge-api/pom.xml
@@ -89,6 +89,12 @@
langchain4j-document-parser-apache-tika
+
+ com.alibaba
+ dashscope-sdk-java
+ 2.19.0
+
+
diff --git a/ruoyi-modules-api/ruoyi-knowledge-api/src/main/java/org/ruoyi/service/DashscopeService.java b/ruoyi-modules-api/ruoyi-knowledge-api/src/main/java/org/ruoyi/service/DashscopeService.java
new file mode 100644
index 00000000..3c8f498e
--- /dev/null
+++ b/ruoyi-modules-api/ruoyi-knowledge-api/src/main/java/org/ruoyi/service/DashscopeService.java
@@ -0,0 +1,23 @@
+package org.ruoyi.service;
+
+import java.io.IOException;
+
+/**
+ * @Description: 阿里百炼api
+ * @Date: 2025/6/4 下午2:24
+ */
+public interface DashscopeService {
+
+ /**
+ * 视觉推理(QVQ)
+ * @param imageUrl 图片可访问的地址
+ * @return
+ */
+ String qvq(String imageUrl) throws IOException;
+ /**
+ * 视觉推理(QVQ) 使用本地文件(输入Base64编码或本地路径)
+ * @param localPath 图片文件的绝对路径
+ * @return
+ */
+ String qvq4LocalPath(String localPath) throws IOException;
+}
diff --git a/ruoyi-modules-api/ruoyi-knowledge-api/src/main/java/org/ruoyi/service/PdfImageExtractService.java b/ruoyi-modules-api/ruoyi-knowledge-api/src/main/java/org/ruoyi/service/PdfImageExtractService.java
new file mode 100644
index 00000000..c9929786
--- /dev/null
+++ b/ruoyi-modules-api/ruoyi-knowledge-api/src/main/java/org/ruoyi/service/PdfImageExtractService.java
@@ -0,0 +1,34 @@
+
+ /**
+ * 处理文件内容
+ *
+ * @param unzip Base64编码的图片数组
+ * @return 文件内容结果列表
+ * @throws IOException 如果API调用过程中发生错误
+ */
+ List dealFileContent(String[] unzip) throws IOException;
+ /**
+ *利用百炼接口处理文件内容
+ *
+ * @param imageUrl 传入图片地址
+ * @return 文件内容结果列表
+ * @throws IOException 如果API调用过程中发生错误
+ */
+ List dealFileContent4Dashscope(String imageUrl) throws IOException;
+
+ /**
+ * 利用百炼接口处理文件内容
+ *
+ * 视觉推理(QVQ) 使用本地文件(输入Base64编码或本地路径)
+ * @param localPath 图片文件的绝对路径
+ * @return
+ */
+ List dealFileContent4DashscopeBase64(String localPath)throws IOException;
+ /**
+ * 提取PDF中的图片并调用gpt-4o-mini,识别图片内容并返回
+ * @param file
+ * @return
+ * @throws IOException
+ */
+ List extractImages(MultipartFile file) throws IOException;
+}
diff --git a/ruoyi-modules-api/ruoyi-knowledge-api/src/main/java/org/ruoyi/service/impl/DashscopeServiceImpl.java b/ruoyi-modules-api/ruoyi-knowledge-api/src/main/java/org/ruoyi/service/impl/DashscopeServiceImpl.java
new file mode 100644
index 00000000..0f6b0014
--- /dev/null
+++ b/ruoyi-modules-api/ruoyi-knowledge-api/src/main/java/org/ruoyi/service/impl/DashscopeServiceImpl.java
@@ -0,0 +1,150 @@
+package org.ruoyi.service.impl;
+
+import com.alibaba.dashscope.aigc.multimodalconversation.MultiModalConversation;
+import com.alibaba.dashscope.aigc.multimodalconversation.MultiModalConversationParam;
+import com.alibaba.dashscope.aigc.multimodalconversation.MultiModalConversationResult;
+import com.alibaba.dashscope.common.MultiModalMessage;
+import com.alibaba.dashscope.common.Role;
+import io.reactivex.Flowable;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import lombok.extern.slf4j.Slf4j;
+import org.ruoyi.domain.PdfFileContentResult;
+import org.ruoyi.service.DashscopeService;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Service;
+
+/**
+ * @Description: 阿里百炼API
+ * @Date: 2025/6/4 下午2:28
+ */
+@Service
+@Slf4j
+public class DashscopeServiceImpl implements DashscopeService {
+
+ private boolean isFirstPrint;
+
+ @Value("${dashscope.model}")
+ private String serviceModel;
+ @Value("${dashscope.key}")
+ private String serviceKey;
+
+ /**
+ * 视觉推理(QVQ)
+ * @param imageUrl 图片可访问地址
+ * @return
+ */
+ @Override
+ public String qvq(String imageUrl) throws IOException {
+ try {
+ // 构建多模态消息
+ MultiModalMessage userMessage = MultiModalMessage.builder()
+ .role(Role.USER.getValue())
+ .content(Arrays.asList(
+ Collections.singletonMap("text", "这张图片有什么"),
+ Collections.singletonMap("image", imageUrl)
+ ))
+ .build();
+
+ // 构建请求参数
+ MultiModalConversationParam param = MultiModalConversationParam.builder()
+ .apiKey(serviceKey) // 使用配置文件中的API Key
+ .model(serviceModel)
+ .message(userMessage)
+ .build();
+
+ MultiModalConversation conv = new MultiModalConversation();
+
+ // 调用API
+ Flowable result = conv.streamCall(
+ param);
+
+ StringBuilder reasoningContent = new StringBuilder();
+ StringBuilder finalContent = new StringBuilder();
+ isFirstPrint = true;
+
+ result.blockingForEach(message -> handleGenerationResult(message, reasoningContent, finalContent));
+
+ return finalContent.toString().replaceAll("[\n\r\s]", "");
+ } catch (Exception e) {
+ log.error("调用百炼API失败: {}", e.getMessage(), e);
+ throw new IOException("百炼API调用失败: " + e.getMessage(), e);
+ }
+ }
+ /**
+ * 视觉推理(QVQ) 使用本地文件(输入Base64编码或本地路径)
+ * @param localPath 图片文件的绝对路径
+ * @return
+ */
+ @Override
+ public String qvq4LocalPath(String localPath) throws IOException {
+ try {
+ // 构建多模态消息
+ String filePath = "file://"+ localPath;
+ log.info("filePath: {}", filePath);
+ MultiModalMessage userMessage = MultiModalMessage.builder().role(Role.USER.getValue())
+ .content(Arrays.asList(new HashMap(){{put("image", filePath);}},
+ new HashMap(){{put("text", "这张图片有什么");}})).build();
+
+ // 构建请求参数
+ MultiModalConversationParam param = MultiModalConversationParam.builder()
+ .apiKey(serviceKey) // 使用配置文件中的API Key
+ .model(serviceModel)
+ .message(userMessage)
+ .build();
+ MultiModalConversation conv = new MultiModalConversation();
+
+ // 调用API
+ Flowable result = conv.streamCall(
+ param);
+
+ StringBuilder reasoningContent = new StringBuilder();
+ StringBuilder finalContent = new StringBuilder();
+ isFirstPrint = true;
+
+ result.blockingForEach(message -> handleGenerationResult(message, reasoningContent, finalContent));
+
+ return finalContent.toString().replaceAll("[\n\r\s]", "");
+ } catch (Exception e) {
+ log.error("调用百炼API失败: {}", e.getMessage(), e);
+ throw new IOException("百炼API调用失败: " + e.getMessage(), e);
+ }
+ }
+
+
+ private void handleGenerationResult(MultiModalConversationResult message, StringBuilder reasoningContent, StringBuilder finalContent) {
+ String re = message.getOutput().getChoices().get(0).getMessage().getReasoningContent();
+ String reasoning = Objects.isNull(re) ? "" : re;
+
+ List