mcp-scraper 0.64.0 → 0.65.0
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/CHANGELOG.md +16 -0
- package/README.md +2 -2
- package/dist/bin/api-server.cjs +1028 -497
- package/dist/bin/api-server.cjs.map +1 -1
- package/dist/bin/api-server.js +2 -2
- package/dist/bin/mcp-scraper-cli.cjs +1 -1
- package/dist/bin/mcp-scraper-cli.cjs.map +1 -1
- package/dist/bin/mcp-scraper-cli.js +1 -1
- package/dist/bin/mcp-scraper-install.cjs +2 -2
- package/dist/bin/mcp-scraper-install.cjs.map +1 -1
- package/dist/bin/mcp-scraper-install.js +2 -2
- package/dist/bin/mcp-stdio-server.cjs +49 -9
- package/dist/bin/mcp-stdio-server.cjs.map +1 -1
- package/dist/bin/mcp-stdio-server.js +4 -4
- package/dist/{chunk-TRSZEK2D.js → chunk-2XUXVKT4.js} +3 -3
- package/dist/{chunk-TRSZEK2D.js.map → chunk-2XUXVKT4.js.map} +1 -1
- package/dist/chunk-5BODYBIP.js +7 -0
- package/dist/chunk-5BODYBIP.js.map +1 -0
- package/dist/{chunk-BRKCPONM.js → chunk-5PIO7QBG.js} +2 -2
- package/dist/{chunk-5QYSY5KI.js → chunk-AMLFKPLL.js} +139 -3
- package/dist/chunk-AMLFKPLL.js.map +1 -0
- package/dist/{chunk-3NXLGTC6.js → chunk-DCWXVAQT.js} +2 -2
- package/dist/{chunk-3NXLGTC6.js.map → chunk-DCWXVAQT.js.map} +1 -1
- package/dist/{chunk-EEW3DMI5.js → chunk-PSKRQDGN.js} +50 -10
- package/dist/chunk-PSKRQDGN.js.map +1 -0
- package/dist/{extract-bundle-FW23CEMG.js → extract-bundle-UWKJT4MU.js} +371 -14
- package/dist/extract-bundle-UWKJT4MU.js.map +1 -0
- package/dist/{server-TMAWQYZE.js → server-AFEA235I.js} +170 -163
- package/dist/server-AFEA235I.js.map +1 -0
- package/dist/{site-extract-repository-UXSFD2QM.js → site-extract-repository-J3RH3MOS.js} +3 -3
- package/dist/{worker-DD243CON.js → worker-YKRIK5LS.js} +2 -2
- package/package.json +3 -1
- package/dist/chunk-5QYSY5KI.js.map +0 -1
- package/dist/chunk-DYSXI6QU.js +0 -7
- package/dist/chunk-DYSXI6QU.js.map +0 -1
- package/dist/chunk-EEW3DMI5.js.map +0 -1
- package/dist/extract-bundle-FW23CEMG.js.map +0 -1
- package/dist/server-TMAWQYZE.js.map +0 -1
- /package/dist/{chunk-BRKCPONM.js.map → chunk-5PIO7QBG.js.map} +0 -0
- /package/dist/{site-extract-repository-UXSFD2QM.js.map → site-extract-repository-J3RH3MOS.js.map} +0 -0
- /package/dist/{worker-DD243CON.js.map → worker-YKRIK5LS.js.map} +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/api/extract-bundle.ts","../src/api/site-content-similarity.ts"],"sourcesContent":["import { createWriteStream, mkdirSync, readFileSync, readdirSync, rmSync, statSync, writeFileSync } from 'node:fs'\nimport { createHash } from 'node:crypto'\nimport { basename, join } from 'node:path'\nimport { tmpdir } from 'node:os'\nimport { createGzip } from 'node:zlib'\nimport { once } from 'node:events'\nimport { finished } from 'node:stream/promises'\nimport { ZipFile } from 'yazl'\nimport pLimit from 'p-limit'\nimport { getDb } from './db.js'\nimport { computeIssues, renderIssueReport } from './seo-issues.js'\nimport { renderLinkReport, type ExtDomainRow, type LinkReport } from './seo-link-report.js'\nimport type { PageLinkMetrics } from './seo-link-graph.js'\nimport type { SeoAudit } from './seo-audit.js'\nimport type { ExtractJobArtifact, ExtractJobRow } from './site-extract-repository.js'\nimport { extractJobLimitInfo } from './site-extract-repository.js'\nimport type { PageData } from './site-extractor.js'\nimport { publicizeExtractionFailure } from './extraction-problems.js'\nimport { renderImageSection, type ImageAudit } from './image-audit.js'\nimport { downloadAsset } from '../lib/media-extractor.js'\nimport { createSiteExtractBundleArtifactStream, createSiteExtractImageArtifact } from './site-extract-artifacts.js'\nimport { createSiteExtractContentReader } from './site-extract-content-store.js'\nimport {\n analyzeSiteContentSimilarity,\n type EmbedSimilarityTexts,\n type SimilarityPageInput,\n type SiteSimilarityRow,\n} from './site-content-similarity.js'\n\nexport const SITE_EXTRACT_PAGE_CHUNK = 25\nconst MAX_IMAGES_PER_PAGE = 20\nconst MAX_IMAGES_PER_SITE = 500\nconst IMAGE_DOWNLOAD_CONCURRENCY = 8\nconst MAX_IMAGE_BYTES = 10 * 1024 * 1024\nconst MAX_SITE_IMAGE_BYTES = 100 * 1024 * 1024\nexport const MAX_ANALYZED_LINK_EDGES = 250_000\n\nfunction normalize(u: string): string {\n return u.split('#')[0].replace(/\\/$/, '')\n}\n\nfunction registrableDomain(host: string): string {\n const h = host.replace(/^www\\./, '').toLowerCase()\n const parts = h.split('.')\n return parts.length <= 2 ? h : parts.slice(-2).join('.')\n}\n\nfunction safeImageFilename(url: string, index: number): string {\n try {\n const u = new URL(url)\n const base = basename(u.pathname).replace(/[^a-zA-Z0-9._-]/g, '_').slice(0, 80)\n return base || `image-${index}`\n } catch {\n return `image-${index}`\n }\n}\n\nfunction slugFactory() {\n const counts = new Map<string, number>()\n return (url: string): string => {\n const base = url.replace(/^https?:\\/\\//, '').replace(/[^a-zA-Z0-9]+/g, '-').replace(/^-+|-+$/g, '').slice(0, 80) || 'page'\n const n = counts.get(base) ?? 0\n counts.set(base, n + 1)\n return n ? `${base}-${n}` : base\n }\n}\n\nasync function* pageChunks(jobId: string): AsyncGenerator<PageData[]> {\n const db = getDb()\n let lastRowId = 0\n for (;;) {\n const res = await db.execute({\n sql: `SELECT rowid AS cursor_id, page\n FROM site_extract_pages\n WHERE job_id = ? AND rowid > ?\n ORDER BY rowid\n LIMIT ${SITE_EXTRACT_PAGE_CHUNK}`,\n args: [jobId, lastRowId],\n })\n if (!res.rows.length) return\n lastRowId = Number(res.rows.at(-1)?.cursor_id ?? lastRowId)\n if (!Number.isSafeInteger(lastRowId) || lastRowId <= 0) throw new Error('site extract page cursor is invalid')\n yield res.rows.map(r => JSON.parse(String((r as unknown as Record<string, unknown>).page)) as PageData)\n }\n}\n\nexport interface AssembleExtras {\n branding?: unknown\n imageAudit?: ImageAudit | null\n seoAudit?: SeoAudit | null\n /** Test seam; production uses the configured Jina embedding provider. */\n embedSimilarityTexts?: EmbedSimilarityTexts\n}\n\nfunction csvCell(value: string | number | boolean | null): string {\n const text = value == null ? '' : String(value)\n return /[\",\\r\\n]/.test(text) ? `\"${text.replace(/\"/g, '\"\"')}\"` : text\n}\n\nfunction similarityTableRow(row: SiteSimilarityRow): Record<string, string | number | boolean | null> {\n return {\n source_url: row.sourceUrl,\n source_title: row.sourceTitle,\n target_url: row.targetUrl,\n target_title: row.targetTitle,\n similarity: row.similarity,\n similarity_percent: row.similarityPercent,\n corpus_percentile: row.corpusPercentile,\n exact_content_duplicate: row.exactContentDuplicate,\n source_word_count: row.sourceWordCount,\n target_word_count: row.targetWordCount,\n cluster_id: row.clusterId,\n }\n}\n\nexport async function assembleExtractArtifacts(job: ExtractJobRow, extras: AssembleExtras = {}): Promise<ExtractJobArtifact[]> {\n const dir = join(tmpdir(), `extract-bundle-${job.id}-${Date.now()}`)\n const downloadImages = job.options.downloadImages === true\n if (job.userId == null) throw new Error('site extract artifact owner is missing')\n const readPageContent = createSiteExtractContentReader(String(job.userId))\n mkdirSync(dir, { recursive: true })\n if (downloadImages) mkdirSync(join(dir, 'images'), { recursive: true })\n const captureRenderedDom = job.options.captureRenderedDom === true\n const semanticSimilarity = job.options.semanticSimilarity === true\n if (captureRenderedDom) mkdirSync(join(dir, 'rendered-dom'), { recursive: true })\n try {\n const metas: PageData[] = []\n const similarityPages: SimilarityPageInput[] = []\n const renderedDomManifest: Array<{\n url: string\n path: string\n bytes: number\n truncated: boolean\n sanitized: boolean\n }> = []\n const domSlug = slugFactory()\n const pageExportEntries: Array<{\n pageId: string\n url: string\n jsonPath: string\n htmlPath: string | null\n markdownPath: string | null\n legacyMarkdownPath: string | null\n jsonSha256: string\n htmlSha256: string | null\n markdownSha256: string | null\n htmlBytes: number\n markdownBytes: number\n }> = []\n const waybackTimeline = job.options.waybackTimeline as {\n rootUrl?: string\n timeline?: { months?: string[]; from?: string; to?: string; intervalMonths?: number; urls?: string[] }\n maxPagesPerSnapshot?: number\n } | undefined\n const statusByUrl = new Map<string, number | null>()\n for await (const chunk of pageChunks(job.id)) {\n for (const p of chunk) {\n statusByUrl.set(normalize(p.url), p.status)\n // Keep only fields needed by computeIssues/renderIssueReport. Holding\n // every bounded PageData field for 10k pages can still consume\n // hundreds of MiB even though DB reads are streamed in small chunks.\n metas.push({\n url: p.url,\n status: p.status,\n title: p.title,\n titleLength: p.titleLength,\n titlePixels: p.titlePixels,\n metaDescription: p.metaDescription,\n metaDescLength: p.metaDescLength,\n h1: p.h1,\n h1_2: p.h1_2,\n h2Count: p.h2Count,\n extractionStatus: p.extractionStatus,\n indexable: p.indexable,\n indexabilityReason: p.indexabilityReason,\n canonicalUrl: p.canonicalUrl ? p.url : null,\n wordCount: p.wordCount,\n contentHash: p.contentHash,\n imagesMissingAlt: p.imagesMissingAlt,\n schemaTypes: p.schemaTypes.length > 0 ? ['present'] : [],\n outlinks: [],\n } as unknown as PageData)\n const pageId = p.pageId ?? createHash('sha256').update(p.archivedUrl ?? p.url).digest('hex')\n const pageDir = join(dir, 'pages', pageId)\n mkdirSync(pageDir, { recursive: true })\n const content = p.contentRef ? await readPageContent(p.contentRef) : null\n const html = content?.html ?? null\n const markdown = content?.markdown ?? p.bodyMarkdown ?? null\n if (semanticSimilarity && p.extractionStatus === 'successful' && markdown?.trim()) {\n similarityPages.push({\n url: p.url,\n title: p.title,\n bodyMarkdown: markdown,\n contentHash: p.contentHash,\n wordCount: p.wordCount,\n })\n }\n if (captureRenderedDom && html != null) {\n const relativePath = `rendered-dom/${domSlug(p.url)}.html.txt`\n writeFileSync(join(dir, relativePath), html)\n renderedDomManifest.push({\n url: p.url,\n path: relativePath,\n bytes: Buffer.byteLength(html),\n truncated: p.renderedDomTruncated === true,\n sanitized: p.renderedDomSanitized === true,\n })\n }\n const htmlPath = html == null ? null : `pages/${pageId}/page.html`\n const markdownPath = markdown == null ? null : `pages/${pageId}/page.md`\n const legacyMarkdownPath = markdown == null || !p.archiveRequestedMonth\n ? null\n : `pages/${p.archiveRequestedMonth}/${pageId}.md`\n if (html != null && htmlPath) writeFileSync(join(dir, htmlPath), html)\n if (markdown != null && markdownPath) writeFileSync(join(dir, markdownPath), markdown)\n if (markdown != null && legacyMarkdownPath) {\n mkdirSync(join(dir, 'pages', p.archiveRequestedMonth!), { recursive: true })\n writeFileSync(join(dir, legacyMarkdownPath), markdown)\n }\n const { bodyMarkdown: _body, contentRef: _contentRef, discoveryLinks: _discovery, ...metadata } = p\n const pageRecord = {\n version: 'site-export-page.v1',\n ...metadata,\n pageId,\n content: {\n htmlPath,\n markdownPath,\n htmlBytes: html == null ? 0 : Buffer.byteLength(html),\n markdownBytes: markdown == null ? 0 : Buffer.byteLength(markdown),\n htmlSha256: html == null ? null : createHash('sha256').update(html).digest('hex'),\n markdownSha256: markdown == null ? null : createHash('sha256').update(markdown).digest('hex'),\n },\n }\n const pageJson = JSON.stringify(pageRecord, null, 2)\n const jsonPath = `pages/${pageId}/page.json`\n writeFileSync(join(dir, jsonPath), pageJson)\n pageExportEntries.push({\n pageId,\n url: p.archivedUrl ?? p.url,\n jsonPath,\n htmlPath,\n markdownPath,\n legacyMarkdownPath,\n jsonSha256: createHash('sha256').update(pageJson).digest('hex'),\n htmlSha256: pageRecord.content.htmlSha256,\n markdownSha256: pageRecord.content.markdownSha256,\n htmlBytes: pageRecord.content.htmlBytes,\n markdownBytes: pageRecord.content.markdownBytes,\n })\n }\n }\n\n const gz = createGzip()\n const linksOut = createWriteStream(join(dir, 'links.jsonl.gz'))\n gz.pipe(linksOut)\n const gzWrite = async (line: string) => { if (!gz.write(line)) await once(gz, 'drain') }\n const schemaOut = createWriteStream(join(dir, 'schema.jsonl'))\n const schemaWrite = async (line: string) => { if (!schemaOut.write(line)) await once(schemaOut, 'drain') }\n const failuresOut = createWriteStream(join(dir, 'failures.jsonl'))\n const failureWrite = async (line: string) => { if (!failuresOut.write(line)) await once(failuresOut, 'drain') }\n\n const inboundFrom = new Map<string, Set<string>>()\n const anchorCounts = new Map<string, Map<string, number>>()\n const adjacency = new Map<string, Set<string>>()\n const outCounts = new Map<string, { int: number; ext: number }>()\n const domMap = new Map<string, { links: number; nofollow: number; pages: Set<string> }>()\n const brokenLinkPages = new Set<string>()\n let internalTotal = 0\n let externalTotal = 0\n let brokenInternal = 0\n let streamedLinkEdges = 0\n let analyzedLinkEdges = 0\n let linkAnalysisTruncated = false\n let siteReg = ''\n try { siteReg = registrableDomain(new URL(job.startUrl).hostname) } catch { siteReg = '' }\n\n const imageLimit = pLimit(IMAGE_DOWNLOAD_CONCURRENCY)\n const imageDownloads: Promise<void>[] = []\n const imageManifest: Array<{\n imageId: string\n sourcePage: string\n sourceUrl: string\n path: string | null\n status: 'not_requested' | 'downloaded' | 'failed' | 'skipped_page_limit' | 'skipped_site_limit'\n mimeType: string | null\n bytes: number | null\n sha256: string | null\n failureCode: string | null\n failureReason: string | null\n artifactId: string | null\n }> = []\n const imageArtifacts: ExtractJobArtifact[] = []\n let imagesQueued = 0\n let imagesFailed = 0\n let imageBytesDownloaded = 0\n const consumeImageBytes = (bytes: number) => {\n if (imageBytesDownloaded + bytes > MAX_SITE_IMAGE_BYTES) return false\n imageBytesDownloaded += bytes\n return true\n }\n\n for await (const chunk of pageChunks(job.id)) {\n for (const p of chunk) {\n if (p.schema?.length) await schemaWrite(JSON.stringify({ url: p.url, schema: p.schema }) + '\\n')\n if (p.extractionStatus === 'failed') {\n const { failureCode, failureReason } = publicizeExtractionFailure(p.failureCode, p.failureReason)\n await failureWrite(JSON.stringify({\n url: p.url,\n status: p.status,\n via: p.via,\n failureCode,\n failureReason,\n fetchAttempts: p.fetchAttempts ?? [],\n }) + '\\n')\n }\n if (p.imageLinks?.length) {\n for (const [idx, imgUrl] of p.imageLinks.entries()) {\n const imageId = createHash('sha256').update(`${p.url}\\0${imgUrl}`).digest('hex')\n const record: (typeof imageManifest)[number] = {\n imageId,\n sourcePage: p.url,\n sourceUrl: imgUrl,\n path: null,\n status: 'not_requested',\n mimeType: null,\n bytes: null,\n sha256: null,\n failureCode: null,\n failureReason: null,\n artifactId: null,\n }\n imageManifest.push(record)\n if (!downloadImages) continue\n if (idx >= MAX_IMAGES_PER_PAGE) {\n record.status = 'skipped_page_limit'\n record.failureCode = 'page_image_limit'\n record.failureReason = `Only the first ${MAX_IMAGES_PER_PAGE} image candidates are downloaded per page.`\n continue\n }\n if (imagesQueued >= MAX_IMAGES_PER_SITE) {\n record.status = 'skipped_site_limit'\n record.failureCode = 'site_image_limit'\n record.failureReason = `Only the first ${MAX_IMAGES_PER_SITE} image candidates are downloaded per site.`\n continue\n }\n imagesQueued++\n const filename = `${imageId}-${safeImageFilename(imgUrl, idx)}`\n const outputPath = join(dir, 'images')\n imageDownloads.push(\n imageLimit(() => downloadAsset(imgUrl, outputPath, filename, {\n expectedType: 'image',\n maxBytes: MAX_IMAGE_BYTES,\n consumeBytes: consumeImageBytes,\n })).then(async result => {\n const bytes = readFileSync(result.savedPath)\n const artifact = await createSiteExtractImageArtifact({\n ownerId: String(job.userId),\n jobId: job.id,\n imageId,\n filename,\n contentType: result.mimeType ?? 'application/octet-stream',\n content: bytes,\n sourceUrl: imgUrl,\n sourcePage: p.url,\n })\n imageArtifacts.push(artifact)\n record.status = 'downloaded'\n record.path = `images/${filename}`\n record.artifactId = artifact.key\n record.mimeType = result.mimeType\n record.bytes = result.sizeBytes\n record.sha256 = createHash('sha256').update(bytes).digest('hex')\n }, error => {\n imagesFailed++\n record.status = 'failed'\n record.failureCode = 'image_download_failed'\n record.failureReason = (error instanceof Error ? error.message : String(error)).replace(/\\s+/g, ' ').slice(0, 500)\n }),\n )\n }\n }\n const from = normalize(p.url)\n const oc = { int: 0, ext: 0 }\n for (const l of p.outlinks ?? []) {\n const nofollow = (l.rel ?? '').split(/\\s+/).includes('nofollow')\n const to = normalize(l.href)\n const targetStatus = statusByUrl.get(to) ?? null\n await gzWrite(JSON.stringify({ from: p.url, to: l.href, anchor: l.anchor, rel: l.rel, internal: l.internal, nofollow, targetStatus }) + '\\n')\n streamedLinkEdges++\n if (analyzedLinkEdges >= MAX_ANALYZED_LINK_EDGES) {\n linkAnalysisTruncated = true\n continue\n }\n analyzedLinkEdges++\n if (l.internal) {\n oc.int++\n internalTotal++\n if (!inboundFrom.has(to)) inboundFrom.set(to, new Set())\n inboundFrom.get(to)!.add(from)\n if (l.anchor) {\n if (!anchorCounts.has(to)) anchorCounts.set(to, new Map())\n const ac = anchorCounts.get(to)!\n ac.set(l.anchor, (ac.get(l.anchor) ?? 0) + 1)\n }\n if (!nofollow && (statusByUrl.get(to) === 200 || !statusByUrl.has(to))) {\n if (!adjacency.has(from)) adjacency.set(from, new Set())\n adjacency.get(from)!.add(to)\n }\n if (targetStatus != null && targetStatus >= 400) {\n brokenInternal++\n brokenLinkPages.add(p.url)\n }\n } else {\n oc.ext++\n let domain = ''\n try { domain = registrableDomain(new URL(l.href).hostname) } catch { continue }\n if (!domain || domain === siteReg) continue\n externalTotal++\n const d = domMap.get(domain) ?? { links: 0, nofollow: 0, pages: new Set<string>() }\n d.links++\n if (nofollow) d.nofollow++\n d.pages.add(p.url)\n domMap.set(domain, d)\n }\n }\n outCounts.set(p.url, oc)\n }\n }\n const outputFinished = Promise.all([finished(linksOut), finished(schemaOut), finished(failuresOut)])\n gz.end()\n schemaOut.end()\n failuresOut.end()\n await outputFinished\n await Promise.all(imageDownloads)\n\n const depth = new Map<string, number>()\n const start = normalize(job.startUrl)\n depth.set(start, 0)\n const queue: string[] = [start]\n while (queue.length > 0) {\n const cur = queue.shift()!\n const d = depth.get(cur)!\n for (const next of adjacency.get(cur) ?? []) {\n if (!depth.has(next)) { depth.set(next, d + 1); queue.push(next) }\n }\n }\n\n const metrics = new Map<string, PageLinkMetrics>()\n for (const p of metas) {\n const key = normalize(p.url)\n const inbound = inboundFrom.get(key) ?? new Set()\n const ac = anchorCounts.get(key)\n const topAnchors = ac\n ? [...ac.entries()].sort((a, b) => b[1] - a[1]).slice(0, 3).map(e => e[0])\n : []\n const oc = outCounts.get(p.url) ?? { int: 0, ext: 0 }\n metrics.set(p.url, {\n url: p.url,\n inlinks: inbound.size,\n uniqueInlinks: inbound.size,\n outlinksInternal: oc.int,\n outlinksExternal: oc.ext,\n crawlDepth: depth.has(key) ? depth.get(key)! : null,\n orphan: inbound.size === 0 && key !== start,\n topAnchors,\n })\n }\n\n const issues = computeIssues(metas, metrics, brokenLinkPages)\n let reportMd = renderIssueReport(job.startUrl, metas, issues, metrics)\n const limits = extractJobLimitInfo(job)\n const crawlSummary = {\n jobId: job.id,\n startUrl: job.startUrl,\n status: job.successfulUrls === 0\n ? 'failed'\n : job.failedUrls > 0 || job.remainingUrls > 0 || limits.creditTruncated\n ? 'partial'\n : 'complete',\n ...limits,\n discovered: job.totalUrls,\n attempted: job.attemptedUrls,\n successful: job.successfulUrls,\n failed: job.failedUrls,\n remaining: job.remainingUrls,\n linkAnalysis: {\n truncated: linkAnalysisTruncated,\n analyzedEdges: analyzedLinkEdges,\n streamedEdges: streamedLinkEdges,\n edgeCap: MAX_ANALYZED_LINK_EDGES,\n },\n generatedAt: new Date().toISOString(),\n }\n reportMd = [\n `## Crawl delivery`,\n `- Discovered: ${crawlSummary.discovered}`,\n `- Attempted: ${crawlSummary.attempted}`,\n `- Successful: ${crawlSummary.successful}`,\n `- Failed: ${crawlSummary.failed}`,\n `- Remaining: ${crawlSummary.remaining}`,\n `- Requested page cap: ${limits.requestedMaxPages}`,\n `- Funded page cap: ${limits.effectiveMaxPages}`,\n `- Credit-truncated: ${limits.creditTruncated ? 'yes' : 'no'}`,\n `- Link analysis: ${analyzedLinkEdges}/${streamedLinkEdges} edges${linkAnalysisTruncated ? ` (capped at ${MAX_ANALYZED_LINK_EDGES})` : ''}`,\n '',\n reportMd,\n ].join('\\n')\n if (extras.imageAudit) reportMd += `\\n\\n${renderImageSection(extras.imageAudit)}`\n\n const metricValues = [...metrics.values()]\n const round = (n: number) => Math.round(n * 10) / 10\n const distribution = { zero: 0, oneToTwo: 0, threeToTen: 0, elevenPlus: 0 }\n let sumInlinks = 0\n let sumOutlinks = 0\n for (const m of metricValues) {\n sumInlinks += m.inlinks\n sumOutlinks += m.outlinksInternal + m.outlinksExternal\n if (m.inlinks === 0) distribution.zero++\n else if (m.inlinks <= 2) distribution.oneToTwo++\n else if (m.inlinks <= 10) distribution.threeToTen++\n else distribution.elevenPlus++\n }\n const externalDomains: ExtDomainRow[] = [...domMap.entries()]\n .map(([domain, d]) => ({ domain, links: d.links, nofollow: d.nofollow, pages: d.pages.size }))\n .sort((a, b) => b.links - a.links)\n const linkReport: LinkReport = {\n summary: {\n internal: {\n totalLinks: internalTotal,\n pages: metas.length,\n orphans: metricValues.filter(m => m.orphan).length,\n brokenInternal,\n avgInlinks: metas.length ? round(sumInlinks / metas.length) : 0,\n avgOutlinks: metas.length ? round(sumOutlinks / metas.length) : 0,\n distribution,\n topByInlinks: [...metricValues].sort((a, b) => b.inlinks - a.inlinks).slice(0, 20)\n .map(m => ({ url: m.url, inlinks: m.inlinks, outlinksInternal: m.outlinksInternal, outlinksExternal: m.outlinksExternal })),\n },\n external: {\n totalLinks: externalTotal,\n uniqueDomains: externalDomains.length,\n topDomains: externalDomains.slice(0, 20),\n },\n },\n externalDomains,\n }\n\n const pagesOut = createWriteStream(join(dir, 'pages.jsonl'))\n const pageExportById = new Map(pageExportEntries.map(entry => [entry.pageId, entry]))\n const captureMatrixOut = waybackTimeline\n ? createWriteStream(join(dir, 'capture-matrix.jsonl'))\n : null\n const capturedCells = new Set<string>()\n const captureCellKey = (month: string | null | undefined, url: string) => {\n let normalized = url\n try { normalized = new URL(url).href } catch { /** Keep the bounded stored value. */ }\n return `${month ?? ''}\\0${normalized}`\n }\n for await (const chunk of pageChunks(job.id)) {\n for (const page of chunk) {\n const publicFailure = page.extractionStatus === 'failed'\n ? publicizeExtractionFailure(page.failureCode, page.failureReason)\n : { failureCode: null, failureReason: null }\n const { bodyMarkdown: _body, schema: _schema, outlinks: _outlinks, contentRef: _contentRef, ...boundedPage } = page\n const m = metrics.get(page.url)\n const exported = page.pageId ? pageExportById.get(page.pageId) : undefined\n const row = {\n ...boundedPage,\n ...(page.extractionStatus === 'failed' ? publicFailure : {}),\n representations: exported ? {\n jsonPath: exported.jsonPath,\n htmlPath: exported.htmlPath,\n markdownPath: exported.markdownPath,\n jsonSha256: exported.jsonSha256,\n htmlSha256: exported.htmlSha256,\n markdownSha256: exported.markdownSha256,\n htmlBytes: exported.htmlBytes,\n markdownBytes: exported.markdownBytes,\n } : null,\n inlinks: m?.inlinks ?? 0,\n crawlDepth: m?.crawlDepth ?? null,\n orphan: m?.orphan ?? false,\n }\n if (!pagesOut.write(JSON.stringify(row) + '\\n')) await once(pagesOut, 'drain')\n if (captureMatrixOut) {\n const cellKey = captureCellKey(page.archiveRequestedMonth, page.originalUrl ?? page.url)\n capturedCells.add(cellKey)\n const captureRow = {\n requestedMonth: page.archiveRequestedMonth ?? null,\n captureTimestamp: page.archiveTimestamp ?? null,\n originalUrl: page.originalUrl ?? page.url,\n archivedUrl: page.archivedUrl ?? null,\n status: page.extractionStatus === 'successful' ? 'captured' : 'failed',\n httpStatus: page.status,\n contentHash: page.contentHash || null,\n wordCount: page.wordCount,\n failureCode: publicFailure.failureCode,\n failureReason: publicFailure.failureReason,\n }\n if (!captureMatrixOut.write(JSON.stringify(captureRow) + '\\n')) await once(captureMatrixOut, 'drain')\n }\n }\n }\n if (captureMatrixOut && waybackTimeline?.timeline?.urls) {\n const timeline = waybackTimeline.timeline\n const requestedUrls = timeline.urls!\n const months = (() => {\n if (timeline.months?.length) return [...new Set(timeline.months)].sort()\n if (!timeline.from || !timeline.to) return []\n const values: string[] = []\n const cursor = new Date(`${timeline.from}-01T00:00:00Z`)\n const end = new Date(`${timeline.to}-01T00:00:00Z`)\n while (cursor <= end && values.length < 60) {\n values.push(`${cursor.getUTCFullYear()}-${String(cursor.getUTCMonth() + 1).padStart(2, '0')}`)\n cursor.setUTCMonth(cursor.getUTCMonth() + (timeline.intervalMonths ?? 1))\n }\n return values\n })()\n for (const requestedMonth of months) {\n for (const originalUrl of requestedUrls) {\n if (capturedCells.has(captureCellKey(requestedMonth, originalUrl))) continue\n if (!captureMatrixOut.write(JSON.stringify({\n requestedMonth,\n captureTimestamp: null,\n originalUrl,\n archivedUrl: null,\n status: 'missing',\n httpStatus: null,\n contentHash: null,\n wordCount: 0,\n failureCode: 'wayback_capture_missing',\n failureReason: 'No successful HTML capture was available in the requested month.',\n }) + '\\n')) await once(captureMatrixOut, 'drain')\n }\n }\n }\n const pagesFinished = finished(pagesOut)\n const captureMatrixFinished = captureMatrixOut ? finished(captureMatrixOut) : Promise.resolve()\n pagesOut.end()\n captureMatrixOut?.end()\n await Promise.all([pagesFinished, captureMatrixFinished])\n\n if (captureRenderedDom) {\n writeFileSync(\n join(dir, 'rendered-dom', 'manifest.jsonl'),\n renderedDomManifest.map(row => JSON.stringify(row)).join('\\n'),\n )\n }\n\n if (semanticSimilarity) {\n const analysis = await analyzeSiteContentSimilarity(similarityPages, {\n threshold: Number(job.options.similarityThreshold ?? undefined),\n maxPairs: Number(job.options.similarityMaxPairs ?? undefined),\n embedTexts: extras.embedSimilarityTexts,\n })\n const tableRows = analysis.rows.map(similarityTableRow)\n const columns = tableRows.length > 0 ? Object.keys(tableRows[0]) : [\n 'source_url',\n 'source_title',\n 'target_url',\n 'target_title',\n 'similarity',\n 'similarity_percent',\n 'corpus_percentile',\n 'exact_content_duplicate',\n 'source_word_count',\n 'target_word_count',\n 'cluster_id',\n ]\n const csv = [\n columns.join(','),\n ...tableRows.map(row => columns.map(column => csvCell(row[column] ?? null)).join(',')),\n ].join('\\n') + '\\n'\n const { rows: _rows, clusters: _clusters, ...summary } = analysis\n writeFileSync(join(dir, 'similarity-table.csv'), csv)\n writeFileSync(join(dir, 'similarity.jsonl'), tableRows.map(row => JSON.stringify(row)).join('\\n'))\n writeFileSync(join(dir, 'similarity-table-schema.json'), JSON.stringify({\n tableNameSuggestion: `site_similarity_${new URL(job.startUrl).hostname.replace(/[^a-z0-9]+/gi, '_').replace(/^_+|_+$/g, '').toLowerCase()}`,\n defaultSort: [{ column: 'similarity', direction: 'desc' }],\n columns: {\n source_url: 'text',\n source_title: 'text',\n target_url: 'text',\n target_title: 'text',\n similarity: 'number',\n similarity_percent: 'number',\n corpus_percentile: 'number',\n exact_content_duplicate: 'boolean',\n source_word_count: 'integer',\n target_word_count: 'integer',\n cluster_id: 'text',\n },\n }, null, 2))\n writeFileSync(join(dir, 'similarity-summary.json'), JSON.stringify(summary, null, 2))\n writeFileSync(join(dir, 'content-clusters.json'), JSON.stringify(analysis.clusters, null, 2))\n reportMd += [\n '',\n '## Rendered content similarity',\n `- Compared pages: ${analysis.comparedPages}`,\n `- Raw cosine threshold: ${analysis.threshold}`,\n `- Corpus score distribution: min ${analysis.scoreDistribution.min ?? 'n/a'} / median ${analysis.scoreDistribution.median ?? 'n/a'} / p90 ${analysis.scoreDistribution.p90 ?? 'n/a'} / max ${analysis.scoreDistribution.max ?? 'n/a'}`,\n `- Qualifying pairs: ${analysis.qualifyingPairs}`,\n `- Returned table rows: ${analysis.returnedPairs}${analysis.pairsTruncated ? ' (capped)' : ''}`,\n `- Multi-page clusters: ${analysis.clusters.length}`,\n `- Embedding model: ${analysis.model} (${analysis.dimensions} dimensions)`,\n `- Corpus boilerplate removed: ${analysis.boilerplateRemoval.removedBlockSignatures} repeated block signatures / ${analysis.boilerplateRemoval.removedCharacters} characters`,\n `- Corpus SHA-256: ${analysis.corpusSha256}`,\n ].join('\\n')\n }\n\n writeFileSync(join(dir, 'report.md'), reportMd)\n writeFileSync(join(dir, 'crawl-summary.json'), JSON.stringify(crawlSummary, null, 2))\n writeFileSync(join(dir, 'images-manifest.jsonl'), imageManifest.map(record => JSON.stringify(record)).join('\\n'))\n writeFileSync(join(dir, 'manifest.json'), JSON.stringify({\n version: 'site-export.v1',\n jobId: job.id,\n startUrl: job.startUrl,\n generatedAt: crawlSummary.generatedAt,\n outputProfile: {\n json: true,\n html: true,\n markdown: true,\n imageManifest: true,\n imageBytes: downloadImages,\n },\n pages: [...pageExportEntries].sort((a, b) => a.pageId.localeCompare(b.pageId)),\n imagesManifestPath: 'images-manifest.jsonl',\n download: 'This ZIP is the complete human export. AI clients should use site_export_read and site_export_image.',\n }, null, 2))\n if (waybackTimeline) {\n writeFileSync(join(dir, 'wayback-manifest.json'), JSON.stringify({\n rootUrl: waybackTimeline.rootUrl ?? job.startUrl,\n requested: waybackTimeline.timeline ?? null,\n maxPagesPerSnapshot: waybackTimeline.maxPagesPerSnapshot ?? null,\n captureMatrix: 'capture-matrix.jsonl',\n }, null, 2))\n }\n writeFileSync(join(dir, 'issues.json'), JSON.stringify(issues, null, 2))\n writeFileSync(join(dir, 'link-metrics.jsonl'), metricValues.map(m => JSON.stringify(m)).join('\\n'))\n writeFileSync(join(dir, 'link-report.md'), renderLinkReport(linkReport))\n writeFileSync(join(dir, 'links-summary.json'), JSON.stringify(linkReport.summary, null, 2))\n writeFileSync(join(dir, 'external-domains.json'), JSON.stringify(linkReport.externalDomains, null, 2))\n if (extras.imageAudit) {\n writeFileSync(join(dir, 'images.jsonl'), extras.imageAudit.rows.map(r => JSON.stringify(r)).join('\\n'))\n writeFileSync(join(dir, 'images-summary.json'), JSON.stringify(extras.imageAudit.summary, null, 2))\n }\n if (extras.seoAudit) writeFileSync(join(dir, 'seo-audit.json'), JSON.stringify(extras.seoAudit, null, 2))\n if (extras.branding) writeFileSync(join(dir, 'branding.json'), JSON.stringify(extras.branding, null, 2))\n if (downloadImages) {\n writeFileSync(join(dir, 'images-download-summary.json'), JSON.stringify({\n queued: imagesQueued,\n downloaded: imagesQueued - imagesFailed,\n failed: imagesFailed,\n downloadedBytes: imageBytesDownloaded,\n perPageCap: MAX_IMAGES_PER_PAGE,\n perSiteCap: MAX_IMAGES_PER_SITE,\n perFileByteCap: MAX_IMAGE_BYTES,\n totalByteCap: MAX_SITE_IMAGE_BYTES,\n }, null, 2))\n }\n\n const artifactFiles: Array<{ name: string; type: string }> = [\n { name: 'manifest.json', type: 'application/json' },\n { name: 'images-manifest.jsonl', type: 'application/x-ndjson' },\n { name: 'report.md', type: 'text/markdown' },\n { name: 'crawl-summary.json', type: 'application/json' },\n { name: 'failures.jsonl', type: 'application/x-ndjson' },\n { name: 'schema.jsonl', type: 'application/x-ndjson' },\n { name: 'issues.json', type: 'application/json' },\n { name: 'pages.jsonl', type: 'application/x-ndjson' },\n { name: 'links.jsonl.gz', type: 'application/gzip' },\n { name: 'link-metrics.jsonl', type: 'application/x-ndjson' },\n { name: 'link-report.md', type: 'text/markdown' },\n { name: 'links-summary.json', type: 'application/json' },\n { name: 'external-domains.json', type: 'application/json' },\n ]\n if (captureRenderedDom) {\n artifactFiles.push({ name: 'rendered-dom/manifest.jsonl', type: 'application/x-ndjson' })\n for (const row of renderedDomManifest) artifactFiles.push({ name: row.path, type: 'text/plain' })\n }\n if (semanticSimilarity) {\n artifactFiles.push({ name: 'similarity-table.csv', type: 'text/csv' })\n artifactFiles.push({ name: 'similarity.jsonl', type: 'application/x-ndjson' })\n artifactFiles.push({ name: 'similarity-table-schema.json', type: 'application/json' })\n artifactFiles.push({ name: 'similarity-summary.json', type: 'application/json' })\n artifactFiles.push({ name: 'content-clusters.json', type: 'application/json' })\n }\n if (waybackTimeline) {\n artifactFiles.push({ name: 'wayback-manifest.json', type: 'application/json' })\n artifactFiles.push({ name: 'capture-matrix.jsonl', type: 'application/x-ndjson' })\n }\n if (extras.imageAudit) {\n artifactFiles.push({ name: 'images.jsonl', type: 'application/x-ndjson' })\n artifactFiles.push({ name: 'images-summary.json', type: 'application/json' })\n }\n if (extras.seoAudit) artifactFiles.push({ name: 'seo-audit.json', type: 'application/json' })\n if (extras.branding) artifactFiles.push({ name: 'branding.json', type: 'application/json' })\n if (downloadImages) artifactFiles.push({ name: 'images-download-summary.json', type: 'application/json' })\n\n const zip = new ZipFile()\n const artifactPromise = createSiteExtractBundleArtifactStream({\n ownerId: String(job.userId),\n jobId: job.id,\n // Artifact retention starts when this bundle is assembled, including a\n // later support re-finalization, rather than when the crawl was queued.\n createdAt: new Date(),\n content: zip.outputStream,\n })\n for (const f of artifactFiles) zip.addFile(join(dir, f.name), f.name)\n const orderedPageEntries = [...pageExportEntries].sort((a, b) => a.pageId.localeCompare(b.pageId))\n for (const entry of orderedPageEntries) if (entry.markdownPath) zip.addFile(join(dir, entry.markdownPath), entry.markdownPath)\n for (const entry of orderedPageEntries) if (entry.legacyMarkdownPath) zip.addFile(join(dir, entry.legacyMarkdownPath), entry.legacyMarkdownPath)\n for (const entry of orderedPageEntries) if (entry.htmlPath) zip.addFile(join(dir, entry.htmlPath), entry.htmlPath)\n for (const entry of orderedPageEntries) zip.addFile(join(dir, entry.jsonPath), entry.jsonPath)\n if (downloadImages && imagesQueued > imagesFailed) {\n const imagesDir = join(dir, 'images')\n for (const rel of readdirSync(imagesDir, { recursive: true }) as string[]) {\n const full = join(imagesDir, rel)\n if (statSync(full).isFile()) zip.addFile(full, `images/${rel.split('\\\\').join('/')}`)\n }\n }\n zip.end()\n return [await artifactPromise, ...imageArtifacts]\n } finally {\n rmSync(dir, { recursive: true, force: true })\n }\n}\n","import { createHash } from 'node:crypto'\nimport { commonsEmbedDim, commonsEmbedModel, embedCommonsTexts } from './commons-embeddings.js'\n\nexport const MAX_SIMILARITY_PAGES = 500\nexport const DEFAULT_SIMILARITY_THRESHOLD = 0.9\nexport const DEFAULT_SIMILARITY_MAX_PAIRS = 10_000\nexport const MAX_SIMILARITY_PAIRS = 50_000\n\nexport interface SimilarityPageInput {\n url: string\n title: string | null\n bodyMarkdown: string\n contentHash: string\n wordCount: number\n}\n\nexport interface SiteSimilarityRow {\n sourceUrl: string\n sourceTitle: string | null\n targetUrl: string\n targetTitle: string | null\n similarity: number\n similarityPercent: number\n corpusPercentile: number\n exactContentDuplicate: boolean\n sourceWordCount: number\n targetWordCount: number\n clusterId: string | null\n}\n\nexport interface SiteSimilarityCluster {\n clusterId: string\n pageCount: number\n urls: string[]\n}\n\nexport interface SiteSimilarityAnalysis {\n generatedAt: string\n provider: 'jina'\n model: string\n dimensions: number\n threshold: number\n requestedMaxPairs: number\n comparedPages: number\n possiblePairs: number\n qualifyingPairs: number\n returnedPairs: number\n pairsTruncated: boolean\n corpusSha256: string\n analysisSha256: string\n scoreDistribution: {\n min: number | null\n p25: number | null\n median: number | null\n p75: number | null\n p90: number | null\n max: number | null\n }\n boilerplateRemoval: {\n method: 'corpus_repeated_markdown_blocks'\n minimumPageCount: number | null\n removedBlockSignatures: number\n removedCharacters: number\n }\n rows: SiteSimilarityRow[]\n clusters: SiteSimilarityCluster[]\n}\n\nexport type EmbedSimilarityTexts = (texts: string[]) => Promise<number[][]>\n\nfunction round(value: number, places: number): number {\n const scale = 10 ** places\n return Math.round(value * scale) / scale\n}\n\nexport function cosineSimilarity(a: number[], b: number[]): number {\n if (a.length === 0 || a.length !== b.length) throw new Error('Similarity vectors must have the same non-zero dimension.')\n let dot = 0\n let normA = 0\n let normB = 0\n for (let index = 0; index < a.length; index++) {\n dot += a[index] * b[index]\n normA += a[index] * a[index]\n normB += b[index] * b[index]\n }\n if (normA === 0 || normB === 0) return 0\n return Math.max(-1, Math.min(1, dot / (Math.sqrt(normA) * Math.sqrt(normB))))\n}\n\nfunction corpusHash(pages: SimilarityPageInput[]): string {\n const digest = createHash('sha256')\n for (const page of [...pages].sort((a, b) => a.url.localeCompare(b.url))) {\n digest.update(page.url)\n digest.update('\\0')\n digest.update(page.contentHash)\n digest.update('\\0')\n }\n return digest.digest('hex')\n}\n\nfunction markdownBlockSignature(block: string): string | null {\n const normalized = block\n .replace(/!\\[([^\\]]*)\\]\\([^)]*\\)/g, '$1')\n .replace(/\\[([^\\]]+)\\]\\([^)]*\\)/g, '$1')\n .replace(/https?:\\/\\/\\S+/gi, ' ')\n .replace(/&(?:amp|nbsp|quot|#39);/gi, ' ')\n .replace(/[#>*_`~|\\\\-]+/g, ' ')\n .replace(/[^\\p{L}\\p{N}]+/gu, ' ')\n .replace(/\\s+/g, ' ')\n .trim()\n .toLowerCase()\n return normalized.length >= 12 ? normalized : null\n}\n\nfunction prepareEmbeddingTexts(pages: SimilarityPageInput[]): {\n texts: string[]\n minimumPageCount: number | null\n removedBlockSignatures: number\n removedCharacters: number\n} {\n const blocksByPage = pages.map(page => page.bodyMarkdown.split(/\\n{2,}/).map(block => block.trim()).filter(Boolean))\n const minimumPageCount = pages.length >= 4 ? Math.max(3, Math.ceil(pages.length * 0.5)) : null\n const pageFrequency = new Map<string, number>()\n for (const blocks of blocksByPage) {\n const pageSignatures = new Set(blocks.map(markdownBlockSignature).filter((value): value is string => Boolean(value)))\n for (const signature of pageSignatures) pageFrequency.set(signature, (pageFrequency.get(signature) ?? 0) + 1)\n }\n const repeated = new Set<string>()\n if (minimumPageCount != null) {\n for (const [signature, count] of pageFrequency) {\n if (count >= minimumPageCount) repeated.add(signature)\n }\n }\n let removedCharacters = 0\n const texts = pages.map((page, pageIndex) => {\n const kept: string[] = []\n for (const block of blocksByPage[pageIndex]) {\n const signature = markdownBlockSignature(block)\n if (signature && repeated.has(signature)) {\n removedCharacters += block.length\n continue\n }\n kept.push(block)\n }\n const cleaned = kept.join('\\n\\n').trim()\n const content = cleaned.length >= 60 ? cleaned : page.bodyMarkdown\n return `${page.title?.trim() || 'Untitled page'}\\n\\n${content}`\n })\n return {\n texts,\n minimumPageCount,\n removedBlockSignatures: repeated.size,\n removedCharacters,\n }\n}\n\nclass DisjointSet {\n private readonly parent: number[]\n\n constructor(size: number) {\n this.parent = Array.from({ length: size }, (_, index) => index)\n }\n\n find(value: number): number {\n const parent = this.parent[value]\n if (parent !== value) this.parent[value] = this.find(parent)\n return this.parent[value]\n }\n\n union(a: number, b: number): void {\n const rootA = this.find(a)\n const rootB = this.find(b)\n if (rootA !== rootB) this.parent[rootB] = rootA\n }\n}\n\nexport async function analyzeSiteContentSimilarity(\n pages: SimilarityPageInput[],\n options: {\n threshold?: number\n maxPairs?: number\n embedTexts?: EmbedSimilarityTexts\n model?: string\n dimensions?: number\n } = {},\n): Promise<SiteSimilarityAnalysis> {\n const eligible = pages\n .filter(page => page.bodyMarkdown.trim().length > 0)\n .slice(0, MAX_SIMILARITY_PAGES)\n const requestedThreshold = Number.isFinite(options.threshold) ? options.threshold! : DEFAULT_SIMILARITY_THRESHOLD\n const requestedMaxPairs = Number.isFinite(options.maxPairs) ? options.maxPairs! : DEFAULT_SIMILARITY_MAX_PAIRS\n const threshold = Math.max(0, Math.min(1, requestedThreshold))\n const maxPairs = Math.max(1, Math.min(MAX_SIMILARITY_PAIRS, Math.floor(requestedMaxPairs)))\n const model = options.model ?? commonsEmbedModel()\n const dimensions = options.dimensions ?? commonsEmbedDim()\n const embedTexts = options.embedTexts ?? embedCommonsTexts\n const prepared = prepareEmbeddingTexts(eligible)\n const uniqueTexts: string[] = []\n const textIndexByHash = new Map<string, number>()\n const pageTextIndexes: number[] = []\n\n for (const [pageIndex, page] of eligible.entries()) {\n const key = page.contentHash || createHash('sha256').update(page.bodyMarkdown).digest('hex')\n let textIndex = textIndexByHash.get(key)\n if (textIndex == null) {\n textIndex = uniqueTexts.length\n textIndexByHash.set(key, textIndex)\n uniqueTexts.push(prepared.texts[pageIndex])\n }\n pageTextIndexes.push(textIndex)\n }\n\n const uniqueVectors: number[][] = []\n for (let offset = 0; offset < uniqueTexts.length; offset += 64) {\n uniqueVectors.push(...await embedTexts(uniqueTexts.slice(offset, offset + 64)))\n }\n if (uniqueVectors.length !== uniqueTexts.length) {\n throw new Error(`Embedding provider returned ${uniqueVectors.length} vectors for ${uniqueTexts.length} unique page bodies.`)\n }\n\n const vectors = pageTextIndexes.map(index => uniqueVectors[index])\n const sets = new DisjointSet(eligible.length)\n const allScores: number[] = []\n const qualifying: Array<{ source: number; target: number; score: number }> = []\n for (let source = 0; source < eligible.length; source++) {\n for (let target = source + 1; target < eligible.length; target++) {\n const score = cosineSimilarity(vectors[source], vectors[target])\n allScores.push(score)\n if (score < threshold) continue\n qualifying.push({ source, target, score })\n sets.union(source, target)\n }\n }\n qualifying.sort((a, b) => b.score - a.score\n || eligible[a.source].url.localeCompare(eligible[b.source].url)\n || eligible[a.target].url.localeCompare(eligible[b.target].url))\n const sortedScores = [...allScores].sort((a, b) => a - b)\n const quantile = (value: number): number | null => {\n if (!sortedScores.length) return null\n return round(sortedScores[Math.floor((sortedScores.length - 1) * value)], 6)\n }\n\n const membersByRoot = new Map<number, number[]>()\n for (let index = 0; index < eligible.length; index++) {\n const root = sets.find(index)\n const members = membersByRoot.get(root) ?? []\n members.push(index)\n membersByRoot.set(root, members)\n }\n const clusterIdByPage = new Map<number, string>()\n const clusters = [...membersByRoot.values()]\n .filter(members => members.length > 1)\n .sort((a, b) => b.length - a.length || eligible[a[0]].url.localeCompare(eligible[b[0]].url))\n .map((members, index) => {\n const clusterId = `cluster-${String(index + 1).padStart(3, '0')}`\n for (const member of members) clusterIdByPage.set(member, clusterId)\n return {\n clusterId,\n pageCount: members.length,\n urls: members.map(member => eligible[member].url).sort(),\n }\n })\n\n const rows = qualifying.slice(0, maxPairs).map((pair, pairIndex) => {\n const source = eligible[pair.source]\n const target = eligible[pair.target]\n const similarity = round(pair.score, 6)\n return {\n sourceUrl: source.url,\n sourceTitle: source.title,\n targetUrl: target.url,\n targetTitle: target.title,\n similarity,\n similarityPercent: round(similarity * 100, 2),\n corpusPercentile: sortedScores.length <= 1\n ? 100\n : round((1 - pairIndex / (sortedScores.length - 1)) * 100, 2),\n exactContentDuplicate: Boolean(source.contentHash && source.contentHash === target.contentHash),\n sourceWordCount: source.wordCount,\n targetWordCount: target.wordCount,\n clusterId: clusterIdByPage.get(pair.source) ?? null,\n }\n })\n const corpusSha256 = corpusHash(eligible)\n const analysisSha256 = createHash('sha256')\n .update(JSON.stringify({\n corpusSha256,\n model,\n dimensions,\n threshold,\n maxPairs,\n boilerplateRemoval: {\n method: 'corpus_repeated_markdown_blocks',\n minimumPageCount: prepared.minimumPageCount,\n removedBlockSignatures: prepared.removedBlockSignatures,\n },\n }))\n .digest('hex')\n\n return {\n generatedAt: new Date().toISOString(),\n provider: 'jina',\n model,\n dimensions,\n threshold,\n requestedMaxPairs: maxPairs,\n comparedPages: eligible.length,\n possiblePairs: eligible.length * Math.max(0, eligible.length - 1) / 2,\n qualifyingPairs: qualifying.length,\n returnedPairs: rows.length,\n pairsTruncated: qualifying.length > rows.length,\n corpusSha256,\n analysisSha256,\n scoreDistribution: {\n min: quantile(0),\n p25: quantile(0.25),\n median: quantile(0.5),\n p75: quantile(0.75),\n p90: quantile(0.9),\n max: quantile(1),\n },\n boilerplateRemoval: {\n method: 'corpus_repeated_markdown_blocks',\n minimumPageCount: prepared.minimumPageCount,\n removedBlockSignatures: prepared.removedBlockSignatures,\n removedCharacters: prepared.removedCharacters,\n },\n rows,\n clusters,\n }\n}\n"],"mappings":"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","names":["createHash","createHash","round"]}
|