This commit is contained in:
van
2026-04-04 16:20:46 +08:00
parent c31a34f519
commit 74e7990947
3 changed files with 183 additions and 0 deletions

View File

@@ -156,6 +156,50 @@ public class SocialMediaController extends BaseController
}
}
/**
* 获取大模型接入配置API 地址、密钥等,与 Jarvis 共用 Redis
*/
@GetMapping("/llm-config")
public AjaxResult getLlmConfig()
{
try {
return socialMediaService.getLlmConfig();
} catch (Exception e) {
logger.error("获取大模型接入配置失败", e);
return AjaxResult.error("获取失败: " + e.getMessage());
}
}
/**
* 保存大模型接入配置
*/
@Log(title = "保存大模型接入配置", businessType = BusinessType.UPDATE)
@PostMapping("/llm-config/save")
public AjaxResult saveLlmConfig(@RequestBody Map<String, Object> request)
{
try {
return socialMediaService.saveLlmConfig(request);
} catch (Exception e) {
logger.error("保存大模型接入配置失败", e);
return AjaxResult.error("保存失败: " + e.getMessage());
}
}
/**
* 清除大模型接入配置Jarvis 使用 yml 默认 Ollama
*/
@Log(title = "重置大模型接入配置", businessType = BusinessType.DELETE)
@DeleteMapping("/llm-config")
public AjaxResult resetLlmConfig()
{
try {
return socialMediaService.resetLlmConfig();
} catch (Exception e) {
logger.error("重置大模型接入配置失败", e);
return AjaxResult.error("重置失败: " + e.getMessage());
}
}
/**
* 闲鱼文案(手动):根据标题+可选型号生成代下单、教你下单文案不依赖JD接口
*/

View File

@@ -72,5 +72,20 @@ public interface ISocialMediaService
* @return 包含代下单、教你下单两种文案的 Map
*/
Map<String, Object> generateXianyuWenan(String title, String remark);
/**
* 获取社媒大模型接入配置(与 Jarvis 共用 Redis供 OpenAI 兼容接口或 Ollama
*/
com.ruoyi.common.core.domain.AjaxResult getLlmConfig();
/**
* 保存社媒大模型接入配置
*/
com.ruoyi.common.core.domain.AjaxResult saveLlmConfig(Map<String, Object> request);
/**
* 清除 Redis 中的接入配置Jarvis 侧回退为 application.yml 默认 Ollama
*/
com.ruoyi.common.core.domain.AjaxResult resetLlmConfig();
}

View File

@@ -52,6 +52,15 @@ public class SocialMediaServiceImpl implements ISocialMediaService
put("content:both", "通用文案生成提示词模板\n占位符%s - 商品名称,%s - 价格信息,%s - 关键词信息");
}};
/** 与 Jarvis_java SocialMediaLlmClient 使用相同 Redis 键 */
private static final String LLM_KEY_MODE = "social_media:llm:mode";
private static final String LLM_KEY_BASE_URL = "social_media:llm:base_url";
private static final String LLM_KEY_API_KEY = "social_media:llm:api_key";
private static final String LLM_KEY_MODEL = "social_media:llm:model";
private static final String LLM_MODE_OLLAMA = "ollama";
private static final String LLM_MODE_OPENAI = "openai";
/** 闲鱼文案-通用基础说明 */
private static final String WENAN_BASE =
"全新未拆封正品,包邮包安装,支持查验后再签收。\n"
@@ -433,6 +442,121 @@ public class SocialMediaServiceImpl implements ISocialMediaService
}
}
@Override
public AjaxResult getLlmConfig() {
try {
Map<String, Object> data = new HashMap<>();
if (redisTemplate == null) {
data.put("redisAvailable", false);
data.put("mode", LLM_MODE_OLLAMA);
data.put("baseUrl", "");
data.put("model", "");
data.put("hasApiKey", false);
data.put("apiKeyMasked", null);
return AjaxResult.success(data);
}
data.put("redisAvailable", true);
String modeRaw = StringUtils.trim(redisTemplate.opsForValue().get(LLM_KEY_MODE));
String mode = StringUtils.isEmpty(modeRaw) ? LLM_MODE_OLLAMA : modeRaw.toLowerCase();
data.put("mode", mode);
data.put("baseUrl", StringUtils.trim(redisTemplate.opsForValue().get(LLM_KEY_BASE_URL)));
data.put("model", StringUtils.trim(redisTemplate.opsForValue().get(LLM_KEY_MODEL)));
String rawKey = redisTemplate.opsForValue().get(LLM_KEY_API_KEY);
boolean hasKey = StringUtils.isNotEmpty(StringUtils.trim(rawKey));
data.put("hasApiKey", hasKey);
data.put("apiKeyMasked", maskLlmApiKey(rawKey));
return AjaxResult.success(data);
} catch (Exception e) {
log.error("读取大模型接入配置失败", e);
return AjaxResult.error("读取失败: " + e.getMessage());
}
}
private static String maskLlmApiKey(String secret) {
if (StringUtils.isEmpty(StringUtils.trim(secret))) {
return null;
}
String s = secret.trim();
if (s.length() <= 4) {
return "****";
}
return "****" + s.substring(s.length() - 4);
}
@Override
public AjaxResult saveLlmConfig(Map<String, Object> request) {
try {
if (redisTemplate == null) {
return AjaxResult.error("Redis未配置无法保存");
}
String mode = request.get("mode") == null ? "" : request.get("mode").toString().trim().toLowerCase();
if (!LLM_MODE_OLLAMA.equals(mode) && !LLM_MODE_OPENAI.equals(mode)) {
return AjaxResult.error("接入方式只能是 ollama 或 openai");
}
String baseUrl = request.get("baseUrl") == null ? "" : request.get("baseUrl").toString().trim();
String model = request.get("model") == null ? "" : request.get("model").toString().trim();
if (LLM_MODE_OPENAI.equals(mode)) {
if (StringUtils.isEmpty(baseUrl)) {
return AjaxResult.error("OpenAI 兼容模式须填写 Chat Completions 完整地址(如 https://api.openai.com/v1/chat/completions");
}
if (StringUtils.isEmpty(model)) {
return AjaxResult.error("OpenAI 兼容模式须填写模型名称");
}
}
boolean clearApiKey = Boolean.TRUE.equals(request.get("clearApiKey"))
|| "true".equalsIgnoreCase(String.valueOf(request.get("clearApiKey")));
if (clearApiKey) {
redisTemplate.delete(LLM_KEY_API_KEY);
}
Object apiKeyObj = request.get("apiKey");
if (!clearApiKey && apiKeyObj != null) {
String newKey = apiKeyObj.toString().trim();
if (StringUtils.isNotEmpty(newKey)) {
redisTemplate.opsForValue().set(LLM_KEY_API_KEY, newKey);
}
}
redisTemplate.opsForValue().set(LLM_KEY_MODE, mode);
if (StringUtils.isEmpty(baseUrl)) {
redisTemplate.delete(LLM_KEY_BASE_URL);
} else {
redisTemplate.opsForValue().set(LLM_KEY_BASE_URL, baseUrl);
}
if (StringUtils.isEmpty(model)) {
redisTemplate.delete(LLM_KEY_MODEL);
} else {
redisTemplate.opsForValue().set(LLM_KEY_MODEL, model);
}
log.info("保存大模型接入配置成功, mode={}", mode);
return AjaxResult.success("保存成功");
} catch (Exception e) {
log.error("保存大模型接入配置失败", e);
return AjaxResult.error("保存失败: " + e.getMessage());
}
}
@Override
public AjaxResult resetLlmConfig() {
try {
if (redisTemplate == null) {
return AjaxResult.error("Redis未配置");
}
redisTemplate.delete(LLM_KEY_MODE);
redisTemplate.delete(LLM_KEY_BASE_URL);
redisTemplate.delete(LLM_KEY_API_KEY);
redisTemplate.delete(LLM_KEY_MODEL);
log.info("已清除大模型接入 Redis 配置");
return AjaxResult.success("已恢复为 Jarvis 默认 Ollama 配置");
} catch (Exception e) {
log.error("清除大模型接入配置失败", e);
return AjaxResult.error("清除失败: " + e.getMessage());
}
}
/**
* 根据标题(+可选型号备注生成闲鱼文案代下单、教你下单不依赖JD接口
*/