@qzsy/rag-sdk
v0.2.16
Published
TypeScript SDK for ragflow-ingestion integration API (/api/integration/v1)
Readme
@qzsy/rag-sdk
TypeScript/JavaScript SDK for the ragflow-ingestion integration machine API (/api/integration/v1/*).
Business systems use App Key + Biz User (+ Tenant / End User) to upload corpora, query jobs, list ingested documents, and run retrieval tests.
Install
npm install @qzsy/[email protected]Requires Node.js 22+ (monorepo) or modern browser for isomorphic fetch.
Quick start
import { RagflowIngestionClient } from '@qzsy/rag-sdk';
const client = new RagflowIngestionClient({
baseUrl: 'https://your-ingestion-host:28080',
appKey: 'app_xxx',
bizUserId: 'biz-user-1',
tenantKey: 'ten_xxx', // multi-tenant only
endUserId: 'student-001', // required for upload / retrieval / documents
});
const app = await client.getApp();
console.log(app.mode, app.dataset_id);
const job = await client.upload({
files: [
{ data: await readFile('sample.pdf'), filename: 'sample.pdf' },
],
});
console.log(job.id);(Node 示例:import { readFile } from 'node:fs/promises'。浏览器可用 File / Blob。)
Browser upload with upload token
Issue a short-lived token on your server (holds App Key), then upload from the browser without exposing keys:
// Server
const { upload_token } = await client.createUploadToken({ end_user_id: 'student-001' });
// Browser (token only)
await client.upload({
uploadToken: upload_token,
files: [{ data: fileBlob, filename: file.name }],
});Upload token authorizes POST /ingest/upload and POST /ingest/album-upload (path-semantic image collections). Progress, dedup, and jobs still require App Key on the server.
Supported file formats
Server allowlist (also exported from the SDK for client-side validation):
import {
isSupportedFilename,
isAudioFilename,
isWPSFilename,
filterSupportedFilenames,
SUPPORTED_FILE_HINT,
} from '@qzsy/rag-sdk';
if (!isSupportedFilename(file.name)) {
throw new Error(`unsupported: ${file.name} (${SUPPORTED_FILE_HINT})`);
}
// Audio: .mp3 / .wav / .aac / .flac / .ogg — passthrough to RAGFlow ASR (chunk_method=audio)
if (isAudioFilename(file.name)) {
// ensure RAGFlow tenant has Speech2Text (ASR) configured
}
// WPS Writer: .wps / .wpt — server converts via WPS_TO_PDF_URL (not LibreOffice).
// .et / .dps stay rejected.
if (isWPSFilename(file.name)) {
// upload as usual; conversion happens on the server
}Documents: PDF, Word, PPT, WPS Writer (.wps/.wpt), Markdown, TXT, spreadsheets (.xlsx/.xls/.csv), images, audio (see above). Retrieval returns transcribed text chunks like other documents.
Image albums (title + description + S3 members) — v0.2.12+
成员图片直存 S3。可检索部分是本地图集账本的 title + description + 路径。语义召回用 retrieve_mode: 'album'(服务端 LLM 读目录挑选,不进 RAGFlow)。修改某一个图集的标题/描述用 patchAlbum。
const result = await client.albumUpload({
files: [{ data: blobA, filename: '0801.jpg', relativePath: '调研/智算中心/2024/0801.jpg' }],
pathKeywords: '调研,智算中心,2024',
title: '智算中心图集',
description: '园区航拍与平面图',
});
await client.patchAlbum(result.collection_id, {
title: '党建活动计划审批流程',
description: '更新后的图集说明',
});
const hits = await client.ragRetrieve({
question: '党建活动计划审批流程',
retrieve_mode: 'album',
top_k: 5,
batch_size: 200,
evaluate: false,
});
// or: client.ragRetrieveAlbum({ question: '党建活动计划审批流程', top_k: 5, batch_size: 200 })路径目录仍可用 getAlbumCatalog() / ragRetrieveAlbum({ virtual_path })。
// Upload (pathKeywords required on first batch)
const result = await client.albumUpload({
files: [
{
data: blobA,
filename: '0801_143022.jpg',
relativePath: '调研/智算中心/2024/0801_143022.jpg',
},
{
data: blobB,
filename: '封面.jpg',
relativePath: '调研/智算中心/封面.jpg',
},
],
pathKeywords: '调研,智算中心,2024',
// optional: collectionPath: '调研/智算中心/2024',
});
console.log(result.collection_id, result.collection_path, result.s3_prefix);
// Agent catalog: runtime file at /{end_user_id}/_runtime/album-catalog.txt
const catalogText = await client.getAlbumCatalog();
// each line: /eu-1/调研/智算中心/2024|15
// Recall by virtual_path (same string as catalog line prefix)
const hits = await client.ragRetrieveAlbum({
virtual_path: '/eu-1/调研/智算中心/2024',
top_k: 5,
});
for (const col of hits.collections) {
console.log(col.virtual_path, col.member_count);
}
// Or read catalog via VFS runtime document API
const docId = 'albcat_...'; // from fs/tree under _runtime/album-catalog.txt
const sameCatalog = await client.getRuntimeDocumentContent(docId);
// Browse member images
const tree = await client.fsTree({ path: hits.collections[0]?.virtual_path ?? '/' });Requires server S3_* + ORIGIN_BUCKET. Console admin CRUD: /albums. Integration: patchAlbum.
API surface (v0.2.12)
Allowlist: .wps / .wpt via isSupportedFilename / isWPSFilename. Server converts with WPS_TO_PDF_URL.
API surface (v0.2.9)
Album retrieval no longer accepts question; use virtual_path or path_keywords. See CHANGELOG 0.2.9 for migration from 0.2.8.
API surface (v0.2.8)
Retrieval request body supports tag_prefilter and prefer_visual (see API doc). On invalid parameters the server returns 400 with structured validation_errors:
import { RagflowIngestionClient, IngestionApiError } from '@qzsy/rag-sdk';
try {
await client.ragRetrieve({
question: '陈通汕 智算 调研 图片',
tag_prefilter: 'strictly', // typo → 400
});
} catch (e) {
if (e instanceof IngestionApiError && e.hasValidationErrors()) {
for (const issue of e.validationErrors) {
console.log(issue.field, issue.code, issue.allowed, issue.got);
}
// Agent: fix tag_prefilter to one of allowed values and retry
}
}API surface (v0.2.5)
Full coverage of /api/integration/v1/* machine routes (see docs/ragflow-ingestion_api.md route table).
| Group | Methods |
|-------|---------|
| App / tenant | getApp, listTenants, createTenant, resolve |
| Shared library | sharedJoin, sharedMembers |
| Upload | createUploadToken, upload, albumUpload, getUploadStatus, startUploadDedupCheck, getUploadDedupCheck |
| Album | albumUpload, patchAlbum, getAlbumCatalog, getRuntimeDocumentContent, ragRetrieveAlbum |
| Archive | presignArchive, archiveIngestFromObject |
| Jobs | listJobs, getJob, cancelJob |
| Documents | listDocuments, listUploads, getDocument, getDocumentDownloads |
| Virtual FS | fsTree(limit/offset 文档分页), fsSearch(全局搜索,v0.2.5+), fsCreateFolder, fsUpdateFolder, fsDeleteFolder, fsGetDocument, fsUpdateDocument, fsDeleteDocument |
| Retrieval / RAG | retrievalTest, ragRetrieve, ragRetrieveAlbum, getRagChunk, getChunkImage, getRagPageImage |
// fs/tree pagination (maps to ?limit=&offset=)
const page = await client.fsTree({ path: '/', enrich: false, limit: 50, offset: 0 });
console.log(page.total_documents, page.documents.length);
// fs/search — global file lookup across all virtual folders
const hits = await client.fsSearch({ q: '通汕', limit: 50 });
console.log(hits.total, hits.documents.map((d) => d.path));API surface (v0.1.0 legacy)
v0.1.0 covered the upload / jobs / documents / retrieval core; v0.2.0 adds shared join, dedup-check, cancel, fs/*, and image/chunk helpers.
Full HTTP contract: see docs/ragflow-ingestion_api.md in the ragflow-ingestion repository.
Errors
Failed responses throw IngestionApiError with status, message, and optional body.
body.validation_errors— machine-readable field issues (e.g. invalidtag_prefilterenum). Useerr.validationErrors/err.hasValidationErrors().- Invalid
tag_prefiltervalues are not silently coerced toautoon the server (since 2026-08-08); fix and retry.
Publishing (maintainers)
Global registry may point to a mirror; this package publishes to registry.npmjs.org.
- Create an npm Access Token (type Automation or Publish) with rights on
@qzsy. - Set the token (do not commit it):
$env:NPM_TOKEN = "npm_xxxxxxxx"- Publish from repo root (auto-picks Node 22 if pnpm is bound to an older Node):
$env:NPM_TOKEN = "npm_xxxxxxxx"
pnpm publish:sdk
# preview only: pnpm publish:sdk -- --dry-runIf pnpm still complains about Node version, run directly:
node scripts/run-node22.mjs scripts/publish-sdk.mjsScript: scripts/publish-sdk.mjs (checks token, npm whoami, build, npm publish to registry.npmjs.org).
License
MIT
