{ "kind": "open-flow-workflow", "version": 1, "name": "Compare PDF Extraction with Claude and Gemini", "content": { "modelVersion": 14, "document": { "bindings": {}, "graph": { "nodes": { "n_6919a48d2c4b0836": { "name": "Choose a PDF and prompt", "kind": "start", "inputDefs": [ { "jsonSchema": { "type": "string", "minLength": 1 }, "nullable": false, "handle": "fileId" }, { "jsonSchema": { "type": "string", "minLength": 1 }, "nullable": false, "handle": "prompt" } ] }, "n_1b981cec1b5a10f9": { "inputs": { "fileId": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_6919a48d2c4b0836", "output": "fileId" } ] }, "alt": { "kind": "value", "value": "media" } }, "name": "Download the Drive PDF", "kind": "task", "task": { "inputs": [ { "description": "The ID of the file.", "jsonSchema": { "type": "string", "minLength": 1, "description": "The ID of the file." }, "nullable": true, "handle": "fileId", "value": null }, { "description": "When true, includes files from shared drives.", "jsonSchema": { "type": "boolean", "description": "When true, includes files from shared drives." }, "nullable": true, "handle": "includeSharedDrives", "value": null }, { "description": "Return the file content instead of metadata.", "jsonSchema": { "const": "media", "description": "Return the file content instead of metadata." }, "nullable": true, "handle": "alt", "value": null }, { "description": "Whether to acknowledge the risk of downloading known malware or other abusive files.", "jsonSchema": { "type": "boolean", "description": "Whether to acknowledge the risk of downloading known malware or other abusive files." }, "nullable": true, "handle": "acknowledgeAbuse", "value": null } ], "outputs": [ { "description": "Drive file metadata or downloaded file content.", "jsonSchema": { "anyOf": [ { "type": "object", "properties": { "id": { "type": "string", "description": "The unique identifier of the file." }, "name": { "type": "string", "description": "The name of the file." }, "mimeType": { "type": "string", "description": "The MIME type of the file." }, "webViewLink": { "type": [ "string", "null" ], "description": "A link for opening the file in a relevant Google editor or viewer in a browser." }, "createdTime": { "type": [ "string", "null" ], "description": "The time at which the file was created (RFC 3339 date-time)." }, "modifiedTime": { "type": [ "string", "null" ], "description": "The last time the file was modified by anyone (RFC 3339 date-time)." }, "sizeBytes": { "type": [ "integer", "null" ], "description": "The size of the file's content in bytes." }, "driveId": { "type": [ "string", "null" ], "description": "The ID of the shared drive the file belongs to." }, "parents": { "type": "array", "items": { "type": "string", "description": "An array item." }, "description": "The IDs of the parent folders containing the file." }, "owners": { "type": "array", "items": { "type": "object", "properties": { "displayName": { "type": [ "string", "null" ], "description": "The display name of the owner." }, "emailAddress": { "type": [ "string", "null" ], "description": "The email address of the owner." }, "permissionId": { "type": [ "string", "null" ], "description": "The permission ID of the owner." }, "photoLink": { "type": [ "string", "null" ], "description": "A link to the owner's profile photo." } }, "required": [ "displayName", "emailAddress", "permissionId", "photoLink" ], "additionalProperties": false, "description": "Schema for driveOwnerSchema." }, "description": "The owners of the file." }, "shared": { "type": "boolean", "description": "Whether the file has been shared." }, "starred": { "type": "boolean", "description": "Whether the user has starred the file." }, "trashed": { "type": "boolean", "description": "Whether the file has been trashed." }, "ownedByMe": { "type": "boolean", "description": "Whether the authenticated user owns the file." }, "capabilities": { "type": "object", "properties": { "canShare": { "type": "boolean", "description": "Whether the authenticated user may modify sharing settings." } }, "required": [ "canShare" ], "additionalProperties": false, "description": "The projected Drive capabilities for the authenticated user." } }, "required": [ "id", "name", "mimeType", "webViewLink", "createdTime", "modifiedTime", "sizeBytes", "driveId" ], "additionalProperties": false, "description": "Schema for driveFileSchema." }, { "type": "object", "properties": { "fileId": { "type": "string", "description": "The unique identifier of the downloaded file." }, "name": { "type": "string", "description": "The name of the downloaded file." }, "mimeType": { "type": "string", "description": "The MIME type of the downloaded file content." }, "sizeBytes": { "type": [ "integer", "null" ], "description": "The size of the downloaded file content in bytes." }, "transitUrl": { "type": "string", "description": "A temporary transit URL from which the file content can be retrieved." } }, "required": [ "fileId", "name", "mimeType", "sizeBytes", "transitUrl" ], "additionalProperties": false, "description": "Schema for fileContentOutputSchema." } ], "description": "Drive file metadata or downloaded file content." }, "nullable": false, "handle": "output" } ], "name": "Download the Drive PDF", "executor": { "kind": "connector", "action": "googledrive.files.get", "outputMode": "value" } } }, "n_76da45f262cf0a16": { "inputs": { "file": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_1b981cec1b5a10f9", "output": "output" } ] }, "prompt": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_6919a48d2c4b0836", "output": "prompt" } ] } }, "name": "Prepare complete PDF requests", "kind": "task", "task": { "inputs": [ { "jsonSchema": { "anyOf": [ { "type": "object", "properties": { "id": { "type": "string", "description": "The unique identifier of the file." }, "name": { "type": "string", "description": "The name of the file." }, "mimeType": { "type": "string", "description": "The MIME type of the file." }, "webViewLink": { "type": [ "string", "null" ], "description": "A link for opening the file in a relevant Google editor or viewer in a browser." }, "createdTime": { "type": [ "string", "null" ], "description": "The time at which the file was created (RFC 3339 date-time)." }, "modifiedTime": { "type": [ "string", "null" ], "description": "The last time the file was modified by anyone (RFC 3339 date-time)." }, "sizeBytes": { "type": [ "integer", "null" ], "description": "The size of the file's content in bytes." }, "driveId": { "type": [ "string", "null" ], "description": "The ID of the shared drive the file belongs to." }, "parents": { "type": "array", "items": { "type": "string", "description": "An array item." }, "description": "The IDs of the parent folders containing the file." }, "owners": { "type": "array", "items": { "type": "object", "properties": { "displayName": { "type": [ "string", "null" ], "description": "The display name of the owner." }, "emailAddress": { "type": [ "string", "null" ], "description": "The email address of the owner." }, "permissionId": { "type": [ "string", "null" ], "description": "The permission ID of the owner." }, "photoLink": { "type": [ "string", "null" ], "description": "A link to the owner's profile photo." } }, "required": [ "displayName", "emailAddress", "permissionId", "photoLink" ], "additionalProperties": false, "description": "Schema for driveOwnerSchema." }, "description": "The owners of the file." }, "shared": { "type": "boolean", "description": "Whether the file has been shared." }, "starred": { "type": "boolean", "description": "Whether the user has starred the file." }, "trashed": { "type": "boolean", "description": "Whether the file has been trashed." }, "ownedByMe": { "type": "boolean", "description": "Whether the authenticated user owns the file." }, "capabilities": { "type": "object", "properties": { "canShare": { "type": "boolean", "description": "Whether the authenticated user may modify sharing settings." } }, "required": [ "canShare" ], "additionalProperties": false, "description": "The projected Drive capabilities for the authenticated user." } }, "required": [ "id", "name", "mimeType", "webViewLink", "createdTime", "modifiedTime", "sizeBytes", "driveId" ], "additionalProperties": false, "description": "Schema for driveFileSchema." }, { "type": "object", "properties": { "fileId": { "type": "string", "description": "The unique identifier of the downloaded file." }, "name": { "type": "string", "description": "The name of the downloaded file." }, "mimeType": { "type": "string", "description": "The MIME type of the downloaded file content." }, "sizeBytes": { "type": [ "integer", "null" ], "description": "The size of the downloaded file content in bytes." }, "transitUrl": { "type": "string", "description": "A temporary transit URL from which the file content can be retrieved." } }, "required": [ "fileId", "name", "mimeType", "sizeBytes", "transitUrl" ], "additionalProperties": false, "description": "Schema for fileContentOutputSchema." } ], "description": "Drive file metadata or downloaded file content." }, "nullable": false, "handle": "file" }, { "jsonSchema": { "type": "string" }, "nullable": false, "handle": "prompt" } ], "outputs": [ { "jsonSchema": { "type": "array", "items": { "type": "object", "properties": { "role": { "type": "string", "enum": [ "user", "assistant" ], "description": "The role of the message author." }, "content": { "anyOf": [ { "type": "string", "description": "Plain text message content." }, { "type": "array", "items": { "type": "object", "properties": {}, "additionalProperties": true, "description": "A structured Anthropic content block." }, "minItems": 1, "description": "Structured content blocks." } ], "description": "Anthropic message content." } }, "additionalProperties": true, "description": "An input message in an Anthropic conversation." }, "minItems": 1, "description": "The ordered conversation history sent to the model." }, "nullable": false, "handle": "messages" }, { "jsonSchema": { "type": "object", "additionalProperties": true }, "nullable": false, "handle": "geminiBody" }, { "jsonSchema": { "type": "integer", "minimum": 0 }, "nullable": false, "handle": "bytes" } ], "name": "Prepare complete PDF requests", "moduleId": "n_6342c59b4630a965", "capabilities": [ { "kind": "http", "hosts": [ "cdn.example.com" ] } ] } }, "n_1ae895ca25e0ad8c": { "inputs": { "model": { "kind": "value", "value": "claude-sonnet-5-5" }, "max_tokens": { "kind": "value", "value": 1024 }, "messages": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_76da45f262cf0a16", "output": "messages" } ] } }, "name": "Extract with Claude", "kind": "task", "task": { "inputs": [ { "description": "The Anthropic model identifier to use.", "jsonSchema": { "type": "string", "description": "The Anthropic model identifier to use." }, "nullable": false, "handle": "model" }, { "description": "The maximum number of tokens to generate.", "jsonSchema": { "type": "integer", "minimum": 1, "description": "The maximum number of tokens to generate." }, "nullable": false, "handle": "max_tokens" }, { "description": "The ordered conversation history sent to the model.", "jsonSchema": { "type": "array", "items": { "type": "object", "properties": { "role": { "type": "string", "enum": [ "user", "assistant" ], "description": "The role of the message author." }, "content": { "anyOf": [ { "type": "string", "description": "Plain text message content." }, { "type": "array", "items": { "type": "object", "properties": {}, "additionalProperties": true, "description": "A structured Anthropic content block." }, "minItems": 1, "description": "Structured content blocks." } ], "description": "Anthropic message content." } }, "additionalProperties": true, "description": "An input message in an Anthropic conversation." }, "minItems": 1, "description": "The ordered conversation history sent to the model." }, "nullable": false, "handle": "messages" }, { "description": "System prompt content.", "jsonSchema": { "anyOf": [ { "type": "string", "description": "Plain text system prompt." }, { "type": "array", "items": { "type": "object", "properties": {}, "additionalProperties": true, "description": "A structured Anthropic content block." }, "minItems": 1, "description": "Structured system prompt content blocks." } ], "description": "System prompt content." }, "nullable": true, "handle": "system", "value": null }, { "description": "Metadata about the request.", "jsonSchema": { "type": "object", "properties": { "user_id": { "type": "string", "description": "An external user identifier for abuse detection." } }, "additionalProperties": true, "description": "Metadata about the request." }, "nullable": true, "handle": "metadata", "value": null }, { "description": "Custom text sequences that stop generation.", "jsonSchema": { "type": "array", "items": { "type": "string", "description": "A stop sequence." }, "description": "Custom text sequences that stop generation." }, "nullable": true, "handle": "stop_sequences", "value": null }, { "description": "Whether to request a streaming response. This connector only accepts false or an omitted value.", "jsonSchema": { "type": "boolean", "description": "Whether to request a streaming response. This connector only accepts false or an omitted value." }, "nullable": true, "handle": "stream", "value": null }, { "description": "The sampling temperature.", "jsonSchema": { "type": "number", "minimum": 0, "maximum": 1, "description": "The sampling temperature." }, "nullable": true, "handle": "temperature", "value": null }, { "description": "A JSON object passed through to the Anthropic API.", "jsonSchema": { "type": "object", "additionalProperties": { "description": "Any JSON value accepted by the Anthropic API." }, "description": "A JSON object passed through to the Anthropic API." }, "nullable": true, "handle": "thinking", "value": null }, { "description": "Tool selection strategy for the request.", "jsonSchema": { "anyOf": [ { "type": "string", "enum": [ "auto", "any", "none" ], "description": "A predefined tool choice mode." }, { "type": "object", "additionalProperties": { "description": "Any JSON value accepted by the Anthropic API." }, "description": "A JSON object passed through to the Anthropic API." } ], "description": "Tool selection strategy for the request." }, "nullable": true, "handle": "tool_choice", "value": null }, { "description": "Tools available to the model.", "jsonSchema": { "type": "array", "items": { "type": "object", "additionalProperties": { "description": "Any JSON value accepted by the Anthropic API." }, "description": "A JSON object passed through to the Anthropic API." }, "description": "Tools available to the model." }, "nullable": true, "handle": "tools", "value": null }, { "description": "Only sample from the top K options for each token.", "jsonSchema": { "type": "integer", "minimum": 0, "description": "Only sample from the top K options for each token." }, "nullable": true, "handle": "top_k", "value": null }, { "description": "The nucleus sampling threshold.", "jsonSchema": { "type": "number", "minimum": 0, "maximum": 1, "description": "The nucleus sampling threshold." }, "nullable": true, "handle": "top_p", "value": null } ], "outputs": [ { "description": "The response payload for an Anthropic message.", "jsonSchema": { "type": "object", "properties": { "id": { "type": "string", "description": "The message identifier." }, "type": { "type": "string", "description": "The object type returned by the API." }, "role": { "type": "string", "description": "The role of the returned message." }, "model": { "type": "string", "description": "The model used to generate the response." }, "content": { "type": "array", "items": { "type": "object", "properties": {}, "additionalProperties": true, "description": "A structured Anthropic content block." }, "description": "Content blocks generated by the model." }, "stop_reason": { "type": [ "string", "null" ], "description": "The reason generation stopped." }, "stop_sequence": { "type": [ "string", "null" ], "description": "The stop sequence that ended generation." }, "usage": { "type": "object", "properties": { "input_tokens": { "type": "integer", "description": "The number of input tokens consumed." }, "output_tokens": { "type": "integer", "description": "The number of output tokens generated." } }, "additionalProperties": true, "description": "Token usage information." } }, "additionalProperties": true, "description": "The response payload for an Anthropic message." }, "nullable": false, "handle": "output" } ], "name": "Extract with Claude", "executor": { "kind": "connector", "action": "anthropic.create_message", "outputMode": "value" } } }, "n_c912add629c28b21": { "inputs": { "endpoint": { "kind": "value", "value": "/models/gemini-3.8-flash:generateContent" }, "body": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_76da45f262cf0a16", "output": "geminiBody" } ] } }, "name": "Extract with Gemini", "kind": "task", "task": { "inputs": [ { "jsonSchema": { "type": "string" }, "nullable": false, "handle": "endpoint" }, { "jsonSchema": {}, "nullable": true, "handle": "body" } ], "outputs": [ { "jsonSchema": {}, "nullable": true, "handle": "body" }, { "jsonSchema": { "type": "integer" }, "nullable": false, "handle": "statusCode" }, { "jsonSchema": { "type": "object", "additionalProperties": { "type": "string" } }, "nullable": false, "handle": "headers" }, { "jsonSchema": { "const": "base64" }, "nullable": true, "handle": "bodyEncoding" } ], "name": "Extract with Gemini", "executor": { "providerId": "gemini", "method": "POST", "query": { "mode": "fields", "names": [] }, "headers": { "mode": "fields", "names": [] }, "bodyFormat": "json", "kind": "connector-proxy" } } }, "n_eb83a26aba72406e": { "inputs": { "claude": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_1ae895ca25e0ad8c", "output": "output" } ] }, "gemini": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_c912add629c28b21", "output": "body" } ] }, "statusCode": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_c912add629c28b21", "output": "statusCode" } ] }, "bytes": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_76da45f262cf0a16", "output": "bytes" } ] } }, "name": "Keep both model responses", "kind": "task", "task": { "inputs": [ { "jsonSchema": { "type": "object", "properties": { "id": { "type": "string", "description": "The message identifier." }, "type": { "type": "string", "description": "The object type returned by the API." }, "role": { "type": "string", "description": "The role of the returned message." }, "model": { "type": "string", "description": "The model used to generate the response." }, "content": { "type": "array", "items": { "type": "object", "properties": {}, "additionalProperties": true, "description": "A structured Anthropic content block." }, "description": "Content blocks generated by the model." }, "stop_reason": { "type": [ "string", "null" ], "description": "The reason generation stopped." }, "stop_sequence": { "type": [ "string", "null" ], "description": "The stop sequence that ended generation." }, "usage": { "type": "object", "properties": { "input_tokens": { "type": "integer", "description": "The number of input tokens consumed." }, "output_tokens": { "type": "integer", "description": "The number of output tokens generated." } }, "additionalProperties": true, "description": "Token usage information." } }, "additionalProperties": true, "description": "The response payload for an Anthropic message." }, "nullable": false, "handle": "claude" }, { "jsonSchema": {}, "nullable": true, "handle": "gemini" }, { "jsonSchema": { "type": "integer" }, "nullable": false, "handle": "statusCode" }, { "jsonSchema": { "type": "integer", "minimum": 0 }, "nullable": false, "handle": "bytes" } ], "outputs": [ { "jsonSchema": { "type": "object", "additionalProperties": true }, "nullable": false, "handle": "result" } ], "name": "Keep both model responses", "moduleId": "n_8ae217b12d157e75", "capabilities": [ { "kind": "connector", "mode": "independent", "actions": [] } ] } }, "n_b3305b883f9c753f": { "name": "PDF extraction responses", "kind": "outputs", "outputDefs": [ { "jsonSchema": { "type": "object", "additionalProperties": true }, "nullable": false, "handle": "result" } ], "outputMappings": { "result": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_eb83a26aba72406e", "output": "result" } ] } } } }, "edges": [ { "source": "n_6919a48d2c4b0836", "target": "n_1b981cec1b5a10f9" }, { "source": "n_1b981cec1b5a10f9", "target": "n_76da45f262cf0a16" }, { "source": "n_76da45f262cf0a16", "target": "n_1ae895ca25e0ad8c" }, { "source": "n_1ae895ca25e0ad8c", "target": "n_c912add629c28b21" }, { "source": "n_c912add629c28b21", "target": "n_eb83a26aba72406e" }, { "source": "n_eb83a26aba72406e", "target": "n_b3305b883f9c753f" } ] } }, "modules": { "n_6342c59b4630a965": { "name": "Prepare complete PDF requests", "imports": [], "source": "import{Buffer}from'node:buffer';export default async function prepare({file,prompt},context){if(file?.mimeType!=='application/pdf'||typeof file.transitUrl!=='string'||!file.transitUrl.startsWith('https://')||typeof prompt!=='string'||!prompt.trim())throw new Error('Expected a Drive PDF and prompt');const response=await context.fetch(file.transitUrl,{method:'GET'});if(!response.ok)throw new Error('PDF download failed');const bytes=new Uint8Array(await response.arrayBuffer());if(!bytes.length||typeof file.sizeBytes==='number'&&bytes.length!==file.sizeBytes)throw new Error('Incomplete PDF download');const data=Buffer.from(bytes).toString('base64');return{messages:[{role:'user',content:[{type:'document',source:{type:'base64',media_type:'application/pdf',data}},{type:'text',text:prompt}]}],geminiBody:{contents:[{parts:[{inline_data:{mime_type:'application/pdf',data}},{text:prompt}]}]},bytes:bytes.length};}\n" }, "n_8ae217b12d157e75": { "name": "Keep both model responses", "imports": [], "source": "export default function result({claude,gemini,statusCode,bytes}){if(statusCode!==200||!claude||typeof claude!=='object'||!gemini||typeof gemini!=='object'||!Array.isArray(claude.content)||!Array.isArray(gemini.candidates))throw new Error('Both model responses are required');return{result:{claude,gemini,bytes}};}\n" } } }, "presentation": { "designer": { "version": 1, "flow": { "direction": "vertical" } } } }