Skip to content
Toggle navigation
P
Projects
G
Groups
S
Snippets
Help
phsl
/
api
This project
Loading...
Sign in
Toggle navigation
Go to a project
Project
Repository
Issues
0
Merge Requests
0
Pipelines
Wiki
Snippets
Members
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Commit
2e932f1f
authored
Jun 10, 2026
by
renyizhao
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
添加按次计费
parent
8503878e
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
254 additions
and
5 deletions
+254
-5
computility-module-apihub/computility-module-apihub-biz/src/main/java/com/luhu/computility/module/apihub/controller/app/AppAiLogController.java
+130
-0
computility-module-apihub/computility-module-apihub-biz/src/main/java/com/luhu/computility/module/apihub/controller/app/aimodel/AppAiModelController.java
+30
-5
computility-module-apihub/computility-module-apihub-biz/src/main/java/com/luhu/computility/module/apihub/service/newapi/NewApiClient.java
+94
-0
No files found.
computility-module-apihub/computility-module-apihub-biz/src/main/java/com/luhu/computility/module/apihub/controller/app/AppAiLogController.java
0 → 100644
View file @
2e932f1f
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
());
}
}
}
computility-module-apihub/computility-module-apihub-biz/src/main/java/com/luhu/computility/module/apihub/controller/app/aimodel/AppAiModelController.java
View file @
2e932f1f
...
...
@@ -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
()
{
...
...
computility-module-apihub/computility-module-apihub-biz/src/main/java/com/luhu/computility/module/apihub/service/newapi/NewApiClient.java
View file @
2e932f1f
...
...
@@ -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
{
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment