Skip to content

Commit 117d88a

Browse files
authored
新增 weixin-java-aispeech 模块并实现智能对话核心接口
1 parent 72b19e9 commit 117d88a

27 files changed

Lines changed: 940 additions & 0 deletions

pom.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,7 @@
124124
<module>weixin-java-miniapp</module>
125125
<module>weixin-java-open</module>
126126
<module>weixin-java-qidian</module>
127+
<module>weixin-java-aispeech</module>
127128
<module>weixin-java-channel</module>
128129
<module>spring-boot-starters</module>
129130
<module>solon-plugins</module>

weixin-java-aispeech/pom.xml

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
<?xml version="1.0"?>
2+
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
3+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
4+
xmlns="http://maven.apache.org/POM/4.0.0">
5+
<modelVersion>4.0.0</modelVersion>
6+
<parent>
7+
<groupId>com.github.binarywang</groupId>
8+
<artifactId>wx-java</artifactId>
9+
<version>4.8.3.B</version>
10+
</parent>
11+
12+
<artifactId>weixin-java-aispeech</artifactId>
13+
<name>WxJava - Aispeech Java SDK</name>
14+
<description>微信智能对话 Java SDK</description>
15+
16+
<dependencies>
17+
<dependency>
18+
<groupId>com.github.binarywang</groupId>
19+
<artifactId>weixin-java-common</artifactId>
20+
<version>${project.version}</version>
21+
</dependency>
22+
23+
<dependency>
24+
<groupId>org.apache.httpcomponents.client5</groupId>
25+
<artifactId>httpclient5</artifactId>
26+
</dependency>
27+
<dependency>
28+
<groupId>org.apache.httpcomponents</groupId>
29+
<artifactId>httpmime</artifactId>
30+
<scope>provided</scope>
31+
</dependency>
32+
33+
<dependency>
34+
<groupId>org.testng</groupId>
35+
<artifactId>testng</artifactId>
36+
<scope>test</scope>
37+
</dependency>
38+
<dependency>
39+
<groupId>org.projectlombok</groupId>
40+
<artifactId>lombok</artifactId>
41+
</dependency>
42+
</dependencies>
43+
44+
<build>
45+
<plugins>
46+
<plugin>
47+
<groupId>org.apache.maven.plugins</groupId>
48+
<artifactId>maven-surefire-plugin</artifactId>
49+
<configuration>
50+
<suiteXmlFiles>
51+
<suiteXmlFile>src/test/resources/testng.xml</suiteXmlFile>
52+
</suiteXmlFiles>
53+
</configuration>
54+
</plugin>
55+
</plugins>
56+
</build>
57+
</project>
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
package me.chanjar.weixin.aispeech.api;
2+
3+
import java.util.List;
4+
import me.chanjar.weixin.aispeech.bean.dialog.AsyncTaskResult;
5+
import me.chanjar.weixin.aispeech.bean.dialog.BotIntent;
6+
import me.chanjar.weixin.aispeech.bean.dialog.DialogQueryRequest;
7+
import me.chanjar.weixin.aispeech.bean.dialog.DialogResult;
8+
import me.chanjar.weixin.aispeech.bean.dialog.PublishProgress;
9+
import me.chanjar.weixin.common.error.WxErrorException;
10+
11+
public interface WxAispeechDialogService {
12+
String getAccessToken(String appid, String account) throws WxErrorException;
13+
14+
String importBotJson(int mode, List<BotIntent> data) throws WxErrorException;
15+
16+
String publishBot() throws WxErrorException;
17+
18+
PublishProgress getPublishProgress(String env) throws WxErrorException;
19+
20+
AsyncTaskResult queryAsyncTask(String taskId) throws WxErrorException;
21+
22+
DialogResult query(DialogQueryRequest request) throws WxErrorException;
23+
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
package me.chanjar.weixin.aispeech.api;
2+
3+
import java.util.List;
4+
import java.util.Map;
5+
import me.chanjar.weixin.aispeech.bean.knowledge.KnowledgeInfo;
6+
import me.chanjar.weixin.aispeech.bean.knowledge.KnowledgeManualCreateRequest;
7+
import me.chanjar.weixin.aispeech.bean.knowledge.KnowledgeUpdateRequest;
8+
import me.chanjar.weixin.aispeech.bean.knowledge.KnowledgeUrlCreateRequest;
9+
import me.chanjar.weixin.common.error.WxErrorException;
10+
11+
public interface WxAispeechKnowledgeService {
12+
KnowledgeInfo createKnowledgeByUrl(String knowledgeBaseId, KnowledgeUrlCreateRequest request) throws WxErrorException;
13+
14+
KnowledgeInfo createKnowledgeByManual(String knowledgeBaseId, KnowledgeManualCreateRequest request) throws WxErrorException;
15+
16+
List<KnowledgeInfo> listKnowledge(String knowledgeBaseId, Integer page, Integer pageSize) throws WxErrorException;
17+
18+
KnowledgeInfo getKnowledge(String knowledgeId) throws WxErrorException;
19+
20+
KnowledgeInfo updateKnowledge(String knowledgeId, KnowledgeUpdateRequest request) throws WxErrorException;
21+
22+
boolean deleteKnowledge(String knowledgeId) throws WxErrorException;
23+
24+
List<KnowledgeInfo> searchKnowledge(String keyword, String knowledgeBaseId, Integer page, Integer pageSize)
25+
throws WxErrorException;
26+
27+
String postRaw(String path, Object requestBody) throws WxErrorException;
28+
29+
String getRaw(String path, Map<String, String> queryParams) throws WxErrorException;
30+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package me.chanjar.weixin.aispeech.api;
2+
3+
import me.chanjar.weixin.aispeech.config.WxAispeechConfigStorage;
4+
5+
public interface WxAispeechService {
6+
WxAispeechDialogService getDialogService();
7+
8+
WxAispeechKnowledgeService getKnowledgeService();
9+
10+
WxAispeechConfigStorage getConfigStorage();
11+
12+
void setConfigStorage(WxAispeechConfigStorage configStorage);
13+
}
Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
package me.chanjar.weixin.aispeech.api.impl;
2+
3+
import com.google.gson.JsonElement;
4+
import com.google.gson.JsonObject;
5+
import com.google.gson.reflect.TypeToken;
6+
import java.lang.reflect.Type;
7+
import java.util.HashMap;
8+
import java.util.List;
9+
import java.util.Map;
10+
import me.chanjar.weixin.aispeech.api.WxAispeechDialogService;
11+
import me.chanjar.weixin.aispeech.bean.dialog.AispeechApiResponse;
12+
import me.chanjar.weixin.aispeech.bean.dialog.AsyncTaskResult;
13+
import me.chanjar.weixin.aispeech.bean.dialog.BotIntent;
14+
import me.chanjar.weixin.aispeech.bean.dialog.DialogQueryRequest;
15+
import me.chanjar.weixin.aispeech.bean.dialog.DialogResult;
16+
import me.chanjar.weixin.aispeech.bean.dialog.PublishProgress;
17+
import me.chanjar.weixin.aispeech.util.WxAispeechSignUtil;
18+
import me.chanjar.weixin.common.error.WxError;
19+
import me.chanjar.weixin.common.error.WxErrorException;
20+
import me.chanjar.weixin.common.util.json.WxGsonBuilder;
21+
import org.apache.commons.lang3.StringUtils;
22+
23+
public class WxAispeechDialogServiceImpl implements WxAispeechDialogService {
24+
private final WxAispeechServiceImpl service;
25+
26+
public WxAispeechDialogServiceImpl(WxAispeechServiceImpl service) {
27+
this.service = service;
28+
}
29+
30+
@Override
31+
public String getAccessToken(String appid, String account) throws WxErrorException {
32+
Map<String, String> request = new HashMap<>();
33+
if (StringUtils.isNotBlank(account)) {
34+
request.put("account", account);
35+
}
36+
37+
String response = service.executeDialogPost("/v2/token", request, false, appid);
38+
Type type = new TypeToken<AispeechApiResponse<JsonObject>>() { } .getType();
39+
AispeechApiResponse<JsonObject> result = WxGsonBuilder.create().fromJson(response, type);
40+
ensureSuccess(result);
41+
String token = result.getData().get("access_token").getAsString();
42+
service.getConfigStorage().setOpenAiToken(token);
43+
return token;
44+
}
45+
46+
@Override
47+
public String importBotJson(int mode, List<BotIntent> data) throws WxErrorException {
48+
Map<String, Object> request = new HashMap<>();
49+
request.put("mode", mode);
50+
request.put("data", data);
51+
52+
String response = service.executeDialogPost("/v2/bot/import/json", request, true, null);
53+
Type type = new TypeToken<AispeechApiResponse<JsonObject>>() { } .getType();
54+
AispeechApiResponse<JsonObject> result = WxGsonBuilder.create().fromJson(response, type);
55+
ensureSuccess(result);
56+
return result.getData().get("task_id").getAsString();
57+
}
58+
59+
@Override
60+
public String publishBot() throws WxErrorException {
61+
String response = service.executeDialogPost("/v2/bot/publish", "{}", true, null);
62+
Type type = new TypeToken<AispeechApiResponse<JsonObject>>() { } .getType();
63+
AispeechApiResponse<JsonObject> result = WxGsonBuilder.create().fromJson(response, type);
64+
ensureSuccess(result);
65+
return result.getRequestId();
66+
}
67+
68+
@Override
69+
public PublishProgress getPublishProgress(String env) throws WxErrorException {
70+
Map<String, String> request = new HashMap<>();
71+
request.put("env", env);
72+
73+
String response = service.executeDialogPost("/v2/bot/effective_progress", request, true, null);
74+
Type type = new TypeToken<AispeechApiResponse<PublishProgress>>() { } .getType();
75+
AispeechApiResponse<PublishProgress> result = WxGsonBuilder.create().fromJson(response, type);
76+
ensureSuccess(result);
77+
return result.getData();
78+
}
79+
80+
@Override
81+
public AsyncTaskResult queryAsyncTask(String taskId) throws WxErrorException {
82+
Map<String, String> request = new HashMap<>();
83+
request.put("task_id", taskId);
84+
85+
String response = service.executeDialogPost("/v2/async/fetch", request, true, null);
86+
Type type = new TypeToken<AispeechApiResponse<AsyncTaskResult>>() { } .getType();
87+
AispeechApiResponse<AsyncTaskResult> result = WxGsonBuilder.create().fromJson(response, type);
88+
ensureSuccess(result);
89+
return result.getData();
90+
}
91+
92+
@Override
93+
public DialogResult query(DialogQueryRequest request) throws WxErrorException {
94+
String json = WxGsonBuilder.create().toJson(request);
95+
String encrypted = WxAispeechSignUtil.encryptAesCbcToBase64(json, service.getConfigStorage().getAesKey());
96+
String response = service.executeDialogPost("/v2/bot/query", encrypted, true, null);
97+
98+
String responseJson = response;
99+
if (!looksLikeJson(response)) {
100+
responseJson = WxAispeechSignUtil.decryptAesCbcFromBase64(response, service.getConfigStorage().getAesKey());
101+
}
102+
103+
Type type = new TypeToken<AispeechApiResponse<DialogResult>>() { } .getType();
104+
AispeechApiResponse<DialogResult> result = WxGsonBuilder.create().fromJson(responseJson, type);
105+
ensureSuccess(result);
106+
107+
DialogResult dialogResult = result.getData();
108+
if (dialogResult != null && looksLikeJson(dialogResult.getAnswer())) {
109+
dialogResult.setRawAnswer(WxGsonBuilder.create().fromJson(dialogResult.getAnswer(), JsonElement.class));
110+
}
111+
return dialogResult;
112+
}
113+
114+
private boolean looksLikeJson(String value) {
115+
return StringUtils.isNotBlank(value) && (value.startsWith("{") || value.startsWith("["));
116+
}
117+
118+
private void ensureSuccess(AispeechApiResponse<?> response) throws WxErrorException {
119+
if (response == null) {
120+
throw new WxErrorException("响应为空");
121+
}
122+
if (response.getCode() == null || response.getCode() != 0) {
123+
throw new WxErrorException(WxError.builder()
124+
.errorCode(response.getCode() == null ? -1 : response.getCode())
125+
.errorMsg(response.getMsg())
126+
.build());
127+
}
128+
}
129+
}
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
package me.chanjar.weixin.aispeech.api.impl;
2+
3+
import com.google.gson.reflect.TypeToken;
4+
import java.lang.reflect.Type;
5+
import java.util.HashMap;
6+
import java.util.List;
7+
import java.util.Map;
8+
import me.chanjar.weixin.aispeech.api.WxAispeechKnowledgeService;
9+
import me.chanjar.weixin.aispeech.bean.knowledge.KnowledgeInfo;
10+
import me.chanjar.weixin.aispeech.bean.knowledge.KnowledgeListResult;
11+
import me.chanjar.weixin.aispeech.bean.knowledge.KnowledgeManualCreateRequest;
12+
import me.chanjar.weixin.aispeech.bean.knowledge.KnowledgeUpdateRequest;
13+
import me.chanjar.weixin.aispeech.bean.knowledge.KnowledgeUrlCreateRequest;
14+
import me.chanjar.weixin.common.error.WxErrorException;
15+
import me.chanjar.weixin.common.util.json.WxGsonBuilder;
16+
import org.apache.commons.lang3.StringUtils;
17+
18+
public class WxAispeechKnowledgeServiceImpl implements WxAispeechKnowledgeService {
19+
private final WxAispeechServiceImpl service;
20+
21+
public WxAispeechKnowledgeServiceImpl(WxAispeechServiceImpl service) {
22+
this.service = service;
23+
}
24+
25+
@Override
26+
public KnowledgeInfo createKnowledgeByUrl(String knowledgeBaseId, KnowledgeUrlCreateRequest request)
27+
throws WxErrorException {
28+
String response = service.executeKnowledgePost("/api/v1/knowledge-bases/" + knowledgeBaseId + "/knowledge/url", request);
29+
return WxGsonBuilder.create().fromJson(response, KnowledgeInfo.class);
30+
}
31+
32+
@Override
33+
public KnowledgeInfo createKnowledgeByManual(String knowledgeBaseId, KnowledgeManualCreateRequest request)
34+
throws WxErrorException {
35+
String response = service.executeKnowledgePost("/api/v1/knowledge-bases/" + knowledgeBaseId + "/knowledge/manual", request);
36+
return WxGsonBuilder.create().fromJson(response, KnowledgeInfo.class);
37+
}
38+
39+
@Override
40+
public List<KnowledgeInfo> listKnowledge(String knowledgeBaseId, Integer page, Integer pageSize)
41+
throws WxErrorException {
42+
Map<String, String> query = new HashMap<>();
43+
query.put("page", page == null ? null : String.valueOf(page));
44+
query.put("page_size", pageSize == null ? null : String.valueOf(pageSize));
45+
String response = service.executeKnowledgeGet("/api/v1/knowledge-bases/" + knowledgeBaseId + "/knowledge", query);
46+
KnowledgeListResult result = WxGsonBuilder.create().fromJson(response, KnowledgeListResult.class);
47+
return result == null ? null : result.getData();
48+
}
49+
50+
@Override
51+
public KnowledgeInfo getKnowledge(String knowledgeId) throws WxErrorException {
52+
String response = service.executeKnowledgeGet("/api/v1/knowledge/" + knowledgeId, null);
53+
return WxGsonBuilder.create().fromJson(response, KnowledgeInfo.class);
54+
}
55+
56+
@Override
57+
public KnowledgeInfo updateKnowledge(String knowledgeId, KnowledgeUpdateRequest request) throws WxErrorException {
58+
String response = service.executeKnowledgePut("/api/v1/knowledge/" + knowledgeId, request);
59+
return WxGsonBuilder.create().fromJson(response, KnowledgeInfo.class);
60+
}
61+
62+
@Override
63+
public boolean deleteKnowledge(String knowledgeId) throws WxErrorException {
64+
String response = service.executeKnowledgeDelete("/api/v1/knowledge/" + knowledgeId);
65+
return StringUtils.isNotBlank(response);
66+
}
67+
68+
@Override
69+
public List<KnowledgeInfo> searchKnowledge(String keyword, String knowledgeBaseId, Integer page, Integer pageSize)
70+
throws WxErrorException {
71+
Map<String, String> query = new HashMap<>();
72+
query.put("keyword", keyword);
73+
query.put("knowledge_base_id", knowledgeBaseId);
74+
query.put("page", page == null ? null : String.valueOf(page));
75+
query.put("page_size", pageSize == null ? null : String.valueOf(pageSize));
76+
String response = service.executeKnowledgeGet("/api/v1/knowledge/search", query);
77+
78+
Type listType = new TypeToken<List<KnowledgeInfo>>() { } .getType();
79+
return WxGsonBuilder.create().fromJson(response, listType);
80+
}
81+
82+
@Override
83+
public String postRaw(String path, Object requestBody) throws WxErrorException {
84+
return service.executeKnowledgePost(path, requestBody);
85+
}
86+
87+
@Override
88+
public String getRaw(String path, Map<String, String> queryParams) throws WxErrorException {
89+
return service.executeKnowledgeGet(path, queryParams);
90+
}
91+
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
package me.chanjar.weixin.aispeech.api.impl;
2+
3+
public class WxAispeechServiceHttpClientImpl extends WxAispeechServiceHttpComponentsImpl {
4+
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
package me.chanjar.weixin.aispeech.api.impl;
2+
3+
public class WxAispeechServiceHttpComponentsImpl extends WxAispeechServiceImpl {
4+
}

0 commit comments

Comments
 (0)