Skip to content
This repository was archived by the owner on Jan 5, 2026. It is now read-only.

Commit 0791431

Browse files
refactor: split logo variations into parallel light, dark and monochrome generation
1 parent ba9d845 commit 0791431

4 files changed

Lines changed: 287 additions & 61 deletions

File tree

api/services/BandIdentity/branding.service.ts

Lines changed: 149 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,9 @@ import {
88
TypographyModel,
99
} from "../../models/brand-identity.model";
1010
import { LOGO_GENERATION_PROMPT } from "./prompts/singleGenerations/00_logo-generation-section.prompt";
11-
import { LOGO_VARIATIONS_GENERATION_PROMPT } from "./prompts/singleGenerations/01_logo-variations-generation.prompt";
11+
import { LOGO_VARIATION_LIGHT_PROMPT } from "./prompts/singleGenerations/logo-variation-light.prompt";
12+
import { LOGO_VARIATION_DARK_PROMPT } from "./prompts/singleGenerations/logo-variation-dark.prompt";
13+
import { LOGO_VARIATION_MONOCHROME_PROMPT } from "./prompts/singleGenerations/logo-variation-monochrome.prompt";
1214

1315
import { BRAND_HEADER_SECTION_PROMPT } from "./prompts/00_brand-header-section.prompt";
1416
import { LOGO_SYSTEM_SECTION_PROMPT } from "./prompts/01_logo-system-section.prompt";
@@ -181,21 +183,21 @@ export class BrandingService extends GenericService {
181183
stepName: "Brand Header",
182184
hasDependencies: false,
183185
},
184-
// {
185-
// promptConstant: LOGO_SYSTEM_SECTION_PROMPT + projectDescription,
186-
// stepName: "Logo System",
187-
// hasDependencies: false,
188-
// },
189-
// {
190-
// promptConstant: COLOR_PALETTE_SECTION_PROMPT + projectDescription,
191-
// stepName: "Color Palette",
192-
// hasDependencies: false,
193-
// },
194-
// {
195-
// promptConstant: TYPOGRAPHY_SECTION_PROMPT + projectDescription,
196-
// stepName: "Typography",
197-
// hasDependencies: false,
198-
// },
186+
{
187+
promptConstant: LOGO_SYSTEM_SECTION_PROMPT + projectDescription,
188+
stepName: "Logo System",
189+
hasDependencies: false,
190+
},
191+
{
192+
promptConstant: COLOR_PALETTE_SECTION_PROMPT + projectDescription,
193+
stepName: "Color Palette",
194+
hasDependencies: false,
195+
},
196+
{
197+
promptConstant: TYPOGRAPHY_SECTION_PROMPT + projectDescription,
198+
stepName: "Typography",
199+
hasDependencies: false,
200+
},
199201
// {
200202
// promptConstant: USAGE_GUIDELINES_SECTION_PROMPT + projectDescription,
201203
// stepName: "Usage Guidelines",
@@ -206,11 +208,11 @@ export class BrandingService extends GenericService {
206208
// stepName: "Visual Examples",
207209
// hasDependencies: false,
208210
// },
209-
// {
210-
// promptConstant: BRAND_FOOTER_SECTION_PROMPT + projectDescription,
211-
// stepName: "Brand Footer",
212-
// hasDependencies: false,
213-
// },
211+
{
212+
promptConstant: BRAND_FOOTER_SECTION_PROMPT + projectDescription,
213+
stepName: "Brand Footer",
214+
hasDependencies: false,
215+
},
214216
];
215217

216218
// Initialize empty sections array to collect results as they come in
@@ -866,8 +868,107 @@ export class BrandingService extends GenericService {
866868
}
867869

868870
/**
869-
* Generate logo variations using optimized JSON-to-SVG layered approach
870-
* Implements token-saving strategy with compact JSON generation
871+
* Generate single logo variation for light background
872+
*/
873+
private async generateSingleLightVariation(
874+
logoStructure: any,
875+
project: ProjectModel
876+
): Promise<{ lightBackground?: string }> {
877+
const prompt = `Logo structure: ${JSON.stringify(
878+
logoStructure
879+
)}\n\n${LOGO_VARIATION_LIGHT_PROMPT}`;
880+
881+
const steps: IPromptStep[] = [
882+
{
883+
promptConstant: prompt,
884+
stepName: "Light Background Variation",
885+
maxOutputTokens: 1000,
886+
modelParser: (content) => {
887+
try {
888+
const parsed = JSON.parse(content);
889+
return parsed.variation;
890+
} catch (error) {
891+
logger.error("Error parsing light variation JSON:", error);
892+
throw new Error("Failed to parse light variation JSON");
893+
}
894+
},
895+
hasDependencies: false,
896+
},
897+
];
898+
899+
const sectionResults = await this.processSteps(steps, project);
900+
return sectionResults[0].parsedData;
901+
}
902+
903+
/**
904+
* Generate single logo variation for dark background
905+
*/
906+
private async generateSingleDarkVariation(
907+
logoStructure: any,
908+
project: ProjectModel
909+
): Promise<{ darkBackground?: string }> {
910+
const prompt = `Logo structure: ${JSON.stringify(
911+
logoStructure
912+
)}\n\n${LOGO_VARIATION_DARK_PROMPT}`;
913+
914+
const steps: IPromptStep[] = [
915+
{
916+
promptConstant: prompt,
917+
stepName: "Dark Background Variation",
918+
maxOutputTokens: 1000,
919+
modelParser: (content) => {
920+
try {
921+
const parsed = JSON.parse(content);
922+
return parsed.variation;
923+
} catch (error) {
924+
logger.error("Error parsing dark variation JSON:", error);
925+
throw new Error("Failed to parse dark variation JSON");
926+
}
927+
},
928+
hasDependencies: false,
929+
},
930+
];
931+
932+
const sectionResults = await this.processSteps(steps, project);
933+
return sectionResults[0].parsedData;
934+
}
935+
936+
/**
937+
* Generate single logo variation for monochrome
938+
*/
939+
private async generateSingleMonochromeVariation(
940+
logoStructure: any,
941+
project: ProjectModel
942+
): Promise<{ monochrome?: string }> {
943+
const prompt = `Logo structure: ${JSON.stringify(
944+
logoStructure
945+
)}\n\n${LOGO_VARIATION_MONOCHROME_PROMPT}`;
946+
947+
const steps: IPromptStep[] = [
948+
{
949+
promptConstant: prompt,
950+
stepName: "Monochrome Variation",
951+
maxOutputTokens: 1000,
952+
modelParser: (content) => {
953+
try {
954+
const parsed = JSON.parse(content);
955+
return parsed.variation;
956+
} catch (error) {
957+
logger.error("Error parsing monochrome variation JSON:", error);
958+
throw new Error("Failed to parse monochrome variation JSON");
959+
}
960+
},
961+
hasDependencies: false,
962+
},
963+
];
964+
965+
const sectionResults = await this.processSteps(steps, project);
966+
return sectionResults[0].parsedData;
967+
}
968+
969+
/**
970+
* Generate logo variations using parallel execution for each variation type
971+
* Implements optimized parallel generation strategy
871972
*/
872973
async generateLogoVariations(
873974
userId: string,
@@ -886,7 +987,7 @@ export class BrandingService extends GenericService {
886987
};
887988
}> {
888989
logger.info(
889-
`Generating optimized logo variations using JSON-to-SVG conversion for logo: ${selectedLogo.id}`
990+
`Generating logo variations using parallel execution for logo: ${selectedLogo.id}`
890991
);
891992

892993
const project = await this.getProjectOptimized(userId, projectId);
@@ -902,35 +1003,29 @@ export class BrandingService extends GenericService {
9021003
concept: selectedLogo.concept,
9031004
};
9041005

905-
const prompt = `Logo structure: ${JSON.stringify(
906-
logoStructure
907-
)}\n\n${LOGO_VARIATIONS_GENERATION_PROMPT}`;
908-
909-
const steps: IPromptStep[] = [
910-
{
911-
promptConstant: prompt,
912-
stepName: "Logo Variations Generation",
913-
maxOutputTokens: 2000, // Increased tokens for detailed variations
914-
modelParser: (content) => {
915-
try {
916-
const variationsJson: LogoVariationsJson = JSON.parse(content);
917-
return variationsJson;
918-
} catch (error) {
919-
logger.error("Error parsing logo variations JSON:", error);
920-
throw new Error("Failed to parse logo variations JSON");
921-
}
922-
},
923-
hasDependencies: false,
924-
},
925-
];
1006+
// Execute all three variations in parallel
1007+
logger.info(`Starting parallel generation of 3 logo variations`);
1008+
const [lightVariation, darkVariation, monochromeVariation] = await Promise.all([
1009+
this.generateSingleLightVariation(logoStructure, project),
1010+
this.generateSingleDarkVariation(logoStructure, project),
1011+
this.generateSingleMonochromeVariation(logoStructure, project),
1012+
]);
9261013

927-
const sectionResults = await this.processSteps(steps, project);
928-
const variationsResult = sectionResults[0];
929-
const variationsJson: LogoVariationsJson = variationsResult.parsedData;
1014+
logger.info(`Successfully generated all 3 variations in parallel`);
9301015

931-
// Convert JSON variations to optimized SVGs
932-
const svgVariations =
933-
this.logoJsonToSvgService.convertVariationsJsonToSvg(variationsJson);
1016+
// Create direct SVG variations (bypassing JSON-to-SVG conversion since we already have SVGs)
1017+
const svgVariations = {
1018+
withText: {
1019+
lightBackground: lightVariation.lightBackground,
1020+
darkBackground: darkVariation.darkBackground,
1021+
monochrome: monochromeVariation.monochrome,
1022+
},
1023+
iconOnly: {
1024+
lightBackground: lightVariation.lightBackground,
1025+
darkBackground: darkVariation.darkBackground,
1026+
monochrome: monochromeVariation.monochrome,
1027+
},
1028+
};
9341029

9351030
// Apply advanced SVG optimization
9361031
const optimizedVariations = {
@@ -990,16 +1085,9 @@ export class BrandingService extends GenericService {
9901085
});
9911086

9921087
logger.info(
993-
`Optimized logo variations cached - ProjectId: ${projectId}, Shapes: ${Object.keys(
994-
variationsJson.variations
995-
)
996-
.map(
997-
(k) =>
998-
variationsJson.variations[
999-
k as keyof typeof variationsJson.variations
1000-
].shapes.length
1001-
)
1002-
.join("/")}`
1088+
`Optimized logo variations cached - ProjectId: ${projectId}, Variations: ${Object.keys(
1089+
optimizedVariations.iconOnly
1090+
).join("/")}`
10031091
);
10041092
}
10051093

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
export const LOGO_VARIATION_DARK_PROMPT = `
2+
Generate a professional logo variation optimized for DARK BACKGROUNDS with complete SVG code. Extract ONLY the icon part (no text) and adapt colors for dark background contrast. Return JSON with complete SVG content:
3+
4+
{
5+
"variation": {
6+
"darkBackground": "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 80 80\" width=\"80\" height=\"80\"><g id=\"icon\"><circle cx=\"40\" cy=\"40\" r=\"30\" fill=\"#60A5FA\"/></g></svg>"
7+
}
8+
}
9+
10+
SVG VARIATION GENERATION RULES:
11+
- GENERATE COMPLETE SVG CODE with proper XML structure
12+
- Extract ONLY the icon elements from the original logo (remove all text)
13+
- Use viewBox="0 0 80 80" for square icon format (80x80px minimum)
14+
- Include proper xmlns="http://www.w3.org/2000/svg" declaration
15+
- Maintain all original shape complexity and sophistication
16+
- Preserve geometric relationships and proportional scaling
17+
- Center the icon within the 80x80 viewBox for optimal presentation
18+
19+
DARK BACKGROUND COLOR ADAPTATION:
20+
- Use lighter, more vibrant versions of original colors for excellent contrast on dark backgrounds
21+
- Increase brightness by 30-50% from original colors
22+
- Add slight saturation boost for better visibility on dark backgrounds
23+
- Ensure WCAG AA contrast compliance (minimum 4.5:1 ratio)
24+
- Maintain color harmony and brand consistency
25+
- Preserve visual hierarchy through strategic color brightening
26+
27+
SVG STRUCTURE REQUIREMENTS:
28+
- Proper XML declaration and namespace
29+
- Clean <g id="icon"> grouping for organization
30+
- Maintain all original path complexity and Bézier curves
31+
- Preserve opacity values (0.6-1.0) for depth and visual richness
32+
- Scale coordinates proportionally to fit 80x80 viewBox
33+
- Center icon elements around cx="40" cy="40" reference point
34+
- Ensure scalable design that works at any size
35+
36+
COLOR TRANSFORMATION EXAMPLES:
37+
- Original #3B82F6 (blue) → #60A5FA (lighter blue for dark bg)
38+
- Original #10B981 (green) → #34D399 (lighter green for dark bg)
39+
- Original #F59E0B (orange) → #FCD34D (lighter orange for dark bg)
40+
- Original #8B5CF6 (purple) → #A78BFA (lighter purple for dark bg)
41+
42+
AVOID: Broken XML, missing namespaces, text elements, poor centering, colors too dark for contrast
43+
GOAL: Generate production-ready icon SVG optimized specifically for dark background usage with perfect contrast and visibility.
44+
`;
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
export const LOGO_VARIATION_LIGHT_PROMPT = `
2+
Generate a professional logo variation optimized for LIGHT BACKGROUNDS with complete SVG code. Extract ONLY the icon part (no text) and adapt colors for light background contrast. Return JSON with complete SVG content:
3+
4+
{
5+
"variation": {
6+
"lightBackground": "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 80 80\" width=\"80\" height=\"80\"><g id=\"icon\"><circle cx=\"40\" cy=\"40\" r=\"30\" fill=\"#2563EB\"/></g></svg>"
7+
}
8+
}
9+
10+
SVG VARIATION GENERATION RULES:
11+
- GENERATE COMPLETE SVG CODE with proper XML structure
12+
- Extract ONLY the icon elements from the original logo (remove all text)
13+
- Use viewBox="0 0 80 80" for square icon format (80x80px minimum)
14+
- Include proper xmlns="http://www.w3.org/2000/svg" declaration
15+
- Maintain all original shape complexity and sophistication
16+
- Preserve geometric relationships and proportional scaling
17+
- Center the icon within the 80x80 viewBox for optimal presentation
18+
19+
LIGHT BACKGROUND COLOR ADAPTATION:
20+
- Use darker versions of original colors for excellent contrast on light backgrounds
21+
- Reduce brightness by 20-40% from original colors
22+
- Ensure WCAG AA contrast compliance (minimum 4.5:1 ratio)
23+
- Maintain color harmony and brand consistency
24+
- Preserve visual hierarchy through strategic color darkening
25+
26+
SVG STRUCTURE REQUIREMENTS:
27+
- Proper XML declaration and namespace
28+
- Clean <g id="icon"> grouping for organization
29+
- Maintain all original path complexity and Bézier curves
30+
- Preserve opacity values (0.6-1.0) for depth and visual richness
31+
- Scale coordinates proportionally to fit 80x80 viewBox
32+
- Center icon elements around cx="40" cy="40" reference point
33+
- Ensure scalable design that works at any size
34+
35+
COLOR TRANSFORMATION EXAMPLES:
36+
- Original #3B82F6 (blue) → #1D4ED8 (darker blue for light bg)
37+
- Original #10B981 (green) → #047857 (darker green for light bg)
38+
- Original #F59E0B (orange) → #D97706 (darker orange for light bg)
39+
- Original #8B5CF6 (purple) → #7C3AED (darker purple for light bg)
40+
41+
AVOID: Broken XML, missing namespaces, text elements, poor centering, colors too light for contrast
42+
GOAL: Generate production-ready icon SVG optimized specifically for light background usage with perfect contrast and readability.
43+
`;

0 commit comments

Comments
 (0)