feat(edutainment): refresh baby object match flow
This commit is contained in:
@@ -1,5 +1,7 @@
|
||||
import { Buffer } from 'node:buffer';
|
||||
import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
|
||||
import http from 'node:http';
|
||||
import https from 'node:https';
|
||||
import path from 'node:path';
|
||||
|
||||
const repoRoot = process.cwd();
|
||||
@@ -156,6 +158,12 @@ const handsConcepts = [
|
||||
prompt:
|
||||
'围绕“陶泥儿”Logo 方向 03 的“上下两只手”感觉做延展。设计一个无文字扁平矢量主标:上下一对抽象软手 / 软泥掌从两侧微微合捏,中间形成一颗小圆珠或作品核。图形要像品牌符号,不像手势教学图;保留托举与成型的温柔感。禁止播放三角、聊天气泡、笑脸、眼睛、花朵、褐色主色、真实手指、复杂掌纹、碎小图标。风格:flat vector, minimal, mainstream app logo, high contrast, iconic, friendly。配色:莓红、奶白、薄荷青、少量深墨,最多 3 色。',
|
||||
},
|
||||
{
|
||||
id: 'taonier-hands-cradle-v2',
|
||||
title: '托星软掌',
|
||||
prompt:
|
||||
'为“陶泥儿”设计无文字扁平矢量 Logo。图形是上下两片圆润软托,托住中央一颗小星,像把灵感轻轻捏成作品。不要画具体手指,只保留抽象软掌感觉。适合 App icon,简单、亲和、醒目、小尺寸清楚。配色:珊瑚红、薄荷青、奶油白,最多三色。不要播放三角、聊天气泡、笑脸、眼睛、花朵、褐色、文字、字母、3D、碎元素。',
|
||||
},
|
||||
{
|
||||
id: 'taonier-hands-soft-bowl',
|
||||
title: '创意托碗',
|
||||
@@ -176,6 +184,464 @@ const handsConcepts = [
|
||||
},
|
||||
];
|
||||
|
||||
const broadConcepts = [
|
||||
{
|
||||
id: 'taonier-broad-clay-dot-crown',
|
||||
title: '泥点皇冠',
|
||||
prompt:
|
||||
'为中文产品“陶泥儿”设计一个无文字扁平矢量 Logo 图标。产品是 AI UGC 创作与轻休闲互动内容平台,用户用“泥点”驱动 AI,把一句脑洞、一张图或一个梗捏成小游戏和可分享作品。本方向把“泥点”做成核心品牌符号:3 到 5 个圆润泥点自然聚合,形成一个像皇冠、火苗、作品星核之间的抽象主轮廓,表达很多灵感汇聚成精品作品。整体必须像成熟 App 主标,亲和、明亮、可注册感强,小尺寸清楚。避免播放三角、聊天气泡、笑脸、真实陶艺、褐色陶土主色、人物、手、复杂碎点。风格:flat vector logo, bold simple silhouette, modern consumer app, warm, memorable, scalable, solid colors。配色:珊瑚红、奶油白、青绿色、少量金色,最多 4 色。无文字、无字母、无水印、无 3D、无厚阴影、无玻璃高光。',
|
||||
},
|
||||
{
|
||||
id: 'taonier-broad-soft-portal',
|
||||
title: '软泥入口',
|
||||
prompt:
|
||||
'为中文产品“陶泥儿”设计一个无文字扁平矢量 Logo 图标。产品把 AI 创作、UGC、小游戏、视觉小说、拼图和轻互动作品放在同一平台内,核心感觉是“打开一个软软的创作入口,进去就能造作品”。图形主体是一枚被捏开的柔软入口/门洞,外轮廓像软泥被拉开,中心留出干净负形作品核或小星点。图形要完整、抽象、主流,不像播放器、不像聊天框、不像眼睛。风格:flat vector brand mark, simple, iconic, friendly premium, strong silhouette, app icon ready。配色使用亮珊瑚、薄荷青、奶油白、深墨中的 3 色。禁止中文字、英文字母、真实门、真实陶土、3D、复杂纹理、碎小装饰、UI 按钮。',
|
||||
},
|
||||
{
|
||||
id: 'taonier-broad-work-embryo',
|
||||
title: '作品胚芽',
|
||||
prompt:
|
||||
'为中文产品“陶泥儿”设计一个无文字扁平矢量 Logo 图标。品牌隐喻不是传统陶艺,而是“灵感胚胎被 AI 塑形成可玩的作品”。图形主体是一颗圆润的作品胚芽:外形像软泥种子、游戏棋子和小宇宙的结合,内部只有一条柔软切面和一个小星点负形。整体高级、温柔、年轻,适合平台主 Logo 和 App icon。避免植物叶子过强、教育儿童感、播放按钮、聊天气泡、笑脸、循环箭头、褐色主色。风格:flat vector, premium friendly app logo, minimal, bold, clear at 32px, solid colors。配色:湖蓝或青绿主色,珊瑚橙点缀,奶白负形,最多 3 色。无文字、无字母、无水印、无 3D、无照片质感。',
|
||||
},
|
||||
{
|
||||
id: 'taonier-broad-game-mold',
|
||||
title: '游戏模芯',
|
||||
prompt:
|
||||
'为中文产品“陶泥儿”设计一个无文字扁平矢量 Logo 图标。产品不是工具后台,而是能把脑洞生成拼图、抓大鹅、视觉小说、文字游戏等互动作品的平台。本方向用“游戏模芯”做符号:一个圆润软泥主形中嵌入极简十字方向键或小方块负形,但不要画传统手柄,不要出现播放三角。图形要表达可玩、轻休闲、低门槛创作,同时保持品牌主标感。风格:flat vector logo, simple geometric, friendly, playful but mature, app icon, high contrast。配色:珊瑚红、青绿、奶油白、深墨,最多 4 色。禁止文字、字母、水印、3D、复杂按钮、真实手柄、聊天气泡、笑脸、儿童玩具感。',
|
||||
},
|
||||
{
|
||||
id: 'taonier-broad-tao-negative',
|
||||
title: '陶字负形',
|
||||
prompt:
|
||||
'为中文产品“陶泥儿”设计一个无文字扁平矢量 Logo 图标。尝试从“陶”的结构提炼抽象负形,但不要直接写汉字,也不要让模型生成可读文字。图形主体是一枚圆润软泥徽标,内部用两到三块负形构成类似陶器开口、耳部、土块和作品核的抽象关系,让熟悉中文的人隐约感到“陶”,但第一眼仍是现代 App 标志。风格:flat vector brand symbol, abstract Chinese-inspired, clean, iconic, friendly premium, scalable。配色:深墨或莓红主形,奶油白负形,青绿小点缀。禁止真实汉字、书法、篆刻、传统印章、褐色陶艺、播放按钮、聊天气泡、人物、3D、水印。',
|
||||
},
|
||||
{
|
||||
id: 'taonier-broad-soft-totem',
|
||||
title: '软体图腾',
|
||||
prompt:
|
||||
'为中文产品“陶泥儿”设计一个无文字扁平矢量 Logo 图标。基于 Taonier / 陶泥儿 的品牌声母感觉做一个抽象软体图腾,但不要直接画英文字母 T,也不要生成任何文字。图形由一笔连续的圆润软泥带形成稳定的竖向图腾,顶部像被轻捏出的小角,中心有一颗作品星核负形,表达“捏、造、发布”。整体要比普通字母标更独特,适合 App icon、favicon 和平台顶栏。风格:flat vector logo, bold, simple, modern, friendly, memorable, solid colors。配色:珊瑚红主形、奶油白负形、薄荷青小面积辅助。禁止文字、字母直出、播放三角、聊天气泡、笑脸、无限循环、褐色陶土、3D、复杂纹理。',
|
||||
},
|
||||
{
|
||||
id: 'taonier-broad-creation-spark',
|
||||
title: '开捏火花',
|
||||
prompt:
|
||||
'为中文产品“陶泥儿”设计一个无文字扁平矢量 Logo 图标。核心动作为“开捏”:用户输入灵感,AI 立刻生成可玩的作品。图形不要画真实手,用两块极简软形挤压出中心火花,火花不是爆炸特效,而是一个稳定的四角作品星核。外轮廓要比上一轮左右括号更完整,像一个独立品牌图腾。风格:flat vector logo, iconic, minimal, high contrast, friendly, youthful, app icon ready。配色:莓红或珊瑚红主形,奶油白负形,青绿中心点缀,最多 3 色。禁止文字、字母、水印、播放三角、聊天气泡、笑脸、眼睛、真实手指、碎粒、3D、厚阴影。',
|
||||
},
|
||||
{
|
||||
id: 'taonier-broad-content-orbit',
|
||||
title: '作品星轨',
|
||||
prompt:
|
||||
'为中文产品“陶泥儿”设计一个无文字扁平矢量 Logo 图标。产品承载多种互动内容:RPG、拼图、抓大鹅、视觉小说、文字游戏、儿童寓教于乐。图形用一个软泥圆核和两条极简短弧形成“作品星轨”,表达一个灵感生成多个作品形态;但整体必须是一个凝聚的主标,不是天文图标。风格:flat vector brand mark, simple, premium friendly, clean geometry, app icon, scalable。配色:青绿主核、珊瑚红弧线、奶油白负形、深墨小轮廓可选。禁止文字、字母、水印、真实星球、复杂轨道、科技冷硬、播放键、聊天气泡、循环箭头、3D。',
|
||||
},
|
||||
];
|
||||
|
||||
const freshConcepts = [
|
||||
{
|
||||
id: 'taonier-fresh-wheel-imprint',
|
||||
title: '陶轮印记',
|
||||
prompt:
|
||||
'为“陶泥儿”设计无文字扁平矢量 Logo。完全换方向:俯视一个正在旋转的创作轮盘,圆环被轻轻压出一处缺口,像把灵感旋成作品。成熟消费级 App 主标,几何、干净、有速度感。配色:钴蓝、奶白、珊瑚红、少量深墨。不要软手、星核、聊天气泡、播放键、笑脸、真实陶艺、褐色、文字、字母、3D。',
|
||||
},
|
||||
{
|
||||
id: 'taonier-fresh-mold-window',
|
||||
title: '模具窗格',
|
||||
prompt:
|
||||
'为“陶泥儿”设计无文字扁平矢量 Logo。完全换方向:一个圆角模具窗口,内部是 2x2 的不规则负形窗格,像多种小游戏和互动作品从同一个模具里生成。主流、简洁、品牌感强、小尺寸清楚。配色:深墨主形、奶油白负形、亮青绿和珊瑚小点缀。不要软手、星星、播放键、聊天气泡、脸、真实陶土、文字、字母、3D。',
|
||||
},
|
||||
{
|
||||
id: 'taonier-fresh-dot-dice',
|
||||
title: '泥点骰面',
|
||||
prompt:
|
||||
'为“陶泥儿”设计无文字扁平矢量 Logo。完全换方向:一枚圆润方形骰面或游戏牌面,5 个泥点孔组成独特节奏,表达泥点、玩法和随机脑洞。不要画立体骰子,只要正面抽象符号。潮流、轻游戏、可注册。配色:象牙白底、黑色主形、荧光青、珊瑚红。不要播放键、聊天气泡、笑脸、星星、软手、褐色、文字、字母、3D。',
|
||||
},
|
||||
{
|
||||
id: 'taonier-fresh-pinwheel',
|
||||
title: '灵感风车',
|
||||
prompt:
|
||||
'为“陶泥儿”设计无文字扁平矢量 Logo。完全换方向:抽象纸风车,由四片圆润色块围成旋转中心,表达简单、轻松、人人能造内容。它要像品牌主标,不像儿童玩具。配色:莓红、天蓝、薄荷、奶白、深墨。不要软泥团、手、星核、播放键、聊天气泡、笑脸、花朵、文字、字母、3D、复杂渐变。',
|
||||
},
|
||||
{
|
||||
id: 'taonier-fresh-pocket-world',
|
||||
title: '口袋世界',
|
||||
prompt:
|
||||
'为“陶泥儿”设计无文字扁平矢量 Logo。完全换方向:一个抽象口袋形徽标,口袋里露出一小块世界切片或舞台切片,表示把脑洞装进口袋随手开玩。现代、亲和、平台感强。配色:青绿色主形、奶白负形、珊瑚红小块、深墨轮廓。不要软手、星核、播放键、聊天气泡、笑脸、地图图钉、真实口袋、文字、字母、3D。',
|
||||
},
|
||||
{
|
||||
id: 'taonier-fresh-builder-blocks',
|
||||
title: '创作积木',
|
||||
prompt:
|
||||
'为“陶泥儿”设计无文字扁平矢量 Logo。完全换方向:三块圆角积木以不对称方式咬合,形成一个稳定主轮廓,表达 UGC 搭建、模板生成和小游戏创作。不要儿童玩具感,要成熟、潮流、清晰。配色:黑色或深紫主轮廓,珊瑚、青绿、奶白填色。不要软手、星星、播放键、聊天气泡、笑脸、褐色、文字、字母、3D。',
|
||||
},
|
||||
{
|
||||
id: 'taonier-fresh-stage-window',
|
||||
title: '叙事舞台窗',
|
||||
prompt:
|
||||
'为“陶泥儿”设计无文字扁平矢量 Logo。完全换方向:一个极简舞台窗或小剧场窗口,左右两片抽象幕布形成负形中心,代表视觉小说、RPG 和互动叙事。它要是 App icon 主标,不是插画。配色:深墨、珊瑚红、奶油白、少量湖蓝。不要播放键、聊天气泡、笑脸、软手、星核、真实舞台、文字、字母、3D。',
|
||||
},
|
||||
{
|
||||
id: 'taonier-fresh-ribbon-knot',
|
||||
title: '灵感绳结',
|
||||
prompt:
|
||||
'为“陶泥儿”设计无文字扁平矢量 Logo。完全换方向:一条圆润彩色泥条打成简洁绳结,像把多个创意线索系成一个作品。形状必须凝聚成单个主标,不能散。配色:珊瑚、钴蓝、薄荷、奶白,边缘干净。不要无限符号、软手、星核、播放键、聊天气泡、笑脸、褐色陶土、文字、字母、3D。',
|
||||
},
|
||||
{
|
||||
id: 'taonier-fresh-folded-sticker',
|
||||
title: '贴纸折角',
|
||||
prompt:
|
||||
'为“陶泥儿”设计无文字扁平矢量 Logo。完全换方向:一张圆角贴纸或作品卡片,右上角轻轻折起,负形像一个小入口。表达 UGC、作品发布、随手开玩。成熟、潮流、极简。配色:奶白、黑、珊瑚、青绿。不要播放键、聊天气泡、笑脸、手、星星、褐色、文字、字母、3D。',
|
||||
},
|
||||
{
|
||||
id: 'taonier-fresh-punch-hole',
|
||||
title: '印模孔洞',
|
||||
prompt:
|
||||
'为“陶泥儿”设计无文字扁平矢量 Logo。完全换方向:一个圆润印模形状,中间被冲出一个不规则圆孔,像从泥板里取出作品。抽象、强轮廓、可注册、小尺寸清楚。配色:黑色主形、奶白负形、荧光青小块、珊瑚红。不要播放键、聊天气泡、笑脸、手、星星、陶罐、文字、字母、3D。',
|
||||
},
|
||||
];
|
||||
|
||||
const punchReferencePath = path.join(
|
||||
repoRoot,
|
||||
'public',
|
||||
'branding',
|
||||
'taonier-logo-fresh-concepts',
|
||||
'taonier-fresh-punch-hole.png',
|
||||
);
|
||||
const punch04ReferencePath = path.join(
|
||||
repoRoot,
|
||||
'public',
|
||||
'branding',
|
||||
'taonier-logo-punch-hole-concepts',
|
||||
'taonier-punch-color-inlay.png',
|
||||
);
|
||||
const paletteRefineReferencePath = path.join(
|
||||
repoRoot,
|
||||
'public',
|
||||
'branding',
|
||||
'taonier-logo-ref04-palette-transfer',
|
||||
'taonier-ref04-palette-transfer-warm-yellow-sparkle.png',
|
||||
);
|
||||
const paletteShapeReferencePath = path.join(
|
||||
repoRoot,
|
||||
'public',
|
||||
'branding',
|
||||
'taonier-logo-ref04-locked-color-concepts',
|
||||
'taonier-ref04-locked-warm-ink.png',
|
||||
);
|
||||
const sparkleRefineReferencePath = path.join(
|
||||
repoRoot,
|
||||
'public',
|
||||
'branding',
|
||||
'taonier-logo-ref04-warm-sparkle-v2-concepts',
|
||||
'taonier-ref04-warm-sparkle-terracotta.png',
|
||||
);
|
||||
const sparkleCropReferencePath = path.join(
|
||||
repoRoot,
|
||||
'public',
|
||||
'branding',
|
||||
'taonier-logo-ref04-palette-refine-concepts',
|
||||
'taonier-sparkle-reference-crop.png',
|
||||
);
|
||||
const paletteRefineV2ReferencePath = path.join(
|
||||
repoRoot,
|
||||
'public',
|
||||
'branding',
|
||||
'taonier-logo-ref04-palette-refine-v2-concepts',
|
||||
'taonier-ref04-palette-refine-v2-pale-cream.png',
|
||||
);
|
||||
const paletteRefineV4PaleButterReferencePath = path.join(
|
||||
repoRoot,
|
||||
'public',
|
||||
'branding',
|
||||
'taonier-logo-ref04-palette-refine-v4-concepts',
|
||||
'taonier-ref04-palette-refine-v4-pale-butter.png',
|
||||
);
|
||||
|
||||
const punchConcepts = [
|
||||
{
|
||||
id: 'taonier-punch-locked-shape',
|
||||
title: '原型锁定微调',
|
||||
referenceImages: [punchReferencePath],
|
||||
prompt:
|
||||
'为“陶泥儿”继续打磨参考图 06 印模孔洞 logo。必须保持参考图基本造型不变:黑色圆润不规则环形主形、中央白色不规则孔洞、右上珊瑚红辅形、左下青蓝辅形。只优化比例、边缘、留白和小尺寸识别,让它更像成熟 App icon。无文字、无字母、无播放键、无聊天气泡、无手、无星星、无3D。',
|
||||
},
|
||||
{
|
||||
id: 'taonier-punch-stable-icon',
|
||||
title: '稳定主标',
|
||||
referenceImages: [punchReferencePath],
|
||||
prompt:
|
||||
'基于参考图 06 印模孔洞,为“陶泥儿”做无文字扁平矢量 logo 延展。保留黑色冲孔主形和中央不规则白洞,但让外轮廓更稳定、更像长期品牌主标。右上珊瑚红和左下青蓝辅形更克制,白底,强轮廓,小尺寸清楚。无文字、无字母、无播放键、无聊天气泡、无手、无星星、无3D。',
|
||||
},
|
||||
{
|
||||
id: 'taonier-punch-hole-balance',
|
||||
title: '孔洞比例',
|
||||
referenceImages: [punchReferencePath],
|
||||
prompt:
|
||||
'基于参考图 06 印模孔洞,为“陶泥儿”延展一个更干净的无文字 logo。核心仍是黑色圆润印模环和中央不规则白色孔洞,重点调整孔洞大小、厚薄关系和负形节奏,让黑形更有张力。珊瑚红、青蓝只作为小面积辅形。白底。无文字、无字母、无播放键、无聊天气泡、无手、无星星、无3D。',
|
||||
},
|
||||
{
|
||||
id: 'taonier-punch-color-inlay',
|
||||
title: '彩色嵌合',
|
||||
referenceImages: [punchReferencePath],
|
||||
prompt:
|
||||
'基于参考图 06 印模孔洞,为“陶泥儿”做彩色嵌合版 logo。黑色主环保持冲孔感,右上珊瑚红和左下青蓝两块辅形与主形更自然嵌合,像从泥板里取出的两片作品碎片。造型简洁、可注册、App icon 友好。无文字、无字母、无播放键、无聊天气泡、无手、无星星、无3D。',
|
||||
},
|
||||
{
|
||||
id: 'taonier-punch-mono-test',
|
||||
title: '单色测试',
|
||||
referenceImages: [punchReferencePath],
|
||||
prompt:
|
||||
'基于参考图 06 印模孔洞,为“陶泥儿”做单色极简版 logo。只保留黑色圆润冲孔主形和中央白色不规则孔洞,去掉彩色辅形。强调强轮廓、可注册、小尺寸识别和品牌符号感。白底。无文字、无字母、无播放键、无聊天气泡、无手、无星星、无3D。',
|
||||
},
|
||||
{
|
||||
id: 'taonier-punch-app-token',
|
||||
title: '应用图标',
|
||||
referenceImages: [punchReferencePath],
|
||||
prompt:
|
||||
'基于参考图 06 印模孔洞,为“陶泥儿”延展一个更完整的 App icon 核心图形。黑色不规则冲孔主形更饱满,中央白洞更清晰,珊瑚红与青蓝辅形保持年轻感但不抢主体。整体像可长期使用的品牌符号,不像插画。白底。无文字、无字母、无播放键、无聊天气泡、无手、无星星、无3D。',
|
||||
},
|
||||
];
|
||||
|
||||
const punch04Concepts = [
|
||||
{
|
||||
id: 'taonier-punch04-warm-ink-core',
|
||||
title: '暖墨填芯',
|
||||
referenceImages: [punch04ReferencePath],
|
||||
prompt:
|
||||
'基于参考图“04 彩色嵌合”为“陶泥儿”继续做 logo 延展。保持原有基本结构不变:一个圆润不规则环形主形,右上珊瑚红嵌合块,左下青蓝嵌合块,中央不规则孔洞。重点调整配色:中间黑色主形改为温暖深墨灰,不要纯黑;中央孔洞内部加入一枚很简洁的奶油色软泥种子/作品核填充,不要填满,保留留白呼吸。扁平矢量、品牌主标、小尺寸清楚。无文字、无字母、无播放键、无聊天气泡、无手、无星星、无3D。',
|
||||
},
|
||||
{
|
||||
id: 'taonier-punch04-navy-game-core',
|
||||
title: '靛蓝作品核',
|
||||
referenceImages: [punch04ReferencePath],
|
||||
prompt:
|
||||
'基于参考图“04 彩色嵌合”为“陶泥儿”设计一版配色延展。保持黑环、右上红块、左下青块的基本结构和嵌合关系,但把主形从黑色改为深靛蓝或蓝黑色,整体更年轻、更像互联网 App。中央空心区域加入一个极简浅色作品核:小圆角方块或软形小岛,不能像播放键、不能像字母。白底,扁平矢量,干净可注册。无文字、无字母、无聊天气泡、无手、无星星、无3D。',
|
||||
},
|
||||
{
|
||||
id: 'taonier-punch04-cream-window',
|
||||
title: '奶油内窗',
|
||||
referenceImages: [punch04ReferencePath],
|
||||
prompt:
|
||||
'基于参考图“04 彩色嵌合”为“陶泥儿”做一版更柔和的 logo。基本结构不变:主环、右上珊瑚红、左下青蓝、中央孔洞都保留。把原黑色主环调整为柔和深紫灰或墨绿色,降低硬度。中央孔洞不再是纯空白,设计成奶油色内窗,里面有两块极简小色面,表达多个作品从同一模具生成。整体仍然极简,不要复杂插画。无文字、无字母、无播放键、无聊天气泡、无手、无星星、无3D。',
|
||||
},
|
||||
{
|
||||
id: 'taonier-punch04-clay-gradient-flat',
|
||||
title: '陶盒彩芯',
|
||||
referenceImages: [punch04ReferencePath],
|
||||
prompt:
|
||||
'基于参考图“04 彩色嵌合”为“陶泥儿”做配色与中孔设计。保持 04 的基本轮廓和红青嵌合块位置。主形不要纯黑,改成深陶紫、莓紫或炭灰紫,仍保持强轮廓。中央孔洞加入一个扁平的彩色泥芯,由珊瑚、青蓝、奶白三块圆润小面组成,像作品被捏出来的内核。不要渐变高光,不要立体,不要复杂细节。无文字、无字母、无播放键、无聊天气泡、无手、无星星。',
|
||||
},
|
||||
{
|
||||
id: 'taonier-punch04-mint-shadow',
|
||||
title: '薄荷深影',
|
||||
referenceImages: [punch04ReferencePath],
|
||||
prompt:
|
||||
'基于参考图“04 彩色嵌合”为“陶泥儿”做一版更清爽的品牌 logo。保持 04 的三块嵌合结构不变。把中间黑色主形改成深青绿/墨绿,右上红块更偏珊瑚,左下青块更偏亮薄荷。中央空心处加入一枚小小的浅黄色或奶白圆角形,像可玩的作品胚,不要过大。整体强识别、轻休闲、App icon 友好。无文字、无字母、无播放键、无聊天气泡、无手、无星星、无3D。',
|
||||
},
|
||||
{
|
||||
id: 'taonier-punch04-negative-tile',
|
||||
title: '内嵌拼片',
|
||||
referenceImages: [punch04ReferencePath],
|
||||
prompt:
|
||||
'基于参考图“04 彩色嵌合”为“陶泥儿”做一版中间内容更明确的 logo。保持外部基本结构和红青嵌合块位置不变。主形从纯黑改为深墨蓝灰。中央不规则孔洞内部放入一个极简拼片/圆角模块组合,表示拼图、小游戏、互动作品,但必须非常简洁,不能像 UI 图标堆叠。白底,扁平矢量,主标感强。无文字、无字母、无播放键、无聊天气泡、无手、无星星、无3D。',
|
||||
},
|
||||
];
|
||||
|
||||
const paletteRefineConcepts = [
|
||||
{
|
||||
id: 'taonier-ref04-palette-refine-butter',
|
||||
title: '淡黄黄油',
|
||||
referenceImages: [paletteRefineReferencePath, sparkleRefineReferencePath],
|
||||
prompt:
|
||||
'为“陶泥儿”继续调整 REF-04 配色迁移版。必须锁定参考图一的外轮廓和分区:主形、右上红块、左下青块和中间孔洞都保持不变;把中间主形改成温暖、低饱和、很淡的黄油黄或奶油黄,不要脏黄、土黄、芥末黄或偏橙黄。中间的星星必须保持参考图二的原样:四角闪光星,带短小光芒,不能拉伸成细长十字,不能变成五角星,不能加厚底托。整体要像成熟、干净、轻松的品牌 logo。无文字、无字母、无播放键、无聊天气泡、无手、无3D。',
|
||||
},
|
||||
{
|
||||
id: 'taonier-ref04-palette-refine-cream',
|
||||
title: '奶油淡黄',
|
||||
referenceImages: [paletteRefineReferencePath, sparkleRefineReferencePath],
|
||||
prompt:
|
||||
'基于 REF-04 造型锁定版和四角闪光星参考图,生成一版更高级的暖黄配色。保持图一的造型完全不变,只把中间主形改成低饱和奶油淡黄,颜色要轻、透、干净,避免脏、沉、厚。中心星星完全沿用参考图二的四角闪光样式和短光芒,不要拉伸,不要变形,不要变成五角星。红块和青块保持现有位置与比例。白底、扁平、品牌标志感。无文字、无字母、无手、无播放键、无3D。',
|
||||
},
|
||||
{
|
||||
id: 'taonier-ref04-palette-refine-biscuit',
|
||||
title: '饼干淡黄',
|
||||
referenceImages: [paletteRefineReferencePath, sparkleRefineReferencePath],
|
||||
prompt:
|
||||
'继续基于 REF-04 造型锁定版做色彩优化。外轮廓、红青辅形、中孔边界全部锁住不变;中间主形换成更淡的饼干黄、奶油黄或浅麦黄,必须低饱和、暖而不脏。中心填充严格使用参考图二的四角闪光星和短光芒,保持原样,不许被拉长,也不许改成几何五角星。整体要简洁、轻盈、专业。无文字、无字母、无聊天气泡、无3D、无复杂阴影。',
|
||||
},
|
||||
{
|
||||
id: 'taonier-ref04-palette-refine-milk',
|
||||
title: '牛奶暖黄',
|
||||
referenceImages: [paletteRefineReferencePath, sparkleRefineReferencePath],
|
||||
prompt:
|
||||
'在 REF-04 锁形轮廓上做最后一轮暖黄微调。只改中间主形的颜色,把它变成接近牛奶、黄油、奶霜的浅暖黄,低饱和、柔和、干净,不要土气,不要发灰。中间星星必须保持参考图二的四角闪光星原型和短光芒,不能被拉伸,不能变瘦,不能加底托。红青两块辅形位置不动。白底,极简 logo。无文字、无字母、无手、无播放键、无3D。',
|
||||
},
|
||||
];
|
||||
|
||||
const paletteRefineV2Concepts = [
|
||||
{
|
||||
id: 'taonier-ref04-palette-refine-v2-soft-butter',
|
||||
title: '柔和奶黄',
|
||||
referenceImages: [
|
||||
paletteShapeReferencePath,
|
||||
paletteRefineReferencePath,
|
||||
sparkleCropReferencePath,
|
||||
],
|
||||
prompt:
|
||||
'为“陶泥儿”修正 REF-04 配色迁移版。严格锁定参考图一的造型和分区:不改变外轮廓、不改变右上辅形、不改变左下辅形、不改变中央孔洞边界。只做两处调整:1)把中间主形改成温暖、低饱和、淡淡的奶油黄/黄油黄,颜色要高级、轻、干净,绝对不要土黄、脏黄、芥末黄、焦糖黄、偏橙黄;2)中心空洞里的星星必须使用参考图三的原始四角闪光星和短光芒,保持饱满菱形闪光,不要拉伸成十字,不要变成五角星,不要加底托。保持白底和扁平 logo。无文字、无字母、无手、无播放键、无聊天气泡、无3D。',
|
||||
},
|
||||
{
|
||||
id: 'taonier-ref04-palette-refine-v2-pale-cream',
|
||||
title: '浅奶油黄',
|
||||
referenceImages: [
|
||||
paletteShapeReferencePath,
|
||||
paletteRefineReferencePath,
|
||||
sparkleCropReferencePath,
|
||||
],
|
||||
prompt:
|
||||
'基于三张参考图生成一版修正版 logo:参考图一只用于锁定 REF-04 造型;参考图二只用于当前粉红与薄荷青位置;参考图三用于中心星星样式。中间主形颜色改为低饱和浅奶油黄,接近柔和奶霜,不要土气、不要脏、不要高饱和。中心星星必须照参考图三,四角闪光星带短光芒,比例自然饱满,不能被压扁或拉长。外轮廓和孔洞边界不变。白底、干净、成熟品牌 logo。无文字、无字母、无3D。',
|
||||
},
|
||||
{
|
||||
id: 'taonier-ref04-palette-refine-v2-light-vanilla',
|
||||
title: '香草淡黄',
|
||||
referenceImages: [
|
||||
paletteShapeReferencePath,
|
||||
paletteRefineReferencePath,
|
||||
sparkleCropReferencePath,
|
||||
],
|
||||
prompt:
|
||||
'继续优化 REF-04 造型锁定 logo。必须保持参考图一的所有轮廓位置,只把中间原黑色区域换成温暖低饱和的香草淡黄,颜色像轻柔黄油、奶油纸、浅米黄,不能像陶土、咖啡、焦糖或芥末。中心空洞填入参考图三的星星:圆润四角闪光、短小光芒、自然比例,不要变瘦,不要拉伸,不要五角星。粉红和薄荷青辅形沿用参考图二的气质。无文字、无字母、无播放键、无聊天气泡、无手、无3D。',
|
||||
},
|
||||
];
|
||||
|
||||
const paletteRefineV3Concepts = [
|
||||
{
|
||||
id: 'taonier-ref04-palette-refine-v3-butter-soft',
|
||||
title: '淡奶油黄',
|
||||
referenceImages: [
|
||||
paletteShapeReferencePath,
|
||||
paletteRefineV2ReferencePath,
|
||||
sparkleCropReferencePath,
|
||||
],
|
||||
prompt:
|
||||
'为“陶泥儿”继续修正 REF-04 的配色迁移版。锁定参考图一的外轮廓、红块、青块和孔洞边界不动;把中间主形调成更高级的淡奶油黄、黄油白黄或柔软黄米色,颜色要更淡一点、更轻一点、更透一点,不要土黄、脏黄、焦糖黄、芥末黄,也不要偏橙偏褐。中心空洞使用参考图三的星星:必须是饱满的四角闪光星,带短小光芒,不能被拉长成细十字,不能变成五角星,也不能出现厚底托。整体保持白底、扁平、品牌 logo 感。无文字、无字母、无3D、无聊天气泡。',
|
||||
},
|
||||
{
|
||||
id: 'taonier-ref04-palette-refine-v3-milk-cream',
|
||||
title: '奶霜淡黄',
|
||||
referenceImages: [
|
||||
paletteShapeReferencePath,
|
||||
paletteRefineV2ReferencePath,
|
||||
sparkleCropReferencePath,
|
||||
],
|
||||
prompt:
|
||||
'基于三张参考图输出一版更轻的 REF-04 logo。第一张参考只负责锁定原始造型;第二张参考只负责当前配色关系;第三张参考只负责中心闪光星的样子。中间主形改成低饱和的奶霜淡黄,颜色要轻柔、通透、像淡淡的黄油和牛奶混合,不要土、不要厚、不要脏。星星保持参考图三的四角闪光星和短光芒,不许拉伸,不许变形,不许五角星化。红块和青块位置固定。无文字、无字母、无手、无播放键、无3D。',
|
||||
},
|
||||
{
|
||||
id: 'taonier-ref04-palette-refine-v3-soft-vanilla',
|
||||
title: '香草奶黄',
|
||||
referenceImages: [
|
||||
paletteShapeReferencePath,
|
||||
paletteRefineV2ReferencePath,
|
||||
sparkleCropReferencePath,
|
||||
],
|
||||
prompt:
|
||||
'继续保持 REF-04 的造型锁定,做一次更安静的暖黄修正。中间主形变成香草奶黄或浅奶油黄,必须是低饱和、柔和、高级的淡黄,不要像土黄、咖喱黄、焦糖黄或偏橙黄。中心填充沿用参考图三的四角闪光星,星体要圆润饱满,旁边的短光芒保留,但不能夸张,不能拉长。外轮廓完全不动。白底、logo 感、扁平。无文字、无字母、无聊天气泡、无3D。',
|
||||
},
|
||||
];
|
||||
|
||||
const paletteRefineV4Concepts = [
|
||||
{
|
||||
id: 'taonier-ref04-palette-refine-v4-cream-paper',
|
||||
title: '奶油纸淡黄',
|
||||
referenceImages: [
|
||||
paletteShapeReferencePath,
|
||||
paletteRefineReferencePath,
|
||||
sparkleCropReferencePath,
|
||||
],
|
||||
prompt:
|
||||
'继续用 image-2 修正“陶泥儿” REF-04 logo。参考图一只用于锁定 REF-04 原型:外轮廓、右上粉红块、左下薄荷青块、中央孔洞边界都不要重新设计;参考图二只说明当前需要修正的版本;参考图三只用于中心星星。把中间原本土黄/脏黄的主形改成温暖、低饱和、淡淡的奶油纸黄色,接近 #F3E5B4 或 #F6E9C5,颜色要轻、干净、高级,不要陶土黄、芥末黄、咖喱黄、焦糖黄、橙黄、棕黄。中心孔洞里的星星必须保持参考图三原本的四角闪光星比例:上下左右四个圆润尖角,宽高自然,不能被横向或纵向拉伸,不能变成细十字,不能变成五角星,旁边短光芒也保持短小。白底、扁平品牌 logo。无文字、无字母、无播放键、无聊天气泡、无手、无3D。',
|
||||
},
|
||||
{
|
||||
id: 'taonier-ref04-palette-refine-v4-warm-ivory',
|
||||
title: '暖象牙淡黄',
|
||||
referenceImages: [
|
||||
paletteShapeReferencePath,
|
||||
paletteRefineReferencePath,
|
||||
sparkleCropReferencePath,
|
||||
],
|
||||
prompt:
|
||||
'基于三张参考图输出一版 REF-04 精修 logo。第一张参考图的形状和分区必须优先:主形轮廓不改、粉红块和薄荷青块位置不改、中间白色孔洞不改;只把中间主形从现在偏土的黄改成暖象牙淡黄,像很淡的黄油白、奶油米白、暖白纸,低饱和、柔和、通透,不要厚重和脏感。第三张参考图的四角闪光星需要原样放进中心:星体不能被压扁、不能拉长、不能瘦成十字,短光芒不要变多。整体保持成熟、干净、可做 App icon 的扁平 logo。无文字、无字母、无3D。',
|
||||
},
|
||||
{
|
||||
id: 'taonier-ref04-palette-refine-v4-soft-champagne',
|
||||
title: '淡香槟暖黄',
|
||||
referenceImages: [
|
||||
paletteShapeReferencePath,
|
||||
paletteRefineV2ReferencePath,
|
||||
sparkleCropReferencePath,
|
||||
],
|
||||
prompt:
|
||||
'为“陶泥儿”做一版更高级的 REF-04 暖黄精修。参考图一锁定基本造型,不允许改成播放按钮、三角形、气泡或新图标;参考图二只参考淡黄的轻盈程度;参考图三锁定星星。中间主形使用低饱和淡香槟黄/奶霜黄,颜色要非常淡、温暖、干净,不能像泥土、咖喱、焦糖、芥末或橙棕。中心星星必须是参考图三那种饱满四角闪光,保留短光芒,按原始宽高比例绘制,不能拉伸、不能变形、不能五角星化。粉红和薄荷青辅形保持克制。白底、扁平、品牌主标感。无文字、无字母、无3D、无复杂阴影。',
|
||||
},
|
||||
{
|
||||
id: 'taonier-ref04-palette-refine-v4-pale-butter',
|
||||
title: '淡黄油暖白',
|
||||
referenceImages: [
|
||||
paletteShapeReferencePath,
|
||||
paletteRefineV2ReferencePath,
|
||||
sparkleCropReferencePath,
|
||||
],
|
||||
prompt:
|
||||
'继续调整 REF-04 配色版本,只修正颜色和中心星星,不重画 logo。外轮廓、三块嵌合关系、中央孔洞边界以参考图一为准;中间主形换成淡黄油暖白,像轻薄奶油、温暖米白、浅黄纸,低饱和、不土、不脏、不橙、不褐。中心孔洞填入参考图三原样的四角闪光星:星星要圆润饱满,四个尖角长度均衡,短光芒短而自然,不能拉伸成细长十字。保留白底和扁平矢量 logo 气质。禁止文字、字母、五角星、播放键、聊天气泡、手、3D。',
|
||||
},
|
||||
];
|
||||
|
||||
const paletteRefineV5Concepts = [
|
||||
{
|
||||
id: 'taonier-ref04-palette-refine-v5-filled-centered-spark',
|
||||
title: '填心居中亮星',
|
||||
referenceImages: [
|
||||
paletteRefineV4PaleButterReferencePath,
|
||||
paletteShapeReferencePath,
|
||||
sparkleCropReferencePath,
|
||||
],
|
||||
prompt:
|
||||
'根据参考图修改“陶泥儿”04 图标,保留右上粉红块、左下薄荷青块和整体软泥圆润气质。重点做三处修改:1)补全左侧外轮廓曲线,让左侧从上到下形成连续、顺滑、饱满的弧线,不能有缺口、锯齿、截断或不自然凹陷;2)把中央白色空心孔洞完全用主体同色的温暖低饱和淡奶油黄填平,不能再出现白色中孔、白色环或内窗;3)把参考星星改成明亮的黄色四角闪光星,放在整个淡黄主体的视觉中央,星星清晰、圆润、比例自然,不要五角星,不要拉伸成十字。白底、扁平品牌 logo、干净高级。无文字、无字母、无播放键、无聊天气泡、无手、无3D。',
|
||||
},
|
||||
{
|
||||
id: 'taonier-ref04-palette-refine-v5-smooth-left-small-spark',
|
||||
title: '顺滑左弧小亮星',
|
||||
referenceImages: [
|
||||
paletteRefineV4PaleButterReferencePath,
|
||||
paletteShapeReferencePath,
|
||||
sparkleCropReferencePath,
|
||||
],
|
||||
prompt:
|
||||
'继续精修“陶泥儿”04 图标。以参考图一的 04 配色和比例为基础,但不要保留中央白洞。左侧外边缘需要补成更完整、更协调的连续曲线,像一整块柔软陶泥的自然外轮廓;中间原空心区域必须填成和主形一致的淡奶油黄色,与主体融为一体。中心放一枚明亮黄色四角闪光星,星星略小、居中、干净,不带复杂底托,不是五角星,不是细长十字。粉红块和薄荷青块仍然分离在右上和左下,白色间隔保持干净。无文字、无字母、无3D。',
|
||||
},
|
||||
{
|
||||
id: 'taonier-ref04-palette-refine-v5-balanced-bright-spark',
|
||||
title: '平衡亮星',
|
||||
referenceImages: [
|
||||
paletteRefineV4PaleButterReferencePath,
|
||||
paletteShapeReferencePath,
|
||||
sparkleCropReferencePath,
|
||||
],
|
||||
prompt:
|
||||
'为“陶泥儿”输出一版更协调的 04 图标修改稿。主形是温暖、低饱和、淡淡的奶油黄色;请补齐左侧曲线,让左边外轮廓更圆润完整,整体重心更稳。中央空心区域不再留白,必须填平为同样的淡黄色主形。把四角闪光星改成更明亮、更清楚的黄色,准确放在图标中央,星体饱满,四个尖角均衡,可以有很短的小光芒但不要抢主体。保持扁平 logo 感和白底。禁止文字、字母、五角星、播放键、聊天气泡、手、3D。',
|
||||
},
|
||||
{
|
||||
id: 'taonier-ref04-palette-refine-v5-solid-core-no-hole',
|
||||
title: '实体主形亮星',
|
||||
referenceImages: [
|
||||
paletteRefineV4PaleButterReferencePath,
|
||||
paletteShapeReferencePath,
|
||||
sparkleCropReferencePath,
|
||||
],
|
||||
prompt:
|
||||
'按用户参考图修改 04 logo:把淡黄主形做成一个更完整的实体软泥形。左侧曲线补全并顺滑化,外轮廓不要破碎;原中央白色孔洞完全消失,改成与主形同色的淡奶油黄实体面;在实体面的正中央放一枚明亮黄色四角闪光星,星星比主体颜色更亮,有明确识别但不幼稚。保持右上粉红块和左下薄荷青块的年轻配色,整体干净、轻盈、品牌主标感。无文字、无字母、无内孔、无白色中窗、无五角星、无播放键、无3D。',
|
||||
},
|
||||
];
|
||||
|
||||
const args = new Map();
|
||||
for (let index = 2; index < process.argv.length; index += 1) {
|
||||
const raw = process.argv[index];
|
||||
@@ -201,6 +667,24 @@ const concepts =
|
||||
? magicDotConcepts
|
||||
: style === 'hands'
|
||||
? handsConcepts
|
||||
: style === 'broad'
|
||||
? broadConcepts
|
||||
: style === 'fresh'
|
||||
? freshConcepts
|
||||
: style === 'punch'
|
||||
? punchConcepts
|
||||
: style === 'punch04'
|
||||
? punch04Concepts
|
||||
: style === 'palette-refine'
|
||||
? paletteRefineConcepts
|
||||
: style === 'palette-refine-v2'
|
||||
? paletteRefineV2Concepts
|
||||
: style === 'palette-refine-v3'
|
||||
? paletteRefineV3Concepts
|
||||
: style === 'palette-refine-v4'
|
||||
? paletteRefineV4Concepts
|
||||
: style === 'palette-refine-v5'
|
||||
? paletteRefineV5Concepts
|
||||
: dimensionalConcepts;
|
||||
const selectedOutputDir =
|
||||
style === 'flat'
|
||||
@@ -221,6 +705,69 @@ const selectedOutputDir =
|
||||
'branding',
|
||||
'taonier-logo-hands-concepts',
|
||||
)
|
||||
: style === 'broad'
|
||||
? path.join(
|
||||
repoRoot,
|
||||
'public',
|
||||
'branding',
|
||||
'taonier-logo-broad-concepts',
|
||||
)
|
||||
: style === 'fresh'
|
||||
? path.join(
|
||||
repoRoot,
|
||||
'public',
|
||||
'branding',
|
||||
'taonier-logo-fresh-concepts',
|
||||
)
|
||||
: style === 'punch'
|
||||
? path.join(
|
||||
repoRoot,
|
||||
'public',
|
||||
'branding',
|
||||
'taonier-logo-punch-hole-concepts',
|
||||
)
|
||||
: style === 'punch04'
|
||||
? path.join(
|
||||
repoRoot,
|
||||
'public',
|
||||
'branding',
|
||||
'taonier-logo-punch04-color-concepts',
|
||||
)
|
||||
: style === 'palette-refine'
|
||||
? path.join(
|
||||
repoRoot,
|
||||
'public',
|
||||
'branding',
|
||||
'taonier-logo-ref04-palette-refine-concepts',
|
||||
)
|
||||
: style === 'palette-refine-v2'
|
||||
? path.join(
|
||||
repoRoot,
|
||||
'public',
|
||||
'branding',
|
||||
'taonier-logo-ref04-palette-refine-v2-concepts',
|
||||
)
|
||||
: style === 'palette-refine-v3'
|
||||
? path.join(
|
||||
repoRoot,
|
||||
'public',
|
||||
'branding',
|
||||
'taonier-logo-ref04-palette-refine-v3-concepts',
|
||||
)
|
||||
: style === 'palette-refine-v4'
|
||||
? path.join(
|
||||
repoRoot,
|
||||
'public',
|
||||
'branding',
|
||||
'taonier-logo-ref04-palette-refine-v4-concepts',
|
||||
)
|
||||
: style === 'palette-refine-v5'
|
||||
? path.join(
|
||||
repoRoot,
|
||||
'public',
|
||||
'branding',
|
||||
'taonier-logo-ref04-palette-refine-v5-concepts',
|
||||
)
|
||||
: outputDir;
|
||||
|
||||
function readDotenv(fileName) {
|
||||
@@ -276,6 +823,82 @@ function buildUrl(baseUrl) {
|
||||
: `${baseUrl}/v1/images/generations`;
|
||||
}
|
||||
|
||||
function hasHeader(headers, targetName) {
|
||||
return Object.keys(headers).some(
|
||||
(name) => name.toLowerCase() === targetName.toLowerCase(),
|
||||
);
|
||||
}
|
||||
|
||||
async function requestBuffer(url, options, timeoutMs, redirectCount = 0) {
|
||||
const body =
|
||||
typeof options.body === 'string'
|
||||
? Buffer.from(options.body)
|
||||
: options.body || null;
|
||||
const headers = { ...(options.headers || {}) };
|
||||
if (body && !hasHeader(headers, 'content-length')) {
|
||||
headers['Content-Length'] = String(body.length);
|
||||
}
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
const parsedUrl = new URL(url);
|
||||
const transport = parsedUrl.protocol === 'http:' ? http : https;
|
||||
const request = transport.request(
|
||||
parsedUrl,
|
||||
{
|
||||
method: options.method || 'GET',
|
||||
headers,
|
||||
},
|
||||
(response) => {
|
||||
const statusCode = response.statusCode || 0;
|
||||
const location = response.headers.location;
|
||||
if (
|
||||
statusCode >= 300 &&
|
||||
statusCode < 400 &&
|
||||
location &&
|
||||
redirectCount < 5
|
||||
) {
|
||||
response.resume();
|
||||
const redirectedUrl = new URL(location, parsedUrl).toString();
|
||||
const preserveBody = statusCode === 307 || statusCode === 308;
|
||||
requestBuffer(
|
||||
redirectedUrl,
|
||||
preserveBody
|
||||
? options
|
||||
: {
|
||||
method: 'GET',
|
||||
headers: options.headers,
|
||||
},
|
||||
timeoutMs,
|
||||
redirectCount + 1,
|
||||
)
|
||||
.then(resolve)
|
||||
.catch(reject);
|
||||
return;
|
||||
}
|
||||
|
||||
const chunks = [];
|
||||
response.on('data', (chunk) => chunks.push(Buffer.from(chunk)));
|
||||
response.on('end', () =>
|
||||
resolve({
|
||||
statusCode,
|
||||
headers: response.headers,
|
||||
bytes: Buffer.concat(chunks),
|
||||
}),
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
request.setTimeout(timeoutMs, () => {
|
||||
request.destroy(new Error(`request timed out after ${timeoutMs}ms`));
|
||||
});
|
||||
request.on('error', reject);
|
||||
if (body) {
|
||||
request.write(body);
|
||||
}
|
||||
request.end();
|
||||
});
|
||||
}
|
||||
|
||||
function collectStringsByKey(value, targetKey, output) {
|
||||
if (Array.isArray(value)) {
|
||||
value.forEach((entry) => collectStringsByKey(entry, targetKey, output));
|
||||
@@ -331,45 +954,58 @@ function inferExtensionFromBytes(bytes) {
|
||||
return 'png';
|
||||
}
|
||||
|
||||
function imagePathToDataUrl(imagePath) {
|
||||
if (!existsSync(imagePath)) {
|
||||
throw new Error(`Reference image not found: ${imagePath}`);
|
||||
}
|
||||
|
||||
const bytes = readFileSync(imagePath);
|
||||
const extension = path.extname(imagePath).toLowerCase();
|
||||
const mimeType =
|
||||
extension === '.jpg' || extension === '.jpeg'
|
||||
? 'image/jpeg'
|
||||
: extension === '.webp'
|
||||
? 'image/webp'
|
||||
: 'image/png';
|
||||
return `data:${mimeType};base64,${bytes.toString('base64')}`;
|
||||
}
|
||||
|
||||
async function fetchJson(url, options, timeoutMs) {
|
||||
const abortController = new AbortController();
|
||||
const timer = setTimeout(() => abortController.abort(), timeoutMs);
|
||||
try {
|
||||
const response = await fetch(url, {
|
||||
...options,
|
||||
signal: abortController.signal,
|
||||
});
|
||||
const text = await response.text();
|
||||
if (!response.ok) {
|
||||
throw new Error(`VectorEngine ${response.status}: ${text.slice(0, 600)}`);
|
||||
const response = await requestBuffer(url, options, timeoutMs);
|
||||
const text = response.bytes.toString('utf8');
|
||||
if (response.statusCode < 200 || response.statusCode >= 300) {
|
||||
throw new Error(
|
||||
`VectorEngine ${response.statusCode}: ${text.slice(0, 600)}`,
|
||||
);
|
||||
}
|
||||
return JSON.parse(text);
|
||||
} catch (error) {
|
||||
if (error?.name === 'AbortError') {
|
||||
throw new Error(`VectorEngine request timed out after ${timeoutMs}ms`);
|
||||
if (String(error?.message || '').includes('timed out')) {
|
||||
throw new Error(
|
||||
`VectorEngine request timed out after ${timeoutMs}ms`,
|
||||
{ cause: error },
|
||||
);
|
||||
}
|
||||
throw error;
|
||||
} finally {
|
||||
clearTimeout(timer);
|
||||
}
|
||||
}
|
||||
|
||||
async function downloadUrl(url, timeoutMs) {
|
||||
const abortController = new AbortController();
|
||||
const timer = setTimeout(() => abortController.abort(), timeoutMs);
|
||||
try {
|
||||
const response = await fetch(url, { signal: abortController.signal });
|
||||
if (!response.ok) {
|
||||
throw new Error(`download ${response.status}`);
|
||||
const response = await requestBuffer(url, { method: 'GET' }, timeoutMs);
|
||||
if (response.statusCode < 200 || response.statusCode >= 300) {
|
||||
throw new Error(`download ${response.statusCode}`);
|
||||
}
|
||||
return Buffer.from(await response.arrayBuffer());
|
||||
return response.bytes;
|
||||
} catch (error) {
|
||||
if (error?.name === 'AbortError') {
|
||||
throw new Error(`Generated image download timed out after ${timeoutMs}ms`);
|
||||
if (String(error?.message || '').includes('timed out')) {
|
||||
throw new Error(
|
||||
`Generated image download timed out after ${timeoutMs}ms`,
|
||||
{ cause: error },
|
||||
);
|
||||
}
|
||||
throw error;
|
||||
} finally {
|
||||
clearTimeout(timer);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -380,6 +1016,9 @@ async function generateConcept(env, concept) {
|
||||
n: 1,
|
||||
size: '1024x1024',
|
||||
};
|
||||
if (concept.referenceImages?.length) {
|
||||
requestBody.image = concept.referenceImages.map(imagePathToDataUrl);
|
||||
}
|
||||
const payload = await fetchJson(
|
||||
buildUrl(env.baseUrl),
|
||||
{
|
||||
@@ -438,6 +1077,13 @@ if (dryRun) {
|
||||
prompt: concept.prompt,
|
||||
n: 1,
|
||||
size: '1024x1024',
|
||||
...(concept.referenceImages?.length
|
||||
? {
|
||||
image: concept.referenceImages.map((imagePath) =>
|
||||
path.relative(repoRoot, imagePath),
|
||||
),
|
||||
}
|
||||
: {}),
|
||||
},
|
||||
})),
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user