diff --git a/python-api/alembic/versions/95eb1a1c0af9_add_duration_to_point_transaction.py b/python-api/alembic/versions/95eb1a1c0af9_add_duration_to_point_transaction.py new file mode 100644 index 0000000..377036f --- /dev/null +++ b/python-api/alembic/versions/95eb1a1c0af9_add_duration_to_point_transaction.py @@ -0,0 +1,27 @@ +""" +积分流水表添加 duration 字段 + +用于记录按秒计费业务的时长(TTS、数字人视频等)。 +""" + +from typing import Sequence, Union + +import sqlalchemy as sa +from alembic import op + +# revision identifiers, used by Alembic. +revision: str = "95eb1a1c0af9" +down_revision: Union[str, None] = "ccf61ff6f4bb" +branch_labels: Union[str, Sequence[str], None] = None +depends_on: Union[str, Sequence[str], None] = None + + +def upgrade() -> None: + op.add_column( + "mjk_point_transactions", + sa.Column("duration", sa.Float(), nullable=True), + ) + + +def downgrade() -> None: + op.drop_column("mjk_point_transactions", "duration") diff --git a/python-api/app/api/v1/points.py b/python-api/app/api/v1/points.py index c22445a..8569e6f 100644 --- a/python-api/app/api/v1/points.py +++ b/python-api/app/api/v1/points.py @@ -444,7 +444,7 @@ async def consume_points( points=request.points, source_type=request.source_type, source_id=request.source_id, - description=request.description, + description=f"【{request.description or request.source_type}】", ) await db.commit() diff --git a/python-api/app/api/v1/script.py b/python-api/app/api/v1/script.py index 30c10e5..4212392 100644 --- a/python-api/app/api/v1/script.py +++ b/python-api/app/api/v1/script.py @@ -82,7 +82,7 @@ async def polish_content( points=points, source_type="polish", source_id=f"polish_{current_user.id}_{asyncio.get_event_loop().time()}", - description=f"润色 {request.polish_type}", + description="【文案润色】", ) await db.commit() @@ -211,7 +211,7 @@ async def generate_title( points=points, source_type="title", source_id=f"title_{current_user.id}_{asyncio.get_event_loop().time()}", - description=f"生成{request.title_type}标题", + description="【标题生成】", ) await db.commit() diff --git a/python-api/app/api/v1/voice.py b/python-api/app/api/v1/voice.py index 34b3113..bacef51 100644 --- a/python-api/app/api/v1/voice.py +++ b/python-api/app/api/v1/voice.py @@ -231,7 +231,8 @@ async def synthesize_speech( points=points, source_type="tts", source_id=f"tts_{current_user.id}_{asyncio.get_event_loop().time()}", - description=f"TTS 配音 {seconds:.1f} 秒", + description="【配音合成】", + duration=seconds, ) await db.commit() except Exception as e: @@ -317,7 +318,8 @@ async def synthesize_batch( points=points, source_type="tts", source_id=f"tts_batch_{current_user.id}_{asyncio.get_event_loop().time()}", - description=f"批量 TTS 配音 {total_seconds:.1f} 秒", + description="【配音合成】", + duration=total_seconds, ) await db.commit() except Exception as e: @@ -448,7 +450,7 @@ async def submit_clone_task( points=points, source_type="voice_clone", source_id=result.get("voice_id", "unknown"), - description="声音克隆", + description="【声音克隆】", ) await db.commit() except Exception as e: diff --git a/python-api/app/models/point_transaction.py b/python-api/app/models/point_transaction.py index f920a4b..4d0af5b 100644 --- a/python-api/app/models/point_transaction.py +++ b/python-api/app/models/point_transaction.py @@ -73,6 +73,11 @@ class PointTransaction(BaseModelBigInt): comment="关联的积分批次 ID(消费时记录从哪个批次扣)", ) + duration: Mapped[float | None] = mapped_column( + nullable=True, + comment="时长(秒),按秒计费业务记录", + ) + description: Mapped[str | None] = mapped_column( Text, nullable=True, diff --git a/python-api/app/scheduler/handlers/script_handler.py b/python-api/app/scheduler/handlers/script_handler.py index 3324973..be9fcce 100644 --- a/python-api/app/scheduler/handlers/script_handler.py +++ b/python-api/app/scheduler/handlers/script_handler.py @@ -145,7 +145,7 @@ class ScriptHandler(AsyncHandler): points=points, source_type="script", source_id=task.task_id, - description=f"脚本生成 {category}/{subcategory}", + description="【脚本生成】", ) await db.commit() except Exception as e: diff --git a/python-api/app/scheduler/handlers/video_handler.py b/python-api/app/scheduler/handlers/video_handler.py index 019c64e..6cfdb39 100644 --- a/python-api/app/scheduler/handlers/video_handler.py +++ b/python-api/app/scheduler/handlers/video_handler.py @@ -78,7 +78,8 @@ class VideoHandler(AsyncHandler): points=points, source_type="video", source_id=task.task_id, - description=f"对口型视频 {duration:.1f} 秒", + description="【数字人视频】", + duration=duration, ) await db.commit() except Exception as e: @@ -135,7 +136,8 @@ class VideoHandler(AsyncHandler): points=points, source_type="video", source_id=task.task_id, - description=f"对口型视频 {duration:.1f} 秒", + description="【数字人视频】", + duration=duration, ) await db.commit() except Exception as e: diff --git a/python-api/app/schemas/point.py b/python-api/app/schemas/point.py index 8ff2a33..99a669e 100644 --- a/python-api/app/schemas/point.py +++ b/python-api/app/schemas/point.py @@ -32,6 +32,7 @@ class PointTransactionItem(BaseModel): balance_after: int source_type: str | None = Field(None, description="消费来源类型") source_id: str | None = Field(None, description="消费来源业务 ID") + duration: float | None = Field(None, description="时长(秒),按秒计费业务记录") description: str | None = None created_at: datetime diff --git a/python-api/app/services/point_service.py b/python-api/app/services/point_service.py index bb507e1..b17f4a5 100644 --- a/python-api/app/services/point_service.py +++ b/python-api/app/services/point_service.py @@ -272,6 +272,7 @@ async def consume( source_type: str, source_id: str, description: str = "", + duration: float | None = None, ) -> PointTransaction: """ 直接扣费(后置计费)。 @@ -343,6 +344,7 @@ async def consume( source_type=source_type, source_id=source_id, batch_id=batches[0].id if batches else None, + duration=duration, description=description or f"消费 {source_type} {points} 积分", ) db.add(tx) diff --git a/tauri-app/src/api/modules/points.ts b/tauri-app/src/api/modules/points.ts index 266abe9..42a98a8 100644 --- a/tauri-app/src/api/modules/points.ts +++ b/tauri-app/src/api/modules/points.ts @@ -40,6 +40,7 @@ export interface PointTransaction { balanceAfter: number; sourceType: string | null; sourceId: string | null; + duration: number | null; description: string | null; createdAt: string; } diff --git a/tauri-app/src/pages/Profile/UsageDetail.tsx b/tauri-app/src/pages/Profile/UsageDetail.tsx index d4dd337..fe13730 100644 --- a/tauri-app/src/pages/Profile/UsageDetail.tsx +++ b/tauri-app/src/pages/Profile/UsageDetail.tsx @@ -100,7 +100,7 @@ export default function UsageDetail() { 变动积分 变动前余额 变动后余额 - 来源 + 时长 说明 时间 @@ -149,7 +149,7 @@ export default function UsageDetail() { {tx.balanceBefore} {tx.balanceAfter} - {tx.sourceType || '-'} + {tx.duration != null ? `${tx.duration.toFixed(1)}s` : '-'} {tx.description || '-'} {formatTime(tx.createdAt)}