{ "kind": "open-flow-workflow", "version": 1, "name": "Analyze SerpBear Rankings to Baserow", "content": { "modelVersion": 14, "document": { "bindings": {}, "graph": { "nodes": { "n_f8780ebeaf57d076": { "name": "Run report now", "kind": "start", "inputDefs": [] }, "n_57721c9a56a98cef": { "name": "Weekly on Sunday at 00:00 UTC", "kind": "cron", "cronTimes": [ { "type": "cron", "expression": "0 0 * * 0", "timezone": "UTC" } ] }, "n_c4fbeca977e67855": { "inputs": { "instance": { "kind": "value", "value": "https://YOUR_SERPBEAR_HOST/api/keywords" }, "domain": { "kind": "value", "value": "YOUR_DOMAIN" } }, "name": "Configure SerpBear", "kind": "task", "task": { "inputs": [ { "jsonSchema": { "type": "string" }, "nullable": false, "handle": "instance" }, { "jsonSchema": { "type": "string" }, "nullable": false, "handle": "domain" } ], "outputs": [ { "jsonSchema": { "type": "string" }, "nullable": false, "handle": "url" }, { "jsonSchema": { "type": "string" }, "nullable": false, "handle": "domain" } ], "name": "Configure SerpBear", "moduleId": "n_0a99ea982ee08c89", "capabilities": [ { "kind": "connector", "mode": "independent", "actions": [] } ] } }, "n_45f4f0da8139701a": { "inputs": { "url": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_c4fbeca977e67855", "output": "url" } ] }, "query.domain": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_c4fbeca977e67855", "output": "domain" } ] }, "auth.token": { "kind": "unset" } }, "name": "Read SerpBear rankings", "kind": "task", "task": { "inputs": [ { "jsonSchema": { "type": "string" }, "nullable": false, "handle": "url" }, { "jsonSchema": { "anyOf": [ { "type": [ "string", "number", "boolean" ] }, { "type": "array", "items": { "type": [ "string", "number", "boolean" ] } } ] }, "nullable": true, "handle": "query.domain" }, { "jsonSchema": { "type": "string" }, "nullable": false, "handle": "auth.token" } ], "outputs": [ { "jsonSchema": {}, "nullable": true, "handle": "body" }, { "jsonSchema": { "type": "integer" }, "nullable": false, "handle": "statusCode" }, { "jsonSchema": { "type": "object", "additionalProperties": { "type": "string" } }, "nullable": false, "handle": "headers" } ], "name": "Read SerpBear rankings", "executor": { "method": "GET", "query": { "mode": "fields", "names": [ "domain" ] }, "headers": { "mode": "fields", "names": [] }, "bodyFormat": "none", "authentication": { "type": "bearer" }, "responseFormat": "json", "statusPolicy": "success", "kind": "http-request" } } }, "n_96353380970296e4": { "inputs": { "body": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_45f4f0da8139701a", "output": "body" } ] }, "domain": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_c4fbeca977e67855", "output": "domain" } ] } }, "name": "Prepare keyword analysis", "kind": "task", "task": { "inputs": [ { "jsonSchema": {}, "nullable": true, "handle": "body" }, { "jsonSchema": { "type": "string" }, "nullable": false, "handle": "domain" } ], "outputs": [ { "jsonSchema": { "type": "boolean" }, "nullable": false, "handle": "hasKeywords" }, { "jsonSchema": { "type": "array", "items": { "type": "object", "properties": { "role": { "type": "string", "enum": [ "system", "user", "assistant", "tool", "developer" ], "description": "The role of the message sender." }, "content": { "anyOf": [ { "type": "string", "description": "Plain text message content." }, { "type": "array", "items": { "type": "object", "additionalProperties": { "description": "The original value corresponding to the field." }, "description": "A JSON object allowing any additional fields." }, "description": "Multimodal or structured message content blocks." } ], "description": "Message content." }, "name": { "type": "string", "description": "An optional name for the sender of the message." }, "tool_call_id": { "type": "string", "description": "The tool call ID corresponding to the tool message." } }, "required": [ "role", "content" ], "additionalProperties": true, "description": "A message in a chat completion request." }, "description": "An ordered list of conversation messages." }, "nullable": false, "handle": "messages" } ], "name": "Prepare keyword analysis", "moduleId": "n_f5f689bdef128939", "capabilities": [ { "kind": "connector", "mode": "independent", "actions": [] } ] } }, "n_472e922bb960610d": { "inputs": {}, "name": "Any keywords?", "kind": "condition", "matchMode": "first", "cases": [ { "output": "yes", "groups": [ { "expressions": [ { "left": { "kind": "source", "source": { "kind": "node", "nodeId": "n_96353380970296e4", "output": "hasKeywords" } }, "operator": "isTrue" } ] } ] } ] }, "n_3ed27bfff2dc102a": { "inputs": { "model": { "kind": "value", "value": "YOUR_OPENROUTER_MODEL_ID" }, "messages": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_96353380970296e4", "output": "messages" } ] } }, "name": "Analyze keyword rankings", "kind": "task", "task": { "inputs": [ { "description": "The model ID to use.", "jsonSchema": { "type": "string", "description": "The model ID to use." }, "nullable": false, "handle": "model" }, { "description": "An ordered list of conversation messages.", "jsonSchema": { "type": "array", "items": { "type": "object", "properties": { "role": { "type": "string", "enum": [ "system", "user", "assistant", "tool", "developer" ], "description": "The role of the message sender." }, "content": { "anyOf": [ { "type": "string", "description": "Plain text message content." }, { "type": "array", "items": { "type": "object", "additionalProperties": { "description": "The original value corresponding to the field." }, "description": "A JSON object allowing any additional fields." }, "description": "Multimodal or structured message content blocks." } ], "description": "Message content." }, "name": { "type": "string", "description": "An optional name for the sender of the message." }, "tool_call_id": { "type": "string", "description": "The tool call ID corresponding to the tool message." } }, "required": [ "role", "content" ], "additionalProperties": true, "description": "A message in a chat completion request." }, "description": "An ordered list of conversation messages." }, "nullable": false, "handle": "messages" }, { "description": "The number of choices you wish to generate.", "jsonSchema": { "type": "integer", "minimum": 1, "description": "The number of choices you wish to generate." }, "nullable": true, "handle": "n", "value": null }, { "description": "Generation stops when encountering these sequences.", "jsonSchema": { "anyOf": [ { "type": "string", "description": "Single stop sequence." }, { "type": "array", "items": { "type": "string", "description": "A stop sequence." }, "description": "Multiple stop sequences." } ], "description": "Generation stops when encountering these sequences." }, "nullable": true, "handle": "stop", "value": null }, { "description": "The end user's unique identifier.", "jsonSchema": { "type": "string", "description": "The end user's unique identifier." }, "nullable": true, "handle": "user", "value": null }, { "description": "nucleus sampling parameters.", "jsonSchema": { "type": "number", "minimum": 0, "maximum": 1, "description": "nucleus sampling parameters." }, "nullable": true, "handle": "top_p", "value": null }, { "description": "Whether to request a streaming response. Currently connector action only supports false or omitted.", "jsonSchema": { "type": "boolean", "description": "Whether to request a streaming response. Currently connector action only supports false or omitted." }, "nullable": true, "handle": "stream", "value": null }, { "description": "A list of legacy functions that will be converted to tools at execution time.", "jsonSchema": { "type": "array", "items": { "type": "object", "properties": { "name": { "type": "string", "description": "The name of the function tool." }, "description": { "type": "string", "description": "Function tool description." }, "parameters": { "type": "object", "additionalProperties": { "description": "The original value corresponding to the field." }, "description": "JSON Schema parameter definitions for function tools." } }, "required": [ "name" ], "additionalProperties": true, "description": "OpenAI style function tool definition." }, "description": "A list of legacy functions that will be converted to tools at execution time." }, "nullable": true, "handle": "functions", "value": null }, { "description": "Legacy function calling strategies are converted to tool_choice at execution time.", "jsonSchema": { "anyOf": [ { "type": "string", "enum": [ "none", "auto" ], "description": "Legacy function calling strategy." }, { "type": "object", "properties": { "name": { "type": "string", "description": "The name of the function to be forced to be called." } }, "required": [ "name" ], "additionalProperties": true, "description": "Legacy function calls select objects." } ], "description": "Legacy function calling strategies are converted to tool_choice at execution time." }, "nullable": true, "handle": "function_call", "value": null }, { "description": "Adjusts the bias map for the specified token sampling probability.", "jsonSchema": { "type": "object", "additionalProperties": { "type": "number", "description": "The offset value for this token." }, "description": "Adjusts the bias map for the specified token sampling probability." }, "nullable": true, "handle": "logit_bias", "value": null }, { "description": "The maximum number of output tokens.", "jsonSchema": { "type": "integer", "minimum": 1, "description": "The maximum number of output tokens." }, "nullable": true, "handle": "max_tokens", "value": null }, { "description": "New max output token field, taking precedence over max_tokens.", "jsonSchema": { "type": "integer", "minimum": 1, "description": "New max output token field, taking precedence over max_tokens." }, "nullable": true, "handle": "max_completion_tokens", "value": null }, { "description": "Sampling temperature.", "jsonSchema": { "type": "number", "minimum": 0, "maximum": 2, "description": "Sampling temperature." }, "nullable": true, "handle": "temperature", "value": null }, { "description": "There are penalties.", "jsonSchema": { "type": "number", "minimum": -2, "maximum": 2, "description": "There are penalties." }, "nullable": true, "handle": "presence_penalty", "value": null }, { "description": "Frequency penalty.", "jsonSchema": { "type": "number", "minimum": -2, "maximum": 2, "description": "Frequency penalty." }, "nullable": true, "handle": "frequency_penalty", "value": null }, { "description": "Whether to return token level probabilities.", "jsonSchema": { "type": "boolean", "description": "Whether to return token level probabilities." }, "nullable": true, "handle": "logprobs", "value": null }, { "description": "Returns the number of top logprobs.", "jsonSchema": { "type": "integer", "minimum": 0, "maximum": 20, "description": "Returns the number of top logprobs." }, "nullable": true, "handle": "top_logprobs", "value": null }, { "description": "A list of tools that can be called by the model.", "jsonSchema": { "type": "array", "items": { "type": "object", "properties": { "type": { "const": "function", "description": "Tool type, must be function." }, "function": { "type": "object", "properties": { "name": { "type": "string", "description": "The name of the function tool." }, "description": { "type": "string", "description": "Function tool description." }, "parameters": { "type": "object", "additionalProperties": { "description": "The original value corresponding to the field." }, "description": "JSON Schema parameter definitions for function tools." } }, "required": [ "name" ], "additionalProperties": true, "description": "Function tool definition." } }, "required": [ "type", "function" ], "additionalProperties": true, "description": "OpenAI style tool definition." }, "description": "A list of tools that can be called by the model." }, "nullable": true, "handle": "tools", "value": null }, { "description": "Model how to select tools.", "jsonSchema": { "anyOf": [ { "type": "string", "enum": [ "none", "auto", "required" ], "description": "Predefined tool selection strategies." }, { "type": "object", "properties": { "type": { "const": "function", "description": "Tool selection type, must be function." }, "function": { "type": "object", "properties": { "name": { "type": "string", "description": "The name of the function facility to be forced to be called." } }, "required": [ "name" ], "additionalProperties": true, "description": "The function tool that is forced to be selected." } }, "required": [ "type", "function" ], "additionalProperties": true, "description": "Forces the configuration of the specified function tool to be called." } ], "description": "Model how to select tools." }, "nullable": true, "handle": "tool_choice", "value": null }, { "description": "Structured output format configuration.", "jsonSchema": { "type": "object", "additionalProperties": { "description": "The original value corresponding to the field." }, "description": "Structured output format configuration." }, "nullable": true, "handle": "response_format", "value": null }, { "description": "List of modalities to request output from.", "jsonSchema": { "type": "array", "items": { "type": "string", "description": "An output modal." }, "description": "List of modalities to request output from." }, "nullable": true, "handle": "modalities", "value": null }, { "description": "A list of candidate models if the main model fails.", "jsonSchema": { "type": "array", "items": { "type": "string", "description": "A candidate fallback model ID." }, "description": "A list of candidate models if the main model fails." }, "nullable": true, "handle": "models", "value": null }, { "description": "Request additional metadata.", "jsonSchema": { "type": "object", "additionalProperties": { "description": "The original value corresponding to the field." }, "description": "Request additional metadata." }, "nullable": true, "handle": "metadata", "value": null }, { "description": "provider routing preference configuration.", "jsonSchema": { "type": "object", "additionalProperties": { "description": "The original value corresponding to the field." }, "description": "provider routing preference configuration." }, "nullable": true, "handle": "provider", "value": null }, { "description": "Plugin configuration to enable.", "jsonSchema": { "type": "array", "items": { "type": "object", "additionalProperties": { "description": "The original value corresponding to the field." }, "description": "A JSON object allowing any additional fields." }, "description": "Plugin configuration to enable." }, "nullable": true, "handle": "plugins", "value": null }, { "description": "Service level.", "jsonSchema": { "type": "string", "description": "Service level." }, "nullable": true, "handle": "service_tier", "value": null }, { "description": "Session ID used for association requests.", "jsonSchema": { "type": "string", "description": "Session ID used for association requests." }, "nullable": true, "handle": "session_id", "value": null }, { "description": "Whether to allow parallel tool calls.", "jsonSchema": { "type": "boolean", "description": "Whether to allow parallel tool calls." }, "nullable": true, "handle": "parallel_tool_calls", "value": null }, { "description": "Additional options for streaming responses.", "jsonSchema": { "type": "object", "additionalProperties": { "description": "The original value corresponding to the field." }, "description": "Additional options for streaming responses." }, "nullable": true, "handle": "stream_options", "value": null }, { "description": "Inference model configuration.", "jsonSchema": { "type": "object", "additionalProperties": { "description": "The original value corresponding to the field." }, "description": "Inference model configuration." }, "nullable": true, "handle": "reasoning", "value": null } ], "outputs": [ { "description": "OpenRouter chat completion response.", "jsonSchema": { "type": "object", "properties": { "id": { "type": "string", "description": "Chat completion result ID." }, "object": { "type": "string", "description": "Return object type." }, "created": { "type": "integer", "description": "Unix timestamp of the time the result was created." }, "model": { "type": "string", "description": "The model ID used in this response." }, "choices": { "type": "array", "items": { "type": "object", "properties": { "index": { "type": "integer", "description": "The position of this choice in the result array." }, "message": { "type": "object", "properties": { "role": { "type": "string", "description": "Returns the role of the message." }, "content": { "anyOf": [ { "anyOf": [ { "type": "string", "description": "Text message content." }, { "type": "array", "items": { "type": "object", "additionalProperties": { "description": "The original value corresponding to the field." }, "description": "A JSON object allowing any additional fields." }, "description": "List of structured content blocks." } ], "description": "The content of the returned message." }, { "type": "null" } ], "description": "The content of the returned message." }, "tool_calls": { "type": "array", "items": { "type": "object", "additionalProperties": { "description": "The original value corresponding to the field." }, "description": "A JSON object allowing any additional fields." }, "description": "A list of tools called by the model request." }, "refusal": { "type": [ "string", "null" ], "description": "Description text returned when the model refuses to answer." } }, "required": [ "role" ], "additionalProperties": true, "description": "The message corresponding to this choice." }, "finish_reason": { "type": [ "string", "null" ], "description": "The reason why the model stopped outputting." }, "logprobs": { "type": [ "object", "null" ], "additionalProperties": { "description": "The original value corresponding to the field." }, "description": "Optional token-level probability information." } }, "required": [ "index", "message", "finish_reason" ], "additionalProperties": true, "description": "A choice in chat completion." }, "description": "The list of candidate results returned by the model." }, "usage": { "type": "object", "properties": { "prompt_tokens": { "type": "integer", "description": "Enter the number of tokens." }, "completion_tokens": { "type": "integer", "description": "Output the number of tokens." }, "total_tokens": { "type": "integer", "description": "Total number of tokens." }, "prompt_tokens_details": { "type": "object", "additionalProperties": { "description": "The original value corresponding to the field." }, "description": "Enter token segmentation information." }, "completion_tokens_details": { "type": "object", "additionalProperties": { "description": "The original value corresponding to the field." }, "description": "Output token breakdown information." } }, "required": [ "prompt_tokens", "completion_tokens", "total_tokens" ], "additionalProperties": true, "description": "The token usage of this response." } }, "required": [ "id", "object", "created", "model", "choices" ], "additionalProperties": true, "description": "OpenRouter chat completion response." }, "nullable": false, "handle": "output" } ], "name": "Analyze keyword rankings", "executor": { "kind": "connector", "action": "openrouter.create_chat_completion", "outputMode": "value" } } }, "n_21375e7e9bd8ea70": { "inputs": { "completion": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_3ed27bfff2dc102a", "output": "output" } ] }, "blog": { "kind": "value", "value": "YOUR_BLOG_NAME" } }, "name": "Prepare report row", "kind": "task", "task": { "inputs": [ { "jsonSchema": { "type": "object", "properties": { "id": { "type": "string", "description": "Chat completion result ID." }, "object": { "type": "string", "description": "Return object type." }, "created": { "type": "integer", "description": "Unix timestamp of the time the result was created." }, "model": { "type": "string", "description": "The model ID used in this response." }, "choices": { "type": "array", "items": { "type": "object", "properties": { "index": { "type": "integer", "description": "The position of this choice in the result array." }, "message": { "type": "object", "properties": { "role": { "type": "string", "description": "Returns the role of the message." }, "content": { "anyOf": [ { "anyOf": [ { "type": "string", "description": "Text message content." }, { "type": "array", "items": { "type": "object", "additionalProperties": { "description": "The original value corresponding to the field." }, "description": "A JSON object allowing any additional fields." }, "description": "List of structured content blocks." } ], "description": "The content of the returned message." }, { "type": "null" } ], "description": "The content of the returned message." }, "tool_calls": { "type": "array", "items": { "type": "object", "additionalProperties": { "description": "The original value corresponding to the field." }, "description": "A JSON object allowing any additional fields." }, "description": "A list of tools called by the model request." }, "refusal": { "type": [ "string", "null" ], "description": "Description text returned when the model refuses to answer." } }, "required": [ "role" ], "additionalProperties": true, "description": "The message corresponding to this choice." }, "finish_reason": { "type": [ "string", "null" ], "description": "The reason why the model stopped outputting." }, "logprobs": { "type": [ "object", "null" ], "additionalProperties": { "description": "The original value corresponding to the field." }, "description": "Optional token-level probability information." } }, "required": [ "index", "message", "finish_reason" ], "additionalProperties": true, "description": "A choice in chat completion." }, "description": "The list of candidate results returned by the model." }, "usage": { "type": "object", "properties": { "prompt_tokens": { "type": "integer", "description": "Enter the number of tokens." }, "completion_tokens": { "type": "integer", "description": "Output the number of tokens." }, "total_tokens": { "type": "integer", "description": "Total number of tokens." }, "prompt_tokens_details": { "type": "object", "additionalProperties": { "description": "The original value corresponding to the field." }, "description": "Enter token segmentation information." }, "completion_tokens_details": { "type": "object", "additionalProperties": { "description": "The original value corresponding to the field." }, "description": "Output token breakdown information." } }, "required": [ "prompt_tokens", "completion_tokens", "total_tokens" ], "additionalProperties": true, "description": "The token usage of this response." } }, "required": [ "id", "object", "created", "model", "choices" ], "additionalProperties": true, "description": "OpenRouter chat completion response." }, "nullable": false, "handle": "completion" }, { "jsonSchema": { "type": "string" }, "nullable": false, "handle": "blog" } ], "outputs": [ { "jsonSchema": { "type": "object", "properties": {}, "additionalProperties": true, "description": "A Baserow row payload keyed by field name or field ID." }, "nullable": false, "handle": "row" } ], "name": "Prepare report row", "moduleId": "n_e4d88fb30db2b875", "capabilities": [ { "kind": "connector", "mode": "independent", "actions": [] } ] } }, "n_05843e81511d963a": { "inputs": { "tableId": { "kind": "unset" }, "userFieldNames": { "kind": "value", "value": true }, "row": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_21375e7e9bd8ea70", "output": "row" } ] } }, "name": "Save report to Baserow", "kind": "task", "task": { "inputs": [ { "description": "The Baserow table ID.", "jsonSchema": { "type": "integer", "exclusiveMinimum": 0, "description": "The Baserow table ID." }, "nullable": true, "handle": "tableId", "value": null }, { "description": "Whether Baserow should use user-facing field names instead of field IDs.", "jsonSchema": { "type": "boolean", "description": "Whether Baserow should use user-facing field names instead of field IDs." }, "nullable": true, "handle": "userFieldNames", "value": null }, { "description": "A Baserow row payload keyed by field name or field ID.", "jsonSchema": { "type": "object", "properties": {}, "additionalProperties": true, "description": "A Baserow row payload keyed by field name or field ID." }, "nullable": false, "handle": "row" } ], "outputs": [ { "description": "The created Baserow row.", "jsonSchema": { "type": "object", "properties": { "id": { "type": "integer", "description": "The Baserow row ID." } }, "required": [ "id" ], "additionalProperties": true, "description": "The created Baserow row." }, "nullable": false, "handle": "row" } ], "name": "Save report to Baserow", "executor": { "kind": "connector", "action": "baserow.create_table_row" } } } }, "edges": [ { "source": "n_f8780ebeaf57d076", "target": "n_c4fbeca977e67855" }, { "source": "n_57721c9a56a98cef", "target": "n_c4fbeca977e67855" }, { "source": "n_c4fbeca977e67855", "target": "n_45f4f0da8139701a" }, { "source": "n_45f4f0da8139701a", "target": "n_96353380970296e4" }, { "source": "n_96353380970296e4", "target": "n_472e922bb960610d" }, { "source": "n_472e922bb960610d", "target": "n_3ed27bfff2dc102a", "sourceHandle": "yes" }, { "source": "n_3ed27bfff2dc102a", "target": "n_21375e7e9bd8ea70" }, { "source": "n_21375e7e9bd8ea70", "target": "n_05843e81511d963a" } ] } }, "modules": { "n_0a99ea982ee08c89": { "name": "Configure SerpBear", "imports": [], "source": "export default function config({instance,domain}){if(typeof instance!=='string'||instance.includes('YOUR_SERPBEAR_HOST')||typeof domain!=='string'||domain==='YOUR_DOMAIN'||!domain.trim())throw Error('Configure SerpBear instance and domain');if(!/^https:\\/\\/[a-z0-9](?:[a-z0-9.-]*[a-z0-9])?(?::[0-9]{1,5})?\\/api\\/keywords$/i.test(instance))throw Error('Use an HTTPS SerpBear /api/keywords URL');return{url:instance,domain}}\n" }, "n_f5f689bdef128939": { "name": "Prepare keyword analysis", "imports": [], "source": "export default function serpbearPrompt({body,domain}){if(typeof domain!=='string'||!domain.trim()||domain==='YOUR_DOMAIN')throw Error('Configure domain');if(!body||typeof body!=='object'||!Array.isArray(body.keywords))throw Error('SerpBear did not return keywords');if(!body.keywords.length)return{hasKeywords:false,messages:[]};const rows=body.keywords.map(k=>{if(!k||typeof k.keyword!=='string'||!k.keyword.trim()||(k.position!=null&&(!Number.isFinite(k.position)||k.position<0))||(k.history!=null&&(typeof k.history!=='object'||Array.isArray(k.history)))||typeof k.domain!=='string'||k.domain!==domain||(k.url!=null&&typeof k.url!=='string'))throw Error('Invalid keyword data');const position=k.position??0,entries=Object.entries(k.history??{});if(entries.some(([date,v])=>!/^\\d{4}-\\d{2}-\\d{2}$/.test(date)||!Number.isFinite(v)||v<0))throw Error('Invalid keyword history');const positions=entries.sort(([a],[b])=>a.localeCompare(b)).slice(-7).map(x=>x[1]).filter(x=>x>0),avg=positions.length?Math.round(positions.reduce((a,b)=>a+b,0)/positions.length*10)/10:null,trend=avg===null||position===0?'not enough ranking data':positionavg?'declining':'stable';return{keyword:k.keyword,currentPosition:position,averagePosition:avg,trend,url:k.url||'not ranking'}});const content=`You are an SEO expert. Analyze this keyword ranking data for ${domain}:\\n${JSON.stringify(rows)}\\nSummarize rankings in a table, identify improvements and issues, and suggest actions.`;return{hasKeywords:true,messages:[{role:'user',content}]}}\n" }, "n_e4d88fb30db2b875": { "name": "Prepare report row", "imports": [], "source": "export default function reportRow({completion,blog}){if(typeof blog!=='string'||!blog.trim()||blog==='YOUR_BLOG_NAME')throw Error('Configure the blog name');const text=completion?.choices?.[0]?.message?.content;if(typeof text!=='string'||!text.trim())throw Error('OpenRouter returned no report text');if(completion.choices[0].finish_reason==='length')throw Error('OpenRouter report was truncated');return {row:{Date:new Date().toISOString().slice(0,10),Note:text,Blog:blog}};}\n" } } }, "presentation": { "designer": { "version": 1, "flow": { "direction": "vertical" } } } }