【留言送书 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所示。

实战API设计如下:
Url:/api/td-user/wechatLogin/{code}
请求方法:POST
请求参数:如表3所示。

返回参数:如表4所示。

代码如下:

     前端小程序获取微信登录的code后,调用微信登录/注册接口,完成微信登录,并将登录信息写入存储。接口代码如下:

@PostMapping("/wechatLogin/{code}")public BaseSingleResponse wechatLogin(@PathVariable("code") 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;}

登录的方法代码如下:

@Overridepublic 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;@Datapublic 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;@Datapublic 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。

具体代码如下:

@Overridepublic 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.返回参数代码

具体代码如下:

@Datapublic class ApiRequestDto {    private Long id;    private Long userId;    private String prompt;    private Long responseId;    private List<ApiResponseImgDto>  apiResponseImgList;}

其中ApiResponseImgDto对象的代码如下:

@Datapublic class ApiResponseImgDto {    private Long id;    private String url;    private String urlMin;    private String fileName;}

2.图片历史列表接口处理

@Resourceprivate TdApiRequestServiceImpl tdApiRequestService;@GetMapping("/getHistoryImg/{userId}")public BaseResponse<ApiRequestDto> getHistoryImg(@PathVariable("userId") 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)最后,返回包含了所有修改后的请求对象的列表。

具体代码如下:

@Overridepublic 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接口中代码如下:

@Mapperpublic 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 = #{userId}</select>

文章出自清华大学出版社OpenAI API接口应用实战》一书中经授权此

编辑推荐

按照从0到1的顺序,引导读者深入理解OpenAI API;

10大核心API,涵盖从自然语言处理到复杂数据分析等多个领域;

12个关键应用场景,帮助读者精准应用OpenAI API;

3个标杆案例,展示OpenAI API的创新应用。


留言:畅想你认为的OpenAI未来


在留言区参与互动,并点击在看和转发活动到朋友圈,我们将选5名读者送书籍1本,截止时间6月30日。

浏览 34
点赞
评论
收藏
分享

手机扫一扫分享

举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

举报