@s-hirano-ist/s-scripts 1.26.8 → 4.0.1
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.
- package/README.md +2 -0
- package/dist/chunk-6ADTNHCK.js +85 -0
- package/dist/chunk-7PVU2Z32.js +71 -0
- package/dist/chunk-AJMTRCPJ.js +15 -0
- package/dist/chunk-AUD3PD6K.js +85 -0
- package/dist/chunk-F4J6JBR4.js +115 -0
- package/dist/chunk-HDYQV2Y2.js +58 -0
- package/dist/chunk-J4VLH4VA.js +267 -0
- package/dist/chunk-JZOR5GA2.js +42 -0
- package/dist/chunk-KKZP7ZF3.js +77 -0
- package/dist/chunk-M275YZQP.js +7723 -0
- package/dist/chunk-Q6QUV5VR.js +102 -0
- package/dist/chunk-TK456CR2.js +85 -0
- package/dist/chunk-UXGLXHQ6.js +40 -0
- package/dist/chunk-XG6LAGZO.js +590 -0
- package/dist/cleanup-minio-images.js +115 -92
- package/dist/enrich-books.js +87 -78
- package/dist/fetch-articles.js +101 -90
- package/dist/fetch-books.js +147 -128
- package/dist/fetch-images.js +88 -72
- package/dist/fetch-notes.js +66 -54
- package/dist/find-duplicate-json-articles.js +100 -97
- package/dist/fix-book-frontmatter.js +111 -99
- package/dist/fix-image-formats.js +81 -65
- package/dist/ingest-articles.js +30 -249
- package/dist/ingest-books.js +61 -318
- package/dist/ingest-images.js +33 -184
- package/dist/ingest-notes.js +41 -171
- package/dist/rag/delete-collection.js +32 -22
- package/dist/rag/ingest.js +371 -92
- package/dist/rag/search.js +80 -76
- package/dist/reset-articles.js +57 -60
- package/dist/reset-books.js +57 -59
- package/dist/reset-images.js +57 -59
- package/dist/reset-notes.js +57 -59
- package/dist/revert-articles.js +53 -55
- package/dist/revert-books.js +53 -53
- package/dist/revert-images.js +53 -53
- package/dist/revert-notes.js +53 -53
- package/dist/s-content-format.js +103 -13
- package/dist/update-json-articles.js +101 -97
- package/dist/update-raw-articles.js +130 -130
- package/dist/validate-json-articles.js +129 -130
- package/package.json +13 -50
- package/dist/cleanup-minio-images.d.ts +0 -3
- package/dist/cleanup-minio-images.d.ts.map +0 -1
- package/dist/cleanup-minio-images.js.map +0 -1
- package/dist/enrich-books.d.ts +0 -3
- package/dist/enrich-books.d.ts.map +0 -1
- package/dist/enrich-books.js.map +0 -1
- package/dist/fetch-articles.d.ts +0 -3
- package/dist/fetch-articles.d.ts.map +0 -1
- package/dist/fetch-articles.js.map +0 -1
- package/dist/fetch-books.d.ts +0 -3
- package/dist/fetch-books.d.ts.map +0 -1
- package/dist/fetch-books.js.map +0 -1
- package/dist/fetch-images.d.ts +0 -3
- package/dist/fetch-images.d.ts.map +0 -1
- package/dist/fetch-images.js.map +0 -1
- package/dist/fetch-notes.d.ts +0 -3
- package/dist/fetch-notes.d.ts.map +0 -1
- package/dist/fetch-notes.js.map +0 -1
- package/dist/find-duplicate-json-articles.d.ts +0 -3
- package/dist/find-duplicate-json-articles.d.ts.map +0 -1
- package/dist/find-duplicate-json-articles.js.map +0 -1
- package/dist/fix-book-frontmatter.d.ts +0 -3
- package/dist/fix-book-frontmatter.d.ts.map +0 -1
- package/dist/fix-book-frontmatter.js.map +0 -1
- package/dist/fix-image-formats.d.ts +0 -3
- package/dist/fix-image-formats.d.ts.map +0 -1
- package/dist/fix-image-formats.js.map +0 -1
- package/dist/infrastructures/articles-command-repository.d.ts +0 -57
- package/dist/infrastructures/articles-command-repository.d.ts.map +0 -1
- package/dist/infrastructures/articles-command-repository.js +0 -68
- package/dist/infrastructures/articles-command-repository.js.map +0 -1
- package/dist/infrastructures/books-command-repository.d.ts +0 -34
- package/dist/infrastructures/books-command-repository.d.ts.map +0 -1
- package/dist/infrastructures/books-command-repository.js +0 -53
- package/dist/infrastructures/books-command-repository.js.map +0 -1
- package/dist/infrastructures/cache-invalidation-client.d.ts +0 -9
- package/dist/infrastructures/cache-invalidation-client.d.ts.map +0 -1
- package/dist/infrastructures/cache-invalidation-client.js +0 -21
- package/dist/infrastructures/cache-invalidation-client.js.map +0 -1
- package/dist/infrastructures/cache-invalidation-client.test.d.ts +0 -2
- package/dist/infrastructures/cache-invalidation-client.test.d.ts.map +0 -1
- package/dist/infrastructures/cache-invalidation-client.test.js +0 -25
- package/dist/infrastructures/cache-invalidation-client.test.js.map +0 -1
- package/dist/infrastructures/images-command-repository.d.ts +0 -34
- package/dist/infrastructures/images-command-repository.d.ts.map +0 -1
- package/dist/infrastructures/images-command-repository.js +0 -53
- package/dist/infrastructures/images-command-repository.js.map +0 -1
- package/dist/infrastructures/notes-command-repository.d.ts +0 -34
- package/dist/infrastructures/notes-command-repository.d.ts.map +0 -1
- package/dist/infrastructures/notes-command-repository.js +0 -53
- package/dist/infrastructures/notes-command-repository.js.map +0 -1
- package/dist/ingest-articles.d.ts +0 -3
- package/dist/ingest-articles.d.ts.map +0 -1
- package/dist/ingest-articles.js.map +0 -1
- package/dist/ingest-books.d.ts +0 -3
- package/dist/ingest-books.d.ts.map +0 -1
- package/dist/ingest-books.js.map +0 -1
- package/dist/ingest-images.d.ts +0 -3
- package/dist/ingest-images.d.ts.map +0 -1
- package/dist/ingest-images.js.map +0 -1
- package/dist/ingest-notes.d.ts +0 -3
- package/dist/ingest-notes.d.ts.map +0 -1
- package/dist/ingest-notes.js.map +0 -1
- package/dist/lib/glob-paths.d.ts +0 -6
- package/dist/lib/glob-paths.d.ts.map +0 -1
- package/dist/lib/glob-paths.js +0 -9
- package/dist/lib/glob-paths.js.map +0 -1
- package/dist/lib/glob-paths.test.d.ts +0 -2
- package/dist/lib/glob-paths.test.d.ts.map +0 -1
- package/dist/lib/glob-paths.test.js +0 -30
- package/dist/lib/glob-paths.test.js.map +0 -1
- package/dist/lib/html-charset.d.ts +0 -4
- package/dist/lib/html-charset.d.ts.map +0 -1
- package/dist/lib/html-charset.js +0 -33
- package/dist/lib/html-charset.js.map +0 -1
- package/dist/lib/html-charset.test.d.ts +0 -2
- package/dist/lib/html-charset.test.d.ts.map +0 -1
- package/dist/lib/html-charset.test.js +0 -27
- package/dist/lib/html-charset.test.js.map +0 -1
- package/dist/rag/delete-collection.d.ts +0 -3
- package/dist/rag/delete-collection.d.ts.map +0 -1
- package/dist/rag/delete-collection.js.map +0 -1
- package/dist/rag/ingest-config.d.ts +0 -8
- package/dist/rag/ingest-config.d.ts.map +0 -1
- package/dist/rag/ingest-config.js +0 -8
- package/dist/rag/ingest-config.js.map +0 -1
- package/dist/rag/ingest.d.ts +0 -3
- package/dist/rag/ingest.d.ts.map +0 -1
- package/dist/rag/ingest.js.map +0 -1
- package/dist/rag/search.d.ts +0 -3
- package/dist/rag/search.d.ts.map +0 -1
- package/dist/rag/search.js.map +0 -1
- package/dist/reset-articles.d.ts +0 -3
- package/dist/reset-articles.d.ts.map +0 -1
- package/dist/reset-articles.js.map +0 -1
- package/dist/reset-books.d.ts +0 -3
- package/dist/reset-books.d.ts.map +0 -1
- package/dist/reset-books.js.map +0 -1
- package/dist/reset-images.d.ts +0 -3
- package/dist/reset-images.d.ts.map +0 -1
- package/dist/reset-images.js.map +0 -1
- package/dist/reset-notes.d.ts +0 -3
- package/dist/reset-notes.d.ts.map +0 -1
- package/dist/reset-notes.js.map +0 -1
- package/dist/revert-articles.d.ts +0 -3
- package/dist/revert-articles.d.ts.map +0 -1
- package/dist/revert-articles.js.map +0 -1
- package/dist/revert-books.d.ts +0 -3
- package/dist/revert-books.d.ts.map +0 -1
- package/dist/revert-books.js.map +0 -1
- package/dist/revert-images.d.ts +0 -3
- package/dist/revert-images.d.ts.map +0 -1
- package/dist/revert-images.js.map +0 -1
- package/dist/revert-notes.d.ts +0 -3
- package/dist/revert-notes.d.ts.map +0 -1
- package/dist/revert-notes.js.map +0 -1
- package/dist/s-content-format-runner.d.ts +0 -10
- package/dist/s-content-format-runner.d.ts.map +0 -1
- package/dist/s-content-format-runner.js +0 -76
- package/dist/s-content-format-runner.js.map +0 -1
- package/dist/s-content-format.d.ts +0 -3
- package/dist/s-content-format.d.ts.map +0 -1
- package/dist/s-content-format.js.map +0 -1
- package/dist/s-content-format.test.d.ts +0 -2
- package/dist/s-content-format.test.d.ts.map +0 -1
- package/dist/s-content-format.test.js +0 -99
- package/dist/s-content-format.test.js.map +0 -1
- package/dist/update-json-articles.d.ts +0 -3
- package/dist/update-json-articles.d.ts.map +0 -1
- package/dist/update-json-articles.js.map +0 -1
- package/dist/update-raw-articles.d.ts +0 -3
- package/dist/update-raw-articles.d.ts.map +0 -1
- package/dist/update-raw-articles.js.map +0 -1
- package/dist/validate-json-articles.d.ts +0 -3
- package/dist/validate-json-articles.d.ts.map +0 -1
- package/dist/validate-json-articles.js.map +0 -1
package/dist/ingest-images.js
CHANGED
|
@@ -1,188 +1,37 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
2
|
+
import { createRequire as __cliCreateRequire } from "node:module"; const require = __cliCreateRequire(import.meta.url);
|
|
3
|
+
import {
|
|
4
|
+
runContentImport,
|
|
5
|
+
sharpImageProcessor
|
|
6
|
+
} from "./chunk-XG6LAGZO.js";
|
|
7
|
+
import "./chunk-KKZP7ZF3.js";
|
|
8
|
+
import "./chunk-F4J6JBR4.js";
|
|
9
|
+
import "./chunk-M275YZQP.js";
|
|
10
|
+
import "./chunk-7PVU2Z32.js";
|
|
11
|
+
import {
|
|
12
|
+
globPaths
|
|
13
|
+
} from "./chunk-AJMTRCPJ.js";
|
|
14
|
+
import "./chunk-JZOR5GA2.js";
|
|
15
|
+
|
|
16
|
+
// src/ingest-images.ts
|
|
7
17
|
import { readFile, stat } from "node:fs/promises";
|
|
8
|
-
import { basename
|
|
9
|
-
|
|
10
|
-
const
|
|
11
|
-
const
|
|
12
|
-
|
|
13
|
-
const
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
default:
|
|
25
|
-
return null;
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
async function main() {
|
|
29
|
-
const dryRun = process.argv.includes("--dry-run");
|
|
30
|
-
const env = {
|
|
31
|
-
DATABASE_URL: process.env.DATABASE_URL,
|
|
32
|
-
PUSHOVER_URL: process.env.PUSHOVER_URL,
|
|
33
|
-
PUSHOVER_USER_KEY: process.env.PUSHOVER_USER_KEY,
|
|
34
|
-
PUSHOVER_APP_TOKEN: process.env.PUSHOVER_APP_TOKEN,
|
|
35
|
-
USERNAME_TO_EXPORT: process.env.USERNAME_TO_EXPORT,
|
|
36
|
-
MINIO_BUCKET_NAME: process.env.MINIO_BUCKET_NAME,
|
|
18
|
+
import { basename } from "node:path";
|
|
19
|
+
async function* source(root) {
|
|
20
|
+
for (const path of await globPaths(`${root}/image/dump/*`)) {
|
|
21
|
+
const format = /\.(jpg|jpeg|png|webp)$/iu.exec(path)?.[1]?.toLowerCase();
|
|
22
|
+
if (!format) continue;
|
|
23
|
+
const bytes = await readFile(path);
|
|
24
|
+
const metadata = await sharpImageProcessor.getMetadata(bytes);
|
|
25
|
+
yield {
|
|
26
|
+
values: {
|
|
27
|
+
path: basename(path),
|
|
28
|
+
fileSize: (await stat(path)).size,
|
|
29
|
+
contentType: `image/${format === "jpg" ? "jpeg" : format}`,
|
|
30
|
+
width: metadata.width ?? null,
|
|
31
|
+
height: metadata.height ?? null
|
|
32
|
+
},
|
|
33
|
+
media: { path: basename(path), bytes }
|
|
37
34
|
};
|
|
38
|
-
|
|
39
|
-
throw new Error("Required environment variables are not set.");
|
|
40
|
-
}
|
|
41
|
-
if (process.env.MINIO_USE_SSL === "true" &&
|
|
42
|
-
(!process.env.CF_ACCESS_CLIENT_ID || !process.env.CF_ACCESS_CLIENT_SECRET)) {
|
|
43
|
-
throw new Error("CF_ACCESS_CLIENT_ID and CF_ACCESS_CLIENT_SECRET are required when MINIO_USE_SSL is true.");
|
|
44
|
-
}
|
|
45
|
-
const contentsPath = process.env.S_CONTENTS_PATH ?? process.cwd();
|
|
46
|
-
const prisma = createPrismaClient(env.DATABASE_URL ?? "");
|
|
47
|
-
const notificationService = createPushoverService({
|
|
48
|
-
url: env.PUSHOVER_URL ?? "",
|
|
49
|
-
userKey: env.PUSHOVER_USER_KEY ?? "",
|
|
50
|
-
appToken: env.PUSHOVER_APP_TOKEN ?? "",
|
|
51
|
-
});
|
|
52
|
-
const minioClient = createMinioClient();
|
|
53
|
-
const bucketName = env.MINIO_BUCKET_NAME ?? "";
|
|
54
|
-
const userId = makeUserId(env.USERNAME_TO_EXPORT ?? "");
|
|
55
|
-
const exported = makeExportedStatus();
|
|
56
|
-
const filePaths = new Set();
|
|
57
|
-
async function ingestImages() {
|
|
58
|
-
const files = await globPaths(`${contentsPath}/image/dump/*`);
|
|
59
|
-
const imageFiles = files.filter((f) => getContentType(f) !== null);
|
|
60
|
-
console.log(`📁 ${imageFiles.length} 件の画像ファイルを検出しました。`);
|
|
61
|
-
const existingImages = await prisma.image.findMany({
|
|
62
|
-
where: { userId },
|
|
63
|
-
select: { id: true, path: true },
|
|
64
|
-
});
|
|
65
|
-
const existingImagesMap = new Map(existingImages.map((i) => [i.path, i]));
|
|
66
|
-
console.log(`📊 DB に ${existingImagesMap.size} 件の既存画像があります。`);
|
|
67
|
-
let insertedCount = 0;
|
|
68
|
-
let skippedCount = 0;
|
|
69
|
-
let errorCount = 0;
|
|
70
|
-
for (const filePath of imageFiles) {
|
|
71
|
-
const imagePath = basename(filePath);
|
|
72
|
-
filePaths.add(imagePath);
|
|
73
|
-
try {
|
|
74
|
-
if (existingImagesMap.has(imagePath)) {
|
|
75
|
-
skippedCount++;
|
|
76
|
-
continue;
|
|
77
|
-
}
|
|
78
|
-
const buffer = await readFile(filePath);
|
|
79
|
-
const fileStat = await stat(filePath);
|
|
80
|
-
const metadata = await readImageMetadata(buffer);
|
|
81
|
-
const contentType = getContentType(filePath);
|
|
82
|
-
if (!contentType) {
|
|
83
|
-
console.log(`⏭️ スキップ(未対応形式): ${imagePath}`);
|
|
84
|
-
skippedCount++;
|
|
85
|
-
continue;
|
|
86
|
-
}
|
|
87
|
-
if (dryRun) {
|
|
88
|
-
console.log(`🔍 [dry-run] 挿入予定: ${imagePath}`);
|
|
89
|
-
insertedCount++;
|
|
90
|
-
continue;
|
|
91
|
-
}
|
|
92
|
-
// Upload original to MinIO if not exists
|
|
93
|
-
const originalKey = `${ORIGINAL_IMAGE_PATH}/${imagePath}`;
|
|
94
|
-
try {
|
|
95
|
-
await minioClient.statObject(bucketName, originalKey);
|
|
96
|
-
console.log(`📦 MinIO に既存(original): ${imagePath}`);
|
|
97
|
-
}
|
|
98
|
-
catch {
|
|
99
|
-
await minioClient.putObject(bucketName, originalKey, buffer);
|
|
100
|
-
console.log(`📤 MinIO アップロード(original): ${imagePath}`);
|
|
101
|
-
}
|
|
102
|
-
// Generate and upload thumbnail
|
|
103
|
-
const thumbnailBuffer = await createWebpThumbnail(buffer, {
|
|
104
|
-
width: THUMBNAIL_SIZE,
|
|
105
|
-
height: THUMBNAIL_SIZE,
|
|
106
|
-
});
|
|
107
|
-
const thumbnailKey = `${THUMBNAIL_IMAGE_PATH}/${imagePath}`;
|
|
108
|
-
await minioClient.putObject(bucketName, thumbnailKey, Buffer.from(thumbnailBuffer));
|
|
109
|
-
console.log(`📤 MinIO アップロード(thumbnail): ${imagePath}`);
|
|
110
|
-
// Create DB record
|
|
111
|
-
await prisma.image.create({
|
|
112
|
-
data: {
|
|
113
|
-
id: String(makeId()),
|
|
114
|
-
path: imagePath,
|
|
115
|
-
contentType,
|
|
116
|
-
fileSize: fileStat.size,
|
|
117
|
-
width: metadata.width,
|
|
118
|
-
height: metadata.height,
|
|
119
|
-
status: exported.status,
|
|
120
|
-
exportedAt: exported.exportedAt,
|
|
121
|
-
userId,
|
|
122
|
-
createdAt: new Date(),
|
|
123
|
-
},
|
|
124
|
-
});
|
|
125
|
-
insertedCount++;
|
|
126
|
-
console.log(`✅ 挿入: ${imagePath}`);
|
|
127
|
-
}
|
|
128
|
-
catch (error) {
|
|
129
|
-
console.error(`❌ エラー(${imagePath}):`, error);
|
|
130
|
-
errorCount++;
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
return { insertedCount, skippedCount, errorCount };
|
|
134
|
-
}
|
|
135
|
-
async function purgeImages() {
|
|
136
|
-
const exportedImages = await prisma.image.findMany({
|
|
137
|
-
where: { userId, status: exported.status },
|
|
138
|
-
select: { id: true, path: true },
|
|
139
|
-
});
|
|
140
|
-
const toDelete = exportedImages.filter((i) => !filePaths.has(i.path));
|
|
141
|
-
if (toDelete.length === 0) {
|
|
142
|
-
console.log("🗑️ 削除対象なし");
|
|
143
|
-
return 0;
|
|
144
|
-
}
|
|
145
|
-
let deletedCount = 0;
|
|
146
|
-
for (const image of toDelete) {
|
|
147
|
-
try {
|
|
148
|
-
if (dryRun) {
|
|
149
|
-
console.log(`🗑️ [dry-run] 削除予定: ${image.path}`);
|
|
150
|
-
}
|
|
151
|
-
else {
|
|
152
|
-
await prisma.image.delete({ where: { id: image.id } });
|
|
153
|
-
await minioClient.removeObject(bucketName, `${ORIGINAL_IMAGE_PATH}/${image.path}`);
|
|
154
|
-
await minioClient.removeObject(bucketName, `${THUMBNAIL_IMAGE_PATH}/${image.path}`);
|
|
155
|
-
console.log(`🗑️ 削除: ${image.path}`);
|
|
156
|
-
}
|
|
157
|
-
deletedCount++;
|
|
158
|
-
}
|
|
159
|
-
catch (error) {
|
|
160
|
-
console.error(`❌ 削除エラー(${image.path}):`, error);
|
|
161
|
-
}
|
|
162
|
-
}
|
|
163
|
-
return deletedCount;
|
|
164
|
-
}
|
|
165
|
-
try {
|
|
166
|
-
const { insertedCount, skippedCount, errorCount } = await ingestImages();
|
|
167
|
-
const deletedCount = await purgeImages();
|
|
168
|
-
console.log(`\n📊 結果: 挿入 ${insertedCount} 件, スキップ ${skippedCount} 件, 削除 ${deletedCount} 件, エラー ${errorCount} 件${dryRun ? " (dry-run)" : ""}`);
|
|
169
|
-
await notificationService.notifyInfo(`${SCRIPT_NAME} completed`, {
|
|
170
|
-
caller: SCRIPT_NAME,
|
|
171
|
-
});
|
|
172
|
-
}
|
|
173
|
-
catch (error) {
|
|
174
|
-
console.error("❌ エラーが発生しました:", error);
|
|
175
|
-
await notificationService.notifyError(`${SCRIPT_NAME} failed: ${String(error)}`, {
|
|
176
|
-
caller: SCRIPT_NAME,
|
|
177
|
-
});
|
|
178
|
-
process.exit(1);
|
|
179
|
-
}
|
|
180
|
-
finally {
|
|
181
|
-
await prisma.$disconnect();
|
|
182
|
-
}
|
|
35
|
+
}
|
|
183
36
|
}
|
|
184
|
-
|
|
185
|
-
console.error(error);
|
|
186
|
-
process.exit(1);
|
|
187
|
-
});
|
|
188
|
-
//# sourceMappingURL=ingest-images.js.map
|
|
37
|
+
await runContentImport("images", source);
|
package/dist/ingest-notes.js
CHANGED
|
@@ -1,179 +1,49 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
|
|
2
|
+
import { createRequire as __cliCreateRequire } from "node:module"; const require = __cliCreateRequire(import.meta.url);
|
|
3
|
+
import {
|
|
4
|
+
runContentImport
|
|
5
|
+
} from "./chunk-XG6LAGZO.js";
|
|
6
|
+
import "./chunk-KKZP7ZF3.js";
|
|
7
|
+
import "./chunk-F4J6JBR4.js";
|
|
8
|
+
import "./chunk-M275YZQP.js";
|
|
9
|
+
import "./chunk-7PVU2Z32.js";
|
|
10
|
+
import {
|
|
11
|
+
parseMarkdownFrontmatter
|
|
12
|
+
} from "./chunk-HDYQV2Y2.js";
|
|
13
|
+
import {
|
|
14
|
+
globPaths
|
|
15
|
+
} from "./chunk-AJMTRCPJ.js";
|
|
16
|
+
import "./chunk-JZOR5GA2.js";
|
|
17
|
+
|
|
18
|
+
// src/ingest-notes.ts
|
|
6
19
|
import { readFile } from "node:fs/promises";
|
|
7
20
|
import { basename } from "node:path";
|
|
8
|
-
import { globPaths } from "./lib/glob-paths.js";
|
|
9
|
-
const SCRIPT_NAME = "ingest-notes";
|
|
10
21
|
function parseFrontmatter(content) {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
22
|
+
const parsed = parseMarkdownFrontmatter(content);
|
|
23
|
+
return {
|
|
24
|
+
body: parsed.content.trim(),
|
|
25
|
+
draft: typeof parsed.data.draft === "boolean" ? parsed.data.draft : void 0,
|
|
26
|
+
heading: typeof parsed.data.heading === "string" ? parsed.data.heading : void 0
|
|
27
|
+
};
|
|
17
28
|
}
|
|
18
29
|
function parseNoteFile(filePath, content) {
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
return { title, markdown };
|
|
30
|
+
const { heading, draft, body } = parseFrontmatter(content);
|
|
31
|
+
if (draft) return null;
|
|
32
|
+
if (heading) {
|
|
33
|
+
return { title: heading, markdown: body };
|
|
34
|
+
}
|
|
35
|
+
const title = basename(filePath, ".md");
|
|
36
|
+
const titleLine = `# ${title}`;
|
|
37
|
+
let markdown = body;
|
|
38
|
+
if (markdown.startsWith(titleLine)) {
|
|
39
|
+
markdown = markdown.slice(titleLine.length).replace(/^\n+/u, "");
|
|
40
|
+
}
|
|
41
|
+
return { title, markdown };
|
|
32
42
|
}
|
|
33
|
-
async function
|
|
34
|
-
|
|
35
|
-
const
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
PUSHOVER_USER_KEY: process.env.PUSHOVER_USER_KEY,
|
|
39
|
-
PUSHOVER_APP_TOKEN: process.env.PUSHOVER_APP_TOKEN,
|
|
40
|
-
USERNAME_TO_EXPORT: process.env.USERNAME_TO_EXPORT,
|
|
41
|
-
};
|
|
42
|
-
if (Object.values(env).some((v) => !v)) {
|
|
43
|
-
throw new Error("Required environment variables are not set.");
|
|
44
|
-
}
|
|
45
|
-
const contentsPath = process.env.S_CONTENTS_PATH ?? process.cwd();
|
|
46
|
-
const prisma = createPrismaClient(env.DATABASE_URL ?? "");
|
|
47
|
-
const notificationService = createPushoverService({
|
|
48
|
-
url: env.PUSHOVER_URL ?? "",
|
|
49
|
-
userKey: env.PUSHOVER_USER_KEY ?? "",
|
|
50
|
-
appToken: env.PUSHOVER_APP_TOKEN ?? "",
|
|
51
|
-
});
|
|
52
|
-
const userId = makeUserId(env.USERNAME_TO_EXPORT ?? "");
|
|
53
|
-
const exported = makeExportedStatus();
|
|
54
|
-
const fileTitles = new Set();
|
|
55
|
-
async function ingestNotes() {
|
|
56
|
-
const files = await globPaths(`${contentsPath}/markdown/note/*.md`);
|
|
57
|
-
console.log(`📁 ${files.length} 件のファイルを検出しました。`);
|
|
58
|
-
const existingNotes = await prisma.note.findMany({
|
|
59
|
-
where: { userId },
|
|
60
|
-
select: { id: true, title: true, markdown: true },
|
|
61
|
-
});
|
|
62
|
-
const existingNotesMap = new Map(existingNotes.map((n) => [n.title, n]));
|
|
63
|
-
console.log(`📊 DB に ${existingNotesMap.size} 件の既存ノートがあります。`);
|
|
64
|
-
async function upsertNote(parsed) {
|
|
65
|
-
fileTitles.add(parsed.title);
|
|
66
|
-
const existing = existingNotesMap.get(parsed.title);
|
|
67
|
-
if (existing) {
|
|
68
|
-
if (existing.markdown === parsed.markdown) {
|
|
69
|
-
// console.log(`⏭️ スキップ(変更なし): ${parsed.title}`);
|
|
70
|
-
return "skipped";
|
|
71
|
-
}
|
|
72
|
-
if (dryRun) {
|
|
73
|
-
console.log(`🔄 [dry-run] 更新予定: ${parsed.title}`);
|
|
74
|
-
}
|
|
75
|
-
else {
|
|
76
|
-
await prisma.note.update({
|
|
77
|
-
where: { id: existing.id },
|
|
78
|
-
data: { markdown: parsed.markdown },
|
|
79
|
-
});
|
|
80
|
-
console.log(`🔄 更新: ${parsed.title}`);
|
|
81
|
-
}
|
|
82
|
-
return "updated";
|
|
83
|
-
}
|
|
84
|
-
if (dryRun) {
|
|
85
|
-
console.log(`🔍 [dry-run] 挿入予定: ${parsed.title}`);
|
|
86
|
-
return "inserted";
|
|
87
|
-
}
|
|
88
|
-
await prisma.note.create({
|
|
89
|
-
data: {
|
|
90
|
-
id: String(makeId()),
|
|
91
|
-
title: parsed.title,
|
|
92
|
-
markdown: parsed.markdown,
|
|
93
|
-
status: exported.status,
|
|
94
|
-
exportedAt: exported.exportedAt,
|
|
95
|
-
userId,
|
|
96
|
-
createdAt: new Date(),
|
|
97
|
-
},
|
|
98
|
-
});
|
|
99
|
-
console.log(`✅ 挿入: ${parsed.title}`);
|
|
100
|
-
return "inserted";
|
|
101
|
-
}
|
|
102
|
-
let insertedCount = 0;
|
|
103
|
-
let updatedCount = 0;
|
|
104
|
-
let skippedCount = 0;
|
|
105
|
-
let errorCount = 0;
|
|
106
|
-
for (const filePath of files) {
|
|
107
|
-
let parsed = null;
|
|
108
|
-
try {
|
|
109
|
-
const content = await readFile(filePath, "utf-8");
|
|
110
|
-
parsed = parseNoteFile(filePath, content);
|
|
111
|
-
if (!parsed) {
|
|
112
|
-
console.log(`⏭️ スキップ(draft): ${basename(filePath)}`);
|
|
113
|
-
skippedCount++;
|
|
114
|
-
continue;
|
|
115
|
-
}
|
|
116
|
-
const result = await upsertNote(parsed);
|
|
117
|
-
if (result === "inserted")
|
|
118
|
-
insertedCount++;
|
|
119
|
-
else if (result === "updated")
|
|
120
|
-
updatedCount++;
|
|
121
|
-
else
|
|
122
|
-
skippedCount++;
|
|
123
|
-
}
|
|
124
|
-
catch (error) {
|
|
125
|
-
console.error(`❌ エラー(${basename(filePath)}):`, parsed
|
|
126
|
-
? `title(${parsed.title.length}文字) markdown(${parsed.markdown.length}文字)`
|
|
127
|
-
: "parse前", error);
|
|
128
|
-
errorCount++;
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
return { insertedCount, updatedCount, skippedCount, errorCount };
|
|
132
|
-
}
|
|
133
|
-
async function purgeNotes() {
|
|
134
|
-
const exportedNotes = await prisma.note.findMany({
|
|
135
|
-
where: { userId, status: exported.status },
|
|
136
|
-
select: { id: true, title: true },
|
|
137
|
-
});
|
|
138
|
-
const toDelete = exportedNotes.filter((n) => !fileTitles.has(n.title));
|
|
139
|
-
if (toDelete.length === 0) {
|
|
140
|
-
console.log("🗑️ 削除対象なし");
|
|
141
|
-
return 0;
|
|
142
|
-
}
|
|
143
|
-
let deletedCount = 0;
|
|
144
|
-
for (const note of toDelete) {
|
|
145
|
-
if (dryRun) {
|
|
146
|
-
console.log(`🗑️ [dry-run] 削除予定: ${note.title}`);
|
|
147
|
-
}
|
|
148
|
-
else {
|
|
149
|
-
await prisma.note.delete({ where: { id: note.id } });
|
|
150
|
-
console.log(`🗑️ 削除: ${note.title}`);
|
|
151
|
-
}
|
|
152
|
-
deletedCount++;
|
|
153
|
-
}
|
|
154
|
-
return deletedCount;
|
|
155
|
-
}
|
|
156
|
-
try {
|
|
157
|
-
const { insertedCount, updatedCount, skippedCount, errorCount } = await ingestNotes();
|
|
158
|
-
const deletedCount = await purgeNotes();
|
|
159
|
-
console.log(`\n📊 結果: 挿入 ${insertedCount} 件, 更新 ${updatedCount} 件, スキップ ${skippedCount} 件, 削除 ${deletedCount} 件, エラー ${errorCount} 件${dryRun ? " (dry-run)" : ""}`);
|
|
160
|
-
await notificationService.notifyInfo(`${SCRIPT_NAME} completed`, {
|
|
161
|
-
caller: SCRIPT_NAME,
|
|
162
|
-
});
|
|
163
|
-
}
|
|
164
|
-
catch (error) {
|
|
165
|
-
console.error("❌ エラーが発生しました:", error);
|
|
166
|
-
await notificationService.notifyError(`${SCRIPT_NAME} failed: ${String(error)}`, {
|
|
167
|
-
caller: SCRIPT_NAME,
|
|
168
|
-
});
|
|
169
|
-
process.exit(1);
|
|
170
|
-
}
|
|
171
|
-
finally {
|
|
172
|
-
await prisma.$disconnect();
|
|
173
|
-
}
|
|
43
|
+
async function* source(root) {
|
|
44
|
+
for (const path of await globPaths(`${root}/markdown/note/*.md`)) {
|
|
45
|
+
const values = parseNoteFile(path, await readFile(path, "utf-8"));
|
|
46
|
+
if (values) yield { values };
|
|
47
|
+
}
|
|
174
48
|
}
|
|
175
|
-
|
|
176
|
-
console.error(error);
|
|
177
|
-
process.exit(1);
|
|
178
|
-
});
|
|
179
|
-
//# sourceMappingURL=ingest-notes.js.map
|
|
49
|
+
await runContentImport("notes", source);
|
|
@@ -1,27 +1,37 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
2
|
+
import { createRequire as __cliCreateRequire } from "node:module"; const require = __cliCreateRequire(import.meta.url);
|
|
3
|
+
import {
|
|
4
|
+
deleteCollection,
|
|
5
|
+
getQdrantClient
|
|
6
|
+
} from "../chunk-J4VLH4VA.js";
|
|
7
|
+
import "../chunk-JZOR5GA2.js";
|
|
8
|
+
|
|
9
|
+
// src/rag/delete-collection.ts
|
|
3
10
|
async function main() {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
11
|
+
const collectionName = process.argv[2];
|
|
12
|
+
if (!collectionName) {
|
|
13
|
+
console.error(
|
|
14
|
+
"Usage: rag-delete-collection <collection-name>\nExample: rag-delete-collection knowledge_v1"
|
|
15
|
+
);
|
|
16
|
+
process.exit(1);
|
|
17
|
+
}
|
|
18
|
+
if (!process.env.QDRANT_URL) {
|
|
19
|
+
throw new Error("QDRANT_URL environment variable is required.");
|
|
20
|
+
}
|
|
21
|
+
const qdrant = getQdrantClient();
|
|
22
|
+
const collections = await qdrant.getCollections();
|
|
23
|
+
const exists = collections.collections.some((c) => c.name === collectionName);
|
|
24
|
+
if (!exists) {
|
|
25
|
+
console.log(
|
|
26
|
+
`Collection "${collectionName}" does not exist. Nothing to delete.`
|
|
27
|
+
);
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
console.log(`Deleting collection "${collectionName}"...`);
|
|
31
|
+
await deleteCollection(collectionName);
|
|
32
|
+
console.log(`Collection "${collectionName}" deleted successfully.`);
|
|
22
33
|
}
|
|
23
34
|
main().catch((error) => {
|
|
24
|
-
|
|
25
|
-
|
|
35
|
+
console.error("Failed to delete collection:", error);
|
|
36
|
+
process.exit(1);
|
|
26
37
|
});
|
|
27
|
-
//# sourceMappingURL=delete-collection.js.map
|