# 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 product descriptions automatically based on product names.

## Overview[​](#overview "Direct link to Overview")

The process involves:

1. defining an AI prompt with clear instructions
2. making a request to OpenAI API
3. processing the response
4. updating the record with generated content

## Prerequisites[​](#prerequisites "Direct link to 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[​](#implementation "Direct link to 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[​](#how-it-works "Direct link to How it works")

1. **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)

2. **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.

3. **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

4. **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

5. **Main action**: the `generate_description()` function orchestrates the process by calling the helper functions in sequence.

## Setting up the API key[​](#setting-up-the-api-key "Direct link to Setting up the API key")

To configure your OpenAI API key:

1. navigate to your app's configuration
2. go to the secrets management section
3. add a new secret named `COMIND_OPEN_AI_API_KEY`
4. paste your OpenAI API key as the value

tip

Keep your API keys secure and never commit them to version control. Always use the secrets management system.

## Field requirements[​](#field-requirements "Direct link to 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[​](#error-handling "Direct link to 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[​](#customization-options "Direct link to 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 in `getOpenAiResponse()` 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[​](#example-usage "Direct link to Example usage")

1. create a new product record
2. enter the product name in the `title` field (e.g., "Wireless Noise-Canceling Headphones")
3. click the "Generate Description" action button
4. 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[​](#use-cases "Direct link to 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[​](#advanced-scenarios "Direct link to Advanced scenarios")

### Generating content from multiple fields[​](#generating-content-from-multiple-fields "Direct link to 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[​](#using-different-ai-models-for-different-purposes "Direct link to 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[​](#conditional-generation "Direct link to 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[​](#cost-considerations "Direct link to 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[​](#debugging "Direct link to 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.

## Related[​](#related "Direct link to Related")

* [Actions](/developer-guide/building-blocks/actions.md) - action definitions, logic, and preconditions reference
* [External API calls](/developer-guide/how-to/advanced/external-api-calls.md) - the `RestApi` builder pattern, authentication, and error handling
* [Server-side API](/developer-guide/reference/server-side-globals.md) - full reference for `RestApi`, `AppSchema`, and other globals

## Video demonstration[​](#video-demonstration "Direct link to Video demonstration")

Your browser does not support the video tag.
