tik集成
This commit is contained in:
2
pom.xml
2
pom.xml
@@ -15,7 +15,7 @@
|
||||
<!-- 各种 module 拓展 -->
|
||||
<module>yudao-module-system</module>
|
||||
<module>yudao-module-infra</module>
|
||||
<!-- <module>yudao-module-member</module>-->
|
||||
<module>yudao-module-member</module>
|
||||
<!-- <module>yudao-module-bpm</module>-->
|
||||
<!-- <module>yudao-module-report</module>-->
|
||||
<!-- <module>yudao-module-mp</module>-->
|
||||
|
||||
@@ -149,6 +149,43 @@
|
||||
<version>${alibaba-ai.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.alibaba</groupId>
|
||||
<artifactId>dashscope-sdk-java</artifactId>
|
||||
<version>2.21.11</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>com.github.victools</groupId>
|
||||
<artifactId>jsonschema-generator</artifactId>
|
||||
</exclusion>
|
||||
<!-- 排除 SDK 自带的 OkHttp 和 Okio -->
|
||||
<exclusion>
|
||||
<groupId>com.squareup.okhttp3</groupId>
|
||||
<artifactId>okhttp</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>com.squareup.okio</groupId>
|
||||
<artifactId>okio</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.squareup.okhttp3</groupId>
|
||||
<artifactId>okhttp</artifactId>
|
||||
<version>4.12.0</version> <!-- 使用较新的稳定版本 -->
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.squareup.okio</groupId>
|
||||
<artifactId>okio</artifactId>
|
||||
<version>3.8.0</version> <!-- 与 OkHttp 4.12.0 严格兼容 -->
|
||||
</dependency>
|
||||
|
||||
<!-- 3. 引入 Kotlin 运行时(OkHttp 4.x+ 必须) -->
|
||||
<dependency>
|
||||
<groupId>org.jetbrains.kotlin</groupId>
|
||||
<artifactId>kotlin-stdlib</artifactId>
|
||||
<version>1.9.20</version> <!-- 与 OkHttp 4.12.0 兼容的版本 -->
|
||||
</dependency>
|
||||
<dependency>
|
||||
<!-- 文心一言 -->
|
||||
<groupId>org.springaicommunity</groupId>
|
||||
|
||||
@@ -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<String,Object> 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<String> callWorkflow(@RequestBody Map<String,Object> 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<ApplicationResult> 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());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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<TikPromptVO> {
|
||||
|
||||
default TikPromptVO getTikPromptVO(String promptType) {
|
||||
return selectOne("prompt_type",promptType);
|
||||
}
|
||||
|
||||
default List<TikPromptVO> getTikPromptVOList() {
|
||||
return selectList();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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<TikTokenVO> {
|
||||
public interface TikTokenMapper extends BaseMapperX<TikTokenVO> {
|
||||
|
||||
default TikTokenVO getPlatformToken(String platformUrl) {
|
||||
return selectOne("platform_url",platformUrl);
|
||||
@@ -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<String> fileLinkList);
|
||||
|
||||
/**
|
||||
*
|
||||
* @param promptType 提示词类型
|
||||
* @param content 提示词内容
|
||||
* @return deepseek改写后的内容
|
||||
*/
|
||||
Object deepseekAnalysis(String promptType,String content);
|
||||
|
||||
}
|
||||
|
||||
@@ -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<String> 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;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -33,11 +33,11 @@
|
||||
</dependency>
|
||||
|
||||
<!-- 会员中心。默认注释,保证编译速度 -->
|
||||
<!-- <dependency>-->
|
||||
<!-- <groupId>cn.iocoder.boot</groupId>-->
|
||||
<!-- <artifactId>yudao-module-member</artifactId>-->
|
||||
<!-- <version>${revision}</version>-->
|
||||
<!-- </dependency>-->
|
||||
<dependency>
|
||||
<groupId>cn.iocoder.boot</groupId>
|
||||
<artifactId>yudao-module-member</artifactId>
|
||||
<version>${revision}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- 数据报表。默认注释,保证编译速度 -->
|
||||
<!-- <dependency>-->
|
||||
|
||||
Reference in New Issue
Block a user