Skip to content

Commit c393540

Browse files
Add shared fixtures module and JSON metadata
- Update AI SDK example to use shared fixtures from pdf-example-fetch - Use absolute paths so examples work from any directory - Read verification codes from JSON metadata (inherited from parent branch) - Add file-parser-pdf-url.ts example
1 parent f9ab3b5 commit c393540

File tree

3 files changed

+98
-51
lines changed

3 files changed

+98
-51
lines changed

typescript/ai-sdk-v5/src/plugin-file-parser/file-parser-all-sizes.ts

Lines changed: 15 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -8,67 +8,38 @@
88
* - FileParserPlugin automatically enabled for file attachments
99
* - PDFs sent via data URI format
1010
* - Tests multiple PDF sizes with verification code extraction
11+
* - Uses shared fixtures module with absolute paths
1112
*
1213
* To run: bun run typescript/ai-sdk-v5/src/plugin-file-parser/file-parser-all-sizes.ts
1314
*/
1415

1516
import { createOpenRouter } from '@openrouter/ai-sdk-provider';
1617
import { generateText } from 'ai';
18+
import {
19+
type PdfSize,
20+
PDF_SIZES,
21+
readExpectedCode,
22+
readPdfAsDataUrl,
23+
getPdfSize,
24+
formatSize,
25+
extractCode,
26+
} from '@openrouter-examples/shared/fixtures';
1727

1828
const openrouter = createOpenRouter({
1929
apiKey: process.env.OPENROUTER_API_KEY,
2030
});
2131

2232
const MODEL = 'anthropic/claude-3.5-sonnet';
2333

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-
6234
/**
6335
* Process a single PDF with FileParserPlugin
6436
*/
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);
37+
async function testPdf(size: PdfSize, expectedCode: string): Promise<boolean> {
38+
const dataUrl = await readPdfAsDataUrl(size);
39+
const fileSize = getPdfSize(size);
6940

7041
console.log(`\n=== ${size.toUpperCase()} PDF ===`);
71-
console.log(`Size: ${formatSize(file.size)}`);
42+
console.log(`Size: ${formatSize(fileSize)}`);
7243
console.log(`Expected: ${expectedCode}`);
7344

7445
const model = openrouter(MODEL, { usage: { include: true } });
@@ -123,14 +94,8 @@ async function main() {
12394
const results: boolean[] = [];
12495

12596
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-
13397
try {
98+
const expectedCode = await readExpectedCode(size);
13499
results.push(await testPdf(size, expectedCode));
135100
} catch (error) {
136101
console.log('Status: ❌ FAIL');
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
/**
2+
* Example: OpenRouter FileParserPlugin - PDF URL (AI SDK)
3+
*
4+
* This example demonstrates sending PDFs via publicly accessible URLs using AI SDK.
5+
* This is more efficient than base64 encoding as you don't need to download
6+
* and encode the file.
7+
*
8+
* Key Points:
9+
* - Send PDFs directly via URL without downloading
10+
* - Works with AI SDK's file attachment format
11+
* - Reduces payload size compared to base64
12+
* - Ideal for publicly accessible documents
13+
*
14+
* To run: bun run typescript/ai-sdk-v5/src/plugin-file-parser/file-parser-pdf-url.ts
15+
*/
16+
17+
import { createOpenRouter } from '@openrouter/ai-sdk-provider';
18+
import { generateText } from 'ai';
19+
20+
const openrouter = createOpenRouter({
21+
apiKey: process.env.OPENROUTER_API_KEY,
22+
});
23+
24+
const MODEL = 'anthropic/claude-3.5-sonnet';
25+
26+
/**
27+
* Example using the Bitcoin whitepaper (publicly accessible PDF)
28+
*/
29+
async function main() {
30+
console.log('╔════════════════════════════════════════════════════════════════════════════╗');
31+
console.log('║ OpenRouter FileParserPlugin - PDF URL Example (AI SDK) ║');
32+
console.log('╚════════════════════════════════════════════════════════════════════════════╝');
33+
console.log();
34+
console.log('Sending PDF via public URL (Bitcoin whitepaper)');
35+
console.log('URL: https://bitcoin.org/bitcoin.pdf');
36+
console.log();
37+
38+
try {
39+
const model = openrouter(MODEL, { usage: { include: true } });
40+
41+
const result = await generateText({
42+
model,
43+
messages: [
44+
{
45+
role: 'user',
46+
content: [
47+
{
48+
type: 'text',
49+
text: 'What are the main points of this document? Provide a brief 2-3 sentence summary.',
50+
},
51+
{
52+
type: 'file',
53+
// Send PDF via public URL - AI SDK supports this directly
54+
data: 'https://bitcoin.org/bitcoin.pdf',
55+
mediaType: 'application/pdf',
56+
},
57+
],
58+
},
59+
],
60+
});
61+
62+
console.log('✅ Request successful!');
63+
console.log('\nSummary:');
64+
console.log(result.text);
65+
console.log('\nToken usage:');
66+
console.log(`- Prompt tokens: ${result.usage.promptTokens}`);
67+
console.log(`- Completion tokens: ${result.usage.completionTokens}`);
68+
console.log(`- Total tokens: ${result.usage.totalTokens}`);
69+
70+
const cost = (result.providerMetadata?.openrouter?.usage as any)?.cost;
71+
if (cost) {
72+
console.log(`\nCost: $${cost.toFixed(6)}`);
73+
}
74+
75+
process.exit(0);
76+
} catch (error) {
77+
console.error('\n❌ Error:', error instanceof Error ? error.message : String(error));
78+
process.exit(1);
79+
}
80+
}
81+
82+
main();

typescript/shared/src/fixtures.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
* using absolute paths so examples work regardless of where they're run from.
66
*/
77

8-
import { dirname, join } from 'node:path';
8+
import { join, dirname } from 'node:path';
99
import { fileURLToPath } from 'node:url';
1010

1111
// Calculate absolute path to fixtures directory

0 commit comments

Comments
 (0)