diff --git a/pom.xml b/pom.xml
index 5df1abae8d..bc99634106 100644
--- a/pom.xml
+++ b/pom.xml
@@ -15,7 +15,7 @@
yudao-module-system
yudao-module-infra
-
+ yudao-module-member
diff --git a/yudao-module-ai/pom.xml b/yudao-module-ai/pom.xml
index 8773e02a9a..4f545f9a1a 100644
--- a/yudao-module-ai/pom.xml
+++ b/yudao-module-ai/pom.xml
@@ -149,6 +149,43 @@
${alibaba-ai.version}
+
+ com.alibaba
+ dashscope-sdk-java
+ 2.21.11
+
+
+ com.github.victools
+ jsonschema-generator
+
+
+
+ com.squareup.okhttp3
+ okhttp
+
+
+ com.squareup.okio
+ okio
+
+
+
+
+ com.squareup.okhttp3
+ okhttp
+ 4.12.0
+
+
+ com.squareup.okio
+ okio
+ 3.8.0
+
+
+
+
+ org.jetbrains.kotlin
+ kotlin-stdlib
+ 1.9.20
+
org.springaicommunity
diff --git a/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/tikhup/TikHupController.java b/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/tikhup/TikHupController.java
index 7e7a0114a9..50eceff67d 100644
--- a/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/tikhup/TikHupController.java
+++ b/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/tikhup/TikHupController.java
@@ -1,10 +1,23 @@
package cn.iocoder.yudao.module.ai.controller.admin.tikhup;
+import cn.iocoder.yudao.framework.common.pojo.CommonResult;
+import cn.iocoder.yudao.module.ai.dal.mysql.tikhup.TikPromptMapper;
import cn.iocoder.yudao.module.ai.service.tikhup.TikHupService;
+import com.alibaba.dashscope.app.Application;
+import com.alibaba.dashscope.app.ApplicationParam;
+import com.alibaba.dashscope.app.ApplicationResult;
+import com.alibaba.dashscope.app.FlowStreamMode;
+import com.alibaba.dashscope.utils.Constants;
+import com.alibaba.dashscope.utils.JsonUtils;
+import com.alibaba.fastjson.JSON;
+import io.reactivex.Flowable;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;
+import reactor.core.publisher.Flux;
+import reactor.core.scheduler.Schedulers;
import java.util.List;
import java.util.Map;
@@ -13,10 +26,13 @@ import java.util.Map;
@RestController
@RequestMapping("/ai/tikHup")
@RequiredArgsConstructor
+@Slf4j
public class TikHupController {
private final TikHupService tikHupService;
+ private final TikPromptMapper tikPromptMapper;
+
@GetMapping("/fetch_user_post_videos")
@Operation(
summary = "获取用户主页作品数据",
@@ -44,4 +60,68 @@ public class TikHupController {
return tikHupService.videoToCharacters2(fileLinkList);
}
+
+
+ @GetMapping("/getPromptTypeList")
+ @Operation(summary = "获取提示词类型列表", description = "获取提示词类型列表")
+ public Object getPromptTypeList(){
+ return CommonResult.success(tikPromptMapper.getTikPromptVOList());
+ }
+
+
+ @PostMapping("/deepseekAnalysis")
+ @Operation(summary = "deepseek文案重写", description = "deepseek文案重写")
+ public Object deepseekAnalysis(@RequestBody Map contentMap){
+ String content = (String) contentMap.get("content");
+ String promptType = (String) contentMap.get("promptType");
+ return tikHupService.deepseekAnalysis(promptType,content);
+ }
+
+ @PostMapping("/callWorkflow")
+ @Operation(summary = "调用阿里工作流", description = "调用阿里工作流 文档地址:https://help.aliyun.com/zh/model-studio/invoke-workflow-application?mode=pure#8f4b4d2ce9fry")
+ public Flux callWorkflow(@RequestBody Map params){
+ Constants.baseHttpApiUrl = "https://dashscope.aliyuncs.com/api/v1";
+ ApplicationParam param = ApplicationParam.builder()
+ // 若没有配置环境变量,可用百炼API Key将下行替换为:.apiKey("sk-xxx")。但不建议在生产环境中直接将API Key硬编码到代码中,以减少API Key泄露风险。
+ .apiKey("sk-10c746f8cb8640738f8d6b71af699003")
+ .appId("bb746b74bfb0439e841cb309dc9f945c")
+ .flowStreamMode(FlowStreamMode.MESSAGE_FORMAT)
+ .bizParams(JsonUtils.parse(JSON.toJSONString(params)))
+ .prompt((String) params.get("audio_prompt"))
+ .hasThoughts(false)
+ .incrementalOutput(true)
+ .build();
+ Application application = new Application();
+ try{
+ //ApplicationResult result = application.call(param);
+ //return CommonResult.success(result.getOutput().getText());
+ Flowable flowableResult = application.streamCall(param);
+ // 关键:RxJava Flowable 转 WebFlux Flux,指定非阻塞线程调度
+ // 4.2 将 RxJava Flowable 转换为 WebFlux Flux(响应式转换,无阻塞)
+ return Flux.from(flowableResult)
+ // 关键:切换到非阻塞线程执行(避免阻塞 WebFlux 事件循环)
+ .subscribeOn(Schedulers.boundedElastic())
+ // 4.3 处理每一条流式数据:提取 thoughts 字段(按你的需求,也可提取 text)
+ .map(applicationResult -> {
+ // 校验结果非 null(阿里 SDK 可能返回空结果)
+ if (applicationResult == null || applicationResult.getOutput() == null) {
+ log.warn("收到空的流式结果");
+ return "空结果";
+ }
+ return applicationResult.getOutput().getWorkflowMessage().getMessage().getContent();
+ })
+ // 4.4 流处理异常捕获(如网络中断、阿里 SDK 内部错误)
+ .onErrorMap(e -> {
+ log.error("流式处理异常", e); // 打印完整异常栈,便于排查
+ return new RuntimeException("流式处理错误:" + e.getMessage());
+ })
+ // 4.5 异常时返回默认提示(前端不会断连,而是接收错误信息)
+ .onErrorReturn("错误:流式处理中断:" + "请重试或联系管理员");
+ }catch (Exception e){
+ // 捕获 SDK 调用时的同步异常(如初始化失败、网络连接超时)
+ log.error("调用阿里 SDK 失败", e);
+ return Flux.just("错误:SDK 调用失败:" + e.getMessage());
+ }
+ }
+
}
diff --git a/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/tikhup/vo/TikPromptVO.java b/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/tikhup/vo/TikPromptVO.java
new file mode 100644
index 0000000000..c0b8a4b01b
--- /dev/null
+++ b/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/tikhup/vo/TikPromptVO.java
@@ -0,0 +1,20 @@
+package cn.iocoder.yudao.module.ai.controller.admin.tikhup.vo;
+
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Data;
+
+@TableName("tik_prompt")
+@Data
+public class TikPromptVO {
+
+ @TableField(value = "prompt_type")
+ private String promptType;
+
+ @TableField(value = "prompt_name")
+ private String promptName;
+
+ @TableField(value = "prompt")
+ private String prompt;
+
+}
diff --git a/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/tikhup/vo/TikTokenVO.java b/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/tikhup/vo/TikTokenVO.java
index cf8db27f28..6913526c49 100644
--- a/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/tikhup/vo/TikTokenVO.java
+++ b/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/tikhup/vo/TikTokenVO.java
@@ -2,29 +2,15 @@ package cn.iocoder.yudao.module.ai.controller.admin.tikhup.vo;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableName;
-import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
-@Schema(description = "TikToken - TikToken管理 Request VO")
@TableName("tik_token")
@Data
public class TikTokenVO {
- @Schema(
- description = "TikHup平台API地址",
- requiredMode = Schema.RequiredMode.REQUIRED,
- example = "https://api.tikhub.io/api/v1/xiaohongshu/app/get_user_info",
- title = "平台API地址"
- )
@TableField(value = "platform_url")
private String platformUrl;
- @Schema(
- description = "TikHup平台访问Token,用于API认证",
- requiredMode = Schema.RequiredMode.REQUIRED,
- example = "y15aJOgphU+dik4QGaCW3CL2bR7eQ6ZA2Tz3tUe8c6ycoW27OX+zRTO6Ow==",
- title = "平台访问Token"
- )
@TableField(value = "platform_token")
private String platformToken;
diff --git a/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/dal/mysql/tikhup/TikPromptMapper.java b/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/dal/mysql/tikhup/TikPromptMapper.java
new file mode 100644
index 0000000000..7a05739326
--- /dev/null
+++ b/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/dal/mysql/tikhup/TikPromptMapper.java
@@ -0,0 +1,20 @@
+package cn.iocoder.yudao.module.ai.dal.mysql.tikhup;
+
+import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
+import cn.iocoder.yudao.module.ai.controller.admin.tikhup.vo.TikPromptVO;
+import org.apache.ibatis.annotations.Mapper;
+
+import java.util.List;
+
+@Mapper
+public interface TikPromptMapper extends BaseMapperX {
+
+ default TikPromptVO getTikPromptVO(String promptType) {
+ return selectOne("prompt_type",promptType);
+ }
+
+ default List getTikPromptVOList() {
+ return selectList();
+ }
+
+}
diff --git a/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/dal/mysql/tikhup/TikHupMapper.java b/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/dal/mysql/tikhup/TikTokenMapper.java
similarity index 84%
rename from yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/dal/mysql/tikhup/TikHupMapper.java
rename to yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/dal/mysql/tikhup/TikTokenMapper.java
index 442e848a85..689b00424e 100644
--- a/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/dal/mysql/tikhup/TikHupMapper.java
+++ b/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/dal/mysql/tikhup/TikTokenMapper.java
@@ -5,7 +5,7 @@ import cn.iocoder.yudao.module.ai.controller.admin.tikhup.vo.TikTokenVO;
import org.apache.ibatis.annotations.Mapper;
@Mapper
-public interface TikHupMapper extends BaseMapperX {
+public interface TikTokenMapper extends BaseMapperX {
default TikTokenVO getPlatformToken(String platformUrl) {
return selectOne("platform_url",platformUrl);
diff --git a/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/service/tikhup/TikHupService.java b/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/service/tikhup/TikHupService.java
index 2801f03209..a932b48ab5 100644
--- a/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/service/tikhup/TikHupService.java
+++ b/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/service/tikhup/TikHupService.java
@@ -1,6 +1,9 @@
package cn.iocoder.yudao.module.ai.service.tikhup;
+import org.springframework.web.bind.annotation.RequestBody;
+
import java.util.List;
+import java.util.Map;
public interface TikHupService {
@@ -27,4 +30,12 @@ public interface TikHupService {
*/
Object videoToCharacters2(List fileLinkList);
+ /**
+ *
+ * @param promptType 提示词类型
+ * @param content 提示词内容
+ * @return deepseek改写后的内容
+ */
+ Object deepseekAnalysis(String promptType,String content);
+
}
diff --git a/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/service/tikhup/TikHupServiceImpl.java b/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/service/tikhup/TikHupServiceImpl.java
index e4e1e0fcd6..2e586a273f 100644
--- a/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/service/tikhup/TikHupServiceImpl.java
+++ b/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/service/tikhup/TikHupServiceImpl.java
@@ -2,8 +2,10 @@ package cn.iocoder.yudao.module.ai.service.tikhup;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils;
+import cn.iocoder.yudao.module.ai.controller.admin.tikhup.vo.TikPromptVO;
import cn.iocoder.yudao.module.ai.controller.admin.tikhup.vo.TikTokenVO;
-import cn.iocoder.yudao.module.ai.dal.mysql.tikhup.TikHupMapper;
+import cn.iocoder.yudao.module.ai.dal.mysql.tikhup.TikPromptMapper;
+import cn.iocoder.yudao.module.ai.dal.mysql.tikhup.TikTokenMapper;
import com.alibaba.dashscope.audio.asr.transcription.Transcription;
import com.alibaba.dashscope.audio.asr.transcription.TranscriptionParam;
import com.alibaba.dashscope.audio.asr.transcription.TranscriptionQueryParam;
@@ -25,7 +27,9 @@ import java.util.List;
@RequiredArgsConstructor
public class TikHupServiceImpl implements TikHupService{
- private final TikHupMapper tikHupMapper;
+ private final TikTokenMapper tikTokenMapper;
+
+ private final TikPromptMapper tikPromptMapper;
@Override
public Object fetch_user_post_videos(String type,String sec_user_id, int max_cursor, int count){
@@ -37,7 +41,7 @@ public class TikHupServiceImpl implements TikHupService{
} else if("tik-app".equals(type)){
url = "https://api.tikhub.io/api/v1/douyin/app/v3/fetch_user_post_videos";
}
- TikTokenVO tikTokenVO = tikHupMapper.getPlatformToken(url);
+ TikTokenVO tikTokenVO = tikTokenMapper.getPlatformToken(url);
String Authorization = tikTokenVO.getPlatformToken();
try{
Unirest.setTimeouts(0, 0);
@@ -57,6 +61,7 @@ public class TikHupServiceImpl implements TikHupService{
private final String appKey = "sldJ4XSpYp3rKALZ ";
private final String accessKeyId = "LTAI5tPV9Ag3csf41GZjaLTA";
private final String accessKeySecret = "kDqlGeJTKw6tJtFYiaY8vQTFuVIQDs";
+ private final String deepseekApiKey="sk-7f666f993b144d279ae375a015e4de56";
@Override
public Object videoToCharacters(String fileLink){
@@ -104,4 +109,26 @@ public class TikHupServiceImpl implements TikHupService{
}
+
+ public Object deepseekAnalysis(String promptType,String content){
+ Unirest.setTimeouts(0, 0);
+ try{
+ TikPromptVO tikPromptVO = tikPromptMapper.getTikPromptVO(promptType);
+ HttpResponse response = Unirest.post("https://api.deepseek.com/chat/completions")
+ .header("Content-Type", "application/json")
+ .header("Accept", "application/json")
+ .header("Authorization", "Bearer " + deepseekApiKey)
+ .body("{\n \"messages\": [\n {\n \"content\": \""+tikPromptVO.getPrompt()+"\n\n\n原文如下:\n"+content+"\",\n \"role\": \"system\"\n },\n {\n \"content\": \"Hi\",\n \"role\": \"user\"\n }\n ],\n \"model\": \"deepseek-chat\",\n \"frequency_penalty\": 0,\n \"max_tokens\": 8000,\n \"presence_penalty\": 0,\n \"response_format\": {\n \"type\": \"text\"\n },\n \"stop\": null,\n \"stream\": false,\n \"stream_options\": null,\n \"temperature\": 1,\n \"top_p\": 1,\n \"tools\": null,\n \"tool_choice\": \"none\",\n \"logprobs\": false,\n \"top_logprobs\": null\n}")
+ .asString();
+ if(response.getStatus() == 200){
+ return response.getBody();
+ }
+ }catch (Exception e){
+ log.error(e.getMessage());
+ return CommonResult.error(500,"文案改写失败!");
+ }
+ return null;
+
+ }
+
}
diff --git a/yudao-server/pom.xml b/yudao-server/pom.xml
index b4c9bb04ac..d4f7b570ab 100644
--- a/yudao-server/pom.xml
+++ b/yudao-server/pom.xml
@@ -33,11 +33,11 @@
-
-
-
-
-
+
+ cn.iocoder.boot
+ yudao-module-member
+ ${revision}
+