|
|
@@ -1,5 +1,6 @@
|
|
|
package com.tzld.videoVector.service.impl;
|
|
|
|
|
|
+import com.alibaba.fastjson.JSONArray;
|
|
|
import com.alibaba.fastjson.JSONObject;
|
|
|
import com.tzld.videoVector.api.VideoApiService;
|
|
|
import com.tzld.videoVector.common.constant.VectorConstants;
|
|
|
@@ -222,6 +223,204 @@ public class VideoSearchServiceImpl implements VideoSearchService {
|
|
|
return null;
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * 精简版: 复用 getDeconstructResult, 把 result 字段(原始 JSON)提取成 topic + highValuePoints,
|
|
|
+ * 然后从返回里去掉 result 字段, 顶层放 topic + highValuePoints.
|
|
|
+ * 提取规则与 sync_decode_to_redis.py 一致, 实质阈值 0.8.
|
|
|
+ */
|
|
|
+ @Override
|
|
|
+ public JSONObject getDeconstructResultMini(GetDeconstructParam param) {
|
|
|
+ JSONObject full = getDeconstructResult(param);
|
|
|
+ if (full == null) {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 默认顶层放空数组, 失败/未完成时也好让前端渲染
|
|
|
+ full.put("topic", "");
|
|
|
+ full.put("highValuePoints", new JSONArray());
|
|
|
+
|
|
|
+ Object resultObj = full.get("result");
|
|
|
+ if (resultObj instanceof JSONObject) {
|
|
|
+ try {
|
|
|
+ JSONObject extracted = parseRawDeconstruct((JSONObject) resultObj);
|
|
|
+ full.put("topic", extracted.getString("topic"));
|
|
|
+ full.put("highValuePoints", extracted.getJSONArray("highValuePoints"));
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.error("getDeconstructResultMini parse failed, taskId={}, err={}",
|
|
|
+ param.getTaskId(), e.getMessage(), e);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ // 不论解析成功与否都丢掉原始 result, 控制返回体积
|
|
|
+ full.remove("result");
|
|
|
+ return full;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 解析外部解构 API 返回的原始 JSON, 抽取 topic + highValuePoints
|
|
|
+ * 规则:
|
|
|
+ * - 灵感点: 全部纳入(分词都视为实质); 仅保留 contribution >= 0.8 的词
|
|
|
+ * - 关键点: 仅当元数据 类型=='实质' 才纳入; 同样过滤 contribution >= 0.8
|
|
|
+ * - 目的点: 全部纳入; 同样过滤 contribution >= 0.8
|
|
|
+ * - 任一点 essences 为空 -> 不纳入
|
|
|
+ */
|
|
|
+ private JSONObject parseRawDeconstruct(JSONObject d) {
|
|
|
+ final double THRESHOLD = 0.8;
|
|
|
+
|
|
|
+ // ① 选题
|
|
|
+ String topic = "";
|
|
|
+ JSONObject finalTopic = d.getJSONObject("最终选题");
|
|
|
+ if (finalTopic != null) {
|
|
|
+ String t = finalTopic.getString("选题");
|
|
|
+ if (t != null) topic = t;
|
|
|
+ }
|
|
|
+
|
|
|
+ // ② 词 -> 贡献度
|
|
|
+ Map<String, Double> contribMap = new HashMap<>();
|
|
|
+ JSONArray contribArr = d.getJSONArray("contribution_results");
|
|
|
+ if (contribArr != null) {
|
|
|
+ for (int i = 0; i < contribArr.size(); i++) {
|
|
|
+ JSONObject row = contribArr.getJSONObject(i);
|
|
|
+ if (row == null) continue;
|
|
|
+ String word = row.getString("词");
|
|
|
+ if (word == null) continue;
|
|
|
+ Double score = row.getDouble("贡献度");
|
|
|
+ contribMap.put(word, score == null ? 0.0 : score);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // ③ 灵感点元数据 -> id
|
|
|
+ Map<String, String> inspirationIdMap = new HashMap<>();
|
|
|
+ JSONObject inspirationFinal = d.getJSONObject("inspiration_final_result");
|
|
|
+ if (inspirationFinal != null) {
|
|
|
+ JSONArray list = inspirationFinal.getJSONArray("最终灵感点列表");
|
|
|
+ if (list != null) {
|
|
|
+ for (int i = 0; i < list.size(); i++) {
|
|
|
+ JSONObject row = list.getJSONObject(i);
|
|
|
+ if (row == null) continue;
|
|
|
+ String name = row.getString("灵感点");
|
|
|
+ if (name != null) inspirationIdMap.put(name, row.getString("id"));
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // ④ 关键点元数据 -> (类型, id)
|
|
|
+ Map<String, String[]> keypointMetaMap = new HashMap<>();
|
|
|
+ JSONObject keypointFinal = d.getJSONObject("keypoint_final");
|
|
|
+ if (keypointFinal != null) {
|
|
|
+ JSONArray list = keypointFinal.getJSONArray("最终关键点列表");
|
|
|
+ if (list != null) {
|
|
|
+ for (int i = 0; i < list.size(); i++) {
|
|
|
+ JSONObject row = list.getJSONObject(i);
|
|
|
+ if (row == null) continue;
|
|
|
+ String name = row.getString("关键点");
|
|
|
+ if (name != null) {
|
|
|
+ keypointMetaMap.put(name,
|
|
|
+ new String[]{row.getString("类型"), row.getString("关键点ID")});
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // ⑤ 目的点元数据 -> id
|
|
|
+ Map<String, String> purposeIdMap = new HashMap<>();
|
|
|
+ JSONObject purposeFinal = d.getJSONObject("purpose_final_result");
|
|
|
+ if (purposeFinal != null) {
|
|
|
+ JSONArray list = purposeFinal.getJSONArray("最终目的点列表");
|
|
|
+ if (list != null) {
|
|
|
+ for (int i = 0; i < list.size(); i++) {
|
|
|
+ JSONObject row = list.getJSONObject(i);
|
|
|
+ if (row == null) continue;
|
|
|
+ String name = row.getString("目的点");
|
|
|
+ if (name != null) purposeIdMap.put(name, row.getString("id"));
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ JSONArray highValue = new JSONArray();
|
|
|
+
|
|
|
+ // ⑥ 灵感点
|
|
|
+ JSONArray inspirations = d.getJSONArray("灵感点");
|
|
|
+ if (inspirations != null) {
|
|
|
+ for (int i = 0; i < inspirations.size(); i++) {
|
|
|
+ JSONObject ip = inspirations.getJSONObject(i);
|
|
|
+ if (ip == null) continue;
|
|
|
+ String name = ip.getString("点");
|
|
|
+ if (name == null || name.isEmpty()) continue;
|
|
|
+ JSONArray essences = collectEssences(ip.getJSONArray("分词结果"), contribMap, THRESHOLD);
|
|
|
+ if (essences.isEmpty()) continue;
|
|
|
+ JSONObject point = new JSONObject();
|
|
|
+ point.put("id", inspirationIdMap.getOrDefault(name, ""));
|
|
|
+ point.put("type", "灵感点");
|
|
|
+ point.put("name", name);
|
|
|
+ point.put("essences", essences);
|
|
|
+ highValue.add(point);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // ⑦ 关键点 (仅 类型=='实质')
|
|
|
+ JSONArray keypoints = d.getJSONArray("关键点");
|
|
|
+ if (keypoints != null) {
|
|
|
+ for (int i = 0; i < keypoints.size(); i++) {
|
|
|
+ JSONObject kp = keypoints.getJSONObject(i);
|
|
|
+ if (kp == null) continue;
|
|
|
+ String name = kp.getString("点");
|
|
|
+ if (name == null || name.isEmpty()) continue;
|
|
|
+ String[] meta = keypointMetaMap.get(name);
|
|
|
+ if (meta == null || !"实质".equals(meta[0])) continue;
|
|
|
+ JSONArray essences = collectEssences(kp.getJSONArray("分词结果"), contribMap, THRESHOLD);
|
|
|
+ if (essences.isEmpty()) continue;
|
|
|
+ JSONObject point = new JSONObject();
|
|
|
+ point.put("id", meta[1] == null ? "" : meta[1]);
|
|
|
+ point.put("type", "关键点");
|
|
|
+ point.put("name", name);
|
|
|
+ point.put("essences", essences);
|
|
|
+ highValue.add(point);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // ⑧ 目的点
|
|
|
+ JSONArray purposes = d.getJSONArray("目的点");
|
|
|
+ if (purposes != null) {
|
|
|
+ for (int i = 0; i < purposes.size(); i++) {
|
|
|
+ JSONObject pp = purposes.getJSONObject(i);
|
|
|
+ if (pp == null) continue;
|
|
|
+ String name = pp.getString("点");
|
|
|
+ if (name == null || name.isEmpty()) continue;
|
|
|
+ JSONArray essences = collectEssences(pp.getJSONArray("分词结果"), contribMap, THRESHOLD);
|
|
|
+ if (essences.isEmpty()) continue;
|
|
|
+ JSONObject point = new JSONObject();
|
|
|
+ point.put("id", purposeIdMap.getOrDefault(name, ""));
|
|
|
+ point.put("type", "目的点");
|
|
|
+ point.put("name", name);
|
|
|
+ point.put("essences", essences);
|
|
|
+ highValue.add(point);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ JSONObject out = new JSONObject();
|
|
|
+ out.put("topic", topic);
|
|
|
+ out.put("highValuePoints", highValue);
|
|
|
+ return out;
|
|
|
+ }
|
|
|
+
|
|
|
+ private JSONArray collectEssences(JSONArray words, Map<String, Double> contribMap, double threshold) {
|
|
|
+ JSONArray essences = new JSONArray();
|
|
|
+ if (words == null) return essences;
|
|
|
+ for (int i = 0; i < words.size(); i++) {
|
|
|
+ JSONObject w = words.getJSONObject(i);
|
|
|
+ if (w == null) continue;
|
|
|
+ String word = w.getString("词");
|
|
|
+ if (word == null) continue;
|
|
|
+ Double score = contribMap.get(word);
|
|
|
+ if (score == null || score < threshold) continue;
|
|
|
+ JSONObject e = new JSONObject();
|
|
|
+ e.put("word", word);
|
|
|
+ e.put("score", score);
|
|
|
+ essences.add(e);
|
|
|
+ }
|
|
|
+ return essences;
|
|
|
+ }
|
|
|
+
|
|
|
/**
|
|
|
* 根据taskId查询解构内容
|
|
|
*/
|