Updated handling of Explanation when cards are renamed
Browse filesAfter a set of cards is generated, the previous logic included a check for card names that have already been used by pre-existing MTG cards. If this situation was detected, the card's name is re-generated (keeping all other card information unchanged). The card name is re-generated until a name is generated that has not been used already.
Unfortunately, the previous logic did not also update the Explanation with the newly regenerated card name(s). This commit implements code that also updates the Explanation with the newly regenerated card name(s).
app.py
CHANGED
|
@@ -377,62 +377,115 @@ def CreateCard(msg: str, card_model: str, extract_model: str, temp: float):
|
|
| 377 |
parsed_list: MTGCardList = completion.choices[0].message.parsed
|
| 378 |
cards = parsed_list.cards
|
| 379 |
set_name = parsed_list.Name
|
| 380 |
-
#
|
| 381 |
-
|
| 382 |
|
| 383 |
# Track names in the current batch to ensure uniqueness within the batch
|
| 384 |
batch_names = set()
|
|
|
|
|
|
|
| 385 |
|
| 386 |
# Check if any generated card names are duplicates and regenerate them
|
| 387 |
for i, card in enumerate(cards):
|
|
|
|
| 388 |
# Check if name is duplicate in existing card database
|
| 389 |
if card.Name in card_names:
|
| 390 |
-
|
| 391 |
-
|
| 392 |
-
|
| 393 |
-
|
| 394 |
-
|
| 395 |
-
|
| 396 |
-
|
| 397 |
-
|
| 398 |
-
|
| 399 |
-
|
| 400 |
-
|
| 401 |
-
|
| 402 |
-
|
| 403 |
-
|
| 404 |
-
|
| 405 |
-
|
| 406 |
-
|
| 407 |
-
|
| 408 |
-
|
| 409 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 410 |
|
| 411 |
# Check if name is duplicate within the current batch
|
| 412 |
if card.Name in batch_names:
|
| 413 |
-
|
| 414 |
-
|
| 415 |
-
|
| 416 |
-
|
| 417 |
-
|
| 418 |
-
|
| 419 |
-
|
| 420 |
-
|
| 421 |
-
|
| 422 |
-
|
| 423 |
-
|
| 424 |
-
|
| 425 |
-
|
| 426 |
-
|
| 427 |
-
|
| 428 |
-
|
| 429 |
-
|
| 430 |
-
|
| 431 |
-
|
| 432 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 433 |
|
| 434 |
# Add the (now unique) name to batch tracking
|
| 435 |
batch_names.add(card.Name)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 436 |
|
| 437 |
# Success - format all cards (without explanation)
|
| 438 |
formatted_cards = []
|
|
|
|
| 377 |
parsed_list: MTGCardList = completion.choices[0].message.parsed
|
| 378 |
cards = parsed_list.cards
|
| 379 |
set_name = parsed_list.Name
|
| 380 |
+
# Get original explanation before any renaming
|
| 381 |
+
original_explanation = parsed_list.explanation
|
| 382 |
|
| 383 |
# Track names in the current batch to ensure uniqueness within the batch
|
| 384 |
batch_names = set()
|
| 385 |
+
# Track name mappings for updating explanation (old_name -> new_name)
|
| 386 |
+
name_mappings = {}
|
| 387 |
|
| 388 |
# Check if any generated card names are duplicates and regenerate them
|
| 389 |
for i, card in enumerate(cards):
|
| 390 |
+
original_name = card.Name
|
| 391 |
# Check if name is duplicate in existing card database
|
| 392 |
if card.Name in card_names:
|
| 393 |
+
# Keep trying to generate a unique name until one is found
|
| 394 |
+
max_name_attempts = 10 # Try up to 10 times to generate a unique name
|
| 395 |
+
name_found = False
|
| 396 |
+
for name_attempt in range(max_name_attempts):
|
| 397 |
+
try:
|
| 398 |
+
# Combine existing names and current batch names to avoid duplicates
|
| 399 |
+
all_used_names = card_names | batch_names
|
| 400 |
+
new_name = generate_unique_name_for_card(
|
| 401 |
+
parsed_card=card,
|
| 402 |
+
used_names=all_used_names,
|
| 403 |
+
extract_model=extract_model,
|
| 404 |
+
)
|
| 405 |
+
# Verify the regenerated name is actually unique
|
| 406 |
+
if new_name in card_names:
|
| 407 |
+
print(f"⚠ Regenerated name '{new_name}' (attempt {name_attempt + 1}) is still a duplicate in card_names, retrying...")
|
| 408 |
+
continue # Try again
|
| 409 |
+
if new_name in batch_names:
|
| 410 |
+
print(f"⚠ Regenerated name '{new_name}' (attempt {name_attempt + 1}) conflicts with another card in this batch, retrying...")
|
| 411 |
+
continue # Try again
|
| 412 |
+
# Unique name found!
|
| 413 |
+
card.Name = new_name
|
| 414 |
+
# Track the name change
|
| 415 |
+
if original_name != new_name:
|
| 416 |
+
name_mappings[original_name] = new_name
|
| 417 |
+
name_found = True
|
| 418 |
+
break
|
| 419 |
+
except Exception as e:
|
| 420 |
+
print(f"⚠ Failed to generate replacement name (attempt {name_attempt + 1}): {e}")
|
| 421 |
+
if name_attempt == max_name_attempts - 1:
|
| 422 |
+
# Last attempt failed, give up and retry entire card generation
|
| 423 |
+
raise ValueError("Failed to generate unique name after multiple attempts")
|
| 424 |
+
continue # Try again
|
| 425 |
+
|
| 426 |
+
if not name_found:
|
| 427 |
+
raise ValueError("Failed to generate unique name after multiple attempts")
|
| 428 |
|
| 429 |
# Check if name is duplicate within the current batch
|
| 430 |
if card.Name in batch_names:
|
| 431 |
+
# Keep trying to generate a unique name until one is found
|
| 432 |
+
max_name_attempts = 10 # Try up to 10 times to generate a unique name
|
| 433 |
+
name_found = False
|
| 434 |
+
for name_attempt in range(max_name_attempts):
|
| 435 |
+
try:
|
| 436 |
+
# Combine existing names and current batch names to avoid duplicates
|
| 437 |
+
all_used_names = card_names | batch_names
|
| 438 |
+
new_name = generate_unique_name_for_card(
|
| 439 |
+
parsed_card=card,
|
| 440 |
+
used_names=all_used_names,
|
| 441 |
+
extract_model=extract_model,
|
| 442 |
+
)
|
| 443 |
+
# Verify the regenerated name is actually unique
|
| 444 |
+
if new_name in card_names:
|
| 445 |
+
print(f"⚠ Regenerated name '{new_name}' (attempt {name_attempt + 1}) is still a duplicate in card_names, retrying...")
|
| 446 |
+
continue # Try again
|
| 447 |
+
if new_name in batch_names:
|
| 448 |
+
print(f"⚠ Regenerated name '{new_name}' (attempt {name_attempt + 1}) conflicts with another card in this batch, retrying...")
|
| 449 |
+
continue # Try again
|
| 450 |
+
# Unique name found!
|
| 451 |
+
card.Name = new_name
|
| 452 |
+
# Track the name change
|
| 453 |
+
if original_name != new_name:
|
| 454 |
+
name_mappings[original_name] = new_name
|
| 455 |
+
name_found = True
|
| 456 |
+
break
|
| 457 |
+
except Exception as e:
|
| 458 |
+
print(f"⚠ Failed to generate replacement name for batch duplicate (attempt {name_attempt + 1}): {e}")
|
| 459 |
+
if name_attempt == max_name_attempts - 1:
|
| 460 |
+
# Last attempt failed, give up and retry entire card generation
|
| 461 |
+
raise ValueError("Failed to generate unique name after multiple attempts")
|
| 462 |
+
continue # Try again
|
| 463 |
+
|
| 464 |
+
if not name_found:
|
| 465 |
+
raise ValueError("Failed to generate unique name after multiple attempts")
|
| 466 |
|
| 467 |
# Add the (now unique) name to batch tracking
|
| 468 |
batch_names.add(card.Name)
|
| 469 |
+
|
| 470 |
+
# Update explanation with new card names if any cards were renamed
|
| 471 |
+
if name_mappings:
|
| 472 |
+
explanation = original_explanation
|
| 473 |
+
# Replace old names with new names in the explanation
|
| 474 |
+
# Sort by length (longest first) to handle cases where one name contains another
|
| 475 |
+
sorted_mappings = sorted(name_mappings.items(), key=lambda x: len(x[0]), reverse=True)
|
| 476 |
+
for old_name, new_name in sorted_mappings:
|
| 477 |
+
# Use word boundaries to replace whole words only
|
| 478 |
+
escaped_old_name = re.escape(old_name)
|
| 479 |
+
pattern = r'\b' + escaped_old_name + r'\b'
|
| 480 |
+
explanation = re.sub(pattern, new_name, explanation)
|
| 481 |
+
# Update parsed_list.explanation so clean_explanation_quotes uses the updated version
|
| 482 |
+
parsed_list.explanation = explanation
|
| 483 |
+
else:
|
| 484 |
+
explanation = original_explanation
|
| 485 |
+
|
| 486 |
+
# Clean the explanation to remove quotes around card names (after updating names)
|
| 487 |
+
# Note: parsed_list.cards already have the updated names since they're the same objects
|
| 488 |
+
explanation = clean_explanation_quotes(parsed_list, card_model)
|
| 489 |
|
| 490 |
# Success - format all cards (without explanation)
|
| 491 |
formatted_cards = []
|