cencori 1.3.0 → 1.4.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/README.md CHANGED
@@ -130,6 +130,46 @@ const response = await cencori.ai.embeddings({
130
130
  console.log(response.embeddings[0]); // [0.1, 0.2, ...]
131
131
  ```
132
132
 
133
+ ### Vision (Image Understanding)
134
+
135
+ Analyze, describe, OCR, and classify images. Routes across OpenAI, Anthropic, and Google vision-capable models.
136
+
137
+ ```typescript
138
+ // General analysis with a custom prompt
139
+ const result = await cencori.vision.analyze({
140
+ image: { url: 'https://example.com/photo.jpg' },
141
+ prompt: 'What breed of dog is this?'
142
+ });
143
+
144
+ // OCR from a local file
145
+ import fs from 'node:fs';
146
+ const buf = fs.readFileSync('receipt.png');
147
+ const { text } = await cencori.vision.ocr({
148
+ image: { base64: buf.toString('base64'), mimeType: 'image/png' }
149
+ });
150
+
151
+ // Structured classification
152
+ const { classification } = await cencori.vision.classify({
153
+ image: { url: 'https://example.com/product.jpg' }
154
+ });
155
+ // classification: { primary_category, tags, objects, safe_for_work, ... }
156
+ ```
157
+
158
+ Drop-in React uploader for your own product (`cencori/react`):
159
+
160
+ ```tsx
161
+ import { VisionUploader } from 'cencori/react';
162
+
163
+ <VisionUploader
164
+ endpoint="https://cencori.com/api/ai/vision"
165
+ apiKey={process.env.NEXT_PUBLIC_CENCORI_KEY}
166
+ task="describe"
167
+ onResult={(r) => console.log(r)}
168
+ />
169
+ ```
170
+
171
+ Full API in [docs](https://cencori.com/docs/ai/endpoints/vision).
172
+
133
173
  ### Image Generation
134
174
 
135
175
  Generate images from text prompts using multiple providers:
@@ -0,0 +1,94 @@
1
+ import { C as CencoriConfig } from '../types-kh1whvNH.mjs';
2
+
3
+ /**
4
+ * Documents API — extract text from PDFs and images, summarize, and query.
5
+ *
6
+ * @example
7
+ * const { text, pageCount } = await cencori.documents.extract({
8
+ * document: { url: 'https://example.com/contract.pdf' },
9
+ * });
10
+ *
11
+ * @example
12
+ * const { summary } = await cencori.documents.summarize({
13
+ * document: { base64, mimeType: 'application/pdf' },
14
+ * });
15
+ *
16
+ * @example
17
+ * const { answer } = await cencori.documents.query({
18
+ * document: { url: 'https://example.com/report.pdf' },
19
+ * question: 'What is the total revenue for Q3?',
20
+ * });
21
+ */
22
+
23
+ type DocumentExtractMethod = 'pdf_text' | 'vision_ocr';
24
+ type DocumentKind = 'pdf' | 'image';
25
+ interface DocumentInput {
26
+ url?: string;
27
+ base64?: string;
28
+ mimeType?: string;
29
+ filename?: string;
30
+ }
31
+ interface DocumentRequest {
32
+ document: DocumentInput;
33
+ prompt?: string;
34
+ model?: string;
35
+ maxTokens?: number;
36
+ temperature?: number;
37
+ }
38
+ interface DocumentQueryRequest extends DocumentRequest {
39
+ question: string;
40
+ }
41
+ interface DocumentUsage {
42
+ promptTokens: number;
43
+ completionTokens: number;
44
+ totalTokens: number;
45
+ }
46
+ interface DocumentCost {
47
+ providerCostUsd: number;
48
+ cencoriChargeUsd: number;
49
+ markupPercentage: number;
50
+ }
51
+ interface DocumentExtractResult {
52
+ text: string;
53
+ pageCount: number;
54
+ kind: DocumentKind;
55
+ method: DocumentExtractMethod;
56
+ model?: string;
57
+ provider?: string;
58
+ metadata?: Record<string, unknown>;
59
+ usage?: DocumentUsage;
60
+ cost?: DocumentCost;
61
+ }
62
+ interface DocumentSummarizeResult {
63
+ summary: string;
64
+ text: string;
65
+ pageCount: number;
66
+ model: string;
67
+ provider: string;
68
+ extractMethod: DocumentExtractMethod;
69
+ usage: DocumentUsage;
70
+ cost: DocumentCost;
71
+ }
72
+ interface DocumentQueryResult {
73
+ answer: string;
74
+ question: string;
75
+ pageCount: number;
76
+ model: string;
77
+ provider: string;
78
+ extractMethod: DocumentExtractMethod;
79
+ usage: DocumentUsage;
80
+ cost: DocumentCost;
81
+ }
82
+ declare class DocumentsNamespace {
83
+ private config;
84
+ constructor(config: Required<CencoriConfig>);
85
+ /** Extract text from a PDF (native, no LLM) or image (via Vision OCR). */
86
+ extract(request: DocumentRequest): Promise<DocumentExtractResult>;
87
+ /** Extract then summarize the document with a chat model. */
88
+ summarize(request: DocumentRequest): Promise<DocumentSummarizeResult>;
89
+ /** Extract then answer a question about the document. */
90
+ query(request: DocumentQueryRequest): Promise<DocumentQueryResult>;
91
+ private post;
92
+ }
93
+
94
+ export { type DocumentCost, type DocumentExtractMethod, type DocumentExtractResult, type DocumentInput, type DocumentKind, type DocumentQueryRequest, type DocumentQueryResult, type DocumentRequest, type DocumentSummarizeResult, type DocumentUsage, DocumentsNamespace };
@@ -0,0 +1,94 @@
1
+ import { C as CencoriConfig } from '../types-kh1whvNH.js';
2
+
3
+ /**
4
+ * Documents API — extract text from PDFs and images, summarize, and query.
5
+ *
6
+ * @example
7
+ * const { text, pageCount } = await cencori.documents.extract({
8
+ * document: { url: 'https://example.com/contract.pdf' },
9
+ * });
10
+ *
11
+ * @example
12
+ * const { summary } = await cencori.documents.summarize({
13
+ * document: { base64, mimeType: 'application/pdf' },
14
+ * });
15
+ *
16
+ * @example
17
+ * const { answer } = await cencori.documents.query({
18
+ * document: { url: 'https://example.com/report.pdf' },
19
+ * question: 'What is the total revenue for Q3?',
20
+ * });
21
+ */
22
+
23
+ type DocumentExtractMethod = 'pdf_text' | 'vision_ocr';
24
+ type DocumentKind = 'pdf' | 'image';
25
+ interface DocumentInput {
26
+ url?: string;
27
+ base64?: string;
28
+ mimeType?: string;
29
+ filename?: string;
30
+ }
31
+ interface DocumentRequest {
32
+ document: DocumentInput;
33
+ prompt?: string;
34
+ model?: string;
35
+ maxTokens?: number;
36
+ temperature?: number;
37
+ }
38
+ interface DocumentQueryRequest extends DocumentRequest {
39
+ question: string;
40
+ }
41
+ interface DocumentUsage {
42
+ promptTokens: number;
43
+ completionTokens: number;
44
+ totalTokens: number;
45
+ }
46
+ interface DocumentCost {
47
+ providerCostUsd: number;
48
+ cencoriChargeUsd: number;
49
+ markupPercentage: number;
50
+ }
51
+ interface DocumentExtractResult {
52
+ text: string;
53
+ pageCount: number;
54
+ kind: DocumentKind;
55
+ method: DocumentExtractMethod;
56
+ model?: string;
57
+ provider?: string;
58
+ metadata?: Record<string, unknown>;
59
+ usage?: DocumentUsage;
60
+ cost?: DocumentCost;
61
+ }
62
+ interface DocumentSummarizeResult {
63
+ summary: string;
64
+ text: string;
65
+ pageCount: number;
66
+ model: string;
67
+ provider: string;
68
+ extractMethod: DocumentExtractMethod;
69
+ usage: DocumentUsage;
70
+ cost: DocumentCost;
71
+ }
72
+ interface DocumentQueryResult {
73
+ answer: string;
74
+ question: string;
75
+ pageCount: number;
76
+ model: string;
77
+ provider: string;
78
+ extractMethod: DocumentExtractMethod;
79
+ usage: DocumentUsage;
80
+ cost: DocumentCost;
81
+ }
82
+ declare class DocumentsNamespace {
83
+ private config;
84
+ constructor(config: Required<CencoriConfig>);
85
+ /** Extract text from a PDF (native, no LLM) or image (via Vision OCR). */
86
+ extract(request: DocumentRequest): Promise<DocumentExtractResult>;
87
+ /** Extract then summarize the document with a chat model. */
88
+ summarize(request: DocumentRequest): Promise<DocumentSummarizeResult>;
89
+ /** Extract then answer a question about the document. */
90
+ query(request: DocumentQueryRequest): Promise<DocumentQueryResult>;
91
+ private post;
92
+ }
93
+
94
+ export { type DocumentCost, type DocumentExtractMethod, type DocumentExtractResult, type DocumentInput, type DocumentKind, type DocumentQueryRequest, type DocumentQueryResult, type DocumentRequest, type DocumentSummarizeResult, type DocumentUsage, DocumentsNamespace };
@@ -0,0 +1,88 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/documents/index.ts
21
+ var documents_exports = {};
22
+ __export(documents_exports, {
23
+ DocumentsNamespace: () => DocumentsNamespace
24
+ });
25
+ module.exports = __toCommonJS(documents_exports);
26
+ function toBody(request, extra = {}) {
27
+ const body = {
28
+ prompt: request.prompt,
29
+ model: request.model,
30
+ max_tokens: request.maxTokens,
31
+ temperature: request.temperature,
32
+ ...extra
33
+ };
34
+ if (request.document.url) {
35
+ body.document_url = request.document.url;
36
+ } else if (request.document.base64) {
37
+ body.document_base64 = request.document.base64;
38
+ body.mime_type = request.document.mimeType;
39
+ body.filename = request.document.filename;
40
+ } else {
41
+ throw new Error("documents request requires document.url or document.base64");
42
+ }
43
+ return body;
44
+ }
45
+ var DocumentsNamespace = class {
46
+ constructor(config) {
47
+ this.config = config;
48
+ }
49
+ /** Extract text from a PDF (native, no LLM) or image (via Vision OCR). */
50
+ async extract(request) {
51
+ return this.post("/api/ai/documents/extract", toBody(request));
52
+ }
53
+ /** Extract then summarize the document with a chat model. */
54
+ async summarize(request) {
55
+ return this.post("/api/ai/documents/summarize", toBody(request));
56
+ }
57
+ /** Extract then answer a question about the document. */
58
+ async query(request) {
59
+ if (!request.question) throw new Error("documents.query requires a `question`");
60
+ return this.post("/api/ai/documents/query", toBody(request, { question: request.question }));
61
+ }
62
+ async post(path, body) {
63
+ const response = await fetch(`${this.config.baseUrl}${path}`, {
64
+ method: "POST",
65
+ headers: {
66
+ "CENCORI_API_KEY": this.config.apiKey,
67
+ "Content-Type": "application/json",
68
+ ...this.config.headers
69
+ },
70
+ body: JSON.stringify(body)
71
+ });
72
+ const data = await response.json();
73
+ if (!response.ok) {
74
+ const message = data && typeof data === "object" && "message" in data && typeof data.message === "string" ? data.message : `Documents request failed with status ${response.status}`;
75
+ const code = data && typeof data === "object" && "error" in data && typeof data.error === "string" ? data.error : "request_failed";
76
+ const err = new Error(message);
77
+ err.code = code;
78
+ err.details = data;
79
+ throw err;
80
+ }
81
+ return data;
82
+ }
83
+ };
84
+ // Annotate the CommonJS export names for ESM import in node:
85
+ 0 && (module.exports = {
86
+ DocumentsNamespace
87
+ });
88
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/documents/index.ts"],"sourcesContent":["/**\n * Documents API — extract text from PDFs and images, summarize, and query.\n *\n * @example\n * const { text, pageCount } = await cencori.documents.extract({\n * document: { url: 'https://example.com/contract.pdf' },\n * });\n *\n * @example\n * const { summary } = await cencori.documents.summarize({\n * document: { base64, mimeType: 'application/pdf' },\n * });\n *\n * @example\n * const { answer } = await cencori.documents.query({\n * document: { url: 'https://example.com/report.pdf' },\n * question: 'What is the total revenue for Q3?',\n * });\n */\n\nimport type { CencoriConfig } from '../types';\n\nexport type DocumentExtractMethod = 'pdf_text' | 'vision_ocr';\nexport type DocumentKind = 'pdf' | 'image';\n\nexport interface DocumentInput {\n url?: string;\n base64?: string;\n mimeType?: string;\n filename?: string;\n}\n\nexport interface DocumentRequest {\n document: DocumentInput;\n prompt?: string;\n model?: string;\n maxTokens?: number;\n temperature?: number;\n}\n\nexport interface DocumentQueryRequest extends DocumentRequest {\n question: string;\n}\n\nexport interface DocumentUsage {\n promptTokens: number;\n completionTokens: number;\n totalTokens: number;\n}\n\nexport interface DocumentCost {\n providerCostUsd: number;\n cencoriChargeUsd: number;\n markupPercentage: number;\n}\n\nexport interface DocumentExtractResult {\n text: string;\n pageCount: number;\n kind: DocumentKind;\n method: DocumentExtractMethod;\n model?: string;\n provider?: string;\n metadata?: Record<string, unknown>;\n usage?: DocumentUsage;\n cost?: DocumentCost;\n}\n\nexport interface DocumentSummarizeResult {\n summary: string;\n text: string;\n pageCount: number;\n model: string;\n provider: string;\n extractMethod: DocumentExtractMethod;\n usage: DocumentUsage;\n cost: DocumentCost;\n}\n\nexport interface DocumentQueryResult {\n answer: string;\n question: string;\n pageCount: number;\n model: string;\n provider: string;\n extractMethod: DocumentExtractMethod;\n usage: DocumentUsage;\n cost: DocumentCost;\n}\n\ninterface JsonBody {\n document_url?: string;\n document_base64?: string;\n mime_type?: string;\n filename?: string;\n prompt?: string;\n model?: string;\n max_tokens?: number;\n temperature?: number;\n question?: string;\n}\n\nfunction toBody(request: DocumentRequest, extra: Partial<JsonBody> = {}): JsonBody {\n const body: JsonBody = {\n prompt: request.prompt,\n model: request.model,\n max_tokens: request.maxTokens,\n temperature: request.temperature,\n ...extra,\n };\n if (request.document.url) {\n body.document_url = request.document.url;\n } else if (request.document.base64) {\n body.document_base64 = request.document.base64;\n body.mime_type = request.document.mimeType;\n body.filename = request.document.filename;\n } else {\n throw new Error('documents request requires document.url or document.base64');\n }\n return body;\n}\n\nexport class DocumentsNamespace {\n private config: Required<CencoriConfig>;\n\n constructor(config: Required<CencoriConfig>) {\n this.config = config;\n }\n\n /** Extract text from a PDF (native, no LLM) or image (via Vision OCR). */\n async extract(request: DocumentRequest): Promise<DocumentExtractResult> {\n return this.post<DocumentExtractResult>('/api/ai/documents/extract', toBody(request));\n }\n\n /** Extract then summarize the document with a chat model. */\n async summarize(request: DocumentRequest): Promise<DocumentSummarizeResult> {\n return this.post<DocumentSummarizeResult>('/api/ai/documents/summarize', toBody(request));\n }\n\n /** Extract then answer a question about the document. */\n async query(request: DocumentQueryRequest): Promise<DocumentQueryResult> {\n if (!request.question) throw new Error('documents.query requires a `question`');\n return this.post<DocumentQueryResult>('/api/ai/documents/query', toBody(request, { question: request.question }));\n }\n\n private async post<T>(path: string, body: JsonBody): Promise<T> {\n const response = await fetch(`${this.config.baseUrl}${path}`, {\n method: 'POST',\n headers: {\n 'CENCORI_API_KEY': this.config.apiKey,\n 'Content-Type': 'application/json',\n ...this.config.headers,\n },\n body: JSON.stringify(body),\n });\n const data = await response.json();\n if (!response.ok) {\n const message =\n (data && typeof data === 'object' && 'message' in data && typeof data.message === 'string')\n ? data.message\n : `Documents request failed with status ${response.status}`;\n const code =\n (data && typeof data === 'object' && 'error' in data && typeof data.error === 'string')\n ? data.error\n : 'request_failed';\n const err = new Error(message) as Error & { code?: string; details?: unknown };\n err.code = code;\n err.details = data;\n throw err;\n }\n return data as T;\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAsGA,SAAS,OAAO,SAA0B,QAA2B,CAAC,GAAa;AAC/E,QAAM,OAAiB;AAAA,IACnB,QAAQ,QAAQ;AAAA,IAChB,OAAO,QAAQ;AAAA,IACf,YAAY,QAAQ;AAAA,IACpB,aAAa,QAAQ;AAAA,IACrB,GAAG;AAAA,EACP;AACA,MAAI,QAAQ,SAAS,KAAK;AACtB,SAAK,eAAe,QAAQ,SAAS;AAAA,EACzC,WAAW,QAAQ,SAAS,QAAQ;AAChC,SAAK,kBAAkB,QAAQ,SAAS;AACxC,SAAK,YAAY,QAAQ,SAAS;AAClC,SAAK,WAAW,QAAQ,SAAS;AAAA,EACrC,OAAO;AACH,UAAM,IAAI,MAAM,4DAA4D;AAAA,EAChF;AACA,SAAO;AACX;AAEO,IAAM,qBAAN,MAAyB;AAAA,EAG5B,YAAY,QAAiC;AACzC,SAAK,SAAS;AAAA,EAClB;AAAA;AAAA,EAGA,MAAM,QAAQ,SAA0D;AACpE,WAAO,KAAK,KAA4B,6BAA6B,OAAO,OAAO,CAAC;AAAA,EACxF;AAAA;AAAA,EAGA,MAAM,UAAU,SAA4D;AACxE,WAAO,KAAK,KAA8B,+BAA+B,OAAO,OAAO,CAAC;AAAA,EAC5F;AAAA;AAAA,EAGA,MAAM,MAAM,SAA6D;AACrE,QAAI,CAAC,QAAQ,SAAU,OAAM,IAAI,MAAM,uCAAuC;AAC9E,WAAO,KAAK,KAA0B,2BAA2B,OAAO,SAAS,EAAE,UAAU,QAAQ,SAAS,CAAC,CAAC;AAAA,EACpH;AAAA,EAEA,MAAc,KAAQ,MAAc,MAA4B;AAC5D,UAAM,WAAW,MAAM,MAAM,GAAG,KAAK,OAAO,OAAO,GAAG,IAAI,IAAI;AAAA,MAC1D,QAAQ;AAAA,MACR,SAAS;AAAA,QACL,mBAAmB,KAAK,OAAO;AAAA,QAC/B,gBAAgB;AAAA,QAChB,GAAG,KAAK,OAAO;AAAA,MACnB;AAAA,MACA,MAAM,KAAK,UAAU,IAAI;AAAA,IAC7B,CAAC;AACD,UAAM,OAAO,MAAM,SAAS,KAAK;AACjC,QAAI,CAAC,SAAS,IAAI;AACd,YAAM,UACD,QAAQ,OAAO,SAAS,YAAY,aAAa,QAAQ,OAAO,KAAK,YAAY,WAC5E,KAAK,UACL,wCAAwC,SAAS,MAAM;AACjE,YAAM,OACD,QAAQ,OAAO,SAAS,YAAY,WAAW,QAAQ,OAAO,KAAK,UAAU,WACxE,KAAK,QACL;AACV,YAAM,MAAM,IAAI,MAAM,OAAO;AAC7B,UAAI,OAAO;AACX,UAAI,UAAU;AACd,YAAM;AAAA,IACV;AACA,WAAO;AAAA,EACX;AACJ;","names":[]}
@@ -0,0 +1,63 @@
1
+ // src/documents/index.ts
2
+ function toBody(request, extra = {}) {
3
+ const body = {
4
+ prompt: request.prompt,
5
+ model: request.model,
6
+ max_tokens: request.maxTokens,
7
+ temperature: request.temperature,
8
+ ...extra
9
+ };
10
+ if (request.document.url) {
11
+ body.document_url = request.document.url;
12
+ } else if (request.document.base64) {
13
+ body.document_base64 = request.document.base64;
14
+ body.mime_type = request.document.mimeType;
15
+ body.filename = request.document.filename;
16
+ } else {
17
+ throw new Error("documents request requires document.url or document.base64");
18
+ }
19
+ return body;
20
+ }
21
+ var DocumentsNamespace = class {
22
+ constructor(config) {
23
+ this.config = config;
24
+ }
25
+ /** Extract text from a PDF (native, no LLM) or image (via Vision OCR). */
26
+ async extract(request) {
27
+ return this.post("/api/ai/documents/extract", toBody(request));
28
+ }
29
+ /** Extract then summarize the document with a chat model. */
30
+ async summarize(request) {
31
+ return this.post("/api/ai/documents/summarize", toBody(request));
32
+ }
33
+ /** Extract then answer a question about the document. */
34
+ async query(request) {
35
+ if (!request.question) throw new Error("documents.query requires a `question`");
36
+ return this.post("/api/ai/documents/query", toBody(request, { question: request.question }));
37
+ }
38
+ async post(path, body) {
39
+ const response = await fetch(`${this.config.baseUrl}${path}`, {
40
+ method: "POST",
41
+ headers: {
42
+ "CENCORI_API_KEY": this.config.apiKey,
43
+ "Content-Type": "application/json",
44
+ ...this.config.headers
45
+ },
46
+ body: JSON.stringify(body)
47
+ });
48
+ const data = await response.json();
49
+ if (!response.ok) {
50
+ const message = data && typeof data === "object" && "message" in data && typeof data.message === "string" ? data.message : `Documents request failed with status ${response.status}`;
51
+ const code = data && typeof data === "object" && "error" in data && typeof data.error === "string" ? data.error : "request_failed";
52
+ const err = new Error(message);
53
+ err.code = code;
54
+ err.details = data;
55
+ throw err;
56
+ }
57
+ return data;
58
+ }
59
+ };
60
+ export {
61
+ DocumentsNamespace
62
+ };
63
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/documents/index.ts"],"sourcesContent":["/**\n * Documents API — extract text from PDFs and images, summarize, and query.\n *\n * @example\n * const { text, pageCount } = await cencori.documents.extract({\n * document: { url: 'https://example.com/contract.pdf' },\n * });\n *\n * @example\n * const { summary } = await cencori.documents.summarize({\n * document: { base64, mimeType: 'application/pdf' },\n * });\n *\n * @example\n * const { answer } = await cencori.documents.query({\n * document: { url: 'https://example.com/report.pdf' },\n * question: 'What is the total revenue for Q3?',\n * });\n */\n\nimport type { CencoriConfig } from '../types';\n\nexport type DocumentExtractMethod = 'pdf_text' | 'vision_ocr';\nexport type DocumentKind = 'pdf' | 'image';\n\nexport interface DocumentInput {\n url?: string;\n base64?: string;\n mimeType?: string;\n filename?: string;\n}\n\nexport interface DocumentRequest {\n document: DocumentInput;\n prompt?: string;\n model?: string;\n maxTokens?: number;\n temperature?: number;\n}\n\nexport interface DocumentQueryRequest extends DocumentRequest {\n question: string;\n}\n\nexport interface DocumentUsage {\n promptTokens: number;\n completionTokens: number;\n totalTokens: number;\n}\n\nexport interface DocumentCost {\n providerCostUsd: number;\n cencoriChargeUsd: number;\n markupPercentage: number;\n}\n\nexport interface DocumentExtractResult {\n text: string;\n pageCount: number;\n kind: DocumentKind;\n method: DocumentExtractMethod;\n model?: string;\n provider?: string;\n metadata?: Record<string, unknown>;\n usage?: DocumentUsage;\n cost?: DocumentCost;\n}\n\nexport interface DocumentSummarizeResult {\n summary: string;\n text: string;\n pageCount: number;\n model: string;\n provider: string;\n extractMethod: DocumentExtractMethod;\n usage: DocumentUsage;\n cost: DocumentCost;\n}\n\nexport interface DocumentQueryResult {\n answer: string;\n question: string;\n pageCount: number;\n model: string;\n provider: string;\n extractMethod: DocumentExtractMethod;\n usage: DocumentUsage;\n cost: DocumentCost;\n}\n\ninterface JsonBody {\n document_url?: string;\n document_base64?: string;\n mime_type?: string;\n filename?: string;\n prompt?: string;\n model?: string;\n max_tokens?: number;\n temperature?: number;\n question?: string;\n}\n\nfunction toBody(request: DocumentRequest, extra: Partial<JsonBody> = {}): JsonBody {\n const body: JsonBody = {\n prompt: request.prompt,\n model: request.model,\n max_tokens: request.maxTokens,\n temperature: request.temperature,\n ...extra,\n };\n if (request.document.url) {\n body.document_url = request.document.url;\n } else if (request.document.base64) {\n body.document_base64 = request.document.base64;\n body.mime_type = request.document.mimeType;\n body.filename = request.document.filename;\n } else {\n throw new Error('documents request requires document.url or document.base64');\n }\n return body;\n}\n\nexport class DocumentsNamespace {\n private config: Required<CencoriConfig>;\n\n constructor(config: Required<CencoriConfig>) {\n this.config = config;\n }\n\n /** Extract text from a PDF (native, no LLM) or image (via Vision OCR). */\n async extract(request: DocumentRequest): Promise<DocumentExtractResult> {\n return this.post<DocumentExtractResult>('/api/ai/documents/extract', toBody(request));\n }\n\n /** Extract then summarize the document with a chat model. */\n async summarize(request: DocumentRequest): Promise<DocumentSummarizeResult> {\n return this.post<DocumentSummarizeResult>('/api/ai/documents/summarize', toBody(request));\n }\n\n /** Extract then answer a question about the document. */\n async query(request: DocumentQueryRequest): Promise<DocumentQueryResult> {\n if (!request.question) throw new Error('documents.query requires a `question`');\n return this.post<DocumentQueryResult>('/api/ai/documents/query', toBody(request, { question: request.question }));\n }\n\n private async post<T>(path: string, body: JsonBody): Promise<T> {\n const response = await fetch(`${this.config.baseUrl}${path}`, {\n method: 'POST',\n headers: {\n 'CENCORI_API_KEY': this.config.apiKey,\n 'Content-Type': 'application/json',\n ...this.config.headers,\n },\n body: JSON.stringify(body),\n });\n const data = await response.json();\n if (!response.ok) {\n const message =\n (data && typeof data === 'object' && 'message' in data && typeof data.message === 'string')\n ? data.message\n : `Documents request failed with status ${response.status}`;\n const code =\n (data && typeof data === 'object' && 'error' in data && typeof data.error === 'string')\n ? data.error\n : 'request_failed';\n const err = new Error(message) as Error & { code?: string; details?: unknown };\n err.code = code;\n err.details = data;\n throw err;\n }\n return data as T;\n }\n}\n"],"mappings":";AAsGA,SAAS,OAAO,SAA0B,QAA2B,CAAC,GAAa;AAC/E,QAAM,OAAiB;AAAA,IACnB,QAAQ,QAAQ;AAAA,IAChB,OAAO,QAAQ;AAAA,IACf,YAAY,QAAQ;AAAA,IACpB,aAAa,QAAQ;AAAA,IACrB,GAAG;AAAA,EACP;AACA,MAAI,QAAQ,SAAS,KAAK;AACtB,SAAK,eAAe,QAAQ,SAAS;AAAA,EACzC,WAAW,QAAQ,SAAS,QAAQ;AAChC,SAAK,kBAAkB,QAAQ,SAAS;AACxC,SAAK,YAAY,QAAQ,SAAS;AAClC,SAAK,WAAW,QAAQ,SAAS;AAAA,EACrC,OAAO;AACH,UAAM,IAAI,MAAM,4DAA4D;AAAA,EAChF;AACA,SAAO;AACX;AAEO,IAAM,qBAAN,MAAyB;AAAA,EAG5B,YAAY,QAAiC;AACzC,SAAK,SAAS;AAAA,EAClB;AAAA;AAAA,EAGA,MAAM,QAAQ,SAA0D;AACpE,WAAO,KAAK,KAA4B,6BAA6B,OAAO,OAAO,CAAC;AAAA,EACxF;AAAA;AAAA,EAGA,MAAM,UAAU,SAA4D;AACxE,WAAO,KAAK,KAA8B,+BAA+B,OAAO,OAAO,CAAC;AAAA,EAC5F;AAAA;AAAA,EAGA,MAAM,MAAM,SAA6D;AACrE,QAAI,CAAC,QAAQ,SAAU,OAAM,IAAI,MAAM,uCAAuC;AAC9E,WAAO,KAAK,KAA0B,2BAA2B,OAAO,SAAS,EAAE,UAAU,QAAQ,SAAS,CAAC,CAAC;AAAA,EACpH;AAAA,EAEA,MAAc,KAAQ,MAAc,MAA4B;AAC5D,UAAM,WAAW,MAAM,MAAM,GAAG,KAAK,OAAO,OAAO,GAAG,IAAI,IAAI;AAAA,MAC1D,QAAQ;AAAA,MACR,SAAS;AAAA,QACL,mBAAmB,KAAK,OAAO;AAAA,QAC/B,gBAAgB;AAAA,QAChB,GAAG,KAAK,OAAO;AAAA,MACnB;AAAA,MACA,MAAM,KAAK,UAAU,IAAI;AAAA,IAC7B,CAAC;AACD,UAAM,OAAO,MAAM,SAAS,KAAK;AACjC,QAAI,CAAC,SAAS,IAAI;AACd,YAAM,UACD,QAAQ,OAAO,SAAS,YAAY,aAAa,QAAQ,OAAO,KAAK,YAAY,WAC5E,KAAK,UACL,wCAAwC,SAAS,MAAM;AACjE,YAAM,OACD,QAAQ,OAAO,SAAS,YAAY,WAAW,QAAQ,OAAO,KAAK,UAAU,WACxE,KAAK,QACL;AACV,YAAM,MAAM,IAAI,MAAM,OAAO;AAC7B,UAAI,OAAO;AACX,UAAI,UAAU;AACd,YAAM;AAAA,IACV;AACA,WAAO;AAAA,EACX;AACJ;","names":[]}
package/dist/index.d.mts CHANGED
@@ -3,7 +3,9 @@ export { j as ChatMessage, a as ChatRequest, b as ChatResponse, o as CodeInterpr
3
3
  import { AINamespace } from './ai/index.mjs';
4
4
  export { StreamChunk } from './ai/index.mjs';
5
5
  import { VisionNamespace } from './vision/index.mjs';
6
- export { VisionClassification, VisionClassifyResult, VisionCost, VisionDescribeResult, VisionImage, VisionOcrResult, VisionProvider, VisionRequest, VisionResult, VisionTask, VisionUsage } from './vision/index.mjs';
6
+ export { VisionClassification, VisionClassifyResult, VisionCost, VisionDescribeResult, VisionImage, VisionOcrResult, VisionProvider, VisionRequest, VisionResult, VisionStreamChunk, VisionTask, VisionUsage } from './vision/index.mjs';
7
+ import { DocumentsNamespace } from './documents/index.mjs';
8
+ export { DocumentCost, DocumentExtractMethod, DocumentExtractResult, DocumentInput, DocumentKind, DocumentQueryRequest, DocumentQueryResult, DocumentRequest, DocumentSummarizeResult, DocumentUsage } from './documents/index.mjs';
7
9
  import { ComputeNamespace } from './compute/index.mjs';
8
10
  import { WorkflowNamespace } from './workflow/index.mjs';
9
11
  import { StorageNamespace } from './storage/index.mjs';
@@ -229,6 +231,26 @@ declare class Cencori {
229
231
  * });
230
232
  */
231
233
  readonly vision: VisionNamespace;
234
+ /**
235
+ * Documents - Extract text from PDFs and images, summarize, and query
236
+ *
237
+ * @example
238
+ * const { text } = await cencori.documents.extract({
239
+ * document: { url: 'https://example.com/contract.pdf' }
240
+ * });
241
+ *
242
+ * @example
243
+ * const { summary } = await cencori.documents.summarize({
244
+ * document: { url: 'https://example.com/report.pdf' }
245
+ * });
246
+ *
247
+ * @example
248
+ * const { answer } = await cencori.documents.query({
249
+ * document: { url },
250
+ * question: 'What is the total revenue for Q3?',
251
+ * });
252
+ */
253
+ readonly documents: DocumentsNamespace;
232
254
  /**
233
255
  * Agents - Create and manage AI agents programmatically.
234
256
  *
@@ -369,4 +391,4 @@ declare class SafetyError extends CencoriError {
369
391
  */
370
392
  declare function fetchWithRetry(url: string, options: RequestInit, maxRetries?: number): Promise<Response>;
371
393
 
372
- export { AINamespace, type Agent, type AgentConfig, type AgentKey, type AgentListItem, AgentsNamespace, AuthenticationError, Cencori, CencoriConfig, CencoriError, ComputeNamespace, type CreateAgentKeyParams, type CreateAgentParams, type CreateSessionParams, MemoryClient, type PaginatedResponse, RateLimitError, RequestOptions, SafetyError, type Session, type SessionEvent, type SessionListParams, SessionsNamespace, StorageNamespace, TelemetryClient, type TurnParams, type UpdateAgentParams, VisionNamespace, WorkflowNamespace, Cencori as default, fetchWithRetry };
394
+ export { AINamespace, type Agent, type AgentConfig, type AgentKey, type AgentListItem, AgentsNamespace, AuthenticationError, Cencori, CencoriConfig, CencoriError, ComputeNamespace, type CreateAgentKeyParams, type CreateAgentParams, type CreateSessionParams, DocumentsNamespace, MemoryClient, type PaginatedResponse, RateLimitError, RequestOptions, SafetyError, type Session, type SessionEvent, type SessionListParams, SessionsNamespace, StorageNamespace, TelemetryClient, type TurnParams, type UpdateAgentParams, VisionNamespace, WorkflowNamespace, Cencori as default, fetchWithRetry };
package/dist/index.d.ts CHANGED
@@ -3,7 +3,9 @@ export { j as ChatMessage, a as ChatRequest, b as ChatResponse, o as CodeInterpr
3
3
  import { AINamespace } from './ai/index.js';
4
4
  export { StreamChunk } from './ai/index.js';
5
5
  import { VisionNamespace } from './vision/index.js';
6
- export { VisionClassification, VisionClassifyResult, VisionCost, VisionDescribeResult, VisionImage, VisionOcrResult, VisionProvider, VisionRequest, VisionResult, VisionTask, VisionUsage } from './vision/index.js';
6
+ export { VisionClassification, VisionClassifyResult, VisionCost, VisionDescribeResult, VisionImage, VisionOcrResult, VisionProvider, VisionRequest, VisionResult, VisionStreamChunk, VisionTask, VisionUsage } from './vision/index.js';
7
+ import { DocumentsNamespace } from './documents/index.js';
8
+ export { DocumentCost, DocumentExtractMethod, DocumentExtractResult, DocumentInput, DocumentKind, DocumentQueryRequest, DocumentQueryResult, DocumentRequest, DocumentSummarizeResult, DocumentUsage } from './documents/index.js';
7
9
  import { ComputeNamespace } from './compute/index.js';
8
10
  import { WorkflowNamespace } from './workflow/index.js';
9
11
  import { StorageNamespace } from './storage/index.js';
@@ -229,6 +231,26 @@ declare class Cencori {
229
231
  * });
230
232
  */
231
233
  readonly vision: VisionNamespace;
234
+ /**
235
+ * Documents - Extract text from PDFs and images, summarize, and query
236
+ *
237
+ * @example
238
+ * const { text } = await cencori.documents.extract({
239
+ * document: { url: 'https://example.com/contract.pdf' }
240
+ * });
241
+ *
242
+ * @example
243
+ * const { summary } = await cencori.documents.summarize({
244
+ * document: { url: 'https://example.com/report.pdf' }
245
+ * });
246
+ *
247
+ * @example
248
+ * const { answer } = await cencori.documents.query({
249
+ * document: { url },
250
+ * question: 'What is the total revenue for Q3?',
251
+ * });
252
+ */
253
+ readonly documents: DocumentsNamespace;
232
254
  /**
233
255
  * Agents - Create and manage AI agents programmatically.
234
256
  *
@@ -369,4 +391,4 @@ declare class SafetyError extends CencoriError {
369
391
  */
370
392
  declare function fetchWithRetry(url: string, options: RequestInit, maxRetries?: number): Promise<Response>;
371
393
 
372
- export { AINamespace, type Agent, type AgentConfig, type AgentKey, type AgentListItem, AgentsNamespace, AuthenticationError, Cencori, CencoriConfig, CencoriError, ComputeNamespace, type CreateAgentKeyParams, type CreateAgentParams, type CreateSessionParams, MemoryClient, type PaginatedResponse, RateLimitError, RequestOptions, SafetyError, type Session, type SessionEvent, type SessionListParams, SessionsNamespace, StorageNamespace, TelemetryClient, type TurnParams, type UpdateAgentParams, VisionNamespace, WorkflowNamespace, Cencori as default, fetchWithRetry };
394
+ export { AINamespace, type Agent, type AgentConfig, type AgentKey, type AgentListItem, AgentsNamespace, AuthenticationError, Cencori, CencoriConfig, CencoriError, ComputeNamespace, type CreateAgentKeyParams, type CreateAgentParams, type CreateSessionParams, DocumentsNamespace, MemoryClient, type PaginatedResponse, RateLimitError, RequestOptions, SafetyError, type Session, type SessionEvent, type SessionListParams, SessionsNamespace, StorageNamespace, TelemetryClient, type TurnParams, type UpdateAgentParams, VisionNamespace, WorkflowNamespace, Cencori as default, fetchWithRetry };
package/dist/index.js CHANGED
@@ -26,6 +26,7 @@ __export(src_exports, {
26
26
  Cencori: () => Cencori,
27
27
  CencoriError: () => CencoriError,
28
28
  ComputeNamespace: () => ComputeNamespace,
29
+ DocumentsNamespace: () => DocumentsNamespace,
29
30
  MemoryClient: () => MemoryClient,
30
31
  RateLimitError: () => RateLimitError,
31
32
  SafetyError: () => SafetyError,
@@ -643,6 +644,17 @@ function toBody(request) {
643
644
  temperature: request.temperature,
644
645
  response_format: request.responseFormat
645
646
  };
647
+ if (request.images && request.images.length > 0) {
648
+ body.images = request.images.map((img) => {
649
+ if (img.url) return { url: img.url };
650
+ if (img.base64) return { base64: img.base64, mime_type: img.mimeType };
651
+ throw new Error("Each entry in images requires url or base64");
652
+ });
653
+ return body;
654
+ }
655
+ if (!request.image) {
656
+ throw new Error("vision request requires `image` or `images[]`");
657
+ }
646
658
  if (request.image.url) {
647
659
  body.image_url = request.image.url;
648
660
  } else if (request.image.base64) {
@@ -676,6 +688,57 @@ var VisionNamespace = class {
676
688
  async classify(request) {
677
689
  return this.post("/api/ai/vision/classify", request);
678
690
  }
691
+ /**
692
+ * Stream a vision analysis. Yields `{ delta }` chunks as text arrives, then
693
+ * a final `{ done: true, model, provider, usage, cost }` chunk with totals.
694
+ *
695
+ * @example
696
+ * for await (const chunk of cencori.vision.analyzeStream({ image: { url } })) {
697
+ * if (chunk.delta) process.stdout.write(chunk.delta);
698
+ * if (chunk.done) console.log(chunk.cost);
699
+ * }
700
+ */
701
+ async *analyzeStream(request) {
702
+ const body = { ...toBody(request), stream: true };
703
+ const response = await fetch(`${this.config.baseUrl}/api/ai/vision`, {
704
+ method: "POST",
705
+ headers: {
706
+ "CENCORI_API_KEY": this.config.apiKey,
707
+ "Content-Type": "application/json",
708
+ ...this.config.headers
709
+ },
710
+ body: JSON.stringify(body)
711
+ });
712
+ if (!response.ok) {
713
+ const data = await response.json().catch(() => ({}));
714
+ const message = data && typeof data === "object" && "message" in data && typeof data.message === "string" ? data.message : `Vision stream request failed with status ${response.status}`;
715
+ throw new Error(message);
716
+ }
717
+ if (!response.body) throw new Error("Response body is null");
718
+ const reader = response.body.getReader();
719
+ const decoder = new TextDecoder();
720
+ let buffer = "";
721
+ try {
722
+ while (true) {
723
+ const { done, value } = await reader.read();
724
+ if (done) break;
725
+ buffer += decoder.decode(value, { stream: true });
726
+ const lines = buffer.split("\n");
727
+ buffer = lines.pop() ?? "";
728
+ for (const line of lines) {
729
+ if (!line.startsWith("data: ")) continue;
730
+ const data = line.slice(6);
731
+ if (data === "[DONE]") return;
732
+ try {
733
+ yield JSON.parse(data);
734
+ } catch {
735
+ }
736
+ }
737
+ }
738
+ } finally {
739
+ reader.releaseLock();
740
+ }
741
+ }
679
742
  async post(path, request) {
680
743
  const response = await fetch(`${this.config.baseUrl}${path}`, {
681
744
  method: "POST",
@@ -699,6 +762,66 @@ var VisionNamespace = class {
699
762
  }
700
763
  };
701
764
 
765
+ // src/documents/index.ts
766
+ function toBody2(request, extra = {}) {
767
+ const body = {
768
+ prompt: request.prompt,
769
+ model: request.model,
770
+ max_tokens: request.maxTokens,
771
+ temperature: request.temperature,
772
+ ...extra
773
+ };
774
+ if (request.document.url) {
775
+ body.document_url = request.document.url;
776
+ } else if (request.document.base64) {
777
+ body.document_base64 = request.document.base64;
778
+ body.mime_type = request.document.mimeType;
779
+ body.filename = request.document.filename;
780
+ } else {
781
+ throw new Error("documents request requires document.url or document.base64");
782
+ }
783
+ return body;
784
+ }
785
+ var DocumentsNamespace = class {
786
+ constructor(config) {
787
+ this.config = config;
788
+ }
789
+ /** Extract text from a PDF (native, no LLM) or image (via Vision OCR). */
790
+ async extract(request) {
791
+ return this.post("/api/ai/documents/extract", toBody2(request));
792
+ }
793
+ /** Extract then summarize the document with a chat model. */
794
+ async summarize(request) {
795
+ return this.post("/api/ai/documents/summarize", toBody2(request));
796
+ }
797
+ /** Extract then answer a question about the document. */
798
+ async query(request) {
799
+ if (!request.question) throw new Error("documents.query requires a `question`");
800
+ return this.post("/api/ai/documents/query", toBody2(request, { question: request.question }));
801
+ }
802
+ async post(path, body) {
803
+ const response = await fetch(`${this.config.baseUrl}${path}`, {
804
+ method: "POST",
805
+ headers: {
806
+ "CENCORI_API_KEY": this.config.apiKey,
807
+ "Content-Type": "application/json",
808
+ ...this.config.headers
809
+ },
810
+ body: JSON.stringify(body)
811
+ });
812
+ const data = await response.json();
813
+ if (!response.ok) {
814
+ const message = data && typeof data === "object" && "message" in data && typeof data.message === "string" ? data.message : `Documents request failed with status ${response.status}`;
815
+ const code = data && typeof data === "object" && "error" in data && typeof data.error === "string" ? data.error : "request_failed";
816
+ const err = new Error(message);
817
+ err.code = code;
818
+ err.details = data;
819
+ throw err;
820
+ }
821
+ return data;
822
+ }
823
+ };
824
+
702
825
  // src/sessions/index.ts
703
826
  var SessionsNamespace = class {
704
827
  constructor(config) {
@@ -1223,6 +1346,7 @@ var Cencori = class {
1223
1346
  };
1224
1347
  this.ai = new AINamespace(this.config);
1225
1348
  this.vision = new VisionNamespace(this.config);
1349
+ this.documents = new DocumentsNamespace(this.config);
1226
1350
  this.agents = new AgentsNamespace(this.config);
1227
1351
  this.compute = new ComputeNamespace();
1228
1352
  this.workflow = new WorkflowNamespace();
@@ -1650,6 +1774,7 @@ cencori.chat = cencori;
1650
1774
  Cencori,
1651
1775
  CencoriError,
1652
1776
  ComputeNamespace,
1777
+ DocumentsNamespace,
1653
1778
  MemoryClient,
1654
1779
  RateLimitError,
1655
1780
  SafetyError,