| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218 |
- <?php
- namespace App\Libs;
- use App\Models\MpUserPointsDetail;
- use Illuminate\Support\Facades\DB;
- /**
- * 积分明细展示辅助类
- *
- * 统一定义积分流水(列表/导出)对外展示的模型名与分辨率:
- * - 模型名:隐藏供应商字样(百度/快快AI/智帧/字节跳动等),如百度Seedance2.0 → Seedance2.0
- * 模型展示名优先取配置表(mp_video_models / mp_image_models / mp_text_models)的 name,
- * 配置缺失时回退内置映射,仍未命中则仅剥离供应商前缀原样返回。
- * - 分辨率:视频显示 480p/720p/1080p/4k 与 超分720p/超分1080p;图片显示 实际宽*高(如 1600*2848);
- * 其他类型(AI对话/积分发放等)返回空串。
- */
- class PointsDisplay
- {
- /**
- * 需要从展示名中隐藏的供应商字样(仅处理名称开头的前缀)
- */
- const VENDOR_WORDS = [
- '百度',
- '快快AI',
- '快快',
- '智帧平台',
- '智帧',
- '字节跳动',
- ];
- /**
- * 英文供应商前缀(模型ID开头)
- */
- const VENDOR_PREFIXES = [
- 'baidu-',
- 'kuaikuai-',
- ];
- /**
- * 配置表缺失时的内置兜底映射(模型ID => 展示名)
- */
- const MODEL_NAME_FALLBACK = [
- // 视频(Seedance 系列)
- 'doubao-seedance-1-5-pro-251215' => 'Seedance1.5pro',
- 'doubao-seedance-1-0-pro-250528' => 'Seedance1.0pro',
- 'doubao-seedance-1-0-pro-fast-251015' => 'Seedance1.0profast',
- 'doubao-seedance-2-0-260128' => 'Seedance2.0',
- 'doubao-seedance-2-0-fast-260128' => 'Seedance2.0fast',
- 'doubao-seedance-2.0' => 'Seedance2.0',
- 'baidu-doubao-seedance-2-0-260128' => 'Seedance2.0',
- 'baidu-doubao-seedance-2-0-fast-260128' => 'Seedance2.0fast',
- 'baidu-doubao-seedance-2-0-mini-260615' => 'Seedance2.0mini',
- 'baidu-doubao-seedance-2-5-260628' => 'Seedance2.5',
- 'baidu-dreamina-seedance-2-0-260128' => 'Seedance2.0(海外)',
- 'baidu-dreamina-seedance-2-0-fast-260128' => 'Seedance2.0fast(海外)',
- 'baidu-dreamina-seedance-2-0-mini-260615' => 'Seedance2.0mini(海外)',
- 'baidu-dreamina-seedance-2-5-260628' => 'Seedance2.5(海外)',
- 'zhizhen-20' => 'Seedance2.0',
- 'zhizhen-20-fast' => 'Seedance2.0fast',
- 'zhizhen-20-mini' => 'Seedance2.0mini',
- 'seed-2' => 'Seedance2.0',
- 'seed-2-fast' => 'Seedance2.0fast',
- 'seed-2-mini' => 'Seedance2.0mini',
- 'seed-2.5' => 'Seedance2.5',
- // 文本
- 'baidu-glm-5.2' => 'GLM-5.2',
- 'baidu-glm-5.3' => 'GLM-5.3',
- ];
- /**
- * 视频分辨率取值 => 展示文案
- */
- const VIDEO_RESOLUTION_LABELS = [
- '480p' => '480p',
- '720p' => '720p',
- '1080p' => '1080p',
- '4k' => '4k',
- '2160p' => '4k',
- '4096x2160' => '4k',
- 'sr_720p' => '超分720p',
- 'sr720p' => '超分720p',
- '超分720p' => '超分720p',
- 'sr_1080p' => '超分1080p',
- 'sr1080p' => '超分1080p',
- '超分1080p' => '超分1080p',
- ];
- /**
- * 配置表读取的模型展示名缓存(单次请求内只查一次)
- *
- * @var array|null
- */
- private static $modelNameMap = null;
- /**
- * 获取模型对外展示名(隐藏百度/快快等供应商字样)
- *
- * @param string $model 模型ID(charge_info.model)
- * @return string
- */
- public static function modelName(string $model = ''): string
- {
- $model = trim($model);
- if ($model === '' || $model === 'unknown') {
- return '';
- }
- $map = self::modelNameMap();
- $name = $map[$model] ?? self::MODEL_NAME_FALLBACK[$model] ?? '';
- if ($name === '') {
- $name = $model;
- }
- return self::stripVendor($name);
- }
- /**
- * 获取明细的分辨率展示文案
- *
- * - 视频:480p/720p/1080p/4k、超分720p、超分1080p(来自 charge_info.video_resolution)
- * - 图片:实际宽*高,如 1600*2848(来自 charge_info.width / height)
- * - 其他类型或无数据:空串
- *
- * @param string $type 明细类型(video/image/chat/system/company)
- * @param array $chargeInfo 计费信息
- * @return string
- */
- public static function resolution(string $type, array $chargeInfo = []): string
- {
- if ($type === MpUserPointsDetail::TYPE_VIDEO) {
- $resolution = strtolower(trim((string)getProp($chargeInfo, 'video_resolution', '')));
- if ($resolution === '') {
- return '';
- }
- return self::VIDEO_RESOLUTION_LABELS[$resolution] ?? $resolution;
- }
- if ($type === MpUserPointsDetail::TYPE_IMAGE) {
- $width = (int)getProp($chargeInfo, 'width', 0);
- $height = (int)getProp($chargeInfo, 'height', 0);
- if ($width <= 0 || $height <= 0) {
- return '';
- }
- return $width . '*' . $height;
- }
- return '';
- }
- /**
- * 仅保留名称主体:剥离供应商字样前缀(百度Seedance2.0 → Seedance2.0,baidu-xxx → xxx)
- *
- * @param string $name
- * @return string
- */
- private static function stripVendor(string $name): string
- {
- $name = trim($name);
- // 英文前缀(模型ID形态)
- foreach (self::VENDOR_PREFIXES as $prefix) {
- if (stripos($name, $prefix) === 0) {
- $name = trim(substr($name, strlen($prefix)));
- }
- }
- // 中文前缀(配置表 name 形态),可能连续出现(如“百度智帧xxx”)
- $changed = true;
- while ($changed) {
- $changed = false;
- foreach (self::VENDOR_WORDS as $word) {
- if (mb_strpos($name, $word) === 0) {
- $name = trim(mb_substr($name, mb_strlen($word)));
- $changed = true;
- break;
- }
- }
- }
- return $name;
- }
- /**
- * 模型ID => 配置表展示名(读取失败或未命中时返回空数组,由调用方走兜底映射)
- *
- * @return array
- */
- private static function modelNameMap(): array
- {
- if (self::$modelNameMap !== null) {
- return self::$modelNameMap;
- }
- $map = [];
- foreach (['mp_video_models', 'mp_image_models', 'mp_text_models'] as $table) {
- try {
- $rows = DB::table($table)->select('model', 'name')->get();
- } catch (\Throwable $e) {
- continue;
- }
- foreach ($rows as $row) {
- $model = trim((string)getProp($row, 'model', ''));
- $name = trim((string)getProp($row, 'name', ''));
- if ($model !== '' && $name !== '') {
- $map[$model] = $name;
- }
- }
- }
- self::$modelNameMap = $map;
- return self::$modelNameMap;
- }
- }
|