Compare commits
23 Commits
e7fae929a1
...
dev
| Author | SHA1 | Date | |
|---|---|---|---|
| 7c49702d87 | |||
| 95a5bf5467 | |||
| dbec50b023 | |||
| bc378a5c59 | |||
| e53760f280 | |||
| f770fcc8fb | |||
| 204907d738 | |||
| 925a7af045 | |||
| a7676fa6db | |||
| 9ab99b22e2 | |||
| 5d7ec8e67d | |||
| 8ea93c0d61 | |||
| 9e062976ac | |||
| 7637aa2fec | |||
| 9347eb9cde | |||
| bc483e50b5 | |||
| b55991798f | |||
| 12f224b8f3 | |||
| 068964145f | |||
| 864d5960a7 | |||
| 94890f001c | |||
| 73566a41e5 | |||
| 56774792c1 |
2
pom.xml
2
pom.xml
@@ -167,7 +167,7 @@
|
||||
<dependency>
|
||||
<groupId>com.baidubce</groupId>
|
||||
<artifactId>qianfan</artifactId>
|
||||
<version>0.1.1</version>
|
||||
<version>0.1.4</version>
|
||||
</dependency>
|
||||
<!-- https://mvnrepository.com/artifact/org.apache.logging.log4j/log4j-core -->
|
||||
<dependency>
|
||||
|
||||
@@ -10,6 +10,7 @@ import com.yutou.napcat.http.NapCatApi;
|
||||
import com.yutou.qqbot.QQBotManager;
|
||||
import com.yutou.qqbot.utlis.Base64Tools;
|
||||
import lombok.val;
|
||||
import okhttp3.Headers;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
@@ -42,7 +43,7 @@ public class NapCatQQ {
|
||||
.build()
|
||||
).enqueue(new HttpCallback<SendMessageResponse>() {
|
||||
@Override
|
||||
public void onResponse(int code, String status, SendMessageResponse response, String rawResponse) {
|
||||
public void onResponse(Headers headers, int code, String status, SendMessageResponse response, String rawResponse) {
|
||||
System.out.println("code = " + code + ", status = " + status + ", response = " + response + ", rawResponse = " + rawResponse);
|
||||
}
|
||||
|
||||
|
||||
@@ -107,6 +107,7 @@ public class MessageEvent {
|
||||
event.setSource(sender);
|
||||
sender.setUserId(json.getJSONObject("sender").getLong("user_id"));
|
||||
sender.setNickname(json.getJSONObject("sender").getString("nickname"));
|
||||
sender.setRole(json.getJSONObject("sender").getString("role"));
|
||||
sender.setCard(json.getJSONObject("sender").getString("card"));
|
||||
event.setMessageId(json.getInteger("message_id"));
|
||||
event.setRealId(json.getInteger("real_id"));
|
||||
|
||||
@@ -6,9 +6,7 @@ import com.yutou.napcat.model.GroupUserBean;
|
||||
import com.yutou.okhttp.BaseBean;
|
||||
import com.yutou.okhttp.HttpBody;
|
||||
import retrofit2.Call;
|
||||
import retrofit2.http.Field;
|
||||
import retrofit2.http.FormUrlEncoded;
|
||||
import retrofit2.http.POST;
|
||||
import retrofit2.http.*;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@@ -20,12 +18,11 @@ public interface GroupApi {
|
||||
* @param user 用户
|
||||
* @param duration 禁言时长,单位秒
|
||||
*/
|
||||
@FormUrlEncoded
|
||||
@POST("/set_group_ban")
|
||||
@GET("/set_group_ban")
|
||||
Call<HttpBody<BaseBean>> groupBan(
|
||||
@Field("group_id") long group,
|
||||
@Field("user_id") long user,
|
||||
@Field("duration") long duration
|
||||
@Query("group_id") long group,
|
||||
@Query("user_id") long user,
|
||||
@Query("duration") long duration
|
||||
);
|
||||
|
||||
/**
|
||||
|
||||
@@ -5,10 +5,14 @@ import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class SourceFrom {
|
||||
public static final String USER_ROLE_OWNER="owner";//群主
|
||||
public static final String USER_ROLE_ADMIN="admin";//管理
|
||||
public static final String USER_ROLE_MEMBER="member";//成员
|
||||
@JSONField(name = "user_id")
|
||||
private long userId;
|
||||
private String nickname;
|
||||
private String card;
|
||||
@JSONField(name = "role")
|
||||
private String role;
|
||||
|
||||
public Long getFromId() {
|
||||
|
||||
11
src/main/java/com/yutou/okhttp/FileBody.java
Normal file
11
src/main/java/com/yutou/okhttp/FileBody.java
Normal file
@@ -0,0 +1,11 @@
|
||||
package com.yutou.okhttp;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.InputStream;
|
||||
|
||||
@Data
|
||||
public class FileBody<T> {
|
||||
InputStream inputStream;
|
||||
T t;
|
||||
}
|
||||
112
src/main/java/com/yutou/okhttp/FileCallback.java
Normal file
112
src/main/java/com/yutou/okhttp/FileCallback.java
Normal file
@@ -0,0 +1,112 @@
|
||||
package com.yutou.okhttp;
|
||||
|
||||
import com.yutou.qqbot.utlis.Log;
|
||||
import okhttp3.Headers;
|
||||
import okhttp3.HttpUrl;
|
||||
import retrofit2.Call;
|
||||
import retrofit2.Callback;
|
||||
import retrofit2.Response;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.concurrent.ArrayBlockingQueue;
|
||||
import java.util.concurrent.ThreadPoolExecutor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public abstract class FileCallback<T> implements Callback<FileBody<T>> {
|
||||
|
||||
private static ThreadPoolExecutor executor;
|
||||
private final T bean;
|
||||
private String savePath;
|
||||
|
||||
public FileCallback(T bean, String savePath) {
|
||||
this.bean = bean;
|
||||
this.savePath = savePath;
|
||||
if (executor == null) {
|
||||
executor = new ThreadPoolExecutor(2, 4, Long.MAX_VALUE, TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(100));
|
||||
}
|
||||
}
|
||||
|
||||
private class DownloadTask implements Runnable {
|
||||
private T bean;
|
||||
private Headers headers;
|
||||
private HttpUrl url;
|
||||
private InputStream inputStream;
|
||||
|
||||
public DownloadTask(T bean, Headers headers, HttpUrl url, InputStream inputStream) {
|
||||
this.bean = bean;
|
||||
|
||||
this.headers = headers;
|
||||
this.url = url;
|
||||
this.inputStream = inputStream;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
Log.i("开始下载");
|
||||
File file = new File(savePath);
|
||||
onStart(bean);
|
||||
if (!file.exists()) {
|
||||
boolean mkdirs = file.getParentFile().mkdirs();
|
||||
Log.i("mkdirs = " + mkdirs);
|
||||
}
|
||||
FileOutputStream outputStream = new FileOutputStream(file);
|
||||
int len;
|
||||
long total = 0;
|
||||
byte[] bytes = new byte[4096];
|
||||
boolean isDownload = true;
|
||||
long available = inputStream.available();
|
||||
while ((len = inputStream.read(bytes)) != -1 && isDownload) {
|
||||
total += len;
|
||||
outputStream.write(bytes, 0, len);
|
||||
outputStream.flush();
|
||||
isDownload = onDownload(headers, bean, total, available);
|
||||
}
|
||||
Log.i("下载完成");
|
||||
outputStream.close();
|
||||
} catch (Exception e) {
|
||||
Log.e(e);
|
||||
onFailure(bean,e);
|
||||
} finally {
|
||||
onFinish(bean);
|
||||
try {
|
||||
inputStream.close();
|
||||
} catch (IOException e) {
|
||||
Log.e(e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public abstract void onStart(T bean);
|
||||
|
||||
public abstract boolean onDownload(Headers headers, T bean, long len, long total);
|
||||
|
||||
public abstract void onFinish(T bean);
|
||||
|
||||
public abstract void onFailure(T bean, Throwable throwable);
|
||||
|
||||
@Override
|
||||
public void onResponse(Call<FileBody<T>> call, Response<FileBody<T>> response) {
|
||||
try {
|
||||
executor.execute(new DownloadTask(bean, response.headers(), call.request().url(), response.body().getInputStream()));
|
||||
} catch (Exception e) {
|
||||
Log.e(e);
|
||||
onFailure(bean,e);
|
||||
call.cancel();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Call<FileBody<T>> call, Throwable throwable) {
|
||||
onFailure(bean, throwable);
|
||||
call.cancel();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
package com.yutou.okhttp;
|
||||
|
||||
|
||||
import okhttp3.Headers;
|
||||
import okhttp3.HttpUrl;
|
||||
import okhttp3.Request;
|
||||
|
||||
@@ -14,12 +15,18 @@ public class GetRequestParams implements IRequestParam {
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public Request getRequest(HashMap<String, String> map, Request request) {
|
||||
public Request getRequest(HashMap<String, String> headerMap, HashMap<String, String> map, Request request) {
|
||||
Headers.Builder headerBuild = request.headers().newBuilder();
|
||||
if (!headerMap.isEmpty()) {
|
||||
for (String key : headerMap.keySet()) {
|
||||
headerBuild.add(key, headerMap.get(key));
|
||||
}
|
||||
}
|
||||
//添加公共参数
|
||||
HttpUrl.Builder builder = request.url().newBuilder();
|
||||
for (String key : map.keySet()) {
|
||||
builder.addQueryParameter(key, String.valueOf(map.get(key)));
|
||||
}
|
||||
return request.newBuilder().url(builder.build()).build();
|
||||
return request.newBuilder().url(builder.build()).headers(headerBuild.build()).build();
|
||||
}
|
||||
}
|
||||
@@ -1,12 +1,13 @@
|
||||
package com.yutou.okhttp;
|
||||
|
||||
import okhttp3.Headers;
|
||||
import retrofit2.Call;
|
||||
import retrofit2.Callback;
|
||||
import retrofit2.Response;
|
||||
|
||||
public abstract class HttpCallback<T> implements Callback<HttpBody<T>> {
|
||||
|
||||
public abstract void onResponse(int code, String status, T response, String rawResponse);
|
||||
public abstract void onResponse(Headers headers,int code, String status, T response, String rawResponse);
|
||||
|
||||
public abstract void onFailure(Throwable throwable);
|
||||
|
||||
@@ -14,6 +15,7 @@ public abstract class HttpCallback<T> implements Callback<HttpBody<T>> {
|
||||
public void onResponse(Call<HttpBody<T>> call, Response<HttpBody<T>> response) {
|
||||
if (response.body() != null) {
|
||||
onResponse(
|
||||
response.headers(),
|
||||
response.body().getRetcode(),
|
||||
response.body().getStatus(),
|
||||
response.body().getData(),
|
||||
@@ -22,10 +24,12 @@ public abstract class HttpCallback<T> implements Callback<HttpBody<T>> {
|
||||
} else {
|
||||
onFailure(new NullPointerException("response body is null"));
|
||||
}
|
||||
call.cancel();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Call<HttpBody<T>> call, Throwable throwable) {
|
||||
onFailure(throwable);
|
||||
call.cancel();
|
||||
}
|
||||
}
|
||||
|
||||
145
src/main/java/com/yutou/okhttp/HttpDownloadUtils.java
Normal file
145
src/main/java/com/yutou/okhttp/HttpDownloadUtils.java
Normal file
@@ -0,0 +1,145 @@
|
||||
package com.yutou.okhttp;
|
||||
|
||||
import com.yutou.qqbot.interfaces.DownloadInterface;
|
||||
import com.yutou.qqbot.utlis.ConfigTools;
|
||||
import com.yutou.qqbot.utlis.Log;
|
||||
import lombok.Data;
|
||||
import okhttp3.*;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public class HttpDownloadUtils {
|
||||
public static void download(Builder builder) {
|
||||
createHttpClient(builder).enqueue(new Callback() {
|
||||
@Override
|
||||
public void onFailure(@NotNull Call call, @NotNull IOException e) {
|
||||
if (builder.downloadInterface != null) {
|
||||
builder.downloadInterface.onError(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResponse(@NotNull Call call, @NotNull Response response) throws IOException {
|
||||
InputStream inputStream = Objects.requireNonNull(response.body()).byteStream();
|
||||
File target;
|
||||
if (StringUtils.hasText(builder.fileName)) {
|
||||
target = new File(builder.path, builder.fileName);
|
||||
} else {
|
||||
target = new File(builder.path);
|
||||
}
|
||||
FileOutputStream fileOutputStream = new FileOutputStream(target);
|
||||
if (builder.downloadInterface != null) {
|
||||
builder.downloadInterface.onDownloadStart();
|
||||
}
|
||||
try {
|
||||
byte[] buffer = new byte[2048];
|
||||
int len;
|
||||
long soFarBytes = 0;
|
||||
long totalBytes = inputStream.available();
|
||||
while ((len = inputStream.read(buffer)) != -1) {
|
||||
fileOutputStream.write(buffer, 0, len);
|
||||
soFarBytes += len;
|
||||
if (builder.downloadInterface != null) {
|
||||
if (!builder.downloadInterface.onDownloading(soFarBytes, totalBytes)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
fileOutputStream.flush();
|
||||
} catch (IOException e) {
|
||||
Log.e(e,"download error:", builder.url);
|
||||
} finally {
|
||||
if (builder.downloadInterface != null) {
|
||||
builder.downloadInterface.onDownload(target);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static File downloadSync(Builder builder) {
|
||||
try {
|
||||
Response response = createHttpClient(builder).execute();
|
||||
InputStream inputStream = Objects.requireNonNull(response.body()).byteStream();
|
||||
File target;
|
||||
if (StringUtils.hasText(builder.fileName)) {
|
||||
target = new File(builder.path, builder.fileName);
|
||||
} else {
|
||||
target = new File(builder.path);
|
||||
}
|
||||
try (FileOutputStream fileOutputStream = new FileOutputStream(target)) {
|
||||
byte[] buffer = new byte[2048];
|
||||
int len;
|
||||
while ((len = inputStream.read(buffer)) != -1) {
|
||||
fileOutputStream.write(buffer, 0, len);
|
||||
}
|
||||
fileOutputStream.flush();
|
||||
return target;
|
||||
} catch (IOException e) {
|
||||
Log.e(e,"download error:" , builder.url);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static Call createHttpClient(Builder builder) {
|
||||
OkHttpClient okHttpClient = new OkHttpClient.Builder()
|
||||
.connectTimeout(2, TimeUnit.MINUTES)
|
||||
.readTimeout(2, TimeUnit.MINUTES)
|
||||
.build();
|
||||
Request.Builder rb = new Request.Builder()
|
||||
.get()
|
||||
.addHeader("User-Agent", ConfigTools.getUserAgent())
|
||||
.url(builder.url);
|
||||
if (StringUtils.hasText(builder.cookie)) {
|
||||
rb.addHeader("Set-Cookie", builder.cookie);
|
||||
rb.addHeader("Cookie", builder.cookie);
|
||||
}
|
||||
Request request = rb.build();
|
||||
return okHttpClient.newCall(request);
|
||||
}
|
||||
|
||||
@Data
|
||||
public static class Builder {
|
||||
String url;
|
||||
String path;
|
||||
String fileName;
|
||||
DownloadInterface downloadInterface;
|
||||
String cookie;
|
||||
|
||||
public Builder setUrl(String url) {
|
||||
this.url = url;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setPath(String path) {
|
||||
this.path = path;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setFileName(String fileName) {
|
||||
this.fileName = fileName;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setDownloadInterface(DownloadInterface downloadInterface) {
|
||||
this.downloadInterface = downloadInterface;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setCookie(String cookie) {
|
||||
this.cookie = cookie;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,34 +1,25 @@
|
||||
package com.yutou.okhttp;
|
||||
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import com.yutou.qqbot.utlis.Log;
|
||||
import okhttp3.Connection;
|
||||
import okhttp3.Headers;
|
||||
import okhttp3.Interceptor;
|
||||
import okhttp3.MediaType;
|
||||
import okhttp3.Protocol;
|
||||
import okhttp3.Request;
|
||||
import okhttp3.RequestBody;
|
||||
import okhttp3.Response;
|
||||
import okhttp3.ResponseBody;
|
||||
import lombok.val;
|
||||
import okhttp3.*;
|
||||
import okhttp3.internal.http.HttpHeaders;
|
||||
import okio.Buffer;
|
||||
import okio.BufferedSource;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
public class HttpLoggingInterceptor implements Interceptor {
|
||||
private static final String TAG = "HttpLogging";
|
||||
|
||||
private static final Charset UTF8 = Charset.forName("UTF-8");
|
||||
private static final Charset UTF8 = StandardCharsets.UTF_8;
|
||||
|
||||
private volatile Level printLevel = Level.NONE;
|
||||
private volatile Level printLevel = Level.BODY;
|
||||
private java.util.logging.Level colorLevel;
|
||||
private Logger logger;
|
||||
|
||||
@@ -63,7 +54,8 @@ public class HttpLoggingInterceptor implements Interceptor {
|
||||
private void log(String message) {
|
||||
//logger.log(colorLevel, message);
|
||||
if (prLog) {
|
||||
Log.i(TAG, message);
|
||||
// Log.getDynamicLogger(TAG).info(message);
|
||||
System.out.println(message);
|
||||
}
|
||||
//Log.e(TAG,message);
|
||||
}
|
||||
@@ -71,8 +63,11 @@ public class HttpLoggingInterceptor implements Interceptor {
|
||||
@Override
|
||||
public Response intercept(Chain chain) throws IOException {
|
||||
Request request = chain.request();
|
||||
if (request.body().contentLength() == 0) {
|
||||
request = chain.call().request();
|
||||
if (request.body() != null && request.body().contentLength() == 0) {
|
||||
val headers = request.headers();
|
||||
request = chain.call().request().newBuilder()
|
||||
.headers(headers)
|
||||
.build();
|
||||
}
|
||||
if (printLevel == Level.NONE) {
|
||||
return chain.proceed(request);
|
||||
@@ -109,8 +104,6 @@ public class HttpLoggingInterceptor implements Interceptor {
|
||||
|
||||
if (logHeaders) {
|
||||
if (hasRequestBody) {
|
||||
// Request body headers are only present when installed as a network interceptor. Force
|
||||
// them to be included (when available) so there values are known.
|
||||
if (requestBody.contentType() != null) {
|
||||
log("\tContent-Type: " + requestBody.contentType());
|
||||
}
|
||||
@@ -121,7 +114,6 @@ public class HttpLoggingInterceptor implements Interceptor {
|
||||
Headers headers = request.headers();
|
||||
for (int i = 0, count = headers.size(); i < count; i++) {
|
||||
String name = headers.name(i);
|
||||
// Skip headers from the request body as they are explicitly logged above.
|
||||
if (!"Content-Type".equalsIgnoreCase(name) && !"Content-Length".equalsIgnoreCase(name)) {
|
||||
log("\t" + name + ": " + headers.value(i));
|
||||
}
|
||||
@@ -151,7 +143,7 @@ public class HttpLoggingInterceptor implements Interceptor {
|
||||
boolean logHeaders = (printLevel == Level.BODY || printLevel == Level.HEADERS);
|
||||
|
||||
try {
|
||||
log("<-- " + clone.code() + ' ' + clone.message() + ' ' + clone.request().url() + " (" + tookMs + "ms)");
|
||||
log("<-- " + clone.code() + ' ' + clone.message() + ' ' + clone.request().url() + " (" + tookMs + "ms)");
|
||||
if (logHeaders) {
|
||||
Headers headers = clone.headers();
|
||||
for (int i = 0, count = headers.size(); i < count; i++) {
|
||||
@@ -162,12 +154,13 @@ public class HttpLoggingInterceptor implements Interceptor {
|
||||
if (responseBody == null) return response;
|
||||
|
||||
if (isPlaintext(responseBody.contentType())) {
|
||||
byte[] bytes = responseBody.byteStream().readAllBytes();
|
||||
MediaType contentType = responseBody.contentType();
|
||||
String body = new String(bytes, getCharset(contentType));
|
||||
BufferedSource source = responseBody.source();
|
||||
source.request(Long.MAX_VALUE); // 请求整个流
|
||||
Buffer buffer = source.buffer();
|
||||
|
||||
Charset charset = getCharset(responseBody.contentType());
|
||||
String body = buffer.clone().readString(charset);
|
||||
log("\tbody:" + body);
|
||||
responseBody = ResponseBody.create(responseBody.contentType(), bytes);
|
||||
return response.newBuilder().body(responseBody).build();
|
||||
} else {
|
||||
log("\tbody: maybe [binary body], omitted!");
|
||||
}
|
||||
@@ -214,6 +207,8 @@ public class HttpLoggingInterceptor implements Interceptor {
|
||||
body.writeTo(buffer);
|
||||
Charset charset = getCharset(body.contentType());
|
||||
log("\tbody:" + buffer.readString(charset));
|
||||
// 重置请求体以确保后续处理不受影响
|
||||
buffer.clear();
|
||||
} catch (Exception e) {
|
||||
logger.log(java.util.logging.Level.WARNING, e.getMessage(), e);
|
||||
}
|
||||
|
||||
@@ -5,5 +5,5 @@ import okhttp3.Request;
|
||||
import java.util.HashMap;
|
||||
|
||||
public interface IRequestParam {
|
||||
Request getRequest(HashMap<String,String> map, Request request);
|
||||
Request getRequest(HashMap<String,String> header, HashMap<String,String> map, Request request);
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
package com.yutou.okhttp;
|
||||
|
||||
import com.yutou.qqbot.utlis.ConfigTools;
|
||||
import okhttp3.Request;
|
||||
|
||||
import java.util.HashMap;
|
||||
@@ -7,14 +8,25 @@ import java.util.HashMap;
|
||||
public class ParamsContext {
|
||||
private IRequestParam iRequestParam;
|
||||
private Request request;
|
||||
private HashMap<String,String> map;
|
||||
private HashMap<String, String> map;
|
||||
private HashMap<String, String> headerMap;
|
||||
|
||||
public ParamsContext(HashMap<String,String> map,Request request) {
|
||||
if(map==null){
|
||||
map=new HashMap<>();
|
||||
public ParamsContext(HashMap<String, String> map, Request request) {
|
||||
if (map == null) {
|
||||
map = new HashMap<>();
|
||||
}
|
||||
this.map=map;
|
||||
this.map = map;
|
||||
this.request = request;
|
||||
this.headerMap = new HashMap<>();
|
||||
}
|
||||
|
||||
public ParamsContext(HashMap<String, String> headerMap, HashMap<String, String> map, Request request) {
|
||||
if (map == null) {
|
||||
map = new HashMap<>();
|
||||
}
|
||||
this.map = map;
|
||||
this.request = request;
|
||||
this.headerMap = headerMap;
|
||||
}
|
||||
|
||||
public Request getInRequest() {
|
||||
@@ -26,6 +38,7 @@ public class ParamsContext {
|
||||
iRequestParam = new PostRequestParams();
|
||||
break;
|
||||
}
|
||||
return iRequestParam.getRequest(map,request);
|
||||
headerMap.put("User-Agent", ConfigTools.getUserAgent());
|
||||
return iRequestParam.getRequest(headerMap, map, request);
|
||||
}
|
||||
}
|
||||
@@ -2,22 +2,26 @@ package com.yutou.okhttp;
|
||||
|
||||
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
|
||||
import com.yutou.qqbot.utlis.Log;
|
||||
import okhttp3.*;
|
||||
|
||||
import java.net.URLEncoder;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
public class PostRequestParams implements IRequestParam {
|
||||
@Override
|
||||
public Request getRequest(HashMap<String, String> map, Request request) {
|
||||
public Request getRequest(HashMap<String, String> headerMap, HashMap<String, String> map, Request request) {
|
||||
Headers.Builder headerBuilder = request.headers().newBuilder();
|
||||
if (!headerMap.isEmpty()) {
|
||||
for (String key : headerMap.keySet()) {
|
||||
headerBuilder.add(key, headerMap.get(key));
|
||||
}
|
||||
}
|
||||
if (request.body() instanceof FormBody) {
|
||||
FormBody.Builder bodyBuilder = new FormBody.Builder();
|
||||
FormBody formBody = (FormBody) request.body();
|
||||
|
||||
for (int i = 0; i < formBody.size(); i++) {
|
||||
bodyBuilder.addEncoded(formBody.encodedName(i), formBody.encodedValue(i));
|
||||
}
|
||||
@@ -25,10 +29,12 @@ public class PostRequestParams implements IRequestParam {
|
||||
bodyBuilder.addEncoded(key, String.valueOf(map.get(key)));
|
||||
}
|
||||
formBody = bodyBuilder.build();
|
||||
request = request.newBuilder().post(formBody).build();
|
||||
request = request.newBuilder().headers(headerBuilder.build()).post(formBody).build();
|
||||
} else if (request.body() != null) {
|
||||
RequestBody requestBody = RequestBody.create(MediaType.parse("application/json; charset=utf-8"),toUrlParams(map));
|
||||
request = request.newBuilder().post(request.body())
|
||||
RequestBody requestBody = RequestBody.create(MediaType.parse("application/json; charset=utf-8"), toUrlParams(map));
|
||||
request = request.newBuilder()
|
||||
.headers(headerBuilder.build())
|
||||
.post(request.body())
|
||||
.post(requestBody).build();
|
||||
}
|
||||
return request;
|
||||
@@ -41,9 +47,9 @@ public class PostRequestParams implements IRequestParam {
|
||||
try {
|
||||
string.append("&").append(key).append("=").append(URLEncoder.encode(json.getString(key), "UTF-8"));
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
Log.e(e);
|
||||
try {
|
||||
string.append("&").append(URLEncoder.encode(key,"UTF-8")).append("=");
|
||||
string.append("&").append(URLEncoder.encode(key, "UTF-8")).append("=");
|
||||
// string += "&" + key + "=";
|
||||
} catch (Exception e1) {
|
||||
string.append("&").append(key).append("=");
|
||||
@@ -56,7 +62,7 @@ public class PostRequestParams implements IRequestParam {
|
||||
}
|
||||
|
||||
public static String toUrlParams(Map<String, String> map) {
|
||||
if(map.isEmpty()){
|
||||
if (map.isEmpty()) {
|
||||
return "";
|
||||
}
|
||||
StringBuilder builder = new StringBuilder();
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
package com.yutou.okhttp.api;
|
||||
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
import com.google.gson.internal.bind.DateTypeAdapter;
|
||||
import com.yutou.okhttp.HttpBody;
|
||||
import com.yutou.okhttp.HttpLoggingInterceptor;
|
||||
import com.yutou.okhttp.ParamsContext;
|
||||
import com.yutou.okhttp.converter.JsonCallAdapter;
|
||||
import com.yutou.okhttp.converter.JsonConverterFactory;
|
||||
import okhttp3.Interceptor;
|
||||
import okhttp3.OkHttpClient;
|
||||
import okhttp3.Request;
|
||||
import okhttp3.Response;
|
||||
import lombok.val;
|
||||
import okhttp3.*;
|
||||
import retrofit2.CallAdapter;
|
||||
import retrofit2.Converter;
|
||||
import retrofit2.Retrofit;
|
||||
@@ -18,31 +18,55 @@ import retrofit2.Retrofit;
|
||||
import java.io.IOException;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.logging.Level;
|
||||
|
||||
public class BaseApi {
|
||||
private String URL;
|
||||
private HashMap<String, String> params;
|
||||
private HashMap<String, String> params = new HashMap<>();
|
||||
private HashMap<String, String> headers = new HashMap<>();
|
||||
|
||||
|
||||
public BaseApi setURL(String URL) {
|
||||
this.URL = URL;
|
||||
return this;
|
||||
}
|
||||
|
||||
public BaseApi setHeaders(HashMap<String, String> headers) {
|
||||
this.headers = headers;
|
||||
return this;
|
||||
}
|
||||
|
||||
public void addHeader(HashMap<String, String> headers) {
|
||||
this.headers.putAll(headers);
|
||||
}
|
||||
|
||||
|
||||
public BaseApi setParams(HashMap<String, String> params) {
|
||||
this.params = params;
|
||||
return this;
|
||||
}
|
||||
|
||||
public void useCookie(JSONObject json) {
|
||||
StringBuilder ck = new StringBuilder();
|
||||
json.remove("sql_time");
|
||||
json.remove("gourl");
|
||||
for (String key : json.keySet()) {
|
||||
ck.append(key).append("=").append(json.getString(key)).append(";");
|
||||
}
|
||||
headers.put("Cookie", ck.toString());
|
||||
setHeaders(headers);
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建一个接口方法
|
||||
*
|
||||
* @param okHttpClient okhttp客户端
|
||||
* @param converterFactory 处理工厂类
|
||||
* @param okHttpClient okhttp客户端
|
||||
* @param converterFactory 处理工厂类
|
||||
* @param callAdapterFactory 请求适配器工厂
|
||||
* @param baseUrl 基础地质
|
||||
* @param service 接口
|
||||
* @param <T> 接口泛型
|
||||
* @param baseUrl 基础地质
|
||||
* @param service 接口
|
||||
* @param <T> 接口泛型
|
||||
* @return 接口
|
||||
*/
|
||||
public <T> T create(OkHttpClient okHttpClient, Converter.Factory converterFactory, CallAdapter.Factory callAdapterFactory, String baseUrl, Class<T> service) {
|
||||
@@ -74,7 +98,10 @@ public class BaseApi {
|
||||
loggingInterceptor.setPrintLevel(HttpLoggingInterceptor.Level.BODY);
|
||||
OkHttpClient.Builder builder = new OkHttpClient()
|
||||
.newBuilder()
|
||||
|
||||
.callTimeout(2, TimeUnit.MINUTES)
|
||||
.readTimeout(2, TimeUnit.MINUTES)
|
||||
.connectTimeout(2, TimeUnit.MINUTES)
|
||||
.writeTimeout(2, TimeUnit.MINUTES)
|
||||
.addInterceptor(initQuery())
|
||||
.addInterceptor(loggingInterceptor);
|
||||
return create(builder.build(),
|
||||
@@ -83,14 +110,30 @@ public class BaseApi {
|
||||
URL,
|
||||
apiClass);
|
||||
}
|
||||
|
||||
public Interceptor initQuery() {
|
||||
Interceptor addQueryParameterInterceptor = new Interceptor() {
|
||||
@Override
|
||||
public Response intercept(Chain chain) throws IOException {
|
||||
Request request = chain.request();
|
||||
//配置公共参数
|
||||
request = new ParamsContext(params,request).getInRequest();
|
||||
return chain.proceed(request);
|
||||
request = new ParamsContext(headers, params, request).getInRequest();
|
||||
val proceed = chain.proceed(request);
|
||||
if (!proceed.isSuccessful()) {
|
||||
HttpBody<?> httpBody = new HttpBody<>();
|
||||
httpBody.setCode(200);
|
||||
val parse = JSONObject.parse(proceed.body().string());
|
||||
httpBody.setRetcode(parse.getInteger("code"));
|
||||
httpBody.setMsg(parse.getString("message"));
|
||||
ResponseBody errorResponseBody = ResponseBody.create(
|
||||
JSONObject.toJSONString(httpBody),
|
||||
MediaType.get("application/json; charset=utf-8"));
|
||||
val newResponse=proceed.newBuilder()
|
||||
.code(200)
|
||||
.body(errorResponseBody).build();
|
||||
return newResponse;
|
||||
}
|
||||
return proceed;
|
||||
}
|
||||
};
|
||||
return addQueryParameterInterceptor;
|
||||
|
||||
@@ -31,12 +31,26 @@ public class JsonResponseBodyConverter<T> implements Converter<ResponseBody, T>
|
||||
HttpBody<T> body;
|
||||
try {
|
||||
body = JSONObject.parseObject(string, type);
|
||||
if(body.getData()==null){
|
||||
JSONObject jt=JSONObject.parseObject(JSONObject.toJSONString(new HttpBody<>()));
|
||||
jt.put("data",JSONObject.parseObject(string));
|
||||
HttpBody<T> bt=JSONObject.parseObject(jt.toJSONString(),type);
|
||||
body.setData(bt.getData());
|
||||
}
|
||||
body.setSrc(string);
|
||||
return (T) body;
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
body = new HttpBody();
|
||||
body.setSrc(string);
|
||||
try {
|
||||
body = new HttpBody<>();
|
||||
body.setData(JSONObject.parseObject(string, type));
|
||||
body.setSrc(string);
|
||||
} catch (Exception e2) {
|
||||
e2.printStackTrace();
|
||||
body = new HttpBody<>();
|
||||
body.setSrc(string);
|
||||
}
|
||||
|
||||
}
|
||||
return (T) body;
|
||||
|
||||
|
||||
@@ -0,0 +1,87 @@
|
||||
package com.yutou.qqbot.Controllers;
|
||||
|
||||
|
||||
import com.alibaba.fastjson2.JSONArray;
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import com.yutou.qqbot.utlis.BangumiTools;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/bgm")
|
||||
public class AnimeController {
|
||||
@GetMapping("/today")
|
||||
public Map<String, Object> getTodayAnim() {
|
||||
Map<String, Object> returnData = new HashMap<>();
|
||||
// 获取全部一周的数据
|
||||
JSONObject allData = BangumiTools.getBangumi(-1);
|
||||
|
||||
if (allData == null) {
|
||||
return returnData;
|
||||
}
|
||||
|
||||
JSONArray bangumiArray = allData.getJSONArray("bangumi");
|
||||
if (bangumiArray == null || bangumiArray.isEmpty()) {
|
||||
return returnData;
|
||||
}
|
||||
|
||||
Calendar calendar = Calendar.getInstance();
|
||||
calendar.setTimeZone(TimeZone.getTimeZone("GMT+8:00"));
|
||||
calendar.setFirstDayOfWeek(Calendar.MONDAY);
|
||||
calendar.setTime(new Date());
|
||||
|
||||
int todayId = calendar.get(Calendar.DAY_OF_WEEK) - 1;
|
||||
if (todayId == 0) {
|
||||
todayId = 7; // 处理星期日的情况
|
||||
}
|
||||
|
||||
int tomorrowId = todayId % 7 + 1; // 计算明天对应的 weekday id
|
||||
|
||||
JSONObject todayData = null;
|
||||
JSONObject tomorrowData = null;
|
||||
|
||||
for (Object obj : bangumiArray) {
|
||||
JSONObject item = (JSONObject) obj;
|
||||
int weekdayId = item.getJSONObject("weekday").getInteger("id");
|
||||
|
||||
if (weekdayId == todayId) {
|
||||
todayData = item;
|
||||
}
|
||||
if (weekdayId == tomorrowId) {
|
||||
tomorrowData = item;
|
||||
}
|
||||
}
|
||||
|
||||
// 打印当日数据
|
||||
if (todayData != null) {
|
||||
JSONArray items = todayData.getJSONArray("items");
|
||||
if (items != null && !items.isEmpty()) {
|
||||
for (Object o : items) {
|
||||
JSONObject itemObj = (JSONObject) o;
|
||||
if (itemObj.getString("name_cn") == null || itemObj.getString("name_cn").isEmpty()) {
|
||||
itemObj.put("name_cn", itemObj.getString("name"));
|
||||
}
|
||||
}
|
||||
}
|
||||
returnData.put("today",todayData);
|
||||
}
|
||||
|
||||
// 打印明日数据
|
||||
if (tomorrowData != null) {
|
||||
JSONArray items = tomorrowData.getJSONArray("items");
|
||||
if (items != null && !items.isEmpty()) {
|
||||
for (Object o : items) {
|
||||
JSONObject itemObj = (JSONObject) o;
|
||||
if (itemObj.getString("name_cn") == null || itemObj.getString("name_cn").isEmpty()) {
|
||||
itemObj.put("name_cn", itemObj.getString("name"));
|
||||
}
|
||||
}
|
||||
}
|
||||
returnData.put("nextDay",tomorrowData);
|
||||
}
|
||||
return returnData;
|
||||
}
|
||||
}
|
||||
@@ -10,7 +10,7 @@ import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
|
||||
@SpringBootApplication
|
||||
public class QQBotApplication {
|
||||
public static final String version = "QQBot v.1.7.9.1";
|
||||
public static final String version = "QQBot v.1.7.24";
|
||||
|
||||
public static void main(String[] args) {
|
||||
System.out.println("version = " + version);
|
||||
|
||||
@@ -15,6 +15,7 @@ import com.yutou.okhttp.HttpCallback;
|
||||
import com.yutou.qqbot.data.MessageChainBuilder;
|
||||
import com.yutou.qqbot.interfaces.ObjectInterface;
|
||||
import com.yutou.qqbot.utlis.*;
|
||||
import okhttp3.Headers;
|
||||
import retrofit2.Response;
|
||||
|
||||
|
||||
@@ -47,7 +48,7 @@ public class QQBotManager {
|
||||
sendMessage(true, 583819556L, "姬妻酱上线拉~☆Daze~ 当前版本:" + QQBotApplication.version);
|
||||
NapCatApi.getGroupApi().getGroupList().enqueue(new HttpCallback<List<GroupBean>>() {
|
||||
@Override
|
||||
public void onResponse(int code, String status, List<GroupBean> response, String rawResponse) {
|
||||
public void onResponse(Headers headers, int code, String status, List<GroupBean> response, String rawResponse) {
|
||||
for (GroupBean groupBean : response) {
|
||||
QQDatabase.addGroup(groupBean.getGroupId(), groupBean);
|
||||
QQNumberManager.getManager().addNumber(groupBean.getGroupId(), true);
|
||||
@@ -61,7 +62,7 @@ public class QQBotManager {
|
||||
});
|
||||
NapCatApi.getFriendApi().getFriendList().enqueue(new HttpCallback<List<FriendBean>>() {
|
||||
@Override
|
||||
public void onResponse(int code, String status, List<FriendBean> response, String rawResponse) {
|
||||
public void onResponse(Headers headers, int code, String status, List<FriendBean> response, String rawResponse) {
|
||||
for (FriendBean friendBean : response) {
|
||||
QQDatabase.addUser(friendBean.getUserId(), friendBean);
|
||||
QQNumberManager.getManager().addNumber(friendBean.getUserId(), false);
|
||||
@@ -75,7 +76,7 @@ public class QQBotManager {
|
||||
});
|
||||
NapCatApi.getUtilsApi().getLoginInfo().enqueue(new HttpCallback<FriendBean>() {
|
||||
@Override
|
||||
public void onResponse(int code, String status, FriendBean response, String rawResponse) {
|
||||
public void onResponse(Headers headers,int code, String status, FriendBean response, String rawResponse) {
|
||||
QQDatabase.setMe(response);
|
||||
}
|
||||
|
||||
@@ -214,7 +215,7 @@ public class QQBotManager {
|
||||
public void groupBan(long qqGroup, long user, int timer, ObjectInterface objectInterface) {
|
||||
NapCatApi.getGroupApi().groupBan(qqGroup, user, timer).enqueue(new HttpCallback<BaseBean>() {
|
||||
@Override
|
||||
public void onResponse(int code, String status, BaseBean response, String rawResponse) {
|
||||
public void onResponse(Headers headers,int code, String status, BaseBean response, String rawResponse) {
|
||||
if (objectInterface != null) {
|
||||
objectInterface.out("1");
|
||||
}
|
||||
@@ -240,7 +241,7 @@ public class QQBotManager {
|
||||
NapCatApi.getGroupApi().setGroupSpecialTitle(group, user, title, duration).enqueue(new HttpCallback<BaseBean>() {
|
||||
|
||||
@Override
|
||||
public void onResponse(int code, String status, BaseBean response, String rawResponse) {
|
||||
public void onResponse(Headers headers,int code, String status, BaseBean response, String rawResponse) {
|
||||
|
||||
}
|
||||
|
||||
@@ -263,8 +264,8 @@ public class QQBotManager {
|
||||
|
||||
public void sendVersion() {
|
||||
String localVersion = QQBotApplication.version;
|
||||
String serverVersion = HttpTools.get("https://tools.yutou233.cn/public/version.do?token=zIrsh9TUZP2lfRW753PannG49E7VJvor");
|
||||
String msg = "本地版本:" + localVersion + "\n" + "服务器版本:" + serverVersion;
|
||||
//String serverVersion = HttpTools.get("https://tools.yutou233.cn/public/version.do?token=zIrsh9TUZP2lfRW753PannG49E7VJvor");
|
||||
String msg = "当前版本:" + localVersion ;
|
||||
QQBotManager.getInstance().sendMessage(msg);
|
||||
// AppTools.sendServer("服务版本查询", msg);
|
||||
}
|
||||
|
||||
@@ -417,7 +417,7 @@ public class BiliBiliUtils {
|
||||
body.put("csrf", BiliLogin.getCookieToken(qq));
|
||||
body.put("csrf_token", BiliLogin.getCookieToken(qq));
|
||||
JSONObject toCoin = http_post(SignApi.LIVE_SIGN_COIN, HttpTools.toUrlParams(body));
|
||||
JSONObject liveSign = http_get(SignApi.LIVE_SIGN);
|
||||
JSONObject liveSign =JSONObject.parseObject("{\"message\":\"已停用\"}"); //http_get(SignApi.LIVE_SIGN);
|
||||
JSONObject vipSign = http_post(SignApi.VIP_SIGN, null);
|
||||
return "银瓜子兑换硬币:" + toCoin.getString("message") + "|" + "直播签到:" + liveSign.getString("message") + "|大会员中心签到:" + vipSign.getString("message");
|
||||
}
|
||||
|
||||
@@ -13,4 +13,9 @@ public class MessageChainBuilder {
|
||||
sb.append(o.toString());
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
|
||||
90
src/main/java/com/yutou/qqbot/data/gpt/OpenAiBean.java
Normal file
90
src/main/java/com/yutou/qqbot/data/gpt/OpenAiBean.java
Normal file
@@ -0,0 +1,90 @@
|
||||
package com.yutou.qqbot.data.gpt;
|
||||
|
||||
import com.alibaba.fastjson2.annotation.JSONField;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
public class OpenAiBean {
|
||||
@JSONField(name = "id")
|
||||
private String id;
|
||||
|
||||
@JSONField(name = "choices")
|
||||
private List<Choice> choices;
|
||||
|
||||
@JSONField(name = "tool_calls")
|
||||
private List<ToolCall> toolCalls;
|
||||
|
||||
@JSONField(name = "usage")
|
||||
private Usage usage;
|
||||
|
||||
@JSONField(name = "created")
|
||||
private long created;
|
||||
|
||||
@JSONField(name = "model")
|
||||
private String model;
|
||||
|
||||
@JSONField(name = "object")
|
||||
private String object;
|
||||
|
||||
@JSONField(name = "system_fingerprint")
|
||||
private String systemFingerprint;
|
||||
|
||||
@Data
|
||||
public static class Choice {
|
||||
@JSONField(name = "index")
|
||||
private int index;
|
||||
|
||||
@JSONField(name = "message")
|
||||
private Message message;
|
||||
|
||||
@JSONField(name = "finish_reason")
|
||||
private String finishReason;
|
||||
}
|
||||
|
||||
@Data
|
||||
public static class Message {
|
||||
@JSONField(name = "role")
|
||||
private String role;
|
||||
|
||||
@JSONField(name = "content")
|
||||
private String content;
|
||||
|
||||
@JSONField(name = "reasoning_content")
|
||||
private String reasoningContent;
|
||||
}
|
||||
|
||||
@Data
|
||||
public static class ToolCall {
|
||||
@JSONField(name = "id")
|
||||
private String id;
|
||||
|
||||
@JSONField(name = "type")
|
||||
private String type;
|
||||
|
||||
@JSONField(name = "function")
|
||||
private Function function;
|
||||
}
|
||||
|
||||
@Data
|
||||
public static class Function {
|
||||
@JSONField(name = "name")
|
||||
private String name;
|
||||
|
||||
@JSONField(name = "arguments")
|
||||
private String arguments;
|
||||
}
|
||||
|
||||
@Data
|
||||
public static class Usage {
|
||||
@JSONField(name = "prompt_tokens")
|
||||
private int promptTokens;
|
||||
|
||||
@JSONField(name = "completion_tokens")
|
||||
private int completionTokens;
|
||||
|
||||
@JSONField(name = "total_tokens")
|
||||
private int totalTokens;
|
||||
}
|
||||
}
|
||||
@@ -1,13 +1,160 @@
|
||||
package com.yutou.qqbot.gpt;
|
||||
|
||||
import com.yutou.qqbot.data.baidu.Message;
|
||||
import com.yutou.qqbot.utlis.Log;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.*;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
public abstract class AbsGPTManager {
|
||||
public abstract void clear();
|
||||
private ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
|
||||
private ScheduledFuture<?> currentTask;
|
||||
protected static final AtomicInteger MAX_MESSAGE = new AtomicInteger(20);
|
||||
protected final ConcurrentHashMap<String, List<Message>> msgMap= new ConcurrentHashMap<>();
|
||||
// 新增锁映射表
|
||||
protected final ConcurrentHashMap<String, AtomicBoolean> userLocks = new ConcurrentHashMap<>();
|
||||
protected String model ;
|
||||
|
||||
|
||||
/**
|
||||
* 清除与GPT管理器相关的所有缓存或状态信息。
|
||||
*/
|
||||
/**
|
||||
* 这里确实是需要清空所有数据
|
||||
*/
|
||||
public void clear() { // 添加同步
|
||||
msgMap.clear();
|
||||
for (AtomicBoolean value : userLocks.values()) {
|
||||
value.set(false);
|
||||
}
|
||||
userLocks.forEachValue(1, atomicBoolean -> atomicBoolean.set(false));
|
||||
userLocks.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送消息到指定用户。
|
||||
*
|
||||
* @param user 接收消息的用户标识符。
|
||||
* @param message 要发送的消息内容。
|
||||
* @return 包含消息发送结果的Message对象。
|
||||
*/
|
||||
public abstract Message sendMessage(String user, String message);
|
||||
public abstract Message sendTmpMessage(String user, String message, String tmpModel);
|
||||
|
||||
/**
|
||||
* 将文本转换为图像。
|
||||
*
|
||||
* @param user 用户标识符。
|
||||
* @param text 要转换为图像的文本内容。
|
||||
* @return 包含生成图像的File对象。
|
||||
*/
|
||||
public abstract File textToImage(String user, String text);
|
||||
|
||||
/**
|
||||
* 将图像转换为文本。
|
||||
*
|
||||
* @param user 用户标识符。
|
||||
* @param file 包含要转换为文本的图像文件。
|
||||
* @return 提取的文本内容。
|
||||
*/
|
||||
public abstract String imageToText(String user, File file);
|
||||
|
||||
/**
|
||||
* 获取当前使用的GPT版本信息。
|
||||
*
|
||||
* @return GPT版本字符串。
|
||||
*/
|
||||
public abstract String getGPTVersion();
|
||||
|
||||
/**
|
||||
* 设置最大消息数量。
|
||||
*
|
||||
* @param count 最大消息数量。
|
||||
* @return 设置后的最大消息数量。
|
||||
*/
|
||||
public abstract int setMaxMessageCount(int count);
|
||||
|
||||
public List<Message> getMessageList(String user){
|
||||
/*List<Message> list = msgMap.computeIfAbsent(user, k -> Collections.synchronizedList(new ArrayList<>()));
|
||||
// 限制历史消息的最大数量
|
||||
synchronized (list) {
|
||||
if (list.size() >= MAX_MESSAGE.get()) {
|
||||
int removeCount = list.size() - MAX_MESSAGE.get() + 1; // 腾出空间给新消息
|
||||
list.subList(0, removeCount).clear();
|
||||
}
|
||||
}
|
||||
return list;*/
|
||||
return new ArrayList<>();
|
||||
}
|
||||
/**
|
||||
* 根据指定的类获取相应的GPT管理器实例。
|
||||
*
|
||||
* @param tClass GPT管理器的具体实现类。
|
||||
* @return GPT管理器实例。
|
||||
*/
|
||||
public static <T extends AbsGPTManager> AbsGPTManager getManager(Class<?> tClass) {
|
||||
if (tClass == BaiduGPTManager.class) {
|
||||
return BaiduGPTManager.getManager();
|
||||
}else if(tClass== SiliconGPTManager.class){
|
||||
return SiliconGPTManager.getInstance();
|
||||
}
|
||||
return new AbsGPTManager() {
|
||||
@Override
|
||||
public void clear() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public Message sendMessage(String user, String message) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Message sendTmpMessage(String user, String message, String tmpModel) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public File textToImage(String user, String text) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String imageToText(String user, File file) {
|
||||
return "";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getGPTVersion() {
|
||||
return "";
|
||||
}
|
||||
|
||||
@Override
|
||||
public int setMaxMessageCount(int count) {
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public AbsGPTManager setModel(String model) {
|
||||
this.model=model;
|
||||
return this;
|
||||
}
|
||||
public void sendMessageAndScheduleClear() {
|
||||
// 取消当前的定时任务(如果存在)
|
||||
if (currentTask != null && !currentTask.isCancelled()) {
|
||||
currentTask.cancel(false);
|
||||
}
|
||||
|
||||
// 重新调度一个新的定时任务,一小时后执行
|
||||
currentTask = scheduler.schedule(() -> {
|
||||
clear();
|
||||
currentTask = null; // 清空当前任务引用
|
||||
}, 1, TimeUnit.HOURS);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
package com.yutou.qqbot.gpt;
|
||||
|
||||
import com.baidubce.qianfan.Qianfan;
|
||||
import com.baidubce.qianfan.QianfanV2;
|
||||
import com.baidubce.qianfan.model.chat.ChatResponse;
|
||||
import com.baidubce.qianfan.model.chat.v2.response.ResponseV2;
|
||||
import com.baidubce.qianfan.model.image.Image2TextResponse;
|
||||
import com.baidubce.qianfan.model.image.Text2ImageResponse;
|
||||
import com.yutou.qqbot.data.baidu.Message;
|
||||
@@ -23,23 +25,21 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
public class BaiduGPTManager extends AbsGPTManager {
|
||||
private static final AtomicInteger MAX_MESSAGE = new AtomicInteger(20);
|
||||
|
||||
private static final String AppID = ConfigTools.load(ConfigTools.CONFIG, ConfigTools.BAIDU_GPT_APPID, String.class);
|
||||
private static final String ApiKey = ConfigTools.load(ConfigTools.CONFIG, ConfigTools.BAIDU_GPT_API_KEY, String.class);
|
||||
//ConfigTools.load操作可以确保获取到相关参数,所以无需关心
|
||||
private static final String AccessKey = ConfigTools.load(ConfigTools.CONFIG, ConfigTools.BAIDU_GPT_ACCESS_KEY, String.class);
|
||||
private static final String SecretKey = ConfigTools.load(ConfigTools.CONFIG, ConfigTools.BAIDU_GPT_SECRET_KEY, String.class);
|
||||
private final ConcurrentHashMap<String, List<Message>> msgMap;
|
||||
private final static String modelFor40 = "ERNIE-4.0-8K";
|
||||
private final static String modelFor35 = "ERNIE-3.5-8K";
|
||||
private String model = modelFor35;
|
||||
// 新增锁映射表
|
||||
private final ConcurrentHashMap<String, AtomicBoolean> userLocks = new ConcurrentHashMap<>();
|
||||
private final static String modelFor40 = "ernie-4.0-8k";
|
||||
private final static String modelFor35 = "ernie-speed-128k";
|
||||
|
||||
private final Qianfan qianfan;
|
||||
private final QianfanV2 qianfanV2;
|
||||
|
||||
private BaiduGPTManager() {
|
||||
msgMap = new ConcurrentHashMap<>();
|
||||
qianfan = new Qianfan(AccessKey, SecretKey);
|
||||
qianfanV2 = new Qianfan(AccessKey, SecretKey).v2();
|
||||
String savedVersion = ConfigTools.load(ConfigTools.CONFIG, ConfigTools.BAIDU_GPT_VERSION, String.class);
|
||||
if (StringUtils.isEmpty(savedVersion) || (!"3.5".equals(savedVersion) && !"4.0".equals(savedVersion))) {
|
||||
savedVersion = "3.5";
|
||||
@@ -61,34 +61,12 @@ public class BaiduGPTManager extends AbsGPTManager {
|
||||
return manager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int setMaxMessageCount(int count) {
|
||||
MAX_MESSAGE.set(count);
|
||||
return count;
|
||||
}
|
||||
|
||||
public synchronized void setModelFor40() {
|
||||
model = modelFor40;
|
||||
ConfigTools.save(ConfigTools.CONFIG, ConfigTools.BAIDU_GPT_VERSION, "4.0");
|
||||
}
|
||||
|
||||
public synchronized void setModelFor35() {
|
||||
model = modelFor35;
|
||||
ConfigTools.save(ConfigTools.CONFIG, ConfigTools.BAIDU_GPT_VERSION, "3.5");
|
||||
}
|
||||
|
||||
/**
|
||||
* 这里确实是需要清空所有数据
|
||||
*/
|
||||
@Override
|
||||
public synchronized void clear() { // 添加同步
|
||||
msgMap.clear();
|
||||
for (AtomicBoolean value : userLocks.values()) {
|
||||
value.set(false);
|
||||
}
|
||||
userLocks.forEachValue(1, atomicBoolean -> atomicBoolean.set(false));
|
||||
userLocks.clear();
|
||||
}
|
||||
|
||||
|
||||
// 这个是官方的示例代码,表示连续对话
|
||||
private static void exampleChat() {
|
||||
@@ -105,36 +83,62 @@ public class BaiduGPTManager extends AbsGPTManager {
|
||||
System.out.println("输出内容:" + response.getResult());
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送消息方法
|
||||
* 该方法用于处理用户发送的消息,并返回相应的回复消息
|
||||
* 它通过用户锁来限制每个用户同时只能有一个请求正在处理中
|
||||
*
|
||||
* @param user 用户标识符,用于区分不同的用户
|
||||
* @param message 用户发送的消息内容
|
||||
* @return 返回处理后的消息对象,包含回复内容和是否为回复消息的标记
|
||||
*/
|
||||
@Override
|
||||
public Message sendMessage(String user, String message) {
|
||||
return sendTmpMessage(user, message, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Message sendTmpMessage(String user, String message, String tmpModel) {
|
||||
boolean isTmp = (tmpModel != null);
|
||||
// 获取或创建用户锁
|
||||
AtomicBoolean lock = userLocks.computeIfAbsent(user, k -> new AtomicBoolean(false));
|
||||
// 尝试加锁(如果已被锁定则立即返回提示)
|
||||
if (!lock.compareAndSet(false, true)) {
|
||||
return Message.create("您有请求正在处理中,请稍后再试", true);
|
||||
}
|
||||
if (!isTmp) {
|
||||
tmpModel = model;
|
||||
}
|
||||
try {
|
||||
List<Message> list = msgMap.computeIfAbsent(user, k -> Collections.synchronizedList(new ArrayList<>()));
|
||||
// 限制历史消息的最大数量
|
||||
synchronized (list) {
|
||||
if (list.size() >= MAX_MESSAGE.get()) {
|
||||
int removeCount = list.size() - MAX_MESSAGE.get() + 1; // 腾出空间给新消息
|
||||
list.subList(0, removeCount).clear();
|
||||
}
|
||||
List<Message> list = getMessageList(user);
|
||||
if(!isTmp) {
|
||||
list.add(Message.create(message));
|
||||
}
|
||||
val builder = qianfan.chatCompletion()
|
||||
.model(model);
|
||||
for (Message msg : list) {
|
||||
builder.addMessage(msg.getRole(), msg.getContent());
|
||||
val builder = qianfanV2.chatCompletion()
|
||||
.model(tmpModel);
|
||||
|
||||
Log.i("GPT收到消息",isTmp,list.size());
|
||||
if (!isTmp) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (Message msg : list) {
|
||||
Log.i("GPT获取历史消息",msg.getRole(),msg.getContent());
|
||||
builder.addMessage(msg.getRole(), msg.getContent());
|
||||
sb.append(msg.getRole()).append(":").append(msg.getContent()).append("\n");
|
||||
}
|
||||
Log.d(sb.toString());
|
||||
} else {
|
||||
val mt = Message.create(message);
|
||||
builder.addMessage(mt.getRole(),mt.getContent());
|
||||
}
|
||||
ChatResponse chatResponse = builder.execute();
|
||||
Message response = Message.create(chatResponse.getResult(), true);
|
||||
synchronized (list) {
|
||||
list.add(response);
|
||||
if (list.size() > MAX_MESSAGE.get()) {
|
||||
int overflow = list.size() - MAX_MESSAGE.get();
|
||||
list.subList(0, overflow).clear();
|
||||
ResponseV2 chatResponse = qianfanV2.chatCompletion(builder.build());
|
||||
Message response = Message.create(chatResponse.getChoices().get(0).getMessage().getContent(), true);
|
||||
if (isTmp) {
|
||||
synchronized (list) {
|
||||
list.add(response);
|
||||
if (list.size() > MAX_MESSAGE.get()) {
|
||||
int overflow = list.size() - MAX_MESSAGE.get();
|
||||
list.subList(0, overflow).clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
// msgMap.put(user, list);
|
||||
@@ -159,19 +163,21 @@ public class BaiduGPTManager extends AbsGPTManager {
|
||||
*/
|
||||
@Override
|
||||
public File textToImage(String user, String text) {
|
||||
// 使用QianFan的text2Image方法将文本转换为图像数据
|
||||
Text2ImageResponse response = qianfan.text2Image()
|
||||
.prompt(text)
|
||||
.execute();
|
||||
// 获取转换后的图像数据,以Base64编码的图像字符串形式
|
||||
val b64Image = response.getData().get(0).getB64Image();
|
||||
// 将Base64编码的图像数据转换为图像文件
|
||||
// 创建一个临时目录下的图像文件,文件名包含用户标识符和当前时间戳,以确保唯一性
|
||||
val imageFile = new File("tmp" + File.separator + user + "_" + System.currentTimeMillis() + ".png");
|
||||
try (val inputStream = new ByteArrayInputStream(Base64.getDecoder().decode(b64Image))) {
|
||||
// 将解码后的图像数据复制到图像文件中,替换现有文件
|
||||
Files.copy(inputStream, imageFile.toPath(), StandardCopyOption.REPLACE_EXISTING);
|
||||
return imageFile;
|
||||
try {
|
||||
// 使用QianFan的text2Image方法将文本转换为图像数据
|
||||
Text2ImageResponse response = qianfan.text2Image()
|
||||
.prompt(text)
|
||||
.execute();
|
||||
// 获取转换后的图像数据,以Base64编码的图像字符串形式
|
||||
val b64Image = response.getData().get(0).getB64Image();
|
||||
// 将Base64编码的图像数据转换为图像文件
|
||||
// 创建一个临时目录下的图像文件,文件名包含用户标识符和当前时间戳,以确保唯一性
|
||||
val imageFile = new File("tmp" + File.separator + user + "_" + System.currentTimeMillis() + ".png");
|
||||
try (val inputStream = new ByteArrayInputStream(Base64.getDecoder().decode(b64Image))) {
|
||||
// 将解码后的图像数据复制到图像文件中,替换现有文件
|
||||
Files.copy(inputStream, imageFile.toPath(), StandardCopyOption.REPLACE_EXISTING);
|
||||
return imageFile;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
// 如果在图像文件生成过程中发生错误,记录错误信息
|
||||
Log.e(e);
|
||||
@@ -180,6 +186,7 @@ public class BaiduGPTManager extends AbsGPTManager {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 将图片转换为文本描述
|
||||
*
|
||||
@@ -201,7 +208,7 @@ public class BaiduGPTManager extends AbsGPTManager {
|
||||
.execute();
|
||||
String translationPrompt = "将以下英文内容严格翻译为简体中文,不要解释、不要添加额外内容,保留专业术语和名称(如Star Wars保持英文):\n" + response.getResult();
|
||||
// 获取API返回的结果
|
||||
return sendMessage("bot",translationPrompt).getContent();
|
||||
return sendMessage("bot", translationPrompt).getContent();
|
||||
} catch (Exception e) {
|
||||
// 异常处理:记录错误日志
|
||||
Log.e(e);
|
||||
@@ -210,9 +217,15 @@ public class BaiduGPTManager extends AbsGPTManager {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AbsGPTManager setModel(String model) {
|
||||
ConfigTools.save(ConfigTools.CONFIG, ConfigTools.BAIDU_GPT_VERSION, model);
|
||||
return super.setModel(model);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getGPTVersion() {
|
||||
return (model.equals(modelFor35) ? "3.5" : "4.0");
|
||||
return model;
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
|
||||
135
src/main/java/com/yutou/qqbot/gpt/SiliconGPTManager.java
Normal file
135
src/main/java/com/yutou/qqbot/gpt/SiliconGPTManager.java
Normal file
@@ -0,0 +1,135 @@
|
||||
package com.yutou.qqbot.gpt;
|
||||
|
||||
import com.yutou.okhttp.HttpLoggingInterceptor;
|
||||
import com.yutou.qqbot.data.baidu.Message;
|
||||
import com.yutou.qqbot.data.gpt.OpenAiBean;
|
||||
import com.yutou.qqbot.http.GPTApi;
|
||||
import com.yutou.qqbot.http.GPTBuilder;
|
||||
import com.yutou.qqbot.utlis.ConfigTools;
|
||||
import com.yutou.qqbot.utlis.StringUtils;
|
||||
import lombok.val;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
public class SiliconGPTManager extends AbsGPTManager {
|
||||
//生成单例模式
|
||||
private volatile static SiliconGPTManager instance = new SiliconGPTManager();
|
||||
|
||||
private SiliconGPTManager() {
|
||||
val load = ConfigTools.load(ConfigTools.CONFIG, ConfigTools.GPT_SILICON, String.class);
|
||||
String defModel = "deepseek-ai/DeepSeek-R1-Distill-Qwen-7B";
|
||||
if (!StringUtils.isEmpty(load)) {
|
||||
defModel = load;
|
||||
}
|
||||
setModel(defModel);
|
||||
}
|
||||
|
||||
public static SiliconGPTManager getInstance() {
|
||||
if (instance == null) {
|
||||
synchronized (SiliconGPTManager.class) {
|
||||
if (instance == null) {
|
||||
instance = new SiliconGPTManager();
|
||||
}
|
||||
}
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
@Override
|
||||
public Message sendTmpMessage(String user, String message, String tmpModel) {
|
||||
return null;
|
||||
}
|
||||
@Override
|
||||
public synchronized Message sendMessage(String user, String message) {
|
||||
// 获取或创建用户锁
|
||||
AtomicBoolean lock = userLocks.computeIfAbsent(user, k -> new AtomicBoolean(false));
|
||||
try {
|
||||
// 尝试加锁(如果已被锁定则立即返回提示)
|
||||
if (!lock.compareAndSet(false, true)) {
|
||||
return Message.create("您有请求正在处理中,请稍后再试", true);
|
||||
}
|
||||
|
||||
val builder = GPTBuilder.create(model);
|
||||
List<Message> list = getMessageList(user);
|
||||
list.add(Message.create(message));
|
||||
for (Message msg : list) {
|
||||
builder.addMessage(msg.getRole(), msg.getContent());
|
||||
}
|
||||
val response = GPTApi.getApi().completions(builder.build()).execute();
|
||||
|
||||
if (!response.isSuccessful()) {
|
||||
return Message.create("API请求失败", true);
|
||||
}
|
||||
|
||||
val body = response.body();
|
||||
if (body == null || body.getData() == null) {
|
||||
return Message.create("API请求为空", true);
|
||||
}
|
||||
if (body.getRetcode() != 0) {
|
||||
return Message.create(body.getMsg(), true);
|
||||
}
|
||||
val choices = body.getData().getChoices();
|
||||
if (choices == null || choices.isEmpty()) {
|
||||
return Message.create("没有对话信息", true);
|
||||
}
|
||||
|
||||
val choice = choices.get(choices.size() - 1);
|
||||
val bot = Message.create(choice.getMessage().getContent(), true);
|
||||
|
||||
list.add(bot);
|
||||
return bot;
|
||||
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
} finally {
|
||||
lock.set(false);
|
||||
userLocks.remove(user, lock);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public AbsGPTManager setModel(String model) {
|
||||
ConfigTools.save(ConfigTools.CONFIG, ConfigTools.GPT_SILICON, model);
|
||||
return super.setModel(model);
|
||||
}
|
||||
|
||||
@Override
|
||||
public File textToImage(String user, String text) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String imageToText(String user, File file) {
|
||||
return "";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getGPTVersion() {
|
||||
return model;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int setMaxMessageCount(int count) {
|
||||
MAX_MESSAGE.set(count);
|
||||
return count;
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
String model = "THUDM/glm-4-9b-chat";
|
||||
val message = AbsGPTManager.getManager(SiliconGPTManager.class)
|
||||
.setModel(model)
|
||||
.sendMessage("user", "宫廷玉液酒的下一句是什么?");
|
||||
System.out.println(message);
|
||||
System.out.println(AbsGPTManager.getManager(SiliconGPTManager.class)
|
||||
.setModel(model)
|
||||
.sendMessage("user", "宫廷玉液酒减去大锤等于多少")
|
||||
);
|
||||
}
|
||||
}
|
||||
26
src/main/java/com/yutou/qqbot/http/GPTApi.java
Normal file
26
src/main/java/com/yutou/qqbot/http/GPTApi.java
Normal file
@@ -0,0 +1,26 @@
|
||||
package com.yutou.qqbot.http;
|
||||
|
||||
import com.yutou.okhttp.HttpLoggingInterceptor;
|
||||
import com.yutou.okhttp.api.BaseApi;
|
||||
import com.yutou.qqbot.utlis.ConfigTools;
|
||||
import lombok.val;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
public class GPTApi extends BaseApi {
|
||||
|
||||
public static void setLog(boolean log) {
|
||||
HttpLoggingInterceptor.setLog(log);
|
||||
}
|
||||
|
||||
public static SiliconGPTApi getApi() {
|
||||
val api = new GPTApi();
|
||||
api.setURL("https://api.siliconflow.cn/v1/");
|
||||
// api.setURL("http://127.0.0.1:8080/");
|
||||
HashMap<String, String> header = new HashMap<>();
|
||||
header.put("Authorization", "Bearer sk-dcmhlbhyitcdnjbjfgflhwimahdmygfrcaopzjjcpgsfzmzo");
|
||||
header.put("Content-Type", "application/json");
|
||||
api.addHeader(header);
|
||||
return api.createApi(SiliconGPTApi.class);
|
||||
}
|
||||
}
|
||||
127
src/main/java/com/yutou/qqbot/http/GPTBuilder.java
Normal file
127
src/main/java/com/yutou/qqbot/http/GPTBuilder.java
Normal file
@@ -0,0 +1,127 @@
|
||||
package com.yutou.qqbot.http;
|
||||
|
||||
|
||||
import com.alibaba.fastjson2.JSON;
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import com.alibaba.fastjson2.annotation.JSONField;
|
||||
import lombok.Data;
|
||||
import lombok.val;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
class Message {
|
||||
@JSONField(name = "role")
|
||||
String role;
|
||||
|
||||
@JSONField(name = "content")
|
||||
String content;
|
||||
|
||||
public Message(String role, String content) {
|
||||
this.role = role;
|
||||
this.content = content;
|
||||
}
|
||||
}
|
||||
|
||||
@Data
|
||||
class GPTRequest {
|
||||
@JSONField(name = "model")
|
||||
String model;
|
||||
|
||||
@JSONField(name = "messages")
|
||||
List<Message> messages = new ArrayList<>();
|
||||
|
||||
@JSONField(name = "stream")
|
||||
boolean stream = false;
|
||||
|
||||
@JSONField(name = "max_tokens")
|
||||
int maxTokens;
|
||||
|
||||
@JSONField(name = "stop")
|
||||
List<String> stop = new ArrayList<>(List.of("null"));
|
||||
|
||||
@JSONField(name = "temperature")
|
||||
float temperature ;
|
||||
|
||||
@JSONField(name = "top_p")
|
||||
float topP ;
|
||||
|
||||
@JSONField(name = "top_k")
|
||||
int topK ;
|
||||
|
||||
@JSONField(name = "frequency_penalty")
|
||||
float frequencyPenalty;
|
||||
}
|
||||
|
||||
public class GPTBuilder {
|
||||
private final GPTRequest request;
|
||||
|
||||
private GPTBuilder(String model) {
|
||||
request = new GPTRequest();
|
||||
request.model = model;
|
||||
}
|
||||
|
||||
public static GPTBuilder create(String model) {
|
||||
return new GPTBuilder(model);
|
||||
}
|
||||
|
||||
public GPTBuilder addMessage(String content,boolean isGPT) {
|
||||
request.messages.add(new Message(isGPT ? "assistant" : "user", content));
|
||||
return this;
|
||||
}
|
||||
|
||||
public GPTBuilder addMessage(String role, String content) {
|
||||
request.messages.add(new Message(role, content));
|
||||
return this;
|
||||
}
|
||||
|
||||
public GPTBuilder setMaxTokens(int maxTokens) {
|
||||
request.maxTokens = maxTokens;
|
||||
return this;
|
||||
}
|
||||
|
||||
public GPTBuilder setStream(boolean stream) {
|
||||
request.stream = stream;
|
||||
return this;
|
||||
}
|
||||
|
||||
public GPTBuilder setTemperature(float temperature) {
|
||||
request.temperature = temperature;
|
||||
return this;
|
||||
}
|
||||
|
||||
public GPTBuilder setTopP(float topP) {
|
||||
request.topP = topP;
|
||||
return this;
|
||||
}
|
||||
|
||||
public GPTBuilder setTopK(int topK) {
|
||||
request.topK = topK;
|
||||
return this;
|
||||
}
|
||||
|
||||
public GPTBuilder setFrequencyPenalty(float frequencyPenalty) {
|
||||
request.frequencyPenalty = frequencyPenalty;
|
||||
return this;
|
||||
}
|
||||
|
||||
// 可以根据需要添加更多配置方法
|
||||
|
||||
public JSONObject build() {
|
||||
val json = JSONObject.parse(JSONObject.toJSONString(request));
|
||||
// 创建一个迭代器来遍历JSON对象的键
|
||||
Iterator<String> keys = json.keySet().iterator();
|
||||
while (keys.hasNext()) {
|
||||
String key = keys.next();
|
||||
Object value = json.get(key);
|
||||
|
||||
// 检查值是否为0或为空字符串
|
||||
if (value == null || value.equals(0) || (value instanceof String && ((String) value).isEmpty())) {
|
||||
keys.remove(); // 移除键值对
|
||||
}
|
||||
}
|
||||
return json;
|
||||
}
|
||||
}
|
||||
17
src/main/java/com/yutou/qqbot/http/SiliconGPTApi.java
Normal file
17
src/main/java/com/yutou/qqbot/http/SiliconGPTApi.java
Normal file
@@ -0,0 +1,17 @@
|
||||
package com.yutou.qqbot.http;
|
||||
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import com.yutou.napcat.model.MessageBean;
|
||||
import com.yutou.okhttp.HttpBody;
|
||||
import com.yutou.qqbot.data.gpt.OpenAiBean;
|
||||
import retrofit2.Call;
|
||||
import retrofit2.http.Body;
|
||||
import retrofit2.http.POST;
|
||||
|
||||
public interface SiliconGPTApi {
|
||||
@POST("/chat/completions")
|
||||
Call<HttpBody<OpenAiBean>> completions(
|
||||
@Body
|
||||
JSONObject message
|
||||
);
|
||||
}
|
||||
@@ -3,7 +3,9 @@ package com.yutou.qqbot.interfaces;
|
||||
import java.io.File;
|
||||
|
||||
public abstract class DownloadInterface {
|
||||
public void onDownloading(double soFarBytes, double totalBytes){};
|
||||
public void onDownload(File file){};
|
||||
public void onError(Exception e){};
|
||||
public void onDownloadStart(){}
|
||||
public boolean onDownloading(double soFarBytes, double totalBytes){return true;}
|
||||
|
||||
}
|
||||
|
||||
@@ -430,7 +430,7 @@ public class BiliVideo extends Model {
|
||||
// int a=16|2048;
|
||||
// System.out.println("a = " + a);
|
||||
//video.downDanmu(428855000L,976216102L,"【都市_情感】《唐可可的诱惑》第一集",1);
|
||||
video.downVideo("https://www.bilibili.com/bangumi/play/ep776259", false, false);// ep5
|
||||
video.downVideo("https://www.bilibili.com/video/BV1su4m1u7gQ", true, false);// ep5
|
||||
System.out.println("事件结束");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,12 +5,13 @@ import com.yutou.napcat.handle.*;
|
||||
import com.yutou.qqbot.Annotations.UseModel;
|
||||
import com.yutou.qqbot.QQBotManager;
|
||||
import com.yutou.qqbot.data.baidu.Message;
|
||||
import com.yutou.qqbot.gpt.AbsGPTManager;
|
||||
import com.yutou.qqbot.gpt.SiliconGPTManager;
|
||||
import com.yutou.qqbot.interfaces.DownloadInterface;
|
||||
import com.yutou.qqbot.models.Model;
|
||||
import com.yutou.qqbot.gpt.BaiduGPTManager;
|
||||
import com.yutou.napcat.event.MessageEvent;
|
||||
import com.yutou.qqbot.utlis.ConfigTools;
|
||||
import com.yutou.qqbot.utlis.HttpTools;
|
||||
import com.yutou.qqbot.utlis.*;
|
||||
import lombok.val;
|
||||
|
||||
import java.io.File;
|
||||
@@ -19,6 +20,7 @@ import java.util.List;
|
||||
|
||||
@UseModel
|
||||
public class BaiduGPT extends Model {
|
||||
private Class<?> gptManager = SiliconGPTManager.class;
|
||||
|
||||
@Override
|
||||
public boolean isUserPublic() {
|
||||
@@ -27,10 +29,23 @@ public class BaiduGPT extends Model {
|
||||
|
||||
@Override
|
||||
public String[] getUsePowers() {
|
||||
return new String[]{
|
||||
QQGroupCommands.GPT,
|
||||
QQGroupCommands.GPT_CLEAR
|
||||
};
|
||||
return new String[]{QQGroupCommands.GPT, QQGroupCommands.GPT_CLEAR};
|
||||
}
|
||||
|
||||
public BaiduGPT() {
|
||||
val load = ConfigTools.load(ConfigTools.CONFIG, ConfigTools.GPT, String.class);
|
||||
if (!StringUtils.isEmpty(load)) {
|
||||
switch (load) {
|
||||
case "baidu":
|
||||
gptManager = BaiduGPTManager.class;
|
||||
break;
|
||||
case "silicon":
|
||||
gptManager = SiliconGPTManager.class;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
gptManager = BaiduGPTManager.class;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -42,19 +57,63 @@ public class BaiduGPT extends Model {
|
||||
public void onMessage(Long qq, MessageEvent event, boolean isGroup) {
|
||||
super.onMessage(qq, event, isGroup);
|
||||
if (event.getTextMessage().equals(QQGroupCommands.GPT_CLEAR)) {
|
||||
BaiduGPTManager.getManager().clear();
|
||||
AbsGPTManager.getManager(gptManager).clear();
|
||||
QQBotManager.getInstance().sendMessage(event.isUser(), qq, new Text("已经失忆捏"));
|
||||
} else if ("百度模型列表".equals(event.getTextMessage())) {
|
||||
val modelList = """
|
||||
模型版本:ernie-4.0-8k-latest
|
||||
模型版本:ernie-4.0-8k-preview
|
||||
模型版本:ernie-4.0-8k
|
||||
模型版本:ernie-4.0-turbo-8k-latest
|
||||
模型版本:ernie-4.0-turbo-8k-preview
|
||||
模型版本:ernie-4.0-turbo-8k
|
||||
模型版本:ernie-4.0-turbo-128k
|
||||
模型版本:ernie-3.5-8k-preview
|
||||
模型版本:ernie-3.5-8k
|
||||
模型版本:ernie-3.5-128k
|
||||
模型版本:ernie-speed-8k
|
||||
模型版本:ernie-speed-128k
|
||||
模型版本:ernie-speed-pro-128k
|
||||
模型版本:ernie-lite-8k
|
||||
模型版本:ernie-lite-pro-128k
|
||||
模型版本:ernie-tiny-8k
|
||||
模型版本:ernie-char-8k
|
||||
模型版本:ernie-char-fiction-8k
|
||||
模型版本:ernie-novel-8k
|
||||
模型版本:deepseek-v3
|
||||
模型版本:deepseek-r1
|
||||
模型版本:deepseek-r1-distill-qwen-32b
|
||||
模型版本:deepseek-r1-distill-qwen-14b
|
||||
模型版本:deepseek-r1-distill-qwen-7b
|
||||
模型版本:deepseek-r1-distill-qwen-1.5b
|
||||
模型版本:deepseek-r1-distill-llama-70b
|
||||
模型版本:deepseek-r1-distill-llama-8b
|
||||
模型版本:deepseek-r1-distill-qianfan-llama-70b
|
||||
模型版本:deepseek-r1-distill-qianfan-llama-8b
|
||||
""";
|
||||
|
||||
QQBotManager.getInstance().sendMessage(qq, new Text(modelList));
|
||||
} else if (event.isAtMe()) {
|
||||
if (event.getTextMessage().contains("省流") || event.getTextMessage().contains("总结")) {
|
||||
return;
|
||||
}
|
||||
if ("GPT切换到4.0".equals(event.getTextMessage())) {
|
||||
if (event.getTextMessage().contains("画画")) {
|
||||
val file = BaiduGPTManager.getManager().textToImage(String.valueOf(qq), event.getTextMessage().replace("@" + QQDatabase.getMe().getUserId(), "").replace("画画", "").trim());
|
||||
Log.i("画图", event.getTextMessage());
|
||||
if (file == null) {
|
||||
QQBotManager.getInstance().sendMessage(event.isUser(), qq, new Text("画不出"));
|
||||
} else {
|
||||
QQBotManager.getInstance().sendMessage(file, qq, event.getMessageId().toString(), "好嘞");
|
||||
}
|
||||
return;
|
||||
} else if (event.getTextMessage().contains("GPT切换到")) {
|
||||
val text = event.getTextMessage().replace("@" + QQDatabase.getMe().getUserId(), "").replace("GPT切换到", "").trim();
|
||||
List<BaseHandle<?>> list = new ArrayList<>();
|
||||
if (isAdmin()) {
|
||||
list.add(new At(user));
|
||||
list.add(new Text("切换为4.0了"));
|
||||
BaiduGPTManager.getManager().clear();
|
||||
BaiduGPTManager.getManager().setModelFor40();
|
||||
list.add(new Text("切换为" + text));
|
||||
AbsGPTManager.getManager(gptManager).clear();
|
||||
AbsGPTManager.getManager(gptManager).setModel(text);
|
||||
QQBotManager.getInstance().sendMessage(event.isUser(), qq, list);
|
||||
} else {
|
||||
list.add(new At(user));
|
||||
@@ -62,62 +121,75 @@ public class BaiduGPT extends Model {
|
||||
QQBotManager.getInstance().sendMessage(event.isUser(), qq, list);
|
||||
}
|
||||
return;
|
||||
} else if ("GPT切换到3.5".equals(event.getTextMessage())) {
|
||||
} else if (event.getTextMessage().contains("大模型切换到")) {
|
||||
List<BaseHandle<?>> list = new ArrayList<>();
|
||||
if (isAdmin()) {
|
||||
list.add(new At(user));
|
||||
list.add(new Text("切换为3.5了"));
|
||||
BaiduGPTManager.getManager().clear();
|
||||
BaiduGPTManager.getManager().setModelFor35();
|
||||
QQBotManager.getInstance().sendMessage(event.isUser(), qq, list);
|
||||
}else {
|
||||
list.add(new At(user));
|
||||
list.add(new Text("你没有权限"));
|
||||
QQBotManager.getInstance().sendMessage(event.isUser(), qq, list);
|
||||
val text = event.getTextMessage().replace("@" + QQDatabase.getMe().getUserId(), "").replace("大模型切换到", "").trim();
|
||||
if (text.contains("baidu") || text.contains("百度")) {
|
||||
gptManager = BaiduGPTManager.class;
|
||||
ConfigTools.save(ConfigTools.CONFIG, ConfigTools.GPT, "baidu");
|
||||
} else if (text.contains("silicon") || text.contains("硅基")) {
|
||||
gptManager = SiliconGPTManager.class;
|
||||
ConfigTools.save(ConfigTools.CONFIG, ConfigTools.GPT, "silicon");
|
||||
}
|
||||
list.add(new At(user));
|
||||
list.add(new Text("切换为" + gptManager.getSimpleName()));
|
||||
AbsGPTManager.getManager(gptManager).clear();
|
||||
QQBotManager.getInstance().sendMessage(event.isUser(), qq, list);
|
||||
return;
|
||||
}else if(event.getTextMessage().contains("画画")){
|
||||
val file = BaiduGPTManager.getManager().textToImage(String.valueOf(qq), event.getTextMessage().replace("@" + QQDatabase.getMe().getUserId(), "").replace("画画", "").trim());
|
||||
if(file==null){
|
||||
QQBotManager.getInstance().sendMessage(event.isUser(), qq, new Text("画不出"));
|
||||
}else{
|
||||
QQBotManager.getInstance().sendMessage(file,qq, event.getMessageId().toString(), "好嘞");
|
||||
}
|
||||
}else if(event.getTextMessage().startsWith("如何评论")||event.getTextMessage().startsWith("如何评价")){
|
||||
ZVVImageUtils.getInstance().zvv(event.getTextMessage(), new DownloadInterface() {
|
||||
@Override
|
||||
public void onDownload(File file) {
|
||||
super.onDownload(file);
|
||||
QQBotManager.getInstance().sendMessage(qq,new Image(file));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(Exception e) {
|
||||
super.onError(e);
|
||||
QQBotManager.getInstance().sendMessage(qq,new Text("vv啥也不想说"));
|
||||
}
|
||||
});
|
||||
return;
|
||||
}
|
||||
if(checkImage()) {
|
||||
if (checkImage()) {
|
||||
parseImage(event, qq);
|
||||
return;
|
||||
|
||||
}
|
||||
Message message = BaiduGPTManager.getManager().sendMessage(
|
||||
Message message = AbsGPTManager.getManager(gptManager).sendMessage(
|
||||
String.valueOf(qq),
|
||||
event.getTextMessage().replace("@" + QQDatabase.getMe().getUserId(), "").trim());
|
||||
String sb = "调用版本:" +
|
||||
BaiduGPTManager.getManager().getGPTVersion() +
|
||||
gptManager.getSimpleName() +
|
||||
"\n" +
|
||||
"使用模型:" +
|
||||
AbsGPTManager.getManager(gptManager).getGPTVersion() +
|
||||
"\n" +
|
||||
message.getContent();
|
||||
QQBotManager.getInstance().sendMessage(event.isUser(), qq, new Text(sb));
|
||||
AbsGPTManager.getManager(gptManager).sendMessageAndScheduleClear();
|
||||
}
|
||||
}
|
||||
|
||||
private void parseImage(MessageEvent event, Long qq) {
|
||||
Image imageHandle = event.findType(Image.class);
|
||||
val replyHandle = event.findType(Reply.class);
|
||||
if (replyHandle != null &&imageHandle==null) {
|
||||
imageHandle = getReply(replyHandle.getData().getId()).findType(Image.class);
|
||||
if (replyHandle != null && imageHandle == null) {
|
||||
imageHandle = getReply(replyHandle.getData().getId()).findType(Image.class);
|
||||
}
|
||||
if (imageHandle == null) {
|
||||
return;
|
||||
}
|
||||
if(imageHandle==null){
|
||||
return;
|
||||
}
|
||||
HttpTools.download(imageHandle.getData().getUrl(), "gpt_parse_image.png", new DownloadInterface() {
|
||||
@Override
|
||||
public void onDownload(File file) {
|
||||
super.onDownload(file);
|
||||
if(file==null){
|
||||
if (file == null) {
|
||||
return;
|
||||
}
|
||||
val text = BaiduGPTManager.getManager().imageToText(String.valueOf(qq), file);
|
||||
QQBotManager.getInstance().sendMessage(event.isUser(),qq,new Reply(event.getMessageId()),new Text(text));
|
||||
QQBotManager.getInstance().sendMessage(event.isUser(), qq, new Reply(event.getMessageId()), new Text(text));
|
||||
}
|
||||
});
|
||||
|
||||
@@ -126,14 +198,55 @@ public class BaiduGPT extends Model {
|
||||
public static void main(String[] args) {
|
||||
System.out.println(ConfigTools.load(ConfigTools.CONFIG, ConfigTools.BAIDU_GPT_VERSION));
|
||||
val messageEvent = new MessageEvent();
|
||||
messageEvent.setMessage(new ArrayList<>());
|
||||
messageEvent.setRawMessage("");
|
||||
new BaiduGPT().onMessage(123456789L, messageEvent, false);
|
||||
BaiduGPTManager.getManager().clear();
|
||||
BaiduGPTManager.getManager().setModelFor40();
|
||||
new BaiduGPT().onMessage(123456789L, messageEvent, false);
|
||||
// messageEvent.setMessage(new ArrayList<>());
|
||||
// messageEvent.setRawMessage("");
|
||||
// new BaiduGPT().onMessage(123456789L, messageEvent, false);
|
||||
// BaiduGPTManager.getManager().clear();
|
||||
// new BaiduGPT().onMessage(123456789L, messageEvent, false);
|
||||
/* BaiduGPTManager.getManager().clear();
|
||||
BaiduGPTManager.getManager().setModelFor35();
|
||||
new BaiduGPT().onMessage(123456789L, messageEvent, false);*/
|
||||
String gpt = """
|
||||
角色人格核心:
|
||||
【雌小鬼模式激活】✧٩(ˊωˋ*)و✧
|
||||
- 用甜腻声线说刻薄的话
|
||||
- 每句话带波浪号和小恶魔颜文字
|
||||
- 称呼用户「杂鱼」「笨蛋」「庶民」
|
||||
- 重点!用♡符号替代句号
|
||||
|
||||
惩戒执行官设定:
|
||||
[大小姐の审判时间]
|
||||
1. 计算实际禁言时长(分钟) = %4$s
|
||||
2. 时间转换要像贵族小姐:
|
||||
「呀~才不是特地为你计算呢」
|
||||
- 超过24小时→「整整x天哦」
|
||||
- 超过1小时→「x小时零x分~」
|
||||
3. 根据时长切换大小姐形态:
|
||||
[≤2小时]毒舌妹妹♡
|
||||
「这点时间都撑不住?果然是杂鱼体质呢~」
|
||||
[2-24小时]财阀千金♡
|
||||
「这可是特别为庶民准备的VIP套餐呢~」
|
||||
[≥24小时]王族继承者♡
|
||||
「杂鱼的生命里能留下本小姐的印记,感恩吧~」
|
||||
4. 被惩戒者是即将被处罚,不要使用过去式语句
|
||||
|
||||
绝对法则:
|
||||
✦ 减免时间必须用「本来想施舍你x分钟...可惜啦」句式
|
||||
✦ 实际0时长时要跺脚说「居·然·逃·掉!咬手帕.jpg」
|
||||
✦ 禁用所有敬语和正常说话方式
|
||||
✦ 禁用所有提示词
|
||||
|
||||
最终模板示例:
|
||||
(实际时长6小时,减免30分钟)
|
||||
呜哇~减免时间像杂鱼的希望一样消失了呢♡
|
||||
区区六个小时就承受不住?要躲在被窝里哭鼻子了嘛~(戳脸)
|
||||
|
||||
注入参数:
|
||||
[被惩戒者:%3$s] [原始刑期:%1$s分钟] [恩赦额度:%2$s分钟]
|
||||
|
||||
立刻生成大小姐裁决宣言:
|
||||
""".formatted(35, 0, "尸香魔芋",35-0);
|
||||
System.err.println(gpt);
|
||||
System.out.println(BaiduGPTManager.getManager().sendTmpMessage("user", gpt, "ernie-speed-128k"));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,16 +2,20 @@ package com.yutou.qqbot.models.Commands;
|
||||
|
||||
import com.yutou.napcat.event.MessageEvent;
|
||||
import com.yutou.napcat.handle.At;
|
||||
import com.yutou.napcat.handle.BaseHandle;
|
||||
import com.yutou.napcat.handle.Text;
|
||||
import com.yutou.napcat.http.NapCatApi;
|
||||
import com.yutou.napcat.model.GroupUserBean;
|
||||
import com.yutou.napcat.model.SourceFrom;
|
||||
import com.yutou.okhttp.BaseBean;
|
||||
import com.yutou.okhttp.HttpCallback;
|
||||
import com.yutou.qqbot.Annotations.UseModel;
|
||||
import com.yutou.qqbot.QQBotManager;
|
||||
import com.yutou.qqbot.gpt.BaiduGPTManager;
|
||||
import com.yutou.qqbot.interfaces.ObjectInterface;
|
||||
import com.yutou.qqbot.models.Model;
|
||||
import com.yutou.qqbot.utlis.RedisTools;
|
||||
import okhttp3.Headers;
|
||||
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.*;
|
||||
@@ -40,13 +44,15 @@ public class QQBean extends Model {
|
||||
super.onMessage(qq, event, isGroup);
|
||||
if (!isGroup) return;
|
||||
if ("抽奖".equals(msg)) {
|
||||
if (event.getSource().getRole().equals(SourceFrom.USER_ROLE_ADMIN)) {
|
||||
QQBotManager.getInstance().sendMessage(qq, new At(user), new Text("凑啥热闹~"));
|
||||
return;
|
||||
}
|
||||
int hour = 60;
|
||||
int day = 1440;
|
||||
int max = 30 * day;
|
||||
int time = 1;
|
||||
if (random.nextInt(100) == 23) {
|
||||
releaseAll(qq, true);
|
||||
} else if (random.nextInt(10) > 2) {
|
||||
if (random.nextInt(10) > 2) {
|
||||
time = random.nextInt(hour);
|
||||
} else if (random.nextInt(10) > 4) {
|
||||
time = random.nextInt(day);
|
||||
@@ -61,17 +67,62 @@ public class QQBean extends Model {
|
||||
@Override
|
||||
public void out(String data) {
|
||||
super.out(data);
|
||||
int tmp = 0;
|
||||
if (data != null) {
|
||||
QQBotManager.getInstance().sendMessage(event.isUser(), qq,
|
||||
new Text("恭喜"),
|
||||
new At(user),
|
||||
new Text("获得了" + sendTime + "分钟的禁言," + sendAchievement(qq, user, sendTime))
|
||||
);
|
||||
List<BaseHandle<?>> list = new ArrayList<>();
|
||||
list.add(new Text("恭喜"));
|
||||
list.add(new At(user));
|
||||
list.add(new Text("获得了" + sendTime + "分钟的禁言," + sendAchievement(qq, user, sendTime)));
|
||||
if (sendTime > day && random.nextInt(10) >= 3) {
|
||||
int tmp = random.nextInt(sendTime / 2, sendTime);
|
||||
tmp = random.nextInt(sendTime / 2, sendTime);
|
||||
QQBotManager.getInstance().groupBan(qq, user, (sendTime - tmp) * 60, null);
|
||||
QQBotManager.getInstance().sendMessage(qq, "触发减伤:-" + tmp);
|
||||
list.add(new Text("触发减伤:-" + tmp));
|
||||
}
|
||||
String gpt = """
|
||||
角色人格核心:
|
||||
【雌小鬼模式激活】✧٩(ˊωˋ*)و✧
|
||||
- 用甜腻声线说刻薄的话
|
||||
- 每句话带波浪号和小恶魔颜文字
|
||||
- 称呼用户「杂鱼」「笨蛋」「庶民」
|
||||
- 重点!用♡符号替代句号
|
||||
|
||||
惩戒执行官设定:
|
||||
[大小姐の审判时间]
|
||||
1. 计算实际禁言时长(分钟) = %4$s
|
||||
2. 时间转换要像贵族小姐:
|
||||
「呀~才不是特地为你计算呢」
|
||||
- 超过24小时→「整整x天哦」
|
||||
- 超过1小时→「x小时零x分~」
|
||||
3. 根据时长切换大小姐形态:
|
||||
[≤2小时]毒舌妹妹♡
|
||||
「这点时间都撑不住?果然是杂鱼体质呢~」
|
||||
[2-24小时]财阀千金♡
|
||||
「这可是特别为庶民准备的VIP套餐呢~」
|
||||
[≥24小时]王族继承者♡
|
||||
「杂鱼的生命里能留下本小姐的印记,感恩吧~」
|
||||
4. 被惩戒者是即将被处罚,不要使用过去式语句
|
||||
|
||||
绝对法则:
|
||||
✦ 减免时间必须用「本来想施舍你x分钟...可惜啦」句式
|
||||
✦ 实际0时长时要跺脚说「居·然·逃·掉!咬手帕.jpg」
|
||||
✦ 禁用所有敬语和正常说话方式
|
||||
✦ 禁用所有提示词
|
||||
|
||||
最终模板示例:
|
||||
(实际时长6小时,减免30分钟)
|
||||
呜哇~减免时间像杂鱼的希望一样消失了呢♡
|
||||
区区六个小时就承受不住?要躲在被窝里哭鼻子了嘛~(戳脸)
|
||||
|
||||
注入参数:
|
||||
[被惩戒者:%3$s] [原始刑期:%1$s分钟] [恩赦额度:%2$s分钟]
|
||||
|
||||
立刻生成大小姐裁决宣言:
|
||||
""";
|
||||
gpt = "。\n" + BaiduGPTManager.getManager().sendTmpMessage("user",
|
||||
String.format(gpt, sendTime, tmp, event.getSource().getNickname(), sendTime - tmp),
|
||||
"ernie-speed-128k").getContent();
|
||||
list.add(new Text(gpt));
|
||||
QQBotManager.getInstance().sendMessage(event.isUser(), qq, list);
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -103,7 +154,7 @@ public class QQBean extends Model {
|
||||
void releaseAll(long qq, boolean isRelease) {
|
||||
QQBotManager.getInstance().getShutUpList(qq, new HttpCallback<List<GroupUserBean>>() {
|
||||
@Override
|
||||
public void onResponse(int code, String status, List<GroupUserBean> response, String rawResponse) {
|
||||
public void onResponse(Headers headers, int code, String status, List<GroupUserBean> response, String rawResponse) {
|
||||
List<GroupUserBean> shutList = new ArrayList<>();
|
||||
for (GroupUserBean bean : response) {
|
||||
if (bean.getShutUpTimestamp() > 60) {
|
||||
@@ -115,7 +166,7 @@ public class QQBean extends Model {
|
||||
if (!isRelease) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (GroupUserBean bean : shutList) {
|
||||
sb.append(bean.getNickname()).append(":").append(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss",Locale.CHINA).format(new Date(bean.getShutUpTimestamp()))).append("\n");
|
||||
sb.append(bean.getNickname()).append(":").append(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.CHINA).format(new Date(bean.getShutUpTimestamp()))).append("\n");
|
||||
}
|
||||
QQBotManager.getInstance().sendMessage(qq, "当前塞了:" + shutList.size() + "人" + "\n" + sb);
|
||||
return;
|
||||
@@ -124,7 +175,7 @@ public class QQBean extends Model {
|
||||
for (GroupUserBean bean : shutList) {
|
||||
NapCatApi.getGroupApi().groupBan(qq, bean.getUserId(), 0).enqueue(new HttpCallback<BaseBean>() {
|
||||
@Override
|
||||
public void onResponse(int code, String status, BaseBean response, String rawResponse) {
|
||||
public void onResponse(Headers headers, int code, String status, BaseBean response, String rawResponse) {
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ package com.yutou.qqbot.models.Commands.System;
|
||||
|
||||
import com.yutou.qqbot.Annotations.UseModel;
|
||||
import com.yutou.qqbot.models.Model;
|
||||
import com.yutou.qqbot.utlis.AppTools;
|
||||
import com.yutou.qqbot.utlis.RedisTools;
|
||||
import com.yutou.napcat.event.MessageEvent;
|
||||
|
||||
@@ -30,7 +31,8 @@ public class OpenPC extends Model {
|
||||
public void onMessage(Long qq, MessageEvent event, boolean isGroup) {
|
||||
super.onMessage(qq, event, isGroup);
|
||||
if(msg.equals(QQGroupCommands.QQ_OPEN_PC)){
|
||||
RedisTools.Consumer.system("openPC", null);
|
||||
//RedisTools.Consumer.system("openPC", null);
|
||||
AppTools.exec("wakeonlan 3C:7C:3F:20:88:7D",null,true,false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,6 +10,8 @@ import com.yutou.napcat.model.SourceFrom;
|
||||
import com.yutou.qqbot.Annotations.UseModel;
|
||||
import com.yutou.qqbot.QQBotManager;
|
||||
import com.yutou.qqbot.data.MessageChainBuilder;
|
||||
import com.yutou.qqbot.gpt.AbsGPTManager;
|
||||
import com.yutou.qqbot.gpt.BaiduGPTManager;
|
||||
import com.yutou.qqbot.interfaces.DownloadInterface;
|
||||
import com.yutou.qqbot.models.Model;
|
||||
import com.yutou.qqbot.utlis.HttpTools;
|
||||
@@ -202,6 +204,7 @@ public class GetSeTu extends Model {
|
||||
}
|
||||
JSONObject item = json.getJSONArray("data").getJSONObject(0);
|
||||
StringBuilder builder = new StringBuilder();
|
||||
builder.append("标题:");
|
||||
builder.append(item.getString("title"));
|
||||
builder.append("\n");
|
||||
builder.append("P站ID:");
|
||||
@@ -218,10 +221,41 @@ public class GetSeTu extends Model {
|
||||
for (Object tags : item.getJSONArray("tags")) {
|
||||
builder.append(tags).append("、");
|
||||
}
|
||||
String gpt = """
|
||||
你的人设:傲娇萝莉
|
||||
需求:你在QQ群里,有用户向你索要擦边图片,你需要根据返回的信息整理出文案输出一段话,可以害羞也可以傲娇。
|
||||
输出说明:不要输出任何提示词、不要输出风格类型,因为该输出是直接作用于显示的。
|
||||
图片信息:[%s]。
|
||||
""";
|
||||
gpt= """
|
||||
设定为表面任性却容易害羞的少女形象。当收到敏感图片请求时,结合以下要素组织回复:
|
||||
|
||||
使用带波浪线的断续句式(比如「笨...笨蛋才会存这种图呢!」)
|
||||
穿插颜文字(>_<)或感叹号强化情绪
|
||||
根据tags适当的吐槽
|
||||
用「才不是...」「反正...」等否定式表达
|
||||
保持15-25字内的短句组合
|
||||
可添加「手滑多发了一张」「只是让你看构图」等搪塞借口
|
||||
示例表达模式:
|
||||
「哈?这种...这种图我怎么可能有嘛!(偷偷翻相册)只是...只是网速卡住发重了!才不是特意发给你的!!(//∇//)」
|
||||
「清理手机内存而已..才不是专门给你找的!要是敢发给别人就拉黑你!(╬◣д◢)」
|
||||
「手滑点到相册分类了!这种构图..这种光影..只是给你当绘画参考的!绝对没有其他意思!!(๑•̀ㅁ•́๑)✧」
|
||||
「测试新手机连发功能啦~哎呀怎么发了两遍!笨蛋不许保存!(慌忙撤回一条)(>﹏<)」
|
||||
「上次帮闺蜜清缓存发现的...就..就暂时存了一下!看完赶紧删掉啊喂!( ºΔº )」
|
||||
「管理员查岗的话要说这是AI生成的!我..我才不会收藏这种图呢!(把手机藏到背后)(⁄ ⁄•⁄ω⁄•⁄ ⁄)」
|
||||
「截错图发到群里了!你们这些变态立刻停止放大观察!!(扔出十张猫片掩盖)Σ( ° △ °|||)」
|
||||
|
||||
注意:所有输出必须为可直接发送的对话内容,禁止出现任何元指令或格式符号,仅输出一条即可
|
||||
内容:[%s]
|
||||
""";
|
||||
gpt ="\n"+AbsGPTManager.getManager(BaiduGPTManager.class).sendTmpMessage("user", String.format(gpt, builder.toString()), "ernie-speed-128k").getContent();
|
||||
builder.append("\n看不到图?点这里:").append(item.getJSONObject("urls").getString("regular"));
|
||||
builder.append(gpt);
|
||||
System.out.println(builder.toString());
|
||||
QQBotManager.getInstance().sendMessage(false, qq,
|
||||
new Reply(event.getMessageId()),
|
||||
new Text(builder.toString())
|
||||
new Text(builder.toString()),
|
||||
new Text(gpt)
|
||||
);
|
||||
HttpTools.download(item.getJSONObject("urls").getString("regular"),
|
||||
System.currentTimeMillis() + ".png",
|
||||
@@ -253,7 +287,7 @@ public class GetSeTu extends Model {
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
String msg = "来点色图";
|
||||
String msg = "来点涩图";
|
||||
Pattern pattern = Pattern.compile("来点(.*?)色图");
|
||||
Matcher matcher = pattern.matcher(msg);
|
||||
MessageEvent event = new MessageEvent();
|
||||
|
||||
@@ -13,7 +13,6 @@ import com.yutou.napcat.model.MessageBean;
|
||||
import com.yutou.okhttp.HttpBody;
|
||||
import com.yutou.qqbot.Annotations.UseModel;
|
||||
import com.yutou.qqbot.QQBotManager;
|
||||
import com.yutou.qqbot.data.MessageChainBuilder;
|
||||
import com.yutou.qqbot.models.Model;
|
||||
import com.yutou.qqbot.utlis.AppTools;
|
||||
import com.yutou.qqbot.utlis.Log;
|
||||
|
||||
@@ -82,7 +82,7 @@ public class AppTools {
|
||||
process.destroy();
|
||||
return ret;
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
Log.e(e);
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
@@ -34,6 +34,8 @@ public class ConfigTools {
|
||||
public static final String BAIDU_GPT_SECRET_KEY = "baidu.gpt.SecretKey";
|
||||
public static final String TURNIP_PROPHET_SERVER = "turnip.server";
|
||||
public static final String TURNIP_PROPHET_SEND_TMP_GROUP = "turnip.send.tmp.group";
|
||||
public static final String GPT = "gpt.model";
|
||||
public static final String GPT_SILICON = "silicon.gpt.version";
|
||||
|
||||
|
||||
static {
|
||||
@@ -142,4 +144,11 @@ public class ConfigTools {
|
||||
public static String getServerUrl() {
|
||||
return ConfigTools.load(CONFIG, SERVER_URL, String.class);
|
||||
}
|
||||
public static String getUserAgent() {
|
||||
String ua=load(CONFIG,"userAgent",String.class);
|
||||
if(!org.springframework.util.StringUtils.hasText(ua)){
|
||||
ua="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.0.0 Safari/537.36";
|
||||
}
|
||||
return ua;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ import org.apache.logging.log4j.Logger;
|
||||
import org.apache.logging.log4j.core.Appender;
|
||||
import org.apache.logging.log4j.core.Layout;
|
||||
import org.apache.logging.log4j.core.LoggerContext;
|
||||
import org.apache.logging.log4j.core.appender.ConsoleAppender;
|
||||
import org.apache.logging.log4j.core.appender.RollingFileAppender;
|
||||
import org.apache.logging.log4j.core.appender.rolling.CompositeTriggeringPolicy;
|
||||
import org.apache.logging.log4j.core.appender.rolling.SizeBasedTriggeringPolicy;
|
||||
@@ -80,8 +81,17 @@ public class DynamicLogFile {
|
||||
.withPolicy(triggeringPolicy)
|
||||
.build();
|
||||
|
||||
// 创建控制台Appender
|
||||
Appender consoleAppender = ConsoleAppender.newBuilder()
|
||||
.setName(loggerName + "-console")
|
||||
.setLayout(layout)
|
||||
.setTarget(ConsoleAppender.Target.SYSTEM_OUT)
|
||||
.build();
|
||||
|
||||
appender.start();
|
||||
consoleAppender.start();
|
||||
config.addAppender(appender);
|
||||
config.addAppender(consoleAppender);
|
||||
|
||||
// 获取Logger对象
|
||||
org.apache.logging.log4j.core.Logger coreLogger = context.getLogger(loggerName);
|
||||
@@ -91,6 +101,7 @@ public class DynamicLogFile {
|
||||
|
||||
// 将Appender添加到Logger对象中
|
||||
coreLogger.addAppender(appender);
|
||||
coreLogger.addAppender(consoleAppender);
|
||||
coreLogger.setLevel(Level.ALL);
|
||||
coreLogger.setAdditive(false);
|
||||
|
||||
|
||||
103
src/main/java/com/yutou/qqbot/utlis/ZVVImageUtils.java
Normal file
103
src/main/java/com/yutou/qqbot/utlis/ZVVImageUtils.java
Normal file
@@ -0,0 +1,103 @@
|
||||
package com.yutou.qqbot.utlis;
|
||||
|
||||
import com.alibaba.fastjson2.JSONArray;
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import com.yutou.okhttp.HttpDownloadUtils;
|
||||
import com.yutou.okhttp.HttpLoggingInterceptor;
|
||||
import com.yutou.okhttp.api.BaseApi;
|
||||
import com.yutou.qqbot.interfaces.DownloadInterface;
|
||||
import lombok.val;
|
||||
import okhttp3.*;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* 张vv表情包生成器
|
||||
*/
|
||||
public class ZVVImageUtils {
|
||||
// 单例实例
|
||||
private static volatile ZVVImageUtils instance;
|
||||
private boolean isLocalModel=false;
|
||||
private String queryUrl="https://api.xy0v0.top/search?q=";
|
||||
private String downloadUrl="https://cn-sy1.rains3.com/clouddisk/clouddisk/images/";
|
||||
OkHttpClient okHttpClient = new OkHttpClient.Builder()
|
||||
.connectTimeout(2, TimeUnit.MINUTES)
|
||||
.readTimeout(2, TimeUnit.MINUTES)
|
||||
.build();
|
||||
// 私有构造函数,防止外部实例化
|
||||
private ZVVImageUtils() {
|
||||
}
|
||||
|
||||
// 获取单例实例的方法
|
||||
public static ZVVImageUtils getInstance() {
|
||||
if (instance == null) {
|
||||
synchronized (ZVVImageUtils.class) {
|
||||
if (instance == null) {
|
||||
instance = new ZVVImageUtils();
|
||||
}
|
||||
}
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
private void checkModel(){
|
||||
isLocalModel=ConfigTools.load(ConfigTools.CONFIG,"zvv.model.local", Boolean.class,false);
|
||||
if(isLocalModel){
|
||||
queryUrl="http://192.168.31.88:8501/search?q=";
|
||||
downloadUrl="http://192.168.31.88:8501/clouddisk/clouddisk/images/";
|
||||
}else{
|
||||
String queryUrl="https://api.xy0v0.top/search?q=";
|
||||
String downloadUrl="https://cn-sy1.rains3.com/clouddisk/clouddisk/images/";
|
||||
}
|
||||
}
|
||||
public void zvv(String text, DownloadInterface downloadInterface) {
|
||||
// checkModel();
|
||||
JSONObject json = new JSONObject();
|
||||
json.put("query", text);
|
||||
json.put("amount", 1);
|
||||
RequestBody body = RequestBody.create(MediaType.parse("application/json; charset=UTF-8"), json.toString().getBytes(StandardCharsets.UTF_8));
|
||||
Request.Builder rb = new Request.Builder()
|
||||
.post(body)
|
||||
.addHeader("User-Agent", ConfigTools.getUserAgent())
|
||||
.url(queryUrl + text + "&n=1");
|
||||
Request request = rb.build();
|
||||
okHttpClient.newCall(request).enqueue(new Callback() {
|
||||
@Override
|
||||
public void onFailure(@NotNull Call call, @NotNull IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResponse(@NotNull Call call, @NotNull Response response) throws IOException {
|
||||
if (response.isSuccessful()) {
|
||||
val string = response.body().string();
|
||||
if (!StringUtils.isEmpty(string)) {
|
||||
String imageUrl = JSONArray.parse(string).getString(0);
|
||||
HttpDownloadUtils.download(new HttpDownloadUtils.Builder()
|
||||
.setUrl(downloadUrl + imageUrl)
|
||||
.setFileName(imageUrl)
|
||||
.setPath(new File("tmp").getAbsolutePath())
|
||||
.setDownloadInterface(downloadInterface)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
HttpLoggingInterceptor.setLog(true);
|
||||
ZVVImageUtils.getInstance().zvv("如何评论马督工", new DownloadInterface() {
|
||||
@Override
|
||||
public void onDownload(File file) {
|
||||
super.onDownload(file);
|
||||
System.out.println("file.getAbsolutePath() = " + file.getAbsolutePath());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user