@zodic/shared 0.0.312 → 0.0.314
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,6 +3,7 @@ import { inject, injectable } from 'inversify';
|
|
|
3
3
|
import { ChatMessages, Composition, schema } from '../..';
|
|
4
4
|
import { KVArchetype, ZodiacSignSlug } from '../../types/scopes/legacy';
|
|
5
5
|
import { generateArchetypePrompt } from '../../utils/archetypeNamesMessages';
|
|
6
|
+
import { duplicatedArchetypeNamePrompt } from '../../utils/duplicatedArchetypeNamePrompt';
|
|
6
7
|
import { buildCosmicMirrorArchetypeKVKey } from '../../utils/KVKeysBuilders';
|
|
7
8
|
import { AppContext } from '../base';
|
|
8
9
|
|
|
@@ -449,18 +450,36 @@ export class ArchetypeService {
|
|
|
449
450
|
|
|
450
451
|
const { english, portuguese } = this.parseArchetypeNameBlocks(block);
|
|
451
452
|
|
|
453
|
+
// Check if parsing produced the expected number of entries
|
|
454
|
+
if (english.length !== 3 || portuguese.length !== 3) {
|
|
455
|
+
console.error(
|
|
456
|
+
`[Batch] Parsing failed for ${combination}. Expected 3 entries, got English: ${english.length}, Portuguese: ${portuguese.length}`
|
|
457
|
+
);
|
|
458
|
+
continue; // Skip this combination if parsing failed
|
|
459
|
+
}
|
|
460
|
+
|
|
452
461
|
for (let j = 0; j < 3; j++) {
|
|
453
462
|
const index = (j + 1).toString();
|
|
454
463
|
const englishEntry = english[j];
|
|
455
464
|
const ptEntry = portuguese[j];
|
|
456
465
|
|
|
457
|
-
if (
|
|
466
|
+
// Skip if either entry is missing (shouldn't happen with the above check, but added for safety)
|
|
467
|
+
if (!englishEntry || !ptEntry) {
|
|
458
468
|
console.warn(
|
|
459
|
-
|
|
469
|
+
`[Batch] Skipping index ${index} for ${combination} due to missing parsed data. English: ${JSON.stringify(
|
|
470
|
+
englishEntry
|
|
471
|
+
)}, Portuguese: ${JSON.stringify(ptEntry)}`
|
|
460
472
|
);
|
|
461
473
|
continue;
|
|
462
474
|
}
|
|
463
475
|
|
|
476
|
+
// if (await isEnglishNameDuplicate(englishEntry.name)) {
|
|
477
|
+
// console.warn(
|
|
478
|
+
// `⚠️ [Batch] Duplicate name skipped: ${englishEntry.name}`
|
|
479
|
+
// );
|
|
480
|
+
// continue;
|
|
481
|
+
// }
|
|
482
|
+
|
|
464
483
|
for (const gender of ['male', 'female']) {
|
|
465
484
|
const enId = `${combination}:${gender}:${index}`;
|
|
466
485
|
const ptId = `${combination}:${gender}:${index}:pt`;
|
|
@@ -733,26 +752,221 @@ export class ArchetypeService {
|
|
|
733
752
|
);
|
|
734
753
|
}
|
|
735
754
|
|
|
736
|
-
async
|
|
755
|
+
async regenerateDuplicateArchetypeNamesBatch(
|
|
756
|
+
entriesByCombination: Record<string, any[]>
|
|
757
|
+
) {
|
|
758
|
+
const db = this.context.drizzle();
|
|
759
|
+
console.log(
|
|
760
|
+
`[RegenerateDuplicatesBatch] Processing batch with ${
|
|
761
|
+
Object.keys(entriesByCombination).length
|
|
762
|
+
} combinations`
|
|
763
|
+
);
|
|
764
|
+
|
|
765
|
+
// Process each combination in the batch
|
|
766
|
+
for (const [combination, entries] of Object.entries(entriesByCombination)) {
|
|
767
|
+
console.log(
|
|
768
|
+
`[RegenerateDuplicatesBatch] Processing combination: ${combination}`
|
|
769
|
+
);
|
|
770
|
+
|
|
771
|
+
// Fetch all existing English names for this combination (across all archetypeIndex, gender, language)
|
|
772
|
+
const existingNamesResult = await db
|
|
773
|
+
.selectDistinct({ name: schema.archetypesData.name })
|
|
774
|
+
.from(schema.archetypesData)
|
|
775
|
+
.where(
|
|
776
|
+
and(
|
|
777
|
+
eq(schema.archetypesData.combination, combination),
|
|
778
|
+
eq(schema.archetypesData.language, 'en-us')
|
|
779
|
+
)
|
|
780
|
+
)
|
|
781
|
+
.execute();
|
|
782
|
+
|
|
783
|
+
let existingNames = existingNamesResult.map((r) => r.name);
|
|
784
|
+
console.log(
|
|
785
|
+
`[RegenerateDuplicatesBatch] Existing names for ${combination}: ${existingNames.join(
|
|
786
|
+
', '
|
|
787
|
+
)}`
|
|
788
|
+
);
|
|
789
|
+
|
|
790
|
+
// Process each entry with the duplicate name in this combination
|
|
791
|
+
for (const entry of entries) {
|
|
792
|
+
const { archetypeIndex, essenceLine } = entry;
|
|
793
|
+
console.log(
|
|
794
|
+
`[RegenerateDuplicatesBatch] Regenerating name for ${combination} (archetypeIndex: ${archetypeIndex})`
|
|
795
|
+
);
|
|
796
|
+
|
|
797
|
+
let newName: {
|
|
798
|
+
name_en: string;
|
|
799
|
+
name_pt_male: string;
|
|
800
|
+
name_pt_female: string;
|
|
801
|
+
} | null = null;
|
|
802
|
+
let attempts = 0;
|
|
803
|
+
const maxAttempts = 5;
|
|
804
|
+
|
|
805
|
+
// Generate a new name until a unique one is found
|
|
806
|
+
while (attempts < maxAttempts) {
|
|
807
|
+
attempts++;
|
|
808
|
+
console.log(
|
|
809
|
+
`[RegenerateDuplicatesBatch] Attempt ${attempts} to generate a new name for ${combination} (archetypeIndex: ${archetypeIndex})`
|
|
810
|
+
);
|
|
811
|
+
|
|
812
|
+
// Build the prompt
|
|
813
|
+
const prompt = duplicatedArchetypeNamePrompt({
|
|
814
|
+
combination,
|
|
815
|
+
essenceLine: essenceLine || 'A unique and meaningful archetype', // Fallback for null essenceLine
|
|
816
|
+
existingNames,
|
|
817
|
+
});
|
|
818
|
+
|
|
819
|
+
// Send the request to the AI
|
|
820
|
+
const messages: ChatMessages = [{ role: 'user', content: prompt }];
|
|
821
|
+
const response = await this.context
|
|
822
|
+
.api()
|
|
823
|
+
.callTogether.single(messages, {});
|
|
824
|
+
|
|
825
|
+
if (!response) {
|
|
826
|
+
console.error(
|
|
827
|
+
`[RegenerateDuplicatesBatch] No response from model for ${combination} (archetypeIndex: ${archetypeIndex})`
|
|
828
|
+
);
|
|
829
|
+
continue;
|
|
830
|
+
}
|
|
831
|
+
|
|
832
|
+
// Parse the response
|
|
833
|
+
try {
|
|
834
|
+
newName = JSON.parse(response);
|
|
835
|
+
console.log(
|
|
836
|
+
`[RegenerateDuplicatesBatch] Generated new name: ${JSON.stringify(
|
|
837
|
+
newName,
|
|
838
|
+
null,
|
|
839
|
+
2
|
|
840
|
+
)}`
|
|
841
|
+
);
|
|
842
|
+
|
|
843
|
+
// Validate the response format
|
|
844
|
+
if (
|
|
845
|
+
!newName ||
|
|
846
|
+
!newName.name_en ||
|
|
847
|
+
!newName.name_pt_male ||
|
|
848
|
+
!newName.name_pt_female
|
|
849
|
+
) {
|
|
850
|
+
console.error(
|
|
851
|
+
`[RegenerateDuplicatesBatch] Invalid response format for ${combination} (archetypeIndex: ${archetypeIndex}): ${response}`
|
|
852
|
+
);
|
|
853
|
+
newName = null;
|
|
854
|
+
continue;
|
|
855
|
+
}
|
|
856
|
+
} catch (error) {
|
|
857
|
+
console.error(
|
|
858
|
+
`[RegenerateDuplicatesBatch] Failed to parse AI response for ${combination} (archetypeIndex: ${archetypeIndex}): ${response}`,
|
|
859
|
+
error
|
|
860
|
+
);
|
|
861
|
+
continue;
|
|
862
|
+
}
|
|
863
|
+
|
|
864
|
+
// Check if the new name is unique (globally across all combinations)
|
|
865
|
+
const isDuplicate = await db
|
|
866
|
+
.select({ name: schema.archetypesData.name })
|
|
867
|
+
.from(schema.archetypesData)
|
|
868
|
+
.where(
|
|
869
|
+
and(
|
|
870
|
+
eq(schema.archetypesData.language, 'en-us'),
|
|
871
|
+
eq(schema.archetypesData.name, newName.name_en)
|
|
872
|
+
)
|
|
873
|
+
)
|
|
874
|
+
.limit(1)
|
|
875
|
+
.execute();
|
|
876
|
+
|
|
877
|
+
if (isDuplicate.length > 0) {
|
|
878
|
+
console.warn(
|
|
879
|
+
`[RegenerateDuplicatesBatch] Generated name "${newName.name_en}" is already used. Adding to existing names and retrying.`
|
|
880
|
+
);
|
|
881
|
+
existingNames.push(newName.name_en);
|
|
882
|
+
newName = null;
|
|
883
|
+
continue;
|
|
884
|
+
}
|
|
885
|
+
|
|
886
|
+
// If we reach here, the name is unique
|
|
887
|
+
break;
|
|
888
|
+
}
|
|
889
|
+
|
|
890
|
+
if (!newName) {
|
|
891
|
+
console.error(
|
|
892
|
+
`[RegenerateDuplicatesBatch] Failed to generate a unique name for ${combination} (archetypeIndex: ${archetypeIndex}) after ${maxAttempts} attempts`
|
|
893
|
+
);
|
|
894
|
+
continue;
|
|
895
|
+
}
|
|
896
|
+
|
|
897
|
+
// Update the database with the new names
|
|
898
|
+
for (const gender of ['male', 'female']) {
|
|
899
|
+
const enId = `${combination}:${gender}:${archetypeIndex}`;
|
|
900
|
+
const ptId = `${combination}:${gender}:${archetypeIndex}:pt`;
|
|
901
|
+
|
|
902
|
+
// Update English entry
|
|
903
|
+
await db
|
|
904
|
+
.update(schema.archetypesData)
|
|
905
|
+
.set({
|
|
906
|
+
name: newName.name_en,
|
|
907
|
+
updatedAt: new Date().getTime(),
|
|
908
|
+
})
|
|
909
|
+
.where(
|
|
910
|
+
and(
|
|
911
|
+
eq(schema.archetypesData.id, enId),
|
|
912
|
+
eq(schema.archetypesData.language, 'en-us')
|
|
913
|
+
)
|
|
914
|
+
)
|
|
915
|
+
.execute();
|
|
916
|
+
|
|
917
|
+
// Update Portuguese entry
|
|
918
|
+
const ptName =
|
|
919
|
+
gender === 'female' ? newName.name_pt_female : newName.name_pt_male;
|
|
920
|
+
await db
|
|
921
|
+
.update(schema.archetypesData)
|
|
922
|
+
.set({
|
|
923
|
+
name: ptName,
|
|
924
|
+
updatedAt: new Date().getTime(),
|
|
925
|
+
})
|
|
926
|
+
.where(
|
|
927
|
+
and(
|
|
928
|
+
eq(schema.archetypesData.id, ptId),
|
|
929
|
+
eq(schema.archetypesData.language, 'pt-br')
|
|
930
|
+
)
|
|
931
|
+
)
|
|
932
|
+
.execute();
|
|
933
|
+
|
|
934
|
+
console.log(
|
|
935
|
+
`[RegenerateDuplicatesBatch] Updated ${combination} (archetypeIndex: ${archetypeIndex}, gender: ${gender}) with new name - English: ${newName.name_en}, Portuguese: ${ptName}`
|
|
936
|
+
);
|
|
937
|
+
}
|
|
938
|
+
}
|
|
939
|
+
}
|
|
940
|
+
|
|
941
|
+
console.log(`✅ [RegenerateDuplicatesBatch] Finished processing batch`);
|
|
942
|
+
}
|
|
943
|
+
|
|
944
|
+
async recycleArchetypeNameDumpsBatch(
|
|
945
|
+
compositions: Composition[]
|
|
946
|
+
): Promise<void> {
|
|
737
947
|
console.log('🔁 [Recycle] Starting recycling of archetype name dumps');
|
|
738
|
-
|
|
948
|
+
|
|
739
949
|
if (compositions.length === 0) {
|
|
740
950
|
console.log('✅ [Recycle] No compositions provided for recycling');
|
|
741
951
|
return;
|
|
742
952
|
}
|
|
743
|
-
|
|
953
|
+
|
|
744
954
|
console.log(
|
|
745
955
|
`📦 [Recycle] Total compositions to recycle: ${compositions.length}`
|
|
746
956
|
);
|
|
747
|
-
|
|
957
|
+
|
|
748
958
|
// Step 1: Process each composition
|
|
749
959
|
const db = this.context.drizzle();
|
|
750
960
|
for (const comp of compositions) {
|
|
751
961
|
const combination = [comp.sun, comp.ascendant, comp.moon].join('-');
|
|
752
962
|
const indexes = comp.indexesToGenerate ?? [1, 2, 3];
|
|
753
|
-
|
|
754
|
-
console.log(
|
|
755
|
-
|
|
963
|
+
|
|
964
|
+
console.log(
|
|
965
|
+
`🔄 [Recycle] Processing combination: ${combination} with indexes: [${indexes.join(
|
|
966
|
+
', '
|
|
967
|
+
)}]`
|
|
968
|
+
);
|
|
969
|
+
|
|
756
970
|
// Fetch all dump entries for this combination
|
|
757
971
|
const dumpEntries = await db
|
|
758
972
|
.select({
|
|
@@ -762,22 +976,28 @@ export class ArchetypeService {
|
|
|
762
976
|
.from(schema.archetypeNameDumps)
|
|
763
977
|
.where(eq(schema.archetypeNameDumps.combination, combination))
|
|
764
978
|
.execute();
|
|
765
|
-
|
|
979
|
+
|
|
766
980
|
console.log(
|
|
767
|
-
`[Recycle] Retrieved ${
|
|
981
|
+
`[Recycle] Retrieved ${
|
|
982
|
+
dumpEntries.length
|
|
983
|
+
} dump entries for ${combination}: ${JSON.stringify(
|
|
984
|
+
dumpEntries,
|
|
985
|
+
null,
|
|
986
|
+
2
|
|
987
|
+
)}`
|
|
768
988
|
);
|
|
769
|
-
|
|
989
|
+
|
|
770
990
|
if (dumpEntries.length === 0) {
|
|
771
991
|
console.log(
|
|
772
992
|
`⚠️ [Recycle] No dump entries found for combination: ${combination}`
|
|
773
993
|
);
|
|
774
994
|
continue;
|
|
775
995
|
}
|
|
776
|
-
|
|
996
|
+
|
|
777
997
|
// Step 2: Process each missing index
|
|
778
998
|
for (const index of indexes) {
|
|
779
999
|
console.log(`[Recycle] Processing index ${index} for ${combination}`);
|
|
780
|
-
|
|
1000
|
+
|
|
781
1001
|
// Find a dump entry that contains the specific index
|
|
782
1002
|
let rawText: string | null = null;
|
|
783
1003
|
let selectedEntryId: string | null = null;
|
|
@@ -791,21 +1011,25 @@ export class ArchetypeService {
|
|
|
791
1011
|
break;
|
|
792
1012
|
}
|
|
793
1013
|
}
|
|
794
|
-
|
|
1014
|
+
|
|
795
1015
|
if (!rawText) {
|
|
796
1016
|
console.log(
|
|
797
1017
|
`⚠️ [Recycle] No dump entry contains index ${index} for combination: ${combination}`
|
|
798
1018
|
);
|
|
799
1019
|
continue;
|
|
800
1020
|
}
|
|
801
|
-
|
|
1021
|
+
|
|
802
1022
|
// Clean up the raw text
|
|
803
|
-
console.log(
|
|
1023
|
+
console.log(
|
|
1024
|
+
`[Recycle] Cleaning rawText for index ${index}: ${rawText}`
|
|
1025
|
+
);
|
|
804
1026
|
const cleanedText = rawText
|
|
805
1027
|
.replace(/###|---\s*###|-\s*###/g, '')
|
|
806
1028
|
.trim();
|
|
807
|
-
console.log(
|
|
808
|
-
|
|
1029
|
+
console.log(
|
|
1030
|
+
`[Recycle] Cleaned text for index ${index}: ${cleanedText}`
|
|
1031
|
+
);
|
|
1032
|
+
|
|
809
1033
|
// Extract the specific index sections
|
|
810
1034
|
const enSectionMatch = cleanedText.match(
|
|
811
1035
|
new RegExp(`-EN ${index}\\.\\s*[^-]*(?=-EN|-PT|$)`, 's')
|
|
@@ -813,28 +1037,43 @@ export class ArchetypeService {
|
|
|
813
1037
|
const ptSectionMatch = cleanedText.match(
|
|
814
1038
|
new RegExp(`-PT ${index}\\.\\s*[^-]*(?=-EN|-PT|$)`, 's')
|
|
815
1039
|
);
|
|
816
|
-
|
|
1040
|
+
|
|
817
1041
|
console.log(
|
|
818
|
-
`[Recycle] Extracted sections for index ${index} - enSectionMatch: ${JSON.stringify(
|
|
1042
|
+
`[Recycle] Extracted sections for index ${index} - enSectionMatch: ${JSON.stringify(
|
|
1043
|
+
enSectionMatch
|
|
1044
|
+
)}, ptSectionMatch: ${JSON.stringify(ptSectionMatch)}`
|
|
819
1045
|
);
|
|
820
|
-
|
|
821
|
-
if (
|
|
1046
|
+
|
|
1047
|
+
if (
|
|
1048
|
+
!enSectionMatch ||
|
|
1049
|
+
!ptSectionMatch ||
|
|
1050
|
+
!enSectionMatch[0] ||
|
|
1051
|
+
!ptSectionMatch[0]
|
|
1052
|
+
) {
|
|
822
1053
|
console.log(
|
|
823
|
-
`⚠️ [Recycle] Could not extract index ${index} sections for combination: ${combination}. enSectionMatch: ${JSON.stringify(
|
|
1054
|
+
`⚠️ [Recycle] Could not extract index ${index} sections for combination: ${combination}. enSectionMatch: ${JSON.stringify(
|
|
1055
|
+
enSectionMatch
|
|
1056
|
+
)}, ptSectionMatch: ${JSON.stringify(ptSectionMatch)}`
|
|
824
1057
|
);
|
|
825
1058
|
continue;
|
|
826
1059
|
}
|
|
827
|
-
|
|
1060
|
+
|
|
828
1061
|
// Combine the extracted sections into a block for parsing
|
|
829
|
-
const block = `-EN\n${enSectionMatch[0]
|
|
1062
|
+
const block = `-EN\n${enSectionMatch[0]
|
|
1063
|
+
.replace(/-EN\s*/, '')
|
|
1064
|
+
.trim()}\n\n-PT\n${ptSectionMatch[0].replace(/-PT\s*/, '').trim()}`;
|
|
830
1065
|
console.log(`[Recycle] Constructed block for index ${index}: ${block}`);
|
|
831
|
-
|
|
1066
|
+
|
|
832
1067
|
// Step 3: Parse the block
|
|
833
1068
|
const { english, portuguese } = this.parseArchetypeNameBlocks(block);
|
|
834
1069
|
console.log(
|
|
835
|
-
`[Recycle] Parsed results for index ${index} - English: ${JSON.stringify(
|
|
1070
|
+
`[Recycle] Parsed results for index ${index} - English: ${JSON.stringify(
|
|
1071
|
+
english,
|
|
1072
|
+
null,
|
|
1073
|
+
2
|
|
1074
|
+
)}, Portuguese: ${JSON.stringify(portuguese, null, 2)}`
|
|
836
1075
|
);
|
|
837
|
-
|
|
1076
|
+
|
|
838
1077
|
if (english.length === 0 || portuguese.length === 0) {
|
|
839
1078
|
console.error(
|
|
840
1079
|
`❌ [Recycle] Parsing failed for index ${index} of combination: ${combination}. Block: ${block}`
|
|
@@ -860,27 +1099,33 @@ export class ArchetypeService {
|
|
|
860
1099
|
}
|
|
861
1100
|
continue;
|
|
862
1101
|
}
|
|
863
|
-
|
|
1102
|
+
|
|
864
1103
|
const englishEntry = english[0];
|
|
865
1104
|
const ptEntry = portuguese[0];
|
|
866
|
-
|
|
1105
|
+
|
|
867
1106
|
console.log(
|
|
868
|
-
`[Recycle] Extracted entries for index ${index} - englishEntry: ${JSON.stringify(
|
|
1107
|
+
`[Recycle] Extracted entries for index ${index} - englishEntry: ${JSON.stringify(
|
|
1108
|
+
englishEntry,
|
|
1109
|
+
null,
|
|
1110
|
+
2
|
|
1111
|
+
)}, ptEntry: ${JSON.stringify(ptEntry, null, 2)}`
|
|
869
1112
|
);
|
|
870
|
-
|
|
1113
|
+
|
|
871
1114
|
if (!englishEntry || !ptEntry) {
|
|
872
1115
|
console.warn(
|
|
873
|
-
`⚠️ [Recycle] Skipping index ${index} for ${combination} due to missing parsed data. englishEntry: ${JSON.stringify(
|
|
1116
|
+
`⚠️ [Recycle] Skipping index ${index} for ${combination} due to missing parsed data. englishEntry: ${JSON.stringify(
|
|
1117
|
+
englishEntry
|
|
1118
|
+
)}, ptEntry: ${JSON.stringify(ptEntry)}`
|
|
874
1119
|
);
|
|
875
1120
|
continue;
|
|
876
1121
|
}
|
|
877
|
-
|
|
1122
|
+
|
|
878
1123
|
// Step 4: Insert the parsed data into archetypes_data
|
|
879
1124
|
for (const gender of ['male', 'female']) {
|
|
880
1125
|
const enId = `${combination}:${gender}:${index}`;
|
|
881
1126
|
const ptId = `${combination}:${gender}:${index}:pt`;
|
|
882
1127
|
const ptName = gender === 'female' ? ptEntry.fem : ptEntry.masc;
|
|
883
|
-
|
|
1128
|
+
|
|
884
1129
|
console.log(
|
|
885
1130
|
`[Recycle] Inserting English entry for ${combination}, index ${index}, gender ${gender}: id=${enId}, name=${englishEntry.name}, essenceLine=${englishEntry.essenceLine}`
|
|
886
1131
|
);
|
|
@@ -905,7 +1150,7 @@ export class ArchetypeService {
|
|
|
905
1150
|
updatedAt: new Date().getTime(),
|
|
906
1151
|
},
|
|
907
1152
|
});
|
|
908
|
-
|
|
1153
|
+
|
|
909
1154
|
console.log(
|
|
910
1155
|
`[Recycle] Inserting Portuguese entry for ${combination}, index ${index}, gender ${gender}: id=${ptId}, name=${ptName}, essenceLine=${ptEntry.essenceLine}`
|
|
911
1156
|
);
|
|
@@ -930,7 +1175,7 @@ export class ArchetypeService {
|
|
|
930
1175
|
updatedAt: new Date().getTime(),
|
|
931
1176
|
},
|
|
932
1177
|
});
|
|
933
|
-
|
|
1178
|
+
|
|
934
1179
|
// Delete the processed dump entry
|
|
935
1180
|
if (selectedEntryId) {
|
|
936
1181
|
console.log(
|
|
@@ -947,16 +1192,16 @@ export class ArchetypeService {
|
|
|
947
1192
|
`[Recycle] Could not delete dump entry for ${combination}, index ${index}: selectedEntryId is null`
|
|
948
1193
|
);
|
|
949
1194
|
}
|
|
950
|
-
|
|
1195
|
+
|
|
951
1196
|
console.log(
|
|
952
1197
|
`✅ [Recycle] Saved archetype ${index} (${gender}) for ${combination}`
|
|
953
1198
|
);
|
|
954
1199
|
}
|
|
955
1200
|
}
|
|
956
|
-
|
|
1201
|
+
|
|
957
1202
|
console.log(`🏁 [Recycle] Finished combination: ${combination}`);
|
|
958
1203
|
}
|
|
959
|
-
|
|
1204
|
+
|
|
960
1205
|
console.log(
|
|
961
1206
|
`🎉 [Recycle] Completed recycling for ${compositions.length} combinations`
|
|
962
1207
|
);
|
|
@@ -1022,95 +1267,139 @@ export class ArchetypeService {
|
|
|
1022
1267
|
portuguese: any[];
|
|
1023
1268
|
} {
|
|
1024
1269
|
console.log(`[Parse] Starting parsing of block: ${block}`);
|
|
1025
|
-
|
|
1270
|
+
|
|
1271
|
+
// Split the block into sections based on -EN and -PT markers
|
|
1026
1272
|
const sections = block.split(/^-EN|^-PT/m).filter((s) => s.trim());
|
|
1027
1273
|
console.log(
|
|
1028
|
-
`[Parse] Split block into ${sections.length} sections: ${JSON.stringify(
|
|
1274
|
+
`[Parse] Split block into ${sections.length} sections: ${JSON.stringify(
|
|
1275
|
+
sections,
|
|
1276
|
+
null,
|
|
1277
|
+
2
|
|
1278
|
+
)}`
|
|
1029
1279
|
);
|
|
1030
|
-
|
|
1280
|
+
|
|
1031
1281
|
const english: any[] = [];
|
|
1032
1282
|
const portuguese: any[] = [];
|
|
1033
|
-
|
|
1034
|
-
|
|
1283
|
+
|
|
1284
|
+
// Track whether we're in an EN or PT section
|
|
1285
|
+
let currentLang: 'EN' | 'PT' | null = null;
|
|
1286
|
+
|
|
1287
|
+
for (let i = 0; i < block.length; i++) {
|
|
1288
|
+
if (block.startsWith('-EN', i)) {
|
|
1289
|
+
currentLang = 'EN';
|
|
1290
|
+
i += 3; // Skip past "-EN"
|
|
1291
|
+
} else if (block.startsWith('-PT', i)) {
|
|
1292
|
+
currentLang = 'PT';
|
|
1293
|
+
i += 3; // Skip past "-PT"
|
|
1294
|
+
}
|
|
1295
|
+
}
|
|
1296
|
+
|
|
1297
|
+
// Process each section
|
|
1298
|
+
for (let i = 0; i < sections.length; i++) {
|
|
1299
|
+
const section = sections[i].trim();
|
|
1035
1300
|
console.log(`[Parse] Processing section: ${section}`);
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
?.trim();
|
|
1053
|
-
console.log(`[Parse] English essenceMatch: ${essenceMatch}`);
|
|
1054
|
-
|
|
1055
|
-
if (nameMatch && essenceMatch) {
|
|
1056
|
-
const entry = { name: nameMatch, essenceLine: essenceMatch };
|
|
1057
|
-
english.push(entry);
|
|
1058
|
-
console.log(
|
|
1059
|
-
`[Parse] Added English entry: ${JSON.stringify(entry, null, 2)}`
|
|
1060
|
-
);
|
|
1061
|
-
} else {
|
|
1062
|
-
console.warn(
|
|
1063
|
-
`[Parse] Skipping English section due to missing fields. nameMatch: ${nameMatch}, essenceMatch: ${essenceMatch}`
|
|
1064
|
-
);
|
|
1065
|
-
}
|
|
1066
|
-
} else if (section.startsWith('PT')) {
|
|
1067
|
-
const lines = section.split('\n').filter((l) => l.trim());
|
|
1301
|
+
|
|
1302
|
+
// Determine the language based on the section's position relative to -EN and -PT markers
|
|
1303
|
+
const lang = i === 0 ? 'EN' : 'PT'; // First section after -EN, second after -PT
|
|
1304
|
+
|
|
1305
|
+
// Split the section into individual entries based on numbered markers (1., 2., 3.)
|
|
1306
|
+
const entries = section.split(/\n(?=\d+\.\s*)/).filter((e) => e.trim());
|
|
1307
|
+
console.log(
|
|
1308
|
+
`[Parse] Split section into ${entries.length} entries: ${JSON.stringify(
|
|
1309
|
+
entries,
|
|
1310
|
+
null,
|
|
1311
|
+
2
|
|
1312
|
+
)}`
|
|
1313
|
+
);
|
|
1314
|
+
|
|
1315
|
+
for (const entry of entries) {
|
|
1316
|
+
const lines = entry.split('\n').filter((l) => l.trim());
|
|
1068
1317
|
console.log(
|
|
1069
|
-
`[Parse] Extracted ${lines.length} lines from
|
|
1318
|
+
`[Parse] Extracted ${lines.length} lines from entry: ${JSON.stringify(
|
|
1319
|
+
lines,
|
|
1320
|
+
null,
|
|
1321
|
+
2
|
|
1322
|
+
)}`
|
|
1070
1323
|
);
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
}
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
} else {
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1324
|
+
|
|
1325
|
+
if (lang === 'EN') {
|
|
1326
|
+
const nameMatch = lines
|
|
1327
|
+
.find((l) => l.includes('• Name:'))
|
|
1328
|
+
?.split('• Name:')[1]
|
|
1329
|
+
?.trim();
|
|
1330
|
+
console.log(`[Parse] English nameMatch: ${nameMatch}`);
|
|
1331
|
+
|
|
1332
|
+
const essenceMatch = lines
|
|
1333
|
+
.find((l) => l.includes('• Essence:'))
|
|
1334
|
+
?.split('• Essence:')[1]
|
|
1335
|
+
?.trim();
|
|
1336
|
+
console.log(`[Parse] English essenceMatch: ${essenceMatch}`);
|
|
1337
|
+
|
|
1338
|
+
if (nameMatch && essenceMatch) {
|
|
1339
|
+
const englishEntry = { name: nameMatch, essenceLine: essenceMatch };
|
|
1340
|
+
english.push(englishEntry);
|
|
1341
|
+
console.log(
|
|
1342
|
+
`[Parse] Added English entry: ${JSON.stringify(
|
|
1343
|
+
englishEntry,
|
|
1344
|
+
null,
|
|
1345
|
+
2
|
|
1346
|
+
)}`
|
|
1347
|
+
);
|
|
1348
|
+
} else {
|
|
1349
|
+
console.warn(
|
|
1350
|
+
`[Parse] Skipping English entry due to missing fields. nameMatch: ${nameMatch}, essenceMatch: ${essenceMatch}`
|
|
1351
|
+
);
|
|
1352
|
+
}
|
|
1353
|
+
} else if (lang === 'PT') {
|
|
1354
|
+
const mascMatch = lines
|
|
1355
|
+
.find((l) => l.includes('• Masculino:'))
|
|
1356
|
+
?.split('• Masculino:')[1]
|
|
1357
|
+
?.trim();
|
|
1358
|
+
console.log(`[Parse] Portuguese mascMatch: ${mascMatch}`);
|
|
1359
|
+
|
|
1360
|
+
const femMatch = lines
|
|
1361
|
+
.find((l) => l.includes('• Feminino:'))
|
|
1362
|
+
?.split('• Feminino:')[1]
|
|
1363
|
+
?.trim();
|
|
1364
|
+
console.log(`[Parse] Portuguese femMatch: ${femMatch}`);
|
|
1365
|
+
|
|
1366
|
+
const essenceMatch = lines
|
|
1367
|
+
.find((l) => l.includes('• Essência:'))
|
|
1368
|
+
?.split('• Essência:')[1]
|
|
1369
|
+
?.trim();
|
|
1370
|
+
console.log(`[Parse] Portuguese essenceMatch: ${essenceMatch}`);
|
|
1371
|
+
|
|
1372
|
+
if (mascMatch && femMatch && essenceMatch) {
|
|
1373
|
+
const ptEntry = {
|
|
1374
|
+
masc: mascMatch,
|
|
1375
|
+
fem: femMatch,
|
|
1376
|
+
essenceLine: essenceMatch,
|
|
1377
|
+
};
|
|
1378
|
+
portuguese.push(ptEntry);
|
|
1379
|
+
console.log(
|
|
1380
|
+
`[Parse] Added Portuguese entry: ${JSON.stringify(
|
|
1381
|
+
ptEntry,
|
|
1382
|
+
null,
|
|
1383
|
+
2
|
|
1384
|
+
)}`
|
|
1385
|
+
);
|
|
1386
|
+
} else {
|
|
1387
|
+
console.warn(
|
|
1388
|
+
`[Parse] Skipping Portuguese entry due to missing fields. mascMatch: ${mascMatch}, femMatch: ${femMatch}, essenceMatch: ${essenceMatch}`
|
|
1389
|
+
);
|
|
1390
|
+
}
|
|
1104
1391
|
}
|
|
1105
|
-
} else {
|
|
1106
|
-
console.warn(`[Parse] Unrecognized section: ${section}`);
|
|
1107
1392
|
}
|
|
1108
1393
|
}
|
|
1109
|
-
|
|
1394
|
+
|
|
1110
1395
|
console.log(
|
|
1111
|
-
`[Parse] Final parsed results - English: ${JSON.stringify(
|
|
1396
|
+
`[Parse] Final parsed results - English: ${JSON.stringify(
|
|
1397
|
+
english,
|
|
1398
|
+
null,
|
|
1399
|
+
2
|
|
1400
|
+
)}, Portuguese: ${JSON.stringify(portuguese, null, 2)}`
|
|
1112
1401
|
);
|
|
1113
|
-
|
|
1402
|
+
|
|
1114
1403
|
return { english, portuguese };
|
|
1115
1404
|
}
|
|
1116
1405
|
}
|
package/package.json
CHANGED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
type ArchetypePromptInputs = {
|
|
2
|
+
combination: string;
|
|
3
|
+
essenceLine: string;
|
|
4
|
+
existingNames: string[];
|
|
5
|
+
};
|
|
6
|
+
|
|
7
|
+
export function duplicatedArchetypeNamePrompt({
|
|
8
|
+
combination,
|
|
9
|
+
essenceLine,
|
|
10
|
+
existingNames,
|
|
11
|
+
}: ArchetypePromptInputs): string {
|
|
12
|
+
return `
|
|
13
|
+
You are a creative naming assistant for a symbolic astrology project. Each archetype is defined by a unique combination of three zodiac signs (Sun, Moon, Ascendant), and has an associated *essence line* that captures its spiritual and psychological meaning. Your task is to generate a new, poetic and meaningful name for the archetype, ensuring it is unique among previously used names.
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
Input:
|
|
18
|
+
|
|
19
|
+
- Combination: \`${combination}\`
|
|
20
|
+
- Essence Line: \`${essenceLine}\`
|
|
21
|
+
- Existing Names: \`${JSON.stringify(existingNames)}\`
|
|
22
|
+
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
Important Instructions:
|
|
26
|
+
|
|
27
|
+
1. Create a new archetype name that poetically reflects the given essence line.
|
|
28
|
+
2. The name should follow the same style as existing archetypes (e.g., \`The Wandering Alchemist\`, \`The Radiant Mask\`, \`The Harmonious Builder\`).
|
|
29
|
+
3. The name must not appear in the list of existing names.
|
|
30
|
+
4. Also generate Portuguese translations of the name:
|
|
31
|
+
- One in masculine form.
|
|
32
|
+
- One in feminine form.
|
|
33
|
+
5. Ensure all outputs are semantically coherent and well-written.
|
|
34
|
+
6. Use the following output format precisely.
|
|
35
|
+
|
|
36
|
+
---
|
|
37
|
+
|
|
38
|
+
Output Format (exactly like this, do not change it):
|
|
39
|
+
|
|
40
|
+
{
|
|
41
|
+
"name_en": <Name in English>,
|
|
42
|
+
"name_pt_male": <Name in Portuguese Male>,
|
|
43
|
+
"name_pt_female": <Name in Portuguese Female>,
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
`;
|
|
47
|
+
}
|