【留言送书 5 本】AI绘画系统实战代码
共 22944字,需浏览 46分钟
·
2024-06-20 16:55
AI绘画系统的构成包括前端和后端,我们这里前端采用微信进行登录注册,因前端相对简单,我们这里只详细介绍后端代码。
1.前端
调用微信的 wx.login API 获取 code:
wx.login({
success: function(res) {
if (res.code) {
// 在这里将 code 发送给后端
}
}
});
在成功获取用户凭证(code)后,将其发送到服务器:
可以使用 wx.request 发起 HTTPS 请求,例如:
wx.request({
url: 'https://your-website.com/path', // 后端接口地址
data: {
code: res.code // 这是从 wx.login 的响应中获取的 code
},
success: function(response) {
// 在这里处理后端的响应
}
});
2.后端
后端接收到来自前端的 code 后,会用它来请求微信服务器以换取 openid 和 session_key。请求参数如表1所示。
其返回参数如表2所示。
返回参数:如表4所示。
代码如下:
前端小程序获取微信登录的code后,调用微信登录/注册接口,完成微信登录,并将登录信息写入存储。接口代码如下:
public BaseSingleResponse wechatLogin( String code) {
BaseSingleResponse userDtoBaseResponse= new BaseSingleResponse();
try {
userDtoBaseResponse.setCode("200"); //正常返回
userDtoBaseResponse.setData(tdUserService.wechatLogin(code));
}catch (Exception e){
userDtoBaseResponse.setCode("501");
userDtoBaseResponse.setError(e.getMessage()); //登录失败返回501
}
return userDtoBaseResponse;
}
登录的方法代码如下:
public UserDto wechatLogin(String code) throws Exception {
WechatUserInfo wechatInfoByCode = getWechatInfoByCode(code); //通过微信code获取用户信息
if (!ObjectUtil.isNotEmpty(wechatInfoByCode.getOpenid())) {
throw new Exception("登录异常!");
}
UserDto userDto = checkUserLogin(wechatInfoByCode);
userDto.setAllPoint(userDto.getDailyPoint() + userDto.getTotalPoint());
return userDto;
}
获取通过微信code获取用户信息代码:
private WechatUserInfo getWechatInfoByCode(String code) {
OkHttpClient client = new OkHttpClient.Builder()
.readTimeout(120, TimeUnit.SECONDS)
.writeTimeout(120, TimeUnit.SECONDS)
.connectTimeout(240, TimeUnit.SECONDS)
.build();
String loginUrl = "https://api.weixin.qq.com/sns/jscode2session?appid={}&secret={}&js_code={}&grant_type=authorization_code";
final Request okRequest = new Request.Builder()
.url(StrFormatter.format(loginUrl, appid, secret, code))
.header("Authorization", "Bearer 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")
.get()
.build(); //创建请求对象
try {
Response response = client.newCall(okRequest).execute();
if (response.isSuccessful()) { //判断返回数据是否正确
WechatUserInfo result = JSON.parseObject(response.body().string(), WechatUserInfo.class);
return result;
} else {
throw new IOException("Unexpected code " + response);
}
} catch (IOException e) {
e.printStackTrace();
return null;
}
(1)接收用户描述:用户在微信应用中输入描述,例如"一个在海滩上玩飞盘的小狗"。这个描述通过微信的接口被收集,然后发送到本地服务器的API。
(2)本地服务API处理:本地服务API接收到描述后,将其与其他可能的参数(如用户ID、时间戳等)一起打包,并构建为OpenAI Images API所需的格式。可能需要对描述进行一定的处理,例如过滤掉一些特殊字符,或者限制描述的长度。
(3)调用OpenAI Images API:本地服务API将打包好的参数发送给OpenAI Images API,并等待API的响应。这可能涉及到网络请求的创建和发送,需要处理各种可能的网络错误,例如网络连接失败、API服务器无响应、响应超时等。
(4)处理API返回的结果:当OpenAI Images API返回结果时,本地服务API需要处理返回的数据。首先,需要检查API是否成功返回了图像,如果有错误,可能需要根据错误信息进行相应的处理或者错误反馈。如果成功,本地服务API将接收到图像数据,这可能是二进制数据,或者是一个图像的URL。二进制数据需要保存到本地的文件系统或者云存储中,转换为URL。
(5)返回图像给用户:本地服务API将生成的图像URL返回给微信端,微信端再将图像显示给用户。如果图像是URL,可以直接发送;如果是文件,可能需要先上传到微信的文件服务器,转换为微信的文件链接,再发送。
(6)保存生成记录:在本地服务API中,需要在数据库中保存生成图像的记录。记录中需要包括用户的ID、描述、生成的图像链接、生成时间等信息。这些信息将用于用户后续查看历史记录、分享图像等操作。需要保证数据的完整性和一致性,例如使用事务来保证操作的原子性。
具体API设计如下:
Url:/api/chat/getImg
请求方法:POST
请求参数:如表6所示。
返回参数如表7所示。
API代码实现:
1.请求对象代码
请求的JSON对象中,必须包含用户编号、图片描述。
luserId:这是一个用于标识用户的唯一标识符。在用户注册或第一次登录应用时生成。服务器使用它来跟踪用户的请求,例如保存用户的生成图像历史记录,以及用于身份验证等。
lprompt:这是用户提供的描述,用于指导AI生成图像。例如,用户可能输入"一个在海滩上玩飞盘的小狗"作为提示。这个提示被发送到OpenAI Images API,API根据这个提示生成图像。
ln:这是一个指示服务器生成图像的数量的参数。例如,如果用户想要看到不同版本的同一描述的图像,他们可能会设置n为一个大于1的值。然后服务器将返回n个根据同一描述生成的不同图像。
limgSize:这是一个指示生成图像的大小的参数。用户可以根据需要选择不同的图像大小。这个参数可能需要按照OpenAI Images API的要求设置,例如可能需要是某个特定的尺寸或者在一个范围内。
isMock:这是一个布尔值,通常用于测试或调试。如果isMock为true,那么系统可能不会真的调用OpenAI Images API,而是返回一些预设的或者随机的结果。这样可以在开发和测试过程中避免不必要的API调用,节省开发者的时间和资源。
请求对象代码如下:
package com.td.rich.model.request;
import com.td.rich.enums.ImgSize;
import lombok.Data;
public class ImgInputReq {
private Long userId;
private String prompt;
private Integer n = 1;
private ImgSize imgSize = ImgSize.SIZE1024;
private Integer isMock = 0;
}
2.返回对象代码
返回对象的JSON包括code、createtime、data、error。具体描述如下:
code:这是一个字符串,通常用于表示API调用的结果状态。例如,"200"可能表示成功,"400"可能表示客户端错误,"500"可能表示服务器错误。这个码可以根据HTTP状态码的标准来设置,也可以根据应用的需要自定义。
lcreatetime:这是一个字符串,通常用于表示API调用的时间。它可能是一个标准的时间戳,也可能是一个格式化的日期和时间字符串。客户端可以使用这个值来了解API调用的时间,例如用于调试,或者用于显示给用户。
ldata:这是一个ImgUrl对象的列表,用于返回生成的图像的URL。每个ImgUrl对象可能包含一个URL,客户端可以使用这个URL来下载或显示图像。如果生成了多个图像(例如n大于1),那么这个列表可能包含多个ImgUrl对象。
lerror:这是一个字符串,用于返回API调用的错误信息。如果code不是表示成功的值,那么error可能包含一个描述错误的消息。客户端可以使用这个消息来显示错误信息给用户,或者用于调试。
package com.td.rich.model.response;
import lombok.Data;
import java.util.List;
public class ImgResponse {
private String code;
private String createtime;
private List<ImgUrl> data;
private String error;
}
3.API接口代码
使用上面的ImgInputReq 类作为输入参数,ImgResponse 类作为返回参数,我们的接口代码如下:
package com.td.rich.controller;
import com.td.rich.model.request.ImgInputReq;
import com.td.rich.model.request.NormalChatReq;
import com.td.rich.model.request.UserInputReq;
import com.td.rich.model.response.ChatCompletionResponse;
import com.td.rich.model.response.ImgResponse;
import com.td.rich.model.response.NormalChatResp;
import com.td.rich.service.CompletionsService;
import com.td.rich.service.TestService;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
@RestController
@RequestMapping("/api/chat")
public class chatController {
@PostMapping("/getImg")
public ImgResponse getImg(@RequestBody ImgInputReq request) {
return completionsService.getImg(request);
}
}
4.getImg方法
此为接口所调用的方法,该方法的实现步骤如下:
(1)检查描述是否重复:然后,方法调用checkIfPromptDuplicate方法来检查用户的描述是否重复,如果重复,则抛出USER_SAME_PROMPT的错误。
(2)处理模拟请求:如果用户请求的是模拟数据(即request.getIsMock() == 1),则直接返回一个预定义的模拟数据,并结束方法。
(3)创建HTTP客户端:如果用户请求的不是模拟数据,那么方法开始创建一个OkHttpClient对象,这是一个用于发送HTTP请求的客户端。客户端的读、写、连接超时时间都设置为较长的时间,连接池的配置也被自定义。
(4)创建HTTP请求体:然后,方法创建一个RequestBody对象,这是HTTP请求的正文部分。请求体的内容是将ImgInputReq对象转换为JSON字符串,内容类型是"application/json;charset=utf-8"。
(5)创建HTTP请求:然后,方法创建一个Request对象,这是HTTP请求的整体。请求的URL是OpenAI Images API的URL,请求的头部包含一个Authorization字段,其中的Bearer token是API的访问凭证。请求的正文部分就是前面创建的RequestBody。
(6)发送HTTP请求并处理响应:然后,方法使用OkHttpClient发送Request,并得到一个Response。如果Response表示成功(即response.isSuccessful()返回true),那么方法将Response的正文转换为字符串,然后调用getImgResponse方法将其转换为ImgResponse对象并返回。如果Response表示失败,那么方法抛出一个包含Response信息的IOException。
(7)处理错误:如果在发送请求或处理响应过程中发生错误,那么方法捕获IOException,打印错误堆栈,然后返回null。
具体代码如下:
public ImgResponse getImg(ImgInputReq request) {
RichErrorEnum.USER_NOT_POINT.assertIsTrue(tdUserService.consumePoint(request.getUserId()));
RichErrorEnum.USER_SAME_PROMPT.assertIsFalse(tdApiRequestService.checkIfPromptDuplicate(request.getUserId(), request.getPrompt()));
if (request.getIsMock() == 1) {
String mockStr = "{\n" +
" \"created\": \"1683515163\",\n" +
" \"data\": [\n" +
" {\n" +
" \"url\": \"https://qinglite-1253448069.cos.ap-shanghai.myqcloud.com/web/65ae56461ef89a4da2bcdb232d286d2278f5b09d\"\n" +
" },\n" +
" {\n" +
" \"url\": \"https://img1.baidu.com/it/u=2833916768,4266163791&fm=253&fmt=auto&app=138&f=PNG?w=574&h=402\"\n" +
" }\n" +
" ]\n" +
"}";
return getImgResponse(request, mockStr);
}
OkHttpClient client = new OkHttpClient.Builder()
.readTimeout(120, TimeUnit.SECONDS)
.writeTimeout(120, TimeUnit.SECONDS)
.connectTimeout(240, TimeUnit.SECONDS)
//配置自定义连接池参数
.connectionPool(new ConnectionPool(5, 6000, TimeUnit.SECONDS))
.build();
MediaType type = MediaType.parse("application/json;charset=utf-8");
RequestBody requestBody = RequestBody.create(type, JSON.toJSONString(request));
final Request okRequest = new Request.Builder()
.url("https://api.openai.com/v1/images/generations")
.header("Authorization", "Bearer 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")
.post(requestBody)
.build();
try {
Response response = client.newCall(okRequest).execute();
if (response.isSuccessful()) {
return getImgResponse(request, response.body().string());
} else {
throw new IOException("Unexpected code " + response);
}
} catch (IOException e) {
e.printStackTrace();
return null;
}
}
5.getImgResponse方法
这是一个将用户的请求和API的响应保存到数据库,并返回响应的私有方法,具体实现步骤如下:
(1)生成TdApiRequest对象:方法首先通过BeanUtil的copyProperties方法将request(用户的请求)的属性复制到一个新的TdApiRequest对象中。
(2)保存请求:然后,方法调用tdApiRequestService的save方法将TdApiRequest对象(即用户的请求和API的名称)保存到数据库。
(3)解析响应:然后,方法使用JSON的parseObject方法将resultStr(API的响应)解析为一个ImgResponse对象。
(4)保存响应:然后,方法调用tdApiResponseService的saveImgResponse方法将ImgResponse对象(即API的响应)、TdApiRequest对象的id(即请求在数据库中的唯一标识符)和用户的id保存到数据库。
(5)返回响应:最后,方法返回ImgResponse对象,这就是API的响应。
private ImgResponse getImgResponse(ImgInputReq request, String resultStr) {
TdApiRequest tdApiRequest = BeanUtil.copyProperties(request, TdApiRequest.class);
tdApiRequest.setApi(Api.IMAGES.getName());
tdApiRequestService.save(tdApiRequest);
ImgResponse imgResponse = JSON.parseObject(resultStr, ImgResponse.class);
tdApiResponseService.saveImgResponse(imgResponse, tdApiRequest.getId(), request.getUserId());
return imgResponse;
}
6.saveImgResponse方法
这个方法用于保存从OpenAI Images API返回的图像响应,具体步骤如下:
(1)生成TdApiResponse对象:方法首先通过BeanUtil的copyProperties方法将imgResponse(API的响应)的属性复制到一个新的TdApiResponse对象中。
(2)设置请求ID和用户ID:然后,方法将请求的ID和用户的ID设置到TdApiResponse对象中。
(3)检查响应数据:然后,方法检查imgResponse中的data属性的大小。如果没有数据(即data的大小为0),那么方法返回Boolean.FALSE并结束。这可能意味着API没有返回任何图像。
(4)保存响应:如果有数据,那么方法调用save方法将TdApiResponse对象(即API的响应和请求的ID和用户的ID)保存到数据库。
(5)处理每个图像:然后,方法遍历imgResponse中的data属性的每个元素。
对于每个元素,方法执行以下操作:
l创建一个新的TdApiResponseImg对象。
l设置该对象的responseId属性为TdApiResponse对象的id(即响应在数据库中的唯一标识符)。
l创建一个Snowflake对象,用于生成唯一的ID。
l使用Snowflake对象生成一个唯一的ID,加上".png"作为文件名。
l调用saveResult方法将当前元素的url属性(即图像的URL)和文件名作为参数,将图像保存到某个地方(可能是一个文件系统或一个云存储服务),并得到一个新的URL。
l设置TdApiResponseImg对象的fileName属性为新的URL。
l调用tdApiResponseImgService的save方法将TdApiResponseImg对象保存到数据库。
(6)返回成功:最后,方法返回Boolean.TRUE,表示保存成功。
具体代码如下:
public Boolean saveImgResponse(ImgResponse imgResponse, Long requestId, Long userId) {
TdApiResponse tdApiResponse = BeanUtil.copyProperties(imgResponse, TdApiResponse.class);
tdApiResponse.setRequestId(requestId);
tdApiResponse.setUserId(userId);
if (imgResponse.getData().size() == 0)
return Boolean.FALSE;
save(tdApiResponse);
for (int i = 0; i < imgResponse.getData().size(); i++) {
TdApiResponseImg tdApiResponseImg = new TdApiResponseImg();
tdApiResponseImg.setResponseId(tdApiResponse.getId());
Snowflake snowflake = IdUtil.createSnowflake(0, 1);
String fileName = snowflake.nextIdStr() + ".png";
String url = saveResult(imgResponse.getData().get(i).getUrl(), fileName);
tdApiResponseImg.setFileName(url);
tdApiResponseImgService.save(tdApiResponseImg);
}
return Boolean.TRUE;
}
7.图片处理相关方法
(1)saveResult。
此方法的主要作用是从给定的URL下载图像并保存到本地文件系统:
l获取当前日期:创建一个Date对象,用于获取当前日期。
l格式化日期:创建一个SimpleDateFormat对象并指定日期格式为"yyyyMMdd"(年年年年月月日日)。然后使用format方法将当前日期格式化为字符串。
下载并保存图像:在一个try块中,调用ImgUtils.downloadImg方法,将URL、路径(由保存路径、日期字符串和文件名拼接得到)和缩减倍数(reduceMultiple)作为参数。这个方法会尝试从指定URL下载图像,并将其保存在给定路径下的文件中。如果在下载或保存过程中发生异常,catch块会捕获IOException,并打印堆栈轨迹。
返回新文件的路径:最后,方法返回一个字符串,该字符串是由日期字符串、"/"和文件名拼接得到的。这个字符串代表了新下载的图像在文件系统中的相对路径。
代码如下:
private String saveResult(String url, String fileName) {
Date date = new Date(); // 获取当前日期
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyyMMdd"); // 创建一个日期格式化对象,并设置日期格式为"yyyyMMdd"
String dateStr = simpleDateFormat.format(date); // 将当前日期格式化为字符串
try {
// 从指定的URL下载图像,并将其保存在指定的路径下
// 路径由保存路径、日期字符串和文件名拼接得到
// 如果在下载或保存过程中发生异常,将捕获并打印异常
ImgUtils.downloadImg(url, savePath + dateStr, fileName, reduceMultiple);
} catch (IOException e) {
e.printStackTrace(); // 打印异常堆栈轨迹
}
return dateStr + "/" + fileName; // 返回新下载的图像在文件系统中的相对路径
}
(2)downloadImg。
此方法主要用于从网络下载图片,将图片保存到指定的路径,并同时生成一个压缩后的版本。步骤如下:
l通过输入的图片网络地址构造一个URL对象。
l通过openConnection()打开URL连接,并设置连接超时时间为60秒。
l针对savePath路径和savePath + "/min"路径,如果这两个路径不存在,使用mkdirs()方法创建它们。这两个路径分别用于保存原图和缩小后的图。
l从URL连接中获取输入流,并创建一个指向原图保存路径的文件输出流。这个输出流用于将从网络下载的图片数据写入到文件中。
l使用一个大小为1024的字节缓冲区,不断从输入流中读取数据,然后将读取的数据写入到文件输出流。如果在读取或写入过程中出现异常,会打印堆栈信息。
l再次打开URL连接,获取输入流,然后读取图片并将其压缩(按照reduceMultiple的值)。压缩后的图片保存为一个BufferedImage对象。
l将压缩后的BufferedImage对象转为输入流,创建一个指向缩小图片保存路径的文件输出流。用同样的方式将压缩后的图片数据写入到文件中。
l如果所有操作都成功完成,方法返回Boolean.TRUE表示下载和保存图片成功。
实战代码如下:
public static Boolean downloadImg(String urlString, String savePath, String filename, float reduceMultiple) throws IOException {
URL url = new URL(urlString); // 构造URL
URLConnection con = url.openConnection(); // 打开连接
con.setConnectTimeout(60 * 1000); //设置请求超时为20s
File sf = new File(savePath); //文件路径不存在 则创建
if (!sf.exists()) {
sf.mkdirs();
}
File sfMin = new File(savePath + "/min");
if (!sfMin.exists()) {
sfMin.mkdirs();
}
try (InputStream in = con.getInputStream(); //jdk 1.7 新特性自动关闭
OutputStream out = new FileOutputStream(sf.getPath() + "/" + filename)) {
byte[] buff = new byte[1024]; //创建缓冲区
int n;
// 开始读取
while ((n = in.read(buff)) >= 0) {
out.write(buff, 0, n);
}
} catch (Exception e) {
e.printStackTrace();
}
URLConnection con2 = url.openConnection();
con2.setConnectTimeout(60 * 1000); //设置请求超时为20s
BufferedImage image = resizeImage(ImageIO.read(con2.getInputStream()),reduceMultiple);
try (InputStream in = getInputStream(image);
OutputStream out = new FileOutputStream(sfMin.getPath() + "/" + filename)) {
byte[] buff = new byte[1024]; //创建缓冲区
int n;
while ((n = in.read(buff)) >= 0) { // 开始读取
out.write(buff, 0, n);
}
} catch (Exception e) {
e.printStackTrace();
}
return Boolean.TRUE;
}
(3)resizeImage。
这个方法主要用于图片尺寸调整,可以在保持图片内容不变的情况下,根据需要改变图片的宽度和高度,步骤如下:
l首先,计算出新的宽度和高度,这通过将原始图片的宽度和高度分别乘以reduceMultiple得到。
l然后,使用getScaledInstance方法按照计算出的新的宽度和高度对原始图片进行缩放。这个方法使用了区域平均法(Image.SCALE_AREA_AVERAGING)进行缩放,这种方法可以得到较高质量的图片,但是计算开销较大。
l创建一个新的空白BufferedImage对象,其宽度和高度与缩放后的图片一致,图片类型设定为BufferedImage.TYPE_INT_RGB,这表示每个像素用24位RGB颜色模型来表示。
l通过getGraphics().drawImage将缩放后的图片绘制到新的BufferedImage对象上。
l最后,返回这个新的BufferedImage对象,它就是最终缩放后的图片。
代码如下:
public static BufferedImage resizeImage(BufferedImage originalImage, float reduceMultiple) throws IOException {
int width = (int) (originalImage.getWidth() * reduceMultiple); // 计算新的宽度,将原始宽度乘以缩放比例
int height = (int) (originalImage.getHeight() * reduceMultiple); // 计算新的高度,将原始高度乘以缩放比例
Image resultingImage = originalImage.getScaledInstance(width, height, Image.SCALE_AREA_AVERAGING); // 用区域平均算法缩放原始图像
BufferedImage outputImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); // 创建新的缓冲图像,用于存储缩放后的图像
outputImage.getGraphics().drawImage(resultingImage, 0, 0, null); // 在新的缓冲图像上绘制缩放后的图像
return outputImage; // 返回缩放后的缓冲图像
}
(4)getInputStream。
这个方法的主要目的是将一个 BufferedImage 对象转换为 InputStream 对象,以便在其他地方使用这个图像数据,步骤如下:
创建一个ByteArrayOutputStream对象用于临时存储数据。
利用ImageIO.write方法,将BufferedImage的内容以PNG格式写入到ByteArrayOutputStream。若有异常发生,将异常打印出来。
通过ByteArrayOutputStream生成字节数组,然后用这个字节数组创建一个ByteArrayInputStream,这样就得到了一个InputStream对象,它可以被用于输入图像数据。
代码如下:
private static InputStream getInputStream(BufferedImage bi) {
ByteArrayOutputStream os = new ByteArrayOutputStream(); // 创建一个新的字节数组输出流
try {
ImageIO.write(bi, "png", os); // 将BufferedImage以png格式写入字节数组输出流
} catch (IOException e) {
e.printStackTrace(); // 如果有任何IO异常,打印堆栈跟踪
}
return new ByteArrayInputStream(os.toByteArray()); // 使用字节数组输出流中的字节数组创建新的字节数组输入流并返回
}
用户发送HTTP GET请求至服务器,请求路径中包含了用户的唯一标识符(userId),例如/getHistoryImg/123。服务器接收到请求后,调用对应的处理函数getImg。这个函数首先根据请求路径中的{userId}参数来获取该用户的历史图片信息getImg函数调用tdApiRequestService.getHistoryImg(userId)方法来查询数据库或其他数据存储系统,获取所有该用户生成的、已经缩小过的图片记录。这些图片记录包含生成日期、生成的指令(即用户输入的"提示")、缩略图URL(指向缩小后的图片)、原图URL(指向原图片)等信息。API拿到以上信息后,返回到前端。用户可以通过前端按照时间倒序查看自己的历史图片记录。API设计如下:
Url:/getHistoryImg/{userId}
请求方法:GET
请求参数:如表8所示。
返回参数:如表9所示。
代码实现:
1.返回参数代码
具体代码如下:
public class ApiRequestDto {
private Long id;
private Long userId;
private String prompt;
private Long responseId;
private List<ApiResponseImgDto> apiResponseImgList;
}
其中ApiResponseImgDto对象的代码如下:
public class ApiResponseImgDto {
private Long id;
private String url;
private String urlMin;
private String fileName;
}
2.图片历史列表接口处理
private TdApiRequestServiceImpl tdApiRequestService;
public BaseResponse<ApiRequestDto> getHistoryImg( Long userId) {
BaseResponse<ApiRequestDto> response = new BaseResponse<>();
try {
response.setCode("200");
response.setData(tdApiRequestService.getHistoryImg(userId));
}catch (Exception e){
response.setCode("501");
response.setError(e.getMessage());
}
return response;
}
3.主方法getHistoryImg
这个方法的主要功能是获取指定用户的历史图片信息。具体步骤如下:
(1)使用 userId 作为参数调用 tdApiRequestMapper.getRequestList 方法,获取该用户的所有请求列表。每个请求都包含一组与之关联的图片响应,这些信息被存储在 ApiRequestDto 对象的列表中。
(2)通过两层循环遍历每个请求和其相关的每个图片响应。对于每个图片响应,修改其 url 和 urlMin 属性的值。这两个属性分别用于存储原始图片和缩小后的图片的URL地址。图片的URL地址由 readUri (图片存储的基本路径)和图片的文件名拼接而成。特别地,对于 urlMin,其图片文件名的构造还包含了插入了 "min/" 的子路径,这用于标识存储缩小图片的子目录。
(3)最后,返回包含了所有修改后的请求对象的列表。
具体代码如下:
@Override
public List<ApiRequestDto> getHistoryImg(Long userId) {
List<ApiRequestDto> requestList = tdApiRequestMapper.getRequestList(userId); // 从数据库获取指定用户的所有API请求记录
for (int i = 0; i < requestList.size(); i++) { // 遍历所有请求记录
for (int j = 0; j < requestList.get(i).getApiResponseImgList().size(); j++) { // 遍历每个请求记录中的所有图片响应
// 生成并设置原始图片的URL地址
requestList.get(i).getApiResponseImgList().get(j).setUrl(
readUri + requestList.get(i).getApiResponseImgList().get(j).getFileName()
);
// 生成并设置缩小版本的图片的URL地址
requestList.get(i).getApiResponseImgList().get(j).setUrlMin(
readUri + requestList.get(i).getApiResponseImgList().get(j).getFileName().substring(0, 9)
+ "min/" + requestList.get(i).getApiResponseImgList().get(j).getFileName().substring(9)
);
}
}
return requestList; // 返回更新后的请求记录列表
};
其中getRequestList方法在数据库中找出与此用户相关的所有 API 请求及其对应的响应,并将这些信息封装在 ApiRequestDto 对象列表中返回。mapper接口中代码如下:
public interface TdApiRequestMapper extends BaseMapper<TdApiRequest> {
List<ApiRequestDto> getRequestList(Long userId);
}
对应的XML文件中代码如下:
<select id="getRequestList" resultMap="BaseResultMap">
select
a.id as id, a.user_id as userId, a.prompt as prompt, a.messages messages, b.id as responseId
from td_api_request a left join td_api_response b on a.id = b.request_id
where a.user_id =
</select>
文章出自清华大学出版社《OpenAI API接口应用实战》一书中,经授权此公号。
编辑推荐
按照从0到1的顺序,引导读者深入理解OpenAI API;
10大核心API,涵盖从自然语言处理到复杂数据分析等多个领域;
12个关键应用场景,帮助读者精准应用OpenAI API;
3个标杆案例,展示OpenAI API的创新应用。
留言:畅想你认为的OpenAI未来
在留言区参与互动,并点击在看和转发活动到朋友圈,我们将选5名读者送书籍1本,截止时间6月30日。