update
All checks were successful
Deploy to Production / deploy (push) Successful in 20s

This commit is contained in:
vuongps38770
2026-02-28 20:00:38 +07:00
parent f96833a7e4
commit 72283443ab
15 changed files with 972 additions and 318 deletions

View File

@@ -1,59 +1,26 @@
/**
* Import Context (status=5) → Sentences
*
* Logic:
* 1. Lấy tất cả Context có status = 5
* 2. So sánh Context.title với Sentences.text
* - Nếu chưa có → tạo mới Sentence
* - Nếu đã có → cập nhật image vào đúng mảng
* 3. Xác định slot image dựa vào Context.image.split("_")[1]:
* - "square" → image_square
* - "small" → image_small
* - "normal" → image_normal
* 4. Chuyển Context.status → 6
*/
const { sequelize } = require('./config/database');
const Context = require('./models/Context');
const Sentences = require('./models/Sentences');
// ─── helper: thêm URL vào mảng JSON (không trùng lặp) ───────────────────────
function addToArray(existing, url) {
const arr = Array.isArray(existing) ? [...existing] : [];
if (!arr.includes(url)) arr.push(url);
return arr;
}
const { Context, Vocab, Sentences } = require('./models');
// ─── helper: xác định slot image từ tên file/URL ────────────────────────────
function resolveImageSlot(imageUrl) {
if (!imageUrl) return null;
// Lấy phần tên file (bỏ path/query)
const filename = imageUrl.split('/').pop().split('?')[0];
const parts = filename.split('_');
// Duyệt tất cả phần tử, tìm keyword
for (const part of parts) {
const key = part.toLowerCase();
if (key === 'square') return 'image_square';
if (key === 'small') return 'image_small';
if (key === 'small') return 'image_small';
if (key === 'normal') return 'image_normal';
}
return null; // không xác định được
return null;
}
// ─── main ────────────────────────────────────────────────────────────────────
async function run() {
try {
await sequelize.authenticate();
console.log('✅ Database connected\n');
// 1. Lấy tất cả Context có status = 5
const contexts = await Context.findAll({
where: { status: 5 }
});
const contexts = await Context.findAll({ where: { status: 5 } });
console.log(`📦 Tìm thấy ${contexts.length} Context(s) có status = 5\n`);
if (contexts.length === 0) {
@@ -61,76 +28,78 @@ async function run() {
process.exit(0);
}
let created = 0;
let updated = 0;
let updatedVocab = 0;
let updatedSentences = 0;
let skipped = 0;
for (const ctx of contexts) {
const text = ctx.context; // so sánh với Sentences.text
const imageUrl = ctx.image;
const imageSlot = resolveImageSlot(imageUrl);
const imageUrl = ctx.image;
const slot = resolveImageSlot(imageUrl);
if (!text) {
console.warn(` ⚠️ Context [${ctx.uuid}] không có context — bỏ qua`);
if (!imageUrl || !slot) {
console.warn(` ⚠️ [BỎ QUA] ID ${ctx.uuid}: Không xác định được ảnh/slot`);
skipped++;
continue;
}
// 2. Tìm Sentence có text khớp
let sentence = await Sentences.findOne({
where: { text }
});
if (!sentence) {
// ── Tạo mới ──────────────────────────────────────────────────────────
const newData = {
text,
is_active: true,
image_small: [],
image_square: [],
image_normal: [],
};
// Gán image vào đúng slot
if (imageUrl && imageSlot) {
newData[imageSlot] = [imageUrl];
} else if (imageUrl) {
console.warn(` ⚠️ Không xác định slot image từ URL: "${imageUrl}" — bỏ qua image`);
}
await Sentences.create(newData);
console.log(` ✅ [TẠO MỚI] "${text}"${imageSlot ? `${imageSlot}` : ''}`);
created++;
let targetEntity = null;
let entityType = '';
// Xử lý Vocab
if (ctx.type === 'vocabulary') {
// Ưu tiên tìm bản ghi đang active
targetEntity = await Vocab.findOne({
where: { text: ctx.title, is_active: true }
});
// Nếu không có bản ghi active, mới tìm bản ghi bất kỳ
if (!targetEntity) targetEntity = await Vocab.findOne({ where: { text: ctx.title } });
entityType = 'Vocab';
} else {
// ── Cập nhật image ───────────────────────────────────────────────────
if (imageUrl && imageSlot) {
const updatedArr = addToArray(sentence[imageSlot], imageUrl);
await sentence.update({ [imageSlot]: updatedArr });
console.log(` 🔄 [CẬP NHẬT] "${text}" → ${imageSlot} (+1 ảnh)`);
updated++;
} else {
console.warn(` ⚠️ [BỎ QUA IMAGE] "${text}" — URL trống hoặc không xác định slot`);
skipped++;
// Xử lý Sentence (ưu tiên active)
targetEntity = await Sentences.findOne({
where: { text: ctx.context, is_active: true }
});
if (!targetEntity) targetEntity = await Sentences.findOne({ where: { text: ctx.context } });
if (!targetEntity) {
targetEntity = await Sentences.findOne({
where: { text: ctx.title, is_active: true }
});
if (!targetEntity) targetEntity = await Sentences.findOne({ where: { text: ctx.title } });
}
entityType = 'Sentence';
}
// 3. Chuyển Context.status → 6
await ctx.update({ status: 6 });
if (targetEntity) {
// 1. Cập nhật ảnh (Ghi đè - để mảng chỉ có 1 ảnh)
await targetEntity.update({ [slot]: [imageUrl] });
// 2. Kiểm tra và sửa reference_id nếu lệch
const correctId = targetEntity.vocab_id || targetEntity.id;
const updates = { status: 6 };
if (ctx.reference_id !== correctId) {
updates.reference_id = correctId;
}
await ctx.update(updates);
if (entityType === 'Vocab') updatedVocab++; else updatedSentences++;
console.log(` ✅ [${entityType}] "${ctx.title}" -> ${slot} (Đã ghi đè)`);
} else {
console.warn(` ❌ [KHÔNG THẤY] "${ctx.title}" (Type: ${ctx.type})`);
skipped++;
}
}
console.log('\n─────────────────────────────────────');
console.log(`📊 Kết quả:`);
console.log(`Tạo mới : ${created}`);
console.log(` 🔄 Cập nhật : ${updated}`);
console.log(` ⚠️ Bỏ qua : ${skipped}`);
console.log(` 📌 Tổng : ${contexts.length}`);
console.log(`Cập nhật Vocab : ${updatedVocab}`);
console.log(` Cập nhật Sentences: ${updatedSentences}`);
console.log(` ⚠️ Bỏ qua : ${skipped}`);
console.log('─────────────────────────────────────');
process.exit(0);
} catch (error) {
console.error('❌ Lỗi:', error.message);
console.error(error.stack);
process.exit(1);
}
}