@intelligentelectron/pdf-analyzer 0.1.6 → 1.0.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 +4 -9
- package/dist/cli/commands.d.ts +9 -1
- package/dist/cli/commands.d.ts.map +1 -1
- package/dist/cli/commands.js +96 -25
- package/dist/cli/commands.js.map +1 -1
- package/dist/index.d.ts +2 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +13 -4
- package/dist/index.js.map +1 -1
- package/dist/keychain.d.ts +34 -0
- package/dist/keychain.d.ts.map +1 -0
- package/dist/keychain.js +208 -0
- package/dist/keychain.js.map +1 -0
- package/dist/pdf-utils.d.ts +28 -0
- package/dist/pdf-utils.d.ts.map +1 -0
- package/dist/pdf-utils.js +93 -0
- package/dist/pdf-utils.js.map +1 -0
- package/dist/providers/anthropic.d.ts +9 -0
- package/dist/providers/anthropic.d.ts.map +1 -0
- package/dist/providers/anthropic.js +69 -0
- package/dist/providers/anthropic.js.map +1 -0
- package/dist/providers/google.d.ts +13 -0
- package/dist/providers/google.d.ts.map +1 -0
- package/dist/providers/google.js +120 -0
- package/dist/providers/google.js.map +1 -0
- package/dist/providers/openai.d.ts +9 -0
- package/dist/providers/openai.d.ts.map +1 -0
- package/dist/providers/openai.js +70 -0
- package/dist/providers/openai.js.map +1 -0
- package/dist/providers/registry.d.ts +23 -0
- package/dist/providers/registry.d.ts.map +1 -0
- package/dist/providers/registry.js +44 -0
- package/dist/providers/registry.js.map +1 -0
- package/dist/providers/types.d.ts +70 -0
- package/dist/providers/types.d.ts.map +1 -0
- package/dist/providers/types.js +2 -0
- package/dist/providers/types.js.map +1 -0
- package/dist/server.d.ts +2 -1
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +27 -35
- package/dist/server.js.map +1 -1
- package/dist/service.d.ts +7 -35
- package/dist/service.d.ts.map +1 -1
- package/dist/service.js +99 -302
- package/dist/service.js.map +1 -1
- package/dist/types.d.ts +20 -12
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +15 -45
- package/dist/types.js.map +1 -1
- package/package.json +12 -4
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared PDF utility functions.
|
|
3
|
+
*
|
|
4
|
+
* Contains URL validation, path validation, and PDF fetching logic
|
|
5
|
+
* used by both the service layer and provider implementations.
|
|
6
|
+
*/
|
|
7
|
+
import * as fs from "node:fs";
|
|
8
|
+
import * as path from "node:path";
|
|
9
|
+
/** Gemini File API URI prefix. */
|
|
10
|
+
const GEMINI_FILE_URI_PREFIX = "https://generativelanguage.googleapis.com/";
|
|
11
|
+
/**
|
|
12
|
+
* Check if a string is a Gemini File API URI.
|
|
13
|
+
*/
|
|
14
|
+
export function isGeminiFileUri(source) {
|
|
15
|
+
return source.startsWith(GEMINI_FILE_URI_PREFIX);
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Check if a string is a URL (excluding Gemini File API URIs).
|
|
19
|
+
*/
|
|
20
|
+
export function isUrl(source) {
|
|
21
|
+
if (isGeminiFileUri(source)) {
|
|
22
|
+
return false;
|
|
23
|
+
}
|
|
24
|
+
try {
|
|
25
|
+
const url = new URL(source);
|
|
26
|
+
return url.protocol === "http:" || url.protocol === "https:";
|
|
27
|
+
}
|
|
28
|
+
catch {
|
|
29
|
+
return false;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Validates a local PDF file path.
|
|
34
|
+
* Throws descriptive errors for common issues.
|
|
35
|
+
*/
|
|
36
|
+
export function validateLocalPath(pdfPath) {
|
|
37
|
+
const trimmedPath = pdfPath.trim();
|
|
38
|
+
if (!path.isAbsolute(trimmedPath)) {
|
|
39
|
+
throw new Error(`PDF path must be absolute: ${trimmedPath}`);
|
|
40
|
+
}
|
|
41
|
+
if (!fs.existsSync(trimmedPath)) {
|
|
42
|
+
throw new Error(`PDF file not found: ${trimmedPath}`);
|
|
43
|
+
}
|
|
44
|
+
const stats = fs.statSync(trimmedPath);
|
|
45
|
+
if (stats.isDirectory()) {
|
|
46
|
+
throw new Error(`Path is a directory, not a file: ${trimmedPath}`);
|
|
47
|
+
}
|
|
48
|
+
if (!trimmedPath.toLowerCase().endsWith(".pdf")) {
|
|
49
|
+
throw new Error(`File is not a PDF: ${trimmedPath}`);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
/** Timeout for fetching PDFs from URLs (60 seconds). */
|
|
53
|
+
const FETCH_TIMEOUT_MS = 60_000;
|
|
54
|
+
/**
|
|
55
|
+
* Fetch PDF content from a URL with timeout.
|
|
56
|
+
*/
|
|
57
|
+
export async function fetchPdfFromUrl(url) {
|
|
58
|
+
const controller = new AbortController();
|
|
59
|
+
const timeoutId = setTimeout(() => controller.abort(), FETCH_TIMEOUT_MS);
|
|
60
|
+
let response;
|
|
61
|
+
try {
|
|
62
|
+
response = await fetch(url, { signal: controller.signal });
|
|
63
|
+
}
|
|
64
|
+
catch (error) {
|
|
65
|
+
if (error instanceof Error && error.name === "AbortError") {
|
|
66
|
+
throw new Error(`Request timed out after ${FETCH_TIMEOUT_MS / 1000}s`);
|
|
67
|
+
}
|
|
68
|
+
const message = error instanceof Error ? error.message : "Unknown error";
|
|
69
|
+
throw new Error(`Failed to fetch URL: ${message}`);
|
|
70
|
+
}
|
|
71
|
+
finally {
|
|
72
|
+
clearTimeout(timeoutId);
|
|
73
|
+
}
|
|
74
|
+
if (!response.ok) {
|
|
75
|
+
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
|
|
76
|
+
}
|
|
77
|
+
const contentType = response.headers.get("content-type");
|
|
78
|
+
if (contentType &&
|
|
79
|
+
!contentType.includes("application/pdf") &&
|
|
80
|
+
!contentType.includes("octet-stream")) {
|
|
81
|
+
throw new Error(`URL does not point to a PDF file. Content-Type: ${contentType}`);
|
|
82
|
+
}
|
|
83
|
+
const arrayBuffer = await response.arrayBuffer();
|
|
84
|
+
return Buffer.from(arrayBuffer);
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Read PDF bytes from a local file path.
|
|
88
|
+
*/
|
|
89
|
+
export function readPdfBytes(pdfPath) {
|
|
90
|
+
validateLocalPath(pdfPath);
|
|
91
|
+
return fs.readFileSync(pdfPath.trim());
|
|
92
|
+
}
|
|
93
|
+
//# sourceMappingURL=pdf-utils.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pdf-utils.js","sourceRoot":"","sources":["../src/pdf-utils.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAC9B,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAElC,kCAAkC;AAClC,MAAM,sBAAsB,GAAG,4CAA4C,CAAC;AAE5E;;GAEG;AACH,MAAM,UAAU,eAAe,CAAC,MAAc;IAC5C,OAAO,MAAM,CAAC,UAAU,CAAC,sBAAsB,CAAC,CAAC;AACnD,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,KAAK,CAAC,MAAc;IAClC,IAAI,eAAe,CAAC,MAAM,CAAC,EAAE,CAAC;QAC5B,OAAO,KAAK,CAAC;IACf,CAAC;IACD,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,CAAC;QAC5B,OAAO,GAAG,CAAC,QAAQ,KAAK,OAAO,IAAI,GAAG,CAAC,QAAQ,KAAK,QAAQ,CAAC;IAC/D,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,iBAAiB,CAAC,OAAe;IAC/C,MAAM,WAAW,GAAG,OAAO,CAAC,IAAI,EAAE,CAAC;IAEnC,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,WAAW,CAAC,EAAE,CAAC;QAClC,MAAM,IAAI,KAAK,CAAC,8BAA8B,WAAW,EAAE,CAAC,CAAC;IAC/D,CAAC;IAED,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,WAAW,CAAC,EAAE,CAAC;QAChC,MAAM,IAAI,KAAK,CAAC,uBAAuB,WAAW,EAAE,CAAC,CAAC;IACxD,CAAC;IAED,MAAM,KAAK,GAAG,EAAE,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC;IACvC,IAAI,KAAK,CAAC,WAAW,EAAE,EAAE,CAAC;QACxB,MAAM,IAAI,KAAK,CAAC,oCAAoC,WAAW,EAAE,CAAC,CAAC;IACrE,CAAC;IAED,IAAI,CAAC,WAAW,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC;QAChD,MAAM,IAAI,KAAK,CAAC,sBAAsB,WAAW,EAAE,CAAC,CAAC;IACvD,CAAC;AACH,CAAC;AAED,wDAAwD;AACxD,MAAM,gBAAgB,GAAG,MAAM,CAAC;AAEhC;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,GAAW;IAC/C,MAAM,UAAU,GAAG,IAAI,eAAe,EAAE,CAAC;IACzC,MAAM,SAAS,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC,UAAU,CAAC,KAAK,EAAE,EAAE,gBAAgB,CAAC,CAAC;IAEzE,IAAI,QAAkB,CAAC;IACvB,IAAI,CAAC;QACH,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,EAAE,EAAE,MAAM,EAAE,UAAU,CAAC,MAAM,EAAE,CAAC,CAAC;IAC7D,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAI,KAAK,YAAY,KAAK,IAAI,KAAK,CAAC,IAAI,KAAK,YAAY,EAAE,CAAC;YAC1D,MAAM,IAAI,KAAK,CAAC,2BAA2B,gBAAgB,GAAG,IAAI,GAAG,CAAC,CAAC;QACzE,CAAC;QACD,MAAM,OAAO,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,eAAe,CAAC;QACzE,MAAM,IAAI,KAAK,CAAC,wBAAwB,OAAO,EAAE,CAAC,CAAC;IACrD,CAAC;YAAS,CAAC;QACT,YAAY,CAAC,SAAS,CAAC,CAAC;IAC1B,CAAC;IAED,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;QACjB,MAAM,IAAI,KAAK,CAAC,QAAQ,QAAQ,CAAC,MAAM,KAAK,QAAQ,CAAC,UAAU,EAAE,CAAC,CAAC;IACrE,CAAC;IAED,MAAM,WAAW,GAAG,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;IACzD,IACE,WAAW;QACX,CAAC,WAAW,CAAC,QAAQ,CAAC,iBAAiB,CAAC;QACxC,CAAC,WAAW,CAAC,QAAQ,CAAC,cAAc,CAAC,EACrC,CAAC;QACD,MAAM,IAAI,KAAK,CAAC,mDAAmD,WAAW,EAAE,CAAC,CAAC;IACpF,CAAC;IAED,MAAM,WAAW,GAAG,MAAM,QAAQ,CAAC,WAAW,EAAE,CAAC;IACjD,OAAO,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;AAClC,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,YAAY,CAAC,OAAe;IAC1C,iBAAiB,CAAC,OAAO,CAAC,CAAC;IAC3B,OAAO,EAAE,CAAC,YAAY,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC;AACzC,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Anthropic Claude provider.
|
|
3
|
+
*
|
|
4
|
+
* Sends PDFs inline as base64/bytes content parts.
|
|
5
|
+
* No File API, no caching.
|
|
6
|
+
*/
|
|
7
|
+
import type { ProviderConfig } from "./types.js";
|
|
8
|
+
export declare const anthropicProvider: ProviderConfig;
|
|
9
|
+
//# sourceMappingURL=anthropic.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"anthropic.d.ts","sourceRoot":"","sources":["../../src/providers/anthropic.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,KAAK,EAAE,cAAc,EAAoD,MAAM,YAAY,CAAC;AAuDnG,eAAO,MAAM,iBAAiB,EAAE,cAa/B,CAAC"}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Anthropic Claude provider.
|
|
3
|
+
*
|
|
4
|
+
* Sends PDFs inline as base64/bytes content parts.
|
|
5
|
+
* No File API, no caching.
|
|
6
|
+
*/
|
|
7
|
+
import { createAnthropic } from "@ai-sdk/anthropic";
|
|
8
|
+
import { fetchPdfFromUrl, readPdfBytes } from "../pdf-utils.js";
|
|
9
|
+
const MODELS = [
|
|
10
|
+
{
|
|
11
|
+
id: "claude-sonnet-4-6",
|
|
12
|
+
displayName: "Claude Sonnet 4.6",
|
|
13
|
+
hint: "Fast and cost-effective",
|
|
14
|
+
},
|
|
15
|
+
{ id: "claude-opus-4-6", displayName: "Claude Opus 4.6", hint: "Best and most expensive" },
|
|
16
|
+
];
|
|
17
|
+
const DEFAULT_MODEL = "claude-opus-4-6";
|
|
18
|
+
/**
|
|
19
|
+
* Prepare a PDF source for Anthropic by reading bytes inline.
|
|
20
|
+
*/
|
|
21
|
+
async function preparePdf(source) {
|
|
22
|
+
if (source.kind === "cachedUri") {
|
|
23
|
+
throw new Error("Cached URIs are only supported with the Google provider.");
|
|
24
|
+
}
|
|
25
|
+
let bytes;
|
|
26
|
+
if (source.kind === "bytes") {
|
|
27
|
+
bytes = source.bytes;
|
|
28
|
+
}
|
|
29
|
+
else if (source.kind === "url") {
|
|
30
|
+
bytes = new Uint8Array(await fetchPdfFromUrl(source.url));
|
|
31
|
+
}
|
|
32
|
+
else {
|
|
33
|
+
bytes = new Uint8Array(await readPdfBytes(source.path));
|
|
34
|
+
}
|
|
35
|
+
const part = {
|
|
36
|
+
type: "file",
|
|
37
|
+
data: bytes,
|
|
38
|
+
mediaType: "application/pdf",
|
|
39
|
+
};
|
|
40
|
+
return { fileParts: [part], cachedUri: null };
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Check if an error is an Anthropic token limit error.
|
|
44
|
+
*/
|
|
45
|
+
function isTokenLimitError(error) {
|
|
46
|
+
if (!(error instanceof Error))
|
|
47
|
+
return false;
|
|
48
|
+
const msg = error.message.toLowerCase();
|
|
49
|
+
return (msg.includes("too many input tokens") ||
|
|
50
|
+
msg.includes("prompt is too long") ||
|
|
51
|
+
msg.includes("maximum context length") ||
|
|
52
|
+
msg.includes("maximum of 100 pdf pages") ||
|
|
53
|
+
msg.includes("pdf pages may be provided"));
|
|
54
|
+
}
|
|
55
|
+
export const anthropicProvider = {
|
|
56
|
+
id: "anthropic",
|
|
57
|
+
displayName: "Anthropic Claude",
|
|
58
|
+
models: MODELS,
|
|
59
|
+
defaultModel: DEFAULT_MODEL,
|
|
60
|
+
apiKeyUrl: "https://console.anthropic.com/settings/keys",
|
|
61
|
+
createModel: (apiKey, modelId) => {
|
|
62
|
+
const anthropic = createAnthropic({ apiKey });
|
|
63
|
+
return anthropic(modelId);
|
|
64
|
+
},
|
|
65
|
+
providerOptions: {},
|
|
66
|
+
preparePdf,
|
|
67
|
+
isTokenLimitError,
|
|
68
|
+
};
|
|
69
|
+
//# sourceMappingURL=anthropic.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"anthropic.js","sourceRoot":"","sources":["../../src/providers/anthropic.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAEpD,OAAO,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAEhE,MAAM,MAAM,GAAkB;IAC5B;QACE,EAAE,EAAE,mBAAmB;QACvB,WAAW,EAAE,mBAAmB;QAChC,IAAI,EAAE,yBAAyB;KAChC;IACD,EAAE,EAAE,EAAE,iBAAiB,EAAE,WAAW,EAAE,iBAAiB,EAAE,IAAI,EAAE,yBAAyB,EAAE;CAC3F,CAAC;AAEF,MAAM,aAAa,GAAG,iBAAiB,CAAC;AAExC;;GAEG;AACH,KAAK,UAAU,UAAU,CAAC,MAAiB;IACzC,IAAI,MAAM,CAAC,IAAI,KAAK,WAAW,EAAE,CAAC;QAChC,MAAM,IAAI,KAAK,CAAC,0DAA0D,CAAC,CAAC;IAC9E,CAAC;IAED,IAAI,KAAiB,CAAC;IAEtB,IAAI,MAAM,CAAC,IAAI,KAAK,OAAO,EAAE,CAAC;QAC5B,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC;IACvB,CAAC;SAAM,IAAI,MAAM,CAAC,IAAI,KAAK,KAAK,EAAE,CAAC;QACjC,KAAK,GAAG,IAAI,UAAU,CAAC,MAAM,eAAe,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;IAC5D,CAAC;SAAM,CAAC;QACN,KAAK,GAAG,IAAI,UAAU,CAAC,MAAM,YAAY,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC;IAC1D,CAAC;IAED,MAAM,IAAI,GAAgB;QACxB,IAAI,EAAE,MAAM;QACZ,IAAI,EAAE,KAAK;QACX,SAAS,EAAE,iBAAiB;KAC7B,CAAC;IACF,OAAO,EAAE,SAAS,EAAE,CAAC,IAAI,CAAC,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC;AAChD,CAAC;AAED;;GAEG;AACH,SAAS,iBAAiB,CAAC,KAAc;IACvC,IAAI,CAAC,CAAC,KAAK,YAAY,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC;IAC5C,MAAM,GAAG,GAAG,KAAK,CAAC,OAAO,CAAC,WAAW,EAAE,CAAC;IACxC,OAAO,CACL,GAAG,CAAC,QAAQ,CAAC,uBAAuB,CAAC;QACrC,GAAG,CAAC,QAAQ,CAAC,oBAAoB,CAAC;QAClC,GAAG,CAAC,QAAQ,CAAC,wBAAwB,CAAC;QACtC,GAAG,CAAC,QAAQ,CAAC,0BAA0B,CAAC;QACxC,GAAG,CAAC,QAAQ,CAAC,2BAA2B,CAAC,CAC1C,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,MAAM,iBAAiB,GAAmB;IAC/C,EAAE,EAAE,WAAW;IACf,WAAW,EAAE,kBAAkB;IAC/B,MAAM,EAAE,MAAM;IACd,YAAY,EAAE,aAAa;IAC3B,SAAS,EAAE,6CAA6C;IACxD,WAAW,EAAE,CAAC,MAAc,EAAE,OAAe,EAAE,EAAE;QAC/C,MAAM,SAAS,GAAG,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC;QAC9C,OAAO,SAAS,CAAC,OAAO,CAAC,CAAC;IAC5B,CAAC;IACD,eAAe,EAAE,EAAE;IACnB,UAAU;IACV,iBAAiB;CAClB,CAAC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Google Gemini provider.
|
|
3
|
+
*
|
|
4
|
+
* Uses the Gemini File API for uploading PDFs (supports large files and caching),
|
|
5
|
+
* and the Vercel AI SDK for LLM calls.
|
|
6
|
+
*/
|
|
7
|
+
import type { ProviderConfig } from "./types.js";
|
|
8
|
+
/**
|
|
9
|
+
* Check if a string is a Gemini File API URI.
|
|
10
|
+
*/
|
|
11
|
+
export declare function isGeminiFileUri(source: string): boolean;
|
|
12
|
+
export declare const googleProvider: ProviderConfig;
|
|
13
|
+
//# sourceMappingURL=google.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"google.d.ts","sourceRoot":"","sources":["../../src/providers/google.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,OAAO,KAAK,EAAE,cAAc,EAAoD,MAAM,YAAY,CAAC;AAiBnG;;GAEG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAEvD;AA6FD,eAAO,MAAM,cAAc,EAAE,cAe5B,CAAC"}
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Google Gemini provider.
|
|
3
|
+
*
|
|
4
|
+
* Uses the Gemini File API for uploading PDFs (supports large files and caching),
|
|
5
|
+
* and the Vercel AI SDK for LLM calls.
|
|
6
|
+
*/
|
|
7
|
+
import { GoogleGenAI, ApiError } from "@google/genai";
|
|
8
|
+
import { createGoogleGenerativeAI } from "@ai-sdk/google";
|
|
9
|
+
import { fetchPdfFromUrl, validateLocalPath } from "../pdf-utils.js";
|
|
10
|
+
const MODELS = [
|
|
11
|
+
{
|
|
12
|
+
id: "gemini-3-flash-preview",
|
|
13
|
+
displayName: "Gemini 3 Flash",
|
|
14
|
+
hint: "Fast and cost-effective",
|
|
15
|
+
},
|
|
16
|
+
{ id: "gemini-3.1-pro-preview", displayName: "Gemini 3.1 Pro", hint: "Best and most expensive" },
|
|
17
|
+
];
|
|
18
|
+
const DEFAULT_MODEL = "gemini-3.1-pro-preview";
|
|
19
|
+
/** Gemini File API URI prefix. */
|
|
20
|
+
const GEMINI_FILE_URI_PREFIX = "https://generativelanguage.googleapis.com/";
|
|
21
|
+
/**
|
|
22
|
+
* Check if a string is a Gemini File API URI.
|
|
23
|
+
*/
|
|
24
|
+
export function isGeminiFileUri(source) {
|
|
25
|
+
return source.startsWith(GEMINI_FILE_URI_PREFIX);
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Wait for a file to finish processing on the Gemini File API.
|
|
29
|
+
*/
|
|
30
|
+
async function waitForFileReady(client, fileName, maxAttempts = 10) {
|
|
31
|
+
for (let i = 0; i < maxAttempts; i++) {
|
|
32
|
+
const fileInfo = await client.files.get({ name: fileName });
|
|
33
|
+
if (fileInfo.state === "FAILED") {
|
|
34
|
+
throw new Error(`File processing failed: ${fileInfo.name}`);
|
|
35
|
+
}
|
|
36
|
+
if (fileInfo.state !== "PROCESSING") {
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
await new Promise((resolve) => setTimeout(resolve, 2000));
|
|
40
|
+
}
|
|
41
|
+
throw new Error("File processing timed out");
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Upload a PDF to the Gemini File API.
|
|
45
|
+
* Returns the Gemini File API URI.
|
|
46
|
+
*/
|
|
47
|
+
async function uploadToFileApi(client, data) {
|
|
48
|
+
const file = await client.files.upload(typeof data === "string"
|
|
49
|
+
? { file: data, config: { mimeType: "application/pdf" } }
|
|
50
|
+
: { file: data, config: { mimeType: "application/pdf" } });
|
|
51
|
+
if (!file.name || !file.uri) {
|
|
52
|
+
throw new Error("File upload failed: missing name or URI");
|
|
53
|
+
}
|
|
54
|
+
await waitForFileReady(client, file.name);
|
|
55
|
+
return file.uri;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Prepare a PDF source for Google Gemini.
|
|
59
|
+
* Uploads to the File API and returns a URL-based file part.
|
|
60
|
+
*/
|
|
61
|
+
async function preparePdf(source, apiKey) {
|
|
62
|
+
const client = new GoogleGenAI({ apiKey });
|
|
63
|
+
if (source.kind === "cachedUri") {
|
|
64
|
+
const part = {
|
|
65
|
+
type: "file",
|
|
66
|
+
data: new URL(source.uri),
|
|
67
|
+
mediaType: "application/pdf",
|
|
68
|
+
};
|
|
69
|
+
return { fileParts: [part], cachedUri: source.uri };
|
|
70
|
+
}
|
|
71
|
+
let fileUri;
|
|
72
|
+
if (source.kind === "bytes") {
|
|
73
|
+
const blob = new Blob([source.bytes], { type: "application/pdf" });
|
|
74
|
+
fileUri = await uploadToFileApi(client, blob);
|
|
75
|
+
}
|
|
76
|
+
else if (source.kind === "url") {
|
|
77
|
+
const pdfBuffer = await fetchPdfFromUrl(source.url);
|
|
78
|
+
const blob = new Blob([pdfBuffer], { type: "application/pdf" });
|
|
79
|
+
fileUri = await uploadToFileApi(client, blob);
|
|
80
|
+
}
|
|
81
|
+
else {
|
|
82
|
+
validateLocalPath(source.path);
|
|
83
|
+
fileUri = await uploadToFileApi(client, source.path);
|
|
84
|
+
}
|
|
85
|
+
const part = {
|
|
86
|
+
type: "file",
|
|
87
|
+
data: new URL(fileUri),
|
|
88
|
+
mediaType: "application/pdf",
|
|
89
|
+
};
|
|
90
|
+
return { fileParts: [part], cachedUri: fileUri };
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Check if an error is a Gemini token limit error.
|
|
94
|
+
*/
|
|
95
|
+
function isTokenLimitError(error) {
|
|
96
|
+
if (error instanceof ApiError) {
|
|
97
|
+
return error.status === 400 && error.message.includes("input token count exceeds");
|
|
98
|
+
}
|
|
99
|
+
if (error instanceof Error) {
|
|
100
|
+
return error.message.includes("input token count exceeds");
|
|
101
|
+
}
|
|
102
|
+
return false;
|
|
103
|
+
}
|
|
104
|
+
export const googleProvider = {
|
|
105
|
+
id: "google",
|
|
106
|
+
displayName: "Google Gemini",
|
|
107
|
+
models: MODELS,
|
|
108
|
+
defaultModel: DEFAULT_MODEL,
|
|
109
|
+
apiKeyUrl: "https://aistudio.google.com/apikey",
|
|
110
|
+
createModel: (apiKey, modelId) => {
|
|
111
|
+
const google = createGoogleGenerativeAI({ apiKey });
|
|
112
|
+
return google(modelId);
|
|
113
|
+
},
|
|
114
|
+
providerOptions: {
|
|
115
|
+
google: { thinkingConfig: { thinkingLevel: "low" } },
|
|
116
|
+
},
|
|
117
|
+
preparePdf,
|
|
118
|
+
isTokenLimitError,
|
|
119
|
+
};
|
|
120
|
+
//# sourceMappingURL=google.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"google.js","sourceRoot":"","sources":["../../src/providers/google.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"openai.d.ts","sourceRoot":"","sources":["../../src/providers/openai.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,KAAK,EAAE,cAAc,EAAoD,MAAM,YAAY,CAAC;AAsDnG,eAAO,MAAM,cAAc,EAAE,cAe5B,CAAC"}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OpenAI provider.
|
|
3
|
+
*
|
|
4
|
+
* Sends PDFs inline as bytes content parts.
|
|
5
|
+
* No File API, no caching.
|
|
6
|
+
*/
|
|
7
|
+
import { createOpenAI } from "@ai-sdk/openai";
|
|
8
|
+
import { fetchPdfFromUrl, readPdfBytes } from "../pdf-utils.js";
|
|
9
|
+
const MODELS = [
|
|
10
|
+
{
|
|
11
|
+
id: "gpt-5.4-mini",
|
|
12
|
+
displayName: "GPT-5.4 Mini",
|
|
13
|
+
hint: "Fast and cost-effective",
|
|
14
|
+
},
|
|
15
|
+
{ id: "gpt-5.4", displayName: "GPT-5.4", hint: "Best and most expensive" },
|
|
16
|
+
];
|
|
17
|
+
const DEFAULT_MODEL = "gpt-5.4";
|
|
18
|
+
/**
|
|
19
|
+
* Prepare a PDF source for OpenAI by reading bytes inline.
|
|
20
|
+
*/
|
|
21
|
+
async function preparePdf(source) {
|
|
22
|
+
if (source.kind === "cachedUri") {
|
|
23
|
+
throw new Error("Cached URIs are only supported with the Google provider.");
|
|
24
|
+
}
|
|
25
|
+
let bytes;
|
|
26
|
+
if (source.kind === "bytes") {
|
|
27
|
+
bytes = source.bytes;
|
|
28
|
+
}
|
|
29
|
+
else if (source.kind === "url") {
|
|
30
|
+
bytes = new Uint8Array(await fetchPdfFromUrl(source.url));
|
|
31
|
+
}
|
|
32
|
+
else {
|
|
33
|
+
bytes = new Uint8Array(await readPdfBytes(source.path));
|
|
34
|
+
}
|
|
35
|
+
const part = {
|
|
36
|
+
type: "file",
|
|
37
|
+
data: bytes,
|
|
38
|
+
mediaType: "application/pdf",
|
|
39
|
+
};
|
|
40
|
+
return { fileParts: [part], cachedUri: null };
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Check if an error is an OpenAI token limit error.
|
|
44
|
+
*/
|
|
45
|
+
function isTokenLimitError(error) {
|
|
46
|
+
if (!(error instanceof Error))
|
|
47
|
+
return false;
|
|
48
|
+
const msg = error.message.toLowerCase();
|
|
49
|
+
return (msg.includes("maximum context length") ||
|
|
50
|
+
msg.includes("exceeds the context window") ||
|
|
51
|
+
msg.includes("too many tokens") ||
|
|
52
|
+
msg.includes("request too large"));
|
|
53
|
+
}
|
|
54
|
+
export const openaiProvider = {
|
|
55
|
+
id: "openai",
|
|
56
|
+
displayName: "OpenAI GPT",
|
|
57
|
+
models: MODELS,
|
|
58
|
+
defaultModel: DEFAULT_MODEL,
|
|
59
|
+
apiKeyUrl: "https://platform.openai.com/api-keys",
|
|
60
|
+
createModel: (apiKey, modelId) => {
|
|
61
|
+
const openai = createOpenAI({ apiKey });
|
|
62
|
+
return openai(modelId);
|
|
63
|
+
},
|
|
64
|
+
providerOptions: {
|
|
65
|
+
openai: { reasoningEffort: "low" },
|
|
66
|
+
},
|
|
67
|
+
preparePdf,
|
|
68
|
+
isTokenLimitError,
|
|
69
|
+
};
|
|
70
|
+
//# sourceMappingURL=openai.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"openai.js","sourceRoot":"","sources":["../../src/providers/openai.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAE9C,OAAO,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAEhE,MAAM,MAAM,GAAkB;IAC5B;QACE,EAAE,EAAE,cAAc;QAClB,WAAW,EAAE,cAAc;QAC3B,IAAI,EAAE,yBAAyB;KAChC;IACD,EAAE,EAAE,EAAE,SAAS,EAAE,WAAW,EAAE,SAAS,EAAE,IAAI,EAAE,yBAAyB,EAAE;CAC3E,CAAC;AAEF,MAAM,aAAa,GAAG,SAAS,CAAC;AAEhC;;GAEG;AACH,KAAK,UAAU,UAAU,CAAC,MAAiB;IACzC,IAAI,MAAM,CAAC,IAAI,KAAK,WAAW,EAAE,CAAC;QAChC,MAAM,IAAI,KAAK,CAAC,0DAA0D,CAAC,CAAC;IAC9E,CAAC;IAED,IAAI,KAAiB,CAAC;IAEtB,IAAI,MAAM,CAAC,IAAI,KAAK,OAAO,EAAE,CAAC;QAC5B,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC;IACvB,CAAC;SAAM,IAAI,MAAM,CAAC,IAAI,KAAK,KAAK,EAAE,CAAC;QACjC,KAAK,GAAG,IAAI,UAAU,CAAC,MAAM,eAAe,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;IAC5D,CAAC;SAAM,CAAC;QACN,KAAK,GAAG,IAAI,UAAU,CAAC,MAAM,YAAY,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC;IAC1D,CAAC;IAED,MAAM,IAAI,GAAgB;QACxB,IAAI,EAAE,MAAM;QACZ,IAAI,EAAE,KAAK;QACX,SAAS,EAAE,iBAAiB;KAC7B,CAAC;IACF,OAAO,EAAE,SAAS,EAAE,CAAC,IAAI,CAAC,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC;AAChD,CAAC;AAED;;GAEG;AACH,SAAS,iBAAiB,CAAC,KAAc;IACvC,IAAI,CAAC,CAAC,KAAK,YAAY,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC;IAC5C,MAAM,GAAG,GAAG,KAAK,CAAC,OAAO,CAAC,WAAW,EAAE,CAAC;IACxC,OAAO,CACL,GAAG,CAAC,QAAQ,CAAC,wBAAwB,CAAC;QACtC,GAAG,CAAC,QAAQ,CAAC,4BAA4B,CAAC;QAC1C,GAAG,CAAC,QAAQ,CAAC,iBAAiB,CAAC;QAC/B,GAAG,CAAC,QAAQ,CAAC,mBAAmB,CAAC,CAClC,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,MAAM,cAAc,GAAmB;IAC5C,EAAE,EAAE,QAAQ;IACZ,WAAW,EAAE,YAAY;IACzB,MAAM,EAAE,MAAM;IACd,YAAY,EAAE,aAAa;IAC3B,SAAS,EAAE,sCAAsC;IACjD,WAAW,EAAE,CAAC,MAAc,EAAE,OAAe,EAAE,EAAE;QAC/C,MAAM,MAAM,GAAG,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC;QACxC,OAAO,MAAM,CAAC,OAAO,CAAC,CAAC;IACzB,CAAC;IACD,eAAe,EAAE;QACf,MAAM,EAAE,EAAE,eAAe,EAAE,KAAK,EAAE;KACnC;IACD,UAAU;IACV,iBAAiB;CAClB,CAAC"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Provider registry.
|
|
3
|
+
*
|
|
4
|
+
* Maps provider IDs to their configurations and resolves
|
|
5
|
+
* the active provider from the OS credential store.
|
|
6
|
+
*/
|
|
7
|
+
import type { ProviderConfig } from "./types.js";
|
|
8
|
+
/** All supported providers, keyed by ID. */
|
|
9
|
+
export declare const providers: Record<string, ProviderConfig>;
|
|
10
|
+
/** Ordered list for display in the setup menu. */
|
|
11
|
+
export declare const providerList: ProviderConfig[];
|
|
12
|
+
/**
|
|
13
|
+
* Resolve the active provider and API key from the credential store.
|
|
14
|
+
* Returns the provider config and the API key.
|
|
15
|
+
*
|
|
16
|
+
* Throws if no provider is configured or the API key is missing.
|
|
17
|
+
*/
|
|
18
|
+
export declare function resolveActiveProvider(): {
|
|
19
|
+
provider: ProviderConfig;
|
|
20
|
+
apiKey: string;
|
|
21
|
+
modelId: string;
|
|
22
|
+
};
|
|
23
|
+
//# sourceMappingURL=registry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../src/providers/registry.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAMjD,4CAA4C;AAC5C,eAAO,MAAM,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,cAAc,CAIpD,CAAC;AAEF,kDAAkD;AAClD,eAAO,MAAM,YAAY,EAAE,cAAc,EAAwD,CAAC;AAElG;;;;;GAKG;AACH,wBAAgB,qBAAqB,IAAI;IACvC,QAAQ,EAAE,cAAc,CAAC;IACzB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;CACjB,CA+BA"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Provider registry.
|
|
3
|
+
*
|
|
4
|
+
* Maps provider IDs to their configurations and resolves
|
|
5
|
+
* the active provider from the OS credential store.
|
|
6
|
+
*/
|
|
7
|
+
import { googleProvider } from "./google.js";
|
|
8
|
+
import { anthropicProvider } from "./anthropic.js";
|
|
9
|
+
import { openaiProvider } from "./openai.js";
|
|
10
|
+
import { getActiveProvider as getStoredProvider, getApiKey, getModel } from "../keychain.js";
|
|
11
|
+
/** All supported providers, keyed by ID. */
|
|
12
|
+
export const providers = {
|
|
13
|
+
google: googleProvider,
|
|
14
|
+
anthropic: anthropicProvider,
|
|
15
|
+
openai: openaiProvider,
|
|
16
|
+
};
|
|
17
|
+
/** Ordered list for display in the setup menu. */
|
|
18
|
+
export const providerList = [googleProvider, anthropicProvider, openaiProvider];
|
|
19
|
+
/**
|
|
20
|
+
* Resolve the active provider and API key from the credential store.
|
|
21
|
+
* Returns the provider config and the API key.
|
|
22
|
+
*
|
|
23
|
+
* Throws if no provider is configured or the API key is missing.
|
|
24
|
+
*/
|
|
25
|
+
export function resolveActiveProvider() {
|
|
26
|
+
const providerId = getStoredProvider();
|
|
27
|
+
const apiKey = getApiKey();
|
|
28
|
+
if (!providerId) {
|
|
29
|
+
throw new Error("No provider configured. Run `pdf-analyzer --setup` to choose a provider and set your API key.");
|
|
30
|
+
}
|
|
31
|
+
const provider = providers[providerId];
|
|
32
|
+
if (!provider) {
|
|
33
|
+
throw new Error(`Unknown provider "${providerId}". Run \`pdf-analyzer --setup\` to reconfigure.`);
|
|
34
|
+
}
|
|
35
|
+
if (!apiKey) {
|
|
36
|
+
throw new Error(`API key not found for ${provider.displayName}. Run \`pdf-analyzer --setup\` to set your API key.`);
|
|
37
|
+
}
|
|
38
|
+
const storedModel = getModel();
|
|
39
|
+
const modelId = storedModel && provider.models.some((m) => m.id === storedModel)
|
|
40
|
+
? storedModel
|
|
41
|
+
: provider.defaultModel;
|
|
42
|
+
return { provider, apiKey, modelId };
|
|
43
|
+
}
|
|
44
|
+
//# sourceMappingURL=registry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"registry.js","sourceRoot":"","sources":["../../src/providers/registry.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAC7C,OAAO,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AACnD,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAC7C,OAAO,EAAE,iBAAiB,IAAI,iBAAiB,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAE7F,4CAA4C;AAC5C,MAAM,CAAC,MAAM,SAAS,GAAmC;IACvD,MAAM,EAAE,cAAc;IACtB,SAAS,EAAE,iBAAiB;IAC5B,MAAM,EAAE,cAAc;CACvB,CAAC;AAEF,kDAAkD;AAClD,MAAM,CAAC,MAAM,YAAY,GAAqB,CAAC,cAAc,EAAE,iBAAiB,EAAE,cAAc,CAAC,CAAC;AAElG;;;;;GAKG;AACH,MAAM,UAAU,qBAAqB;IAKnC,MAAM,UAAU,GAAG,iBAAiB,EAAE,CAAC;IACvC,MAAM,MAAM,GAAG,SAAS,EAAE,CAAC;IAE3B,IAAI,CAAC,UAAU,EAAE,CAAC;QAChB,MAAM,IAAI,KAAK,CACb,+FAA+F,CAChG,CAAC;IACJ,CAAC;IAED,MAAM,QAAQ,GAAG,SAAS,CAAC,UAAU,CAAC,CAAC;IAEvC,IAAI,CAAC,QAAQ,EAAE,CAAC;QACd,MAAM,IAAI,KAAK,CACb,qBAAqB,UAAU,iDAAiD,CACjF,CAAC;IACJ,CAAC;IAED,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,MAAM,IAAI,KAAK,CACb,yBAAyB,QAAQ,CAAC,WAAW,qDAAqD,CACnG,CAAC;IACJ,CAAC;IAED,MAAM,WAAW,GAAG,QAAQ,EAAE,CAAC;IAC/B,MAAM,OAAO,GACX,WAAW,IAAI,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,WAAW,CAAC;QAC9D,CAAC,CAAC,WAAW;QACb,CAAC,CAAC,QAAQ,CAAC,YAAY,CAAC;IAE5B,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC;AACvC,CAAC"}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import type { LanguageModel } from "ai";
|
|
2
|
+
/**
|
|
3
|
+
* A file content part compatible with the AI SDK message format.
|
|
4
|
+
*/
|
|
5
|
+
export interface PdfFilePart {
|
|
6
|
+
type: "file";
|
|
7
|
+
data: Uint8Array | URL;
|
|
8
|
+
mediaType: "application/pdf";
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* A prepared PDF ready for inclusion in an AI SDK message.
|
|
12
|
+
*/
|
|
13
|
+
export interface PreparedPdf {
|
|
14
|
+
/** Content parts to include in the AI SDK user message. */
|
|
15
|
+
fileParts: PdfFilePart[];
|
|
16
|
+
/** Gemini File API URI for caching (Google only; null for others). */
|
|
17
|
+
cachedUri: string | null;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Source of a PDF to analyze. Discriminated union by `kind`.
|
|
21
|
+
*/
|
|
22
|
+
export type PdfSource = {
|
|
23
|
+
kind: "path";
|
|
24
|
+
path: string;
|
|
25
|
+
} | {
|
|
26
|
+
kind: "url";
|
|
27
|
+
url: string;
|
|
28
|
+
} | {
|
|
29
|
+
kind: "bytes";
|
|
30
|
+
bytes: Uint8Array;
|
|
31
|
+
} | {
|
|
32
|
+
kind: "cachedUri";
|
|
33
|
+
uri: string;
|
|
34
|
+
};
|
|
35
|
+
/**
|
|
36
|
+
* A model option available for selection during setup.
|
|
37
|
+
*/
|
|
38
|
+
export interface ModelOption {
|
|
39
|
+
/** Model ID passed to the AI SDK, e.g. "gemini-3.1-pro-preview". */
|
|
40
|
+
id: string;
|
|
41
|
+
/** Display name shown in the setup TUI. */
|
|
42
|
+
displayName: string;
|
|
43
|
+
/** Short hint shown next to the model name. */
|
|
44
|
+
hint: string;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Configuration for an LLM provider.
|
|
48
|
+
* Each provider exports a plain object satisfying this interface.
|
|
49
|
+
*/
|
|
50
|
+
export interface ProviderConfig {
|
|
51
|
+
/** Provider identifier, e.g. "google", "anthropic", "openai". */
|
|
52
|
+
id: string;
|
|
53
|
+
/** Display name shown during setup. */
|
|
54
|
+
displayName: string;
|
|
55
|
+
/** Available models for this provider. */
|
|
56
|
+
models: ModelOption[];
|
|
57
|
+
/** Default (flagship) model ID, used as fallback. */
|
|
58
|
+
defaultModel: string;
|
|
59
|
+
/** URL where the user obtains an API key. */
|
|
60
|
+
apiKeyUrl: string;
|
|
61
|
+
/** Create an AI SDK LanguageModel instance for the given model ID. */
|
|
62
|
+
createModel: (apiKey: string, modelId: string) => LanguageModel;
|
|
63
|
+
/** Provider-specific options for generateText (e.g. thinking/reasoning config). */
|
|
64
|
+
providerOptions: Record<string, any>;
|
|
65
|
+
/** Prepare a PDF source for inclusion in an LLM call. */
|
|
66
|
+
preparePdf: (source: PdfSource, apiKey: string) => Promise<PreparedPdf>;
|
|
67
|
+
/** Check if an error indicates input token limit exceeded (triggers chunking). */
|
|
68
|
+
isTokenLimitError: (error: unknown) => boolean;
|
|
69
|
+
}
|
|
70
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/providers/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,IAAI,CAAC;AAExC;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,UAAU,GAAG,GAAG,CAAC;IACvB,SAAS,EAAE,iBAAiB,CAAC;CAC9B;AAED;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,2DAA2D;IAC3D,SAAS,EAAE,WAAW,EAAE,CAAC;IACzB,sEAAsE;IACtE,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;CAC1B;AAED;;GAEG;AACH,MAAM,MAAM,SAAS,GACjB;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAC9B;IAAE,IAAI,EAAE,KAAK,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,GAC5B;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,KAAK,EAAE,UAAU,CAAA;CAAE,GACpC;IAAE,IAAI,EAAE,WAAW,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,CAAC;AAEvC;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,oEAAoE;IACpE,EAAE,EAAE,MAAM,CAAC;IACX,2CAA2C;IAC3C,WAAW,EAAE,MAAM,CAAC;IACpB,+CAA+C;IAC/C,IAAI,EAAE,MAAM,CAAC;CACd;AAED;;;GAGG;AACH,MAAM,WAAW,cAAc;IAC7B,iEAAiE;IACjE,EAAE,EAAE,MAAM,CAAC;IACX,uCAAuC;IACvC,WAAW,EAAE,MAAM,CAAC;IACpB,0CAA0C;IAC1C,MAAM,EAAE,WAAW,EAAE,CAAC;IACtB,qDAAqD;IACrD,YAAY,EAAE,MAAM,CAAC;IACrB,6CAA6C;IAC7C,SAAS,EAAE,MAAM,CAAC;IAClB,sEAAsE;IACtE,WAAW,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,KAAK,aAAa,CAAC;IAChE,mFAAmF;IAEnF,eAAe,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IACrC,yDAAyD;IACzD,UAAU,EAAE,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,KAAK,OAAO,CAAC,WAAW,CAAC,CAAC;IACxE,kFAAkF;IAClF,iBAAiB,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,OAAO,CAAC;CAChD"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/providers/types.ts"],"names":[],"mappings":""}
|
package/dist/server.d.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* PDF Analyzer MCP Server
|
|
3
3
|
*
|
|
4
|
-
* Model Context Protocol server for analyzing PDF documents using
|
|
4
|
+
* Model Context Protocol server for analyzing PDF documents using
|
|
5
|
+
* a configurable LLM provider (Google Gemini, Anthropic Claude, or OpenAI).
|
|
5
6
|
*/
|
|
6
7
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
7
8
|
/**
|
package/dist/server.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAoGpE;;GAEG;AACH,eAAO,MAAM,YAAY,QAAO,SA+D/B,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,SAAS,QAAa,OAAO,CAAC,IAAI,CAI9C,CAAC"}
|