Commit 2e932f1f by renyizhao

添加按次计费

parent 8503878e
package com.luhu.computility.module.apihub.controller.app;
import com.luhu.computility.framework.common.pojo.CommonResult;
import com.luhu.computility.framework.security.core.util.SecurityFrameworkUtils;
import com.luhu.computility.module.apihub.controller.admin.newapi.NewApiResponse;
import com.luhu.computility.module.apihub.service.newapi.NewApiClient;
import com.luhu.computility.module.member.dal.dataobject.user.MemberUserDO;
import com.luhu.computility.module.member.service.user.MemberUserService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
import java.util.Map;
@Slf4j
@RestController
@RequestMapping("/app/ai-log")
public class AppAiLogController {
@Resource
private NewApiClient newApiClient;
@Resource
private MemberUserService memberUserService;
/**
* 获取个人日志统计(quota / rpm / tpm)
*/
@GetMapping("/stat")
public CommonResult<Map<String, Object>> getSelfLogStat(
@RequestParam(defaultValue = "0") Integer type,
@RequestParam(required = false) String model_name,
@RequestParam(required = false) Long start_timestamp,
@RequestParam(required = false) Long end_timestamp) {
Long userId = SecurityFrameworkUtils.getLoginUserId();
log.info("[查询个人日志统计] userId={}, type={}, model_name={}, start={}, end={}",
userId, type, model_name, start_timestamp, end_timestamp);
if (userId == null) {
return CommonResult.error(401, "未登录");
}
MemberUserDO user = memberUserService.getUser(userId);
if (user == null) {
log.warn("[查询个人日志统计] 用户不存在, userId={}", userId);
return CommonResult.error(404, "用户不存在");
}
if (user.getNewapiAccessToken() == null || user.getNewapiUserId() == null) {
log.warn("[查询个人日志统计] 用户尚未初始化 New API 账户, userId={}", userId);
java.util.Map<String, Object> empty = new java.util.HashMap<>();
empty.put("quota", 0);
empty.put("rpm", 0);
empty.put("tpm", 0);
return CommonResult.success(empty);
}
try {
Integer newapiUserId = Integer.parseInt(user.getNewapiUserId().toString());
NewApiResponse<Map<String, Object>> resp = newApiClient.getLogStat(
user.getNewapiAccessToken(),
newapiUserId,
type, model_name,
start_timestamp, end_timestamp);
if (Boolean.TRUE.equals(resp.getSuccess()) && resp.getData() != null) {
return CommonResult.success(resp.getData());
}
log.warn("[查询个人日志统计] New API 返回失败, message={}", resp.getMessage());
return CommonResult.error(500, resp.getMessage() != null ? resp.getMessage() : "查询失败");
} catch (Exception e) {
log.error("[查询个人日志统计] 异常", e);
return CommonResult.error(500, "查询异常: " + e.getMessage());
}
}
/**
* 获取个人日志(消费 / 充值)
* 前端传 type=1(充值)或 type=2(消费),后端直接转发 New API /api/log/self
*/
@GetMapping("/self")
public CommonResult<Map<String, Object>> getSelfLog(
@RequestParam(defaultValue = "1") Integer p,
@RequestParam(defaultValue = "10") Integer page_size,
@RequestParam(defaultValue = "0") Integer type,
@RequestParam(required = false) String model_name,
@RequestParam(required = false) Long start_timestamp,
@RequestParam(required = false) Long end_timestamp) {
Long userId = SecurityFrameworkUtils.getLoginUserId();
log.info("[查询个人日志] userId={}, p={}, page_size={}, type={}, model_name={}, start={}, end={}",
userId, p, page_size, type, model_name, start_timestamp, end_timestamp);
if (userId == null) {
return CommonResult.error(401, "未登录");
}
MemberUserDO user = memberUserService.getUser(userId);
if (user == null) {
log.warn("[查询个人日志] 用户不存在, userId={}", userId);
return CommonResult.error(404, "用户不存在");
}
if (user.getNewapiAccessToken() == null || user.getNewapiUserId() == null) {
log.warn("[查询个人日志] 用户尚未初始化 New API 账户, userId={}", userId);
return CommonResult.success(new java.util.HashMap<>());
}
try {
Integer newapiUserId = Integer.parseInt(user.getNewapiUserId().toString());
NewApiResponse<Map<String, Object>> resp = newApiClient.getLog(
user.getNewapiAccessToken(),
newapiUserId,
p, page_size, type, model_name,
start_timestamp, end_timestamp);
if (Boolean.TRUE.equals(resp.getSuccess()) && resp.getData() != null) {
return CommonResult.success(resp.getData());
}
log.warn("[查询个人日志] New API 返回失败, message={}", resp.getMessage());
return CommonResult.error(500, resp.getMessage() != null ? resp.getMessage() : "查询失败");
} catch (Exception e) {
log.error("[查询个人日志] 异常", e);
return CommonResult.error(500, "查询异常: " + e.getMessage());
}
}
}
......@@ -148,8 +148,10 @@ public class AppAiModelController {
}
Map<String, Object> pricingData = pricingResp.getData();
// 业务最终倍率 = group_ratio.default × 业务系数
// 业务最终倍率 = group_ratio.default × 业务系数(仅按量计费使用)
BigDecimal groupRatio = resolveGroupRatio(pricingData);
// 原始倍率 = group_ratio.default(按次计费使用,不叠加 puhui 业务系数)
BigDecimal plainGroupRatio = resolvePlainGroupRatio(pricingData);
// 2. 构造 model_name -> pricing 索引
@SuppressWarnings("unchecked")
......@@ -227,11 +229,13 @@ public class AppAiModelController {
BigDecimal completionRatio = vo.getCompletionRatio() != null ? vo.getCompletionRatio() : BigDecimal.ONE;
if (vo.getQuotaType() != null && vo.getQuotaType() == 1) {
// 固定价模式:业务系数不参与
vo.setInputPrice(modelPrice.setScale(2, RoundingMode.HALF_UP));
vo.setOutputPrice(modelPrice.multiply(completionRatio).setScale(2, RoundingMode.HALF_UP));
// 按次计费(quota_type=1):使用原始 group_ratio.default,不叠加 puhui 业务系数
BigDecimal perCallPrice = modelPrice.multiply(plainGroupRatio)
.setScale(2, RoundingMode.HALF_UP);
vo.setInputPrice(perCallPrice);
vo.setOutputPrice(perCallPrice);
} else {
// 倍率模式
// 按量计费(quota_type=0):应用 groupRatio(含 BUSINESS_RATIO)
vo.setInputPrice(modelPrice.add(modelRatio).multiply(groupRatio).setScale(2, RoundingMode.HALF_UP));
vo.setOutputPrice(modelPrice.add(modelRatio.multiply(completionRatio)).multiply(groupRatio).setScale(2, RoundingMode.HALF_UP));
}
......@@ -272,6 +276,27 @@ public class AppAiModelController {
}
/**
* 从 pricing 原始数据中解析原始 group_ratio.default(不叠加 puhui 业务系数,按次计费使用)
*/
private BigDecimal resolvePlainGroupRatio(Map<String, Object> pricingData) {
@SuppressWarnings("unchecked")
Map<String, Object> groupRatioMap = (Map<String, Object>) pricingData.get("group_ratio");
if (groupRatioMap == null) {
return BigDecimal.ONE;
}
Object defaultRatio = groupRatioMap.get("default");
if (defaultRatio == null) {
return BigDecimal.ONE;
}
try {
return new BigDecimal(String.valueOf(defaultRatio));
} catch (Exception e) {
log.warn("[resolvePlainGroupRatio] 解析 group_ratio.default 失败:{}", defaultRatio);
return BigDecimal.ONE;
}
}
/**
* 获取当前登录用户的 New API accessToken(无则返回 null)
*/
private String getCurrentUserAccessToken() {
......
......@@ -360,6 +360,100 @@ public class NewApiClient {
}
}
/**
* 获取个人日志统计
* GET /api/log/self/stat?type=0&model_name=&start_timestamp=&end_timestamp=
*
* @param accessToken 用户访问令牌
* @param userId 用户在 New API 的 userId
* @param type 0: 全部 1: 充值 2: 消费 3: 管理
* @param modelName 模型名称(可空)
* @param startTimestamp 起始时间戳(可空)
* @param endTimestamp 截止时间戳(可空)
*/
public NewApiResponse<Map<String, Object>> getLogStat(String accessToken, Integer userId,
Integer type, String modelName,
Long startTimestamp, Long endTimestamp) {
StringBuilder url = new StringBuilder(newApiProperties.getBaseUrl())
.append("/api/log/self/stat?")
.append("type=").append(type == null ? 0 : type)
.append("&model_name=").append(modelName == null ? "" : modelName);
if (startTimestamp != null) {
url.append("&start_timestamp=").append(startTimestamp);
}
if (endTimestamp != null) {
url.append("&end_timestamp=").append(endTimestamp);
}
log.info("[NewApiClient.getLogStat] 请求URL: {}", url);
try {
HttpResponse response = HttpRequest.get(url.toString())
.header(HEADER_USER, String.valueOf(userId))
.header(HEADER_AUTH, "Bearer " + accessToken)
.timeout(30000)
.execute();
log.info("[NewApiClient.getLogStat] 响应状态: {}", response.getStatus());
return parseMapResponse(response);
} catch (Exception e) {
log.error("[NewApiClient.getLogStat] 请求异常", e);
return NewApiResponse.<Map<String, Object>>builder()
.success(false)
.message("请求异常: " + e.getMessage())
.httpResponse(null)
.build();
}
}
/**
* 获取个人日志
* GET /api/log/self?p=1&page_size=10&type=0&model_name=&start_timestamp=&end_timestamp=
*
* @param accessToken 用户访问令牌
* @param userId 用户在 New API 的 userId
* @param page 页数
* @param pageSize 每页条数
* @param type 0: 全部 1: 充值 2: 消费 3: 管理
* @param modelName 模型名称(可空)
* @param startTimestamp 起始时间戳(可空)
* @param endTimestamp 截止时间戳(可空)
*/
public NewApiResponse<Map<String, Object>> getLog(String accessToken, Integer userId,
Integer page, Integer pageSize, Integer type,
String modelName, Long startTimestamp, Long endTimestamp) {
StringBuilder url = new StringBuilder(newApiProperties.getBaseUrl())
.append("/api/log/self?")
.append("p=").append(page == null ? 1 : page)
.append("&page_size=").append(pageSize == null ? 10 : pageSize)
.append("&type=").append(type == null ? 0 : type)
.append("&model_name=").append(modelName == null ? "" : modelName);
if (startTimestamp != null) {
url.append("&start_timestamp=").append(startTimestamp);
}
if (endTimestamp != null) {
url.append("&end_timestamp=").append(endTimestamp);
}
log.info("[NewApiClient.getLog] 请求URL: {}", url);
try {
HttpResponse response = HttpRequest.get(url.toString())
.header(HEADER_USER, String.valueOf(userId))
.header(HEADER_AUTH, "Bearer " + accessToken)
.timeout(30000)
.execute();
log.info("[NewApiClient.getLog] 响应状态: {}", response.getStatus());
return parseMapResponse(response);
} catch (Exception e) {
log.error("[NewApiClient.getLog] 请求异常", e);
return NewApiResponse.<Map<String, Object>>builder()
.success(false)
.message("请求异常: " + e.getMessage())
.httpResponse(null)
.build();
}
}
@SuppressWarnings("unchecked")
private NewApiResponse<Map<String, Object>> parseMapResponse(HttpResponse response) {
try {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment