Extracts CreativeX score and URL from DAM master metadata during the
B1→B2 download, persists to creativex_scores with new status
'b1-master-cx-score' (dedup by tracking_id), and surfaces the score in
the b1_to_b2_complete and b1_to_b2_partial emails — falling back to
"No CreativeX Score" when the master has no score yet. Skipped
already-downloaded assets backfill from full_metadata JSONB on next pass.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
A1→A2 now looks up the opentext_id in master_assets for an M-prefixed record
from B1→B2 and stores it as global_master_tracking_id on the local asset record.
This provides traceability from local campaign assets back to their global master
without changing any existing workflow logic or DAM metadata.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Stores master asset CreativeX scores from DAM metadata during A1→A2
download for reference/reporting purposes (not used in uploads).
Database Changes:
creativex_scores table:
- Added: tracking_id VARCHAR(6) column
- Added: idx_creativex_tracking_id index
- Updated comment: status can be 'active', 'superseded', or 'master-cx-score'
Status Values:
- 'active' - Current derivative score (from PDF extraction)
- 'superseded' - Old derivative score (version history)
- 'master-cx-score' - Master asset score (from A1→A2 DAM metadata) ← NEW
Migration SQL (for existing databases):
ALTER TABLE creativex_scores ADD COLUMN tracking_id VARCHAR(6);
CREATE INDEX idx_creativex_tracking_id ON creativex_scores(tracking_id);
Database Method Updates (database.py):
store_creativex_score() signature:
- Added: tracking_id parameter (optional, default None)
- Added: status parameter (optional, default 'active')
Logic:
- If status='master-cx-score': Simple insert, no versioning
- If status='active': Soft delete versioning as before
- Always stores tracking_id if provided
A1→A2 Script Updates (a1_to_a2_download.py):
New Function: extract_creativex_from_dam_metadata()
- Searches metadata_element_list for CREATIVEX fields
- Extracts FERRERO.TAB.FIELD.CREATIVEX (score)
- Extracts FERRERO.FIELD.CREATIVEX LINK (url)
- Returns dict with score/url or None if not found
- Handles tabular field structure for score
- Handles nested value structure for URL
Integration:
- After successful master asset storage
- Extracts CreativeX from asset metadata
- If found: Stores in creativex_scores with status='master-cx-score'
- Links to master via tracking_id
- Logs when score found/stored
- Logs "normal" when not found (not all masters are scored)
Use Cases:
A2→A3 Upload:
- Still uses filename-based lookup ONLY ✅
- No changes to A2→A3 logic ✅
- Master scores not used for uploads ✅
Reporting/Analytics Tools:
- Can query master score by tracking_id
- Compare master vs derivative scores
- Track score improvements
- Audit trail
Query Examples:
-- Get master score for tracking ID
SELECT * FROM creativex_scores
WHERE tracking_id = '7xXgKp' AND status = 'master-cx-score';
-- Get derivative score for filename
SELECT * FROM creativex_scores
WHERE filename = 'file.mp4' AND status = 'active';
Test Record Created:
- Filename: nutella_pbased.jpg
- Tracking ID: 7xXgKp
- Score: 85
- Status: master-cx-score
Benefits:
- Historical reference of master scores
- Enables score comparison analytics
- No impact on A2→A3 upload logic
- Automatic extraction during A1→A2
- Optional (works even if masters don't have scores)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Implements new workflow to extract CreativeX quality scores from PDFs
using LlamaExtract AI and store results in PostgreSQL database.
Components added:
- creativex_scoring_storing.py: Main script to process PDFs from Box
- creativex_scores table: Database table with JSONB for full JSON storage
- Database methods: store_creativex_score() and get_creativex_score_by_filename()
- Email templates: creativex_complete, creativex_partial, creativex_no_files
- Configuration: creativex section in config.yaml
- CREATIVEX_DEPLOYMENT.md: Complete deployment and usage guide
Features:
- Monitors Box folder 350605024645 for PDFs
- Extracts scores using LlamaExtract agent "Creativex-Extract"
- Stores 4 key fields (filename, ID, URL, score) + full JSON
- Deletes processed PDFs from Box after successful extraction
- Sends email notifications for success/partial/no-files scenarios
- Manual execution (python scripts/creativex_scoring_storing.py)
Database schema:
- Table: creativex_scores with 10 columns
- Indexes on filename, box_file_id, status for fast lookups
- JSONB column stores complete extraction for future flexibility
Future integration ready:
db.get_creativex_score_by_filename() available for DAM upload workflows
to attach CreativeX metadata during asset processing.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Fixed database.py line 479: Changed 'CURRENT_TIMESTAMP' string to actual datetime
- Added datetime import for proper UTC timestamp generation
- This fixes the PostgreSQL error: invalid input syntax for type timestamp
- Added migration file for campaign_status table
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>