|
|
@@ -10,6 +10,8 @@ import com.etotem.cfc.mapper.ArticleMapper;
|
|
|
import com.etotem.cfc.mapper.FoodMapper;
|
|
|
import com.etotem.cfc.mapper.HealthKnowledgeBaseMapper;
|
|
|
import com.etotem.cfc.mapper.ProblemDomainMapper;
|
|
|
+import com.etotem.cfc.service.api.WechatServiceInterface;
|
|
|
+import com.etotem.cfc.util.PlanContentSafetyUtil;
|
|
|
import io.swagger.v3.oas.annotations.Operation;
|
|
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
|
|
import javax.annotation.Resource;
|
|
|
@@ -47,6 +49,10 @@ public class ContentFilterController {
|
|
|
@Resource
|
|
|
private ProblemDomainMapper problemDomainMapper;
|
|
|
|
|
|
+ /** SC-T-28:方案内容安全复核原语(wechatService.checkText,true=安全) */
|
|
|
+ @Resource
|
|
|
+ private WechatServiceInterface wechatService;
|
|
|
+
|
|
|
@Operation(summary = "按 resultTags + 问题域 code 过滤文章/知识库/饮食")
|
|
|
@PostMapping("/by-tags")
|
|
|
public Result<Map<String, Object>> byTags(@RequestBody Map<String, Object> params) {
|
|
|
@@ -83,6 +89,42 @@ public class ContentFilterController {
|
|
|
return Result.success(data);
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * SC-T-28:方案内容安全复核端点(AI 方案送审/发布前调用,命中即拦截)。
|
|
|
+ * 请求体支持 {@code content}(方案正文)或 {@code planContent}/{@code planJson}(直接传入方案字段)。
|
|
|
+ */
|
|
|
+ @Operation(summary = "方案内容安全复核(SC-T-28,命中即拦截)")
|
|
|
+ @PostMapping("/plan-safety")
|
|
|
+ public Result<Map<String, Object>> planSafety(@RequestBody(required = false) Map<String, Object> params) {
|
|
|
+ String content = null;
|
|
|
+ if (params != null) {
|
|
|
+ Object raw = params.get("content");
|
|
|
+ if (raw != null) content = String.valueOf(raw);
|
|
|
+ if (content == null || content.trim().isEmpty()) {
|
|
|
+ Object planContent = params.get("planContent");
|
|
|
+ if (planContent != null) content = String.valueOf(planContent);
|
|
|
+ }
|
|
|
+ if (content == null || content.trim().isEmpty()) {
|
|
|
+ Object planJson = params.get("planJson");
|
|
|
+ if (planJson != null) content = String.valueOf(planJson);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (content == null || content.trim().isEmpty()) {
|
|
|
+ return Result.error("content不能为空");
|
|
|
+ }
|
|
|
+
|
|
|
+ String unsafe = PlanContentSafetyUtil.matchUnsafeTerm(content);
|
|
|
+ if (unsafe == null && wechatService != null && !wechatService.checkText(content)) {
|
|
|
+ unsafe = "第三方内容安全检测未通过";
|
|
|
+ }
|
|
|
+
|
|
|
+ Map<String, Object> resp = new HashMap<>();
|
|
|
+ resp.put("safe", unsafe == null);
|
|
|
+ resp.put("hitTerm", unsafe);
|
|
|
+ resp.put("message", unsafe == null ? "内容安全" : "命中违规词:「" + unsafe + "」");
|
|
|
+ return Result.success(resp);
|
|
|
+ }
|
|
|
+
|
|
|
/** 文章:tags 字段 LIKE 任一标签 */
|
|
|
private List<Article> filterArticles(Set<String> tags, int size) {
|
|
|
if (tags.isEmpty()) {
|