Просмотр исходного кода

自动替换的高消耗素材的小程序 关键词提取prompt修改

wangyunpeng 1 день назад
Родитель
Сommit
8a146ed4e7

+ 68 - 29
api-module/src/main/java/com/tzld/piaoquan/api/job/GzhReplyVideoRefreshJob.java

@@ -133,39 +133,12 @@ public class GzhReplyVideoRefreshJob {
         List<String> existTitles = new ArrayList<>();
         for (JSONObject obj : sortedList) {
             String text = obj.getString("title");
-            // 提取关键词
-            String keywordPrompt =
-                    "你是一位精通算法推荐逻辑的世界级短视频SEO专家。你擅长从标题中提炼出搜索量最大、用户意图最明确的“核心流量词”。\n" +
-                            "\n" +
-                            "# Task\n" +
-                            "分析用户提供的视频标题,提炼出 2 个核心搜索关键词。\n" +
-                            "\n" +
-                            "# Constraints (必须严格遵守)\n" +
-                            "1. **字数限制**:每个关键词严格控制在 **3个汉字以内**(包含3个字)。\n" +
-                            "2. **选词逻辑**:\n" +
-                            "   - 优先提取核心名词(人名/物名)或高频动词。\n" +
-                            "   - 剔除虚词(如“的”、“了”、“吗”)。\n" +
-                            "   - 必须与原标题强相关,能覆盖用户搜索意图。\n" +
-                            "3. **输出格式**:仅输出JSON数组,**严禁**包含任何解释、Markdown标记或其他文本。\n" +
-                            "\n" +
-                            "# Example\n" +
-                            "输入:新手如何快速学会剪映剪辑\n" +
-                            "输出:[\"剪映\",\"剪辑\"]\n" +
-                            "\n" +
-                            "输入:宝宝感冒流鼻涕怎么办\n" +
-                            "输出:[\"感冒\",\"流鼻涕\"]\n" +
-                            "\n" +
-                            "# Input\n" +
-                            "内容是: {{text}} \n" +
-                            "\n" +
-                            "# Output\n" +
-                            "请基于上述规则,输出最终的JSON:";
-            keywordPrompt = keywordPrompt.replace("text", text);
+            String keywordPrompt = getKeyWordPrompt(text);
             AIResult aiResult = deepSeekApiService.requestOfficialApi(keywordPrompt, null, null, false);
             if (aiResult.isSuccess()) {
                 List<String> keywords = JSONObject.parseArray(aiResult.getResponse().getChoices().get(0).getMessage().getContent(), String.class);
                 log.info("GzhReplyVideoRefreshJob accountName:{} text:{} keywords:{}", accountName, text, keywords);
-                VideoDetail videoDetail = searchVideoByKeyword(keywords, searchVideos, existTitles);
+                VideoDetail videoDetail = getVideoDetail(keywords, searchVideos, existTitles);
                 if (videoDetail != null) {
                     existTitles.add(videoDetail.getTitle());
                     existTitles.add(text);
@@ -181,6 +154,53 @@ public class GzhReplyVideoRefreshJob {
         }
     }
 
+    private String getKeyWordPrompt(String text) {
+        // 提取关键词
+        String keywordPrompt =
+                "# Role\n" +
+                        "你是一位世界顶级的短视频SEO专家。你擅长剥离标题中的修饰语和状态词,精准捕捉用户真正想搜索的“核心实体”或“核心话题”。\n" +
+                        "\n" +
+                        "# Task\n" +
+                        "分析给定的视频标题,提取 **1个 或 2个** 最具搜索价值的关键词。\n" +
+                        "\n" +
+                        "# Constraints (必须严格执行)\n" +
+                        "1. **字数限制**:每个关键词必须 **≤ 3个汉字**。\n" +
+                        "2. **数量限制**:输出 1 到 2 个关键词。如果只有一个核心词,不要强行凑数,只输出一个。\n" +
+                        "3. **选词优先级 (核心逻辑)**:\n" +
+                        "   - **最高优先级**:核心名词、实体(如:燕子、粮食、早餐)。\n" +
+                        "   - **次优先级**:具有明确分类属性的动词(如:剪辑、做菜)。\n" +
+                        "4. **负面清单 (严禁提取)**:\n" +
+                        "   - **剔除状态词/结果词**:如“过期”、“消失”、“变质”、“最好”、“几点”等描述物体状态或程度的词。\n" +
+                        "   - **剔除虚词**:如“的”、“了”、“吗”。\n" +
+                        "   - **剔除泛词**:如“今天”、“才知道”、“告诉”。\n" +
+                        "5. **输出格式**:仅输出JSON数组,无其他字符。\n" +
+                        "\n" +
+                        "# Few-Shot Examples (学习选词逻辑)\n" +
+                        "Input: 今天才知道5种粮食不怕过期!放越久越好!\n" +
+                        "Output: [\"粮食\"]\n" +
+                        "(解释:剔除“过期”,因为它只是粮食的一个状态,用户搜的是粮食)\n" +
+                        "\n" +
+                        "Input: 今年燕子消失了 你知道怎么回事吗?\n" +
+                        "Output: [\"燕子\"]\n" +
+                        "(解释:剔除“消失”,保留核心生物实体)\n" +
+                        "\n" +
+                        "Input: 新手如何快速学会剪映剪辑\n" +
+                        "Output: [\"剪映\",\"剪辑\"]\n" +
+                        "(解释:两个词都是核心技能点,且都在3字内)\n" +
+                        "\n" +
+                        "Input: 冰箱总是结冰怎么办\n" +
+                        "Output: [\"冰箱\",\"结冰\"]\n" +
+                        "(解释:“结冰”虽是状态,但“冰箱结冰”是常见故障搜索词,故保留;若无法判断,优先保实体)\n" +
+                        "\n" +
+                        "# Input\n" +
+                        "内容是: {{text}} \n" +
+                        "\n" +
+                        "# Output\n" +
+                        "请基于上述规则,输出最终的JSON:";
+        keywordPrompt = keywordPrompt.replace("text", text);
+        return keywordPrompt;
+    }
+
     private Map<String, JSONObject> analysisImageText(List<AdPutCreativeComponentCostData> costDataList) {
         Map<String, JSONObject> creativeIdTextMap = new HashMap<>();
         for (AdPutCreativeComponentCostData costData : costDataList) {
@@ -222,6 +242,25 @@ public class GzhReplyVideoRefreshJob {
         return creativeIdTextMap;
     }
 
+    private VideoDetail getVideoDetail(List<String> keywords, List<VideoDetail> searchVideos, List<String> existTitles) {
+        VideoDetail videoDetail = null;
+        int maxRetries = 3;
+        int retryCount = 0;
+        while (retryCount < maxRetries) {
+            try {
+                videoDetail = searchVideoByKeyword(keywords, searchVideos, existTitles);
+                break;
+            } catch (Exception e) {
+                retryCount++;
+                log.error("GzhReplyVideoRefreshJob searchVideoByKeyword error, retry count: {}/{}", retryCount, maxRetries, e);
+                if (retryCount >= maxRetries) {
+                    break;
+                }
+            }
+        }
+        return videoDetail;
+    }
+
     private VideoDetail searchVideoByKeyword(List<String> keywords, List<VideoDetail> searchVideos, List<String> existTitles) {
         if (CollectionUtils.isNotEmpty(keywords)) {
             String searchVideoSql = "SELECT v.id, v.title, v.cover_img_path\n" +