|
@@ -0,0 +1,146 @@
|
|
|
|
|
+package shop.alien.store.util.ai;
|
|
|
|
|
+
|
|
|
|
|
+import com.alibaba.fastjson2.JSONObject;
|
|
|
|
|
+import lombok.RequiredArgsConstructor;
|
|
|
|
|
+import lombok.extern.slf4j.Slf4j;
|
|
|
|
|
+import org.springframework.beans.factory.annotation.Value;
|
|
|
|
|
+import org.springframework.http.*;
|
|
|
|
|
+import org.springframework.http.client.SimpleClientHttpRequestFactory;
|
|
|
|
|
+import org.springframework.stereotype.Component;
|
|
|
|
|
+import org.springframework.util.StringUtils;
|
|
|
|
|
+import org.springframework.web.client.HttpClientErrorException;
|
|
|
|
|
+import org.springframework.web.client.HttpServerErrorException;
|
|
|
|
|
+import org.springframework.web.client.RestTemplate;
|
|
|
|
|
+
|
|
|
|
|
+import javax.annotation.PostConstruct;
|
|
|
|
|
+import java.util.HashMap;
|
|
|
|
|
+import java.util.Map;
|
|
|
|
|
+
|
|
|
|
|
+/**
|
|
|
|
|
+ * AI 价格查询工具类
|
|
|
|
|
+ *
|
|
|
|
|
+ * @author system
|
|
|
|
|
+ * @since 2025-01-XX
|
|
|
|
|
+ */
|
|
|
|
|
+@Slf4j
|
|
|
|
|
+@Component
|
|
|
|
|
+@RequiredArgsConstructor
|
|
|
|
|
+public class AiGetPriceUtil {
|
|
|
|
|
+
|
|
|
|
|
+ private final AiAuthTokenUtil aiAuthTokenUtil;
|
|
|
|
|
+
|
|
|
|
|
+ private RestTemplate restTemplate;
|
|
|
|
|
+
|
|
|
|
|
+ @Value("${ai.service.price-url}")
|
|
|
|
|
+ private String priceUrl;
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 初始化 RestTemplate,设置超时时间为 180 秒
|
|
|
|
|
+ */
|
|
|
|
|
+ @PostConstruct
|
|
|
|
|
+ public void initRestTemplate() {
|
|
|
|
|
+ SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory();
|
|
|
|
|
+ // 设置连接超时时间为 180 秒(180000 毫秒)
|
|
|
|
|
+ factory.setConnectTimeout(180000);
|
|
|
|
|
+ // 设置读取超时时间为 180 秒(180000 毫秒)
|
|
|
|
|
+ factory.setReadTimeout(180000);
|
|
|
|
|
+ this.restTemplate = new RestTemplate(factory);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 根据菜品名称和位置查询价格
|
|
|
|
|
+ *
|
|
|
|
|
+ * @param dishName 菜品名称
|
|
|
|
|
+ * @param location 位置
|
|
|
|
|
+ * @return 价格查询响应,包含 code, message, data, details, timestamp
|
|
|
|
|
+ */
|
|
|
|
|
+ public JSONObject getDishPrice(String dishName, String location) {
|
|
|
|
|
+ if (!StringUtils.hasText(dishName)) {
|
|
|
|
|
+ log.warn("菜品名称为空,无法查询价格");
|
|
|
|
|
+ return buildErrorResponse("菜品名称不能为空");
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if (!StringUtils.hasText(location)) {
|
|
|
|
|
+ log.warn("位置为空,无法查询价格");
|
|
|
|
|
+ return buildErrorResponse("位置不能为空");
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 获取AI服务访问令牌
|
|
|
|
|
+ String accessToken = aiAuthTokenUtil.getAccessToken();
|
|
|
|
|
+ if (!StringUtils.hasText(accessToken)) {
|
|
|
|
|
+ log.error("获取AI服务访问令牌失败,无法调用价格查询接口");
|
|
|
|
|
+ return buildErrorResponse("获取AI服务访问令牌失败");
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ try {
|
|
|
|
|
+ // 构建请求体
|
|
|
|
|
+ Map<String, Object> requestBody = new HashMap<>();
|
|
|
|
|
+ requestBody.put("dish_name", dishName);
|
|
|
|
|
+ requestBody.put("location", location);
|
|
|
|
|
+
|
|
|
|
|
+ // 构建请求头,添加Authorization
|
|
|
|
|
+ HttpHeaders headers = new HttpHeaders();
|
|
|
|
|
+ headers.setContentType(MediaType.APPLICATION_JSON);
|
|
|
|
|
+ headers.set("Authorization", "Bearer " + accessToken);
|
|
|
|
|
+
|
|
|
|
|
+ HttpEntity<Map<String, Object>> request = new HttpEntity<>(requestBody, headers);
|
|
|
|
|
+
|
|
|
|
|
+ log.info("调用AI价格查询接口,菜品名称: {}, 位置: {}", dishName, location);
|
|
|
|
|
+ ResponseEntity<String> response = restTemplate.postForEntity(priceUrl, request, String.class);
|
|
|
|
|
+
|
|
|
|
|
+ if (response != null && response.getStatusCode() == HttpStatus.OK) {
|
|
|
|
|
+ String responseBody = response.getBody();
|
|
|
|
|
+ log.info("AI价格查询接口响应: {}", responseBody);
|
|
|
|
|
+
|
|
|
|
|
+ if (StringUtils.hasText(responseBody)) {
|
|
|
|
|
+ JSONObject jsonObject = JSONObject.parseObject(responseBody);
|
|
|
|
|
+ if (jsonObject != null) {
|
|
|
|
|
+ Integer code = jsonObject.getInteger("code");
|
|
|
|
|
+ if (code != null && code == 200) {
|
|
|
|
|
+ log.info("成功查询菜品价格,菜品名称: {}, 位置: {}", dishName, location);
|
|
|
|
|
+ return jsonObject;
|
|
|
|
|
+ } else {
|
|
|
|
|
+ String message = jsonObject.getString("message");
|
|
|
|
|
+ log.warn("AI接口返回错误,code: {}, message: {}", code, message);
|
|
|
|
|
+ return jsonObject;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ } else {
|
|
|
|
|
+ log.error("AI价格查询接口调用失败,HTTP状态码: {}",
|
|
|
|
|
+ response != null ? response.getStatusCode() : "null");
|
|
|
|
|
+ return buildErrorResponse("AI价格查询接口调用失败");
|
|
|
|
|
+ }
|
|
|
|
|
+ } catch (HttpClientErrorException e) {
|
|
|
|
|
+ log.error("调用AI价格查询接口失败,HTTP客户端错误,状态码: {}, 响应体: {}, 菜品名称: {}, 位置: {}",
|
|
|
|
|
+ e.getStatusCode(), e.getResponseBodyAsString(), dishName, location, e);
|
|
|
|
|
+ return buildErrorResponse("调用AI价格查询接口失败: " + e.getMessage());
|
|
|
|
|
+ } catch (HttpServerErrorException e) {
|
|
|
|
|
+ log.error("调用AI价格查询接口失败,HTTP服务器错误,状态码: {}, 响应体: {}, 菜品名称: {}, 位置: {}",
|
|
|
|
|
+ e.getStatusCode(), e.getResponseBodyAsString(), dishName, location, e);
|
|
|
|
|
+ return buildErrorResponse("调用AI价格查询接口失败: " + e.getMessage());
|
|
|
|
|
+ } catch (Exception e) {
|
|
|
|
|
+ log.error("调用AI价格查询接口异常,菜品名称: {}, 位置: {}", dishName, location, e);
|
|
|
|
|
+ return buildErrorResponse("调用AI价格查询接口异常: " + e.getMessage());
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ return buildErrorResponse("价格查询失败");
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 构建错误响应
|
|
|
|
|
+ *
|
|
|
|
|
+ * @param message 错误消息
|
|
|
|
|
+ * @return 错误响应JSON对象
|
|
|
|
|
+ */
|
|
|
|
|
+ private JSONObject buildErrorResponse(String message) {
|
|
|
|
|
+ JSONObject response = new JSONObject();
|
|
|
|
|
+ response.put("code", 500);
|
|
|
|
|
+ response.put("message", message);
|
|
|
|
|
+ response.put("data", null);
|
|
|
|
|
+ response.put("details", null);
|
|
|
|
|
+ response.put("timestamp", System.currentTimeMillis() / 1000.0);
|
|
|
|
|
+ return response;
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|