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
8e72bc4d
authored
Jun 24, 2026
by
renyizhao
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
条件乘数
parent
f3ae131f
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
251 additions
and
38 deletions
+251
-38
computility-module-apihub/computility-module-apihub-biz/src/main/java/com/luhu/computility/module/apihub/controller/app/aimodel/AppAiModelController.java
+236
-38
computility-module-apihub/computility-module-apihub-biz/src/main/java/com/luhu/computility/module/apihub/controller/app/aimodel/vo/AppModelPricingVO.java
+15
-0
No files found.
computility-module-apihub/computility-module-apihub-biz/src/main/java/com/luhu/computility/module/apihub/controller/app/aimodel/AppAiModelController.java
View file @
8e72bc4d
...
...
@@ -235,6 +235,9 @@ public class AppAiModelController {
if
(
"tiered_expr"
.
equals
(
billingMode
)
&&
billingExpr
!=
null
)
{
List
<
AppModelPricingVO
.
TierVO
>
tiers
=
parseTieredExpr
(
billingExpr
,
groupRatio
);
vo
.
setTiers
(
tiers
);
// 解析条件乘数
List
<
AppModelPricingVO
.
ConditionMultiplierVO
>
conditionMultipliers
=
parseConditionMultipliers
(
billingExpr
);
vo
.
setConditionMultipliers
(
conditionMultipliers
);
}
// 计算价格
...
...
@@ -470,7 +473,7 @@ public class AppAiModelController {
/**
* 解析分档计费表达式
* 格式:
len <= 200000 && p > 200000 ? tier("base", p * 1 + c * 1.2) : c > 200000 && p > 200000 ? tier("第2档", p * 0.8 + c * 0.9) : tier("第3档", p * 0.5 + c * 0.6)
* 格式:
(条件1 ? tier("档位1", ...) : 条件2 ? tier("档位2", ...) : tier("档位3", ...)) * (条件 ? 倍率 : 1) * ...
*/
private
List
<
AppModelPricingVO
.
TierVO
>
parseTieredExpr
(
String
billingExpr
,
BigDecimal
groupRatio
)
{
List
<
AppModelPricingVO
.
TierVO
>
tiers
=
new
java
.
util
.
ArrayList
<>();
...
...
@@ -479,59 +482,254 @@ public class AppAiModelController {
}
try
{
// 正则匹配 tier("名称", p * 输入倍率 + c * 输出倍率)
// 找到最后一个 tier(...) 结束的位置(用于截取分档表达式部分)
int
lastTierEnd
=
-
1
;
int
searchStart
=
0
;
while
(
true
)
{
int
tierStart
=
billingExpr
.
indexOf
(
"tier("
,
searchStart
);
if
(
tierStart
==
-
1
)
break
;
int
depth
=
0
;
int
i
=
tierStart
;
for
(;
i
<
billingExpr
.
length
();
i
++)
{
char
ch
=
billingExpr
.
charAt
(
i
);
if
(
ch
==
'('
)
depth
++;
else
if
(
ch
==
')'
)
{
depth
--;
if
(
depth
==
0
)
{
lastTierEnd
=
i
+
1
;
break
;
}
}
}
searchStart
=
i
+
1
;
}
if
(
lastTierEnd
==
-
1
)
{
return
tiers
;
}
// 提取分档表达式部分(从开头到最后一个 tier(...) 结束)
String
tierExpr
=
billingExpr
.
substring
(
0
,
lastTierEnd
);
// 找到所有 tier("名称", p * x + c * y) 的位置
java
.
util
.
regex
.
Pattern
tierPattern
=
java
.
util
.
regex
.
Pattern
.
compile
(
"tier\\s*\\(\\s*\"([^\"]+)\"\\s*,\\s*p\\s*\\*\\s*([\\d.]+)\\s*\\+\\s*c\\s*\\*\\s*([\\d.]+)\\s*\\)"
);
java
.
util
.
regex
.
Matcher
tierMatcher
=
tierPattern
.
matcher
(
billing
Expr
);
java
.
util
.
regex
.
Matcher
tierMatcher
=
tierPattern
.
matcher
(
tier
Expr
);
// 提取档位信息
// 收集所有 tier 的位置和内容
java
.
util
.
List
<
java
.
util
.
regex
.
MatchResult
>
tierMatches
=
new
java
.
util
.
ArrayList
<>();
while
(
tierMatcher
.
find
())
{
AppModelPricingVO
.
TierVO
tier
=
new
AppModelPricingVO
.
TierVO
();
tier
.
setName
(
tierMatcher
.
group
(
1
));
// 动态计费的价格倍率已经是最终值,不需要乘以 groupRatio
BigDecimal
inputRatio
=
new
BigDecimal
(
tierMatcher
.
group
(
2
)).
setScale
(
4
,
RoundingMode
.
HALF_UP
);
BigDecimal
outputRatio
=
new
BigDecimal
(
tierMatcher
.
group
(
3
)).
setScale
(
4
,
RoundingMode
.
HALF_UP
);
tier
.
setInputRatio
(
inputRatio
);
tier
.
setOutputRatio
(
outputRatio
);
tiers
.
add
(
tier
);
tierMatches
.
add
(
tierMatcher
.
toMatchResult
());
}
// 解析条件描述
if
(
tiers
.
isEmpty
())
{
if
(
tierMatches
.
isEmpty
())
{
return
tiers
;
}
// 按 : 分割,每一段是 条件? tier(...) 的格式
String
[]
segments
=
billingExpr
.
split
(
":"
);
int
tierIndex
=
0
;
for
(
String
segment
:
segments
)
{
// 找 tier(...) 前的条件(?前面的部分)
// 遍历每个 tier,提取其对应的条件
for
(
int
i
=
0
;
i
<
tierMatches
.
size
();
i
++)
{
AppModelPricingVO
.
TierVO
tier
=
new
AppModelPricingVO
.
TierVO
();
java
.
util
.
regex
.
MatchResult
mr
=
tierMatches
.
get
(
i
);
tier
.
setName
(
mr
.
group
(
1
));
tier
.
setInputRatio
(
new
BigDecimal
(
mr
.
group
(
2
)).
setScale
(
4
,
RoundingMode
.
HALF_UP
));
tier
.
setOutputRatio
(
new
BigDecimal
(
mr
.
group
(
3
)).
setScale
(
4
,
RoundingMode
.
HALF_UP
));
// 提取条件:从上一个 tier 结束(或表达式开头)到当前 tier 开始的 ? 之前
int
tierStart
=
mr
.
start
();
String
segment
;
if
(
i
==
0
)
{
// 第一个 tier:条件在表达式开头到 tier 之前
segment
=
tierExpr
.
substring
(
0
,
tierStart
);
}
else
{
// 后续 tier:条件在上一个 tier 结束后到当前 tier 之前
int
prevTierEnd
=
tierMatches
.
get
(
i
-
1
).
end
();
segment
=
tierExpr
.
substring
(
prevTierEnd
,
tierStart
);
}
// 找到 ? 的位置,? 之前是条件
int
questionMarkIndex
=
segment
.
lastIndexOf
(
'?'
);
if
(
questionMarkIndex
>
0
&&
tierIndex
<
tiers
.
size
())
{
String
conditionDesc
=
segment
.
substring
(
0
,
questionMarkIndex
).
trim
();
// 简化条件描述
conditionDesc
=
conditionDesc
.
replaceAll
(
"\\s+&&\\s+"
,
" 且 "
)
.
replaceAll
(
"\\s+\\|\\|\\s+"
,
" 或 "
)
.
replace
(
"len"
,
"长度"
)
.
replace
(
" p "
,
" 输入 "
)
.
replace
(
" c "
,
" 输出 "
)
.
replace
(
"p >"
,
"输入 >"
)
.
replace
(
"p <"
,
"输入 <"
)
.
replace
(
"p >="
,
"输入 >="
)
.
replace
(
"p <="
,
"输入 <="
)
.
replace
(
"c >"
,
"输出 >"
)
.
replace
(
"c <"
,
"输出 <"
)
.
replace
(
"c >="
,
"输出 >="
)
.
replace
(
"c <="
,
"输出 <="
);
tiers
.
get
(
tierIndex
).
setConditionDesc
(
conditionDesc
);
tierIndex
++;
if
(
questionMarkIndex
>
0
)
{
String
condition
=
segment
.
substring
(
0
,
questionMarkIndex
).
trim
();
// 清理:去掉开头的 ( : 和结尾的空格
condition
=
condition
.
replaceAll
(
"^[\\s(:)]+"
,
""
);
// 去掉首尾括号对
while
(
condition
.
startsWith
(
"("
)
&&
condition
.
endsWith
(
")"
))
{
condition
=
condition
.
substring
(
1
,
condition
.
length
()
-
1
).
trim
();
}
tier
.
setConditionDesc
(
simplifyCondition
(
condition
));
}
else
if
(
i
==
tierMatches
.
size
()
-
1
)
{
// 最后一个 tier 没有 ?,是默认档位
tier
.
setConditionDesc
(
null
);
}
tiers
.
add
(
tier
);
}
}
catch
(
Exception
e
)
{
log
.
warn
(
"[parseTieredExpr] 解析分档表达式失败:{}"
,
billingExpr
,
e
);
}
return
tiers
;
}
/**
* 简化条件描述
*/
private
String
simplifyCondition
(
String
condition
)
{
if
(
condition
==
null
||
condition
.
isEmpty
())
{
return
""
;
}
return
condition
.
replaceAll
(
"\\s+&&\\s+"
,
" 且 "
)
.
replaceAll
(
"\\s+\\|\\|\\s+"
,
" 或 "
)
.
replace
(
"len"
,
"长度"
)
.
replace
(
" p "
,
" 输入 "
)
.
replace
(
" c "
,
" 输出 "
)
.
replace
(
"p >"
,
"输入 >"
)
.
replace
(
"p <"
,
"输入 <"
)
.
replace
(
"p >="
,
"输入 >="
)
.
replace
(
"p <="
,
"输入 <="
)
.
replace
(
"p=="
,
"输入 =="
)
.
replace
(
"c >"
,
"输出 >"
)
.
replace
(
"c <"
,
"输出 <"
)
.
replace
(
"c >="
,
"输出 >="
)
.
replace
(
"c <="
,
"输出 <="
)
.
replace
(
"c=="
,
"输出 =="
)
.
trim
();
}
/**
* 解析条件乘数表达式
* 格式: ((条件) ? 倍率 : 1) * ((条件) ? 倍率 : 1) * ...
*/
private
List
<
AppModelPricingVO
.
ConditionMultiplierVO
>
parseConditionMultipliers
(
String
billingExpr
)
{
List
<
AppModelPricingVO
.
ConditionMultiplierVO
>
multipliers
=
new
java
.
util
.
ArrayList
<>();
if
(
billingExpr
==
null
||
billingExpr
.
isEmpty
())
{
return
multipliers
;
}
try
{
// 找到最后一个 tier(...) 结束的位置
int
lastTierEnd
=
-
1
;
int
searchStart
=
0
;
while
(
true
)
{
int
tierStart
=
billingExpr
.
indexOf
(
"tier("
,
searchStart
);
if
(
tierStart
==
-
1
)
break
;
int
depth
=
0
;
int
i
=
tierStart
;
for
(;
i
<
billingExpr
.
length
();
i
++)
{
char
ch
=
billingExpr
.
charAt
(
i
);
if
(
ch
==
'('
)
depth
++;
else
if
(
ch
==
')'
)
{
depth
--;
if
(
depth
==
0
)
{
lastTierEnd
=
i
+
1
;
break
;
}
}
}
searchStart
=
i
+
1
;
}
if
(
lastTierEnd
==
-
1
||
lastTierEnd
>=
billingExpr
.
length
())
{
return
multipliers
;
}
// 提取条件乘数部分(最后一个 tier(...) 之后的内容)
String
multiplierExpr
=
billingExpr
.
substring
(
lastTierEnd
).
replaceAll
(
"^\\s*\\)\\s*\\*\\s*"
,
""
);
// 用栈匹配方式解析每个条件组: ((... ) ? 倍率 : 1)
int
pos
=
0
;
while
(
pos
<
multiplierExpr
.
length
())
{
// 找到下一个 ( 的位置
int
startParen
=
multiplierExpr
.
indexOf
(
'('
,
pos
);
if
(
startParen
==
-
1
)
break
;
// 从这个 ( 开始,找到对应的 )
int
depth
=
0
;
int
i
=
startParen
;
for
(;
i
<
multiplierExpr
.
length
();
i
++)
{
char
ch
=
multiplierExpr
.
charAt
(
i
);
if
(
ch
==
'('
)
depth
++;
else
if
(
ch
==
')'
)
{
depth
--;
if
(
depth
==
0
)
{
// 找到了对应的 )
// 提取从 startParen 到 i+1 的内容(完整条件组)
String
group
=
multiplierExpr
.
substring
(
startParen
,
i
+
1
);
// 检查是否是条件组格式: (... ) ? 倍率 : 1
int
questionMark
=
group
.
lastIndexOf
(
'?'
);
int
colonIndex
=
group
.
lastIndexOf
(
':'
);
if
(
questionMark
>
0
&&
colonIndex
>
questionMark
)
{
String
condition
=
group
.
substring
(
1
,
questionMark
).
trim
();
// 去掉首尾括号
String
afterQuestion
=
group
.
substring
(
questionMark
+
1
,
colonIndex
).
trim
();
try
{
BigDecimal
multiplier
=
new
BigDecimal
(
afterQuestion
).
setScale
(
1
,
RoundingMode
.
HALF_UP
);
AppModelPricingVO
.
ConditionMultiplierVO
cm
=
new
AppModelPricingVO
.
ConditionMultiplierVO
();
cm
.
setMultiplier
(
multiplier
);
cm
.
setDescription
(
parseConditionDesc
(
condition
));
multipliers
.
add
(
cm
);
}
catch
(
NumberFormatException
ignored
)
{}
}
pos
=
i
+
1
;
break
;
}
}
}
if
(
i
>=
multiplierExpr
.
length
())
break
;
}
}
catch
(
Exception
e
)
{
log
.
warn
(
"[parseConditionMultipliers] 解析条件乘数失败:{}"
,
billingExpr
,
e
);
}
return
multipliers
;
}
/**
* 解析条件描述为用户可读文字
*/
private
String
parseConditionDesc
(
String
condition
)
{
if
(
condition
==
null
||
condition
.
isEmpty
())
{
return
""
;
}
String
result
=
condition
;
// 先处理 has(header(...), "xxx") 这种模式
result
=
result
.
replaceAll
(
"has\\s*\\(\\s*header\\s*\\(\\s*\"([^\"]+)\"\\s*\\)\\s*,\\s*\"([^\"]+)\"\\s*\\)"
,
"请求头 $1 包含 \"$2\""
);
// 替换逻辑运算符
result
=
result
.
replaceAll
(
"\\s+&&\\s+"
,
" 且 "
);
result
=
result
.
replaceAll
(
"\\s+\\|\\|\\s+"
,
" 或 "
);
// 时间条件 - 完整函数调用替换
result
=
result
.
replaceAll
(
"hour\\s*\\(\\s*\"([^\"]+)\"\\s*\\)"
,
"小时"
);
result
=
result
.
replaceAll
(
"minute\\s*\\(\\s*\"([^\"]+)\"\\s*\\)"
,
"分钟"
);
result
=
result
.
replaceAll
(
"weekday\\s*\\(\\s*\"([^\"]+)\"\\s*\\)"
,
"星期"
);
result
=
result
.
replaceAll
(
"month\\s*\\(\\s*\"([^\"]+)\"\\s*\\)"
,
"月份"
);
result
=
result
.
replaceAll
(
"day\\s*\\(\\s*\"([^\"]+)\"\\s*\\)"
,
"日期"
);
// 请求参数条件
result
=
result
.
replaceAll
(
"param\\s*\\(\\s*\"([^\"]+)\"\\s*\\)\\s*"
,
"请求参数 $1 "
);
result
=
result
.
replaceAll
(
"param\\s*\\(\\s*\"([^\"]+)\"\\s*\\)\\s*!=\\s*nil"
,
"请求参数 $1 存在"
);
// 请求头条件 - 处理剩余的 header()
result
=
result
.
replaceAll
(
"header\\s*\\(\\s*\"([^\"]+)\"\\s*\\)\\s*!=\\s*\"\""
,
"请求头 $1 存在"
);
result
=
result
.
replaceAll
(
"header\\s*\\(\\s*\"([^\"]+)\"\\s*\\)\\s*"
,
"请求头 $1 "
);
// 比较运算符
result
=
result
.
replace
(
">="
,
" ≥ "
);
result
=
result
.
replace
(
"<="
,
" ≤ "
);
result
=
result
.
replace
(
"=="
,
" = "
);
result
=
result
.
replace
(
"!="
,
" ≠ "
);
result
=
result
.
replace
(
">"
,
" > "
);
result
=
result
.
replace
(
"<"
,
" < "
);
// 清理多余空格
result
=
result
.
replaceAll
(
"\\s+"
,
" "
);
result
=
result
.
trim
();
return
result
;
}
}
computility-module-apihub/computility-module-apihub-biz/src/main/java/com/luhu/computility/module/apihub/controller/app/aimodel/vo/AppModelPricingVO.java
View file @
8e72bc4d
...
...
@@ -80,6 +80,9 @@ public class AppModelPricingVO {
@Schema
(
description
=
"分档列表"
)
private
List
<
TierVO
>
tiers
;
@Schema
(
description
=
"条件乘数列表"
)
private
List
<
ConditionMultiplierVO
>
conditionMultipliers
;
/**
* 分档信息 VO
*/
...
...
@@ -96,4 +99,16 @@ public class AppModelPricingVO {
private
String
conditionDesc
;
}
/**
* 条件乘数 VO
*/
@Data
@Schema
(
description
=
"条件乘数"
)
public
static
class
ConditionMultiplierVO
{
@Schema
(
description
=
"条件描述(用户可读的文字)"
)
private
String
description
;
@Schema
(
description
=
"倍率"
)
private
BigDecimal
multiplier
;
}
}
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