@zodic/shared 0.0.218 → 0.0.219

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.
@@ -2,7 +2,7 @@ import {
2
2
  KVNamespaceListKey,
3
3
  KVNamespaceListResult,
4
4
  } from '@cloudflare/workers-types';
5
- import { and, eq } from 'drizzle-orm';
5
+ import { and, eq, sql } from 'drizzle-orm';
6
6
  import { inject, injectable } from 'inversify';
7
7
  import 'reflect-metadata';
8
8
  import { v4 as uuidv4 } from 'uuid';
@@ -16,6 +16,8 @@ import {
16
16
  import { leonardoInitImages } from '../../utils/initImages';
17
17
  import { buildConceptKVKey } from '../../utils/KVKeysBuilders';
18
18
  import { AppContext } from '../base/AppContext';
19
+ import { drizzle } from 'drizzle-orm/d1';
20
+ import { conceptsData } from '../../db/schema';
19
21
 
20
22
  @injectable()
21
23
  export class ConceptService {
@@ -1028,41 +1030,48 @@ export class ConceptService {
1028
1030
  };
1029
1031
  }
1030
1032
 
1031
- async regenerateDuplicateNamesForConcept(conceptSlug: Concept) {
1032
- console.log(`🔄 [START] Regenerating duplicate names for concept: ${conceptSlug}`);
1033
+ async regenerateDuplicateNamesForConcept(conceptSlug: Concept, maxEntries?: number) {
1034
+ console.log(`🔄 [START] Regenerating duplicate names for concept: ${conceptSlug}...`);
1033
1035
 
1034
- const kvCacheStore = this.context.env.KV_CONCEPT_CACHE;
1035
- const kvStore = this.context.env.KV_CONCEPTS;
1036
+ const db = drizzle(this.context.env.DB);
1036
1037
 
1037
- // ✅ Get duplicate keys and used names
1038
- const { duplicateKeys, usedNamesEN, usedNamesPT } =
1039
- await this.findDuplicateNamesForConcept(conceptSlug);
1038
+ // ✅ Step 1: Fetch duplicate entries filtered by conceptSlug
1039
+ const duplicateEntries = await db
1040
+ .select({
1041
+ id: conceptsData.id,
1042
+ name: conceptsData.name,
1043
+ description: conceptsData.description,
1044
+ combination: conceptsData.combination,
1045
+ })
1046
+ .from(conceptsData)
1047
+ .where(
1048
+ and(
1049
+ eq(conceptsData.language, 'en-us'), // English version only
1050
+ eq(conceptsData.conceptSlug, conceptSlug), // ✅ Filter by concept
1051
+ sql`name IN (
1052
+ SELECT name FROM concepts_data
1053
+ WHERE language = 'en-us' AND concept_slug = ${conceptSlug}
1054
+ GROUP BY name HAVING COUNT(*) > 1
1055
+ )`
1056
+ )
1057
+ )
1058
+ .limit(maxEntries || 50) // ✅ Apply optional limit
1059
+ .execute();
1040
1060
 
1041
- if (duplicateKeys.length === 0) {
1061
+ if (!duplicateEntries.length) {
1042
1062
  console.log(`🎉 No duplicates found for ${conceptSlug}.`);
1043
1063
  return { message: `No duplicates detected for ${conceptSlug}.` };
1044
1064
  }
1045
1065
 
1046
- let updatedKeys: string[] = [];
1047
- let recentDuplicates = new Set<string>(); // ✅ Track newly generated names dynamically
1066
+ console.log(`🔍 Found ${duplicateEntries.length} duplicate entries to process.`);
1048
1067
 
1049
- console.log(`🔍 Found ${duplicateKeys.length} duplicate keys to process.`);
1068
+ let recentDuplicates = new Set<string>(); // Track newly generated names
1069
+ let updatedEntries = 0;
1050
1070
 
1051
- for (const kvKeyEN of duplicateKeys) {
1052
- const kvKeyPT = kvKeyEN.replace(':en-us:', ':pt-br:');
1071
+ for (const entry of duplicateEntries) {
1072
+ const { id, name, description, combination } = entry;
1053
1073
 
1054
- const kvDataEN = (await kvStore.get(kvKeyEN, 'json')) as {
1055
- name: string;
1056
- description: string;
1057
- };
1058
- const kvDataPT = (await kvStore.get(kvKeyPT, 'json')) as { name: string };
1059
-
1060
- if (!kvDataEN || !kvDataEN.name) {
1061
- console.warn(`⚠️ Missing data for key: ${kvKeyEN}, skipping.`);
1062
- continue;
1063
- }
1064
-
1065
- console.log(`🎭 Processing duplicate: ${kvKeyEN} (Old Name: "${kvDataEN.name}")`);
1074
+ console.log(`🎭 Processing duplicate ID ${id}: "${name}"`);
1066
1075
 
1067
1076
  let newNameEN: string | null = null;
1068
1077
  let newNamePT: string | null = null;
@@ -1077,21 +1086,21 @@ export class ConceptService {
1077
1086
  // ✅ Generate a new name, passing dynamically tracked duplicates
1078
1087
  const messages = this.context.buildLLMMessages().regenerateConceptName({
1079
1088
  conceptSlug,
1080
- oldNameEN: kvDataEN.name,
1081
- description: kvDataEN.description,
1082
- recentNames: Array.from(recentDuplicates), // ✅ Prevent reusing recent names
1089
+ oldNameEN: name,
1090
+ description,
1091
+ recentNames: Array.from(recentDuplicates),
1083
1092
  });
1084
1093
 
1085
1094
  const aiResponse = await this.context.api().callTogether.single(messages, {});
1086
1095
 
1087
1096
  if (!aiResponse) {
1088
- console.warn(`⚠️ AI failed to generate a new name for ${kvKeyEN}, skipping.`);
1097
+ console.warn(`⚠️ AI failed to generate a new name for ID ${id}, skipping.`);
1089
1098
  break;
1090
1099
  }
1091
1100
 
1092
1101
  console.log(`📝 Raw AI Response:\n${aiResponse}`);
1093
1102
 
1094
- // ✅ Correctly map concept names and gendered articles
1103
+ // ✅ Mapping for concept names with proper PT articles
1095
1104
  const conceptMapping = {
1096
1105
  amulet: { en: "Amulet", pt: "Amuleto", articlePT: "O" },
1097
1106
  crown: { en: "Crown", pt: "Coroa", articlePT: "A" },
@@ -1108,83 +1117,59 @@ export class ConceptService {
1108
1117
  };
1109
1118
 
1110
1119
  // ✅ Strict regex matching for English and Portuguese
1111
- const enMatch = aiResponse.match(new RegExp(`EN:\\s*The ${conceptEN} of [A-Za-z\\s]+`));
1112
- const ptMatch = aiResponse.match(new RegExp(`PT:\\s*${articlePT} ${conceptPT} de [A-Za-z\\s]+`));
1120
+ const enMatch = aiResponse.match(new RegExp(`EN:\\s*The ${conceptEN} of (.+)`));
1121
+ const ptMatch = aiResponse.match(new RegExp(`PT:\\s*${articlePT} ${conceptPT} de (.+)`));
1113
1122
 
1114
1123
  if (!enMatch || !ptMatch) {
1115
- console.error(`❌ Invalid AI response format! Retrying...`);
1124
+ console.error(`❌ Invalid AI response format for ID ${id}, retrying...`);
1116
1125
  continue;
1117
1126
  }
1118
1127
 
1119
- newNameEN = enMatch[0].replace(/^EN:\s*/, '').trim();
1120
- newNamePT = ptMatch[0].replace(/^PT:\s*/, '').trim();
1128
+ newNameEN = `The ${conceptEN} of ${enMatch[1].trim()}`;
1129
+ newNamePT = `${articlePT} ${conceptPT} de ${ptMatch[1].trim()}`;
1121
1130
 
1122
1131
  console.log(`🎨 Extracted Names: EN - "${newNameEN}", PT - "${newNamePT}"`);
1123
1132
 
1124
- // ✅ Check if the name already exists
1125
- if (
1126
- usedNamesEN.has(newNameEN) ||
1127
- usedNamesPT.has(newNamePT) ||
1128
- recentDuplicates.has(newNameEN)
1129
- ) {
1130
- console.warn(
1131
- `⚠️ Duplicate detected: EN - "${newNameEN}", PT - "${newNamePT}". Retrying...`
1132
- );
1133
- recentDuplicates.add(newNameEN);
1134
- recentDuplicates.add(newNamePT);
1133
+ // ✅ Check for duplicate avoidance
1134
+ if (recentDuplicates.has(newNameEN)) {
1135
+ console.warn(`⚠️ Duplicate detected: "${newNameEN}", retrying...`);
1135
1136
  continue;
1136
1137
  }
1137
1138
 
1138
1139
  recentDuplicates.add(newNameEN);
1139
- recentDuplicates.add(newNamePT);
1140
- break; // ✅ Found unique names, exit retry loop
1140
+ break; // ✅ Found a valid new name
1141
1141
  }
1142
1142
 
1143
1143
  if (!newNameEN || !newNamePT) {
1144
- console.error(`🚨 Failed to generate a unique name for ${kvKeyEN} after ${maxAttempts} attempts.`);
1144
+ console.error(`🚨 Failed to generate a unique name for ID ${id} after ${maxAttempts} attempts.`);
1145
1145
  continue;
1146
1146
  }
1147
1147
 
1148
- console.log(`✅ Storing new names: EN - "${newNameEN}", PT - "${newNamePT}"`);
1149
-
1150
- // ✅ Update KV with new names (EN)
1151
- Object.assign(kvDataEN, { name: newNameEN });
1152
- await kvStore.put(kvKeyEN, JSON.stringify(kvDataEN));
1148
+ console.log(`✅ Updating names: EN - "${newNameEN}", PT - "${newNamePT}"`);
1153
1149
 
1154
- // ✅ Update KV with new names (PT)
1155
- Object.assign(kvDataPT, { name: newNamePT });
1156
- await kvStore.put(kvKeyPT, JSON.stringify(kvDataPT));
1150
+ // ✅ Update English name using the ID
1151
+ await db
1152
+ .update(conceptsData)
1153
+ .set({ name: newNameEN })
1154
+ .where(and(eq(conceptsData.id, id), eq(conceptsData.language, 'en-us')))
1155
+ .execute();
1157
1156
 
1158
- // ✅ Add new names to used names sets
1159
- usedNamesEN.add(newNameEN);
1160
- usedNamesPT.add(newNamePT);
1157
+ // ✅ Convert English ID to Portuguese ID by replacing `:en-us:` with `:pt-br:`
1158
+ const ptId = id.replace(':en-us:', ':pt-br:');
1161
1159
 
1162
- // ✅ Collect successfully processed keys for cache update
1163
- updatedKeys.push(kvKeyEN);
1164
- }
1165
-
1166
- // Remove successfully updated keys from duplicate cache
1167
- if (updatedKeys.length > 0) {
1168
- let duplicateKeysList: string[] =
1169
- (await kvCacheStore.get(`cache:duplicates:${conceptSlug}`, 'json')) || [];
1170
-
1171
- console.log(`🗑️ Removing ${updatedKeys.length} resolved duplicates from cache.`);
1160
+ // ✅ Update Portuguese name using the derived PT ID
1161
+ await db
1162
+ .update(conceptsData)
1163
+ .set({ name: newNamePT })
1164
+ .where(and(eq(conceptsData.id, ptId), eq(conceptsData.language, 'pt-br')))
1165
+ .execute();
1172
1166
 
1173
- // Remove processed keys
1174
- duplicateKeysList = duplicateKeysList.filter((key) => !updatedKeys.includes(key));
1167
+ console.log(`📝 Updated IDs: EN (${id}) -> "${newNameEN}", PT (${ptId}) -> "${newNamePT}"`);
1175
1168
 
1176
- if (duplicateKeysList.length === 0) {
1177
- console.log(`✅ All duplicates resolved for ${conceptSlug}, deleting cache entry.`);
1178
- await kvCacheStore.delete(`cache:duplicates:${conceptSlug}`);
1179
- } else {
1180
- await kvCacheStore.put(
1181
- `cache:duplicates:${conceptSlug}`,
1182
- JSON.stringify(duplicateKeysList)
1183
- );
1184
- }
1169
+ updatedEntries++;
1185
1170
  }
1186
1171
 
1187
- console.log(`🎉 [COMPLETE] Duplicate names regenerated successfully for concept: ${conceptSlug}.`);
1172
+ console.log(`🎉 [COMPLETE] Regenerated ${updatedEntries} duplicate names for concept: ${conceptSlug}.`);
1188
1173
  return {
1189
1174
  message: `Duplicate names processed and regenerated for ${conceptSlug}.`,
1190
1175
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zodic/shared",
3
- "version": "0.0.218",
3
+ "version": "0.0.219",
4
4
  "module": "index.ts",
5
5
  "type": "module",
6
6
  "publishConfig": {