陈昶聿
10 小时以前 94fd4658ea62c63a164a06fd5973432b651a23f3
【市一】接入阿里NLP
已修改1个文件
已添加1个文件
301 ■■■■■ 文件已修改
ruoyi-quartz/src/main/java/com/ruoyi/quartz/task/RyTask.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
smartor/src/main/java/com/smartor/common/AliNlpUtil.java 299 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
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("【getWXCode】微信公众号返回参数:{}", result);
        JSONObject jsonObject = JSONObject.parseObject(result);
        String code = (String) jsonObject.toString();
        return code;
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;
/**
 * é˜¿é‡Œäº‘自然语言处理(NLP)工具类。
 * <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,AliNlpUtil å°†ä¸å¯ç”¨");
            return;
        }
        IClientProfile profile = DefaultProfile.getProfile(regionId, accessKeyId, accessKeySecret);
        this.client = new DefaultAcsClient(profile);
    }
    // ============================== åŸºç¡€è°ƒç”¨ ==============================
    /**
     * é€šç”¨è°ƒç”¨å…¥å£ï¼šä¼ å…¥ Action ä¸Žä¸šåŠ¡å‚æ•°ï¼Œè¿”å›žè§£æžåŽçš„ 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 è¿”回为空,action={}, 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},ServiceCode:{@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("正面文本结果:" + gson.toJson(res1));
        System.out.println("负面文本结果:" + gson.toJson(res2));
        System.out.println("中性文本结果:" + gson.toJson(res3));
    }
    /**
     * å‘½åå®žä½“识别(通用领域)。
     * å¯¹åº” Action:{@code GetNerChGeneral}。
     *
     * @param text å¾…识别文本
     * @return å®žä½“列表(每个元素含 word、tag、startIndex ç­‰å­—段);失败返回空列表
     */
    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;
    }
    // ============================== å“åº”解析 ==============================
    /**
     * è§£æžé˜¿é‡Œ 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 å­—段,resp={}", resp);
            return null;
        }
        try {
            return JSONObject.parseObject(dataStr);
        } catch (Exception e) {
            log.error("阿里云 NLP Data å­—段解析失败,dataStr={}", dataStr, e);
            return null;
        }
    }
    /**
     * ä»Žåˆ†è¯å“åº”里抽取词列表。result å½¢å¦‚ {@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());
    }
}