From 94fd4658ea62c63a164a06fd5973432b651a23f3 Mon Sep 17 00:00:00 2001
From: 陈昶聿 <chychen@nbjetron.com>
Date: 星期五, 26 六月 2026 14:41:51 +0800
Subject: [PATCH] 【市一】接入阿里NLP

---
 ruoyi-quartz/src/main/java/com/ruoyi/quartz/task/RyTask.java |    2 
 smartor/src/main/java/com/smartor/common/AliNlpUtil.java     |  299 +++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 300 insertions(+), 1 deletions(-)

diff --git a/ruoyi-quartz/src/main/java/com/ruoyi/quartz/task/RyTask.java b/ruoyi-quartz/src/main/java/com/ruoyi/quartz/task/RyTask.java
index ec9250f..c5e07e7 100644
--- a/ruoyi-quartz/src/main/java/com/ruoyi/quartz/task/RyTask.java
+++ b/ruoyi-quartz/src/main/java/com/ruoyi/quartz/task/RyTask.java
@@ -1346,7 +1346,7 @@
         Map<String, String> headerMap = new HashMap<>();
         headerMap.put("sign", encode);
         String result = HttpUtils.sendPostByHeader(wxqqxx.get(3), body, headerMap);
-
+        log.info("銆恎etWXCode銆戝井淇″叕浼楀彿杩斿洖鍙傛暟锛歿}", result);
         JSONObject jsonObject = JSONObject.parseObject(result);
         String code = (String) jsonObject.toString();
         return code;
diff --git a/smartor/src/main/java/com/smartor/common/AliNlpUtil.java b/smartor/src/main/java/com/smartor/common/AliNlpUtil.java
new file mode 100644
index 0000000..967832a
--- /dev/null
+++ b/smartor/src/main/java/com/smartor/common/AliNlpUtil.java
@@ -0,0 +1,299 @@
+package com.smartor.common;
+
+import com.alibaba.fastjson2.JSONArray;
+import com.alibaba.fastjson2.JSONObject;
+import com.aliyuncs.CommonRequest;
+import com.aliyuncs.CommonResponse;
+import com.aliyuncs.DefaultAcsClient;
+import com.aliyuncs.IAcsClient;
+import com.aliyuncs.exceptions.ClientException;
+import com.aliyuncs.exceptions.ServerException;
+import com.aliyuncs.http.MethodType;
+import com.aliyuncs.profile.DefaultProfile;
+import com.aliyuncs.profile.IClientProfile;
+import com.google.gson.Gson;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
+import org.junit.Test;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Component;
+
+import javax.annotation.PostConstruct;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * 闃块噷浜戣嚜鐒惰瑷�澶勭悊锛圢LP锛夊伐鍏风被銆�
+ * <p>
+ * 鏂囨。锛�<a href="https://help.aliyun.com/zh/document_detail/181284.html">NLP 鑷涔犲钩鍙� / 鍩虹鏂囨湰鏈嶅姟</a>
+ * <p>
+ * 璋冪敤鏂瑰紡鍩轰簬 {@code aliyun-java-sdk-alinlp} 鐨� {@link CommonRequest}锛�
+ * 缁熶竴鍚� {@code alinlp.cn-hangzhou.aliyuncs.com} 鍙戦�� POST 璇锋眰锛岀増鏈彿 2020-06-29锛�
+ * 閫氳繃浼犲叆涓嶅悓鐨� {@code Action} 涓� {@code ServiceCode} 璋冪敤鍏蜂綋鑳藉姏銆�
+ * <p>
+ * 閰嶇疆椤癸紙application.yml锛夛細
+ * <pre>
+ * aliyun:
+ *   nlp:
+ *     access-key-id: ${accessKeyId}       # 榛樿澶嶇敤涓昏处鍙� accessKeyId
+ *     access-key-secret: ${accessKeySecret}
+ *     region-id: cn-hangzhou
+ *     domain: alinlp.cn-hangzhou.aliyuncs.com
+ *     version: 2020-06-29
+ *     read-timeout: 5000
+ *     connect-timeout: 3000
+ * </pre>
+ */
+@Slf4j
+@Component
+public class AliNlpUtil {
+
+    /** 闃块噷浜� AccessKey ID锛岄粯璁ゅ鐢ㄤ富璐﹀彿閰嶇疆 */
+    @Value("${aliyun.nlp.access-key-id:${accessKeyId:}}")
+    private String accessKeyId;
+
+    /** 闃块噷浜� AccessKey Secret */
+    @Value("${aliyun.nlp.access-key-secret:${accessKeySecret:}}")
+    private String accessKeySecret;
+
+    /** 鍦板煙 ID锛屽叕鍏变簯鍥哄畾涓� cn-hangzhou */
+    @Value("${aliyun.nlp.region-id:cn-hangzhou}")
+    private String regionId;
+
+    /** 鎺ュ叆鍩熷悕 */
+    @Value("${aliyun.nlp.domain:alinlp.cn-hangzhou.aliyuncs.com}")
+    private String domain = "alinlp.cn-hangzhou.aliyuncs.com";
+
+    /** API 鐗堟湰鍙� */
+    @Value("${aliyun.nlp.version:2020-06-29}")
+    private String version = "2020-06-29";
+
+    /** 璇诲彇瓒呮椂锛堟绉掞級 */
+    @Value("${aliyun.nlp.read-timeout:5000}")
+    private int readTimeout = 5000;
+
+    /** 杩炴帴瓒呮椂锛堟绉掞級 */
+    @Value("${aliyun.nlp.connect-timeout:3000}")
+    private int connectTimeout = 3000;
+
+    // NLP鍦板煙鍥哄畾 cn-hangzhou
+    private static final String REGION_ID = "cn-hangzhou";
+    private static final String PRODUCT = "nlp";
+    private static final String VERSION = "2020-06-08";
+
+    private static final Gson gson = new Gson();
+
+    private IAcsClient client;
+
+    @PostConstruct
+    private void init() {
+//        String accessKeyId = "LTAI5tPfc1VJzz7VuhzcBwug";
+//        String accessKeySecret = "gG1srKxPFDBNWe2oHfqmK1qsSQkf1e";
+
+        String accessKeyId = "LTAI5t6GBf9nUXfX37CUDi4H";
+        String accessKeySecret = "BtjYAES4yjvde5Lwg46sTqnZefPnOE";
+        String regionId = "cn-hangzhou";
+        if (StringUtils.isBlank(accessKeyId) || StringUtils.isBlank(accessKeySecret)) {
+            log.warn("闃块噷浜� NLP 鏈厤缃� AccessKey锛孉liNlpUtil 灏嗕笉鍙敤");
+            return;
+        }
+        IClientProfile profile = DefaultProfile.getProfile(regionId, accessKeyId, accessKeySecret);
+        this.client = new DefaultAcsClient(profile);
+    }
+
+    // ============================== 鍩虹璋冪敤 ==============================
+
+    /**
+     * 閫氱敤璋冪敤鍏ュ彛锛氫紶鍏� Action 涓庝笟鍔″弬鏁帮紝杩斿洖瑙f瀽鍚庣殑 JSON 瀵硅薄銆�
+     *
+     * @param action API 鍔ㄤ綔鍚嶏紝渚嬪 {@code GetWsChGeneral}
+     * @param params 涓氬姟鍙傛暟锛岃嚦灏戦渶瑕佸寘鍚� {@code ServiceCode}銆亄@code Text} 绛�
+     * @return 鎺ュ彛杩斿洖鐨� JSON 瀵硅薄锛涘け璐ユ椂杩斿洖 {@code null}
+     */
+    public JSONObject invoke(String action, Map<String, String> params) {
+        if (client == null) {
+            log.error("闃块噷浜� NLP 瀹㈡埛绔湭鍒濆鍖栵紝鏃犳硶璋冪敤 action={}", action);
+            return null;
+        }
+        if (StringUtils.isBlank(action)) {
+            throw new IllegalArgumentException("action 涓嶈兘涓虹┖");
+        }
+
+        CommonRequest request = new CommonRequest();
+        request.setSysMethod(MethodType.POST);
+        request.setSysDomain(domain);
+        request.setSysVersion(version);
+        request.setSysAction(action);
+        request.setSysReadTimeout(readTimeout);
+        request.setSysConnectTimeout(connectTimeout);
+        if (params != null) {
+            for (Map.Entry<String, String> e : params.entrySet()) {
+                if (e.getValue() != null) {
+                    request.putBodyParameter(e.getKey(), e.getValue());
+                }
+            }
+        }
+
+        try {
+            CommonResponse response = client.getCommonResponse(request);
+            String data = response.getData();
+            if (StringUtils.isBlank(data)) {
+                log.error("闃块噷浜� NLP 杩斿洖涓虹┖锛宎ction={}, params={}", action, params);
+                return null;
+            }
+            return JSONObject.parseObject(data);
+        } catch (ClientException e) {
+            log.error("闃块噷浜� NLP 璋冪敤澶辫触 action={}, params={}, errCode={}, errMsg={}",
+                    action, params, e.getErrCode(), e.getErrMsg(), e);
+            return null;
+        } catch (Exception e) {
+            log.error("闃块噷浜� NLP 璋冪敤寮傚父 action={}, params={}", action, params, e);
+            return null;
+        }
+    }
+
+    // ============================== 渚挎嵎鏂规硶 ==============================
+
+    /**
+     * 涓枃鍒嗚瘝锛堥�氱敤棰嗗煙锛岄珮绾х増锛夈��
+     * 瀵瑰簲 Action锛歿@code GetWsChGeneral}锛孲erviceCode锛歿@code alinlp}銆�
+     *
+     * @param text     寰呭垎璇嶆枃鏈�
+     * @param tokenizer 鍒嗚瘝绮掑害锛屽彲绌恒�傚父鐢ㄥ�硷細{@code GENERAL_CHN}锛堥�氱敤鍩虹绮掑害锛�
+     * @return 鍒嗚瘝缁撴灉鍒楄〃锛涜皟鐢ㄥけ璐ヨ繑鍥炵┖鍒楄〃
+     */
+    public List<String> segmentChinese(String text, String tokenizer) {
+        if (StringUtils.isBlank(text)) {
+            return Collections.emptyList();
+        }
+        Map<String, String> params = new LinkedHashMap<>();
+        params.put("ServiceCode", "alinlp");
+        params.put("Text", text);
+        if (StringUtils.isNotBlank(tokenizer)) {
+            params.put("TokenizerId", tokenizer);
+        }
+        JSONObject resp = invoke("GetWsChGeneral", params);
+        return parseWordsFromData(resp);
+    }
+
+    /** 涓枃鍒嗚瘝锛屼娇鐢ㄩ粯璁ら�氱敤绮掑害 {@code GENERAL_CHN}銆� */
+    public List<String> segmentChinese(String text) {
+        return segmentChinese(text, "GENERAL_CHN");
+    }
+
+    /**
+     * 鎯呮劅鍒嗘瀽锛堥�氱敤棰嗗煙锛屽熀纭�鐗堬級銆�
+     * 瀵瑰簲 Action锛歿@code GetSaChGeneral}銆�
+     *
+     * @param text 寰呭垎鏋愭枃鏈�
+     * @return 褰㈠ {@code {"sentiment":"positive","positive_prob":0.97,...}} 鐨勫璞★紱澶辫触杩斿洖 {@code null}
+     */
+    public JSONObject sentimentAnalysis(String text) {
+        if (StringUtils.isBlank(text)) {
+            return null;
+        }
+        Map<String, String> params = new LinkedHashMap<>();
+        params.put("ServiceCode", "alinlp");
+        params.put("Text", text);
+        JSONObject resp = invoke("GetSaChGeneral", params);
+        return extractDataObject(resp);
+    }
+
+    // 娴嬭瘯鍏ュ彛
+    @Test
+    public void main() {
+        String text1 = "杩欏濂惰尪瓒呯骇濂藉枬锛屼笅娆¤繕鏉ワ紒";
+        String text2 = "鍛抽亾寰堝樊锛屾湇鍔℃�佸害涔熶笉濂斤紝涓嶆帹鑽�";
+        String text3 = "浠婂ぉ鍑洪棬涔颁簡涓�鐡剁熆娉夋按";
+
+        this.init();
+        JSONObject res1 = sentimentAnalysis(text1);
+        JSONObject res2 = sentimentAnalysis(text2);
+        JSONObject res3 = sentimentAnalysis(text3);
+
+        System.out.println("姝i潰鏂囨湰缁撴灉锛�" + gson.toJson(res1));
+        System.out.println("璐熼潰鏂囨湰缁撴灉锛�" + gson.toJson(res2));
+        System.out.println("涓�ф枃鏈粨鏋滐細" + gson.toJson(res3));
+    }
+
+    /**
+     * 鍛藉悕瀹炰綋璇嗗埆锛堥�氱敤棰嗗煙锛夈��
+     * 瀵瑰簲 Action锛歿@code GetNerChGeneral}銆�
+     *
+     * @param text 寰呰瘑鍒枃鏈�
+     * @return 瀹炰綋鍒楄〃锛堟瘡涓厓绱犲惈 word銆乼ag銆乻tartIndex 绛夊瓧娈碉級锛涘け璐ヨ繑鍥炵┖鍒楄〃
+     */
+    public JSONArray namedEntityRecognition(String text) {
+        if (StringUtils.isBlank(text)) {
+            return new JSONArray();
+        }
+        Map<String, String> params = new LinkedHashMap<>();
+        params.put("ServiceCode", "alinlp");
+        params.put("Text", text);
+        JSONObject resp = invoke("GetNerChGeneral", params);
+        JSONObject data = extractDataObject(resp);
+        if (data == null) {
+            return new JSONArray();
+        }
+        JSONArray arr = data.getJSONArray("result");
+        return arr == null ? new JSONArray() : arr;
+    }
+
+    // ============================== 鍝嶅簲瑙f瀽 ==============================
+
+    /**
+     * 瑙f瀽闃块噷 NLP 鐨� {@code Data} 瀛楁锛堝瓧绗︿覆鍖栫殑 JSON锛夈��
+     * 椤跺眰鍝嶅簲褰㈠锛歿@code {"Data":"{...}","RequestId":"..."}}銆�
+     */
+    private JSONObject extractDataObject(JSONObject resp) {
+        if (resp == null) {
+            return null;
+        }
+        String dataStr = resp.getString("Data");
+        if (StringUtils.isBlank(dataStr)) {
+            log.warn("闃块噷浜� NLP 鍝嶅簲缂哄皯 Data 瀛楁锛宺esp={}", resp);
+            return null;
+        }
+        try {
+            return JSONObject.parseObject(dataStr);
+        } catch (Exception e) {
+            log.error("闃块噷浜� NLP Data 瀛楁瑙f瀽澶辫触锛宒ataStr={}", dataStr, e);
+            return null;
+        }
+    }
+
+    /**
+     * 浠庡垎璇嶅搷搴旈噷鎶藉彇璇嶅垪琛ㄣ�俽esult 褰㈠ {@code [{"word":"浠婂ぉ","tag":"t"},...]}銆�
+     */
+    private List<String> parseWordsFromData(JSONObject resp) {
+        JSONObject data = extractDataObject(resp);
+        if (data == null) {
+            return Collections.emptyList();
+        }
+        JSONArray result = data.getJSONArray("result");
+        if (result == null || result.isEmpty()) {
+            return Collections.emptyList();
+        }
+        String[] words = new String[result.size()];
+        for (int i = 0; i < result.size(); i++) {
+            JSONObject item = result.getJSONObject(i);
+            words[i] = item == null ? "" : item.getString("word");
+        }
+        return Arrays.asList(words);
+    }
+
+    @Test
+    public void test() {
+        List <String> result = segmentChinese("闃块噷宸村反闆嗗洟鐨勪娇鍛芥槸璁╁ぉ涓嬫病鏈夐毦鍋氱殑鐢熸剰銆�");
+        log.info(result.toString());
+    }
+
+    @Test
+    public void testP() {
+        JSONObject result = sentimentAnalysis("鎴戣寰椾綘鍙兘鏄鐨�");
+        log.info(result.toString());
+    }
+}

--
Gitblit v1.9.3