Skip to content

Commit f9ab3b5

Browse files
Add FileParserPlugin example for AI SDK v5
- Add PDF fixtures (small, medium, large, xlarge) with verification codes - Create comprehensive file-parser example testing all PDF sizes - Uses AI SDK's file attachment format with automatic plugin enablement - Validates extraction of verification codes from PDFs
1 parent 42726ef commit f9ab3b5

File tree

2 files changed

+181
-0
lines changed

2 files changed

+181
-0
lines changed
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
# OpenRouter FileParserPlugin Examples (AI SDK)
2+
3+
Examples demonstrating OpenRouter's FileParserPlugin with AI SDK v5.
4+
5+
## Overview
6+
7+
The FileParserPlugin is automatically enabled when using file attachments with the AI SDK provider. It:
8+
9+
- Processes PDFs sent via data URIs
10+
- Extracts text using server-side parsing
11+
- Integrates seamlessly with AI SDK's message format
12+
13+
## Examples
14+
15+
- `file-parser-all-sizes.ts` - Tests PDF processing across multiple file sizes
16+
17+
## Running
18+
19+
```bash
20+
bun run typescript/ai-sdk-v5/src/plugin-file-parser/file-parser-all-sizes.ts
21+
```
Lines changed: 160 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,160 @@
1+
/**
2+
* Example: OpenRouter FileParserPlugin with AI SDK Provider
3+
*
4+
* Demonstrates PDF processing using the AI SDK with OpenRouter's file parser plugin.
5+
* PDFs are sent as file attachments and automatically parsed server-side.
6+
*
7+
* Key Points:
8+
* - FileParserPlugin automatically enabled for file attachments
9+
* - PDFs sent via data URI format
10+
* - Tests multiple PDF sizes with verification code extraction
11+
*
12+
* To run: bun run typescript/ai-sdk-v5/src/plugin-file-parser/file-parser-all-sizes.ts
13+
*/
14+
15+
import { createOpenRouter } from '@openrouter/ai-sdk-provider';
16+
import { generateText } from 'ai';
17+
18+
const openrouter = createOpenRouter({
19+
apiKey: process.env.OPENROUTER_API_KEY,
20+
});
21+
22+
const MODEL = 'anthropic/claude-3.5-sonnet';
23+
24+
const PDF_SIZES = ['small', 'medium', 'large', 'xlarge'] as const;
25+
26+
// Expected verification codes from PDFs
27+
const EXPECTED_CODES: Record<string, string> = {
28+
small: 'SMALL-7X9Q2',
29+
medium: 'MEDIUM-K4P8R',
30+
large: 'LARGE-M9N3T',
31+
xlarge: 'XLARGE-F6H2V',
32+
};
33+
34+
/**
35+
* Convert PDF file to base64 data URL
36+
*/
37+
async function readPdfAsDataUrl(filePath: string): Promise<string> {
38+
const file = Bun.file(filePath);
39+
const buffer = await file.arrayBuffer();
40+
const base64 = Buffer.from(buffer).toString('base64');
41+
return `data:application/pdf;base64,${base64}`;
42+
}
43+
44+
/**
45+
* Extract verification code from response text
46+
*/
47+
function extractCode(text: string): string | null {
48+
const match = text.match(/[A-Z]+-[A-Z0-9]{5}/);
49+
return match ? match[0] : null;
50+
}
51+
52+
/**
53+
* Format file size for display
54+
*/
55+
function formatSize(bytes: number): string {
56+
if (bytes < 1024 * 1024) {
57+
return `${(bytes / 1024).toFixed(0)} KB`;
58+
}
59+
return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
60+
}
61+
62+
/**
63+
* Process a single PDF with FileParserPlugin
64+
*/
65+
async function testPdf(size: (typeof PDF_SIZES)[number], expectedCode: string): Promise<boolean> {
66+
const path = `./fixtures/pdfs/${size}.pdf`;
67+
const file = Bun.file(path);
68+
const dataUrl = await readPdfAsDataUrl(path);
69+
70+
console.log(`\n=== ${size.toUpperCase()} PDF ===`);
71+
console.log(`Size: ${formatSize(file.size)}`);
72+
console.log(`Expected: ${expectedCode}`);
73+
74+
const model = openrouter(MODEL, { usage: { include: true } });
75+
76+
const result = await generateText({
77+
model,
78+
messages: [
79+
{
80+
role: 'user',
81+
content: [
82+
{
83+
type: 'text',
84+
text: 'Extract the verification code. Reply with ONLY the code.',
85+
},
86+
{
87+
type: 'file',
88+
data: dataUrl,
89+
mediaType: 'application/pdf',
90+
},
91+
],
92+
},
93+
],
94+
});
95+
96+
const extracted = extractCode(result.text);
97+
const success = extracted === expectedCode;
98+
99+
console.log(`Extracted: ${extracted || '(none)'}`);
100+
console.log(`Status: ${success ? '✅ PASS' : '❌ FAIL'}`);
101+
console.log(`Tokens: ${result.usage.totalTokens}`);
102+
103+
const usage = result.providerMetadata?.openrouter?.usage;
104+
if (usage && typeof usage === 'object' && 'cost' in usage) {
105+
const cost = usage.cost as number;
106+
console.log(`Cost: $${cost.toFixed(6)}`);
107+
}
108+
109+
return success;
110+
}
111+
112+
/**
113+
* Main example
114+
*/
115+
async function main() {
116+
console.log('╔════════════════════════════════════════════════════════════════════════════╗');
117+
console.log('║ OpenRouter FileParserPlugin - AI SDK Provider ║');
118+
console.log('╚════════════════════════════════════════════════════════════════════════════╝');
119+
console.log();
120+
console.log('Testing PDF processing with verification code extraction');
121+
console.log();
122+
123+
const results: boolean[] = [];
124+
125+
for (const size of PDF_SIZES) {
126+
const expectedCode = EXPECTED_CODES[size];
127+
if (!expectedCode) {
128+
console.error(`No expected code found for ${size}`);
129+
results.push(false);
130+
continue;
131+
}
132+
133+
try {
134+
results.push(await testPdf(size, expectedCode));
135+
} catch (error) {
136+
console.log('Status: ❌ FAIL');
137+
console.log(`Error: ${error instanceof Error ? error.message : String(error)}`);
138+
results.push(false);
139+
}
140+
}
141+
142+
const passed = results.filter(Boolean).length;
143+
const total = results.length;
144+
145+
console.log('\n' + '='.repeat(80));
146+
console.log(`Results: ${passed}/${total} passed`);
147+
console.log('='.repeat(80));
148+
149+
if (passed === total) {
150+
console.log('\n✅ All PDF sizes processed successfully!');
151+
process.exit(0);
152+
}
153+
console.log('\n❌ Some PDF tests failed');
154+
process.exit(1);
155+
}
156+
157+
main().catch((error) => {
158+
console.error('Fatal error:', error);
159+
process.exit(1);
160+
});

0 commit comments

Comments
 (0)