feat: automated Qdrant sync with Mistral embeddings + Kabelhandbuch ingestion
Some checks failed
Build & Deploy / 🔍 Prepare (push) Successful in 6s
Build & Deploy / 🧪 QA (push) Failing after 55s
Build & Deploy / 🏗️ Build (push) Has been skipped
Build & Deploy / 🚀 Deploy (push) Has been skipped
Build & Deploy / 🧪 Post-Deploy Verification (push) Has been skipped
Build & Deploy / 🔔 Notify (push) Successful in 2s
Some checks failed
Build & Deploy / 🔍 Prepare (push) Successful in 6s
Build & Deploy / 🧪 QA (push) Failing after 55s
Build & Deploy / 🏗️ Build (push) Has been skipped
Build & Deploy / 🚀 Deploy (push) Has been skipped
Build & Deploy / 🧪 Post-Deploy Verification (push) Has been skipped
Build & Deploy / 🔔 Notify (push) Successful in 2s
- Switch embedding API from OpenRouter to Mistral mistral-embed (1024-dim, EU/DSGVO) - Add afterChange/afterDelete hooks to Posts.ts and Pages.ts for live sync - Integrate kabelhandbuch.txt parsing into /api/sync-qdrant boot route - Add .gitignore entries for kabelhandbuch.txt
This commit is contained in:
@@ -26,6 +26,66 @@ export const Pages: CollectionConfig = {
|
||||
};
|
||||
},
|
||||
},
|
||||
hooks: {
|
||||
afterChange: [
|
||||
async ({ doc, req }) => {
|
||||
// Run index sync asynchronously to not block the CMS save operation
|
||||
setTimeout(async () => {
|
||||
try {
|
||||
const { upsertProductVector, deleteProductVector } = await import('../../lib/qdrant');
|
||||
|
||||
// Check if page is published
|
||||
if (doc._status !== 'published') {
|
||||
await deleteProductVector(`page_${doc.id}`);
|
||||
req.payload.logger.info(`Removed drafted page ${doc.slug} from Qdrant`);
|
||||
} else {
|
||||
// Serialize payload
|
||||
const contentText = [
|
||||
`Seite: ${doc.title}`,
|
||||
doc.excerpt ? `Beschreibung: ${doc.excerpt}` : '',
|
||||
]
|
||||
.filter(Boolean)
|
||||
.join('\n');
|
||||
|
||||
const payload = {
|
||||
type: 'knowledge',
|
||||
content: contentText,
|
||||
data: {
|
||||
title: doc.title,
|
||||
slug: doc.slug,
|
||||
},
|
||||
};
|
||||
|
||||
await upsertProductVector(`page_${doc.id}`, contentText, payload);
|
||||
req.payload.logger.info(`Upserted page ${doc.slug} to Qdrant`);
|
||||
}
|
||||
} catch (error) {
|
||||
req.payload.logger.error({
|
||||
msg: 'Error syncing page to Qdrant',
|
||||
err: error,
|
||||
pageId: doc.id,
|
||||
});
|
||||
}
|
||||
}, 0);
|
||||
return doc;
|
||||
},
|
||||
],
|
||||
afterDelete: [
|
||||
async ({ id, req }) => {
|
||||
try {
|
||||
const { deleteProductVector } = await import('../../lib/qdrant');
|
||||
await deleteProductVector(`page_${id}`);
|
||||
req.payload.logger.info(`Deleted page ${id} from Qdrant`);
|
||||
} catch (error) {
|
||||
req.payload.logger.error({
|
||||
msg: 'Error deleting page from Qdrant',
|
||||
err: error,
|
||||
pageId: id,
|
||||
});
|
||||
}
|
||||
},
|
||||
],
|
||||
},
|
||||
fields: [
|
||||
{
|
||||
name: 'title',
|
||||
|
||||
@@ -45,6 +45,67 @@ export const Posts: CollectionConfig = {
|
||||
};
|
||||
},
|
||||
},
|
||||
hooks: {
|
||||
afterChange: [
|
||||
async ({ doc, req }) => {
|
||||
// Run index sync asynchronously to not block the CMS save operation
|
||||
setTimeout(async () => {
|
||||
try {
|
||||
const { upsertProductVector, deleteProductVector } = await import('../../lib/qdrant');
|
||||
|
||||
// Check if post is published
|
||||
if (doc._status !== 'published') {
|
||||
await deleteProductVector(`post_${doc.id}`);
|
||||
req.payload.logger.info(`Removed drafted post ${doc.slug} from Qdrant`);
|
||||
} else {
|
||||
// Serialize payload
|
||||
const contentText = [
|
||||
`Blog-Artikel: ${doc.title}`,
|
||||
doc.excerpt ? `Zusammenfassung: ${doc.excerpt}` : '',
|
||||
doc.category ? `Kategorie: ${doc.category}` : '',
|
||||
]
|
||||
.filter(Boolean)
|
||||
.join('\n');
|
||||
|
||||
const payload = {
|
||||
type: 'knowledge',
|
||||
content: contentText,
|
||||
data: {
|
||||
title: doc.title,
|
||||
slug: doc.slug,
|
||||
},
|
||||
};
|
||||
|
||||
await upsertProductVector(`post_${doc.id}`, contentText, payload);
|
||||
req.payload.logger.info(`Upserted post ${doc.slug} to Qdrant`);
|
||||
}
|
||||
} catch (error) {
|
||||
req.payload.logger.error({
|
||||
msg: 'Error syncing post to Qdrant',
|
||||
err: error,
|
||||
postId: doc.id,
|
||||
});
|
||||
}
|
||||
}, 0);
|
||||
return doc;
|
||||
},
|
||||
],
|
||||
afterDelete: [
|
||||
async ({ id, req }) => {
|
||||
try {
|
||||
const { deleteProductVector } = await import('../../lib/qdrant');
|
||||
await deleteProductVector(`post_${id}`);
|
||||
req.payload.logger.info(`Deleted post ${id} from Qdrant`);
|
||||
} catch (error) {
|
||||
req.payload.logger.error({
|
||||
msg: 'Error deleting post from Qdrant',
|
||||
err: error,
|
||||
postId: id,
|
||||
});
|
||||
}
|
||||
},
|
||||
],
|
||||
},
|
||||
fields: [
|
||||
{
|
||||
name: 'title',
|
||||
|
||||
Reference in New Issue
Block a user