@zodic/shared 0.0.223 → 0.0.224

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.
@@ -1034,13 +1034,14 @@ export class ConceptService {
1034
1034
  conceptSlug: Concept,
1035
1035
  maxEntries?: number
1036
1036
  ) {
1037
- console.log(
1038
- `🔄 [START] Regenerating duplicate names for concept: ${conceptSlug}...`
1039
- );
1040
-
1037
+ console.log(`🔄 [START] Regenerating duplicate names for concept: ${conceptSlug}...`);
1038
+ const startTime = Date.now();
1039
+
1041
1040
  const db = drizzle(this.context.env.DB);
1042
-
1041
+
1043
1042
  // ✅ Step 1: Fetch duplicate entries filtered by conceptSlug
1043
+ console.log(`📡 Fetching duplicate entries for concept: ${conceptSlug}...`);
1044
+
1044
1045
  const duplicateEntries = await db
1045
1046
  .select({
1046
1047
  id: conceptsData.id,
@@ -1062,16 +1063,14 @@ export class ConceptService {
1062
1063
  )
1063
1064
  .limit(maxEntries || 50) // ✅ Apply optional limit
1064
1065
  .execute();
1065
-
1066
+
1066
1067
  if (!duplicateEntries.length) {
1067
1068
  console.log(`🎉 No duplicates found for ${conceptSlug}.`);
1068
1069
  return { message: `No duplicates detected for ${conceptSlug}.` };
1069
1070
  }
1070
-
1071
- console.log(
1072
- `🔍 Found ${duplicateEntries.length} duplicate entries to process.`
1073
- );
1074
-
1071
+
1072
+ console.log(`🔍 Found ${duplicateEntries.length} duplicate entries to process.`);
1073
+
1075
1074
  // ✅ Group duplicates by name
1076
1075
  const duplicateGroups = new Map<string, typeof duplicateEntries>();
1077
1076
  for (const entry of duplicateEntries) {
@@ -1080,59 +1079,50 @@ export class ConceptService {
1080
1079
  }
1081
1080
  duplicateGroups.get(entry.name)!.push(entry);
1082
1081
  }
1083
-
1082
+
1084
1083
  let recentDuplicates = new Set<string>(); // ✅ Track newly generated names
1085
1084
  let updatedEntries = 0;
1086
-
1085
+ let skippedEntries = 0;
1086
+ let failedEntries = 0;
1087
+
1087
1088
  for (const [duplicateName, entries] of duplicateGroups.entries()) {
1088
- console.log(
1089
- `🔄 Processing duplicate group: "${duplicateName}" with ${entries.length} occurrences`
1090
- );
1091
-
1089
+ console.log(`🔄 Processing duplicate group: "${duplicateName}" with ${entries.length} occurrences`);
1090
+
1092
1091
  // ✅ Leave the first entry unchanged and only process the extras
1093
1092
  const [keepEntry, ...entriesToProcess] = entries;
1094
1093
  console.log(`✅ Keeping original name for ID: ${keepEntry.id}`);
1095
-
1094
+
1096
1095
  for (const entry of entriesToProcess) {
1097
1096
  const { id, description, combination } = entry;
1098
-
1097
+
1099
1098
  console.log(`🎭 Processing duplicate ID ${id}: "${duplicateName}"`);
1100
-
1099
+
1101
1100
  let newNameEN: string | null = null;
1102
1101
  let newNamePT: string | null = null;
1103
1102
  let attempts = 0;
1104
1103
  const maxAttempts = 3;
1105
-
1104
+
1106
1105
  while (attempts < maxAttempts) {
1107
1106
  attempts++;
1108
-
1109
- console.log(
1110
- `📡 Attempt ${attempts}/${maxAttempts} - Requesting AI for new name...`
1111
- );
1112
-
1107
+ console.log(`📡 Attempt ${attempts}/${maxAttempts} - Requesting AI for a new name...`);
1108
+
1113
1109
  // ✅ Generate a new name, passing dynamically tracked duplicates
1114
- const messages = this.context
1115
- .buildLLMMessages()
1116
- .regenerateConceptName({
1117
- conceptSlug,
1118
- oldNameEN: duplicateName,
1119
- description,
1120
- recentNames: Array.from(recentDuplicates),
1121
- });
1122
-
1123
- const aiResponse = await this.context
1124
- .api()
1125
- .callTogether.single(messages, {});
1126
-
1110
+ const messages = this.context.buildLLMMessages().regenerateConceptName({
1111
+ conceptSlug,
1112
+ oldNameEN: duplicateName,
1113
+ description,
1114
+ recentNames: Array.from(recentDuplicates),
1115
+ });
1116
+
1117
+ const aiResponse = await this.context.api().callTogether.single(messages, {});
1118
+
1127
1119
  if (!aiResponse) {
1128
- console.warn(
1129
- `⚠️ AI failed to generate a new name for ID ${id}, skipping.`
1130
- );
1120
+ console.warn(`⚠️ AI failed to generate a new name for ID ${id}, skipping.`);
1131
1121
  break;
1132
1122
  }
1133
-
1123
+
1134
1124
  console.log(`📝 Raw AI Response:\n${aiResponse}`);
1135
-
1125
+
1136
1126
  // ✅ Mapping for concept names with proper PT articles
1137
1127
  const conceptMapping = {
1138
1128
  amulet: { en: 'Amulet', pt: 'Amuleto', articlePT: 'O' },
@@ -1142,7 +1132,7 @@ export class ConceptService {
1142
1132
  ring: { en: 'Ring', pt: 'Anel', articlePT: 'O' },
1143
1133
  orb: { en: 'Orb', pt: 'Orbe', articlePT: 'O' },
1144
1134
  };
1145
-
1135
+
1146
1136
  const {
1147
1137
  en: conceptEN,
1148
1138
  pt: conceptPT,
@@ -1152,90 +1142,81 @@ export class ConceptService {
1152
1142
  pt: conceptSlug,
1153
1143
  articlePT: 'O', // Default to "O" if concept is missing
1154
1144
  };
1155
-
1145
+
1156
1146
  // ✅ Strict regex matching for English and Portuguese
1157
- const enMatch = aiResponse.match(
1158
- new RegExp(`EN:\\s*The ${conceptEN} of (.+)`)
1159
- );
1160
- const ptMatch = aiResponse.match(
1161
- new RegExp(`PT:\\s*${articlePT} ${conceptPT} de (.+)`)
1162
- );
1163
-
1147
+ const enMatch = aiResponse.match(new RegExp(`EN:\\s*The ${conceptEN} of (.+)`));
1148
+ const ptMatch = aiResponse.match(new RegExp(`PT:\\s*${articlePT} ${conceptPT} de (.+)`));
1149
+
1164
1150
  if (!enMatch || !ptMatch) {
1165
- console.error(
1166
- `❌ Invalid AI response format for ID ${id}, retrying...`
1167
- );
1151
+ console.error(`❌ Invalid AI response format for ID ${id}, retrying...`);
1168
1152
  continue;
1169
1153
  }
1170
-
1154
+
1171
1155
  newNameEN = `The ${conceptEN} of ${enMatch[1].trim()}`;
1172
1156
  newNamePT = `${articlePT} ${conceptPT} de ${ptMatch[1].trim()}`;
1173
-
1174
- console.log(
1175
- `🎨 Extracted Names: EN - "${newNameEN}", PT - "${newNamePT}"`
1176
- );
1177
-
1157
+
1158
+ console.log(`🎨 Extracted Names: EN - "${newNameEN}", PT - "${newNamePT}"`);
1159
+
1178
1160
  // ✅ Check if the new name is already in use in D1 before updating
1179
1161
  const existingEntry = await db
1180
1162
  .select({ id: conceptsData.id })
1181
1163
  .from(conceptsData)
1182
1164
  .where(eq(conceptsData.name, newNameEN))
1183
1165
  .execute();
1184
-
1166
+
1185
1167
  if (existingEntry.length > 0 || recentDuplicates.has(newNameEN)) {
1186
1168
  console.warn(`⚠️ Duplicate detected: "${newNameEN}", retrying...`);
1187
1169
  continue;
1188
1170
  }
1189
-
1171
+
1190
1172
  recentDuplicates.add(newNameEN);
1191
1173
  break; // ✅ Found a valid new name
1192
1174
  }
1193
-
1175
+
1194
1176
  if (!newNameEN || !newNamePT) {
1195
- console.error(
1196
- `🚨 Failed to generate a unique name for ID ${id} after ${maxAttempts} attempts.`
1197
- );
1177
+ console.error(`🚨 Failed to generate a unique name for ID ${id} after ${maxAttempts} attempts.`);
1178
+ failedEntries++;
1198
1179
  continue;
1199
1180
  }
1200
-
1201
- console.log(
1202
- `✅ Updating names: EN - "${newNameEN}", PT - "${newNamePT}"`
1203
- );
1204
-
1181
+
1182
+ console.log(`✅ Updating names: EN - "${newNameEN}", PT - "${newNamePT}"`);
1183
+
1205
1184
  // ✅ Update English name using the ID
1206
1185
  await db
1207
1186
  .update(conceptsData)
1208
1187
  .set({ name: newNameEN })
1209
- .where(
1210
- and(eq(conceptsData.id, id), eq(conceptsData.language, 'en-us'))
1211
- )
1188
+ .where(and(eq(conceptsData.id, id), eq(conceptsData.language, 'en-us')))
1212
1189
  .execute();
1213
-
1190
+
1214
1191
  // ✅ Convert English ID to Portuguese ID by replacing `:en-us:` with `:pt-br:`
1215
1192
  const ptId = id.replace(':en-us:', ':pt-br:');
1216
-
1193
+
1217
1194
  // ✅ Update Portuguese name using the derived PT ID
1218
1195
  await db
1219
1196
  .update(conceptsData)
1220
1197
  .set({ name: newNamePT })
1221
- .where(
1222
- and(eq(conceptsData.id, ptId), eq(conceptsData.language, 'pt-br'))
1223
- )
1198
+ .where(and(eq(conceptsData.id, ptId), eq(conceptsData.language, 'pt-br')))
1224
1199
  .execute();
1225
-
1226
- console.log(
1227
- `📝 Updated IDs: EN (${id}) -> "${newNameEN}", PT (${ptId}) -> "${newNamePT}"`
1228
- );
1229
-
1200
+
1201
+ console.log(`📝 Updated IDs: EN (${id}) -> "${newNameEN}", PT (${ptId}) -> "${newNamePT}"`);
1202
+
1230
1203
  updatedEntries++;
1231
1204
  }
1232
1205
  }
1233
-
1234
- console.log(
1235
- `🎉 [COMPLETE] Regenerated ${updatedEntries} duplicate names for concept: ${conceptSlug}.`
1236
- );
1206
+
1207
+ const elapsedTime = ((Date.now() - startTime) / 1000).toFixed(2);
1208
+
1209
+ console.log(`🎉 [COMPLETE] Regeneration finished in ${elapsedTime}s.`);
1210
+ console.log(`✅ Successfully updated: ${updatedEntries}`);
1211
+ console.log(`⚠️ Skipped (already unique): ${skippedEntries}`);
1212
+ console.log(`🚨 Failed attempts: ${failedEntries}`);
1213
+
1237
1214
  return {
1238
1215
  message: `Duplicate names processed and regenerated for ${conceptSlug}.`,
1216
+ updated: updatedEntries,
1217
+ skipped: skippedEntries,
1218
+ failed: failedEntries,
1219
+ elapsedTime,
1239
1220
  };
1240
1221
  }
1241
1222
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zodic/shared",
3
- "version": "0.0.223",
3
+ "version": "0.0.224",
4
4
  "module": "index.ts",
5
5
  "type": "module",
6
6
  "publishConfig": {