Fuyu-8B是由Adept AI训练的多模态图像理解模型,可以支持多样的图像分辨率,回答图形图表有关问题
配置文件,连接池设置和文心设置,模型调用预置服务,即调用本文API,该字段必填,且为固定值Fuyu-8B 该服务
请求地址: https://aip.baidubce.com/rpc/2.0/ai_custom/v1/wenxinworkshop/image2text/fuyu_8b
请求方式: POST
当然这边也可以替换成其他服务地址,使用其他预制服务
OkHttpConfiguration配置
package com.example.aianalyseimageuserservice.Config;
import okhttp3.ConnectionPool;
import okhttp3.OkHttpClient;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.concurrent.TimeUnit;
@Configuration
public class OkHttpConfiguration {
@Value("${ok.http.connect-timeout}")
private Integer connectTimeout;
@Value("${ok.http.read-timeout}")
private Integer readTimeout;
@Value("${ok.http.write-timeout}")
private Integer writeTimeout;
@Value("${ok.http.max-idle-connections}")
private Integer maxIdleConnections;
@Value("${ok.http.keep-alive-duration}")
private Long keepAliveDuration;
@Bean
public OkHttpClient okHttpClient() {
return new OkHttpClient.Builder()
.sslSocketFactory(sslSocketFactory(), x509TrustManager())
// 是否开启缓存
.retryOnConnectionFailure(false)
.connectionPool(pool())
.connectTimeout(connectTimeout, TimeUnit.SECONDS)
.readTimeout(readTimeout, TimeUnit.SECONDS)
.writeTimeout(writeTimeout,TimeUnit.SECONDS)
.hostnameVerifier((hostname, session) -> true)
.build();
}
@Bean
public X509TrustManager x509TrustManager() {
return new X509TrustManager() {
@Override
public void checkClientTrusted(X509Certificate[] chain, String authType)
throws CertificateException {
}
@Override
public void checkServerTrusted(X509Certificate[] chain, String authType)
throws CertificateException {
}
@Override
public X509Certificate[] getAcceptedIssuers() {
return new X509Certificate[0];
}
};
}
@Bean
public SSLSocketFactory sslSocketFactory() {
try {
// 信任任何链接
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, new TrustManager[]{x509TrustManager()}, new SecureRandom());
return sslContext.getSocketFactory();
} catch (NoSuchAlgorithmException | KeyManagementException e) {
e.printStackTrace();
}
return null;
}
@Bean
public ConnectionPool pool() {
return new ConnectionPool(maxIdleConnections, keepAliveDuration, TimeUnit.SECONDS);
}
}
WenXinConfig配置
主要为了获取access_token鉴权
也可以通过官方所给方式获取(通过网址访问),该值有时长
# 步骤一,获取access_token,替换下列示例中的API Key与Secret Key
curl 'https://aip.baidubce.com/oauth/2.0/token?grant_type=client_credentials&client_id=[API Key]&client_secret=[Secret Key]'
# 步骤二,调用本文API,使用步骤一获取的access_token,替换下列示例中的”调用接口获取的access_token“;替换示例中的创建服务时填写的API名称
curl -X POST 'https://aip.baidubce.com/rpc/2.0/ai_custom/v1/wenxinworkshop/image2text/fuyu_8b?access_token=[步骤一调用接口获取的access_token]' -d '{
"prompt": "introduce the picture",
"image": "9j/4AAQSkZJRgABAQAAAQABAAD/xxxxx"
}'
过期自动获取
package com.example.aianalyseimageuserservice.Config;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
import java.io.IOException;
import java.util.Date;
@Configuration
public class WenXinConfig {
@Value("${wenxin.apiKey}")
public String API_KEY;
@Value("${wenxin.secretKey}")
public String SECRET_KEY;
@Value("${wenxin.accessTokenUrl}")
public String ACCESS_TOKEN_URL;
@Value("${wenxin.ERNIE_Bot.URL}")
public String FuYu_8b_URL;
//过期时间为30天
public String ACCESS_TOKEN = null;
public String REFRESH_TOKEN = null;
public Date CREATE_TIME = null;//accessToken创建时间
public Date EXPIRATION_TIME = null;//accessToken到期时间
/**
* 获取accessToken
* @return true表示成功 false表示失败
*/
public synchronized String flushAccessToken(){
//判断当前AccessToken是否为空且判断是否过期
if(ACCESS_TOKEN != null && EXPIRATION_TIME.getTime() > CREATE_TIME.getTime()) return ACCESS_TOKEN;
//构造请求体 包含请求参数和请求头等信息
RequestBody body = RequestBody.create(MediaType.parse("application/json"),"");
Request request = new Request.Builder()
.url(ACCESS_TOKEN_URL+"?client_id="+API_KEY+"&client_secret="+SECRET_KEY+"&grant_type=client_credentials")
.method("POST", body)
.addHeader("Content-Type", "application/json")
.addHeader("Accept", "application/json")
.build();
OkHttpClient HTTP_CLIENT = new OkHttpClient().newBuilder().build();
String response = null;
try {
//请求
response = HTTP_CLIENT.newCall(request).execute().body().string();
} catch (IOException e) {
// log.error("ACCESS_TOKEN获取失败");
System.out.println("ACCESS_TOKEN获取失败");
return null;
}
//刷新令牌以及更新令牌创建时间和过期时间
JSONObject jsonObject = JSON.parseObject(response);
ACCESS_TOKEN = jsonObject.getString("access_token");
REFRESH_TOKEN = jsonObject.getString("refresh_token");
CREATE_TIME = new Date();
EXPIRATION_TIME = new Date(Long.parseLong(jsonObject.getString("expires_in")) + CREATE_TIME.getTime());
return ACCESS_TOKEN;
}
}
主体部分Controller
先来个json构造器,具体想构造参数可以根据官方文
我只构造了几个基本参数
/**
* 构造请求的请求参数
*
* @param userId
* @param image
* @param stream
* @param prompt
* @return
*/
public String constructRequestJson(Integer userId,
String image,
boolean stream,
String prompt
) {
Map<String, Object> request = new HashMap<>();
request.put("user_id", userId.toString());
request.put("image", image);
request.put("stream", stream);
request.put("prompt", prompt);
return JSON.toJSONString(request);
}
图片数据,说明:base64编码,要求base64编码后大小不超过4M,最短边至少15px,最长边最大4096px,支持jpg/png/bmp格式,注意请去掉头部
图片转base64编码类
package com.example.aianalyseimageuserservice.tool;
import org.springframework.stereotype.Component;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.util.Base64;
@Component
public class ImageToBase64 {
/**
* 方法参数
*
* @param imageFileName
* @return
*/
public static String ToBase64(String imageFileName) {
ByteArrayOutputStream baos = null;
try {
//获取图片类型
String suffix = imageFileName.substring(imageFileName.lastIndexOf(".") + 1);
//构建文件
File imageFile = new File(imageFileName);
//通过ImageIO把文件读取成BufferedImage对象
BufferedImage bufferedImage = ImageIO.read(imageFile);
//构建字节数组输出流
baos = new ByteArrayOutputStream();
//写入流
ImageIO.write(bufferedImage, suffix, baos);
//通过字节数组流获取字节数组
byte[] bytes = baos.toByteArray();
//获取JDK8里的编码器Base64.Encoder转为base64字符
return Base64.getEncoder().encodeToString(bytes);
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (baos != null) {
baos.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
return null;
}
}
请求获取图片下载命名,下载目录,文件格式
#生成保存本地图片uuid和格式
requestGetImage:
loadPath: C:\\Users\\chinaxsd\\Desktop\\file\\ #该路径必须存在于计算机中,程序不能新建
uuidFormat: yyyyMMddHHmmssSSSS
ImageFormat: jpg
package com.example.aianalyseimageuserservice.tool;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Random;
@Component
public class DownLoadImageUUID {
@Value("${requestGetImage.uuidFormat}")
private String uuidFormat;
@Value("${requestGetImage.ImageFormat}")
private String ImageFormat;
/**
* @return
*/
public String setRandomUUIDAndImageFormat() {
//进来的PostInfo没有uid,自动生成一个
SimpleDateFormat sdf = new SimpleDateFormat(this.uuidFormat);
//格式当前时间+一个随机数
return sdf.format(new Date()) + new Random().nextInt(0, 9)+"."+this.ImageFormat;
}
}
@RequestHeader部分请忽略
使用非流式上传
package com.example.aianalyseimageuserservice.controller;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.example.aianalyseimageuserservice.Config.WenXinConfig;
import com.example.aianalyseimageuserservice.tool.DownLoadImageUUID;
import com.example.aianalyseimageuserservice.tool.ImageToBase64;
import jakarta.annotation.Resource;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
@RestController
@RequestMapping("/ai-analysisImage")
@RefreshScope
public class analysisImageAPIController {
@Resource
private WenXinConfig wenXinConfig;
@Resource
private DownLoadImageUUID downLoadImageUUID;
/**
* 非流式问答
*
* @param question 用户的问题
* @return
* @throws IOException
*/
@Value("${requestGetImage.loadPath}")
private String ImageLoadPath;
@PostMapping("ask")
public String analysisImage(@RequestParam("question") String question, @RequestParam("file") MultipartFile file,
@RequestHeader(value = "is-success-gateway", required = false) String header) throws IOException {
//判断header 是否是true,不是则不允许访问该服务
if (header == null) {
return "请先登录后再访问";
}
if (question == null || question.equals("")) {
return "请输入问题";
}
if (file == null||file.isEmpty()) {
return "请放入图片";
}
// 图片数据,说明:base64编码,要求base64编码后大小不超过4M,最短边至少15px,最长边最大4096px,支持jpg/png/bmp格式,注意请去掉头部
String ImageFileName = this.ImageLoadPath + downLoadImageUUID.setRandomUUIDAndImageFormat();
file.transferTo(new File(ImageFileName));//保存获取的文件
String responseJson = null;
//先获取令牌然后才能访问api
if (wenXinConfig.flushAccessToken() != null) {
String prompt = question;
String requestJson = constructRequestJson(1, ImageToBase64.ToBase64(ImageFileName), false, prompt);
RequestBody body = RequestBody.create(MediaType.parse("application/json"), requestJson);
Request request = new Request.Builder()
.url(wenXinConfig.FuYu_8b_URL + "?access_token=" + wenXinConfig.flushAccessToken())
.method("POST", body)
.addHeader("Content-Type", "application/json")
.build();
OkHttpClient HTTP_CLIENT = new OkHttpClient().newBuilder().build();
try {
responseJson = HTTP_CLIENT.newCall(request).execute().body().string();
//将回复的内容转为一个JSONObject
JSONObject responseObject = JSON.parseObject(responseJson);
} catch (IOException e) {
System.out.println("网络有问题");
return "网络有问题,请稍后重试";
}
}
return responseJson;
}
responseJson参数https://cloud.baidu.com/doc/WENXINWORKSHOP/s/Qlq4l7uw6