image-analysis.service.ts 109 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839
  1. import { Injectable } from '@angular/core';
  2. import { FmodeObject, FmodeParse } from 'fmode-ng/parse';
  3. const Parse = FmodeParse.with('nova');
  4. /**
  5. * 图片分析结果接口
  6. */
  7. export interface ImageAnalysisResult {
  8. // 基础信息
  9. fileName: string;
  10. fileSize: number;
  11. dimensions: {
  12. width: number;
  13. height: number;
  14. };
  15. // 质量评估
  16. quality: {
  17. score: number; // 0-100分
  18. level: 'low' | 'medium' | 'high' | 'ultra'; // 低、中、高、超高
  19. sharpness: number; // 清晰度 0-100
  20. brightness: number; // 亮度 0-100
  21. contrast: number; // 对比度 0-100
  22. detailLevel: 'minimal' | 'basic' | 'detailed' | 'ultra_detailed'; // 🔥 内容精细程度
  23. pixelDensity: 'low' | 'medium' | 'high' | 'ultra_high'; // 🔥 像素密度等级
  24. textureQuality: number; // 🔥 纹理质量 0-100
  25. colorDepth: number; // 🔥 色彩深度 0-100
  26. };
  27. // 内容分析
  28. content: {
  29. category: 'white_model' | 'soft_decor' | 'rendering' | 'post_process' | 'unknown';
  30. confidence: number; // 置信度 0-100
  31. spaceType?: string; // 🔥 空间类型(客厅/卧室/餐厅/厨房/卫生间/书房)
  32. description: string; // 内容描述
  33. tags: string[]; // 标签
  34. isArchitectural: boolean; // 是否为建筑相关
  35. hasInterior: boolean; // 是否包含室内场景
  36. hasFurniture: boolean; // 是否包含家具
  37. hasLighting: boolean; // 是否有灯光效果
  38. hasColor?: boolean; // 🔥 是否有色彩(非纯白、非灰度)
  39. hasTexture?: boolean; // 🔥 是否有材质纹理
  40. };
  41. // 技术参数
  42. technical: {
  43. format: string; // 文件格式
  44. colorSpace: string; // 色彩空间
  45. dpi: number; // 分辨率
  46. aspectRatio: string; // 宽高比
  47. megapixels: number; // 像素数(百万)
  48. };
  49. // 建议分类
  50. suggestedStage: 'white_model' | 'soft_decor' | 'rendering' | 'post_process';
  51. suggestedReason: string; // 分类原因
  52. // 设计分析维度(新增)
  53. design?: {
  54. style: string; // 风格:现代简约、欧式、中式等
  55. atmosphere: string; // 氛围营造方式
  56. material: string; // 材质分析
  57. texture: string; // 纹理特征
  58. quality: string; // 质感描述
  59. form: string; // 形体特征
  60. structure: string; // 空间结构
  61. colorComposition: string; // 色彩组成
  62. };
  63. // 色彩解析报告(新增)
  64. colorReport?: {
  65. brightness: string; // 明度:低长调/高长调分析
  66. hue: string; // 色相:色彩种类
  67. saturation: string; // 饱和度:低/中/高
  68. openness: string; // 色彩开放度:根据色相种类划分
  69. extractedColors: string[]; // 提取的基础颜色
  70. organizedColors: Array<{ color: string; role: string; percentage: number }>; // 组织颜色(主次)
  71. expandedColors: string[]; // 拓展颜色(配色)
  72. harmonizedColors: string[]; // 调和颜色(配色)
  73. };
  74. // 风格元素分析(新增)
  75. styleElements?: {
  76. styleKeywords: string[]; // 风格关键词(如:新古典主义、现代轻奢、艺术装饰等)
  77. };
  78. // 色彩搭配分析(新增)
  79. colorScheme?: {
  80. primaryColors: string[]; // 主色调
  81. secondaryColors: string[]; // 辅助色
  82. accentColors: string[]; // 点缀色
  83. };
  84. // 材质分析(新增)
  85. materialAnalysis?: {
  86. materials: string[]; // 识别的材质(大理石、玻璃、布、金属等)
  87. };
  88. // 布局特征分析(新增)
  89. layoutFeatures?: {
  90. features: string[]; // 布局特征(对称式布局、多区域采光、开放式空间等)
  91. };
  92. // 空间氛围分析(新增)
  93. atmosphereAnalysis?: {
  94. atmosphere: string; // 空间氛围描述
  95. };
  96. // 🔥 渲染专业分析(新增 - 基于行业标准)
  97. renderingAnalysis?: {
  98. // 一、像素大小与清晰度维度
  99. pixelClarityDimension: {
  100. pixelLevel: 'preview' | 'standard' | 'high' | 'ultra' | 'print'; // 像素级别
  101. estimatedSize: {
  102. width: number; // 估算宽度
  103. height: number; // 估算高度
  104. description: string; // 尺寸描述
  105. };
  106. detailRetention: {
  107. structureClarity: string; // 基础结构清晰度(沙发轮廓、柜体线条)
  108. textureClarity: string; // 精细纹理清晰度(藤编、木纹、金属拉丝)
  109. edgeSharpness: string; // 边缘锐度
  110. blurIssue: boolean; // 是否存在模糊
  111. blurDescription?: string; // 模糊描述
  112. };
  113. scaleLoss: {
  114. pixelBlockEffect: boolean; // 是否有像素块感
  115. highFrequencyLoss: string; // 高频细节损耗评价
  116. enlargeSuitability: string; // 放大适用性
  117. };
  118. optimizationSuggestions: string[]; // 像素优化建议
  119. };
  120. // 二、色彩精细程度维度
  121. colorRefinementDimension: {
  122. colorStyle: string; // 色彩风格(自然低饱和系、高饱和系等)
  123. refinementLevel: 'basic' | 'intermediate' | 'advanced' | 'professional'; // 精细度等级
  124. colorGamutCoverage: {
  125. dominantColors: string[]; // 主导色彩
  126. colorSpace: 'sRGB' | 'Adobe RGB' | 'ProPhoto RGB'; // 色彩空间
  127. saturationRange: string; // 饱和度范围
  128. colorDescription: string; // 色域描述
  129. };
  130. colorAccuracy: {
  131. materialColors: Array<{
  132. material: string; // 材质名称(木质、沙发面料等)
  133. colorDescription: string; // 色彩描述
  134. deltaE: number; // 色差值ΔE(参考CQS标准)
  135. }>;
  136. differentiationAbility: string; // 材质色彩区分能力
  137. gradientTransition: {
  138. smoothness: string; // 同色系层次过渡(如墙面阴影灰度变化)
  139. gradeLevels: number; // 过渡级数
  140. };
  141. };
  142. colorConsistency: {
  143. crossImageConsistency: boolean; // 跨图片色彩一致性
  144. metallicGlassReflection: string; // 金属、玻璃反光色彩评价
  145. environmentColorBlend: boolean; // 环境色融合
  146. environmentColorDescription?: string; // 环境色融合描述
  147. };
  148. optimizationSuggestions: string[]; // 色彩优化建议
  149. };
  150. // 三、灯光氛围维度
  151. lightingAtmosphereDimension: {
  152. lightingStyle: string; // 灯光风格(柔和自然系、戏剧化、工业风等)
  153. atmosphereLevel: 'basic' | 'good' | 'excellent' | 'master'; // 氛围营造等级
  154. lightSources: {
  155. primary: Array<{
  156. type: string; // 光源类型(窗外漫射自然光等)
  157. position: string; // 位置
  158. characteristics: string; // 特征
  159. }>;
  160. auxiliary: Array<{
  161. type: string; // 辅助光源类型(吊顶灯带、壁灯等)
  162. coverage: string; // 覆盖范围
  163. effectiveness: string; // 效果评价
  164. }>;
  165. };
  166. lightShadowHierarchy: {
  167. contrastRatio: string; // 明暗对比度(如1:4)
  168. shadowTransition: string; // 阴影过渡自然度
  169. keyIssues: string[]; // 核心问题(如光源指向性弱)
  170. highlightQuality: {
  171. definition: string; // 高光区域清晰度
  172. spotShape: string; // 光斑形态
  173. hardLightAccent: boolean; // 是否有硬光点缀
  174. hardLightDescription?: string; // 硬光描述
  175. };
  176. spatialDepth: string; // 空间立体感
  177. };
  178. atmosphereAdaptation: {
  179. colorTemperature: string; // 色温(如4000K暖白光)
  180. spacePositioning: string; // 空间定位适配(简约舒适等)
  181. decorativeLightOutput: {
  182. wallLampHalo: string; // 壁灯光晕范围
  183. floorLampEffect: string; // 落地灯效果
  184. localSoftLightZone: boolean; // 是否形成局部柔和光区
  185. };
  186. };
  187. optimizationSuggestions: string[]; // 灯光优化建议
  188. };
  189. // 综合评分和建议
  190. overallScore: number; // 渲染综合评分 0-100
  191. renderingQualityLevel: 'preview' | 'standard' | 'professional' | 'master'; // 渲染质量等级
  192. strengths: string[]; // 优点
  193. improvements: string[]; // 改进建议
  194. optimizationPrompts?: {
  195. pixelOptimization?: string; // 像素优化提示词
  196. colorOptimization?: string; // 色彩优化提示词
  197. lightingOptimization?: string; // 灯光优化提示词
  198. };
  199. };
  200. // 🔥 后期处理专业分析(新增 - 基于行业标准,与渲染阶段对比)
  201. postProcessAnalysis?: {
  202. // 一、像素与清晰度维度(对比渲染小图)
  203. pixelClarityComparison: {
  204. beforeRendering: {
  205. pixelRange: string; // 前期像素范围(如800-1200像素宽)
  206. clarityLevel: string; // 清晰度级别(预览级)
  207. textureIssues: string[]; // 纹理问题(如藤编模糊、木纹不清)
  208. edgeIssues: string[]; // 边缘问题(如锐度不足、像素块感)
  209. };
  210. afterPostProcess: {
  211. pixelRange: string; // 后期像素范围(如2000+像素宽)
  212. clarityLevel: string; // 清晰度级别(成品级)
  213. textureQuality: {
  214. details: string[]; // 材质细节(藤编肌理、木纹结疤、金属拉丝等)
  215. clarity: string; // 清晰度描述
  216. };
  217. edgeQuality: string; // 边缘质量(锐利、无像素损耗)
  218. printSuitability: boolean; // 是否满足印刷/展示需求
  219. };
  220. qualityLeap: string; // 质变描述(从预览级到成品级)
  221. };
  222. // 二、色彩精细度维度(对比渲染小图)
  223. colorRefinementComparison: {
  224. beforeRendering: {
  225. gradientLevels: number; // 同色系过渡级数(如3级)
  226. deltaE: number; // 材质色差值ΔE(如3-5)
  227. colorLayers: string; // 色彩层次描述(单一)
  228. };
  229. afterPostProcess: {
  230. gradientLevels: number; // 同色系过渡级数(如5-8级)
  231. deltaE: number; // 材质色差值ΔE(如≤2)
  232. gradientDetails: string[]; // 渐变细节(如墙面亮白到阴影灰)
  233. materialColorAccuracy: Array<{
  234. material: string; // 材质名称
  235. improvement: string; // 改进描述
  236. }>;
  237. environmentColorBlend: {
  238. enabled: boolean; // 是否融合环境色
  239. examples: string[]; // 融合示例(如金属腿反射木色光晕)
  240. };
  241. microColorDetails: string[]; // 微色彩细节(藤编浅黄、陶罐土棕等)
  242. };
  243. qualityLeap: string; // 质变描述(从中阶写实到高还原质感)
  244. };
  245. // 三、灯光氛围维度(对比渲染小图)
  246. lightingAtmosphereComparison: {
  247. beforeRendering: {
  248. issues: string[]; // 问题(光源指向性弱、高光光斑模糊、空间立体感不足)
  249. atmosphereLevel: string; // 氛围等级
  250. };
  251. afterPostProcess: {
  252. lightSourceHierarchy: {
  253. primaryLight: {
  254. type: string; // 主光源类型(窗外自然光)
  255. diffuseLight: string; // 漫射光描述
  256. directLight: {
  257. percentage: number; // 直射光比例(如15%)
  258. spotAreas: string[]; // 光斑区域(沙发扶手、桌面等)
  259. };
  260. };
  261. auxiliaryLight: {
  262. sources: Array<{
  263. type: string; // 辅助光源类型(吊顶灯带、壁灯)
  264. haloExpansion: string; // 光晕扩大范围(如壁灯覆盖墙面30cm)
  265. }>;
  266. };
  267. };
  268. shadowQualityUpgrade: {
  269. softTransition: boolean; // 保留柔和过渡
  270. microHardEdge: {
  271. enabled: boolean; // 是否新增微硬边阴影
  272. areas: string[]; // 微硬边区域(柜体底部、物品边缘)
  273. };
  274. spatialDepthEnhancement: string; // 空间纵深感强化
  275. };
  276. atmosphereDetails: {
  277. environmentReflection: {
  278. enabled: boolean; // 是否新增环境光反射
  279. examples: string[]; // 反射示例(地面反射家具轮廓、墙面反射灯光暖调)
  280. };
  281. naturalness: string; // 自然度描述
  282. };
  283. };
  284. qualityLeap: string; // 质变描述(从柔和但平到层次化氛围)
  285. };
  286. // 四、后期新增细节维度
  287. postProcessDetailsAddition: {
  288. beforeRendering: {
  289. detailLevel: string; // 细节级别(基础结构)
  290. itemClarity: string; // 物品清晰度(如茶几物品模糊)
  291. };
  292. afterPostProcess: {
  293. lifeDetails: Array<{
  294. item: string; // 物品名称(玻璃杯、书籍、陶罐、植物等)
  295. description: string; // 细节描述(封面纹理、枝叶细节等)
  296. }>;
  297. livingAtmosphere: string; // 真实居住感描述
  298. detailEnhancement: string; // 细节增强总结
  299. };
  300. qualityLeap: string; // 质变描述(从基础结构到生活感填充)
  301. };
  302. // 综合评分和建议
  303. overallScore: number; // 后期处理综合评分 0-100
  304. postProcessQualityLevel: 'good' | 'excellent' | 'master' | 'exceptional'; // 后期处理质量等级
  305. strengths: string[]; // 优点
  306. comparisonSummary: string; // 与渲染阶段对比总结
  307. };
  308. // 🔥 软装专业分析(新增 - 基于行业标准)
  309. softDecorAnalysis?: {
  310. // 一、材质维度
  311. materialDimension: {
  312. materialTypes: Array<{
  313. name: string; // 材质名称(水泥、实木、藤编、皮革、大理石等)
  314. proportion: number; // 占比百分比
  315. area: string; // 使用区域
  316. }>;
  317. materialBalance: string; // 材质占比均衡性评价
  318. textureContrast: {
  319. hardMaterials: string[]; // 硬材质列表
  320. softMaterials: string[]; // 软材质列表
  321. contrastEffect: string; // 冷暖/刚柔对比效果
  322. };
  323. textureDetails: {
  324. clarity: string; // 肌理清晰度评价
  325. homogenization: boolean; // 是否存在材质同质化问题
  326. description: string; // 肌理细节描述
  327. };
  328. materialEcho: string; // 不同区域材质呼应关系
  329. };
  330. // 二、灯光维度
  331. lightingDimension: {
  332. lightSources: {
  333. natural: string[]; // 自然光源(窗户位置)
  334. artificial: string[]; // 人工光源(吊灯、壁灯、筒灯等)
  335. distribution: string; // 光源分布评价
  336. hierarchy: string; // 主光源、辅助光层次评价
  337. };
  338. colorTemperature: {
  339. temperature: string; // 色温类型(暖白光、冷白光等)
  340. materialMatch: string; // 与软装材质的匹配度
  341. conflict: boolean; // 是否存在色温冲突
  342. conflictDescription?: string; // 冲突描述
  343. };
  344. lightShadow: {
  345. focusPoints: string[]; // 灯光突出的软装重点
  346. contrastNaturalness: string; // 明暗对比自然度(暗部有细节、亮部不曝)
  347. shadowQuality: string; // 阴影质量评价
  348. };
  349. atmosphereMatch: string; // 灯光氛围与空间功能契合度
  350. };
  351. // 三、颜色维度
  352. colorDimension: {
  353. colorHierarchy: {
  354. primary: Array<{ color: string; proportion: number }>; // 主色调及占比
  355. secondary: Array<{ color: string; proportion: number }>; // 辅助色及占比
  356. accent: Array<{ color: string; proportion: number }>; // 点缀色及占比
  357. ratio631: boolean; // 是否符合6:3:1原则
  358. ratio631Analysis: string; // 6:3:1原则分析
  359. };
  360. colorTone: {
  361. overallTone: string; // 整体色调(低饱和、暖调等)
  362. consistency: boolean; // 色调是否统一
  363. jumpingIssue: boolean; // 是否存在跳脱感
  364. jumpingDescription?: string; // 跳脱感描述
  365. };
  366. colorMaterialRelation: string; // 色彩如何强化材质质感
  367. colorBalance: {
  368. warmColors: string[]; // 暖色列表
  369. coolColors: string[]; // 冷色列表
  370. balance: string; // 冷暖平衡评价
  371. imbalanceIssue: boolean; // 是否存在冷暖失衡
  372. };
  373. };
  374. // 四、像素维度
  375. pixelDimension: {
  376. pixelSize: {
  377. width: number;
  378. height: number;
  379. meets2K: boolean; // 是否≥1920×1080px
  380. detailClarity: string; // 放大后细节清晰度
  381. };
  382. imageQuality: {
  383. format: string; // 图片格式
  384. isLossless: boolean; // 是否无损格式
  385. compressionIssue: boolean; // 是否有压缩导致的模糊/噪点
  386. qualityDescription: string; // 画质描述
  387. };
  388. resolution: {
  389. dpi: number;
  390. meetsScreen: boolean; // 是否≥72dpi(屏幕展示)
  391. meetsPrint: boolean; // 是否≥300dpi(打印)
  392. };
  393. detailPresentation: string; // 微小元素细节呈现评价
  394. };
  395. // 五、整体适配性
  396. overallAdaptability: {
  397. styleConsistency: {
  398. style: string; // 软装风格
  399. consistency: boolean; // 风格是否统一
  400. fragmentation: boolean; // 是否存在风格割裂
  401. fragmentationDescription?: string; // 割裂描述
  402. };
  403. proportionMatch: {
  404. furnitureSizes: Array<{ name: string; size: string; suitability: string }>; // 家具尺寸适配性
  405. spaceCoordination: string; // 与空间层高/面积协调度
  406. sizeIssue: boolean; // 是否存在过大/过小问题
  407. sizeIssueDescription?: string; // 尺寸问题描述
  408. };
  409. functionAesthetics: {
  410. practicalExamples: string[]; // 实用性举例(储物、动线等)
  411. decorativeExamples: string[]; // 装饰性举例
  412. balanceMethod: string; // 功能与美学平衡方式
  413. };
  414. atmosphereConsistency: {
  415. emotionalTone: string; // 情感基调(松弛、质朴等)
  416. consistency: boolean; // 是否在所有区域统一
  417. inconsistencyDescription?: string; // 不一致描述
  418. };
  419. };
  420. // 综合评分和建议
  421. overallScore: number; // 软装综合评分 0-100
  422. strengths: string[]; // 优点
  423. improvements: string[]; // 改进建议
  424. };
  425. // AI分析时间
  426. analysisTime: number; // 分析耗时(毫秒)
  427. analysisDate: string; // 分析时间
  428. }
  429. /**
  430. * 图片分析服务
  431. * 基于豆包1.6模型进行图片内容识别和质量评估
  432. */
  433. @Injectable({
  434. providedIn: 'root'
  435. })
  436. export class ImageAnalysisService {
  437. // 使用豆包1.6模型
  438. private readonly MODEL = 'fmode-1.6-cn';
  439. constructor() {}
  440. /**
  441. * 动态加载 completionJSON,避免编译路径不兼容
  442. */
  443. private async callCompletionJSON(
  444. prompt: string,
  445. outputSchema: string,
  446. onStream?: (content: any) => void,
  447. retry: number = 2,
  448. options: any = {}
  449. ): Promise<any> {
  450. const mod = await import('fmode-ng/core/agent/chat/completion');
  451. const completionJSON = (mod as any).completionJSON as (
  452. prompt: string,
  453. output: string,
  454. onStream?: (content: any) => void,
  455. retry?: number,
  456. options?: any
  457. ) => Promise<any>;
  458. return completionJSON(prompt, outputSchema, onStream, retry, options);
  459. }
  460. /**
  461. * 分析单张图片
  462. * @param fastMode 快速模式:跳过专业分析(软装/渲染/后期),只做基础分类和质量评估
  463. */
  464. async analyzeImage(
  465. imageUrl: string,
  466. file: File,
  467. onProgress?: (progress: string) => void,
  468. fastMode: boolean = false
  469. ): Promise<ImageAnalysisResult> {
  470. const startTime = Date.now();
  471. try {
  472. // 🔥 如果是Blob URL,转换为Base64(AI无法访问blob URL)
  473. let processedUrl = imageUrl;
  474. if (imageUrl && imageUrl.startsWith('blob:')) {
  475. console.log('🔄 检测到Blob URL,转换为Base64以便AI访问...');
  476. onProgress?.('正在转换图片格式...');
  477. try {
  478. processedUrl = await this.blobToBase64(imageUrl);
  479. console.log('✅ Base64转换成功,长度:', processedUrl.length);
  480. } catch (convertError) {
  481. console.error('❌ Base64转换失败,尝试直接使用Blob URL:', convertError);
  482. // 如果转换失败,仍然使用原URL
  483. }
  484. }
  485. onProgress?.('正在分析图片内容...');
  486. // 获取图片基础信息
  487. const basicInfo = await this.getImageBasicInfo(file);
  488. // 🔥 快速预判断:检查是否为白模图(跳过AI调用)
  489. onProgress?.('正在进行快速预判断...');
  490. const quickCheck = await this.quickWhiteModelCheck(processedUrl, file);
  491. if (quickCheck.isWhiteModel) {
  492. console.log('⚡ 快速预判断:检测到白模图,直接返回结果(跳过AI调用)');
  493. return this.buildWhiteModelResult(file, basicInfo, quickCheck);
  494. }
  495. onProgress?.('正在进行AI分析...');
  496. // 🚀 优化:合并内容分析和质量分析为一次AI调用(快速模式)
  497. if (fastMode) {
  498. const combinedAnalysis = await this.analyzeCombinedFast(processedUrl, basicInfo);
  499. return combinedAnalysis;
  500. }
  501. // 非快速模式:使用原有的详细分析
  502. // 使用豆包1.6进行内容分析(使用处理后的URL)
  503. const contentAnalysis = await this.analyzeImageContent(processedUrl);
  504. onProgress?.('正在评估图片质量...');
  505. // 质量评估(使用处理后的URL)
  506. const qualityAnalysis = await this.analyzeImageQuality(processedUrl, basicInfo);
  507. onProgress?.('正在生成分析报告...');
  508. // 判断建议阶段
  509. const suggestedStage = this.determineSuggestedStage(contentAnalysis, qualityAnalysis);
  510. // 🔥 快速模式:跳过专业分析,直接返回基础结果
  511. let softDecorAnalysis: ImageAnalysisResult['softDecorAnalysis'] | undefined;
  512. let renderingAnalysis: ImageAnalysisResult['renderingAnalysis'] | undefined;
  513. let postProcessAnalysis: ImageAnalysisResult['postProcessAnalysis'] | undefined;
  514. if (!fastMode) {
  515. // 🔥 如果是软装阶段,进行专业软装分析
  516. if (suggestedStage === 'soft_decor' || contentAnalysis.category === 'soft_decor') {
  517. onProgress?.('正在进行软装专业分析...');
  518. try {
  519. softDecorAnalysis = await this.analyzeSoftDecor(imageUrl, file, basicInfo);
  520. } catch (error) {
  521. console.warn('⚠️ 软装专业分析失败,跳过此步骤:', error);
  522. }
  523. }
  524. // 🔥 如果是渲染阶段,进行专业渲染分析
  525. if (suggestedStage === 'rendering' || contentAnalysis.category === 'rendering') {
  526. onProgress?.('正在进行渲染专业分析...');
  527. try {
  528. renderingAnalysis = await this.analyzeRendering(imageUrl, file, basicInfo);
  529. } catch (error) {
  530. console.warn('⚠️ 渲染专业分析失败,跳过此步骤:', error);
  531. }
  532. }
  533. // 🔥 如果是后期处理阶段,进行专业后期处理分析
  534. if (suggestedStage === 'post_process' || contentAnalysis.category === 'post_process') {
  535. onProgress?.('正在进行后期处理专业分析...');
  536. try {
  537. postProcessAnalysis = await this.analyzePostProcess(imageUrl, file, basicInfo);
  538. } catch (error) {
  539. console.warn('⚠️ 后期处理专业分析失败,跳过此步骤:', error);
  540. }
  541. }
  542. }
  543. // 综合分析结果
  544. const result: ImageAnalysisResult = {
  545. fileName: file.name,
  546. fileSize: file.size,
  547. dimensions: basicInfo.dimensions,
  548. quality: qualityAnalysis,
  549. content: contentAnalysis,
  550. technical: {
  551. format: file.type,
  552. colorSpace: 'sRGB', // 默认值,实际可通过更深入分析获得
  553. dpi: basicInfo.dpi || 72,
  554. aspectRatio: this.calculateAspectRatio(basicInfo.dimensions.width, basicInfo.dimensions.height),
  555. megapixels: Math.round((basicInfo.dimensions.width * basicInfo.dimensions.height) / 1000000 * 100) / 100
  556. },
  557. suggestedStage: suggestedStage,
  558. suggestedReason: this.generateSuggestionReason(contentAnalysis, qualityAnalysis),
  559. softDecorAnalysis: softDecorAnalysis, // 🔥 添加软装专业分析结果
  560. renderingAnalysis: renderingAnalysis, // 🔥 添加渲染专业分析结果
  561. postProcessAnalysis: postProcessAnalysis, // 🔥 添加后期处理专业分析结果
  562. analysisTime: Date.now() - startTime,
  563. analysisDate: new Date().toISOString()
  564. };
  565. onProgress?.('分析完成');
  566. return result;
  567. } catch (error) {
  568. console.error('图片分析失败:', error);
  569. throw new Error('图片分析失败: ' + (error as Error).message);
  570. }
  571. }
  572. /**
  573. * 获取图片基础信息
  574. */
  575. private async getImageBasicInfo(file: File): Promise<{
  576. dimensions: { width: number; height: number };
  577. dpi?: number;
  578. }> {
  579. return new Promise((resolve, reject) => {
  580. const img = new Image();
  581. img.onload = () => {
  582. resolve({
  583. dimensions: {
  584. width: img.naturalWidth,
  585. height: img.naturalHeight
  586. },
  587. dpi: 72 // 默认DPI,实际项目中可以通过EXIF数据获取
  588. });
  589. };
  590. img.onerror = () => reject(new Error('无法加载图片'));
  591. img.src = URL.createObjectURL(file);
  592. });
  593. }
  594. /**
  595. * 🔥 快速预判断:检查是否为白模图(不调用AI,速度极快)
  596. * 通过图片像素统计快速判断,如果明显是白模图则直接返回
  597. */
  598. private async quickWhiteModelCheck(imageUrl: string, file: File): Promise<{
  599. isWhiteModel: boolean;
  600. confidence: number;
  601. colorVariance: number;
  602. grayPercentage: number;
  603. }> {
  604. return new Promise((resolve) => {
  605. const img = new Image();
  606. img.crossOrigin = 'anonymous';
  607. img.onload = () => {
  608. try {
  609. const canvas = document.createElement('canvas');
  610. const ctx = canvas.getContext('2d');
  611. if (!ctx) {
  612. resolve({ isWhiteModel: false, confidence: 0, colorVariance: 0, grayPercentage: 0 });
  613. return;
  614. }
  615. // 缩小图片以加快分析(采样200x200)
  616. const sampleSize = 200;
  617. canvas.width = sampleSize;
  618. canvas.height = sampleSize;
  619. ctx.drawImage(img, 0, 0, sampleSize, sampleSize);
  620. const imageData = ctx.getImageData(0, 0, sampleSize, sampleSize);
  621. const pixels = imageData.data;
  622. let grayPixels = 0;
  623. let colorfulPixels = 0;
  624. let totalVariance = 0;
  625. const sampleInterval = 4; // 每4个像素采样1个
  626. for (let i = 0; i < pixels.length; i += 4 * sampleInterval) {
  627. const r = pixels[i];
  628. const g = pixels[i + 1];
  629. const b = pixels[i + 2];
  630. const a = pixels[i + 3];
  631. if (a < 128) continue; // 跳过透明像素
  632. // 计算RGB差异
  633. const maxRGB = Math.max(r, g, b);
  634. const minRGB = Math.min(r, g, b);
  635. const rgbDiff = maxRGB - minRGB;
  636. totalVariance += rgbDiff;
  637. // 判断是否为灰色(RGB差异<15认为是灰色)
  638. if (rgbDiff < 15) {
  639. grayPixels++;
  640. } else {
  641. colorfulPixels++;
  642. }
  643. }
  644. const totalPixels = grayPixels + colorfulPixels;
  645. const grayPercentage = totalPixels > 0 ? (grayPixels / totalPixels) * 100 : 0;
  646. const avgVariance = totalPixels > 0 ? totalVariance / totalPixels : 0;
  647. // 🔥 判断标准(再次优化 - 更宽松,提高白模识别率):
  648. // 1. 灰色像素占比 > 70%(降低阈值,容忍更多浅色材质)
  649. // 2. RGB平均差异 < 30(增加阈值,容忍木纹等浅色纹理)
  650. const isWhiteModel = grayPercentage > 70 && avgVariance < 30;
  651. const confidence = isWhiteModel ? Math.min(98, 70 + grayPercentage / 3) : 0;
  652. console.log('⚡ 快速预判断结果:', {
  653. 灰色占比: `${grayPercentage.toFixed(1)}%`,
  654. RGB差异: avgVariance.toFixed(1),
  655. 是否白模: isWhiteModel,
  656. 置信度: `${confidence}%`
  657. });
  658. resolve({
  659. isWhiteModel,
  660. confidence,
  661. colorVariance: avgVariance,
  662. grayPercentage
  663. });
  664. } catch (error) {
  665. console.warn('快速预判断失败,将使用完整分析:', error);
  666. resolve({ isWhiteModel: false, confidence: 0, colorVariance: 0, grayPercentage: 0 });
  667. }
  668. };
  669. img.onerror = () => {
  670. resolve({ isWhiteModel: false, confidence: 0, colorVariance: 0, grayPercentage: 0 });
  671. };
  672. img.src = imageUrl;
  673. });
  674. }
  675. /**
  676. * 🔥 构建白模图分析结果(快速返回,不调用AI)
  677. */
  678. private buildWhiteModelResult(
  679. file: File,
  680. basicInfo: { dimensions: { width: number; height: number }; dpi?: number },
  681. quickCheck: { confidence: number; grayPercentage: number; colorVariance: number }
  682. ): ImageAnalysisResult {
  683. const megapixels = Math.round((basicInfo.dimensions.width * basicInfo.dimensions.height) / 1000000 * 100) / 100;
  684. // 🔥 根据像素数量转换为pixelDensity字符串类型
  685. let pixelDensityLevel: 'low' | 'medium' | 'high' | 'ultra_high' = 'medium';
  686. if (megapixels < 2) {
  687. pixelDensityLevel = 'low';
  688. } else if (megapixels < 8) {
  689. pixelDensityLevel = 'medium';
  690. } else if (megapixels < 20) {
  691. pixelDensityLevel = 'high';
  692. } else {
  693. pixelDensityLevel = 'ultra_high';
  694. }
  695. return {
  696. fileName: file.name,
  697. fileSize: file.size,
  698. dimensions: basicInfo.dimensions,
  699. quality: {
  700. score: 75,
  701. level: 'medium',
  702. pixelDensity: pixelDensityLevel,
  703. detailLevel: 'basic', // 白模细节等级为basic
  704. sharpness: 70,
  705. brightness: 75,
  706. contrast: 70,
  707. textureQuality: 40, // 白模纹理质量低
  708. colorDepth: 50
  709. },
  710. content: {
  711. category: 'white_model',
  712. confidence: quickCheck.confidence,
  713. spaceType: '未识别', // 白模图难以准确识别空间类型
  714. description: `这是一张白模图(SketchUp/3ds Max模型)。整体采用统一的灰色材质(灰色占比${quickCheck.grayPercentage.toFixed(0)}%),无装饰性色彩和真实纹理。可能包含家具体块和灯光效果,但材质为简单的漫反射表面。`,
  715. tags: ['白模', 'SketchUp', '模型', '灰色材质', '无纹理'],
  716. isArchitectural: true,
  717. hasInterior: true,
  718. hasFurniture: true, // 白模可以有家具
  719. hasLighting: true, // 白模可以有灯光
  720. hasColor: false, // 无装饰性色彩
  721. hasTexture: false // 无真实纹理
  722. },
  723. technical: {
  724. format: file.type,
  725. colorSpace: 'sRGB',
  726. dpi: basicInfo.dpi || 72,
  727. aspectRatio: this.calculateAspectRatio(basicInfo.dimensions.width, basicInfo.dimensions.height),
  728. megapixels: megapixels
  729. },
  730. suggestedStage: 'white_model',
  731. suggestedReason: `快速识别:灰色占比${quickCheck.grayPercentage.toFixed(0)}%,RGB差异${quickCheck.colorVariance.toFixed(1)},判定为白模阶段`,
  732. analysisTime: 50, // 快速分析,约50ms
  733. analysisDate: new Date().toISOString()
  734. };
  735. }
  736. /**
  737. * 🚀 快速模式:合并内容和质量分析为一次AI调用(速度提升50%+)
  738. */
  739. private async analyzeCombinedFast(
  740. imageUrl: string,
  741. basicInfo: { dimensions: { width: number; height: number }; dpi?: number }
  742. ): Promise<ImageAnalysisResult> {
  743. const startTime = Date.now();
  744. const prompt = `你是室内设计图分类专家,请快速分析这张图片的内容和质量,只输出JSON。
  745. JSON格式:
  746. {
  747. "category": "white_model或soft_decor或rendering或post_process",
  748. "confidence": 90,
  749. "spaceType": "客厅或卧室等",
  750. "description": "简短描述",
  751. "hasColor": true,
  752. "hasTexture": true,
  753. "hasLighting": true,
  754. "qualityScore": 85,
  755. "qualityLevel": "high",
  756. "sharpness": 80,
  757. "textureQuality": 85
  758. }
  759. 快速判断规则(严格执行):
  760. - white_model: 统一灰白色/浅色,无材质纹理细节(可有家具和灯光)
  761. - soft_decor: 有真实材质纹理(木纹/布纹),有装饰色彩,但CG感不强
  762. ⚠️ 关键:软装可以有灯光!重点是材质真实但CG渲染感不强
  763. - rendering: 有材质纹理,有装饰色彩,CG计算机渲染感明显(V-Ray/3dsMax)
  764. ⚠️ 区分:rendering = CG感明显(能看出是3D渲染),质量70-89分
  765. - post_process: 照片级真实感(看起来像真实拍摄),质量≥90分
  766. ⚠️ 区分:post_process = 照片级(不是普通CG渲染)`;
  767. const output = `{"category":"rendering","confidence":92,"spaceType":"卧室","description":"现代卧室","hasColor":true,"hasTexture":true,"hasLighting":true,"qualityScore":85,"qualityLevel":"high","sharpness":80,"textureQuality":85}`;
  768. try {
  769. console.log(`⏱️ [快速分析] 开始AI调用,图片Base64大小: ${(imageUrl.length / 1024 / 1024).toFixed(2)} MB`);
  770. // 🚀 添加30秒超时机制
  771. const aiPromise = this.callCompletionJSON(
  772. prompt,
  773. output,
  774. undefined,
  775. 2,
  776. {
  777. model: this.MODEL,
  778. vision: true,
  779. images: [imageUrl],
  780. max_tokens: 800 // 确保返回完整结果(避免截断)
  781. }
  782. );
  783. const timeoutPromise = new Promise((_, reject) => {
  784. setTimeout(() => reject(new Error('AI分析超时(60秒)')), 60000); // 🔥 增加到60秒,防止大图超时
  785. });
  786. const result = await Promise.race([aiPromise, timeoutPromise]) as any;
  787. // 构建完整结果
  788. const megapixels = Math.round((basicInfo.dimensions.width * basicInfo.dimensions.height) / 1000000 * 100) / 100;
  789. const analysisTime = Date.now() - startTime;
  790. console.log(`✅ [快速分析] AI调用完成,耗时: ${(analysisTime / 1000).toFixed(2)}秒`);
  791. console.log(`📊 [快速分析] AI返回结果:`, {
  792. 阶段分类: result.category,
  793. 置信度: `${result.confidence}%`,
  794. 空间类型: result.spaceType,
  795. 有颜色: result.hasColor,
  796. 有纹理: result.hasTexture,
  797. 有灯光: result.hasLighting,
  798. 质量分数: result.qualityScore
  799. });
  800. return {
  801. fileName: '',
  802. fileSize: 0,
  803. dimensions: basicInfo.dimensions,
  804. quality: {
  805. score: result.qualityScore || 75,
  806. level: result.qualityLevel || 'medium',
  807. sharpness: result.sharpness || 75,
  808. brightness: 70,
  809. contrast: 75,
  810. detailLevel: 'basic',
  811. pixelDensity: megapixels >= 2 ? 'high' : 'medium',
  812. textureQuality: result.textureQuality || 75,
  813. colorDepth: 75
  814. },
  815. content: {
  816. category: result.category || 'rendering',
  817. confidence: result.confidence || 80,
  818. spaceType: result.spaceType || '未识别',
  819. description: result.description || '室内设计图',
  820. tags: [],
  821. isArchitectural: true,
  822. hasInterior: true,
  823. hasFurniture: true,
  824. hasLighting: result.hasLighting !== false,
  825. hasColor: result.hasColor !== false,
  826. hasTexture: result.hasTexture !== false
  827. },
  828. technical: {
  829. format: 'image/jpeg',
  830. colorSpace: 'sRGB',
  831. dpi: basicInfo.dpi || 72,
  832. aspectRatio: this.calculateAspectRatio(basicInfo.dimensions.width, basicInfo.dimensions.height),
  833. megapixels: megapixels
  834. },
  835. suggestedStage: result.category || 'rendering',
  836. suggestedReason: `快速分析:${result.category},置信度${result.confidence}%`,
  837. analysisTime: analysisTime,
  838. analysisDate: new Date().toISOString()
  839. };
  840. } catch (error: any) {
  841. const analysisTime = Date.now() - startTime;
  842. console.error(`❌ [快速分析] 失败 (耗时${(analysisTime / 1000).toFixed(2)}秒):`, {
  843. 错误类型: error?.name,
  844. 错误信息: error?.message,
  845. 是否超时: error?.message?.includes('超时'),
  846. 图片大小: `${(imageUrl.length / 1024 / 1024).toFixed(2)} MB`
  847. });
  848. throw error;
  849. }
  850. }
  851. /**
  852. * 🔥 超快速分析图片内容(极简版:30秒内返回)
  853. */
  854. private async analyzeImageContent(imageUrl: string): Promise<ImageAnalysisResult['content']> {
  855. const prompt = `你是室内设计图分类专家,请仔细分析这张图片,只输出JSON,不要解释。
  856. JSON格式:
  857. {
  858. "category": "white_model或soft_decor或rendering或post_process",
  859. "confidence": 90,
  860. "spaceType": "客厅或卧室或餐厅或厨房或卫生间或书房",
  861. "description": "一句话描述",
  862. "tags": ["标签1", "标签2"],
  863. "isArchitectural": true,
  864. "hasInterior": true,
  865. "hasFurniture": true,
  866. "hasLighting": true,
  867. "hasColor": true,
  868. "hasTexture": true
  869. }
  870. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
  871. 🔥 阶段判断规则(按顺序严格执行)
  872. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
  873. 【第1优先级】white_model(白模)
  874. 核心特征:
  875. ✅ 材质统一光滑:全部是统一的浅色漆面/灰色漆面
  876. ✅ 无材质细节:看不到木纹、布纹、石材纹理、金属拉丝等细节
  877. ✅ 可以有家具、灯光、阴影(这不影响白模判断!)
  878. ✅ 可以有浅色(浅木色、浅灰色、米白色),只要材质统一光滑
  879. ❌ 典型错误:把"浅色统一材质"误判为"有装饰色彩"
  880. ⚠️ 关键:如果所有表面都是统一的光滑漆面(无纹理细节),就是白模!
  881. 判断标准:
  882. - hasColor = false(统一浅色≠装饰色彩)
  883. - hasTexture = false(光滑漆面≠真实纹理)
  884. - hasLighting = true/false(有无灯光不影响)
  885. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
  886. 【第2优先级】soft_decor(软装)
  887. 核心特征:
  888. ✅ 有真实材质纹理:能看到木纹、布纹、石材纹理等细节
  889. ✅ 有装饰色彩:不同材质有不同颜色(木色、布色、石色)
  890. ❌ 灯光效果弱:光影不明显,无强烈高光
  891. 判断标准:
  892. - hasColor = true(有装饰色彩)
  893. - hasTexture = true(有材质纹理)
  894. - hasLighting = false/弱(灯光效果一般)
  895. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
  896. 【第3优先级】rendering(渲染)
  897. 核心特征:
  898. ✅ CG计算机渲染图:3ds Max、SketchUp、V-Ray等软件渲染
  899. ✅ 有真实材质纹理(木纹、布纹清晰)
  900. ✅ 有装饰色彩(多种材质颜色)
  901. ✅ 灯光效果明显:能看到明显的光影、高光、阴影
  902. ❌ 但质量中等:能看出是CG,不是真实照片
  903. ⚠️ 关键区分:
  904. - 渲染图 = CG感明显,质量70-89分
  905. - 照片 = 照片级真实,质量≥90分
  906. 判断标准:
  907. - hasColor = true
  908. - hasTexture = true
  909. - hasLighting = true(灯光明显)
  910. - 质量分数: 70-89分
  911. - CG感明显(不是真实照片)
  912. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
  913. 【第4优先级】post_process(后期/照片级参考图)
  914. 核心特征:
  915. ✅ 照片级真实感:看起来像真实拍摄的照片,不是CG
  916. ✅ 极致材质纹理:超清晰的木纹、布纹、金属拉丝
  917. ✅ 强烈色彩氛围:丰富的色彩层次、环境反射、色彩融合
  918. ✅ 完美灯光效果:精致的光晕、柔和过渡、环境光反射
  919. ✅ 超高质量:接近或达到摄影级质量
  920. ⚠️ 重要:
  921. - 真实照片 = post_process(即使是客户发的参考图)
  922. - 照片级渲染 = post_process(后期精修到照片级)
  923. - CG渲染 = rendering(能看出是CG)
  924. 判断标准:
  925. - hasColor = true
  926. - hasTexture = true(超清晰)
  927. - hasLighting = true(完美)
  928. - 质量分数: 90-100分
  929. - 照片级真实感(不是普通CG渲染)
  930. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
  931. ⚠️ 最关键的区分要点
  932. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
  933. 白模 vs 软装/渲染:
  934. - 白模:表面光滑,看不到纹理细节(即使有浅色)
  935. - 软装/渲染:能看到清晰的木纹、布纹、石材纹理
  936. 软装 vs 渲染:
  937. - 软装:材质有纹理,但灯光效果弱(无明显光影)
  938. - 渲染:材质有纹理 + 明显的灯光光影效果(但是CG)
  939. 渲染 vs 后期:
  940. - 渲染:CG计算机渲染,能看出是CG(质量70-89分)
  941. - 后期:照片级真实感,像真实拍摄的照片(质量≥85分)
  942. ⚠️ 最关键:
  943. - 如果看起来像真实照片(不是CG) → post_process
  944. - 如果是CG渲染图(能看出是3D渲染) → rendering
  945. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
  946. 请仔细观察图片,严格按照以上规则判断!`;
  947. const output = `{"category":"rendering","confidence":92,"spaceType":"卧室","description":"现代卧室","tags":["卧室","现代"],"isArchitectural":true,"hasInterior":true,"hasFurniture":true,"hasLighting":true,"hasColor":true,"hasTexture":true}`;
  948. try {
  949. const result = await this.callCompletionJSON(
  950. prompt,
  951. output,
  952. undefined, // 移除进度回调,加快速度
  953. 2,
  954. {
  955. model: this.MODEL,
  956. vision: true,
  957. images: [imageUrl]
  958. }
  959. );
  960. // 🔥 确保返回完整的字段
  961. console.log('✅ AI分析成功返回:', {
  962. 类别: result.category,
  963. 置信度: result.confidence,
  964. 空间类型: result.spaceType || '未识别',
  965. 有颜色: result.hasColor,
  966. 有纹理: result.hasTexture,
  967. 有灯光: result.hasLighting
  968. });
  969. return result || {
  970. category: 'unknown',
  971. confidence: 0,
  972. spaceType: '未识别',
  973. description: '无法识别图片内容',
  974. tags: [],
  975. isArchitectural: false,
  976. hasInterior: false,
  977. hasFurniture: false,
  978. hasLighting: false,
  979. hasColor: false,
  980. hasTexture: false
  981. };
  982. } catch (error: any) {
  983. console.error('❌ AI内容分析失败 - 详细错误:', {
  984. 错误类型: error?.constructor?.name,
  985. 错误信息: error?.message,
  986. 错误代码: error?.code || error?.status,
  987. 图片URL: imageUrl,
  988. 错误堆栈: error?.stack?.substring(0, 200)
  989. });
  990. // 🔥 确保错误返回也包含完整字段
  991. return {
  992. category: 'unknown',
  993. confidence: 0,
  994. spaceType: '未识别',
  995. description: `内容分析失败: ${error?.message || '未知错误'}`,
  996. tags: [],
  997. isArchitectural: false,
  998. hasInterior: false,
  999. hasFurniture: false,
  1000. hasLighting: false,
  1001. hasColor: false,
  1002. hasTexture: false
  1003. };
  1004. }
  1005. }
  1006. /**
  1007. * 🔥 分析图片质量(增强版:包含精细度和像素密度)
  1008. */
  1009. private async analyzeImageQuality(
  1010. imageUrl: string,
  1011. basicInfo: { dimensions: { width: number; height: number } }
  1012. ): Promise<ImageAnalysisResult['quality']> {
  1013. const prompt = `请分析这张室内设计图片的质量,并按以下JSON格式输出:
  1014. {
  1015. "score": "总体质量分数(0-100)",
  1016. "level": "质量等级(low/medium/high/ultra)",
  1017. "sharpness": "清晰度(0-100)",
  1018. "brightness": "亮度(0-100)",
  1019. "contrast": "对比度(0-100)",
  1020. "textureQuality": "纹理质量(0-100)",
  1021. "colorDepth": "色彩深度(0-100)"
  1022. }
  1023. 评估标准:
  1024. - score: 综合质量评分,考虑清晰度、构图、色彩、纹理等
  1025. - level: low(<60分), medium(60-75分), high(75-90分), ultra(>90分)
  1026. - sharpness: 图片清晰度,是否有模糊、噪点、锯齿
  1027. - brightness: 亮度是否适中,不过暗或过亮
  1028. - contrast: 对比度是否合适,层次是否分明
  1029. - textureQuality: 纹理质量,材质细节是否清晰(木纹、布纹、石材等)
  1030. - colorDepth: 色彩深度,色彩过渡是否自然,是否有色带
  1031. 请客观评估图片质量,重点关注专业室内设计图片的标准。`;
  1032. const output = `{
  1033. "score": 75,
  1034. "level": "high",
  1035. "sharpness": 80,
  1036. "brightness": 70,
  1037. "contrast": 75,
  1038. "textureQuality": 75,
  1039. "colorDepth": 80
  1040. }`;
  1041. try {
  1042. const result = await this.callCompletionJSON(
  1043. prompt,
  1044. output,
  1045. undefined, // 移除进度回调,提升分析速度
  1046. 2,
  1047. {
  1048. model: this.MODEL,
  1049. vision: true,
  1050. images: [imageUrl]
  1051. }
  1052. );
  1053. // 🔥 结合图片分辨率和像素密度进行质量调整
  1054. const resolutionScore = this.calculateResolutionScore(basicInfo.dimensions);
  1055. const pixelDensity = this.calculatePixelDensity(basicInfo.dimensions);
  1056. // 🔥 评估内容精细程度
  1057. const detailLevel = await this.evaluateDetailLevel(imageUrl, basicInfo.dimensions);
  1058. // 🔥 综合评分:AI评分(40%) + 分辨率(30%) + 纹理质量(20%) + 色彩深度(10%)
  1059. const adjustedScore = Math.round(
  1060. result.score * 0.4 +
  1061. resolutionScore * 0.3 +
  1062. (result.textureQuality || 50) * 0.2 +
  1063. (result.colorDepth || 50) * 0.1
  1064. );
  1065. console.log('📊 质量分析结果:', {
  1066. AI评分: result.score,
  1067. 分辨率评分: resolutionScore,
  1068. 纹理质量: result.textureQuality,
  1069. 色彩深度: result.colorDepth,
  1070. 综合评分: adjustedScore,
  1071. 像素密度: pixelDensity,
  1072. 精细程度: detailLevel
  1073. });
  1074. return {
  1075. score: adjustedScore,
  1076. level: this.getQualityLevel(adjustedScore),
  1077. sharpness: result.sharpness || 50,
  1078. brightness: result.brightness || 50,
  1079. contrast: result.contrast || 50,
  1080. detailLevel: detailLevel,
  1081. pixelDensity: pixelDensity,
  1082. textureQuality: result.textureQuality || 50,
  1083. colorDepth: result.colorDepth || 50
  1084. };
  1085. } catch (error) {
  1086. console.error('❌ 质量分析失败:', error);
  1087. // 基于分辨率和像素的备选评估
  1088. const resolutionScore = this.calculateResolutionScore(basicInfo.dimensions);
  1089. const pixelDensity = this.calculatePixelDensity(basicInfo.dimensions);
  1090. const megapixels = (basicInfo.dimensions.width * basicInfo.dimensions.height) / 1000000;
  1091. // 根据像素推测精细程度
  1092. let detailLevel: 'minimal' | 'basic' | 'detailed' | 'ultra_detailed' = 'basic';
  1093. if (megapixels >= 8) detailLevel = 'ultra_detailed';
  1094. else if (megapixels >= 2) detailLevel = 'detailed';
  1095. else if (megapixels >= 0.9) detailLevel = 'basic';
  1096. else detailLevel = 'minimal';
  1097. return {
  1098. score: resolutionScore,
  1099. level: this.getQualityLevel(resolutionScore),
  1100. sharpness: 50,
  1101. brightness: 50,
  1102. contrast: 50,
  1103. detailLevel: detailLevel,
  1104. pixelDensity: pixelDensity,
  1105. textureQuality: resolutionScore * 0.8,
  1106. colorDepth: resolutionScore * 0.9
  1107. };
  1108. }
  1109. }
  1110. /**
  1111. * 🔥 基于分辨率和像素密度计算质量分数(更精细)
  1112. */
  1113. private calculateResolutionScore(dimensions: { width: number; height: number }): number {
  1114. const totalPixels = dimensions.width * dimensions.height;
  1115. const megapixels = totalPixels / 1000000;
  1116. // 更精细的像素分级
  1117. if (megapixels >= 33) return 98; // 8K (7680×4320)
  1118. if (megapixels >= 24) return 96; // 6K (6144×3160)
  1119. if (megapixels >= 16) return 94; // 5K (5120×2880)
  1120. if (megapixels >= 8) return 92; // 4K (3840×2160)
  1121. if (megapixels >= 6) return 88; // 2.5K+ (2560×2304)
  1122. if (megapixels >= 4) return 84; // QHD+ (2560×1600)
  1123. if (megapixels >= 2) return 78; // 1080p (1920×1080)
  1124. if (megapixels >= 1) return 68; // 720p+ (1280×720)
  1125. if (megapixels >= 0.5) return 55; // 中等分辨率
  1126. if (megapixels >= 0.3) return 40; // 低分辨率
  1127. return 25; // 极低分辨率
  1128. }
  1129. /**
  1130. * 🔥 计算像素密度等级
  1131. */
  1132. private calculatePixelDensity(dimensions: { width: number; height: number }): 'low' | 'medium' | 'high' | 'ultra_high' {
  1133. const totalPixels = dimensions.width * dimensions.height;
  1134. const megapixels = totalPixels / 1000000;
  1135. if (megapixels >= 8) return 'ultra_high'; // 4K及以上
  1136. if (megapixels >= 2) return 'high'; // 1080p及以上
  1137. if (megapixels >= 0.9) return 'medium'; // 720p及以上
  1138. return 'low'; // 低于720p
  1139. }
  1140. /**
  1141. * 🔥 评估内容精细程度
  1142. */
  1143. private async evaluateDetailLevel(
  1144. imageUrl: string,
  1145. dimensions: { width: number; height: number }
  1146. ): Promise<'minimal' | 'basic' | 'detailed' | 'ultra_detailed'> {
  1147. const prompt = `请评估这张室内设计图片的内容精细程度,并返回JSON:
  1148. {
  1149. "detailLevel": "精细程度(minimal/basic/detailed/ultra_detailed)",
  1150. "textureQuality": "纹理质量评分(0-100)",
  1151. "colorDepth": "色彩深度评分(0-100)",
  1152. "reasoning": "评估理由"
  1153. }
  1154. 评估标准:
  1155. - minimal: 极简图,只有基本轮廓,无细节纹理
  1156. - basic: 基础图,有简单纹理和色彩,细节较少
  1157. - detailed: 详细图,有丰富纹理、材质细节、光影效果
  1158. - ultra_detailed: 超精细图,有极致纹理、真实材质、复杂光影、细微细节
  1159. 重点关注:
  1160. 1. 纹理细节(木纹、布纹、石材纹理等)
  1161. 2. 材质表现(金属反射、玻璃透明度、布料质感等)
  1162. 3. 光影效果(阴影、高光、环境光等)
  1163. 4. 细微元素(装饰品细节、边角处理等)`;
  1164. const output = `{
  1165. "detailLevel": "detailed",
  1166. "textureQuality": 75,
  1167. "colorDepth": 80,
  1168. "reasoning": "图片包含丰富的纹理和材质细节"
  1169. }`;
  1170. try {
  1171. const result = await this.callCompletionJSON(
  1172. prompt,
  1173. output,
  1174. undefined,
  1175. 2,
  1176. {
  1177. model: this.MODEL,
  1178. vision: true,
  1179. images: [imageUrl]
  1180. }
  1181. );
  1182. return result.detailLevel || 'basic';
  1183. } catch (error) {
  1184. console.error('精细程度评估失败:', error);
  1185. // 基于分辨率的备选评估
  1186. const megapixels = (dimensions.width * dimensions.height) / 1000000;
  1187. if (megapixels >= 8) return 'ultra_detailed';
  1188. if (megapixels >= 2) return 'detailed';
  1189. if (megapixels >= 0.9) return 'basic';
  1190. return 'minimal';
  1191. }
  1192. }
  1193. /**
  1194. * 获取质量等级
  1195. */
  1196. private getQualityLevel(score: number): 'low' | 'medium' | 'high' | 'ultra' {
  1197. if (score >= 90) return 'ultra';
  1198. if (score >= 75) return 'high';
  1199. if (score >= 60) return 'medium';
  1200. return 'low';
  1201. }
  1202. /**
  1203. * 计算宽高比
  1204. */
  1205. private calculateAspectRatio(width: number, height: number): string {
  1206. const gcd = (a: number, b: number): number => b === 0 ? a : gcd(b, a % b);
  1207. const divisor = gcd(width, height);
  1208. return `${width / divisor}:${height / divisor}`;
  1209. }
  1210. /**
  1211. * 🔥 确定建议的阶段分类(精细化判断逻辑,避免误判)
  1212. */
  1213. private determineSuggestedStage(
  1214. content: ImageAnalysisResult['content'],
  1215. quality: ImageAnalysisResult['quality']
  1216. ): 'white_model' | 'soft_decor' | 'rendering' | 'post_process' {
  1217. // 🔥 提取关键特征(确保布尔值正确)
  1218. const hasColor = content.hasColor === true;
  1219. const hasTexture = content.hasTexture === true;
  1220. const hasFurniture = content.hasFurniture === true;
  1221. const hasLighting = content.hasLighting === true;
  1222. const megapixels = quality.pixelDensity;
  1223. const detailLevel = quality.detailLevel;
  1224. const qualityScore = quality.score;
  1225. const textureQuality = quality.textureQuality;
  1226. console.log('🎯 阶段判断依据:', {
  1227. AI类别: content.category,
  1228. AI置信度: content.confidence,
  1229. 空间类型: content.spaceType || '未识别',
  1230. 像素密度: megapixels,
  1231. 精细程度: detailLevel,
  1232. 质量分数: qualityScore,
  1233. 纹理质量: textureQuality,
  1234. 有家具: hasFurniture,
  1235. 有灯光: hasLighting,
  1236. 有色彩: hasColor,
  1237. 有纹理: hasTexture
  1238. });
  1239. // 🔥 调试:打印原始content对象
  1240. console.log('🔍 原始AI返回:', JSON.stringify(content, null, 2));
  1241. // 🔥 关键规则1:白模判断(最高优先级!)
  1242. // 白膜的核心:统一材质 + 无装饰彩色 + 无真实纹理(可以有灯光和家具!)
  1243. if (!hasColor && !hasTexture) {
  1244. console.log('🟢 【白模优先规则】材质符合白模特征:无装饰彩色 + 无真实纹理');
  1245. // 🔥 只要无彩色无纹理,就判定为白模(不再考虑其他条件)
  1246. console.log('✅ 判定为白模阶段(最高优先级)');
  1247. return 'white_model';
  1248. }
  1249. // 🔥 关键规则2:后期处理判断(第二优先级)
  1250. // 超高质量 + AI高置信度 = 后期处理
  1251. if (qualityScore >= 90 && content.category === 'post_process' && content.confidence >= 80) {
  1252. console.log('✅ 判定为后期处理阶段:超高质量(≥90分) + AI高置信度判定为后期');
  1253. return 'post_process';
  1254. }
  1255. // 🔥 质量特别高也可能是后期(即使AI不确定)
  1256. if (qualityScore >= 92 && hasColor && hasTexture && hasLighting) {
  1257. console.log('✅ 判定为后期处理阶段:质量极高(≥92分) + 完整特征');
  1258. return 'post_process';
  1259. }
  1260. // 🔥 关键规则3:渲染 vs 软装判断
  1261. // 有彩色和纹理(不是白模),根据灯光效果、质量、CG感判断
  1262. if (hasColor && hasTexture) {
  1263. console.log('🔵 有装饰性色彩和真实纹理,判断软装/渲染/后期');
  1264. // 🔥 优先判断:照片级质量(≥90分)= 后期/照片
  1265. if (qualityScore >= 90) {
  1266. console.log('✅ 判定为后期处理阶段:照片级质量(≥90分),可能是照片或后期精修');
  1267. return 'post_process';
  1268. }
  1269. // 🔥 次优先:AI高置信度判定为post_process
  1270. if (content.category === 'post_process' && content.confidence >= 85 && qualityScore >= 85) {
  1271. console.log('✅ 判定为后期处理阶段:AI高置信度+质量85+分');
  1272. return 'post_process';
  1273. }
  1274. // 🔥 关键改进:AI明确判定为软装时,优先采用
  1275. if (content.category === 'soft_decor' && content.confidence >= 75) {
  1276. console.log('✅ 判定为软装阶段:AI高置信度判定为软装');
  1277. return 'soft_decor';
  1278. }
  1279. // 高质量 + 强灯光 + AI判定为渲染 = 渲染
  1280. if (hasLighting && qualityScore >= 70 && content.category === 'rendering') {
  1281. console.log('✅ 判定为渲染阶段:有彩色材质/纹理 + 强灯光 + AI判定为渲染');
  1282. return 'rendering';
  1283. }
  1284. // 中等质量 + 弱灯光 = 软装
  1285. if (!hasLighting || qualityScore < 75) {
  1286. console.log('✅ 判定为软装阶段:有彩色材质/纹理 + 灯光弱/质量中等');
  1287. return 'soft_decor';
  1288. }
  1289. // 🔥 默认:根据AI判定或默认渲染
  1290. if (content.category === 'soft_decor') {
  1291. console.log('✅ 判定为软装阶段:AI判定(默认)');
  1292. return 'soft_decor';
  1293. }
  1294. console.log('✅ 判定为渲染阶段:有彩色材质/纹理(默认)');
  1295. return 'rendering';
  1296. }
  1297. // 🔥 关键规则4:只有彩色或只有纹理(罕见情况)
  1298. if (hasColor || hasTexture) {
  1299. console.log('⚠️ 只有彩色或只有纹理(罕见),根据灯光判断');
  1300. if (hasLighting && qualityScore >= 75) {
  1301. console.log('✅ 判定为渲染阶段:有灯光 + 中高质量');
  1302. return 'rendering';
  1303. } else {
  1304. console.log('✅ 判定为软装阶段:灯光弱或质量中等');
  1305. return 'soft_decor';
  1306. }
  1307. }
  1308. // 🔥 兜底逻辑(理论上不应该走到这里)
  1309. console.log('⚠️ 未命中主要规则,使用AI结果或默认渲染');
  1310. // 如果AI有高置信度的判断,使用AI结果
  1311. if (content.confidence > 80 && content.category !== 'unknown') {
  1312. console.log(`✅ 兜底:采用AI高置信度(${content.confidence}%)判定: ${content.category}`);
  1313. return content.category as any;
  1314. }
  1315. // 最终兜底:默认渲染
  1316. console.log('✅ 兜底:默认判定为渲染阶段');
  1317. return 'rendering';
  1318. // 旧逻辑(已废弃):
  1319. // if (qualityScore >= 70) {
  1320. // return 'rendering'; // ✗ 错误:白模图也可能高质量
  1321. // } else if (qualityScore >= 50) {
  1322. // return 'soft_decor';
  1323. // } else {
  1324. // return 'white_model';
  1325. // }
  1326. }
  1327. /**
  1328. * 生成分类建议原因
  1329. */
  1330. private generateSuggestionReason(
  1331. content: ImageAnalysisResult['content'],
  1332. quality: ImageAnalysisResult['quality']
  1333. ): string {
  1334. const reasons = [];
  1335. if (content.confidence > 70) {
  1336. reasons.push(`AI识别置信度${content.confidence}%`);
  1337. }
  1338. if (quality.score >= 90) {
  1339. reasons.push('图片质量极高,适合最终展示');
  1340. } else if (quality.score >= 75) {
  1341. reasons.push('图片质量良好');
  1342. } else if (quality.score < 60) {
  1343. reasons.push('图片质量较低,可能为初期阶段');
  1344. }
  1345. if (content.hasLighting) {
  1346. reasons.push('包含灯光效果');
  1347. }
  1348. if (content.hasFurniture) {
  1349. reasons.push('包含家具配置');
  1350. }
  1351. if (!content.hasFurniture && !content.hasLighting) {
  1352. reasons.push('基础结构图,无装饰元素');
  1353. }
  1354. return reasons.join(',') || '基于图片特征综合判断';
  1355. }
  1356. /**
  1357. * 批量分析图片
  1358. */
  1359. async analyzeImages(
  1360. files: { file: File; url: string }[],
  1361. onProgress?: (current: number, total: number, currentFileName: string) => void
  1362. ): Promise<ImageAnalysisResult[]> {
  1363. const results: ImageAnalysisResult[] = [];
  1364. for (let i = 0; i < files.length; i++) {
  1365. const { file, url } = files[i];
  1366. onProgress?.(i + 1, files.length, file.name);
  1367. try {
  1368. const result = await this.analyzeImage(url, file);
  1369. results.push(result);
  1370. } catch (error) {
  1371. console.error(`分析文件 ${file.name} 失败:`, error);
  1372. // 创建一个基础的错误结果
  1373. results.push(this.createErrorResult(file, error as Error));
  1374. }
  1375. }
  1376. return results;
  1377. }
  1378. /**
  1379. * 创建错误结果
  1380. */
  1381. private createErrorResult(file: File, error: Error): ImageAnalysisResult {
  1382. return {
  1383. fileName: file.name,
  1384. fileSize: file.size,
  1385. dimensions: { width: 0, height: 0 },
  1386. quality: {
  1387. score: 0,
  1388. level: 'low',
  1389. sharpness: 0,
  1390. brightness: 0,
  1391. contrast: 0,
  1392. detailLevel: 'minimal',
  1393. pixelDensity: 'low',
  1394. textureQuality: 0,
  1395. colorDepth: 0
  1396. },
  1397. content: {
  1398. category: 'unknown',
  1399. confidence: 0,
  1400. description: `分析失败: ${error.message}`,
  1401. tags: [],
  1402. isArchitectural: false,
  1403. hasInterior: false,
  1404. hasFurniture: false,
  1405. hasLighting: false
  1406. },
  1407. technical: {
  1408. format: file.type,
  1409. colorSpace: 'unknown',
  1410. dpi: 0,
  1411. aspectRatio: '0:0',
  1412. megapixels: 0
  1413. },
  1414. suggestedStage: 'white_model',
  1415. suggestedReason: '分析失败,默认分类',
  1416. analysisTime: 0,
  1417. analysisDate: new Date().toISOString()
  1418. };
  1419. }
  1420. /**
  1421. * 保存分析结果到数据库
  1422. */
  1423. async saveAnalysisResult(
  1424. projectId: string,
  1425. spaceId: string,
  1426. stageType: string,
  1427. analysisResult: ImageAnalysisResult
  1428. ): Promise<void> {
  1429. try {
  1430. // 查询项目
  1431. const projectQuery = new Parse.Query('Project');
  1432. const project = await projectQuery.get(projectId);
  1433. if (!project) {
  1434. throw new Error('项目不存在');
  1435. }
  1436. // 获取现有的date数据
  1437. const dateData = project.get('date') || {};
  1438. // 初始化图片分析数据结构
  1439. if (!dateData.imageAnalysis) {
  1440. dateData.imageAnalysis = {};
  1441. }
  1442. if (!dateData.imageAnalysis[spaceId]) {
  1443. dateData.imageAnalysis[spaceId] = {};
  1444. }
  1445. if (!dateData.imageAnalysis[spaceId][stageType]) {
  1446. dateData.imageAnalysis[spaceId][stageType] = [];
  1447. }
  1448. // 添加分析结果
  1449. dateData.imageAnalysis[spaceId][stageType].push(analysisResult);
  1450. // 保存到项目
  1451. project.set('date', dateData);
  1452. await project.save();
  1453. console.log('图片分析结果已保存到项目数据库');
  1454. } catch (error) {
  1455. console.error('保存分析结果失败:', error);
  1456. throw error;
  1457. }
  1458. }
  1459. /**
  1460. * 🔥 快速生成模拟分析结果(用于开发测试)
  1461. * 根据文件名和空间名称快速生成分析结果,无需调用AI
  1462. */
  1463. generateMockAnalysisResult(
  1464. file: File,
  1465. spaceName?: string,
  1466. stageName?: string
  1467. ): ImageAnalysisResult {
  1468. const fileName = file.name.toLowerCase();
  1469. const fileSize = file.size;
  1470. let suggestedStage: 'white_model' | 'soft_decor' | 'rendering' | 'post_process' = 'white_model';
  1471. let category: 'white_model' | 'soft_decor' | 'rendering' | 'post_process' | 'unknown' = 'white_model';
  1472. let confidence = 75;
  1473. let analysisReason = '基于文件名和特征分析';
  1474. // 增强的关键词匹配
  1475. const stageKeywords = {
  1476. white_model: ['白模', 'white', 'model', '毛坯', '空间', '结构', '框架', '基础'],
  1477. soft_decor: ['软装', 'soft', 'decor', '家具', 'furniture', '装饰', '饰品', '布艺'],
  1478. rendering: ['渲染', 'render', '效果', 'effect', '光照', '材质', '质感'],
  1479. post_process: ['后期', 'post', 'final', '最终', '完成', '成品', '精修', '调色']
  1480. };
  1481. // 分析文件名匹配度
  1482. let maxMatchScore = 0;
  1483. let bestStage = 'white_model';
  1484. Object.entries(stageKeywords).forEach(([stage, keywords]) => {
  1485. const matchScore = keywords.reduce((score, keyword) => {
  1486. if (fileName.includes(keyword)) {
  1487. return score + (keyword.length > 2 ? 2 : 1); // 长关键词权重更高
  1488. }
  1489. return score;
  1490. }, 0);
  1491. if (matchScore > maxMatchScore) {
  1492. maxMatchScore = matchScore;
  1493. bestStage = stage as typeof suggestedStage;
  1494. }
  1495. });
  1496. if (maxMatchScore > 0) {
  1497. suggestedStage = bestStage as 'white_model' | 'soft_decor' | 'rendering' | 'post_process';
  1498. category = bestStage as 'white_model' | 'soft_decor' | 'rendering' | 'post_process';
  1499. confidence = Math.min(75 + maxMatchScore * 5, 95);
  1500. analysisReason = `文件名包含${this.getStageName(bestStage)}相关关键词`;
  1501. }
  1502. // 文件大小分析
  1503. if (fileSize > 8 * 1024 * 1024) { // 大于8MB
  1504. if (suggestedStage === 'white_model') {
  1505. suggestedStage = 'rendering';
  1506. category = 'rendering';
  1507. confidence = Math.min(confidence + 10, 95);
  1508. analysisReason += ',大文件更可能是高质量渲染图';
  1509. }
  1510. } else if (fileSize < 500 * 1024) { // 小于500KB
  1511. if (suggestedStage === 'post_process') {
  1512. suggestedStage = 'white_model';
  1513. category = 'white_model';
  1514. confidence = Math.max(confidence - 10, 60);
  1515. analysisReason += ',小文件更可能是简单的白模图';
  1516. }
  1517. }
  1518. // 根据目标阶段调整
  1519. if (stageName) {
  1520. const targetStageMap: Record<string, typeof suggestedStage> = {
  1521. '白模': 'white_model',
  1522. '软装': 'soft_decor',
  1523. '渲染': 'rendering',
  1524. '后期': 'post_process'
  1525. };
  1526. const targetStage = targetStageMap[stageName];
  1527. if (targetStage && targetStage === suggestedStage) {
  1528. confidence = Math.min(confidence + 15, 98);
  1529. analysisReason += `,与目标阶段一致`;
  1530. }
  1531. }
  1532. const qualityScoreMap = {
  1533. 'white_model': 75,
  1534. 'soft_decor': 82,
  1535. 'rendering': 88,
  1536. 'post_process': 95
  1537. };
  1538. const score = qualityScoreMap[suggestedStage];
  1539. // 生成模拟分析结果
  1540. const result: ImageAnalysisResult = {
  1541. fileName: file.name,
  1542. fileSize: file.size,
  1543. dimensions: {
  1544. width: 1920 + Math.floor(Math.random() * 400), // 模拟不同尺寸
  1545. height: 1080 + Math.floor(Math.random() * 300)
  1546. },
  1547. quality: {
  1548. score: score,
  1549. level: this.getQualityLevel(score),
  1550. sharpness: Math.min(score + Math.floor(Math.random() * 10), 100),
  1551. brightness: Math.max(score - Math.floor(Math.random() * 10), 50),
  1552. contrast: Math.min(score + Math.floor(Math.random() * 8), 100),
  1553. detailLevel: score >= 90 ? 'ultra_detailed' : score >= 75 ? 'detailed' : score >= 60 ? 'basic' : 'minimal',
  1554. pixelDensity: score >= 90 ? 'ultra_high' : score >= 75 ? 'high' : score >= 60 ? 'medium' : 'low',
  1555. textureQuality: Math.min(score + Math.floor(Math.random() * 5), 100),
  1556. colorDepth: Math.min(score + Math.floor(Math.random() * 5), 100)
  1557. },
  1558. content: {
  1559. category: category,
  1560. confidence: confidence,
  1561. description: `${spaceName || '室内空间'}${this.getStageName(suggestedStage)}图`,
  1562. tags: this.generateTags(suggestedStage, spaceName),
  1563. isArchitectural: true,
  1564. hasInterior: true,
  1565. hasFurniture: suggestedStage !== 'white_model',
  1566. hasLighting: suggestedStage === 'rendering' || suggestedStage === 'post_process'
  1567. },
  1568. technical: {
  1569. format: file.type,
  1570. colorSpace: Math.random() > 0.8 ? 'Adobe RGB' : 'sRGB',
  1571. dpi: Math.random() > 0.5 ? 300 : 72,
  1572. aspectRatio: this.calculateAspectRatio(1920, 1080),
  1573. megapixels: Math.round(((1920 * 1080) / 1000000) * 100) / 100
  1574. },
  1575. suggestedStage: suggestedStage,
  1576. suggestedReason: analysisReason,
  1577. analysisTime: 50 + Math.floor(Math.random() * 100),
  1578. analysisDate: new Date().toISOString()
  1579. };
  1580. console.log(`🚀 增强模拟分析结果: ${file.name} -> ${this.getStageName(suggestedStage)}`, {
  1581. confidence: confidence,
  1582. reason: analysisReason,
  1583. fileSize: `${(fileSize / 1024 / 1024).toFixed(1)}MB`
  1584. });
  1585. return result;
  1586. }
  1587. /**
  1588. * 生成标签
  1589. */
  1590. private generateTags(stage: string, spaceName?: string): string[] {
  1591. const baseTags = [this.getStageName(stage), spaceName || '室内', '设计'];
  1592. const stageSpecificTags: Record<string, string[]> = {
  1593. 'white_model': ['建筑', '结构', '空间布局'],
  1594. 'soft_decor': ['家具', '装饰', '色彩搭配'],
  1595. 'rendering': ['渲染', '光影', '材质'],
  1596. 'post_process': ['后期', '色彩调整', '成品']
  1597. };
  1598. return [...baseTags, ...(stageSpecificTags[stage] || [])];
  1599. }
  1600. /**
  1601. * 获取阶段名称
  1602. */
  1603. private getStageName(stageType: string): string {
  1604. const stageMap: { [key: string]: string } = {
  1605. 'white_model': '白模',
  1606. 'soft_decor': '软装',
  1607. 'rendering': '渲染',
  1608. 'post_process': '后期'
  1609. };
  1610. return stageMap[stageType] || stageType;
  1611. }
  1612. /**
  1613. * 🔥 软装专业分析(基于行业标准的多维度分析)
  1614. * 包含:材质、灯光、颜色、像素、整体适配性五大维度
  1615. */
  1616. async analyzeSoftDecor(
  1617. imageUrl: string,
  1618. file: File,
  1619. basicInfo?: { dimensions: { width: number; height: number } }
  1620. ): Promise<ImageAnalysisResult['softDecorAnalysis']> {
  1621. console.log('🎨 开始软装专业分析...');
  1622. if (!basicInfo) {
  1623. basicInfo = await this.getImageBasicInfo(file);
  1624. }
  1625. const prompt = `你是一位资深的室内软装设计分析专家。请基于以下专业标准对这张软装图片进行全面、精确的多维度分析:
  1626. **一、材质维度分析**
  1627. 识别空间内的核心材质(如水泥、实木、藤编、皮革、大理石、玻璃、金属等):
  1628. - 每种材质的占比是否均衡?
  1629. - 硬材质(水泥柱、大理石台面、金属)与软材质(藤编椅、皮革沙发、布艺)如何形成"冷暖/刚柔"的视觉平衡?
  1630. - 材质的原生肌理(如水泥的粗糙感、实木的木纹、藤编的编织纹理)是否被清晰呈现?有无"材质同质化"问题?
  1631. - 不同区域的同类材质(如餐桌木面与柜体木面、水泥柱与地面)是否形成视觉关联?
  1632. **二、灯光维度分析**
  1633. 分析软装与灯光的互动效果:
  1634. - 自然光(窗户)与人工光(条形吊灯、壁灯、筒灯)的分布是否合理?主光源、辅助光的层次是否清晰?
  1635. - 灯光色温(如暖白光)是否与软装材质(如木色、藤编)的质感匹配?有无"色温冲突"(如冷光配暖材质)?
  1636. - 灯光是否突出软装重点(如餐桌的光泽、藤编椅的纹理)?明暗对比是否自然(暗部有细节、亮部不曝)?
  1637. - 灯光营造的氛围(如静谧感)是否与空间功能(客餐厅、厨房)的使用场景契合?
  1638. **三、颜色维度分析**
  1639. 拆解软装的色彩系统:
  1640. - 主色调、辅助色、点缀色的占比是否符合"6:3:1"原则?请详细列出各色彩及占比。
  1641. - 整体色调(低饱和、暖调)是否统一?不同区域的色彩是否存在"跳脱感"?
  1642. - 颜色是否强化了材质质感(如木色的暖调+实木的温润、水泥灰的冷调+水泥的粗粝)?
  1643. - 冷暖色(木色/藤编的暖 vs 水泥/黑色的冷)的占比是否均衡?有无"冷暖失衡"问题?
  1644. **四、像素维度评价**
  1645. - 图片像素是否≥1920×1080px(2K)?放大后软装细节(如藤编纹理、木纹)是否清晰?
  1646. - 图片是否为无损格式(如PNG/TIF)?有无压缩导致的"模糊/噪点"?
  1647. - 分辨率是否≥72dpi(屏幕展示)/300dpi(打印)?
  1648. - 软装的微小元素(如玻璃器皿的纹理、餐具的细节)是否被清晰捕捉?
  1649. **五、整体适配性评估**
  1650. - 软装风格(如侘寂、工业混搭、现代简约)是否贯穿所有区域?有无"风格割裂"?
  1651. - 家具尺寸(如餐桌长度、沙发体量)与空间层高/面积是否协调?有无"过大/过小"导致的空间压抑/空洞?
  1652. - 软装是否兼顾实用性(如储物、动线流畅)与装饰性?请举例说明功能与美学的平衡方式。
  1653. - 软装传递的情感基调(松弛、质朴、温馨、静谧)是否在所有区域统一?
  1654. 请按以下JSON格式输出分析结果(确保所有字段都填写完整):`;
  1655. const outputSchema = `{
  1656. "materialDimension": {
  1657. "materialTypes": [
  1658. { "name": "实木", "proportion": 30, "area": "餐桌、柜体" },
  1659. { "name": "水泥", "proportion": 25, "area": "立柱、墙面" },
  1660. { "name": "藤编", "proportion": 15, "area": "餐椅" },
  1661. { "name": "大理石", "proportion": 15, "area": "台面" },
  1662. { "name": "玻璃", "proportion": 10, "area": "器皿、窗户" },
  1663. { "name": "金属", "proportion": 5, "area": "灯具、五金" }
  1664. ],
  1665. "materialBalance": "材质占比相对均衡,主材实木与水泥形成对比,辅材藤编、大理石、玻璃丰富层次,无明显失衡。",
  1666. "textureContrast": {
  1667. "hardMaterials": ["水泥立柱", "大理石台面", "玻璃"],
  1668. "softMaterials": ["实木餐桌", "藤编椅", "布艺装饰"],
  1669. "contrastEffect": "硬材质(水泥的粗粝、大理石的冷峻)与软材质(实木的温润、藤编的柔和)形成'冷暖对比'和'刚柔平衡',营造侘寂风格的质朴感与精致感并存。"
  1670. },
  1671. "textureDetails": {
  1672. "clarity": "肌理呈现清晰,水泥立柱的粗糙斑驳、实木的自然木纹、藤编的编织纹理均可辨识,无模糊或失真。",
  1673. "homogenization": false,
  1674. "description": "各材质保持独特肌理:水泥呈现原生粗糙感,实木纹理自然流畅,藤编编织层次分明,大理石光泽温润,玻璃透明通透,无材质同质化问题。"
  1675. },
  1676. "materialEcho": "实木元素在餐桌与柜体间呼应,水泥在立柱与墙面间延续,形成视觉统一;藤编椅与木色系呼应,强化暖调基底。"
  1677. },
  1678. "lightingDimension": {
  1679. "lightSources": {
  1680. "natural": ["客厅落地窗", "厨房侧窗"],
  1681. "artificial": ["餐厅条形吊灯", "厨房筒灯", "客厅壁灯"],
  1682. "distribution": "光源分布合理,自然光覆盖主要活动区,人工光补充暗部,无明显死角。",
  1683. "hierarchy": "主光源为餐厅吊灯与自然光,辅助光为筒灯与壁灯,层次清晰,形成视觉焦点。"
  1684. },
  1685. "colorTemperature": {
  1686. "temperature": "暖白光(约3000-3500K)",
  1687. "materialMatch": "暖白光与实木、藤编等暖色材质匹配度高,强化温润质感;与水泥、大理石冷材质形成对比但不冲突。",
  1688. "conflict": false
  1689. },
  1690. "lightShadow": {
  1691. "focusPoints": ["餐桌木纹光泽", "藤编椅纹理", "大理石台面反光"],
  1692. "contrastNaturalness": "明暗对比自然,亮部(餐桌、台面)不曝光,暗部(水泥柱背面)保留细节,过渡柔和。",
  1693. "shadowQuality": "阴影自然,水泥柱投影清晰但不生硬,符合物理光照逻辑。"
  1694. },
  1695. "atmosphereMatch": "灯光营造静谧、温馨氛围,与客餐厅休闲功能、厨房实用功能契合度高。"
  1696. },
  1697. "colorDimension": {
  1698. "colorHierarchy": {
  1699. "primary": [
  1700. { "color": "米白/原木色", "proportion": 60 }
  1701. ],
  1702. "secondary": [
  1703. { "color": "水泥灰", "proportion": 25 },
  1704. { "color": "黑色(家具框架)", "proportion": 5 }
  1705. ],
  1706. "accent": [
  1707. { "color": "玻璃透明", "proportion": 5 },
  1708. { "color": "绿植点缀", "proportion": 3 },
  1709. { "color": "花瓶蓝调", "proportion": 2 }
  1710. ],
  1711. "ratio631": true,
  1712. "ratio631Analysis": "主色调米白/木色占比约60%,辅助色水泥灰+黑色约30%,点缀色玻璃+绿植+蓝调约10%,符合6:3:1原则,色彩层次分明。"
  1713. },
  1714. "colorTone": {
  1715. "overallTone": "低饱和暖调为主,米白、木色、藤编营造温润基底,水泥灰、黑色提供冷调平衡。",
  1716. "consistency": true,
  1717. "jumpingIssue": false
  1718. },
  1719. "colorMaterialRelation": "木色的暖调强化了实木的温润质感,水泥灰的冷调凸显了水泥的粗粝质朴,藤编的黄调增添了手工感,色彩与材质相互强化。",
  1720. "colorBalance": {
  1721. "warmColors": ["米白", "原木色", "藤编黄", "暖白光"],
  1722. "coolColors": ["水泥灰", "黑色", "玻璃透明"],
  1723. "balance": "暖色占比约65%,冷色约35%,冷暖平衡合理,暖色主导但不失稳重,冷色点缀但不压抑。",
  1724. "imbalanceIssue": false
  1725. }
  1726. },
  1727. "pixelDimension": {
  1728. "pixelSize": {
  1729. "width": 2400,
  1730. "height": 1600,
  1731. "meets2K": true,
  1732. "detailClarity": "放大后藤编纹理、木纹、水泥斑驳均清晰可辨,无明显像素化或模糊。"
  1733. },
  1734. "imageQuality": {
  1735. "format": "JPEG",
  1736. "isLossless": false,
  1737. "compressionIssue": false,
  1738. "qualityDescription": "画质良好,虽为JPEG有损格式,但压缩率适中,无明显噪点或色块,细节保留完整。"
  1739. },
  1740. "resolution": {
  1741. "dpi": 72,
  1742. "meetsScreen": true,
  1743. "meetsPrint": false
  1744. },
  1745. "detailPresentation": "微小元素如玻璃器皿的透明质感、餐具的金属光泽、绿植叶脉均被清晰捕捉,细节呈现优秀。"
  1746. },
  1747. "overallAdaptability": {
  1748. "styleConsistency": {
  1749. "style": "侘寂 + 工业混搭",
  1750. "consistency": true,
  1751. "fragmentation": false
  1752. },
  1753. "proportionMatch": {
  1754. "furnitureSizes": [
  1755. { "name": "餐桌", "size": "长约2.2m", "suitability": "与层高2.8m、开放式空间协调,无压抑感" },
  1756. { "name": "藤编椅", "size": "高约0.45m", "suitability": "与餐桌高度匹配,体量适中" },
  1757. { "name": "沙发", "size": "三人位", "suitability": "与客厅面积协调,无空洞感" }
  1758. ],
  1759. "spaceCoordination": "家具尺寸与空间层高、面积协调性高,餐桌长度适配开放式布局,沙发体量填充客厅但不拥挤。",
  1760. "sizeIssue": false
  1761. },
  1762. "functionAesthetics": {
  1763. "practicalExamples": ["餐边柜提供储物", "开放式布局优化动线", "厨房台面满足操作需求"],
  1764. "decorativeExamples": ["藤编椅增添手工感", "玻璃器皿点缀", "绿植提升自然氛围"],
  1765. "balanceMethod": "功能性通过储物、动线优化体现,装饰性通过材质对比、色彩搭配、手工元素呈现,两者相互融合,实用与美观并重。"
  1766. },
  1767. "atmosphereConsistency": {
  1768. "emotionalTone": "松弛、质朴、静谧、温馨",
  1769. "consistency": true,
  1770. "inconsistencyDescription": null
  1771. }
  1772. },
  1773. "overallScore": 92,
  1774. "strengths": [
  1775. "材质搭配丰富且均衡,硬软对比明显,呈现侘寂美学",
  1776. "色彩符合6:3:1原则,冷暖平衡合理,层次分明",
  1777. "灯光层次清晰,暖白光与材质匹配度高,氛围营造到位",
  1778. "家具尺寸与空间协调,功能与美学平衡良好",
  1779. "风格统一,侘寂+工业混搭贯穿始终,无割裂感"
  1780. ],
  1781. "improvements": [
  1782. "像素分辨率为72dpi,满足屏幕展示但不适合高精度打印,建议提升至300dpi",
  1783. "JPEG格式为有损压缩,建议保存PNG/TIF无损版本以保留最佳细节",
  1784. "点缀色占比略少,可适当增加绿植或装饰品丰富视觉层次"
  1785. ]
  1786. }`;
  1787. try {
  1788. const result = await this.callCompletionJSON(
  1789. prompt,
  1790. outputSchema,
  1791. (content) => {
  1792. console.log('🎨 软装分析进度:', content?.length || 0);
  1793. },
  1794. 2,
  1795. {
  1796. model: this.MODEL,
  1797. vision: true,
  1798. images: [imageUrl]
  1799. }
  1800. );
  1801. console.log('✅ 软装专业分析完成');
  1802. return result;
  1803. } catch (error) {
  1804. console.error('❌ 软装分析失败:', error);
  1805. return undefined;
  1806. }
  1807. }
  1808. /**
  1809. * 🔥 渲染专业分析(基于行业标准的三大维度分析)
  1810. * 包含:像素清晰度、色彩精细度、灯光氛围三大维度
  1811. */
  1812. async analyzeRendering(
  1813. imageUrl: string,
  1814. file: File,
  1815. basicInfo?: { dimensions: { width: number; height: number } }
  1816. ): Promise<ImageAnalysisResult['renderingAnalysis']> {
  1817. console.log('🎬 开始渲染专业分析...');
  1818. if (!basicInfo) {
  1819. basicInfo = await this.getImageBasicInfo(file);
  1820. }
  1821. const prompt = `你是一位资深的室内渲染图质量分析专家。请基于以下专业标准对这张渲染图进行全面、精确的三大维度分析:
  1822. **一、像素大小与清晰度维度分析**
  1823. 从渲染图的视觉细节判断像素级别和清晰度:
  1824. 1. **像素级别判断**:
  1825. - preview(小图预览级):约800-1200像素宽,适合快速预览
  1826. - standard(标准级):约1500-1920像素宽,适合一般展示
  1827. - high(高清级):约2000-2500像素宽,适合专业展示
  1828. - ultra(超高清级):约3000-4000像素宽,适合印刷
  1829. - print(印刷级):≥4000像素宽,适合高精度印刷
  1830. 2. **细节保留度评估**:
  1831. - 基础结构清晰度:沙发轮廓、柜体线条、墙面接缝等基础结构是否清晰
  1832. - 精细纹理清晰度:藤编座椅的编织纹路、木纹的自然结疤、金属拉丝纹理等精细材质是否清晰
  1833. - 边缘锐度:物品边缘、家具线条的锐度是否足够
  1834. - 是否存在轻微模糊或像素块感
  1835. 3. **放大损耗评估**:
  1836. - 局部放大后(如茶几桌面、桌面物品)是否出现像素块感
  1837. - 高频细节(如物品边缘锐度)的衰减程度
  1838. - 放大适用性评价
  1839. **二、色彩精细程度维度评估**
  1840. 分析渲染图的色彩风格和精细度:
  1841. 1. **色彩风格识别**:
  1842. - 自然低饱和系、高饱和系、单色调系等
  1843. - 主导色彩识别(如木色、米白、浅灰等)
  1844. 2. **色域覆盖分析**:
  1845. - 色彩空间判断(sRGB、Adobe RGB等)
  1846. - 饱和度范围(低饱和度、中饱和度、高饱和度)
  1847. - 色域集中区域
  1848. 3. **色彩还原精度**:
  1849. - 材质色彩(如木质柜体、沙发面料、墙面)与真实材质的色差值ΔE评估(参考CQS标准)
  1850. - ΔE≤2:专业级色彩还原
  1851. - ΔE 3-5:中阶写实级色彩还原
  1852. - ΔE>5:基础色彩还原
  1853. - 不同材质的色彩区分能力
  1854. 4. **色彩层次过渡**:
  1855. - 同色系的层次过渡细腻度(如墙面阴影的灰度变化)
  1856. - 过渡级数评估(是否需要增加过渡层次)
  1857. 5. **色彩一致性**:
  1858. - 跨图片/区域的色彩统一性
  1859. - 金属、玻璃等材质的反光色彩是否融合环境色(如木色、白色)
  1860. - 环境色融合细节评价
  1861. **三、灯光氛围维度分析**
  1862. 评估灯光设计和氛围营造:
  1863. 1. **灯光风格识别**:
  1864. - 柔和自然系、戏剧化、工业风等灯光风格
  1865. - 氛围营造等级(basic/good/excellent/master)
  1866. 2. **光源类型分析**:
  1867. - 主光源:窗外漫射自然光、直射光等
  1868. - 辅助光源:间接照明(吊顶灯带、墙面壁灯)、装饰光源
  1869. 3. **光影层次评估**:
  1870. - 整体明暗对比度(如1:4、1:6等)
  1871. - 阴影过渡自然度(如沙发底部、柜体侧面)
  1872. - 核心问题识别:
  1873. * 光源指向性是否清晰
  1874. * 主光源位置是否明确
  1875. * 高光区域(如桌面物品、玻璃器皿)的光斑形态是否清晰
  1876. * 是否缺乏"硬光点缀"(如窗外直射光的局部亮斑)
  1877. * 空间立体感是否充足
  1878. 4. **氛围适配度**:
  1879. - 灯光色温(如4000K暖白光)
  1880. - 与空间定位的契合度(如简约舒适、高级奢华等)
  1881. - 装饰光源的氛围感输出:
  1882. * 壁灯光晕范围是否足够
  1883. * 落地灯效果是否明显
  1884. * 是否形成局部柔和光区
  1885. 5. **优化方向**:
  1886. - 像素提升建议:是否需要提升至2000+/8K超高清
  1887. - 色彩优化建议:色差值ΔE目标、同色系过渡层次增加等
  1888. - 灯光优化建议:增加直射光光斑、扩大光晕范围、增强光源指向性等
  1889. 请按以下JSON格式输出分析结果(确保所有字段都填写完整):`;
  1890. const outputSchema = `{
  1891. "pixelClarityDimension": {
  1892. "pixelLevel": "preview",
  1893. "estimatedSize": {
  1894. "width": 1000,
  1895. "height": 600,
  1896. "description": "小图预览级,约1000×600像素,适合渲染阶段快速输出"
  1897. },
  1898. "detailRetention": {
  1899. "structureClarity": "基础结构(沙发轮廓、柜体线条、墙面接缝)清晰,主体结构完整",
  1900. "textureClarity": "精细纹理(藤编编织纹路、木纹结疤、金属拉丝)存在轻微模糊,未达到2000+像素精度",
  1901. "edgeSharpness": "物品边缘锐度中等,主体清晰但精细边缘略显柔和",
  1902. "blurIssue": true,
  1903. "blurDescription": "放大后局部区域(如茶几桌面、装饰品细节)存在轻微模糊,高频细节保留不足"
  1904. },
  1905. "scaleLoss": {
  1906. "pixelBlockEffect": true,
  1907. "highFrequencyLoss": "局部放大后像素块感明显,高频细节(物品边缘、纹理微结构)衰减较快",
  1908. "enlargeSuitability": "适合屏幕小尺寸预览,不适合大幅放大或印刷使用"
  1909. },
  1910. "optimizationSuggestions": [
  1911. "提升像素至2500像素宽(高清级),保留藤编纹理、木纹结疤等精细材质细节",
  1912. "增强边缘锐度,消除像素模糊,实现印刷级细节精度",
  1913. "如需8K超高清,建议提升至3500-4000像素宽"
  1914. ]
  1915. },
  1916. "colorRefinementDimension": {
  1917. "colorStyle": "自然低饱和系",
  1918. "refinementLevel": "intermediate",
  1919. "colorGamutCoverage": {
  1920. "dominantColors": ["木色(暖棕/浅柚木)", "米白", "浅灰"],
  1921. "colorSpace": "sRGB",
  1922. "saturationRange": "中低饱和度区域,无高饱和色块",
  1923. "colorDescription": "色域集中在sRGB的中低饱和度区域,以暖色调为主,冷暖平衡"
  1924. },
  1925. "colorAccuracy": {
  1926. "materialColors": [
  1927. {
  1928. "material": "木质柜体",
  1929. "colorDescription": "暖棕色,接近真实木材色彩",
  1930. "deltaE": 3.5
  1931. },
  1932. {
  1933. "material": "沙发面料",
  1934. "colorDescription": "米灰色,与真实布料色差适中",
  1935. "deltaE": 4.0
  1936. },
  1937. {
  1938. "material": "墙面",
  1939. "colorDescription": "浅灰白色,接近真实涂料色彩",
  1940. "deltaE": 3.0
  1941. }
  1942. ],
  1943. "differentiationAbility": "能区分不同材质的色彩差异,但同色系层次感不足",
  1944. "gradientTransition": {
  1945. "smoothness": "墙面阴影的灰度变化过渡不够细腻,层次感略显生硬",
  1946. "gradeLevels": 3
  1947. }
  1948. },
  1949. "colorConsistency": {
  1950. "crossImageConsistency": true,
  1951. "metallicGlassReflection": "金属、玻璃材质的反光色彩(如餐桌金属腿的冷灰反光)缺乏环境色融合细节",
  1952. "environmentColorBlend": false,
  1953. "environmentColorDescription": "金属反光未融合木色/白色环境色,显得略显生硬"
  1954. },
  1955. "optimizationSuggestions": [
  1956. "提升色彩还原精度,目标ΔE≤2(专业级)",
  1957. "增加同色系过渡层次至5-7级(如墙面阴影灰度细分)",
  1958. "金属/玻璃反光融合环境色(木色/白色),增强材质色彩的真实感与层次感",
  1959. "确保sRGB色域100%覆盖"
  1960. ]
  1961. },
  1962. "lightingAtmosphereDimension": {
  1963. "lightingStyle": "柔和自然系氛围光",
  1964. "atmosphereLevel": "good",
  1965. "lightSources": {
  1966. "primary": [
  1967. {
  1968. "type": "窗外漫射自然光",
  1969. "position": "落地窗区域",
  1970. "characteristics": "柔和、均匀,覆盖主要活动区"
  1971. }
  1972. ],
  1973. "auxiliary": [
  1974. {
  1975. "type": "吊顶灯带间接照明",
  1976. "coverage": "顶部区域",
  1977. "effectiveness": "补充暗部,光晕范围略小"
  1978. },
  1979. {
  1980. "type": "墙面壁灯",
  1981. "coverage": "局部墙面",
  1982. "effectiveness": "装饰性光源,氛围感输出不足,光晕范围过小"
  1983. }
  1984. ]
  1985. },
  1986. "lightShadowHierarchy": {
  1987. "contrastRatio": "1:4(柔和对比)",
  1988. "shadowTransition": "阴影过渡自然,沙发底部、柜体侧面阴影柔和",
  1989. "keyIssues": [
  1990. "光源指向性弱,无法明确区分主光源位置",
  1991. "高光区域(如桌面物品、玻璃器皿)光斑形态模糊",
  1992. "缺乏硬光点缀(如窗外直射光的局部亮斑)",
  1993. "空间立体感稍弱"
  1994. ],
  1995. "highlightQuality": {
  1996. "definition": "高光区域清晰度不足,光斑边界模糊",
  1997. "spotShape": "光斑形态不明确,缺乏清晰的光影轮廓",
  1998. "hardLightAccent": false,
  1999. "hardLightDescription": "缺少窗外直射光的硬光点缀,导致空间立体感不足"
  2000. },
  2001. "spatialDepth": "空间立体感稍弱,明暗层次不够丰富"
  2002. },
  2003. "atmosphereAdaptation": {
  2004. "colorTemperature": "4000K暖白光",
  2005. "spacePositioning": "符合简约舒适的空间定位",
  2006. "decorativeLightOutput": {
  2007. "wallLampHalo": "壁灯光晕范围过小,未形成局部柔和光区",
  2008. "floorLampEffect": "落地灯效果不明显,氛围感输出不足",
  2009. "localSoftLightZone": false
  2010. }
  2011. },
  2012. "optimizationSuggestions": [
  2013. "增加15%的窗外直射光光斑(如桌面、沙发扶手区域),增强硬光点缀",
  2014. "吊顶灯带的间接照明光晕范围扩大至墙面30cm",
  2015. "壁灯的暖光光晕形成局部柔和光区,增强装饰性光源的氛围感输出",
  2016. "增强光源指向性,明确主光源位置",
  2017. "提升空间明暗层次与立体感,保留柔和舒适的整体氛围"
  2018. ]
  2019. },
  2020. "overallScore": 75,
  2021. "renderingQualityLevel": "standard",
  2022. "strengths": [
  2023. "基础结构清晰,主体轮廓完整",
  2024. "色彩风格统一,自然低饱和系营造舒适氛围",
  2025. "阴影过渡自然,整体明暗柔和",
  2026. "灯光色温适配,符合空间定位"
  2027. ],
  2028. "improvements": [
  2029. "像素尺寸建议提升至2500像素宽,增强精细纹理清晰度",
  2030. "色彩还原精度建议优化至ΔE≤2,增加同色系过渡层次",
  2031. "增加硬光点缀和光源指向性,提升空间立体感",
  2032. "金属/玻璃反光需融合环境色,增强真实感"
  2033. ],
  2034. "optimizationPrompts": {
  2035. "pixelOptimization": "8K超高清室内渲染图,2500像素宽,保留藤编纹理、木纹结疤、金属拉丝等精细材质细节,边缘锐度提升,消除像素模糊,实现印刷级细节精度。",
  2036. "colorOptimization": "自然低饱和色彩体系,sRGB色域100%覆盖,木质材质色差值ΔE≤2,同色系色彩层次增加5级过渡(如墙面阴影的灰度细分),金属/玻璃反光融合环境色(木色/白色),增强材质色彩的真实感与层次感。",
  2037. "lightingOptimization": "以窗外4000K漫射自然光为主光源,增加15%的直射光光斑(如桌面、沙发扶手区域),吊顶灯带的间接照明光晕范围扩大至墙面30cm,壁灯的暖光光晕形成局部柔和光区,增强光源指向性,提升空间明暗层次与立体感,保留柔和舒适的整体氛围。"
  2038. }
  2039. }`;
  2040. try {
  2041. const result = await this.callCompletionJSON(
  2042. prompt,
  2043. outputSchema,
  2044. (content) => {
  2045. console.log('🎬 渲染分析进度:', content?.length || 0);
  2046. },
  2047. 2,
  2048. {
  2049. model: this.MODEL,
  2050. vision: true,
  2051. images: [imageUrl]
  2052. }
  2053. );
  2054. console.log('✅ 渲染专业分析完成');
  2055. return result;
  2056. } catch (error) {
  2057. console.error('❌ 渲染分析失败:', error);
  2058. return undefined;
  2059. }
  2060. }
  2061. /**
  2062. * 🔥 后期处理专业分析(基于行业标准,与渲染阶段对比)
  2063. * 包含:像素清晰度对比、色彩精细度对比、灯光氛围对比、后期新增细节四大维度
  2064. */
  2065. async analyzePostProcess(
  2066. imageUrl: string,
  2067. file: File,
  2068. basicInfo?: { dimensions: { width: number; height: number } }
  2069. ): Promise<ImageAnalysisResult['postProcessAnalysis']> {
  2070. console.log('🎞️ 开始后期处理专业分析(与渲染阶段对比)...');
  2071. if (!basicInfo) {
  2072. basicInfo = await this.getImageBasicInfo(file);
  2073. }
  2074. const prompt = `你是一位资深的室内后期处理图片分析专家。请基于以下专业标准,对这张后期处理图片进行全面的四大维度对比分析(与前期渲染小图对比):
  2075. **分析框架:对比前期渲染小图与后期成品大图的质变**
  2076. **一、像素与清晰度维度对比**
  2077. **前期渲染小图特征**(800-1200像素宽):
  2078. - 精细纹理(如藤编座椅纹路、木纹结疤)模糊
  2079. - 边缘锐度不足
  2080. - 存在像素块感
  2081. **后期成品大图评估标准**(2000+像素宽):
  2082. 1. **材质细节清晰度**:
  2083. - 藤编的编织肌理是否完全清晰
  2084. - 木质柜体的自然纹理是否可辨识
  2085. - 金属的拉丝质感是否清晰
  2086. - 其他精细材质细节
  2087. 2. **边缘质量**:
  2088. - 边缘线条是否锐利
  2089. - 是否消除像素块感
  2090. - 物品轮廓清晰度
  2091. 3. **印刷/展示适用性**:
  2092. - 是否满足印刷需求
  2093. - 是否适合大幅展示
  2094. **质变描述**:从"预览级"到"成品级"的具体提升
  2095. **二、色彩精细度维度对比**
  2096. **前期渲染小图特征**:
  2097. - 色彩层次单一(同色系过渡仅3级左右)
  2098. - 材质色差值ΔE≈3-5(中阶写实级)
  2099. **后期成品大图评估标准**:
  2100. 1. **色彩层次升级**:
  2101. - 同色系过渡增加至5-8级(如墙面从亮白到阴影灰的渐变)
  2102. - 具体的渐变细节描述
  2103. 2. **材质色彩还原精度**:
  2104. - 材质色差值ΔE是否≤2(专业级)
  2105. - 木色的暖棕/浅柚木区分精准度
  2106. - 各材质的色彩改进描述
  2107. 3. **环境色融合**:
  2108. - 金属/玻璃反光是否融入环境色
  2109. - 具体融合示例(如餐桌金属腿反射出的木色光晕)
  2110. 4. **微色彩细节**:
  2111. - 新增的微色彩肌理(如藤编座椅的浅黄肌理、装饰陶罐的土棕纹理)
  2112. - 这些细节如何提升材质真实感
  2113. **质变描述**:从"中阶写实"到"高还原质感"的具体提升
  2114. **三、灯光氛围维度对比**
  2115. **前期渲染小图问题**:
  2116. - 光源指向性弱
  2117. - 高光光斑模糊
  2118. - 空间立体感不足
  2119. **后期成品大图评估标准**:
  2120. 1. **光源层次明确化**:
  2121. - 主光源(窗外自然光):
  2122. * 漫射光描述
  2123. * 增加的直射光比例(如15%)
  2124. * 直射光光斑的具体区域(如沙发扶手、桌面的局部亮区)
  2125. - 辅助光源(吊顶灯带、壁灯):
  2126. * 光晕范围扩大情况(如壁灯光晕覆盖墙面30cm)
  2127. 2. **阴影质感升级**:
  2128. - 是否保留柔和感
  2129. - 是否新增"微硬边阴影"(如柜体底部、物品边缘)
  2130. - 如何强化空间纵深感
  2131. 3. **氛围细节补充**:
  2132. - 是否新增"环境光反射"
  2133. - 具体反射示例(如地面反射的家具轮廓、墙面反射的灯光暖调)
  2134. - 空间光感自然度
  2135. **质变描述**:从"柔和但平"到"层次化氛围"的具体提升
  2136. **四、后期新增细节维度**
  2137. **前期渲染小图特征**:
  2138. - 物品陈设仅保留基础轮廓
  2139. - 细节模糊(如茶几上的物品模糊)
  2140. **后期成品大图评估标准**:
  2141. 1. **生活化细节**:
  2142. - 识别新增的物品(玻璃杯、书籍、装饰陶罐、植物等)
  2143. - 每个物品的细节描述(如书籍的封面纹理、植物的枝叶细节、玻璃杯的透明质感)
  2144. 2. **真实居住感**:
  2145. - 这些细节如何填充空间的真实居住感
  2146. - 生活化氛围营造
  2147. **质变描述**:从"基础结构"到"生活感填充"的具体提升
  2148. **综合评估**:
  2149. - 后期处理综合评分(0-100分)
  2150. - 后期处理质量等级(good/excellent/master/exceptional)
  2151. - 优点总结
  2152. - 与渲染阶段对比总结
  2153. 请按以下JSON格式输出分析结果(确保所有字段都填写完整):`;
  2154. const outputSchema = `{
  2155. "pixelClarityComparison": {
  2156. "beforeRendering": {
  2157. "pixelRange": "800-1200像素宽",
  2158. "clarityLevel": "预览级",
  2159. "textureIssues": [
  2160. "藤编座椅纹路模糊",
  2161. "木纹结疤不清晰",
  2162. "金属拉丝纹理缺失"
  2163. ],
  2164. "edgeIssues": [
  2165. "边缘锐度不足",
  2166. "局部像素块感明显",
  2167. "物品轮廓软化"
  2168. ]
  2169. },
  2170. "afterPostProcess": {
  2171. "pixelRange": "2000+像素宽(约2400×1440)",
  2172. "clarityLevel": "成品级/展示级",
  2173. "textureQuality": {
  2174. "details": [
  2175. "藤编编织肌理完全清晰,可辨识编织纹路的交错细节",
  2176. "木质柜体的自然纹理、结疤、年轮均清晰可见",
  2177. "金属灯具的拉丝质感、光泽细节完整呈现",
  2178. "布艺装饰的织纹结构清晰"
  2179. ],
  2180. "clarity": "材质细节完全清晰,无模糊或像素损耗"
  2181. },
  2182. "edgeQuality": "边缘线条锐利,物品轮廓清晰,无像素块感,边缘过渡自然",
  2183. "printSuitability": true
  2184. },
  2185. "qualityLeap": "从预览级(800-1200px)提升至成品级(2000+px),材质细节从模糊到完全清晰,边缘从软化到锐利,实现印刷级质量,像素密度提升约67-150%"
  2186. },
  2187. "colorRefinementComparison": {
  2188. "beforeRendering": {
  2189. "gradientLevels": 3,
  2190. "deltaE": 4.0,
  2191. "colorLayers": "色彩层次单一,同色系过渡生硬,缺乏细腻的灰度变化"
  2192. },
  2193. "afterPostProcess": {
  2194. "gradientLevels": 7,
  2195. "deltaE": 1.5,
  2196. "gradientDetails": [
  2197. "墙面从亮白(RGB 245,245,245)到阴影灰(RGB 180,180,180)的7级细腻过渡",
  2198. "地面从浅灰到暗灰的5级自然渐变",
  2199. "木质柜体表面的光影过渡增加至6级"
  2200. ],
  2201. "materialColorAccuracy": [
  2202. {
  2203. "material": "木质柜体",
  2204. "improvement": "暖棕色精准度提升,ΔE从3.5降至1.2,浅柚木与深柚木的色相区分更清晰"
  2205. },
  2206. {
  2207. "material": "沙发面料",
  2208. "improvement": "米灰色还原度提升,ΔE从4.0降至1.5,布料的冷暖调细分更精准"
  2209. },
  2210. {
  2211. "material": "墙面涂料",
  2212. "improvement": "浅灰白色层次感提升,ΔE从3.0降至1.8,阴影区域的灰度细分更丰富"
  2213. }
  2214. ],
  2215. "environmentColorBlend": {
  2216. "enabled": true,
  2217. "examples": [
  2218. "餐桌金属腿反射出的木色光晕(暖黄调),融合了周边木质家具的环境色",
  2219. "玻璃器皿反射的墙面灰白色调,与空间色彩协调统一",
  2220. "地面反射的暖色调灯光,与木质元素的色温相呼应"
  2221. ]
  2222. },
  2223. "microColorDetails": [
  2224. "藤编座椅的浅黄肌理(米黄至淡金的微色差)",
  2225. "装饰陶罐的土棕纹理(褐色至红棕的自然变化)",
  2226. "植物叶片的翠绿至深绿的色彩层次",
  2227. "书籍封面的微妙色彩(米白、浅灰、淡蓝的细微区分)"
  2228. ]
  2229. },
  2230. "qualityLeap": "从中阶写实(ΔE≈4.0,3级过渡)提升至高还原质感(ΔE≈1.5,7级过渡),色彩层次提升133%,材质色彩还原精度提升至专业级,新增环境色融合与微色彩细节"
  2231. },
  2232. "lightingAtmosphereComparison": {
  2233. "beforeRendering": {
  2234. "issues": [
  2235. "光源指向性弱,无法明确主光源位置",
  2236. "高光光斑模糊,缺乏清晰的光影轮廓",
  2237. "空间立体感不足,明暗层次平淡",
  2238. "缺乏硬光点缀,氛围单调"
  2239. ],
  2240. "atmosphereLevel": "柔和但平淡(good级)"
  2241. },
  2242. "afterPostProcess": {
  2243. "lightSourceHierarchy": {
  2244. "primaryLight": {
  2245. "type": "窗外自然光",
  2246. "diffuseLight": "柔和的漫射光覆盖主要活动区,保持整体温馨氛围",
  2247. "directLight": {
  2248. "percentage": 15,
  2249. "spotAreas": [
  2250. "沙发扶手局部亮区(形成明显光斑)",
  2251. "餐桌桌面的局部照射区",
  2252. "茶几表面的高光区域",
  2253. "装饰画框的边缘反光"
  2254. ]
  2255. }
  2256. },
  2257. "auxiliaryLight": {
  2258. "sources": [
  2259. {
  2260. "type": "吊顶灯带间接照明",
  2261. "haloExpansion": "光晕范围从原15cm扩大至墙面30cm,形成更柔和的过渡光区"
  2262. },
  2263. {
  2264. "type": "墙面壁灯",
  2265. "haloExpansion": "暖光光晕覆盖墙面30cm范围,形成局部柔和光区,氛围感提升"
  2266. }
  2267. ]
  2268. }
  2269. },
  2270. "shadowQualityUpgrade": {
  2271. "softTransition": true,
  2272. "microHardEdge": {
  2273. "enabled": true,
  2274. "areas": [
  2275. "柜体底部的微硬边阴影(强化物体接地感)",
  2276. "装饰品边缘的清晰阴影轮廓",
  2277. "家具腿部的投影(增强纵深感)",
  2278. "墙面装饰的明确投影"
  2279. ]
  2280. },
  2281. "spatialDepthEnhancement": "通过微硬边阴影与柔和阴影的结合,空间纵深感显著提升,前后景层次分明"
  2282. },
  2283. "atmosphereDetails": {
  2284. "environmentReflection": {
  2285. "enabled": true,
  2286. "examples": [
  2287. "地面反射的家具轮廓(如沙发底部、柜体底部的模糊反射)",
  2288. "墙面反射的灯光暖调(形成二次光源效果)",
  2289. "玻璃器皿反射的窗外光线",
  2290. "木质桌面反射的顶部光源"
  2291. ]
  2292. },
  2293. "naturalness": "环境光反射自然,光影逻辑符合物理规律,空间光感真实且富有层次"
  2294. }
  2295. },
  2296. "qualityLeap": "从柔和但平(good级)提升至层次化氛围(excellent级),主光源增加15%直射光,辅助光源光晕扩大100%,新增微硬边阴影与环境光反射,空间立体感与光感层次显著提升"
  2297. },
  2298. "postProcessDetailsAddition": {
  2299. "beforeRendering": {
  2300. "detailLevel": "基础结构级,仅保留家具主体轮廓",
  2301. "itemClarity": "茶几上的物品模糊,缺乏细节,装饰品仅保留基础形态"
  2302. },
  2303. "afterPostProcess": {
  2304. "lifeDetails": [
  2305. {
  2306. "item": "玻璃杯",
  2307. "description": "透明玻璃杯的光影折射、杯壁厚度、杯口细节完整呈现,杯中液体(水/饮料)的透明质感清晰"
  2308. },
  2309. {
  2310. "item": "书籍",
  2311. "description": "书籍封面的纹理(布纹/纸质)、书脊的文字、页面的微妙色差、书角的磨损细节"
  2312. },
  2313. {
  2314. "item": "装饰陶罐",
  2315. "description": "陶罐的土棕肌理、手工痕迹、表面的微妙光泽、开口边缘的细节"
  2316. },
  2317. {
  2318. "item": "植物(枝叶/花卉)",
  2319. "description": "植物叶片的脉络、叶缘锯齿、枝干的自然弯曲、叶片的翠绿至深绿渐变"
  2320. },
  2321. {
  2322. "item": "其他装饰品",
  2323. "description": "如相框的金属边框细节、装饰盘的花纹、蜡烛的质感等"
  2324. }
  2325. ],
  2326. "livingAtmosphere": "通过玻璃杯、书籍、植物等生活化物品的细节填充,空间从'展示型'转变为'居住型',真实居住感显著提升,营造出温馨、有生活气息的家居氛围"
  2327. "detailEnhancement": "新增10+项生活化细节,从基础陈设到精细物品,细节丰富度提升约200%,空间叙事性增强"
  2328. },
  2329. "qualityLeap": "从基础结构(仅保留轮廓)提升至生活感填充(精细物品细节),新增玻璃杯、书籍、陶罐、植物等10+项生活化元素,空间从展示型转变为居住型,真实感提升150%"
  2330. },
  2331. "overallScore": 95,
  2332. "postProcessQualityLevel": "master",
  2333. "strengths": [
  2334. "像素密度从预览级提升至成品级,材质细节完全清晰,满足印刷需求",
  2335. "色彩还原精度达专业级(ΔE≤2),色彩层次从3级提升至7级",
  2336. "灯光氛围从柔和但平提升至层次化,新增15%直射光与环境光反射",
  2337. "新增10+项生活化细节,空间真实居住感显著提升",
  2338. "环境色融合自然,微色彩细节丰富,材质真实感强"
  2339. ],
  2340. "comparisonSummary": "后期处理实现了从'预览级渲染小图'到'成品级展示大图'的全方位质变:像素密度提升67-150%(从800-1200px到2000+px),色彩还原精度提升至专业级(ΔE从4.0降至1.5),灯光层次从平淡到丰富(新增15%直射光、微硬边阴影、环境光反射),生活化细节从无到有(新增10+项物品细节),整体从展示型空间转变为居住型空间,真实感与氛围感全面提升。"
  2341. }`;
  2342. try {
  2343. const result = await this.callCompletionJSON(
  2344. prompt,
  2345. outputSchema,
  2346. (content) => {
  2347. console.log('🎞️ 后期处理分析进度:', content?.length || 0);
  2348. },
  2349. 2,
  2350. {
  2351. model: this.MODEL,
  2352. vision: true,
  2353. images: [imageUrl]
  2354. }
  2355. );
  2356. console.log('✅ 后期处理专业分析完成');
  2357. return result;
  2358. } catch (error) {
  2359. console.error('❌ 后期处理分析失败:', error);
  2360. return undefined;
  2361. }
  2362. }
  2363. /**
  2364. * 🚀 压缩图片以加快AI分析速度(大图压缩到1920px宽度)
  2365. */
  2366. private async compressImageForAnalysis(imageUrl: string, maxWidth: number = 1920): Promise<string> {
  2367. return new Promise((resolve, reject) => {
  2368. const img = new Image();
  2369. img.crossOrigin = 'anonymous';
  2370. img.onload = () => {
  2371. try {
  2372. // 如果图片宽度 <= maxWidth,无需压缩,直接转Base64
  2373. if (img.naturalWidth <= maxWidth) {
  2374. console.log(`✅ 图片宽度${img.naturalWidth}px ≤ ${maxWidth}px,无需压缩`);
  2375. // 直接使用原图转Base64
  2376. this.blobToBase64Original(imageUrl).then(resolve).catch(reject);
  2377. return;
  2378. }
  2379. // 计算压缩比例
  2380. const scale = maxWidth / img.naturalWidth;
  2381. const newWidth = maxWidth;
  2382. const newHeight = Math.round(img.naturalHeight * scale);
  2383. console.log(`🔄 压缩图片: ${img.naturalWidth}x${img.naturalHeight} → ${newWidth}x${newHeight}`);
  2384. // 创建Canvas进行压缩
  2385. const canvas = document.createElement('canvas');
  2386. canvas.width = newWidth;
  2387. canvas.height = newHeight;
  2388. const ctx = canvas.getContext('2d');
  2389. if (!ctx) {
  2390. reject(new Error('无法创建Canvas上下文'));
  2391. return;
  2392. }
  2393. // 绘制压缩后的图片
  2394. ctx.drawImage(img, 0, 0, newWidth, newHeight);
  2395. // 转换为Base64(JPEG格式,质量85%)
  2396. const compressedBase64 = canvas.toDataURL('image/jpeg', 0.85);
  2397. console.log(`✅ 压缩完成,Base64长度: ${(compressedBase64.length / 1024 / 1024).toFixed(2)} MB`);
  2398. resolve(compressedBase64);
  2399. } catch (error) {
  2400. console.error('❌ 图片压缩失败:', error);
  2401. reject(error);
  2402. }
  2403. };
  2404. img.onerror = () => {
  2405. reject(new Error('图片加载失败'));
  2406. };
  2407. img.src = imageUrl;
  2408. });
  2409. }
  2410. /**
  2411. * 🔥 将Blob URL转换为Base64(原始方法,供压缩逻辑调用)
  2412. */
  2413. private async blobToBase64Original(blobUrl: string): Promise<string> {
  2414. try {
  2415. const response = await fetch(blobUrl);
  2416. const blob = await response.blob();
  2417. return new Promise<string>((resolve, reject) => {
  2418. const reader = new FileReader();
  2419. reader.onloadend = () => {
  2420. const result = reader.result as string;
  2421. if (result) {
  2422. resolve(result);
  2423. } else {
  2424. reject(new Error('FileReader返回空结果'));
  2425. }
  2426. };
  2427. reader.onerror = () => {
  2428. reject(new Error('FileReader读取失败: ' + reader.error?.message));
  2429. };
  2430. reader.readAsDataURL(blob);
  2431. });
  2432. } catch (error: any) {
  2433. console.error('❌ Blob转Base64失败:', error);
  2434. throw error;
  2435. }
  2436. }
  2437. /**
  2438. * 🔥 将Blob URL转换为Base64(已优化:自动压缩大图)
  2439. * AI模型无法访问blob: URL,需要转换为base64格式
  2440. */
  2441. private async blobToBase64(blobUrl: string): Promise<string> {
  2442. try {
  2443. // 🚀 优化:自动压缩大图,加快AI分析速度
  2444. return await this.compressImageForAnalysis(blobUrl, 1920);
  2445. } catch (error: any) {
  2446. console.error('❌ Blob转Base64失败:', error);
  2447. throw error;
  2448. }
  2449. }
  2450. /**
  2451. * 🚀 快速分析交付图片(返回简化JSON)
  2452. * 专为交付执行阶段优化,快速返回空间和阶段信息
  2453. * 格式: {"space":"客厅","stage":"软装"}
  2454. */
  2455. async quickAnalyzeDeliveryImage(imageUrl: string): Promise<{ space: string; stage: string; confidence?: number }> {
  2456. try {
  2457. console.log('🚀 [快速分析] 开始分析图片...');
  2458. // 调用AI进行快速分析
  2459. const analysisResult = await Parse.Cloud.run('ai-quick-delivery-analysis', {
  2460. imageUrl,
  2461. analysisType: 'quick_delivery'
  2462. });
  2463. console.log('✅ [快速分析] 分析完成:', analysisResult);
  2464. // 返回简化的JSON结果
  2465. return {
  2466. space: analysisResult?.space || '未知空间',
  2467. stage: analysisResult?.stage || 'rendering',
  2468. confidence: analysisResult?.confidence || 0
  2469. };
  2470. } catch (error: any) {
  2471. console.error('❌ [快速分析] 分析失败:', error);
  2472. // 失败时使用基于文件名的快速判断
  2473. return this.quickAnalyzeByFileName(imageUrl);
  2474. }
  2475. }
  2476. /**
  2477. * 🔥 基于文件名快速分析(兜底方案)
  2478. * 当AI分析失败时,根据文件名关键词快速判断
  2479. */
  2480. private quickAnalyzeByFileName(imageUrl: string): { space: string; stage: string; confidence: number } {
  2481. const fileName = imageUrl.toLowerCase();
  2482. // 🔥 阶段判断(优先级:白膜 > 软装 > 渲染 > 后期)
  2483. let stage = 'rendering'; // 默认渲染
  2484. // 白膜关键词(最高优先级)
  2485. if (fileName.includes('白模') || fileName.includes('bm') || fileName.includes('whitemodel') ||
  2486. fileName.includes('模型') || fileName.includes('建模') || fileName.includes('白膜')) {
  2487. stage = 'white_model';
  2488. }
  2489. // 软装关键词
  2490. else if (fileName.includes('软装') || fileName.includes('rz') || fileName.includes('softdecor') ||
  2491. fileName.includes('家具') || fileName.includes('配饰') || fileName.includes('陈设')) {
  2492. stage = 'soft_decor';
  2493. }
  2494. // 后期关键词
  2495. else if (fileName.includes('后期') || fileName.includes('hq') || fileName.includes('postprocess') ||
  2496. fileName.includes('修图') || fileName.includes('精修') || fileName.includes('调色')) {
  2497. stage = 'post_process';
  2498. }
  2499. // 渲染关键词(默认)
  2500. else if (fileName.includes('渲染') || fileName.includes('xr') || fileName.includes('rendering') ||
  2501. fileName.includes('效果图') || fileName.includes('render')) {
  2502. stage = 'rendering';
  2503. }
  2504. // 🔥 空间判断
  2505. let space = '未知空间';
  2506. if (fileName.includes('客厅') || fileName.includes('kt') || fileName.includes('living')) {
  2507. space = '客厅';
  2508. } else if (fileName.includes('卧室') || fileName.includes('ws') || fileName.includes('bedroom') ||
  2509. fileName.includes('主卧') || fileName.includes('次卧')) {
  2510. space = '卧室';
  2511. } else if (fileName.includes('餐厅') || fileName.includes('ct') || fileName.includes('dining')) {
  2512. space = '餐厅';
  2513. } else if (fileName.includes('厨房') || fileName.includes('cf') || fileName.includes('kitchen')) {
  2514. space = '厨房';
  2515. } else if (fileName.includes('卫生间') || fileName.includes('wsj') || fileName.includes('bathroom') ||
  2516. fileName.includes('浴室') || fileName.includes('厕所')) {
  2517. space = '卫生间';
  2518. } else if (fileName.includes('书房') || fileName.includes('sf') || fileName.includes('study')) {
  2519. space = '书房';
  2520. } else if (fileName.includes('阳台') || fileName.includes('yt') || fileName.includes('balcony')) {
  2521. space = '阳台';
  2522. } else if (fileName.includes('玄关') || fileName.includes('xg') || fileName.includes('entrance')) {
  2523. space = '玄关';
  2524. }
  2525. console.log(`🔍 [文件名分析] ${fileName} → 空间: ${space}, 阶段: ${stage}`);
  2526. return {
  2527. space,
  2528. stage,
  2529. confidence: 70 // 基于文件名的分析,置信度设为70%
  2530. };
  2531. }
  2532. }