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.
@@ -24,13 +24,25 @@ interface VisionImage {
24
24
  mimeType?: string;
25
25
  }
26
26
  interface VisionRequest {
27
- image: VisionImage;
27
+ /** Single image. Use this OR `images`. */
28
+ image?: VisionImage;
29
+ /** Multiple images to analyze together. */
30
+ images?: VisionImage[];
28
31
  prompt?: string;
29
32
  model?: string;
30
33
  maxTokens?: number;
31
34
  temperature?: number;
32
35
  responseFormat?: 'text' | 'json';
33
36
  }
37
+ interface VisionStreamChunk {
38
+ delta?: string;
39
+ done?: boolean;
40
+ model?: string;
41
+ provider?: VisionProvider;
42
+ usage?: VisionUsage;
43
+ cost?: VisionCost;
44
+ error?: string;
45
+ }
34
46
  interface VisionUsage {
35
47
  promptTokens: number;
36
48
  completionTokens: number;
@@ -93,7 +105,18 @@ declare class VisionNamespace {
93
105
  ocr(request: VisionRequest): Promise<VisionOcrResult>;
94
106
  /** Return structured tags, objects, and category classification. */
95
107
  classify(request: VisionRequest): Promise<VisionClassifyResult>;
108
+ /**
109
+ * Stream a vision analysis. Yields `{ delta }` chunks as text arrives, then
110
+ * a final `{ done: true, model, provider, usage, cost }` chunk with totals.
111
+ *
112
+ * @example
113
+ * for await (const chunk of cencori.vision.analyzeStream({ image: { url } })) {
114
+ * if (chunk.delta) process.stdout.write(chunk.delta);
115
+ * if (chunk.done) console.log(chunk.cost);
116
+ * }
117
+ */
118
+ analyzeStream(request: VisionRequest): AsyncGenerator<VisionStreamChunk, void, unknown>;
96
119
  private post;
97
120
  }
98
121
 
99
- export { type VisionClassification, type VisionClassifyResult, type VisionCost, type VisionDescribeResult, type VisionImage, VisionNamespace, type VisionOcrResult, type VisionProvider, type VisionRequest, type VisionResult, type VisionTask, type VisionUsage };
122
+ export { type VisionClassification, type VisionClassifyResult, type VisionCost, type VisionDescribeResult, type VisionImage, VisionNamespace, type VisionOcrResult, type VisionProvider, type VisionRequest, type VisionResult, type VisionStreamChunk, type VisionTask, type VisionUsage };
@@ -24,13 +24,25 @@ interface VisionImage {
24
24
  mimeType?: string;
25
25
  }
26
26
  interface VisionRequest {
27
- image: VisionImage;
27
+ /** Single image. Use this OR `images`. */
28
+ image?: VisionImage;
29
+ /** Multiple images to analyze together. */
30
+ images?: VisionImage[];
28
31
  prompt?: string;
29
32
  model?: string;
30
33
  maxTokens?: number;
31
34
  temperature?: number;
32
35
  responseFormat?: 'text' | 'json';
33
36
  }
37
+ interface VisionStreamChunk {
38
+ delta?: string;
39
+ done?: boolean;
40
+ model?: string;
41
+ provider?: VisionProvider;
42
+ usage?: VisionUsage;
43
+ cost?: VisionCost;
44
+ error?: string;
45
+ }
34
46
  interface VisionUsage {
35
47
  promptTokens: number;
36
48
  completionTokens: number;
@@ -93,7 +105,18 @@ declare class VisionNamespace {
93
105
  ocr(request: VisionRequest): Promise<VisionOcrResult>;
94
106
  /** Return structured tags, objects, and category classification. */
95
107
  classify(request: VisionRequest): Promise<VisionClassifyResult>;
108
+ /**
109
+ * Stream a vision analysis. Yields `{ delta }` chunks as text arrives, then
110
+ * a final `{ done: true, model, provider, usage, cost }` chunk with totals.
111
+ *
112
+ * @example
113
+ * for await (const chunk of cencori.vision.analyzeStream({ image: { url } })) {
114
+ * if (chunk.delta) process.stdout.write(chunk.delta);
115
+ * if (chunk.done) console.log(chunk.cost);
116
+ * }
117
+ */
118
+ analyzeStream(request: VisionRequest): AsyncGenerator<VisionStreamChunk, void, unknown>;
96
119
  private post;
97
120
  }
98
121
 
99
- export { type VisionClassification, type VisionClassifyResult, type VisionCost, type VisionDescribeResult, type VisionImage, VisionNamespace, type VisionOcrResult, type VisionProvider, type VisionRequest, type VisionResult, type VisionTask, type VisionUsage };
122
+ export { type VisionClassification, type VisionClassifyResult, type VisionCost, type VisionDescribeResult, type VisionImage, VisionNamespace, type VisionOcrResult, type VisionProvider, type VisionRequest, type VisionResult, type VisionStreamChunk, type VisionTask, type VisionUsage };
@@ -31,6 +31,17 @@ function toBody(request) {
31
31
  temperature: request.temperature,
32
32
  response_format: request.responseFormat
33
33
  };
34
+ if (request.images && request.images.length > 0) {
35
+ body.images = request.images.map((img) => {
36
+ if (img.url) return { url: img.url };
37
+ if (img.base64) return { base64: img.base64, mime_type: img.mimeType };
38
+ throw new Error("Each entry in images requires url or base64");
39
+ });
40
+ return body;
41
+ }
42
+ if (!request.image) {
43
+ throw new Error("vision request requires `image` or `images[]`");
44
+ }
34
45
  if (request.image.url) {
35
46
  body.image_url = request.image.url;
36
47
  } else if (request.image.base64) {
@@ -64,6 +75,57 @@ var VisionNamespace = class {
64
75
  async classify(request) {
65
76
  return this.post("/api/ai/vision/classify", request);
66
77
  }
78
+ /**
79
+ * Stream a vision analysis. Yields `{ delta }` chunks as text arrives, then
80
+ * a final `{ done: true, model, provider, usage, cost }` chunk with totals.
81
+ *
82
+ * @example
83
+ * for await (const chunk of cencori.vision.analyzeStream({ image: { url } })) {
84
+ * if (chunk.delta) process.stdout.write(chunk.delta);
85
+ * if (chunk.done) console.log(chunk.cost);
86
+ * }
87
+ */
88
+ async *analyzeStream(request) {
89
+ const body = { ...toBody(request), stream: true };
90
+ const response = await fetch(`${this.config.baseUrl}/api/ai/vision`, {
91
+ method: "POST",
92
+ headers: {
93
+ "CENCORI_API_KEY": this.config.apiKey,
94
+ "Content-Type": "application/json",
95
+ ...this.config.headers
96
+ },
97
+ body: JSON.stringify(body)
98
+ });
99
+ if (!response.ok) {
100
+ const data = await response.json().catch(() => ({}));
101
+ const message = data && typeof data === "object" && "message" in data && typeof data.message === "string" ? data.message : `Vision stream request failed with status ${response.status}`;
102
+ throw new Error(message);
103
+ }
104
+ if (!response.body) throw new Error("Response body is null");
105
+ const reader = response.body.getReader();
106
+ const decoder = new TextDecoder();
107
+ let buffer = "";
108
+ try {
109
+ while (true) {
110
+ const { done, value } = await reader.read();
111
+ if (done) break;
112
+ buffer += decoder.decode(value, { stream: true });
113
+ const lines = buffer.split("\n");
114
+ buffer = lines.pop() ?? "";
115
+ for (const line of lines) {
116
+ if (!line.startsWith("data: ")) continue;
117
+ const data = line.slice(6);
118
+ if (data === "[DONE]") return;
119
+ try {
120
+ yield JSON.parse(data);
121
+ } catch {
122
+ }
123
+ }
124
+ }
125
+ } finally {
126
+ reader.releaseLock();
127
+ }
128
+ }
67
129
  async post(path, request) {
68
130
  const response = await fetch(`${this.config.baseUrl}${path}`, {
69
131
  method: "POST",
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/vision/index.ts"],"sourcesContent":["/**\n * Vision API — analyze, describe, OCR, and classify images.\n *\n * @example\n * const result = await cencori.vision.analyze({\n * image: { url: 'https://example.com/photo.jpg' },\n * prompt: 'What breed of dog is this?',\n * });\n *\n * @example\n * const { text } = await cencori.vision.ocr({ image: { base64, mimeType: 'image/png' } });\n */\n\nimport type { CencoriConfig } from '../types';\n\nexport type VisionProvider = 'openai' | 'anthropic' | 'google';\n\nexport type VisionTask = 'analyze' | 'describe' | 'ocr' | 'classify';\n\nexport interface VisionImage {\n /** https:// URL or data: URL. Exactly one of `url` or `base64` must be set. */\n url?: string;\n /** Raw base64 (no data: prefix). Requires `mimeType`. */\n base64?: string;\n /** Image mime type. Required when using `base64`. */\n mimeType?: string;\n}\n\nexport interface VisionRequest {\n image: VisionImage;\n prompt?: string;\n model?: string;\n maxTokens?: number;\n temperature?: number;\n responseFormat?: 'text' | 'json';\n}\n\nexport interface VisionUsage {\n promptTokens: number;\n completionTokens: number;\n totalTokens: number;\n}\n\nexport interface VisionCost {\n providerCostUsd: number;\n cencoriChargeUsd: number;\n markupPercentage: number;\n}\n\nexport interface VisionResult {\n analysis: string;\n model: string;\n provider: VisionProvider;\n usage: VisionUsage;\n cost: VisionCost;\n}\n\nexport interface VisionDescribeResult {\n description: string;\n model: string;\n provider: VisionProvider;\n usage: VisionUsage;\n cost: VisionCost;\n}\n\nexport interface VisionOcrResult {\n text: string;\n model: string;\n provider: VisionProvider;\n usage: VisionUsage;\n cost: VisionCost;\n}\n\nexport interface VisionClassification {\n primary_category?: string;\n tags?: string[];\n objects?: string[];\n safe_for_work?: boolean;\n confidence?: number;\n summary?: string;\n [key: string]: unknown;\n}\n\nexport interface VisionClassifyResult {\n classification: VisionClassification | string;\n raw: string;\n model: string;\n provider: VisionProvider;\n usage: VisionUsage;\n cost: VisionCost;\n}\n\ninterface JsonBody {\n image_url?: string;\n image_base64?: string;\n mime_type?: string;\n prompt?: string;\n model?: string;\n max_tokens?: number;\n temperature?: number;\n response_format?: 'text' | 'json';\n}\n\nfunction toBody(request: VisionRequest): JsonBody {\n const body: JsonBody = {\n prompt: request.prompt,\n model: request.model,\n max_tokens: request.maxTokens,\n temperature: request.temperature,\n response_format: request.responseFormat,\n };\n if (request.image.url) {\n body.image_url = request.image.url;\n } else if (request.image.base64) {\n body.image_base64 = request.image.base64;\n body.mime_type = request.image.mimeType;\n } else {\n throw new Error('vision request requires image.url or image.base64');\n }\n return body;\n}\n\nexport class VisionNamespace {\n private config: Required<CencoriConfig>;\n\n constructor(config: Required<CencoriConfig>) {\n this.config = config;\n }\n\n /**\n * General image analysis — provide your own prompt.\n * Default prompt: \"Describe this image in detail.\"\n */\n async analyze(request: VisionRequest): Promise<VisionResult> {\n return this.post<VisionResult>('/api/ai/vision', request);\n }\n\n /** Describe the image in rich detail. */\n async describe(request: VisionRequest): Promise<VisionDescribeResult> {\n return this.post<VisionDescribeResult>('/api/ai/vision/describe', request);\n }\n\n /** Extract all visible text from the image. */\n async ocr(request: VisionRequest): Promise<VisionOcrResult> {\n return this.post<VisionOcrResult>('/api/ai/vision/ocr', request);\n }\n\n /** Return structured tags, objects, and category classification. */\n async classify(request: VisionRequest): Promise<VisionClassifyResult> {\n return this.post<VisionClassifyResult>('/api/ai/vision/classify', request);\n }\n\n private async post<T>(path: string, request: VisionRequest): 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(toBody(request)),\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 : `Vision 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;AAuGA,SAAS,OAAO,SAAkC;AAC9C,QAAM,OAAiB;AAAA,IACnB,QAAQ,QAAQ;AAAA,IAChB,OAAO,QAAQ;AAAA,IACf,YAAY,QAAQ;AAAA,IACpB,aAAa,QAAQ;AAAA,IACrB,iBAAiB,QAAQ;AAAA,EAC7B;AACA,MAAI,QAAQ,MAAM,KAAK;AACnB,SAAK,YAAY,QAAQ,MAAM;AAAA,EACnC,WAAW,QAAQ,MAAM,QAAQ;AAC7B,SAAK,eAAe,QAAQ,MAAM;AAClC,SAAK,YAAY,QAAQ,MAAM;AAAA,EACnC,OAAO;AACH,UAAM,IAAI,MAAM,mDAAmD;AAAA,EACvE;AACA,SAAO;AACX;AAEO,IAAM,kBAAN,MAAsB;AAAA,EAGzB,YAAY,QAAiC;AACzC,SAAK,SAAS;AAAA,EAClB;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,QAAQ,SAA+C;AACzD,WAAO,KAAK,KAAmB,kBAAkB,OAAO;AAAA,EAC5D;AAAA;AAAA,EAGA,MAAM,SAAS,SAAuD;AAClE,WAAO,KAAK,KAA2B,2BAA2B,OAAO;AAAA,EAC7E;AAAA;AAAA,EAGA,MAAM,IAAI,SAAkD;AACxD,WAAO,KAAK,KAAsB,sBAAsB,OAAO;AAAA,EACnE;AAAA;AAAA,EAGA,MAAM,SAAS,SAAuD;AAClE,WAAO,KAAK,KAA2B,2BAA2B,OAAO;AAAA,EAC7E;AAAA,EAEA,MAAc,KAAQ,MAAc,SAAoC;AACpE,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,OAAO,OAAO,CAAC;AAAA,IACxC,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,qCAAqC,SAAS,MAAM;AAC9D,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":[]}
1
+ {"version":3,"sources":["../../src/vision/index.ts"],"sourcesContent":["/**\n * Vision API — analyze, describe, OCR, and classify images.\n *\n * @example\n * const result = await cencori.vision.analyze({\n * image: { url: 'https://example.com/photo.jpg' },\n * prompt: 'What breed of dog is this?',\n * });\n *\n * @example\n * const { text } = await cencori.vision.ocr({ image: { base64, mimeType: 'image/png' } });\n */\n\nimport type { CencoriConfig } from '../types';\n\nexport type VisionProvider = 'openai' | 'anthropic' | 'google';\n\nexport type VisionTask = 'analyze' | 'describe' | 'ocr' | 'classify';\n\nexport interface VisionImage {\n /** https:// URL or data: URL. Exactly one of `url` or `base64` must be set. */\n url?: string;\n /** Raw base64 (no data: prefix). Requires `mimeType`. */\n base64?: string;\n /** Image mime type. Required when using `base64`. */\n mimeType?: string;\n}\n\nexport interface VisionRequest {\n /** Single image. Use this OR `images`. */\n image?: VisionImage;\n /** Multiple images to analyze together. */\n images?: VisionImage[];\n prompt?: string;\n model?: string;\n maxTokens?: number;\n temperature?: number;\n responseFormat?: 'text' | 'json';\n}\n\nexport interface VisionStreamChunk {\n delta?: string;\n done?: boolean;\n model?: string;\n provider?: VisionProvider;\n usage?: VisionUsage;\n cost?: VisionCost;\n error?: string;\n}\n\nexport interface VisionUsage {\n promptTokens: number;\n completionTokens: number;\n totalTokens: number;\n}\n\nexport interface VisionCost {\n providerCostUsd: number;\n cencoriChargeUsd: number;\n markupPercentage: number;\n}\n\nexport interface VisionResult {\n analysis: string;\n model: string;\n provider: VisionProvider;\n usage: VisionUsage;\n cost: VisionCost;\n}\n\nexport interface VisionDescribeResult {\n description: string;\n model: string;\n provider: VisionProvider;\n usage: VisionUsage;\n cost: VisionCost;\n}\n\nexport interface VisionOcrResult {\n text: string;\n model: string;\n provider: VisionProvider;\n usage: VisionUsage;\n cost: VisionCost;\n}\n\nexport interface VisionClassification {\n primary_category?: string;\n tags?: string[];\n objects?: string[];\n safe_for_work?: boolean;\n confidence?: number;\n summary?: string;\n [key: string]: unknown;\n}\n\nexport interface VisionClassifyResult {\n classification: VisionClassification | string;\n raw: string;\n model: string;\n provider: VisionProvider;\n usage: VisionUsage;\n cost: VisionCost;\n}\n\ninterface JsonBody {\n image_url?: string;\n image_base64?: string;\n mime_type?: string;\n images?: Array<{ url?: string; base64?: string; mime_type?: string }>;\n prompt?: string;\n model?: string;\n max_tokens?: number;\n temperature?: number;\n response_format?: 'text' | 'json';\n}\n\nfunction toBody(request: VisionRequest): JsonBody {\n const body: JsonBody = {\n prompt: request.prompt,\n model: request.model,\n max_tokens: request.maxTokens,\n temperature: request.temperature,\n response_format: request.responseFormat,\n };\n\n if (request.images && request.images.length > 0) {\n body.images = request.images.map(img => {\n if (img.url) return { url: img.url };\n if (img.base64) return { base64: img.base64, mime_type: img.mimeType };\n throw new Error('Each entry in images requires url or base64');\n });\n return body;\n }\n if (!request.image) {\n throw new Error('vision request requires `image` or `images[]`');\n }\n if (request.image.url) {\n body.image_url = request.image.url;\n } else if (request.image.base64) {\n body.image_base64 = request.image.base64;\n body.mime_type = request.image.mimeType;\n } else {\n throw new Error('vision request requires image.url or image.base64');\n }\n return body;\n}\n\nexport class VisionNamespace {\n private config: Required<CencoriConfig>;\n\n constructor(config: Required<CencoriConfig>) {\n this.config = config;\n }\n\n /**\n * General image analysis — provide your own prompt.\n * Default prompt: \"Describe this image in detail.\"\n */\n async analyze(request: VisionRequest): Promise<VisionResult> {\n return this.post<VisionResult>('/api/ai/vision', request);\n }\n\n /** Describe the image in rich detail. */\n async describe(request: VisionRequest): Promise<VisionDescribeResult> {\n return this.post<VisionDescribeResult>('/api/ai/vision/describe', request);\n }\n\n /** Extract all visible text from the image. */\n async ocr(request: VisionRequest): Promise<VisionOcrResult> {\n return this.post<VisionOcrResult>('/api/ai/vision/ocr', request);\n }\n\n /** Return structured tags, objects, and category classification. */\n async classify(request: VisionRequest): Promise<VisionClassifyResult> {\n return this.post<VisionClassifyResult>('/api/ai/vision/classify', request);\n }\n\n /**\n * Stream a vision analysis. Yields `{ delta }` chunks as text arrives, then\n * a final `{ done: true, model, provider, usage, cost }` chunk with totals.\n *\n * @example\n * for await (const chunk of cencori.vision.analyzeStream({ image: { url } })) {\n * if (chunk.delta) process.stdout.write(chunk.delta);\n * if (chunk.done) console.log(chunk.cost);\n * }\n */\n async *analyzeStream(request: VisionRequest): AsyncGenerator<VisionStreamChunk, void, unknown> {\n const body = { ...toBody(request), stream: true };\n const response = await fetch(`${this.config.baseUrl}/api/ai/vision`, {\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 if (!response.ok) {\n const data = await response.json().catch(() => ({}));\n const message =\n (data && typeof data === 'object' && 'message' in data && typeof data.message === 'string')\n ? data.message\n : `Vision stream request failed with status ${response.status}`;\n throw new Error(message);\n }\n if (!response.body) throw new Error('Response body is null');\n\n const reader = response.body.getReader();\n const decoder = new TextDecoder();\n let buffer = '';\n try {\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n buffer += decoder.decode(value, { stream: true });\n const lines = buffer.split('\\n');\n buffer = lines.pop() ?? '';\n for (const line of lines) {\n if (!line.startsWith('data: ')) continue;\n const data = line.slice(6);\n if (data === '[DONE]') return;\n try {\n yield JSON.parse(data) as VisionStreamChunk;\n } catch {\n // skip malformed frame\n }\n }\n }\n } finally {\n reader.releaseLock();\n }\n }\n\n private async post<T>(path: string, request: VisionRequest): 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(toBody(request)),\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 : `Vision 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":"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","names":[]}
@@ -7,6 +7,17 @@ function toBody(request) {
7
7
  temperature: request.temperature,
8
8
  response_format: request.responseFormat
9
9
  };
10
+ if (request.images && request.images.length > 0) {
11
+ body.images = request.images.map((img) => {
12
+ if (img.url) return { url: img.url };
13
+ if (img.base64) return { base64: img.base64, mime_type: img.mimeType };
14
+ throw new Error("Each entry in images requires url or base64");
15
+ });
16
+ return body;
17
+ }
18
+ if (!request.image) {
19
+ throw new Error("vision request requires `image` or `images[]`");
20
+ }
10
21
  if (request.image.url) {
11
22
  body.image_url = request.image.url;
12
23
  } else if (request.image.base64) {
@@ -40,6 +51,57 @@ var VisionNamespace = class {
40
51
  async classify(request) {
41
52
  return this.post("/api/ai/vision/classify", request);
42
53
  }
54
+ /**
55
+ * Stream a vision analysis. Yields `{ delta }` chunks as text arrives, then
56
+ * a final `{ done: true, model, provider, usage, cost }` chunk with totals.
57
+ *
58
+ * @example
59
+ * for await (const chunk of cencori.vision.analyzeStream({ image: { url } })) {
60
+ * if (chunk.delta) process.stdout.write(chunk.delta);
61
+ * if (chunk.done) console.log(chunk.cost);
62
+ * }
63
+ */
64
+ async *analyzeStream(request) {
65
+ const body = { ...toBody(request), stream: true };
66
+ const response = await fetch(`${this.config.baseUrl}/api/ai/vision`, {
67
+ method: "POST",
68
+ headers: {
69
+ "CENCORI_API_KEY": this.config.apiKey,
70
+ "Content-Type": "application/json",
71
+ ...this.config.headers
72
+ },
73
+ body: JSON.stringify(body)
74
+ });
75
+ if (!response.ok) {
76
+ const data = await response.json().catch(() => ({}));
77
+ const message = data && typeof data === "object" && "message" in data && typeof data.message === "string" ? data.message : `Vision stream request failed with status ${response.status}`;
78
+ throw new Error(message);
79
+ }
80
+ if (!response.body) throw new Error("Response body is null");
81
+ const reader = response.body.getReader();
82
+ const decoder = new TextDecoder();
83
+ let buffer = "";
84
+ try {
85
+ while (true) {
86
+ const { done, value } = await reader.read();
87
+ if (done) break;
88
+ buffer += decoder.decode(value, { stream: true });
89
+ const lines = buffer.split("\n");
90
+ buffer = lines.pop() ?? "";
91
+ for (const line of lines) {
92
+ if (!line.startsWith("data: ")) continue;
93
+ const data = line.slice(6);
94
+ if (data === "[DONE]") return;
95
+ try {
96
+ yield JSON.parse(data);
97
+ } catch {
98
+ }
99
+ }
100
+ }
101
+ } finally {
102
+ reader.releaseLock();
103
+ }
104
+ }
43
105
  async post(path, request) {
44
106
  const response = await fetch(`${this.config.baseUrl}${path}`, {
45
107
  method: "POST",
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/vision/index.ts"],"sourcesContent":["/**\n * Vision API — analyze, describe, OCR, and classify images.\n *\n * @example\n * const result = await cencori.vision.analyze({\n * image: { url: 'https://example.com/photo.jpg' },\n * prompt: 'What breed of dog is this?',\n * });\n *\n * @example\n * const { text } = await cencori.vision.ocr({ image: { base64, mimeType: 'image/png' } });\n */\n\nimport type { CencoriConfig } from '../types';\n\nexport type VisionProvider = 'openai' | 'anthropic' | 'google';\n\nexport type VisionTask = 'analyze' | 'describe' | 'ocr' | 'classify';\n\nexport interface VisionImage {\n /** https:// URL or data: URL. Exactly one of `url` or `base64` must be set. */\n url?: string;\n /** Raw base64 (no data: prefix). Requires `mimeType`. */\n base64?: string;\n /** Image mime type. Required when using `base64`. */\n mimeType?: string;\n}\n\nexport interface VisionRequest {\n image: VisionImage;\n prompt?: string;\n model?: string;\n maxTokens?: number;\n temperature?: number;\n responseFormat?: 'text' | 'json';\n}\n\nexport interface VisionUsage {\n promptTokens: number;\n completionTokens: number;\n totalTokens: number;\n}\n\nexport interface VisionCost {\n providerCostUsd: number;\n cencoriChargeUsd: number;\n markupPercentage: number;\n}\n\nexport interface VisionResult {\n analysis: string;\n model: string;\n provider: VisionProvider;\n usage: VisionUsage;\n cost: VisionCost;\n}\n\nexport interface VisionDescribeResult {\n description: string;\n model: string;\n provider: VisionProvider;\n usage: VisionUsage;\n cost: VisionCost;\n}\n\nexport interface VisionOcrResult {\n text: string;\n model: string;\n provider: VisionProvider;\n usage: VisionUsage;\n cost: VisionCost;\n}\n\nexport interface VisionClassification {\n primary_category?: string;\n tags?: string[];\n objects?: string[];\n safe_for_work?: boolean;\n confidence?: number;\n summary?: string;\n [key: string]: unknown;\n}\n\nexport interface VisionClassifyResult {\n classification: VisionClassification | string;\n raw: string;\n model: string;\n provider: VisionProvider;\n usage: VisionUsage;\n cost: VisionCost;\n}\n\ninterface JsonBody {\n image_url?: string;\n image_base64?: string;\n mime_type?: string;\n prompt?: string;\n model?: string;\n max_tokens?: number;\n temperature?: number;\n response_format?: 'text' | 'json';\n}\n\nfunction toBody(request: VisionRequest): JsonBody {\n const body: JsonBody = {\n prompt: request.prompt,\n model: request.model,\n max_tokens: request.maxTokens,\n temperature: request.temperature,\n response_format: request.responseFormat,\n };\n if (request.image.url) {\n body.image_url = request.image.url;\n } else if (request.image.base64) {\n body.image_base64 = request.image.base64;\n body.mime_type = request.image.mimeType;\n } else {\n throw new Error('vision request requires image.url or image.base64');\n }\n return body;\n}\n\nexport class VisionNamespace {\n private config: Required<CencoriConfig>;\n\n constructor(config: Required<CencoriConfig>) {\n this.config = config;\n }\n\n /**\n * General image analysis — provide your own prompt.\n * Default prompt: \"Describe this image in detail.\"\n */\n async analyze(request: VisionRequest): Promise<VisionResult> {\n return this.post<VisionResult>('/api/ai/vision', request);\n }\n\n /** Describe the image in rich detail. */\n async describe(request: VisionRequest): Promise<VisionDescribeResult> {\n return this.post<VisionDescribeResult>('/api/ai/vision/describe', request);\n }\n\n /** Extract all visible text from the image. */\n async ocr(request: VisionRequest): Promise<VisionOcrResult> {\n return this.post<VisionOcrResult>('/api/ai/vision/ocr', request);\n }\n\n /** Return structured tags, objects, and category classification. */\n async classify(request: VisionRequest): Promise<VisionClassifyResult> {\n return this.post<VisionClassifyResult>('/api/ai/vision/classify', request);\n }\n\n private async post<T>(path: string, request: VisionRequest): 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(toBody(request)),\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 : `Vision 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":";AAuGA,SAAS,OAAO,SAAkC;AAC9C,QAAM,OAAiB;AAAA,IACnB,QAAQ,QAAQ;AAAA,IAChB,OAAO,QAAQ;AAAA,IACf,YAAY,QAAQ;AAAA,IACpB,aAAa,QAAQ;AAAA,IACrB,iBAAiB,QAAQ;AAAA,EAC7B;AACA,MAAI,QAAQ,MAAM,KAAK;AACnB,SAAK,YAAY,QAAQ,MAAM;AAAA,EACnC,WAAW,QAAQ,MAAM,QAAQ;AAC7B,SAAK,eAAe,QAAQ,MAAM;AAClC,SAAK,YAAY,QAAQ,MAAM;AAAA,EACnC,OAAO;AACH,UAAM,IAAI,MAAM,mDAAmD;AAAA,EACvE;AACA,SAAO;AACX;AAEO,IAAM,kBAAN,MAAsB;AAAA,EAGzB,YAAY,QAAiC;AACzC,SAAK,SAAS;AAAA,EAClB;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,QAAQ,SAA+C;AACzD,WAAO,KAAK,KAAmB,kBAAkB,OAAO;AAAA,EAC5D;AAAA;AAAA,EAGA,MAAM,SAAS,SAAuD;AAClE,WAAO,KAAK,KAA2B,2BAA2B,OAAO;AAAA,EAC7E;AAAA;AAAA,EAGA,MAAM,IAAI,SAAkD;AACxD,WAAO,KAAK,KAAsB,sBAAsB,OAAO;AAAA,EACnE;AAAA;AAAA,EAGA,MAAM,SAAS,SAAuD;AAClE,WAAO,KAAK,KAA2B,2BAA2B,OAAO;AAAA,EAC7E;AAAA,EAEA,MAAc,KAAQ,MAAc,SAAoC;AACpE,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,OAAO,OAAO,CAAC;AAAA,IACxC,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,qCAAqC,SAAS,MAAM;AAC9D,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":[]}
1
+ {"version":3,"sources":["../../src/vision/index.ts"],"sourcesContent":["/**\n * Vision API — analyze, describe, OCR, and classify images.\n *\n * @example\n * const result = await cencori.vision.analyze({\n * image: { url: 'https://example.com/photo.jpg' },\n * prompt: 'What breed of dog is this?',\n * });\n *\n * @example\n * const { text } = await cencori.vision.ocr({ image: { base64, mimeType: 'image/png' } });\n */\n\nimport type { CencoriConfig } from '../types';\n\nexport type VisionProvider = 'openai' | 'anthropic' | 'google';\n\nexport type VisionTask = 'analyze' | 'describe' | 'ocr' | 'classify';\n\nexport interface VisionImage {\n /** https:// URL or data: URL. Exactly one of `url` or `base64` must be set. */\n url?: string;\n /** Raw base64 (no data: prefix). Requires `mimeType`. */\n base64?: string;\n /** Image mime type. Required when using `base64`. */\n mimeType?: string;\n}\n\nexport interface VisionRequest {\n /** Single image. Use this OR `images`. */\n image?: VisionImage;\n /** Multiple images to analyze together. */\n images?: VisionImage[];\n prompt?: string;\n model?: string;\n maxTokens?: number;\n temperature?: number;\n responseFormat?: 'text' | 'json';\n}\n\nexport interface VisionStreamChunk {\n delta?: string;\n done?: boolean;\n model?: string;\n provider?: VisionProvider;\n usage?: VisionUsage;\n cost?: VisionCost;\n error?: string;\n}\n\nexport interface VisionUsage {\n promptTokens: number;\n completionTokens: number;\n totalTokens: number;\n}\n\nexport interface VisionCost {\n providerCostUsd: number;\n cencoriChargeUsd: number;\n markupPercentage: number;\n}\n\nexport interface VisionResult {\n analysis: string;\n model: string;\n provider: VisionProvider;\n usage: VisionUsage;\n cost: VisionCost;\n}\n\nexport interface VisionDescribeResult {\n description: string;\n model: string;\n provider: VisionProvider;\n usage: VisionUsage;\n cost: VisionCost;\n}\n\nexport interface VisionOcrResult {\n text: string;\n model: string;\n provider: VisionProvider;\n usage: VisionUsage;\n cost: VisionCost;\n}\n\nexport interface VisionClassification {\n primary_category?: string;\n tags?: string[];\n objects?: string[];\n safe_for_work?: boolean;\n confidence?: number;\n summary?: string;\n [key: string]: unknown;\n}\n\nexport interface VisionClassifyResult {\n classification: VisionClassification | string;\n raw: string;\n model: string;\n provider: VisionProvider;\n usage: VisionUsage;\n cost: VisionCost;\n}\n\ninterface JsonBody {\n image_url?: string;\n image_base64?: string;\n mime_type?: string;\n images?: Array<{ url?: string; base64?: string; mime_type?: string }>;\n prompt?: string;\n model?: string;\n max_tokens?: number;\n temperature?: number;\n response_format?: 'text' | 'json';\n}\n\nfunction toBody(request: VisionRequest): JsonBody {\n const body: JsonBody = {\n prompt: request.prompt,\n model: request.model,\n max_tokens: request.maxTokens,\n temperature: request.temperature,\n response_format: request.responseFormat,\n };\n\n if (request.images && request.images.length > 0) {\n body.images = request.images.map(img => {\n if (img.url) return { url: img.url };\n if (img.base64) return { base64: img.base64, mime_type: img.mimeType };\n throw new Error('Each entry in images requires url or base64');\n });\n return body;\n }\n if (!request.image) {\n throw new Error('vision request requires `image` or `images[]`');\n }\n if (request.image.url) {\n body.image_url = request.image.url;\n } else if (request.image.base64) {\n body.image_base64 = request.image.base64;\n body.mime_type = request.image.mimeType;\n } else {\n throw new Error('vision request requires image.url or image.base64');\n }\n return body;\n}\n\nexport class VisionNamespace {\n private config: Required<CencoriConfig>;\n\n constructor(config: Required<CencoriConfig>) {\n this.config = config;\n }\n\n /**\n * General image analysis — provide your own prompt.\n * Default prompt: \"Describe this image in detail.\"\n */\n async analyze(request: VisionRequest): Promise<VisionResult> {\n return this.post<VisionResult>('/api/ai/vision', request);\n }\n\n /** Describe the image in rich detail. */\n async describe(request: VisionRequest): Promise<VisionDescribeResult> {\n return this.post<VisionDescribeResult>('/api/ai/vision/describe', request);\n }\n\n /** Extract all visible text from the image. */\n async ocr(request: VisionRequest): Promise<VisionOcrResult> {\n return this.post<VisionOcrResult>('/api/ai/vision/ocr', request);\n }\n\n /** Return structured tags, objects, and category classification. */\n async classify(request: VisionRequest): Promise<VisionClassifyResult> {\n return this.post<VisionClassifyResult>('/api/ai/vision/classify', request);\n }\n\n /**\n * Stream a vision analysis. Yields `{ delta }` chunks as text arrives, then\n * a final `{ done: true, model, provider, usage, cost }` chunk with totals.\n *\n * @example\n * for await (const chunk of cencori.vision.analyzeStream({ image: { url } })) {\n * if (chunk.delta) process.stdout.write(chunk.delta);\n * if (chunk.done) console.log(chunk.cost);\n * }\n */\n async *analyzeStream(request: VisionRequest): AsyncGenerator<VisionStreamChunk, void, unknown> {\n const body = { ...toBody(request), stream: true };\n const response = await fetch(`${this.config.baseUrl}/api/ai/vision`, {\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 if (!response.ok) {\n const data = await response.json().catch(() => ({}));\n const message =\n (data && typeof data === 'object' && 'message' in data && typeof data.message === 'string')\n ? data.message\n : `Vision stream request failed with status ${response.status}`;\n throw new Error(message);\n }\n if (!response.body) throw new Error('Response body is null');\n\n const reader = response.body.getReader();\n const decoder = new TextDecoder();\n let buffer = '';\n try {\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n buffer += decoder.decode(value, { stream: true });\n const lines = buffer.split('\\n');\n buffer = lines.pop() ?? '';\n for (const line of lines) {\n if (!line.startsWith('data: ')) continue;\n const data = line.slice(6);\n if (data === '[DONE]') return;\n try {\n yield JSON.parse(data) as VisionStreamChunk;\n } catch {\n // skip malformed frame\n }\n }\n }\n } finally {\n reader.releaseLock();\n }\n }\n\n private async post<T>(path: string, request: VisionRequest): 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(toBody(request)),\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 : `Vision 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":"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","names":[]}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "$schema": "https://json.schemastore.org/package.json",
3
3
  "name": "cencori",
4
- "version": "1.3.0",
4
+ "version": "1.4.0",
5
5
  "description": "Cencori - The unified infrastructure layer for AI applications. One SDK for AI Gateway, Compute, Workflow, and Storage.",
6
6
  "main": "dist/index.js",
7
7
  "module": "dist/index.mjs",
@@ -32,6 +32,11 @@
32
32
  "import": "./dist/vision/index.mjs",
33
33
  "require": "./dist/vision/index.js"
34
34
  },
35
+ "./documents": {
36
+ "types": "./dist/documents/index.d.ts",
37
+ "import": "./dist/documents/index.mjs",
38
+ "require": "./dist/documents/index.js"
39
+ },
35
40
  "./react": {
36
41
  "types": "./dist/react/index.d.ts",
37
42
  "import": "./dist/react/index.mjs",