@intelligentelectron/pdf-analyzer 0.2.0 → 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/dist/cli/commands.d.ts +6 -2
- package/dist/cli/commands.d.ts.map +1 -1
- package/dist/cli/commands.js +83 -100
- package/dist/cli/commands.js.map +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +9 -3
- package/dist/index.js.map +1 -1
- package/dist/keychain.d.ts +21 -7
- package/dist/keychain.d.ts.map +1 -1
- package/dist/keychain.js +79 -38
- package/dist/keychain.js.map +1 -1
- 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 -31
- 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 -274
- 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,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"}
|
package/dist/server.js
CHANGED
|
@@ -1,51 +1,53 @@
|
|
|
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
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
8
9
|
import { z } from "zod";
|
|
9
10
|
import { VERSION } from "./version.js";
|
|
10
|
-
import {
|
|
11
|
+
import { analyzePdf } from "./service.js";
|
|
12
|
+
import { resolveActiveProvider } from "./providers/registry.js";
|
|
11
13
|
// =============================================================================
|
|
12
14
|
// Server Instructions
|
|
13
15
|
// =============================================================================
|
|
14
16
|
const SERVER_INSTRUCTIONS = `
|
|
15
17
|
# PDF Analyzer MCP Server
|
|
16
18
|
|
|
17
|
-
Analyzes PDF documents using
|
|
19
|
+
Analyzes PDF documents using AI vision capabilities. Supports multiple LLM providers
|
|
20
|
+
(Google Gemini, Anthropic Claude, OpenAI).
|
|
18
21
|
|
|
19
22
|
## Tool: analyze_pdf
|
|
20
23
|
|
|
21
|
-
Pass an absolute file path, URL, or
|
|
22
|
-
sends it to
|
|
24
|
+
Pass an absolute file path, URL, or cached file URI(s) and a list of queries. The server reads the PDF,
|
|
25
|
+
sends it to the configured LLM with your queries, and returns structured responses.
|
|
23
26
|
|
|
24
|
-
Large PDFs that exceed
|
|
27
|
+
Large PDFs that exceed the model's token limit are automatically split into chunks and processed
|
|
25
28
|
sequentially with rolling context. No user intervention is needed.
|
|
26
29
|
|
|
27
|
-
## Caching Strategy
|
|
30
|
+
## Caching Strategy (Google provider only)
|
|
28
31
|
|
|
29
|
-
|
|
30
|
-
queries on the same document. This avoids re-uploading
|
|
32
|
+
When using Google Gemini, the response includes a \`cached_uris\` array (Gemini File API URIs)
|
|
33
|
+
that you should reuse for subsequent queries on the same document. This avoids re-uploading
|
|
34
|
+
and is cached by Gemini for 48 hours. Other providers return an empty \`cached_uris\` array.
|
|
31
35
|
|
|
32
36
|
**Input types accepted:**
|
|
33
37
|
- Local file path: \`/Users/name/docs/report.pdf\`
|
|
34
38
|
- Web URL: \`https://example.com/doc.pdf\`
|
|
35
|
-
- Gemini file URI: \`https://generativelanguage.googleapis.com/v1beta/files/abc123\` (from previous response)
|
|
36
|
-
- Array of Gemini file URIs: for re-analyzing a previously chunked document
|
|
39
|
+
- Gemini file URI: \`https://generativelanguage.googleapis.com/v1beta/files/abc123\` (Google only, from previous response)
|
|
40
|
+
- Array of Gemini file URIs: for re-analyzing a previously chunked document (Google only)
|
|
37
41
|
|
|
38
|
-
**Workflow for multiple queries on same document:**
|
|
39
|
-
1. First call: pass local path or URL
|
|
40
|
-
2. Subsequent calls: pass the \`cached_uris\` value as \`pdf_source\`
|
|
41
|
-
- If \`cached_uris\` has one element, pass the single URI string
|
|
42
|
-
- If \`cached_uris\` has multiple elements (chunked PDF), pass the full array
|
|
42
|
+
**Workflow for multiple queries on same document (Google provider):**
|
|
43
|
+
1. First call: pass local path or URL -> receive \`cached_uris\` in response
|
|
44
|
+
2. Subsequent calls: pass the \`cached_uris\` value as \`pdf_source\` -> no re-upload, faster response
|
|
43
45
|
|
|
44
46
|
## Usage Tips
|
|
45
47
|
|
|
46
48
|
- Ask specific, focused queries for best results
|
|
47
49
|
- For multi-page PDFs, reference page numbers in queries when relevant
|
|
48
|
-
-
|
|
50
|
+
- With Google provider, reuse the returned \`cached_uris\` for follow-up questions
|
|
49
51
|
|
|
50
52
|
## Example
|
|
51
53
|
|
|
@@ -63,7 +65,7 @@ queries on the same document. This avoids re-uploading and is cached by Gemini f
|
|
|
63
65
|
## Error Handling
|
|
64
66
|
|
|
65
67
|
Common errors and solutions:
|
|
66
|
-
- Missing
|
|
68
|
+
- Missing provider/API key: Run \`pdf-analyzer --setup\` to choose a provider and store your API key
|
|
67
69
|
- PDF not found: Verify the path is absolute and file exists
|
|
68
70
|
- URL fetch failed: Check that the URL is accessible and points to a valid PDF
|
|
69
71
|
`.trim();
|
|
@@ -109,11 +111,11 @@ export const createServer = () => {
|
|
|
109
111
|
// Tool: analyze_pdf
|
|
110
112
|
// -------------------------------------------------------------------------
|
|
111
113
|
server.registerTool("analyze_pdf", {
|
|
112
|
-
description: "Analyze a PDF document using
|
|
114
|
+
description: "Analyze a PDF document using AI. Provide an absolute file path, URL, cached file URI (from a previous response, Google only), or array of cached file URIs (from a previous chunked response, Google only) and a list of questions to ask about the PDF content. With the Google provider, returns a cached_uris array that can be reused for subsequent queries on the same document.",
|
|
113
115
|
inputSchema: {
|
|
114
116
|
pdf_source: z
|
|
115
117
|
.union([z.string(), z.array(z.string().min(1)).min(1)])
|
|
116
|
-
.describe("PDF source: absolute local file path
|
|
118
|
+
.describe("PDF source: absolute local file path, URL, cached file URI from a previous response (Google only), or array of cached file URIs from a previous chunked response (Google only)"),
|
|
117
119
|
queries: z
|
|
118
120
|
.array(z.string().min(1))
|
|
119
121
|
.min(1)
|
|
@@ -121,25 +123,19 @@ export const createServer = () => {
|
|
|
121
123
|
},
|
|
122
124
|
}, async ({ pdf_source, queries }) => {
|
|
123
125
|
try {
|
|
124
|
-
const
|
|
125
|
-
const result = await analyzePdf(
|
|
126
|
+
const { provider, apiKey, modelId } = resolveActiveProvider();
|
|
127
|
+
const result = await analyzePdf(provider, apiKey, modelId, { pdf_source, queries });
|
|
126
128
|
return formatResult(result);
|
|
127
129
|
}
|
|
128
130
|
catch (error) {
|
|
129
|
-
// Handle typed Gemini API errors
|
|
130
|
-
if (isApiError(error)) {
|
|
131
|
-
const { message, details } = getApiErrorMessage(error);
|
|
132
|
-
return formatError(message, details);
|
|
133
|
-
}
|
|
134
131
|
const message = error instanceof Error ? error.message : "Unknown error occurred";
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
return formatError(message, "Run `pdf-analyzer --set-key` to store your Gemini API key.");
|
|
132
|
+
if (message.includes("No provider configured") || message.includes("API key not found")) {
|
|
133
|
+
return formatError(message);
|
|
138
134
|
}
|
|
139
135
|
if (message.includes("not found")) {
|
|
140
136
|
return formatError(message, "Ensure the path is absolute and the file exists.");
|
|
141
137
|
}
|
|
142
|
-
if (message.includes("Failed to fetch
|
|
138
|
+
if (message.includes("Failed to fetch")) {
|
|
143
139
|
return formatError(message, "Check that the URL is accessible and points to a valid PDF file.");
|
|
144
140
|
}
|
|
145
141
|
return formatError(message);
|
package/dist/server.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"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"}
|
package/dist/service.d.ts
CHANGED
|
@@ -1,43 +1,15 @@
|
|
|
1
|
-
import { GoogleGenAI, ApiError } from "@google/genai";
|
|
2
1
|
import type { AnalyzePdfInput, AnalyzePdfResponse } from "./types.js";
|
|
2
|
+
import type { ProviderConfig } from "./providers/types.js";
|
|
3
3
|
/**
|
|
4
|
-
*
|
|
5
|
-
* Reads GEMINI_API_KEY from the OS credential store.
|
|
6
|
-
*/
|
|
7
|
-
export declare function createGeminiClient(): GoogleGenAI;
|
|
8
|
-
/**
|
|
9
|
-
* Check if a string is a Gemini File API URI.
|
|
10
|
-
*/
|
|
11
|
-
export declare function isGeminiFileUri(source: string): boolean;
|
|
12
|
-
/**
|
|
13
|
-
* Check if a string is a URL (excluding Gemini File API URIs).
|
|
14
|
-
*/
|
|
15
|
-
export declare function isUrl(source: string): boolean;
|
|
16
|
-
/**
|
|
17
|
-
* Validates a local PDF file path.
|
|
18
|
-
* Throws descriptive errors for common issues.
|
|
19
|
-
*/
|
|
20
|
-
export declare function validateLocalPath(pdfPath: string): void;
|
|
21
|
-
/**
|
|
22
|
-
* Analyzes a PDF document using Gemini.
|
|
4
|
+
* Analyzes a PDF document using the configured provider.
|
|
23
5
|
*
|
|
24
6
|
* Routing:
|
|
25
|
-
* - string[]
|
|
26
|
-
* - Gemini URI string
|
|
27
|
-
* - path/URL
|
|
28
|
-
*/
|
|
29
|
-
export declare function analyzePdf(client: GoogleGenAI, input: AnalyzePdfInput): Promise<AnalyzePdfResponse>;
|
|
30
|
-
/**
|
|
31
|
-
* Check if an error is an ApiError and return typed error info.
|
|
32
|
-
*/
|
|
33
|
-
export declare function isApiError(error: unknown): error is ApiError;
|
|
34
|
-
/**
|
|
35
|
-
* Get error message from ApiError, preserving the actual API response.
|
|
7
|
+
* - string[] -> cached chunk URIs, sequential processing with rolling findings (Google only)
|
|
8
|
+
* - Gemini URI string -> direct single-file analysis via cached URI (Google only)
|
|
9
|
+
* - path/URL -> prepare via provider, try full PDF first, split on token limit error
|
|
36
10
|
*/
|
|
37
|
-
export declare function
|
|
38
|
-
message: string;
|
|
39
|
-
details?: string;
|
|
40
|
-
};
|
|
11
|
+
export declare function analyzePdf(provider: ProviderConfig, apiKey: string, modelId: string, input: AnalyzePdfInput): Promise<AnalyzePdfResponse>;
|
|
41
12
|
export type { AnalyzePdfInput, AnalyzePdfResponse, QueryResponse } from "./types.js";
|
|
42
13
|
export { AnalyzePdfInputSchema } from "./types.js";
|
|
14
|
+
export { isGeminiFileUri, isUrl, validateLocalPath } from "./pdf-utils.js";
|
|
43
15
|
//# sourceMappingURL=service.d.ts.map
|
package/dist/service.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../src/service.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../src/service.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,eAAe,EACf,kBAAkB,EAGnB,MAAM,YAAY,CAAC;AAIpB,OAAO,KAAK,EAAE,cAAc,EAAa,MAAM,sBAAsB,CAAC;AAqRtE;;;;;;;GAOG;AACH,wBAAsB,UAAU,CAC9B,QAAQ,EAAE,cAAc,EACxB,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,eAAe,GACrB,OAAO,CAAC,kBAAkB,CAAC,CAoC7B;AAGD,YAAY,EAAE,eAAe,EAAE,kBAAkB,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AACrF,OAAO,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAC;AACnD,OAAO,EAAE,eAAe,EAAE,KAAK,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC"}
|