image-analysis.service.ts 110 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851
  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. "space": "客厅或卧室或厨房或卫生间或餐厅或书房或阳台等",
  748. "stage": "white_model或soft_decor或rendering或post_process"
  749. }
  750. 阶段判断规则(严格执行,从后向前判断):
  751. **第一步:判断是否为post_process(照片级后期)**
  752. ✅ post_process的特征(满足3项以上即为后期):
  753. - 照片级真实感,无法分辨是否为渲染图
  754. - 光影自然柔和,无明显CG痕迹
  755. - 细节丰富真实(布料褶皱、木纹纹理、金属反射)
  756. - 色彩自然,无过度饱和或过度对比
  757. - 景深效果自然(前景清晰,背景自然虚化)
  758. - 材质表现真实(大理石纹理、玻璃透明度、金属质感)
  759. - 整体画面像单反相机拍摄的照片
  760. **第二步:排除post_process后,判断是否为rendering(CG渲染)**
  761. ❌ rendering的特征(明显CG感):
  762. - 明显的计算机渲染痕迹(过于完美、过于规整)
  763. - 光影对比过强或过于均匀(V-Ray/3dsMax典型特征)
  764. - 颜色过于饱和或过于艳丽
  765. - 材质反射过于理想化(过于光滑、过于规则)
  766. - 阴影边缘过于清晰或模糊不自然
  767. **第三步:判断soft_decor和white_model**
  768. - soft_decor: 有材质纹理和色彩,但CG感不强(偏手绘或简单渲染)
  769. - white_model: 灰白色调,无材质细节
  770. **判断原则**:
  771. ⚠️ 如果无法确定是rendering还是post_process,优先选择post_process
  772. ⚠️ 现代高质量渲染图(超写实风格)应归类为post_process
  773. ⚠️ 只有明显看出CG痕迹的才是rendering
  774. 只输出JSON,不要其他内容。`;
  775. const output = `{"space":"客厅","stage":"post_process"}`;
  776. try {
  777. console.log(`⏱️ [快速分析] 开始AI调用,图片Base64大小: ${(imageUrl.length / 1024 / 1024).toFixed(2)} MB`);
  778. // 🚀 添加30秒超时机制
  779. const aiPromise = this.callCompletionJSON(
  780. prompt,
  781. output,
  782. undefined,
  783. 2,
  784. {
  785. model: this.MODEL,
  786. vision: true,
  787. images: [imageUrl],
  788. max_tokens: 200 // 🔥 简化格式,只需200 tokens即可
  789. }
  790. );
  791. const timeoutPromise = new Promise((_, reject) => {
  792. setTimeout(() => reject(new Error('AI分析超时(120秒)')), 120000); // 🔥 增加到120秒,处理大图片
  793. });
  794. const result = await Promise.race([aiPromise, timeoutPromise]) as any;
  795. // 构建完整结果
  796. const megapixels = Math.round((basicInfo.dimensions.width * basicInfo.dimensions.height) / 1000000 * 100) / 100;
  797. const analysisTime = Date.now() - startTime;
  798. console.log(`✅ [快速分析] AI调用完成,耗时: ${(analysisTime / 1000).toFixed(2)}秒`);
  799. console.log(`📊 [快速分析] AI返回结果:`, {
  800. 空间: result.space,
  801. 阶段: result.stage
  802. });
  803. // 🔥 根据阶段类型设置默认质量分数
  804. const defaultQualityScore = {
  805. 'white_model': 60,
  806. 'soft_decor': 75,
  807. 'rendering': 85,
  808. 'post_process': 92
  809. }[result.stage] || 75;
  810. return {
  811. fileName: '',
  812. fileSize: 0,
  813. dimensions: basicInfo.dimensions,
  814. quality: {
  815. score: defaultQualityScore,
  816. level: defaultQualityScore >= 85 ? 'high' : defaultQualityScore >= 70 ? 'medium' : 'low',
  817. sharpness: defaultQualityScore,
  818. brightness: 70,
  819. contrast: 75,
  820. detailLevel: 'basic',
  821. pixelDensity: megapixels >= 2 ? 'high' : 'medium',
  822. textureQuality: defaultQualityScore,
  823. colorDepth: 75
  824. },
  825. content: {
  826. category: result.stage || 'rendering', // 🔥 使用stage作为category
  827. confidence: 90, // 🔥 默认置信度90%
  828. spaceType: result.space || '未识别', // 🔥 使用space作为spaceType
  829. description: `${result.space || ''}室内设计图`,
  830. tags: [],
  831. isArchitectural: true,
  832. hasInterior: true,
  833. hasFurniture: result.stage !== 'white_model',
  834. hasLighting: result.stage === 'rendering' || result.stage === 'post_process',
  835. hasColor: result.stage !== 'white_model',
  836. hasTexture: result.stage !== 'white_model'
  837. },
  838. technical: {
  839. format: 'image/jpeg',
  840. colorSpace: 'sRGB',
  841. dpi: basicInfo.dpi || 72,
  842. aspectRatio: this.calculateAspectRatio(basicInfo.dimensions.width, basicInfo.dimensions.height),
  843. megapixels: megapixels
  844. },
  845. suggestedStage: result.stage || 'rendering', // 🔥 使用stage作为suggestedStage
  846. suggestedReason: `快速分析:${result.space} - ${this.getStageName(result.stage)}`,
  847. analysisTime: analysisTime,
  848. analysisDate: new Date().toISOString()
  849. };
  850. } catch (error: any) {
  851. const analysisTime = Date.now() - startTime;
  852. console.error(`❌ [快速分析] 失败 (耗时${(analysisTime / 1000).toFixed(2)}秒):`, {
  853. 错误类型: error?.name,
  854. 错误信息: error?.message,
  855. 是否超时: error?.message?.includes('超时'),
  856. 图片大小: `${(imageUrl.length / 1024 / 1024).toFixed(2)} MB`
  857. });
  858. throw error;
  859. }
  860. }
  861. /**
  862. * 🔥 超快速分析图片内容(极简版:30秒内返回)
  863. */
  864. private async analyzeImageContent(imageUrl: string): Promise<ImageAnalysisResult['content']> {
  865. const prompt = `你是室内设计图分类专家,请仔细分析这张图片,只输出JSON,不要解释。
  866. JSON格式:
  867. {
  868. "category": "white_model或soft_decor或rendering或post_process",
  869. "confidence": 90,
  870. "spaceType": "客厅或卧室或餐厅或厨房或卫生间或书房",
  871. "description": "一句话描述",
  872. "tags": ["标签1", "标签2"],
  873. "isArchitectural": true,
  874. "hasInterior": true,
  875. "hasFurniture": true,
  876. "hasLighting": true,
  877. "hasColor": true,
  878. "hasTexture": true
  879. }
  880. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
  881. 🔥 阶段判断规则(按顺序严格执行)
  882. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
  883. 【第1优先级】white_model(白模)
  884. 核心特征:
  885. ✅ 材质统一光滑:全部是统一的浅色漆面/灰色漆面
  886. ✅ 无材质细节:看不到木纹、布纹、石材纹理、金属拉丝等细节
  887. ✅ 可以有家具、灯光、阴影(这不影响白模判断!)
  888. ✅ 可以有浅色(浅木色、浅灰色、米白色),只要材质统一光滑
  889. ❌ 典型错误:把"浅色统一材质"误判为"有装饰色彩"
  890. ⚠️ 关键:如果所有表面都是统一的光滑漆面(无纹理细节),就是白模!
  891. 判断标准:
  892. - hasColor = false(统一浅色≠装饰色彩)
  893. - hasTexture = false(光滑漆面≠真实纹理)
  894. - hasLighting = true/false(有无灯光不影响)
  895. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
  896. 【第2优先级】soft_decor(软装)
  897. 核心特征:
  898. ✅ 有真实材质纹理:能看到木纹、布纹、石材纹理等细节
  899. ✅ 有装饰色彩:不同材质有不同颜色(木色、布色、石色)
  900. ❌ 灯光效果弱:光影不明显,无强烈高光
  901. 判断标准:
  902. - hasColor = true(有装饰色彩)
  903. - hasTexture = true(有材质纹理)
  904. - hasLighting = false/弱(灯光效果一般)
  905. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
  906. 【第3优先级】rendering(渲染)
  907. 核心特征:
  908. ✅ CG计算机渲染图:3ds Max、SketchUp、V-Ray等软件渲染
  909. ✅ 有真实材质纹理(木纹、布纹清晰)
  910. ✅ 有装饰色彩(多种材质颜色)
  911. ✅ 灯光效果明显:能看到明显的光影、高光、阴影
  912. ❌ 但质量中等:能看出是CG,不是真实照片
  913. ⚠️ 关键区分:
  914. - 渲染图 = CG感明显,质量70-89分
  915. - 照片 = 照片级真实,质量≥90分
  916. 判断标准:
  917. - hasColor = true
  918. - hasTexture = true
  919. - hasLighting = true(灯光明显)
  920. - 质量分数: 70-89分
  921. - CG感明显(不是真实照片)
  922. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
  923. 【第4优先级】post_process(后期/照片级参考图)
  924. 核心特征:
  925. ✅ 照片级真实感:看起来像真实拍摄的照片,不是CG
  926. ✅ 极致材质纹理:超清晰的木纹、布纹、金属拉丝
  927. ✅ 强烈色彩氛围:丰富的色彩层次、环境反射、色彩融合
  928. ✅ 完美灯光效果:精致的光晕、柔和过渡、环境光反射
  929. ✅ 超高质量:接近或达到摄影级质量
  930. ⚠️ 重要:
  931. - 真实照片 = post_process(即使是客户发的参考图)
  932. - 照片级渲染 = post_process(后期精修到照片级)
  933. - CG渲染 = rendering(能看出是CG)
  934. 判断标准:
  935. - hasColor = true
  936. - hasTexture = true(超清晰)
  937. - hasLighting = true(完美)
  938. - 质量分数: 90-100分
  939. - 照片级真实感(不是普通CG渲染)
  940. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
  941. ⚠️ 最关键的区分要点
  942. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
  943. 白模 vs 软装/渲染:
  944. - 白模:表面光滑,看不到纹理细节(即使有浅色)
  945. - 软装/渲染:能看到清晰的木纹、布纹、石材纹理
  946. 软装 vs 渲染:
  947. - 软装:材质有纹理,但灯光效果弱(无明显光影)
  948. - 渲染:材质有纹理 + 明显的灯光光影效果(但是CG)
  949. 渲染 vs 后期:
  950. - 渲染:CG计算机渲染,能看出是CG(质量70-89分)
  951. - 后期:照片级真实感,像真实拍摄的照片(质量≥85分)
  952. ⚠️ 最关键:
  953. - 如果看起来像真实照片(不是CG) → post_process
  954. - 如果是CG渲染图(能看出是3D渲染) → rendering
  955. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
  956. 请仔细观察图片,严格按照以上规则判断!`;
  957. const output = `{"category":"rendering","confidence":92,"spaceType":"卧室","description":"现代卧室","tags":["卧室","现代"],"isArchitectural":true,"hasInterior":true,"hasFurniture":true,"hasLighting":true,"hasColor":true,"hasTexture":true}`;
  958. try {
  959. const result = await this.callCompletionJSON(
  960. prompt,
  961. output,
  962. undefined, // 移除进度回调,加快速度
  963. 2,
  964. {
  965. model: this.MODEL,
  966. vision: true,
  967. images: [imageUrl]
  968. }
  969. );
  970. // 🔥 确保返回完整的字段
  971. console.log('✅ AI分析成功返回:', {
  972. 类别: result.category,
  973. 置信度: result.confidence,
  974. 空间类型: result.spaceType || '未识别',
  975. 有颜色: result.hasColor,
  976. 有纹理: result.hasTexture,
  977. 有灯光: result.hasLighting
  978. });
  979. return result || {
  980. category: 'unknown',
  981. confidence: 0,
  982. spaceType: '未识别',
  983. description: '无法识别图片内容',
  984. tags: [],
  985. isArchitectural: false,
  986. hasInterior: false,
  987. hasFurniture: false,
  988. hasLighting: false,
  989. hasColor: false,
  990. hasTexture: false
  991. };
  992. } catch (error: any) {
  993. console.error('❌ AI内容分析失败 - 详细错误:', {
  994. 错误类型: error?.constructor?.name,
  995. 错误信息: error?.message,
  996. 错误代码: error?.code || error?.status,
  997. 图片URL: imageUrl,
  998. 错误堆栈: error?.stack?.substring(0, 200)
  999. });
  1000. // 🔥 确保错误返回也包含完整字段
  1001. return {
  1002. category: 'unknown',
  1003. confidence: 0,
  1004. spaceType: '未识别',
  1005. description: `内容分析失败: ${error?.message || '未知错误'}`,
  1006. tags: [],
  1007. isArchitectural: false,
  1008. hasInterior: false,
  1009. hasFurniture: false,
  1010. hasLighting: false,
  1011. hasColor: false,
  1012. hasTexture: false
  1013. };
  1014. }
  1015. }
  1016. /**
  1017. * 🔥 分析图片质量(增强版:包含精细度和像素密度)
  1018. */
  1019. private async analyzeImageQuality(
  1020. imageUrl: string,
  1021. basicInfo: { dimensions: { width: number; height: number } }
  1022. ): Promise<ImageAnalysisResult['quality']> {
  1023. const prompt = `请分析这张室内设计图片的质量,并按以下JSON格式输出:
  1024. {
  1025. "score": "总体质量分数(0-100)",
  1026. "level": "质量等级(low/medium/high/ultra)",
  1027. "sharpness": "清晰度(0-100)",
  1028. "brightness": "亮度(0-100)",
  1029. "contrast": "对比度(0-100)",
  1030. "textureQuality": "纹理质量(0-100)",
  1031. "colorDepth": "色彩深度(0-100)"
  1032. }
  1033. 评估标准:
  1034. - score: 综合质量评分,考虑清晰度、构图、色彩、纹理等
  1035. - level: low(<60分), medium(60-75分), high(75-90分), ultra(>90分)
  1036. - sharpness: 图片清晰度,是否有模糊、噪点、锯齿
  1037. - brightness: 亮度是否适中,不过暗或过亮
  1038. - contrast: 对比度是否合适,层次是否分明
  1039. - textureQuality: 纹理质量,材质细节是否清晰(木纹、布纹、石材等)
  1040. - colorDepth: 色彩深度,色彩过渡是否自然,是否有色带
  1041. 请客观评估图片质量,重点关注专业室内设计图片的标准。`;
  1042. const output = `{
  1043. "score": 75,
  1044. "level": "high",
  1045. "sharpness": 80,
  1046. "brightness": 70,
  1047. "contrast": 75,
  1048. "textureQuality": 75,
  1049. "colorDepth": 80
  1050. }`;
  1051. try {
  1052. const result = await this.callCompletionJSON(
  1053. prompt,
  1054. output,
  1055. undefined, // 移除进度回调,提升分析速度
  1056. 2,
  1057. {
  1058. model: this.MODEL,
  1059. vision: true,
  1060. images: [imageUrl]
  1061. }
  1062. );
  1063. // 🔥 结合图片分辨率和像素密度进行质量调整
  1064. const resolutionScore = this.calculateResolutionScore(basicInfo.dimensions);
  1065. const pixelDensity = this.calculatePixelDensity(basicInfo.dimensions);
  1066. // 🔥 评估内容精细程度
  1067. const detailLevel = await this.evaluateDetailLevel(imageUrl, basicInfo.dimensions);
  1068. // 🔥 综合评分:AI评分(40%) + 分辨率(30%) + 纹理质量(20%) + 色彩深度(10%)
  1069. const adjustedScore = Math.round(
  1070. result.score * 0.4 +
  1071. resolutionScore * 0.3 +
  1072. (result.textureQuality || 50) * 0.2 +
  1073. (result.colorDepth || 50) * 0.1
  1074. );
  1075. console.log('📊 质量分析结果:', {
  1076. AI评分: result.score,
  1077. 分辨率评分: resolutionScore,
  1078. 纹理质量: result.textureQuality,
  1079. 色彩深度: result.colorDepth,
  1080. 综合评分: adjustedScore,
  1081. 像素密度: pixelDensity,
  1082. 精细程度: detailLevel
  1083. });
  1084. return {
  1085. score: adjustedScore,
  1086. level: this.getQualityLevel(adjustedScore),
  1087. sharpness: result.sharpness || 50,
  1088. brightness: result.brightness || 50,
  1089. contrast: result.contrast || 50,
  1090. detailLevel: detailLevel,
  1091. pixelDensity: pixelDensity,
  1092. textureQuality: result.textureQuality || 50,
  1093. colorDepth: result.colorDepth || 50
  1094. };
  1095. } catch (error) {
  1096. console.error('❌ 质量分析失败:', error);
  1097. // 基于分辨率和像素的备选评估
  1098. const resolutionScore = this.calculateResolutionScore(basicInfo.dimensions);
  1099. const pixelDensity = this.calculatePixelDensity(basicInfo.dimensions);
  1100. const megapixels = (basicInfo.dimensions.width * basicInfo.dimensions.height) / 1000000;
  1101. // 根据像素推测精细程度
  1102. let detailLevel: 'minimal' | 'basic' | 'detailed' | 'ultra_detailed' = 'basic';
  1103. if (megapixels >= 8) detailLevel = 'ultra_detailed';
  1104. else if (megapixels >= 2) detailLevel = 'detailed';
  1105. else if (megapixels >= 0.9) detailLevel = 'basic';
  1106. else detailLevel = 'minimal';
  1107. return {
  1108. score: resolutionScore,
  1109. level: this.getQualityLevel(resolutionScore),
  1110. sharpness: 50,
  1111. brightness: 50,
  1112. contrast: 50,
  1113. detailLevel: detailLevel,
  1114. pixelDensity: pixelDensity,
  1115. textureQuality: resolutionScore * 0.8,
  1116. colorDepth: resolutionScore * 0.9
  1117. };
  1118. }
  1119. }
  1120. /**
  1121. * 🔥 基于分辨率和像素密度计算质量分数(更精细)
  1122. */
  1123. private calculateResolutionScore(dimensions: { width: number; height: number }): number {
  1124. const totalPixels = dimensions.width * dimensions.height;
  1125. const megapixels = totalPixels / 1000000;
  1126. // 更精细的像素分级
  1127. if (megapixels >= 33) return 98; // 8K (7680×4320)
  1128. if (megapixels >= 24) return 96; // 6K (6144×3160)
  1129. if (megapixels >= 16) return 94; // 5K (5120×2880)
  1130. if (megapixels >= 8) return 92; // 4K (3840×2160)
  1131. if (megapixels >= 6) return 88; // 2.5K+ (2560×2304)
  1132. if (megapixels >= 4) return 84; // QHD+ (2560×1600)
  1133. if (megapixels >= 2) return 78; // 1080p (1920×1080)
  1134. if (megapixels >= 1) return 68; // 720p+ (1280×720)
  1135. if (megapixels >= 0.5) return 55; // 中等分辨率
  1136. if (megapixels >= 0.3) return 40; // 低分辨率
  1137. return 25; // 极低分辨率
  1138. }
  1139. /**
  1140. * 🔥 计算像素密度等级
  1141. */
  1142. private calculatePixelDensity(dimensions: { width: number; height: number }): 'low' | 'medium' | 'high' | 'ultra_high' {
  1143. const totalPixels = dimensions.width * dimensions.height;
  1144. const megapixels = totalPixels / 1000000;
  1145. if (megapixels >= 8) return 'ultra_high'; // 4K及以上
  1146. if (megapixels >= 2) return 'high'; // 1080p及以上
  1147. if (megapixels >= 0.9) return 'medium'; // 720p及以上
  1148. return 'low'; // 低于720p
  1149. }
  1150. /**
  1151. * 🔥 评估内容精细程度
  1152. */
  1153. private async evaluateDetailLevel(
  1154. imageUrl: string,
  1155. dimensions: { width: number; height: number }
  1156. ): Promise<'minimal' | 'basic' | 'detailed' | 'ultra_detailed'> {
  1157. const prompt = `请评估这张室内设计图片的内容精细程度,并返回JSON:
  1158. {
  1159. "detailLevel": "精细程度(minimal/basic/detailed/ultra_detailed)",
  1160. "textureQuality": "纹理质量评分(0-100)",
  1161. "colorDepth": "色彩深度评分(0-100)",
  1162. "reasoning": "评估理由"
  1163. }
  1164. 评估标准:
  1165. - minimal: 极简图,只有基本轮廓,无细节纹理
  1166. - basic: 基础图,有简单纹理和色彩,细节较少
  1167. - detailed: 详细图,有丰富纹理、材质细节、光影效果
  1168. - ultra_detailed: 超精细图,有极致纹理、真实材质、复杂光影、细微细节
  1169. 重点关注:
  1170. 1. 纹理细节(木纹、布纹、石材纹理等)
  1171. 2. 材质表现(金属反射、玻璃透明度、布料质感等)
  1172. 3. 光影效果(阴影、高光、环境光等)
  1173. 4. 细微元素(装饰品细节、边角处理等)`;
  1174. const output = `{
  1175. "detailLevel": "detailed",
  1176. "textureQuality": 75,
  1177. "colorDepth": 80,
  1178. "reasoning": "图片包含丰富的纹理和材质细节"
  1179. }`;
  1180. try {
  1181. const result = await this.callCompletionJSON(
  1182. prompt,
  1183. output,
  1184. undefined,
  1185. 2,
  1186. {
  1187. model: this.MODEL,
  1188. vision: true,
  1189. images: [imageUrl]
  1190. }
  1191. );
  1192. return result.detailLevel || 'basic';
  1193. } catch (error) {
  1194. console.error('精细程度评估失败:', error);
  1195. // 基于分辨率的备选评估
  1196. const megapixels = (dimensions.width * dimensions.height) / 1000000;
  1197. if (megapixels >= 8) return 'ultra_detailed';
  1198. if (megapixels >= 2) return 'detailed';
  1199. if (megapixels >= 0.9) return 'basic';
  1200. return 'minimal';
  1201. }
  1202. }
  1203. /**
  1204. * 获取质量等级
  1205. */
  1206. private getQualityLevel(score: number): 'low' | 'medium' | 'high' | 'ultra' {
  1207. if (score >= 90) return 'ultra';
  1208. if (score >= 75) return 'high';
  1209. if (score >= 60) return 'medium';
  1210. return 'low';
  1211. }
  1212. /**
  1213. * 计算宽高比
  1214. */
  1215. private calculateAspectRatio(width: number, height: number): string {
  1216. const gcd = (a: number, b: number): number => b === 0 ? a : gcd(b, a % b);
  1217. const divisor = gcd(width, height);
  1218. return `${width / divisor}:${height / divisor}`;
  1219. }
  1220. /**
  1221. * 🔥 确定建议的阶段分类(精细化判断逻辑,避免误判)
  1222. */
  1223. private determineSuggestedStage(
  1224. content: ImageAnalysisResult['content'],
  1225. quality: ImageAnalysisResult['quality']
  1226. ): 'white_model' | 'soft_decor' | 'rendering' | 'post_process' {
  1227. // 🔥 提取关键特征(确保布尔值正确)
  1228. const hasColor = content.hasColor === true;
  1229. const hasTexture = content.hasTexture === true;
  1230. const hasFurniture = content.hasFurniture === true;
  1231. const hasLighting = content.hasLighting === true;
  1232. const megapixels = quality.pixelDensity;
  1233. const detailLevel = quality.detailLevel;
  1234. const qualityScore = quality.score;
  1235. const textureQuality = quality.textureQuality;
  1236. console.log('🎯 阶段判断依据:', {
  1237. AI类别: content.category,
  1238. AI置信度: content.confidence,
  1239. 空间类型: content.spaceType || '未识别',
  1240. 像素密度: megapixels,
  1241. 精细程度: detailLevel,
  1242. 质量分数: qualityScore,
  1243. 纹理质量: textureQuality,
  1244. 有家具: hasFurniture,
  1245. 有灯光: hasLighting,
  1246. 有色彩: hasColor,
  1247. 有纹理: hasTexture
  1248. });
  1249. // 🔥 调试:打印原始content对象
  1250. console.log('🔍 原始AI返回:', JSON.stringify(content, null, 2));
  1251. // 🔥 关键规则1:白模判断(最高优先级!)
  1252. // 白膜的核心:统一材质 + 无装饰彩色 + 无真实纹理(可以有灯光和家具!)
  1253. if (!hasColor && !hasTexture) {
  1254. console.log('🟢 【白模优先规则】材质符合白模特征:无装饰彩色 + 无真实纹理');
  1255. // 🔥 只要无彩色无纹理,就判定为白模(不再考虑其他条件)
  1256. console.log('✅ 判定为白模阶段(最高优先级)');
  1257. return 'white_model';
  1258. }
  1259. // 🔥 关键规则2:后期处理判断(第二优先级)
  1260. // 超高质量 + AI高置信度 = 后期处理
  1261. if (qualityScore >= 90 && content.category === 'post_process' && content.confidence >= 80) {
  1262. console.log('✅ 判定为后期处理阶段:超高质量(≥90分) + AI高置信度判定为后期');
  1263. return 'post_process';
  1264. }
  1265. // 🔥 质量特别高也可能是后期(即使AI不确定)
  1266. if (qualityScore >= 92 && hasColor && hasTexture && hasLighting) {
  1267. console.log('✅ 判定为后期处理阶段:质量极高(≥92分) + 完整特征');
  1268. return 'post_process';
  1269. }
  1270. // 🔥 关键规则3:渲染 vs 软装判断
  1271. // 有彩色和纹理(不是白模),根据灯光效果、质量、CG感判断
  1272. if (hasColor && hasTexture) {
  1273. console.log('🔵 有装饰性色彩和真实纹理,判断软装/渲染/后期');
  1274. // 🔥 优先判断:照片级质量(≥90分)= 后期/照片
  1275. if (qualityScore >= 90) {
  1276. console.log('✅ 判定为后期处理阶段:照片级质量(≥90分),可能是照片或后期精修');
  1277. return 'post_process';
  1278. }
  1279. // 🔥 次优先:AI高置信度判定为post_process
  1280. if (content.category === 'post_process' && content.confidence >= 85 && qualityScore >= 85) {
  1281. console.log('✅ 判定为后期处理阶段:AI高置信度+质量85+分');
  1282. return 'post_process';
  1283. }
  1284. // 🔥 关键改进:AI明确判定为软装时,优先采用
  1285. if (content.category === 'soft_decor' && content.confidence >= 75) {
  1286. console.log('✅ 判定为软装阶段:AI高置信度判定为软装');
  1287. return 'soft_decor';
  1288. }
  1289. // 高质量 + 强灯光 + AI判定为渲染 = 渲染
  1290. if (hasLighting && qualityScore >= 70 && content.category === 'rendering') {
  1291. console.log('✅ 判定为渲染阶段:有彩色材质/纹理 + 强灯光 + AI判定为渲染');
  1292. return 'rendering';
  1293. }
  1294. // 中等质量 + 弱灯光 = 软装
  1295. if (!hasLighting || qualityScore < 75) {
  1296. console.log('✅ 判定为软装阶段:有彩色材质/纹理 + 灯光弱/质量中等');
  1297. return 'soft_decor';
  1298. }
  1299. // 🔥 默认:根据AI判定或默认渲染
  1300. if (content.category === 'soft_decor') {
  1301. console.log('✅ 判定为软装阶段:AI判定(默认)');
  1302. return 'soft_decor';
  1303. }
  1304. console.log('✅ 判定为渲染阶段:有彩色材质/纹理(默认)');
  1305. return 'rendering';
  1306. }
  1307. // 🔥 关键规则4:只有彩色或只有纹理(罕见情况)
  1308. if (hasColor || hasTexture) {
  1309. console.log('⚠️ 只有彩色或只有纹理(罕见),根据灯光判断');
  1310. if (hasLighting && qualityScore >= 75) {
  1311. console.log('✅ 判定为渲染阶段:有灯光 + 中高质量');
  1312. return 'rendering';
  1313. } else {
  1314. console.log('✅ 判定为软装阶段:灯光弱或质量中等');
  1315. return 'soft_decor';
  1316. }
  1317. }
  1318. // 🔥 兜底逻辑(理论上不应该走到这里)
  1319. console.log('⚠️ 未命中主要规则,使用AI结果或默认渲染');
  1320. // 如果AI有高置信度的判断,使用AI结果
  1321. if (content.confidence > 80 && content.category !== 'unknown') {
  1322. console.log(`✅ 兜底:采用AI高置信度(${content.confidence}%)判定: ${content.category}`);
  1323. return content.category as any;
  1324. }
  1325. // 最终兜底:默认渲染
  1326. console.log('✅ 兜底:默认判定为渲染阶段');
  1327. return 'rendering';
  1328. // 旧逻辑(已废弃):
  1329. // if (qualityScore >= 70) {
  1330. // return 'rendering'; // ✗ 错误:白模图也可能高质量
  1331. // } else if (qualityScore >= 50) {
  1332. // return 'soft_decor';
  1333. // } else {
  1334. // return 'white_model';
  1335. // }
  1336. }
  1337. /**
  1338. * 生成分类建议原因
  1339. */
  1340. private generateSuggestionReason(
  1341. content: ImageAnalysisResult['content'],
  1342. quality: ImageAnalysisResult['quality']
  1343. ): string {
  1344. const reasons = [];
  1345. if (content.confidence > 70) {
  1346. reasons.push(`AI识别置信度${content.confidence}%`);
  1347. }
  1348. if (quality.score >= 90) {
  1349. reasons.push('图片质量极高,适合最终展示');
  1350. } else if (quality.score >= 75) {
  1351. reasons.push('图片质量良好');
  1352. } else if (quality.score < 60) {
  1353. reasons.push('图片质量较低,可能为初期阶段');
  1354. }
  1355. if (content.hasLighting) {
  1356. reasons.push('包含灯光效果');
  1357. }
  1358. if (content.hasFurniture) {
  1359. reasons.push('包含家具配置');
  1360. }
  1361. if (!content.hasFurniture && !content.hasLighting) {
  1362. reasons.push('基础结构图,无装饰元素');
  1363. }
  1364. return reasons.join(',') || '基于图片特征综合判断';
  1365. }
  1366. /**
  1367. * 批量分析图片
  1368. */
  1369. async analyzeImages(
  1370. files: { file: File; url: string }[],
  1371. onProgress?: (current: number, total: number, currentFileName: string) => void
  1372. ): Promise<ImageAnalysisResult[]> {
  1373. const results: ImageAnalysisResult[] = [];
  1374. for (let i = 0; i < files.length; i++) {
  1375. const { file, url } = files[i];
  1376. onProgress?.(i + 1, files.length, file.name);
  1377. try {
  1378. const result = await this.analyzeImage(url, file);
  1379. results.push(result);
  1380. } catch (error) {
  1381. console.error(`分析文件 ${file.name} 失败:`, error);
  1382. // 创建一个基础的错误结果
  1383. results.push(this.createErrorResult(file, error as Error));
  1384. }
  1385. }
  1386. return results;
  1387. }
  1388. /**
  1389. * 创建错误结果
  1390. */
  1391. private createErrorResult(file: File, error: Error): ImageAnalysisResult {
  1392. return {
  1393. fileName: file.name,
  1394. fileSize: file.size,
  1395. dimensions: { width: 0, height: 0 },
  1396. quality: {
  1397. score: 0,
  1398. level: 'low',
  1399. sharpness: 0,
  1400. brightness: 0,
  1401. contrast: 0,
  1402. detailLevel: 'minimal',
  1403. pixelDensity: 'low',
  1404. textureQuality: 0,
  1405. colorDepth: 0
  1406. },
  1407. content: {
  1408. category: 'unknown',
  1409. confidence: 0,
  1410. description: `分析失败: ${error.message}`,
  1411. tags: [],
  1412. isArchitectural: false,
  1413. hasInterior: false,
  1414. hasFurniture: false,
  1415. hasLighting: false
  1416. },
  1417. technical: {
  1418. format: file.type,
  1419. colorSpace: 'unknown',
  1420. dpi: 0,
  1421. aspectRatio: '0:0',
  1422. megapixels: 0
  1423. },
  1424. suggestedStage: 'white_model',
  1425. suggestedReason: '分析失败,默认分类',
  1426. analysisTime: 0,
  1427. analysisDate: new Date().toISOString()
  1428. };
  1429. }
  1430. /**
  1431. * 保存分析结果到数据库
  1432. */
  1433. async saveAnalysisResult(
  1434. projectId: string,
  1435. spaceId: string,
  1436. stageType: string,
  1437. analysisResult: ImageAnalysisResult
  1438. ): Promise<void> {
  1439. try {
  1440. // 查询项目
  1441. const projectQuery = new Parse.Query('Project');
  1442. const project = await projectQuery.get(projectId);
  1443. if (!project) {
  1444. throw new Error('项目不存在');
  1445. }
  1446. // 获取现有的date数据
  1447. const dateData = project.get('date') || {};
  1448. // 初始化图片分析数据结构
  1449. if (!dateData.imageAnalysis) {
  1450. dateData.imageAnalysis = {};
  1451. }
  1452. if (!dateData.imageAnalysis[spaceId]) {
  1453. dateData.imageAnalysis[spaceId] = {};
  1454. }
  1455. if (!dateData.imageAnalysis[spaceId][stageType]) {
  1456. dateData.imageAnalysis[spaceId][stageType] = [];
  1457. }
  1458. // 添加分析结果
  1459. dateData.imageAnalysis[spaceId][stageType].push(analysisResult);
  1460. // 保存到项目
  1461. project.set('date', dateData);
  1462. await project.save();
  1463. console.log('图片分析结果已保存到项目数据库');
  1464. } catch (error) {
  1465. console.error('保存分析结果失败:', error);
  1466. throw error;
  1467. }
  1468. }
  1469. /**
  1470. * 🔥 快速生成模拟分析结果(用于开发测试)
  1471. * 根据文件名和空间名称快速生成分析结果,无需调用AI
  1472. */
  1473. generateMockAnalysisResult(
  1474. file: File,
  1475. spaceName?: string,
  1476. stageName?: string
  1477. ): ImageAnalysisResult {
  1478. const fileName = file.name.toLowerCase();
  1479. const fileSize = file.size;
  1480. let suggestedStage: 'white_model' | 'soft_decor' | 'rendering' | 'post_process' = 'white_model';
  1481. let category: 'white_model' | 'soft_decor' | 'rendering' | 'post_process' | 'unknown' = 'white_model';
  1482. let confidence = 75;
  1483. let analysisReason = '基于文件名和特征分析';
  1484. // 增强的关键词匹配
  1485. const stageKeywords = {
  1486. white_model: ['白模', 'white', 'model', '毛坯', '空间', '结构', '框架', '基础'],
  1487. soft_decor: ['软装', 'soft', 'decor', '家具', 'furniture', '装饰', '饰品', '布艺'],
  1488. rendering: ['渲染', 'render', '效果', 'effect', '光照', '材质', '质感'],
  1489. post_process: ['后期', 'post', 'final', '最终', '完成', '成品', '精修', '调色']
  1490. };
  1491. // 分析文件名匹配度
  1492. let maxMatchScore = 0;
  1493. let bestStage = 'white_model';
  1494. Object.entries(stageKeywords).forEach(([stage, keywords]) => {
  1495. const matchScore = keywords.reduce((score, keyword) => {
  1496. if (fileName.includes(keyword)) {
  1497. return score + (keyword.length > 2 ? 2 : 1); // 长关键词权重更高
  1498. }
  1499. return score;
  1500. }, 0);
  1501. if (matchScore > maxMatchScore) {
  1502. maxMatchScore = matchScore;
  1503. bestStage = stage as typeof suggestedStage;
  1504. }
  1505. });
  1506. if (maxMatchScore > 0) {
  1507. suggestedStage = bestStage as 'white_model' | 'soft_decor' | 'rendering' | 'post_process';
  1508. category = bestStage as 'white_model' | 'soft_decor' | 'rendering' | 'post_process';
  1509. confidence = Math.min(75 + maxMatchScore * 5, 95);
  1510. analysisReason = `文件名包含${this.getStageName(bestStage)}相关关键词`;
  1511. }
  1512. // 文件大小分析
  1513. if (fileSize > 8 * 1024 * 1024) { // 大于8MB
  1514. if (suggestedStage === 'white_model') {
  1515. suggestedStage = 'rendering';
  1516. category = 'rendering';
  1517. confidence = Math.min(confidence + 10, 95);
  1518. analysisReason += ',大文件更可能是高质量渲染图';
  1519. }
  1520. } else if (fileSize < 500 * 1024) { // 小于500KB
  1521. if (suggestedStage === 'post_process') {
  1522. suggestedStage = 'white_model';
  1523. category = 'white_model';
  1524. confidence = Math.max(confidence - 10, 60);
  1525. analysisReason += ',小文件更可能是简单的白模图';
  1526. }
  1527. }
  1528. // 根据目标阶段调整
  1529. if (stageName) {
  1530. const targetStageMap: Record<string, typeof suggestedStage> = {
  1531. '白模': 'white_model',
  1532. '软装': 'soft_decor',
  1533. '渲染': 'rendering',
  1534. '后期': 'post_process'
  1535. };
  1536. const targetStage = targetStageMap[stageName];
  1537. if (targetStage && targetStage === suggestedStage) {
  1538. confidence = Math.min(confidence + 15, 98);
  1539. analysisReason += `,与目标阶段一致`;
  1540. }
  1541. }
  1542. const qualityScoreMap = {
  1543. 'white_model': 75,
  1544. 'soft_decor': 82,
  1545. 'rendering': 88,
  1546. 'post_process': 95
  1547. };
  1548. const score = qualityScoreMap[suggestedStage];
  1549. // 生成模拟分析结果
  1550. const result: ImageAnalysisResult = {
  1551. fileName: file.name,
  1552. fileSize: file.size,
  1553. dimensions: {
  1554. width: 1920 + Math.floor(Math.random() * 400), // 模拟不同尺寸
  1555. height: 1080 + Math.floor(Math.random() * 300)
  1556. },
  1557. quality: {
  1558. score: score,
  1559. level: this.getQualityLevel(score),
  1560. sharpness: Math.min(score + Math.floor(Math.random() * 10), 100),
  1561. brightness: Math.max(score - Math.floor(Math.random() * 10), 50),
  1562. contrast: Math.min(score + Math.floor(Math.random() * 8), 100),
  1563. detailLevel: score >= 90 ? 'ultra_detailed' : score >= 75 ? 'detailed' : score >= 60 ? 'basic' : 'minimal',
  1564. pixelDensity: score >= 90 ? 'ultra_high' : score >= 75 ? 'high' : score >= 60 ? 'medium' : 'low',
  1565. textureQuality: Math.min(score + Math.floor(Math.random() * 5), 100),
  1566. colorDepth: Math.min(score + Math.floor(Math.random() * 5), 100)
  1567. },
  1568. content: {
  1569. category: category,
  1570. confidence: confidence,
  1571. description: `${spaceName || '室内空间'}${this.getStageName(suggestedStage)}图`,
  1572. tags: this.generateTags(suggestedStage, spaceName),
  1573. isArchitectural: true,
  1574. hasInterior: true,
  1575. hasFurniture: suggestedStage !== 'white_model',
  1576. hasLighting: suggestedStage === 'rendering' || suggestedStage === 'post_process'
  1577. },
  1578. technical: {
  1579. format: file.type,
  1580. colorSpace: Math.random() > 0.8 ? 'Adobe RGB' : 'sRGB',
  1581. dpi: Math.random() > 0.5 ? 300 : 72,
  1582. aspectRatio: this.calculateAspectRatio(1920, 1080),
  1583. megapixels: Math.round(((1920 * 1080) / 1000000) * 100) / 100
  1584. },
  1585. suggestedStage: suggestedStage,
  1586. suggestedReason: analysisReason,
  1587. analysisTime: 50 + Math.floor(Math.random() * 100),
  1588. analysisDate: new Date().toISOString()
  1589. };
  1590. console.log(`🚀 增强模拟分析结果: ${file.name} -> ${this.getStageName(suggestedStage)}`, {
  1591. confidence: confidence,
  1592. reason: analysisReason,
  1593. fileSize: `${(fileSize / 1024 / 1024).toFixed(1)}MB`
  1594. });
  1595. return result;
  1596. }
  1597. /**
  1598. * 生成标签
  1599. */
  1600. private generateTags(stage: string, spaceName?: string): string[] {
  1601. const baseTags = [this.getStageName(stage), spaceName || '室内', '设计'];
  1602. const stageSpecificTags: Record<string, string[]> = {
  1603. 'white_model': ['建筑', '结构', '空间布局'],
  1604. 'soft_decor': ['家具', '装饰', '色彩搭配'],
  1605. 'rendering': ['渲染', '光影', '材质'],
  1606. 'post_process': ['后期', '色彩调整', '成品']
  1607. };
  1608. return [...baseTags, ...(stageSpecificTags[stage] || [])];
  1609. }
  1610. /**
  1611. * 获取阶段名称
  1612. */
  1613. private getStageName(stageType: string): string {
  1614. const stageMap: { [key: string]: string } = {
  1615. 'white_model': '白模',
  1616. 'soft_decor': '软装',
  1617. 'rendering': '渲染',
  1618. 'post_process': '后期'
  1619. };
  1620. return stageMap[stageType] || stageType;
  1621. }
  1622. /**
  1623. * 🔥 软装专业分析(基于行业标准的多维度分析)
  1624. * 包含:材质、灯光、颜色、像素、整体适配性五大维度
  1625. */
  1626. async analyzeSoftDecor(
  1627. imageUrl: string,
  1628. file: File,
  1629. basicInfo?: { dimensions: { width: number; height: number } }
  1630. ): Promise<ImageAnalysisResult['softDecorAnalysis']> {
  1631. console.log('🎨 开始软装专业分析...');
  1632. if (!basicInfo) {
  1633. basicInfo = await this.getImageBasicInfo(file);
  1634. }
  1635. const prompt = `你是一位资深的室内软装设计分析专家。请基于以下专业标准对这张软装图片进行全面、精确的多维度分析:
  1636. **一、材质维度分析**
  1637. 识别空间内的核心材质(如水泥、实木、藤编、皮革、大理石、玻璃、金属等):
  1638. - 每种材质的占比是否均衡?
  1639. - 硬材质(水泥柱、大理石台面、金属)与软材质(藤编椅、皮革沙发、布艺)如何形成"冷暖/刚柔"的视觉平衡?
  1640. - 材质的原生肌理(如水泥的粗糙感、实木的木纹、藤编的编织纹理)是否被清晰呈现?有无"材质同质化"问题?
  1641. - 不同区域的同类材质(如餐桌木面与柜体木面、水泥柱与地面)是否形成视觉关联?
  1642. **二、灯光维度分析**
  1643. 分析软装与灯光的互动效果:
  1644. - 自然光(窗户)与人工光(条形吊灯、壁灯、筒灯)的分布是否合理?主光源、辅助光的层次是否清晰?
  1645. - 灯光色温(如暖白光)是否与软装材质(如木色、藤编)的质感匹配?有无"色温冲突"(如冷光配暖材质)?
  1646. - 灯光是否突出软装重点(如餐桌的光泽、藤编椅的纹理)?明暗对比是否自然(暗部有细节、亮部不曝)?
  1647. - 灯光营造的氛围(如静谧感)是否与空间功能(客餐厅、厨房)的使用场景契合?
  1648. **三、颜色维度分析**
  1649. 拆解软装的色彩系统:
  1650. - 主色调、辅助色、点缀色的占比是否符合"6:3:1"原则?请详细列出各色彩及占比。
  1651. - 整体色调(低饱和、暖调)是否统一?不同区域的色彩是否存在"跳脱感"?
  1652. - 颜色是否强化了材质质感(如木色的暖调+实木的温润、水泥灰的冷调+水泥的粗粝)?
  1653. - 冷暖色(木色/藤编的暖 vs 水泥/黑色的冷)的占比是否均衡?有无"冷暖失衡"问题?
  1654. **四、像素维度评价**
  1655. - 图片像素是否≥1920×1080px(2K)?放大后软装细节(如藤编纹理、木纹)是否清晰?
  1656. - 图片是否为无损格式(如PNG/TIF)?有无压缩导致的"模糊/噪点"?
  1657. - 分辨率是否≥72dpi(屏幕展示)/300dpi(打印)?
  1658. - 软装的微小元素(如玻璃器皿的纹理、餐具的细节)是否被清晰捕捉?
  1659. **五、整体适配性评估**
  1660. - 软装风格(如侘寂、工业混搭、现代简约)是否贯穿所有区域?有无"风格割裂"?
  1661. - 家具尺寸(如餐桌长度、沙发体量)与空间层高/面积是否协调?有无"过大/过小"导致的空间压抑/空洞?
  1662. - 软装是否兼顾实用性(如储物、动线流畅)与装饰性?请举例说明功能与美学的平衡方式。
  1663. - 软装传递的情感基调(松弛、质朴、温馨、静谧)是否在所有区域统一?
  1664. 请按以下JSON格式输出分析结果(确保所有字段都填写完整):`;
  1665. const outputSchema = `{
  1666. "materialDimension": {
  1667. "materialTypes": [
  1668. { "name": "实木", "proportion": 30, "area": "餐桌、柜体" },
  1669. { "name": "水泥", "proportion": 25, "area": "立柱、墙面" },
  1670. { "name": "藤编", "proportion": 15, "area": "餐椅" },
  1671. { "name": "大理石", "proportion": 15, "area": "台面" },
  1672. { "name": "玻璃", "proportion": 10, "area": "器皿、窗户" },
  1673. { "name": "金属", "proportion": 5, "area": "灯具、五金" }
  1674. ],
  1675. "materialBalance": "材质占比相对均衡,主材实木与水泥形成对比,辅材藤编、大理石、玻璃丰富层次,无明显失衡。",
  1676. "textureContrast": {
  1677. "hardMaterials": ["水泥立柱", "大理石台面", "玻璃"],
  1678. "softMaterials": ["实木餐桌", "藤编椅", "布艺装饰"],
  1679. "contrastEffect": "硬材质(水泥的粗粝、大理石的冷峻)与软材质(实木的温润、藤编的柔和)形成'冷暖对比'和'刚柔平衡',营造侘寂风格的质朴感与精致感并存。"
  1680. },
  1681. "textureDetails": {
  1682. "clarity": "肌理呈现清晰,水泥立柱的粗糙斑驳、实木的自然木纹、藤编的编织纹理均可辨识,无模糊或失真。",
  1683. "homogenization": false,
  1684. "description": "各材质保持独特肌理:水泥呈现原生粗糙感,实木纹理自然流畅,藤编编织层次分明,大理石光泽温润,玻璃透明通透,无材质同质化问题。"
  1685. },
  1686. "materialEcho": "实木元素在餐桌与柜体间呼应,水泥在立柱与墙面间延续,形成视觉统一;藤编椅与木色系呼应,强化暖调基底。"
  1687. },
  1688. "lightingDimension": {
  1689. "lightSources": {
  1690. "natural": ["客厅落地窗", "厨房侧窗"],
  1691. "artificial": ["餐厅条形吊灯", "厨房筒灯", "客厅壁灯"],
  1692. "distribution": "光源分布合理,自然光覆盖主要活动区,人工光补充暗部,无明显死角。",
  1693. "hierarchy": "主光源为餐厅吊灯与自然光,辅助光为筒灯与壁灯,层次清晰,形成视觉焦点。"
  1694. },
  1695. "colorTemperature": {
  1696. "temperature": "暖白光(约3000-3500K)",
  1697. "materialMatch": "暖白光与实木、藤编等暖色材质匹配度高,强化温润质感;与水泥、大理石冷材质形成对比但不冲突。",
  1698. "conflict": false
  1699. },
  1700. "lightShadow": {
  1701. "focusPoints": ["餐桌木纹光泽", "藤编椅纹理", "大理石台面反光"],
  1702. "contrastNaturalness": "明暗对比自然,亮部(餐桌、台面)不曝光,暗部(水泥柱背面)保留细节,过渡柔和。",
  1703. "shadowQuality": "阴影自然,水泥柱投影清晰但不生硬,符合物理光照逻辑。"
  1704. },
  1705. "atmosphereMatch": "灯光营造静谧、温馨氛围,与客餐厅休闲功能、厨房实用功能契合度高。"
  1706. },
  1707. "colorDimension": {
  1708. "colorHierarchy": {
  1709. "primary": [
  1710. { "color": "米白/原木色", "proportion": 60 }
  1711. ],
  1712. "secondary": [
  1713. { "color": "水泥灰", "proportion": 25 },
  1714. { "color": "黑色(家具框架)", "proportion": 5 }
  1715. ],
  1716. "accent": [
  1717. { "color": "玻璃透明", "proportion": 5 },
  1718. { "color": "绿植点缀", "proportion": 3 },
  1719. { "color": "花瓶蓝调", "proportion": 2 }
  1720. ],
  1721. "ratio631": true,
  1722. "ratio631Analysis": "主色调米白/木色占比约60%,辅助色水泥灰+黑色约30%,点缀色玻璃+绿植+蓝调约10%,符合6:3:1原则,色彩层次分明。"
  1723. },
  1724. "colorTone": {
  1725. "overallTone": "低饱和暖调为主,米白、木色、藤编营造温润基底,水泥灰、黑色提供冷调平衡。",
  1726. "consistency": true,
  1727. "jumpingIssue": false
  1728. },
  1729. "colorMaterialRelation": "木色的暖调强化了实木的温润质感,水泥灰的冷调凸显了水泥的粗粝质朴,藤编的黄调增添了手工感,色彩与材质相互强化。",
  1730. "colorBalance": {
  1731. "warmColors": ["米白", "原木色", "藤编黄", "暖白光"],
  1732. "coolColors": ["水泥灰", "黑色", "玻璃透明"],
  1733. "balance": "暖色占比约65%,冷色约35%,冷暖平衡合理,暖色主导但不失稳重,冷色点缀但不压抑。",
  1734. "imbalanceIssue": false
  1735. }
  1736. },
  1737. "pixelDimension": {
  1738. "pixelSize": {
  1739. "width": 2400,
  1740. "height": 1600,
  1741. "meets2K": true,
  1742. "detailClarity": "放大后藤编纹理、木纹、水泥斑驳均清晰可辨,无明显像素化或模糊。"
  1743. },
  1744. "imageQuality": {
  1745. "format": "JPEG",
  1746. "isLossless": false,
  1747. "compressionIssue": false,
  1748. "qualityDescription": "画质良好,虽为JPEG有损格式,但压缩率适中,无明显噪点或色块,细节保留完整。"
  1749. },
  1750. "resolution": {
  1751. "dpi": 72,
  1752. "meetsScreen": true,
  1753. "meetsPrint": false
  1754. },
  1755. "detailPresentation": "微小元素如玻璃器皿的透明质感、餐具的金属光泽、绿植叶脉均被清晰捕捉,细节呈现优秀。"
  1756. },
  1757. "overallAdaptability": {
  1758. "styleConsistency": {
  1759. "style": "侘寂 + 工业混搭",
  1760. "consistency": true,
  1761. "fragmentation": false
  1762. },
  1763. "proportionMatch": {
  1764. "furnitureSizes": [
  1765. { "name": "餐桌", "size": "长约2.2m", "suitability": "与层高2.8m、开放式空间协调,无压抑感" },
  1766. { "name": "藤编椅", "size": "高约0.45m", "suitability": "与餐桌高度匹配,体量适中" },
  1767. { "name": "沙发", "size": "三人位", "suitability": "与客厅面积协调,无空洞感" }
  1768. ],
  1769. "spaceCoordination": "家具尺寸与空间层高、面积协调性高,餐桌长度适配开放式布局,沙发体量填充客厅但不拥挤。",
  1770. "sizeIssue": false
  1771. },
  1772. "functionAesthetics": {
  1773. "practicalExamples": ["餐边柜提供储物", "开放式布局优化动线", "厨房台面满足操作需求"],
  1774. "decorativeExamples": ["藤编椅增添手工感", "玻璃器皿点缀", "绿植提升自然氛围"],
  1775. "balanceMethod": "功能性通过储物、动线优化体现,装饰性通过材质对比、色彩搭配、手工元素呈现,两者相互融合,实用与美观并重。"
  1776. },
  1777. "atmosphereConsistency": {
  1778. "emotionalTone": "松弛、质朴、静谧、温馨",
  1779. "consistency": true,
  1780. "inconsistencyDescription": null
  1781. }
  1782. },
  1783. "overallScore": 92,
  1784. "strengths": [
  1785. "材质搭配丰富且均衡,硬软对比明显,呈现侘寂美学",
  1786. "色彩符合6:3:1原则,冷暖平衡合理,层次分明",
  1787. "灯光层次清晰,暖白光与材质匹配度高,氛围营造到位",
  1788. "家具尺寸与空间协调,功能与美学平衡良好",
  1789. "风格统一,侘寂+工业混搭贯穿始终,无割裂感"
  1790. ],
  1791. "improvements": [
  1792. "像素分辨率为72dpi,满足屏幕展示但不适合高精度打印,建议提升至300dpi",
  1793. "JPEG格式为有损压缩,建议保存PNG/TIF无损版本以保留最佳细节",
  1794. "点缀色占比略少,可适当增加绿植或装饰品丰富视觉层次"
  1795. ]
  1796. }`;
  1797. try {
  1798. const result = await this.callCompletionJSON(
  1799. prompt,
  1800. outputSchema,
  1801. (content) => {
  1802. console.log('🎨 软装分析进度:', content?.length || 0);
  1803. },
  1804. 2,
  1805. {
  1806. model: this.MODEL,
  1807. vision: true,
  1808. images: [imageUrl]
  1809. }
  1810. );
  1811. console.log('✅ 软装专业分析完成');
  1812. return result;
  1813. } catch (error) {
  1814. console.error('❌ 软装分析失败:', error);
  1815. return undefined;
  1816. }
  1817. }
  1818. /**
  1819. * 🔥 渲染专业分析(基于行业标准的三大维度分析)
  1820. * 包含:像素清晰度、色彩精细度、灯光氛围三大维度
  1821. */
  1822. async analyzeRendering(
  1823. imageUrl: string,
  1824. file: File,
  1825. basicInfo?: { dimensions: { width: number; height: number } }
  1826. ): Promise<ImageAnalysisResult['renderingAnalysis']> {
  1827. console.log('🎬 开始渲染专业分析...');
  1828. if (!basicInfo) {
  1829. basicInfo = await this.getImageBasicInfo(file);
  1830. }
  1831. const prompt = `你是一位资深的室内渲染图质量分析专家。请基于以下专业标准对这张渲染图进行全面、精确的三大维度分析:
  1832. **一、像素大小与清晰度维度分析**
  1833. 从渲染图的视觉细节判断像素级别和清晰度:
  1834. 1. **像素级别判断**:
  1835. - preview(小图预览级):约800-1200像素宽,适合快速预览
  1836. - standard(标准级):约1500-1920像素宽,适合一般展示
  1837. - high(高清级):约2000-2500像素宽,适合专业展示
  1838. - ultra(超高清级):约3000-4000像素宽,适合印刷
  1839. - print(印刷级):≥4000像素宽,适合高精度印刷
  1840. 2. **细节保留度评估**:
  1841. - 基础结构清晰度:沙发轮廓、柜体线条、墙面接缝等基础结构是否清晰
  1842. - 精细纹理清晰度:藤编座椅的编织纹路、木纹的自然结疤、金属拉丝纹理等精细材质是否清晰
  1843. - 边缘锐度:物品边缘、家具线条的锐度是否足够
  1844. - 是否存在轻微模糊或像素块感
  1845. 3. **放大损耗评估**:
  1846. - 局部放大后(如茶几桌面、桌面物品)是否出现像素块感
  1847. - 高频细节(如物品边缘锐度)的衰减程度
  1848. - 放大适用性评价
  1849. **二、色彩精细程度维度评估**
  1850. 分析渲染图的色彩风格和精细度:
  1851. 1. **色彩风格识别**:
  1852. - 自然低饱和系、高饱和系、单色调系等
  1853. - 主导色彩识别(如木色、米白、浅灰等)
  1854. 2. **色域覆盖分析**:
  1855. - 色彩空间判断(sRGB、Adobe RGB等)
  1856. - 饱和度范围(低饱和度、中饱和度、高饱和度)
  1857. - 色域集中区域
  1858. 3. **色彩还原精度**:
  1859. - 材质色彩(如木质柜体、沙发面料、墙面)与真实材质的色差值ΔE评估(参考CQS标准)
  1860. - ΔE≤2:专业级色彩还原
  1861. - ΔE 3-5:中阶写实级色彩还原
  1862. - ΔE>5:基础色彩还原
  1863. - 不同材质的色彩区分能力
  1864. 4. **色彩层次过渡**:
  1865. - 同色系的层次过渡细腻度(如墙面阴影的灰度变化)
  1866. - 过渡级数评估(是否需要增加过渡层次)
  1867. 5. **色彩一致性**:
  1868. - 跨图片/区域的色彩统一性
  1869. - 金属、玻璃等材质的反光色彩是否融合环境色(如木色、白色)
  1870. - 环境色融合细节评价
  1871. **三、灯光氛围维度分析**
  1872. 评估灯光设计和氛围营造:
  1873. 1. **灯光风格识别**:
  1874. - 柔和自然系、戏剧化、工业风等灯光风格
  1875. - 氛围营造等级(basic/good/excellent/master)
  1876. 2. **光源类型分析**:
  1877. - 主光源:窗外漫射自然光、直射光等
  1878. - 辅助光源:间接照明(吊顶灯带、墙面壁灯)、装饰光源
  1879. 3. **光影层次评估**:
  1880. - 整体明暗对比度(如1:4、1:6等)
  1881. - 阴影过渡自然度(如沙发底部、柜体侧面)
  1882. - 核心问题识别:
  1883. * 光源指向性是否清晰
  1884. * 主光源位置是否明确
  1885. * 高光区域(如桌面物品、玻璃器皿)的光斑形态是否清晰
  1886. * 是否缺乏"硬光点缀"(如窗外直射光的局部亮斑)
  1887. * 空间立体感是否充足
  1888. 4. **氛围适配度**:
  1889. - 灯光色温(如4000K暖白光)
  1890. - 与空间定位的契合度(如简约舒适、高级奢华等)
  1891. - 装饰光源的氛围感输出:
  1892. * 壁灯光晕范围是否足够
  1893. * 落地灯效果是否明显
  1894. * 是否形成局部柔和光区
  1895. 5. **优化方向**:
  1896. - 像素提升建议:是否需要提升至2000+/8K超高清
  1897. - 色彩优化建议:色差值ΔE目标、同色系过渡层次增加等
  1898. - 灯光优化建议:增加直射光光斑、扩大光晕范围、增强光源指向性等
  1899. 请按以下JSON格式输出分析结果(确保所有字段都填写完整):`;
  1900. const outputSchema = `{
  1901. "pixelClarityDimension": {
  1902. "pixelLevel": "preview",
  1903. "estimatedSize": {
  1904. "width": 1000,
  1905. "height": 600,
  1906. "description": "小图预览级,约1000×600像素,适合渲染阶段快速输出"
  1907. },
  1908. "detailRetention": {
  1909. "structureClarity": "基础结构(沙发轮廓、柜体线条、墙面接缝)清晰,主体结构完整",
  1910. "textureClarity": "精细纹理(藤编编织纹路、木纹结疤、金属拉丝)存在轻微模糊,未达到2000+像素精度",
  1911. "edgeSharpness": "物品边缘锐度中等,主体清晰但精细边缘略显柔和",
  1912. "blurIssue": true,
  1913. "blurDescription": "放大后局部区域(如茶几桌面、装饰品细节)存在轻微模糊,高频细节保留不足"
  1914. },
  1915. "scaleLoss": {
  1916. "pixelBlockEffect": true,
  1917. "highFrequencyLoss": "局部放大后像素块感明显,高频细节(物品边缘、纹理微结构)衰减较快",
  1918. "enlargeSuitability": "适合屏幕小尺寸预览,不适合大幅放大或印刷使用"
  1919. },
  1920. "optimizationSuggestions": [
  1921. "提升像素至2500像素宽(高清级),保留藤编纹理、木纹结疤等精细材质细节",
  1922. "增强边缘锐度,消除像素模糊,实现印刷级细节精度",
  1923. "如需8K超高清,建议提升至3500-4000像素宽"
  1924. ]
  1925. },
  1926. "colorRefinementDimension": {
  1927. "colorStyle": "自然低饱和系",
  1928. "refinementLevel": "intermediate",
  1929. "colorGamutCoverage": {
  1930. "dominantColors": ["木色(暖棕/浅柚木)", "米白", "浅灰"],
  1931. "colorSpace": "sRGB",
  1932. "saturationRange": "中低饱和度区域,无高饱和色块",
  1933. "colorDescription": "色域集中在sRGB的中低饱和度区域,以暖色调为主,冷暖平衡"
  1934. },
  1935. "colorAccuracy": {
  1936. "materialColors": [
  1937. {
  1938. "material": "木质柜体",
  1939. "colorDescription": "暖棕色,接近真实木材色彩",
  1940. "deltaE": 3.5
  1941. },
  1942. {
  1943. "material": "沙发面料",
  1944. "colorDescription": "米灰色,与真实布料色差适中",
  1945. "deltaE": 4.0
  1946. },
  1947. {
  1948. "material": "墙面",
  1949. "colorDescription": "浅灰白色,接近真实涂料色彩",
  1950. "deltaE": 3.0
  1951. }
  1952. ],
  1953. "differentiationAbility": "能区分不同材质的色彩差异,但同色系层次感不足",
  1954. "gradientTransition": {
  1955. "smoothness": "墙面阴影的灰度变化过渡不够细腻,层次感略显生硬",
  1956. "gradeLevels": 3
  1957. }
  1958. },
  1959. "colorConsistency": {
  1960. "crossImageConsistency": true,
  1961. "metallicGlassReflection": "金属、玻璃材质的反光色彩(如餐桌金属腿的冷灰反光)缺乏环境色融合细节",
  1962. "environmentColorBlend": false,
  1963. "environmentColorDescription": "金属反光未融合木色/白色环境色,显得略显生硬"
  1964. },
  1965. "optimizationSuggestions": [
  1966. "提升色彩还原精度,目标ΔE≤2(专业级)",
  1967. "增加同色系过渡层次至5-7级(如墙面阴影灰度细分)",
  1968. "金属/玻璃反光融合环境色(木色/白色),增强材质色彩的真实感与层次感",
  1969. "确保sRGB色域100%覆盖"
  1970. ]
  1971. },
  1972. "lightingAtmosphereDimension": {
  1973. "lightingStyle": "柔和自然系氛围光",
  1974. "atmosphereLevel": "good",
  1975. "lightSources": {
  1976. "primary": [
  1977. {
  1978. "type": "窗外漫射自然光",
  1979. "position": "落地窗区域",
  1980. "characteristics": "柔和、均匀,覆盖主要活动区"
  1981. }
  1982. ],
  1983. "auxiliary": [
  1984. {
  1985. "type": "吊顶灯带间接照明",
  1986. "coverage": "顶部区域",
  1987. "effectiveness": "补充暗部,光晕范围略小"
  1988. },
  1989. {
  1990. "type": "墙面壁灯",
  1991. "coverage": "局部墙面",
  1992. "effectiveness": "装饰性光源,氛围感输出不足,光晕范围过小"
  1993. }
  1994. ]
  1995. },
  1996. "lightShadowHierarchy": {
  1997. "contrastRatio": "1:4(柔和对比)",
  1998. "shadowTransition": "阴影过渡自然,沙发底部、柜体侧面阴影柔和",
  1999. "keyIssues": [
  2000. "光源指向性弱,无法明确区分主光源位置",
  2001. "高光区域(如桌面物品、玻璃器皿)光斑形态模糊",
  2002. "缺乏硬光点缀(如窗外直射光的局部亮斑)",
  2003. "空间立体感稍弱"
  2004. ],
  2005. "highlightQuality": {
  2006. "definition": "高光区域清晰度不足,光斑边界模糊",
  2007. "spotShape": "光斑形态不明确,缺乏清晰的光影轮廓",
  2008. "hardLightAccent": false,
  2009. "hardLightDescription": "缺少窗外直射光的硬光点缀,导致空间立体感不足"
  2010. },
  2011. "spatialDepth": "空间立体感稍弱,明暗层次不够丰富"
  2012. },
  2013. "atmosphereAdaptation": {
  2014. "colorTemperature": "4000K暖白光",
  2015. "spacePositioning": "符合简约舒适的空间定位",
  2016. "decorativeLightOutput": {
  2017. "wallLampHalo": "壁灯光晕范围过小,未形成局部柔和光区",
  2018. "floorLampEffect": "落地灯效果不明显,氛围感输出不足",
  2019. "localSoftLightZone": false
  2020. }
  2021. },
  2022. "optimizationSuggestions": [
  2023. "增加15%的窗外直射光光斑(如桌面、沙发扶手区域),增强硬光点缀",
  2024. "吊顶灯带的间接照明光晕范围扩大至墙面30cm",
  2025. "壁灯的暖光光晕形成局部柔和光区,增强装饰性光源的氛围感输出",
  2026. "增强光源指向性,明确主光源位置",
  2027. "提升空间明暗层次与立体感,保留柔和舒适的整体氛围"
  2028. ]
  2029. },
  2030. "overallScore": 75,
  2031. "renderingQualityLevel": "standard",
  2032. "strengths": [
  2033. "基础结构清晰,主体轮廓完整",
  2034. "色彩风格统一,自然低饱和系营造舒适氛围",
  2035. "阴影过渡自然,整体明暗柔和",
  2036. "灯光色温适配,符合空间定位"
  2037. ],
  2038. "improvements": [
  2039. "像素尺寸建议提升至2500像素宽,增强精细纹理清晰度",
  2040. "色彩还原精度建议优化至ΔE≤2,增加同色系过渡层次",
  2041. "增加硬光点缀和光源指向性,提升空间立体感",
  2042. "金属/玻璃反光需融合环境色,增强真实感"
  2043. ],
  2044. "optimizationPrompts": {
  2045. "pixelOptimization": "8K超高清室内渲染图,2500像素宽,保留藤编纹理、木纹结疤、金属拉丝等精细材质细节,边缘锐度提升,消除像素模糊,实现印刷级细节精度。",
  2046. "colorOptimization": "自然低饱和色彩体系,sRGB色域100%覆盖,木质材质色差值ΔE≤2,同色系色彩层次增加5级过渡(如墙面阴影的灰度细分),金属/玻璃反光融合环境色(木色/白色),增强材质色彩的真实感与层次感。",
  2047. "lightingOptimization": "以窗外4000K漫射自然光为主光源,增加15%的直射光光斑(如桌面、沙发扶手区域),吊顶灯带的间接照明光晕范围扩大至墙面30cm,壁灯的暖光光晕形成局部柔和光区,增强光源指向性,提升空间明暗层次与立体感,保留柔和舒适的整体氛围。"
  2048. }
  2049. }`;
  2050. try {
  2051. const result = await this.callCompletionJSON(
  2052. prompt,
  2053. outputSchema,
  2054. (content) => {
  2055. console.log('🎬 渲染分析进度:', content?.length || 0);
  2056. },
  2057. 2,
  2058. {
  2059. model: this.MODEL,
  2060. vision: true,
  2061. images: [imageUrl]
  2062. }
  2063. );
  2064. console.log('✅ 渲染专业分析完成');
  2065. return result;
  2066. } catch (error) {
  2067. console.error('❌ 渲染分析失败:', error);
  2068. return undefined;
  2069. }
  2070. }
  2071. /**
  2072. * 🔥 后期处理专业分析(基于行业标准,与渲染阶段对比)
  2073. * 包含:像素清晰度对比、色彩精细度对比、灯光氛围对比、后期新增细节四大维度
  2074. */
  2075. async analyzePostProcess(
  2076. imageUrl: string,
  2077. file: File,
  2078. basicInfo?: { dimensions: { width: number; height: number } }
  2079. ): Promise<ImageAnalysisResult['postProcessAnalysis']> {
  2080. console.log('🎞️ 开始后期处理专业分析(与渲染阶段对比)...');
  2081. if (!basicInfo) {
  2082. basicInfo = await this.getImageBasicInfo(file);
  2083. }
  2084. const prompt = `你是一位资深的室内后期处理图片分析专家。请基于以下专业标准,对这张后期处理图片进行全面的四大维度对比分析(与前期渲染小图对比):
  2085. **分析框架:对比前期渲染小图与后期成品大图的质变**
  2086. **一、像素与清晰度维度对比**
  2087. **前期渲染小图特征**(800-1200像素宽):
  2088. - 精细纹理(如藤编座椅纹路、木纹结疤)模糊
  2089. - 边缘锐度不足
  2090. - 存在像素块感
  2091. **后期成品大图评估标准**(2000+像素宽):
  2092. 1. **材质细节清晰度**:
  2093. - 藤编的编织肌理是否完全清晰
  2094. - 木质柜体的自然纹理是否可辨识
  2095. - 金属的拉丝质感是否清晰
  2096. - 其他精细材质细节
  2097. 2. **边缘质量**:
  2098. - 边缘线条是否锐利
  2099. - 是否消除像素块感
  2100. - 物品轮廓清晰度
  2101. 3. **印刷/展示适用性**:
  2102. - 是否满足印刷需求
  2103. - 是否适合大幅展示
  2104. **质变描述**:从"预览级"到"成品级"的具体提升
  2105. **二、色彩精细度维度对比**
  2106. **前期渲染小图特征**:
  2107. - 色彩层次单一(同色系过渡仅3级左右)
  2108. - 材质色差值ΔE≈3-5(中阶写实级)
  2109. **后期成品大图评估标准**:
  2110. 1. **色彩层次升级**:
  2111. - 同色系过渡增加至5-8级(如墙面从亮白到阴影灰的渐变)
  2112. - 具体的渐变细节描述
  2113. 2. **材质色彩还原精度**:
  2114. - 材质色差值ΔE是否≤2(专业级)
  2115. - 木色的暖棕/浅柚木区分精准度
  2116. - 各材质的色彩改进描述
  2117. 3. **环境色融合**:
  2118. - 金属/玻璃反光是否融入环境色
  2119. - 具体融合示例(如餐桌金属腿反射出的木色光晕)
  2120. 4. **微色彩细节**:
  2121. - 新增的微色彩肌理(如藤编座椅的浅黄肌理、装饰陶罐的土棕纹理)
  2122. - 这些细节如何提升材质真实感
  2123. **质变描述**:从"中阶写实"到"高还原质感"的具体提升
  2124. **三、灯光氛围维度对比**
  2125. **前期渲染小图问题**:
  2126. - 光源指向性弱
  2127. - 高光光斑模糊
  2128. - 空间立体感不足
  2129. **后期成品大图评估标准**:
  2130. 1. **光源层次明确化**:
  2131. - 主光源(窗外自然光):
  2132. * 漫射光描述
  2133. * 增加的直射光比例(如15%)
  2134. * 直射光光斑的具体区域(如沙发扶手、桌面的局部亮区)
  2135. - 辅助光源(吊顶灯带、壁灯):
  2136. * 光晕范围扩大情况(如壁灯光晕覆盖墙面30cm)
  2137. 2. **阴影质感升级**:
  2138. - 是否保留柔和感
  2139. - 是否新增"微硬边阴影"(如柜体底部、物品边缘)
  2140. - 如何强化空间纵深感
  2141. 3. **氛围细节补充**:
  2142. - 是否新增"环境光反射"
  2143. - 具体反射示例(如地面反射的家具轮廓、墙面反射的灯光暖调)
  2144. - 空间光感自然度
  2145. **质变描述**:从"柔和但平"到"层次化氛围"的具体提升
  2146. **四、后期新增细节维度**
  2147. **前期渲染小图特征**:
  2148. - 物品陈设仅保留基础轮廓
  2149. - 细节模糊(如茶几上的物品模糊)
  2150. **后期成品大图评估标准**:
  2151. 1. **生活化细节**:
  2152. - 识别新增的物品(玻璃杯、书籍、装饰陶罐、植物等)
  2153. - 每个物品的细节描述(如书籍的封面纹理、植物的枝叶细节、玻璃杯的透明质感)
  2154. 2. **真实居住感**:
  2155. - 这些细节如何填充空间的真实居住感
  2156. - 生活化氛围营造
  2157. **质变描述**:从"基础结构"到"生活感填充"的具体提升
  2158. **综合评估**:
  2159. - 后期处理综合评分(0-100分)
  2160. - 后期处理质量等级(good/excellent/master/exceptional)
  2161. - 优点总结
  2162. - 与渲染阶段对比总结
  2163. 请按以下JSON格式输出分析结果(确保所有字段都填写完整):`;
  2164. const outputSchema = `{
  2165. "pixelClarityComparison": {
  2166. "beforeRendering": {
  2167. "pixelRange": "800-1200像素宽",
  2168. "clarityLevel": "预览级",
  2169. "textureIssues": [
  2170. "藤编座椅纹路模糊",
  2171. "木纹结疤不清晰",
  2172. "金属拉丝纹理缺失"
  2173. ],
  2174. "edgeIssues": [
  2175. "边缘锐度不足",
  2176. "局部像素块感明显",
  2177. "物品轮廓软化"
  2178. ]
  2179. },
  2180. "afterPostProcess": {
  2181. "pixelRange": "2000+像素宽(约2400×1440)",
  2182. "clarityLevel": "成品级/展示级",
  2183. "textureQuality": {
  2184. "details": [
  2185. "藤编编织肌理完全清晰,可辨识编织纹路的交错细节",
  2186. "木质柜体的自然纹理、结疤、年轮均清晰可见",
  2187. "金属灯具的拉丝质感、光泽细节完整呈现",
  2188. "布艺装饰的织纹结构清晰"
  2189. ],
  2190. "clarity": "材质细节完全清晰,无模糊或像素损耗"
  2191. },
  2192. "edgeQuality": "边缘线条锐利,物品轮廓清晰,无像素块感,边缘过渡自然",
  2193. "printSuitability": true
  2194. },
  2195. "qualityLeap": "从预览级(800-1200px)提升至成品级(2000+px),材质细节从模糊到完全清晰,边缘从软化到锐利,实现印刷级质量,像素密度提升约67-150%"
  2196. },
  2197. "colorRefinementComparison": {
  2198. "beforeRendering": {
  2199. "gradientLevels": 3,
  2200. "deltaE": 4.0,
  2201. "colorLayers": "色彩层次单一,同色系过渡生硬,缺乏细腻的灰度变化"
  2202. },
  2203. "afterPostProcess": {
  2204. "gradientLevels": 7,
  2205. "deltaE": 1.5,
  2206. "gradientDetails": [
  2207. "墙面从亮白(RGB 245,245,245)到阴影灰(RGB 180,180,180)的7级细腻过渡",
  2208. "地面从浅灰到暗灰的5级自然渐变",
  2209. "木质柜体表面的光影过渡增加至6级"
  2210. ],
  2211. "materialColorAccuracy": [
  2212. {
  2213. "material": "木质柜体",
  2214. "improvement": "暖棕色精准度提升,ΔE从3.5降至1.2,浅柚木与深柚木的色相区分更清晰"
  2215. },
  2216. {
  2217. "material": "沙发面料",
  2218. "improvement": "米灰色还原度提升,ΔE从4.0降至1.5,布料的冷暖调细分更精准"
  2219. },
  2220. {
  2221. "material": "墙面涂料",
  2222. "improvement": "浅灰白色层次感提升,ΔE从3.0降至1.8,阴影区域的灰度细分更丰富"
  2223. }
  2224. ],
  2225. "environmentColorBlend": {
  2226. "enabled": true,
  2227. "examples": [
  2228. "餐桌金属腿反射出的木色光晕(暖黄调),融合了周边木质家具的环境色",
  2229. "玻璃器皿反射的墙面灰白色调,与空间色彩协调统一",
  2230. "地面反射的暖色调灯光,与木质元素的色温相呼应"
  2231. ]
  2232. },
  2233. "microColorDetails": [
  2234. "藤编座椅的浅黄肌理(米黄至淡金的微色差)",
  2235. "装饰陶罐的土棕纹理(褐色至红棕的自然变化)",
  2236. "植物叶片的翠绿至深绿的色彩层次",
  2237. "书籍封面的微妙色彩(米白、浅灰、淡蓝的细微区分)"
  2238. ]
  2239. },
  2240. "qualityLeap": "从中阶写实(ΔE≈4.0,3级过渡)提升至高还原质感(ΔE≈1.5,7级过渡),色彩层次提升133%,材质色彩还原精度提升至专业级,新增环境色融合与微色彩细节"
  2241. },
  2242. "lightingAtmosphereComparison": {
  2243. "beforeRendering": {
  2244. "issues": [
  2245. "光源指向性弱,无法明确主光源位置",
  2246. "高光光斑模糊,缺乏清晰的光影轮廓",
  2247. "空间立体感不足,明暗层次平淡",
  2248. "缺乏硬光点缀,氛围单调"
  2249. ],
  2250. "atmosphereLevel": "柔和但平淡(good级)"
  2251. },
  2252. "afterPostProcess": {
  2253. "lightSourceHierarchy": {
  2254. "primaryLight": {
  2255. "type": "窗外自然光",
  2256. "diffuseLight": "柔和的漫射光覆盖主要活动区,保持整体温馨氛围",
  2257. "directLight": {
  2258. "percentage": 15,
  2259. "spotAreas": [
  2260. "沙发扶手局部亮区(形成明显光斑)",
  2261. "餐桌桌面的局部照射区",
  2262. "茶几表面的高光区域",
  2263. "装饰画框的边缘反光"
  2264. ]
  2265. }
  2266. },
  2267. "auxiliaryLight": {
  2268. "sources": [
  2269. {
  2270. "type": "吊顶灯带间接照明",
  2271. "haloExpansion": "光晕范围从原15cm扩大至墙面30cm,形成更柔和的过渡光区"
  2272. },
  2273. {
  2274. "type": "墙面壁灯",
  2275. "haloExpansion": "暖光光晕覆盖墙面30cm范围,形成局部柔和光区,氛围感提升"
  2276. }
  2277. ]
  2278. }
  2279. },
  2280. "shadowQualityUpgrade": {
  2281. "softTransition": true,
  2282. "microHardEdge": {
  2283. "enabled": true,
  2284. "areas": [
  2285. "柜体底部的微硬边阴影(强化物体接地感)",
  2286. "装饰品边缘的清晰阴影轮廓",
  2287. "家具腿部的投影(增强纵深感)",
  2288. "墙面装饰的明确投影"
  2289. ]
  2290. },
  2291. "spatialDepthEnhancement": "通过微硬边阴影与柔和阴影的结合,空间纵深感显著提升,前后景层次分明"
  2292. },
  2293. "atmosphereDetails": {
  2294. "environmentReflection": {
  2295. "enabled": true,
  2296. "examples": [
  2297. "地面反射的家具轮廓(如沙发底部、柜体底部的模糊反射)",
  2298. "墙面反射的灯光暖调(形成二次光源效果)",
  2299. "玻璃器皿反射的窗外光线",
  2300. "木质桌面反射的顶部光源"
  2301. ]
  2302. },
  2303. "naturalness": "环境光反射自然,光影逻辑符合物理规律,空间光感真实且富有层次"
  2304. }
  2305. },
  2306. "qualityLeap": "从柔和但平(good级)提升至层次化氛围(excellent级),主光源增加15%直射光,辅助光源光晕扩大100%,新增微硬边阴影与环境光反射,空间立体感与光感层次显著提升"
  2307. },
  2308. "postProcessDetailsAddition": {
  2309. "beforeRendering": {
  2310. "detailLevel": "基础结构级,仅保留家具主体轮廓",
  2311. "itemClarity": "茶几上的物品模糊,缺乏细节,装饰品仅保留基础形态"
  2312. },
  2313. "afterPostProcess": {
  2314. "lifeDetails": [
  2315. {
  2316. "item": "玻璃杯",
  2317. "description": "透明玻璃杯的光影折射、杯壁厚度、杯口细节完整呈现,杯中液体(水/饮料)的透明质感清晰"
  2318. },
  2319. {
  2320. "item": "书籍",
  2321. "description": "书籍封面的纹理(布纹/纸质)、书脊的文字、页面的微妙色差、书角的磨损细节"
  2322. },
  2323. {
  2324. "item": "装饰陶罐",
  2325. "description": "陶罐的土棕肌理、手工痕迹、表面的微妙光泽、开口边缘的细节"
  2326. },
  2327. {
  2328. "item": "植物(枝叶/花卉)",
  2329. "description": "植物叶片的脉络、叶缘锯齿、枝干的自然弯曲、叶片的翠绿至深绿渐变"
  2330. },
  2331. {
  2332. "item": "其他装饰品",
  2333. "description": "如相框的金属边框细节、装饰盘的花纹、蜡烛的质感等"
  2334. }
  2335. ],
  2336. "livingAtmosphere": "通过玻璃杯、书籍、植物等生活化物品的细节填充,空间从'展示型'转变为'居住型',真实居住感显著提升,营造出温馨、有生活气息的家居氛围"
  2337. "detailEnhancement": "新增10+项生活化细节,从基础陈设到精细物品,细节丰富度提升约200%,空间叙事性增强"
  2338. },
  2339. "qualityLeap": "从基础结构(仅保留轮廓)提升至生活感填充(精细物品细节),新增玻璃杯、书籍、陶罐、植物等10+项生活化元素,空间从展示型转变为居住型,真实感提升150%"
  2340. },
  2341. "overallScore": 95,
  2342. "postProcessQualityLevel": "master",
  2343. "strengths": [
  2344. "像素密度从预览级提升至成品级,材质细节完全清晰,满足印刷需求",
  2345. "色彩还原精度达专业级(ΔE≤2),色彩层次从3级提升至7级",
  2346. "灯光氛围从柔和但平提升至层次化,新增15%直射光与环境光反射",
  2347. "新增10+项生活化细节,空间真实居住感显著提升",
  2348. "环境色融合自然,微色彩细节丰富,材质真实感强"
  2349. ],
  2350. "comparisonSummary": "后期处理实现了从'预览级渲染小图'到'成品级展示大图'的全方位质变:像素密度提升67-150%(从800-1200px到2000+px),色彩还原精度提升至专业级(ΔE从4.0降至1.5),灯光层次从平淡到丰富(新增15%直射光、微硬边阴影、环境光反射),生活化细节从无到有(新增10+项物品细节),整体从展示型空间转变为居住型空间,真实感与氛围感全面提升。"
  2351. }`;
  2352. try {
  2353. const result = await this.callCompletionJSON(
  2354. prompt,
  2355. outputSchema,
  2356. (content) => {
  2357. console.log('🎞️ 后期处理分析进度:', content?.length || 0);
  2358. },
  2359. 2,
  2360. {
  2361. model: this.MODEL,
  2362. vision: true,
  2363. images: [imageUrl]
  2364. }
  2365. );
  2366. console.log('✅ 后期处理专业分析完成');
  2367. return result;
  2368. } catch (error) {
  2369. console.error('❌ 后期处理分析失败:', error);
  2370. return undefined;
  2371. }
  2372. }
  2373. /**
  2374. * 🚀 压缩图片以加快AI分析速度(大图压缩到1920px宽度)
  2375. */
  2376. private async compressImageForAnalysis(imageUrl: string, maxWidth: number = 1920): Promise<string> {
  2377. return new Promise((resolve, reject) => {
  2378. const img = new Image();
  2379. img.crossOrigin = 'anonymous';
  2380. img.onload = () => {
  2381. try {
  2382. // 如果图片宽度 <= maxWidth,无需压缩,直接转Base64
  2383. if (img.naturalWidth <= maxWidth) {
  2384. console.log(`✅ 图片宽度${img.naturalWidth}px ≤ ${maxWidth}px,无需压缩`);
  2385. // 直接使用原图转Base64
  2386. this.blobToBase64Original(imageUrl).then(resolve).catch(reject);
  2387. return;
  2388. }
  2389. // 计算压缩比例
  2390. const scale = maxWidth / img.naturalWidth;
  2391. const newWidth = maxWidth;
  2392. const newHeight = Math.round(img.naturalHeight * scale);
  2393. console.log(`🔄 压缩图片: ${img.naturalWidth}x${img.naturalHeight} → ${newWidth}x${newHeight}`);
  2394. // 创建Canvas进行压缩
  2395. const canvas = document.createElement('canvas');
  2396. canvas.width = newWidth;
  2397. canvas.height = newHeight;
  2398. const ctx = canvas.getContext('2d');
  2399. if (!ctx) {
  2400. reject(new Error('无法创建Canvas上下文'));
  2401. return;
  2402. }
  2403. // 绘制压缩后的图片
  2404. ctx.drawImage(img, 0, 0, newWidth, newHeight);
  2405. // 转换为Base64(JPEG格式,质量85%)
  2406. const compressedBase64 = canvas.toDataURL('image/jpeg', 0.85);
  2407. console.log(`✅ 压缩完成,Base64长度: ${(compressedBase64.length / 1024 / 1024).toFixed(2)} MB`);
  2408. resolve(compressedBase64);
  2409. } catch (error) {
  2410. console.error('❌ 图片压缩失败:', error);
  2411. reject(error);
  2412. }
  2413. };
  2414. img.onerror = () => {
  2415. reject(new Error('图片加载失败'));
  2416. };
  2417. img.src = imageUrl;
  2418. });
  2419. }
  2420. /**
  2421. * 🔥 将Blob URL转换为Base64(原始方法,供压缩逻辑调用)
  2422. */
  2423. private async blobToBase64Original(blobUrl: string): Promise<string> {
  2424. try {
  2425. const response = await fetch(blobUrl);
  2426. const blob = await response.blob();
  2427. return new Promise<string>((resolve, reject) => {
  2428. const reader = new FileReader();
  2429. reader.onloadend = () => {
  2430. const result = reader.result as string;
  2431. if (result) {
  2432. resolve(result);
  2433. } else {
  2434. reject(new Error('FileReader返回空结果'));
  2435. }
  2436. };
  2437. reader.onerror = () => {
  2438. reject(new Error('FileReader读取失败: ' + reader.error?.message));
  2439. };
  2440. reader.readAsDataURL(blob);
  2441. });
  2442. } catch (error: any) {
  2443. console.error('❌ Blob转Base64失败:', error);
  2444. throw error;
  2445. }
  2446. }
  2447. /**
  2448. * 🔥 将Blob URL转换为Base64(已优化:自动压缩大图)
  2449. * AI模型无法访问blob: URL,需要转换为base64格式
  2450. */
  2451. private async blobToBase64(blobUrl: string): Promise<string> {
  2452. try {
  2453. // 🚀 优化:自动压缩大图,加快AI分析速度
  2454. return await this.compressImageForAnalysis(blobUrl, 1920);
  2455. } catch (error: any) {
  2456. console.error('❌ Blob转Base64失败:', error);
  2457. throw error;
  2458. }
  2459. }
  2460. /**
  2461. * 🚀 快速分析交付图片(返回简化JSON)
  2462. * 专为交付执行阶段优化,快速返回空间和阶段信息
  2463. * 格式: {"space":"客厅","stage":"软装"}
  2464. */
  2465. async quickAnalyzeDeliveryImage(imageUrl: string): Promise<{ space: string; stage: string; confidence?: number }> {
  2466. try {
  2467. console.log('🚀 [快速分析] 开始分析图片...');
  2468. // 调用AI进行快速分析
  2469. const analysisResult = await Parse.Cloud.run('ai-quick-delivery-analysis', {
  2470. imageUrl,
  2471. analysisType: 'quick_delivery'
  2472. });
  2473. console.log('✅ [快速分析] 分析完成:', analysisResult);
  2474. // 返回简化的JSON结果
  2475. return {
  2476. space: analysisResult?.space || '未知空间',
  2477. stage: analysisResult?.stage || 'rendering',
  2478. confidence: analysisResult?.confidence || 0
  2479. };
  2480. } catch (error: any) {
  2481. console.error('❌ [快速分析] 分析失败:', error);
  2482. // 失败时使用基于文件名的快速判断
  2483. return this.quickAnalyzeByFileName(imageUrl);
  2484. }
  2485. }
  2486. /**
  2487. * 🔥 基于文件名快速分析(兜底方案)
  2488. * 当AI分析失败时,根据文件名关键词快速判断
  2489. */
  2490. private quickAnalyzeByFileName(imageUrl: string): { space: string; stage: string; confidence: number } {
  2491. const fileName = imageUrl.toLowerCase();
  2492. // 🔥 阶段判断(优先级:白膜 > 软装 > 渲染 > 后期)
  2493. let stage = 'rendering'; // 默认渲染
  2494. // 白膜关键词(最高优先级)
  2495. if (fileName.includes('白模') || fileName.includes('bm') || fileName.includes('whitemodel') ||
  2496. fileName.includes('模型') || fileName.includes('建模') || fileName.includes('白膜')) {
  2497. stage = 'white_model';
  2498. }
  2499. // 软装关键词
  2500. else if (fileName.includes('软装') || fileName.includes('rz') || fileName.includes('softdecor') ||
  2501. fileName.includes('家具') || fileName.includes('配饰') || fileName.includes('陈设')) {
  2502. stage = 'soft_decor';
  2503. }
  2504. // 后期关键词
  2505. else if (fileName.includes('后期') || fileName.includes('hq') || fileName.includes('postprocess') ||
  2506. fileName.includes('修图') || fileName.includes('精修') || fileName.includes('调色')) {
  2507. stage = 'post_process';
  2508. }
  2509. // 渲染关键词(默认)
  2510. else if (fileName.includes('渲染') || fileName.includes('xr') || fileName.includes('rendering') ||
  2511. fileName.includes('效果图') || fileName.includes('render')) {
  2512. stage = 'rendering';
  2513. }
  2514. // 🔥 空间判断
  2515. let space = '未知空间';
  2516. if (fileName.includes('客厅') || fileName.includes('kt') || fileName.includes('living')) {
  2517. space = '客厅';
  2518. } else if (fileName.includes('卧室') || fileName.includes('ws') || fileName.includes('bedroom') ||
  2519. fileName.includes('主卧') || fileName.includes('次卧')) {
  2520. space = '卧室';
  2521. } else if (fileName.includes('餐厅') || fileName.includes('ct') || fileName.includes('dining')) {
  2522. space = '餐厅';
  2523. } else if (fileName.includes('厨房') || fileName.includes('cf') || fileName.includes('kitchen')) {
  2524. space = '厨房';
  2525. } else if (fileName.includes('卫生间') || fileName.includes('wsj') || fileName.includes('bathroom') ||
  2526. fileName.includes('浴室') || fileName.includes('厕所')) {
  2527. space = '卫生间';
  2528. } else if (fileName.includes('书房') || fileName.includes('sf') || fileName.includes('study')) {
  2529. space = '书房';
  2530. } else if (fileName.includes('阳台') || fileName.includes('yt') || fileName.includes('balcony')) {
  2531. space = '阳台';
  2532. } else if (fileName.includes('玄关') || fileName.includes('xg') || fileName.includes('entrance')) {
  2533. space = '玄关';
  2534. }
  2535. console.log(`🔍 [文件名分析] ${fileName} → 空间: ${space}, 阶段: ${stage}`);
  2536. return {
  2537. space,
  2538. stage,
  2539. confidence: 70 // 基于文件名的分析,置信度设为70%
  2540. };
  2541. }
  2542. }