增加预扣积分
This commit is contained in:
Vendored
+1
-1
File diff suppressed because one or more lines are too long
Vendored
+1
-1
@@ -28,7 +28,7 @@
|
|||||||
}
|
}
|
||||||
})();
|
})();
|
||||||
</script>
|
</script>
|
||||||
<script type="module" crossorigin src="/assets/index-BLkGzXo7.js"></script>
|
<script type="module" crossorigin src="/assets/index-CtNUj_vl.js"></script>
|
||||||
<link rel="stylesheet" crossorigin href="/assets/index-D7ShJUt4.css">
|
<link rel="stylesheet" crossorigin href="/assets/index-D7ShJUt4.css">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
|||||||
@@ -178,7 +178,7 @@ const AdminSettings: React.FC = () => {
|
|||||||
'协议配置': configs.filter(c => c.key === 'user_agreement_privacy_url'),
|
'协议配置': configs.filter(c => c.key === 'user_agreement_privacy_url'),
|
||||||
'SEO 设置': configs.filter(c => c.key.startsWith('seo_')),
|
'SEO 设置': configs.filter(c => c.key.startsWith('seo_')),
|
||||||
'用户积分配置': configs.filter(c => c.key.startsWith('user_') && c.key.includes('credits')),
|
'用户积分配置': configs.filter(c => c.key.startsWith('user_') && c.key.includes('credits')),
|
||||||
'其他配置': configs.filter(c => c.key === 'operation_manual'),
|
'其他配置': configs.filter(c => ['operation_manual', 'optimize_hold_credits'].includes(c.key)),
|
||||||
};
|
};
|
||||||
|
|
||||||
const getFieldDescription = (config: SystemConfig): string => {
|
const getFieldDescription = (config: SystemConfig): string => {
|
||||||
@@ -194,6 +194,7 @@ const AdminSettings: React.FC = () => {
|
|||||||
user_login_credits: '用户每日登录赠送的积分数量',
|
user_login_credits: '用户每日登录赠送的积分数量',
|
||||||
user_login_credits_enabled: '是否启用每日登录赠送积分功能',
|
user_login_credits_enabled: '是否启用每日登录赠送积分功能',
|
||||||
operation_manual: '操作手册链接,前台用户菜单将展示该入口,点击跳转此链接',
|
operation_manual: '操作手册链接,前台用户菜单将展示该入口,点击跳转此链接',
|
||||||
|
optimize_hold_credits: 'AI创作时预扣积分数量,用于防止并发超卖。预扣后按实际消耗多退少补',
|
||||||
};
|
};
|
||||||
return descMap[config.key] || config.description || '';
|
return descMap[config.key] || config.description || '';
|
||||||
};
|
};
|
||||||
@@ -323,8 +324,8 @@ const AdminSettings: React.FC = () => {
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if (config.key === 'user_register_credits' || config.key === 'user_login_credits') {
|
if (config.key === 'user_register_credits' || config.key === 'user_login_credits' || config.key === 'optimize_hold_credits') {
|
||||||
return <Input type="number" min={0} placeholder={config.description} size="large" />;
|
return <Input type="number" min={1} placeholder={config.description} size="large" />;
|
||||||
}
|
}
|
||||||
return <Input placeholder={config.description} size="large" />;
|
return <Input placeholder={config.description} size="large" />;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -342,7 +342,7 @@ async def get_site_info(db: AsyncSession = Depends(get_db)):
|
|||||||
"""Public endpoint returning site name, logo, agreement and copyright info."""
|
"""Public endpoint returning site name, logo, agreement and copyright info."""
|
||||||
result = await db.execute(
|
result = await db.execute(
|
||||||
select(SystemConfig).where(SystemConfig.key.in_([
|
select(SystemConfig).where(SystemConfig.key.in_([
|
||||||
"site_name", "site_logo", "user_agreement_privacy_url", "site_copyright", "operation_manual", "login_bg_video"
|
"site_name", "site_logo", "user_agreement_privacy_url", "site_copyright", "operation_manual", "login_bg_video", "optimize_hold_credits"
|
||||||
]))
|
]))
|
||||||
)
|
)
|
||||||
configs = result.scalars().all()
|
configs = result.scalars().all()
|
||||||
@@ -366,6 +366,7 @@ async def get_site_info(db: AsyncSession = Depends(get_db)):
|
|||||||
"site_copyright": info.get("site_copyright", "© 2024 民众智创 版权所有"),
|
"site_copyright": info.get("site_copyright", "© 2024 民众智创 版权所有"),
|
||||||
"operation_manual": info.get("operation_manual", ""),
|
"operation_manual": info.get("operation_manual", ""),
|
||||||
"login_bg_video": to_full_url(info.get("login_bg_video")) if info.get("login_bg_video") else "",
|
"login_bg_video": to_full_url(info.get("login_bg_video")) if info.get("login_bg_video") else "",
|
||||||
|
"optimize_hold_credits": int(info.get("optimize_hold_credits") or 5),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -10,11 +10,11 @@ from fastapi.responses import RedirectResponse
|
|||||||
from sqlalchemy import select, func
|
from sqlalchemy import select, func
|
||||||
from sqlalchemy.ext.asyncio import AsyncSession
|
from sqlalchemy.ext.asyncio import AsyncSession
|
||||||
|
|
||||||
from app.config import settings
|
|
||||||
from app.dependencies import get_db, get_current_user
|
from app.dependencies import get_db, get_current_user
|
||||||
from app.models.user import User
|
from app.models.user import User
|
||||||
from app.models.project import Project
|
from app.models.project import Project
|
||||||
from app.models.generation_record import GenerationRecord
|
from app.models.generation_record import GenerationRecord
|
||||||
|
from app.models.system_config import SystemConfig
|
||||||
from app.schemas.generation import (
|
from app.schemas.generation import (
|
||||||
OptimizeParams,
|
OptimizeParams,
|
||||||
GenerateParams,
|
GenerateParams,
|
||||||
@@ -32,7 +32,7 @@ from app.services.generation.pipeline.db_lock_service import (
|
|||||||
DatabaseRowLockBusy,
|
DatabaseRowLockBusy,
|
||||||
execute_with_lock_timeout,
|
execute_with_lock_timeout,
|
||||||
)
|
)
|
||||||
from app.services.credits import deduct_credits, calc_text_credits
|
from app.services.credits import deduct_credits, add_credits, calc_text_credits
|
||||||
from app.services.llm import optimize_prompt
|
from app.services.llm import optimize_prompt
|
||||||
from app.services.video_url import generate_temp_url, validate_and_get_record_id, get_video_stream_url
|
from app.services.video_url import generate_temp_url, validate_and_get_record_id, get_video_stream_url
|
||||||
from app.services.resource_accounting_service import (
|
from app.services.resource_accounting_service import (
|
||||||
@@ -271,9 +271,17 @@ async def optimize(
|
|||||||
db: AsyncSession = Depends(get_db),
|
db: AsyncSession = Depends(get_db),
|
||||||
):
|
):
|
||||||
record = None
|
record = None
|
||||||
# 积分不足直接返回
|
# 预扣积分(SELECT FOR UPDATE 锁行 + 检查 + 扣费,防止并发超卖)
|
||||||
if (current_user.credits or 0) < 5:
|
hold_credits = 5
|
||||||
raise HTTPException(status_code=402, detail="积分不足,请充值")
|
_hold_cfg = await db.execute(select(SystemConfig).where(SystemConfig.key == "optimize_hold_credits").limit(1))
|
||||||
|
_hold_row = _hold_cfg.scalar_one_or_none()
|
||||||
|
if _hold_row and _hold_row.value:
|
||||||
|
try:
|
||||||
|
hold_credits = int(_hold_row.value)
|
||||||
|
except (ValueError, TypeError):
|
||||||
|
hold_credits = 5
|
||||||
|
await deduct_credits(db, current_user.id, hold_credits, "AI创作预扣积分", biz_key=f"optimize_hold:{req.idempotency_key or 'nokey'}")
|
||||||
|
await db.commit()
|
||||||
# Validate parameters based on generation type
|
# Validate parameters based on generation type
|
||||||
if req.gen_type == GenerationType.video:
|
if req.gen_type == GenerationType.video:
|
||||||
if req.duration not in DURATIONS:
|
if req.duration not in DURATIONS:
|
||||||
@@ -377,6 +385,13 @@ async def optimize(
|
|||||||
db, token_usage["input_tokens"], token_usage["output_tokens"],
|
db, token_usage["input_tokens"], token_usage["output_tokens"],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# 积分结算:预扣金额按实际消耗多退少补
|
||||||
|
if text_credits < hold_credits:
|
||||||
|
await add_credits(db, current_user.id, round(hold_credits - text_credits, 2), f"提示词优化积分退还- {project.name}", biz_key=f"optimize_refund:{req.idempotency_key or 'nokey'}")
|
||||||
|
elif text_credits > hold_credits:
|
||||||
|
await deduct_credits(db, current_user.id, round(text_credits - hold_credits, 2), f"提示词优化补扣积分 - {project.name}", biz_key=f"optimize_topup:{req.idempotency_key or 'nokey'}")
|
||||||
|
await db.commit()
|
||||||
|
|
||||||
failed_record_id = record.id
|
failed_record_id = record.id
|
||||||
failed_user_id = current_user.id
|
failed_user_id = current_user.id
|
||||||
try:
|
try:
|
||||||
|
|||||||
@@ -185,6 +185,7 @@ async def _seed_data():
|
|||||||
("user_login_credits_enabled", "false", "启用每日登录赠送积分"),
|
("user_login_credits_enabled", "false", "启用每日登录赠送积分"),
|
||||||
# Operation manual
|
# Operation manual
|
||||||
("operation_manual", "", "操作手册链接"),
|
("operation_manual", "", "操作手册链接"),
|
||||||
|
("optimize_hold_credits", "5", "AI创作预扣积分数量(防止并发超卖)"),
|
||||||
]
|
]
|
||||||
for key, value, desc in configs:
|
for key, value, desc in configs:
|
||||||
existing = await db.execute(
|
existing = await db.execute(
|
||||||
|
|||||||
Reference in New Issue
Block a user