How to create an AI-based action?
AI-powered actions can enhance your apps by automatically generating content, analyzing data, or providing intelligent suggestions. This is particularly useful when you need to create dynamic content based on existing data without manual intervention.
This guide shows you how to create an action that uses OpenAI to generate compelling product descriptions automatically based on product names.
Overview
The process involves:
- defining an AI prompt with clear instructions
- making a request to OpenAI API
- processing the response
- updating the record with generated content
Prerequisites
Before implementing this action, ensure you have:
- an OpenAI API key
- the API key stored as
COMIND_OPEN_AI_API_KEY
in your app secrets - a text field for product name (e.g.,
title
) - a rich text field for the description (e.g.,
description
)
Implementation
In your actions/logic/index.ts
file, add the following action function and export it. You can either create a new action called generate_description
or add this code to an existing action:
// actions/index.ts
import type { AppActionArray } from "@comind/api";
const actions = [
{
caption: "Generate description",
options: {
showAsButton: true,
viewMode: "local",
},
uid: "generate_description",
},
] as const satisfies AppActionArray;
export default actions;
// actions/logic/index.ts
export default {
generate_description,
// ... other actions
} satisfies ActionLogic<typeof entity>;
import { entity } from "#typings";
import { RestApi, AppSchema } from "@comind/api/server";
const prompt = `
Generate a compelling product description for provided product name in exactly 3 paragraphs.
Use minimal HTML formatting only (bold tags for emphasis, bullet points if needed).
Each paragraph should be put into <p></p> tags. Format as bold 1-2 most important words.
Focus on key features, benefits, and target audience. Keep it professional and engaging.`;
function generate_description() {
const response = getOpenAiResponse(prompt, entity.title || "");
setDescription(response);
}
function setDescription(response: any) {
if (!response.Data.output) throw JSON.stringify(response);
const outputWithMessage = response.Data.output.find(
(o: any) => o.type === "message"
);
const outputText = outputWithMessage.content[0].text;
entity.description = outputText;
}
function getOpenAiResponse(
instructions: string,
input: string,
model = "gpt-5-nano"
) {
const { COMIND_OPEN_AI_API_KEY } = AppSchema.getSecrets();
if (!COMIND_OPEN_AI_API_KEY) throw "Can't find COMIND_OPEN_AI_API_KEY";
const url = "https://api.openai.com/v1/responses";
const body = {
input,
instructions,
max_output_tokens: 20000,
model,
reasoning: { effort: "minimal" },
};
RestApi.createClient(url);
RestApi.createRequest("", "POST");
RestApi.addHeader("Authorization", `Bearer ${COMIND_OPEN_AI_API_KEY}`);
RestApi.addHeader("Content-Type", "application/json");
RestApi.addJsonBody(body);
const response = RestApi.executeRequest();
entity.c_json_response = JSON.stringify(response);
return response;
}
How it works
-
Prompt definition: the
prompt
constant contains detailed instructions for the AI. It specifies:- the output format (3 paragraphs)
- HTML formatting rules (minimal, with
<p>
tags) - content requirements (features, benefits, target audience)
- style guidelines (professional and engaging)
-
API key retrieval: the action retrieves the API key from app secrets using
AppSchema.getSecrets()
. This ensures sensitive credentials are not hardcoded in your code. -
API request: the
getOpenAiResponse()
function:- creates a REST client pointing to OpenAI's API
- sets required headers (Authorization and Content-Type)
- sends a POST request with the prompt and input data
- stores the raw JSON response in
c_json_response
field for debugging
-
Response processing: the
setDescription()
function:- validates that the response contains output data
- finds the message-type output from the response
- extracts the text content
- updates the
description
field with the generated text
-
Main action: the
generate_description()
function orchestrates the process by calling the helper functions in sequence.
Setting up the API key
To configure your OpenAI API key:
- navigate to your app's configuration
- go to the secrets management section
- add a new secret named
COMIND_OPEN_AI_API_KEY
- paste your OpenAI API key as the value
Keep your API keys secure and never commit them to version control. Always use the secrets management system.
Field requirements
For this action to work, ensure your app has:
- a text field named
title
(for the product name) - a rich text field named
description
(for the generated content) - optionally, a text field named
c_json_response
for storing raw API responses (useful for debugging)
Error handling
The action includes error handling for common scenarios:
- Missing API key: throws an error if
COMIND_OPEN_AI_API_KEY
is not configured - Invalid response: throws an error with response details if the expected output structure is missing
- API failures: REST API errors will be thrown automatically
Customization options
You can customize this action by:
- Changing the prompt: modify the
prompt
constant to generate different types of content (e.g., marketing copy, technical specifications, social media posts) - Using different models: change the
model
parameter ingetOpenAiResponse()
to use different AI models (e.g.,gpt-5
,gpt-5-mini
) - Adjusting token limits: modify
max_output_tokens
to control the length of generated content - Different input sources: instead of
entity.title
, use other fields or combine multiple fields as input - Custom formatting: modify the prompt to request different HTML formatting or plain text output
- Multiple languages: enhance the prompt to generate content in specific languages
Example usage
- create a new product record
- enter the product name in the
title
field (e.g., "Wireless Noise-Canceling Headphones") - click the "Generate Description" action button
- the AI will generate a professional product description and populate the
description
field
Example output:
<p>
Introducing our <b>premium wireless headphones</b> that combine cutting-edge
noise-canceling technology with exceptional audio quality.
</p>
<p>
These headphones feature adaptive noise cancellation that automatically
adjusts to your environment, delivering crystal-clear sound whether you're in
a busy office or traveling. The <b>40-hour battery life</b> ensures
uninterrupted listening throughout your entire workweek.
</p>
<p>
Perfect for professionals, commuters, and audio enthusiasts who demand
superior sound quality and comfort during extended listening sessions.
</p>
Use cases
This AI-based action approach is particularly useful for:
- E-commerce: automatically generating product descriptions from product names and attributes
- Content management: creating initial drafts for articles, blog posts, or documentation
- Data enrichment: adding descriptive content to catalog items
- Multilingual content: generating translations or localized versions of text
- Summarization: creating executive summaries from detailed reports
- Research-enhanced content: combining web search results with AI to create more accurate and informed descriptions
- Competitive analysis: generating product positioning based on real-time market research
Advanced scenarios
Generating content from multiple fields
You can combine multiple fields as input:
function generate_description() {
const input = `
Product name: ${entity.title}
Category: ${entity.category}
Key features: ${entity.features}
Price range: ${entity.price_range}
`;
const response = getOpenAiResponse(prompt, input);
setDescription(response);
}
Using different AI models for different purposes
function generate_short_description() {
// Use faster, cheaper model for short content
const response = getOpenAiResponse(shortPrompt, entity.title, "gpt-5-nano");
entity.short_description = processResponse(response);
}
function generate_detailed_analysis() {
// Use more powerful model for complex analysis
const response = getOpenAiResponse(detailedPrompt, entity.data, "gpt-5");
entity.analysis = processResponse(response);
}
Conditional generation
function generate_description() {
// Only generate if description is empty
if (entity.description) {
throw "Description already exists. Clear it first if you want to regenerate.";
}
const response = getOpenAiResponse(prompt, entity.title || "");
setDescription(response);
}
Cost considerations
Keep in mind that AI API calls incur costs:
- monitor your API usage through OpenAI's dashboard
- consider implementing rate limiting for high-volume scenarios
- use smaller models (like
gpt-5-nano
) when appropriate - cache generated content to avoid regenerating the same content multiple times
- set appropriate
max_output_tokens
limits to control costs
Debugging
The action stores the raw API response in entity.c_json_response
, which is helpful for:
- inspecting the full response structure
- debugging issues with response parsing
- analyzing API performance and token usage
- troubleshooting unexpected outputs
To view the raw response, add c_json_response
field to your layout during development.