"""C-04 AI 工具:图片放大(upscale)最小闭环。 设计: - Provider 抽象:BaseProvider + PillowProvider(本地 LANCZOS 2x/4x, 零 key、零外部依赖,mock 链路即生产链路)+ HTTPProvider(预留第三方网关, baseURL/key 全走环境变量,绝不落库、不进响应)。 - 钱包打通:调用前按 AITOOL_UPSCALE_COST 扣积分(事务 + 行锁),处理失败自动回滚。 - 产物存储:MEDIA_ROOT/aitool/upscale/,返回可下载 URL。 - 与钱包打通仅做方案不落地计费:真实扣费走积分(存量 PointTransaction), 不引入支付网关;y币/现金计费留待商业化评审(见 PROGRESS_C-04)。 """ from django.conf import settings from django.db import models class AIToolRecord(models.Model): TOOL_CHOICES = [ ('upscale', '图片放大'), ('matting', '抠图(预留)'), ('id-photo', '证件照(预留)'), ('text2img', '文生图(预留)'), ] STATUS_CHOICES = [ ('success', '成功'), ('failed', '失败'), ('refunded', '已回滚'), ] user = models.ForeignKey( settings.AUTH_USER_MODEL, on_delete=models.SET_NULL, null=True, blank=True, related_name='aitool_records', verbose_name='用户', ) tool = models.CharField(max_length=20, choices=TOOL_CHOICES, default='upscale', verbose_name='工具') status = models.CharField(max_length=10, choices=STATUS_CHOICES, default='success', verbose_name='状态') cost = models.IntegerField(default=0, verbose_name='扣减积分') scale = models.IntegerField(default=2, verbose_name='放大倍数') input_size = models.BigIntegerField(default=0, verbose_name='输入字节') output_size = models.BigIntegerField(default=0, verbose_name='输出字节') file_path = models.CharField(max_length=500, blank=True, default='', verbose_name='产物路径') created_at = models.DateTimeField(auto_now_add=True, verbose_name='创建时间') class Meta: ordering = ['-created_at'] verbose_name = 'AI工具调用记录' verbose_name_plural = 'AI工具调用记录' indexes = [ models.Index(fields=['user', '-created_at']), models.Index(fields=['tool', '-created_at']), ] def __str__(self): return f'{self.tool} x{self.scale} ({self.status})'