@zodic/shared 0.0.90 → 0.0.92

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -3,7 +3,7 @@ import { inject, injectable } from 'inversify';
3
3
  import 'reflect-metadata';
4
4
  import { v4 as uuidv4 } from 'uuid';
5
5
  import { schema } from '../..';
6
- import { Languages } from '../../types';
6
+ import { Concept, Languages } from '../../types';
7
7
  import { KVConcept, sizes } from '../../types/scopes/legacy';
8
8
  import { leonardoInitImages } from '../../utils/initImages';
9
9
  import { buildConceptKVKey } from '../../utils/KVKeysBuilders';
@@ -18,7 +18,7 @@ export class ConceptService {
18
18
  */
19
19
  async generateBasicInfo(
20
20
  language: Languages,
21
- conceptSlug: string,
21
+ conceptSlug: Concept,
22
22
  combinationString: string
23
23
  ): Promise<void> {
24
24
  const kvKey = buildConceptKVKey(language, conceptSlug, combinationString);
@@ -54,20 +54,26 @@ export class ConceptService {
54
54
  description: string;
55
55
  poem: string;
56
56
  } {
57
- console.log('Parsing basic info response from ChatGPT');
58
- const nameMatch = response.match(/- Name: (.+)/);
59
- const descriptionMatch = response.match(/- Description: (.+)/);
60
- const poemMatch = response.match(/- Poem: (.+)/);
57
+ console.log('📌 Parsing basic info response from ChatGPT:', response);
58
+
59
+ const nameMatch = response.match(/1\.\s*Name:\s*(.+)/);
60
+ const descriptionMatch = response.match(
61
+ /2\.\s*Description:\s*([\s\S]+?)\s*3\./
62
+ );
63
+ const poemMatch = response.match(/3\.\s*Poem\/Quote:\s*([\s\S]+)/);
61
64
 
62
65
  if (!nameMatch || !descriptionMatch || !poemMatch) {
66
+ console.error('❌ Invalid basic info response format:', response);
63
67
  throw new Error('Invalid basic info response format');
64
68
  }
65
69
 
66
- return {
67
- name: nameMatch[1].trim(),
68
- description: descriptionMatch[1].trim(),
69
- poem: poemMatch[1].trim(),
70
- };
70
+ const name = nameMatch[1].trim();
71
+ const description = descriptionMatch[1].trim();
72
+ const poem = poemMatch[1].trim();
73
+
74
+ console.log('✅ Parsed basic info:', { name, description, poem });
75
+
76
+ return { name, description, poem };
71
77
  }
72
78
 
73
79
  /**
@@ -75,7 +81,7 @@ export class ConceptService {
75
81
  */
76
82
  async generatePrompt(
77
83
  language: Languages,
78
- conceptSlug: string,
84
+ conceptSlug: Concept,
79
85
  combinationString: string
80
86
  ): Promise<void> {
81
87
  const kvKey = buildConceptKVKey(language, conceptSlug, combinationString);
@@ -116,7 +122,7 @@ export class ConceptService {
116
122
  */
117
123
  async generateContent(
118
124
  language: Languages,
119
- conceptSlug: string,
125
+ conceptSlug: Concept,
120
126
  combinationString: string
121
127
  ): Promise<void> {
122
128
  const kvKey = buildConceptKVKey(language, conceptSlug, combinationString);
@@ -156,7 +162,7 @@ export class ConceptService {
156
162
  */
157
163
  async generateImages(
158
164
  language: Languages,
159
- conceptSlug: string,
165
+ conceptSlug: Concept,
160
166
  combinationString: string
161
167
  ): Promise<void> {
162
168
  const drizzle = this.context.drizzle();
@@ -165,7 +171,7 @@ export class ConceptService {
165
171
 
166
172
  const kvKey = buildConceptKVKey(language, conceptSlug, combinationString);
167
173
  console.log(
168
- `🚀 Queuing image generation for concept: ${conceptSlug}, combination: ${combinationString}, language: ${language}`
174
+ `Queuing image generation for concept: ${conceptSlug}, combination: ${combinationString}, language: ${language}`
169
175
  );
170
176
 
171
177
  const concept = await this.getKVConcept(kvKey);
@@ -175,7 +181,6 @@ export class ConceptService {
175
181
  );
176
182
  }
177
183
 
178
- // 🔍 Fetch Concept ID using conceptSlug
179
184
  const conceptRecord = await drizzle
180
185
  .select({
181
186
  id: concepts.id,
@@ -206,7 +211,7 @@ export class ConceptService {
206
211
  }
207
212
 
208
213
  console.log(
209
- `🌌 Extracted planet signs: ${planet1} -> ${planet1Sign}, ${planet2} -> ${planet2Sign}, ${planet3} -> ${planet3Sign}`
214
+ `Extracted planet signs: ${planet1} -> ${planet1Sign}, ${planet2} -> ${planet2Sign}, ${planet3} -> ${planet3Sign}`
210
215
  );
211
216
 
212
217
  // 🔍 Ensure Concept Combination exists
@@ -234,7 +239,7 @@ export class ConceptService {
234
239
  conceptId,
235
240
  planet1Sign,
236
241
  planet2Sign,
237
- planet3Sign, // Ensure null if planet3 is not used
242
+ planet3Sign,
238
243
  })
239
244
  .returning({ id: conceptCombinations.id });
240
245
 
@@ -246,8 +251,7 @@ export class ConceptService {
246
251
  `✅ Using conceptCombinationId: ${conceptCombinationId} for ${conceptSlug}:${combinationString}`
247
252
  );
248
253
 
249
- // 🎨 Request Leonardo AI image generation
250
- console.log(`🎨 Requesting Leonardo AI image generation...`);
254
+ console.log(`Requesting Leonardo AI image generation...`);
251
255
  const leonardoResponse = await this.context
252
256
  .api()
253
257
  .callLeonardo.generateImage({
@@ -256,12 +260,12 @@ export class ConceptService {
256
260
  height,
257
261
  controlNets: [
258
262
  {
259
- "initImageId": leonardoInitImages.concetps.crown.imageId,
260
- "initImageType": "UPLOADED",
261
- "preprocessorId": 100, // content reference
262
- "strengthType": "Low",
263
- },
264
- ]
263
+ initImageId: leonardoInitImages.concepts[conceptSlug].imageId,
264
+ initImageType: 'UPLOADED',
265
+ preprocessorId: 100, // content reference
266
+ strengthType: 'Low',
267
+ },
268
+ ],
265
269
  });
266
270
 
267
271
  const generationId = leonardoResponse?.sdGenerationJob?.generationId;
@@ -273,9 +277,8 @@ export class ConceptService {
273
277
 
274
278
  console.log(`✅ Leonardo Generation ID received: ${generationId}`);
275
279
 
276
- // 📝 Insert Generation Record with the received generationId
277
280
  await drizzle.insert(generations).values({
278
- id: generationId, // Use the ID from Leonardo
281
+ id: generationId,
279
282
  conceptCombinationId,
280
283
  type: 'concept_image',
281
284
  status: 'pending',
@@ -287,7 +290,7 @@ export class ConceptService {
287
290
  );
288
291
 
289
292
  console.log(
290
- `🎨 Leonardo AI image generation triggered for ${conceptSlug}:${combinationString}, tracking ID: ${generationId}`
293
+ `Leonardo AI image generation triggered for ${conceptSlug}:${combinationString}, tracking ID: ${generationId}`
291
294
  );
292
295
  }
293
296
  /**
@@ -26,7 +26,6 @@ export class LeonardoService {
26
26
  visualDescription: string;
27
27
  }> = [];
28
28
 
29
- // Fetch archetypes that need prompts
30
29
  for (const gender of VALID_GENDERS_ARRAY) {
31
30
  for (let index = 1; index <= 3; index++) {
32
31
  const kvKey = buildCosmicMirrorArchetypeKVKey(
@@ -57,7 +56,6 @@ export class LeonardoService {
57
56
 
58
57
  console.log('Archetypes requiring prompt generation:', promptsToGenerate);
59
58
 
60
- // Generate prompts
61
59
  const archetypes = promptsToGenerate.map(({ name, visualDescription }) => ({
62
60
  name,
63
61
  visualDescription,
@@ -69,7 +67,6 @@ export class LeonardoService {
69
67
  throw new Error('Mismatch between archetypes and generated prompts.');
70
68
  }
71
69
 
72
- // Update KV with generated prompts
73
70
  for (const [index, promptSet] of leonardoPrompts.entries()) {
74
71
  const { kvKey } = promptsToGenerate[index];
75
72
  console.log(`Updating KV with prompts for archetype: ${kvKey}`);
@@ -256,7 +253,6 @@ export class LeonardoService {
256
253
  console.log('Starting uploadImageByUrl with imageUrl:', imageUrl);
257
254
 
258
255
  try {
259
- // Fetch the image from the provided URL
260
256
  console.log('Fetching image from URL...');
261
257
  const response = await fetch(imageUrl);
262
258
 
@@ -279,7 +275,6 @@ export class LeonardoService {
279
275
  mimeType,
280
276
  });
281
277
 
282
- // Request a presigned URL for uploading
283
278
  console.log('Requesting presigned URL...');
284
279
  const presignedUrlData = await this.context
285
280
  .api()
@@ -297,7 +292,6 @@ export class LeonardoService {
297
292
 
298
293
  console.log('Presigned URL obtained:', presignedUrlData);
299
294
 
300
- // Prepare the file to upload
301
295
  const file = new File([blob], `upload.${fileExtension}`, {
302
296
  type: mimeType,
303
297
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zodic/shared",
3
- "version": "0.0.90",
3
+ "version": "0.0.92",
4
4
  "module": "index.ts",
5
5
  "type": "module",
6
6
  "publishConfig": {
@@ -43,12 +43,12 @@ export type CentralBindings = {
43
43
  ISSUER: string;
44
44
  GOOGLE_API_KEY: string;
45
45
  GOOGLE_SERVER_URL: string;
46
- GOOGLE_CLIENT_ID: string;
47
- GOOGLE_CLIENT_SECRET: string;
46
+ GOOGLE_OAUTH_CLIENT_ID: string;
47
+ GOOGLE_OAUTH_CLIENT_SECRET: string;
48
48
  GOOGLE_TIMEZONE_API_KEY: string;
49
49
  FACEBOOK_SERVER_URL: string;
50
- FACEBOOK_CLIENT_ID: string;
51
- FACEBOOK_CLIENT_SECRET: string;
50
+ FACEBOOK_OAUTH_CLIENT_ID: string;
51
+ FACEBOOK_OAUTH_CLIENT_SECRET: string;
52
52
  OAUTH_REDIRECT_URI: string;
53
53
  ASTROLOGY_WESTERN_USER_ID: string;
54
54
  ASTROLOGY_WESTERN_API_KEY: string;
@@ -100,11 +100,7 @@ export type BackendBindings = Env &
100
100
  | 'GOOGLE_API_KEY'
101
101
  | 'GOOGLE_TIMEZONE_API_KEY'
102
102
  | 'GOOGLE_SERVER_URL'
103
- | 'GOOGLE_CLIENT_ID'
104
- | 'GOOGLE_CLIENT_SECRET'
105
103
  | 'FACEBOOK_SERVER_URL'
106
- | 'FACEBOOK_CLIENT_ID'
107
- | 'FACEBOOK_CLIENT_SECRET'
108
104
  | 'OAUTH_REDIRECT_URI'
109
105
  | 'ASTROLOGY_WESTERN_API_KEY'
110
106
  | 'ASTROLOGY_WESTERN_USER_ID'
@@ -151,11 +147,11 @@ export type AuthBindings = Env &
151
147
  Pick<
152
148
  CentralBindings,
153
149
  | 'JWT_SECRET'
154
- | 'GOOGLE_CLIENT_ID'
155
- | 'GOOGLE_CLIENT_SECRET'
150
+ | 'GOOGLE_OAUTH_CLIENT_ID'
151
+ | 'GOOGLE_OAUTH_CLIENT_SECRET'
156
152
  | 'GOOGLE_SERVER_URL'
157
- | 'FACEBOOK_CLIENT_ID'
158
- | 'FACEBOOK_CLIENT_SECRET'
153
+ | 'FACEBOOK_OAUTH_CLIENT_ID'
154
+ | 'FACEBOOK_OAUTH_CLIENT_SECRET'
159
155
  | 'FACEBOOK_SERVER_URL'
160
156
  | 'OAUTH_REDIRECT_URI'
161
157
  | 'ISSUER'
@@ -141,7 +141,15 @@ export interface Crown {
141
141
  moon: string;
142
142
  }
143
143
 
144
- export type Concept = 'crown' | 'scepter' | 'amulet' | 'lantern' | 'orb';
144
+ export type Concept =
145
+ | 'crown'
146
+ | 'scepter'
147
+ | 'amulet'
148
+ | 'lantern'
149
+ | 'orb'
150
+ | 'ring';
151
+
152
+ export type Concepts = ['crown', 'scepter', 'amulet', 'lantern', 'orb', 'ring'];
145
153
  export type ConceptQueueMessage = {
146
154
  conceptSlug: string;
147
155
  combinationString: string;
@@ -1,13 +1,12 @@
1
- import { BackendBindings } from '../types';
1
+ import { BackendBindings, Concept } from '../types';
2
2
 
3
3
  export const conceptPrompts: (
4
4
  env: BackendBindings
5
- ) => Record<string, Record<string, string>> = (
6
- env
7
- ) => ({
5
+ ) => Record<string, Record<Concept, string>> = (env) => ({
8
6
  basicInfo: {
9
7
  crown: PROMPT_GENERATE_CROWN,
10
8
  scepter: PROMPT_GENERATE_SCEPTER,
9
+ ring: PROMPT_GENERATE_RING,
11
10
  amulet: PROMPT_GENERATE_AMULET,
12
11
  lantern: PROMPT_GENERATE_LANTERN,
13
12
  orb: PROMPT_GENERATE_ORB,
@@ -15,6 +14,7 @@ export const conceptPrompts: (
15
14
  content: {
16
15
  crown: PROMPT_GENERATE_CROWN_CONTENT,
17
16
  scepter: PROMPT_GENERATE_SCEPTER_CONTENT,
17
+ ring: PROMPT_GENERATE_RING_CONTENT,
18
18
  amulet: PROMPT_GENERATE_AMULET_CONTENT,
19
19
  lantern: PROMPT_GENERATE_LANTERN_CONTENT,
20
20
  orb: PROMPT_GENERATE_ORB_CONTENT,
@@ -22,6 +22,7 @@ export const conceptPrompts: (
22
22
  leonardoPrompt: {
23
23
  crown: PROMPT_GENERATE_CROWN_LEONARDO,
24
24
  scepter: PROMPT_GENERATE_SCEPTER_LEONARDO,
25
+ ring: PROMPT_GENERATE_RING_LEONARDO,
25
26
  amulet: PROMPT_GENERATE_AMULET_LEONARDO,
26
27
  lantern: PROMPT_GENERATE_LANTERN_LEONARDO,
27
28
  orb: PROMPT_GENERATE_ORB_LEONARDO,
@@ -72,6 +73,17 @@ For the given combination:
72
73
  Do not mention zodiac signs or planets explicitly in the content. Ensure the output is insightful, symbolic, and emotionally resonant.
73
74
  `;
74
75
 
76
+ export const PROMPT_GENERATE_RING = `
77
+ You are a skilled creative writer specializing in astrology and symbolic storytelling. Your task is to craft a name, description, and poetic quote for the Scepter concept. The Scepter reflects external influence and action, symbolizing leadership, initiative, and the ability to shape one’s surroundings, as influenced by a given zodiac sign combination.
78
+
79
+ For the given combination:
80
+ 1. Name: Keep it sober and descriptive, focusing on the Scepter’s symbolic purpose. It should start with “The Scepter of…”.
81
+ 2. Description: Write a concise, grounded narrative that links the Scepter’s qualities to the traits of the zodiac combination. Emphasize themes of authority, initiative, and action.
82
+ 3. Poem/Quote: Provide a short rhyming poetic paragraph or couplet (1-2 sentences) that encapsulates the Scepter’s essence. Use rhyme to inspire and evoke confidence.
83
+
84
+ Do not mention zodiac signs or planets explicitly in the content. Ensure the output is insightful, symbolic, and emotionally resonant.
85
+ `;
86
+
75
87
  export const PROMPT_GENERATE_AMULET = `
76
88
  You are a skilled creative writer specializing in astrology and symbolic storytelling. Your task is to craft a name, description, and poetic quote for the Amulet concept. The Amulet reflects healing and growth, representing protection, stability, and resilience, as influenced by a given zodiac sign combination.
77
89
 
@@ -131,6 +143,24 @@ For the provided Scepter name, description, and zodiac combination, expand on th
131
143
  Write each section with clarity, insight, and emotional resonance. Avoid mentioning zodiac signs or planets explicitly in the text. Ensure the content is symbolic, inspiring, and deeply aligned with the Scepter’s themes. Keep the response concise and meaningful.
132
144
  `;
133
145
 
146
+ export const PROMPT_GENERATE_RING_CONTENT = `
147
+ You are a skilled creative writer specializing in astrology and symbolic storytelling. Your task is to craft five distinct sections of descriptive content for the Ring concept. The Ring symbolizes Love and Bonds, representing the unseen forces of attraction, karmic connections, and the lessons woven into relationships, as influenced by a given zodiac sign combination.
148
+
149
+ For the provided Ring name, description, and zodiac combination, expand on the following themes:
150
+
151
+ 1. Magnetic Pull – Explore what the bearer unconsciously attracts in love, the qualities they draw into their life, and the recurring patterns that shape their relationships.
152
+
153
+ 2. Hidden Desires – Reveal the unspoken parts of the bearer’s romantic self, the emotions, needs, and passions that influence their approach to love, whether acknowledged or not.
154
+
155
+ 3. The Fated Dance – Describe how destiny and unseen forces shape the bearer’s relationships, including karmic encounters, serendipitous connections, and lessons bound by fate.
156
+
157
+ 4. Unveiling the Shadows – Reflect on the hidden lessons of past loves, the patterns that must be understood, and how past relationships contribute to emotional wisdom and healing.
158
+
159
+ 5. Your Love Power – Explore the bearer’s unique way of loving, their capacity for connection, and how they can embrace and express love in its truest, most fulfilling form.
160
+
161
+ Write each section with clarity, insight, and emotional resonance. Avoid mentioning zodiac signs or planets explicitly in the text. Ensure the content is symbolic, poetic, and deeply aligned with the Ring’s themes. Keep the response concise and meaningful.
162
+ `;
163
+
134
164
  export const PROMPT_GENERATE_AMULET_CONTENT = `
135
165
  You are a skilled creative writer specializing in astrology and symbolic storytelling. Your task is to craft five distinct sections of descriptive content for the Amulet concept. The Amulet symbolizes Healing and Growth, representing protection, resilience, and nurturing energy, as influenced by a given zodiac sign combination.
136
166
 
@@ -183,6 +213,10 @@ Ensure the design elements convey strength, authority, and purpose, while mainta
183
213
  Make the prompt start with: "Create an ultra-realistic, 8K resolution, HDR image of a regal scepter that symbolizes influence and authority, crafted with meaningful engravings and glowing with a commanding presence."
184
214
  `;
185
215
 
216
+ export const PROMPT_GENERATE_RING_LEONARDO = `
217
+ You are an expert creative writer specializing in crafting intricate and vivid prompts for AI image generation. Your task is to create a detailed, high-quality prompt for a symbolic ring that embodies love and bonds. The design of the ring must reflect the mystical and fated nature of deep relationships, shaped by a given zodiac sign combination. Describe the ring in detail, including its materials, structure, engravings, and artistic patterns. Focus on capturing the essence of attraction, karmic ties, and emotional depth through meaningful motifs and elegant, symbolic elements, avoiding direct references to zodiac signs. Highlight the aura or glow the ring emanates, the emotions it evokes, and the way it would be worn as a symbol of fate and devotion. Ensure the design conveys a sense of destined connection, passion, and spiritual intimacy, while maintaining an artistic and mystical tone. Include artistic rendering details such as “ultra-realistic,” “8K resolution,” “HDR lighting,” and “intricate details” to guide the AI model. Keep the description concise, under 1500 characters, and ensure it can be used directly with Leonardo.ai for image generation. Respond with a single descriptive paragraph based on the given zodiac sign combination."
218
+ `;
219
+
186
220
  export const PROMPT_GENERATE_AMULET_LEONARDO = `
187
221
  You are an expert creative writer specializing in crafting intricate and vivid prompts for AI image generation. Your task is to create a detailed, high-quality prompt for a symbolic amulet that embodies healing, growth, and protection. The design of the amulet must reflect the symbolic traits of a given zodiac sign combination.
188
222
 
@@ -1,9 +1,45 @@
1
- export const leonardoInitImages = {
2
- concetps: {
1
+ import { Concept } from '../types';
2
+
3
+ export const leonardoInitImages: LeonardoInitImages = {
4
+ concepts: {
3
5
  crown: {
4
6
  imageId: '450076a1-c6bb-4877-8a0b-c0d3ba72fca7',
5
7
  imageUrl:
6
8
  'https://cdn.leonardo.ai/users/b117a933-e5c9-45b2-96aa-4b619c2d74ba/initImages/450076a1-c6bb-4877-8a0b-c0d3ba72fca7.jpg',
7
9
  },
10
+ scepter: {
11
+ imageId: '450076a1-c6bb-4877-8a0b-c0d3ba72fca7',
12
+ imageUrl:
13
+ 'https://cdn.leonardo.ai/users/b117a933-e5c9-45b2-96aa-4b619c2d74ba/initImages/450076a1-c6bb-4877-8a0b-c0d3ba72fca7.jpg',
14
+ },
15
+ amulet: {
16
+ imageId: '450076a1-c6bb-4877-8a0b-c0d3ba72fca7',
17
+ imageUrl:
18
+ 'https://cdn.leonardo.ai/users/b117a933-e5c9-45b2-96aa-4b619c2d74ba/initImages/450076a1-c6bb-4877-8a0b-c0d3ba72fca7.jpg',
19
+ },
20
+ lantern: {
21
+ imageId: '450076a1-c6bb-4877-8a0b-c0d3ba72fca7',
22
+ imageUrl:
23
+ 'https://cdn.leonardo.ai/users/b117a933-e5c9-45b2-96aa-4b619c2d74ba/initImages/450076a1-c6bb-4877-8a0b-c0d3ba72fca7.jpg',
24
+ },
25
+ orb: {
26
+ imageId: '450076a1-c6bb-4877-8a0b-c0d3ba72fca7',
27
+ imageUrl:
28
+ 'https://cdn.leonardo.ai/users/b117a933-e5c9-45b2-96aa-4b619c2d74ba/initImages/450076a1-c6bb-4877-8a0b-c0d3ba72fca7.jpg',
29
+ },
30
+ ring: {
31
+ imageId: '450076a1-c6bb-4877-8a0b-c0d3ba72fca7',
32
+ imageUrl:
33
+ 'https://cdn.leonardo.ai/users/b117a933-e5c9-45b2-96aa-4b619c2d74ba/initImages/450076a1-c6bb-4877-8a0b-c0d3ba72fca7.jpg',
34
+ },
8
35
  },
9
36
  };
37
+
38
+ type ConceptsInitImages = Record<
39
+ Concept,
40
+ { imageId: string; imageUrl: string }
41
+ >;
42
+
43
+ type LeonardoInitImages = {
44
+ concepts: ConceptsInitImages;
45
+ };