AI Integration

Add AI capabilities to your Appivo applications

AI Integration Example

Learn how to integrate AI agents into your Appivo applications for intelligent automation.

What You'll Build

AI-powered features including:

  • Automated code generation
  • Intelligent content processing
  • Smart search with context-aware responses
  • Document analysis and summarization

Prerequisites

  • Completed the Rules and Actions example
  • Understanding of action scripts and the context object

Understanding AI in Appivo

Appivo provides 23 pre-built AI agents accessible through the AIFunctions API:

Agent CategoryExamples
Code Assistancegenerate-code, code analyzers
Data Processinggenerate-data-model, generate-query
Content Processingclean-html, extract-keywords, translate
Media Processingtranscribe-audio, transcribe-image

Example 1: Code Generation

Generate action scripts automatically.

Create the Action

'use strict';
exports.execute = async function(context, params) {
    const aiFunctions = context.getAIFunctions();

    const result = await aiFunctions.invokeAgent('generate-code', {
        arguments: {
            instructions: params.instructions,
            model: params.modelName,
            context: {
                operation: params.operation
            }
        }
    });

    if (result.success) {
        return {
            success: true,
            code: result.result,
            message: 'Code generated successfully'
        };
    }

    return {
        success: false,
        error: result.error
    };
};

Usage

// Call the action
const generated = await context.executeAction('GenerateCode', {
    instructions: 'Create a function to validate email addresses',
    modelName: 'User',
    operation: 'validation'
});

if (generated.success) {
    console.log('Generated code:', generated.code);
}

Example 2: Content Translation

Translate user content between languages.

Create the Translation Action

'use strict';
exports.execute = async function(context, params) {
    const aiFunctions = context.getAIFunctions();

    const result = await aiFunctions.invokeAgent('translate', {
        arguments: {
            text: params.text,
            targetLanguage: params.targetLanguage
        }
    });

    if (result.success) {
        return {
            success: true,
            translated: result.result,
            originalLanguage: result.detectedLanguage
        };
    }

    return {
        success: false,
        error: result.error
    };
};

Trigger on Data Save

Create a rule to auto-translate content:

Rule: Auto-Translate Content
Type: DATA
Model: Article
Event: CREATE

Action: SCRIPT
'use strict';
exports.execute = async function(context, params) {
    const article = params.record;
    const aiFunctions = context.getAIFunctions();

    // Translate title to Swedish
    const titleSv = await aiFunctions.invokeAgent('translate', {
        arguments: {
            text: article.title,
            targetLanguage: 'sv'
        }
    });

    // Translate content to Swedish
    const contentSv = await aiFunctions.invokeAgent('translate', {
        arguments: {
            text: article.content,
            targetLanguage: 'sv'
        }
    });

    if (titleSv.success && contentSv.success) {
        await context.updateRecord('Article', article.id, {
            title_sv: titleSv.result,
            content_sv: contentSv.result
        });
    }

    return { success: true };
};

Example 3: Smart Document Processing

Extract information from uploaded documents.

Process Uploaded Files

'use strict';
exports.execute = async function(context, params) {
    const document = params.record;
    const aiFunctions = context.getAIFunctions();

    // Extract text from image if applicable
    if (document.file_type === 'image') {
        const extracted = await aiFunctions.invokeAgent('transcribe-image', {
            arguments: {
                imageFile: document.file_checksum
            }
        });

        if (extracted.success) {
            await context.updateRecord('Document', document.id, {
                extracted_text: extracted.result
            });
        }
    }

    // Extract keywords from content
    const content = document.extracted_text || document.content;
    if (content) {
        const keywords = await aiFunctions.invokeAgent('extract-keywords', {
            arguments: {
                text: content
            }
        });

        if (keywords.success) {
            await context.updateRecord('Document', document.id, {
                keywords: keywords.result
            });
        }
    }

    return { success: true };
};

Example 4: Audio Transcription

Convert audio messages to text.

'use strict';
exports.execute = async function(context, params) {
    const message = params.record;
    const aiFunctions = context.getAIFunctions();

    // Transcribe audio file
    const transcript = await aiFunctions.invokeAgent('transcribe-audio', {
        arguments: {
            audioFile: message.audio_checksum
        }
    });

    if (transcript.success) {
        await context.updateRecord('VoiceMessage', message.id, {
            transcript: transcript.result,
            transcribed_at: new Date()
        });

        // Detect language of transcription
        const langInfo = aiFunctions.detectLanguage(transcript.result);

        await context.updateRecord('VoiceMessage', message.id, {
            detected_language: langInfo.language,
            language_code: langInfo.code
        });

        return { success: true, transcript: transcript.result };
    }

    return { success: false, error: transcript.error };
};

Build a smart Q&A system using SearchIndexes.

Step 1: Create the SearchIndex

  1. Go to Data → Search Indexes
  2. Create index "KnowledgeBase"
  3. Select the Article model
  4. Include: title, content, category
  5. Set search type: BOTH (hybrid)

Step 2: Create the Search Action

'use strict';
exports.execute = async function(context, params) {
    const userQuestion = params.question;

    // Search the knowledge base
    const searchResults = await context.searchIndex('KnowledgeBase', {
        query: userQuestion,
        type: 'BOTH',
        limit: 5
    });

    if (!searchResults.documents || searchResults.documents.length === 0) {
        return {
            success: true,
            answer: 'I could not find relevant information for your question.',
            sources: []
        };
    }

    // Generate contextual response
    const aiFunctions = context.getAIFunctions();
    const response = await aiFunctions.invokeAgent('generate-response', {
        arguments: {
            question: userQuestion,
            context: searchResults.documents.map(d => d.content).join('\n\n'),
            instructions: 'Answer the question based only on the provided context. If the context does not contain enough information, say so.'
        }
    });

    return {
        success: true,
        answer: response.result,
        sources: searchResults.documents.map(d => ({
            title: d.title,
            score: d.score
        }))
    };
};

Step 3: Create the UI

Panel: Knowledge Assistant
├── TextField: Question
│   Placeholder: "Ask a question..."
│   onKeyPress (Enter): Call search action
│
├── Button: Ask
│   onClick: Call search action, show loading
│
├── Panel: Answer (visible when answer exists)
│   ├── Label: Answer text
│   └── Panel: Sources
│       └── List: Source articles with scores
│
└── Panel: Loading (visible during search)
    └── Spinner

Example 6: HTML Content Cleaning

Sanitize user-submitted HTML content.

'use strict';
exports.execute = async function(context, params) {
    const submission = params.record;
    const aiFunctions = context.getAIFunctions();

    // Clean HTML content
    const cleaned = await aiFunctions.invokeAgent('clean-html', {
        arguments: {
            content: submission.html_content
        }
    });

    if (cleaned.success) {
        await context.updateRecord('Submission', submission.id, {
            cleaned_content: cleaned.result,
            processing_status: 'cleaned'
        });

        return { success: true };
    }

    await context.updateRecord('Submission', submission.id, {
        processing_status: 'error',
        processing_error: cleaned.error
    });

    return { success: false, error: cleaned.error };
};

Example 7: Data Model Generation

Generate models from descriptions.

'use strict';
exports.execute = async function(context, params) {
    const aiFunctions = context.getAIFunctions();

    const modelDef = await aiFunctions.invokeAgent('generate-data-model', {
        arguments: {
            instructions: params.description
        }
    });

    if (modelDef.success) {
        // Log the generated model definition
        await context.createRecord('GeneratedModel', {
            description: params.description,
            definition: JSON.stringify(modelDef.result),
            created_at: new Date(),
            status: 'pending_review'
        });

        return {
            success: true,
            model: modelDef.result
        };
    }

    return { success: false, error: modelDef.error };
};

Example 8: Document Summarization

Summarize long documents automatically.

'use strict';
exports.execute = async function(context, params) {
    const document = params.record;
    const aiFunctions = context.getAIFunctions();

    // Use the built-in summarization function
    const summary = await aiFunctions.summarizeDocument(document.content, {
        chunkSize: 4000,
        maxOutputTokens: 500,
        temperature: 0.2,
        model: 'gemini-2.5-flash'
    });

    await context.updateRecord('Document', document.id, {
        summary: summary,
        summarized_at: new Date()
    });

    return { success: true, summary: summary };
};

Using the AiButton Widget

For client-side AI interactions, use the AiButton widget in your views:

<aibutton
    :agent="'generate-data-model'"
    :onresult="handleModelGenerated"
    :onask="showLoading">
</aibutton>
methods: {
    handleModelGenerated: function(data) {
        this.generatedModel = data;
        this.isLoading = false;
        this.showPreview = true;
    },
    showLoading: function() {
        this.isLoading = true;
    }
}

Error Handling Pattern

Always handle AI responses properly:

'use strict';
exports.execute = async function(context, params) {
    const aiFunctions = context.getAIFunctions();

    try {
        const result = await aiFunctions.invokeAgent('agent-name', {
            arguments: params.data
        });

        if (result.success) {
            // Validate the result
            if (result.result && typeof result.result === 'object') {
                return {
                    success: true,
                    data: result.result
                };
            } else {
                return {
                    success: false,
                    error: 'Unexpected response format'
                };
            }
        } else {
            // Log the error for debugging
            context.log.error('AI agent failed', {
                agent: 'agent-name',
                error: result.error,
                params: params.data
            });

            return {
                success: false,
                error: result.error
            };
        }
    } catch (error) {
        context.log.error('System error calling AI', {
            error: error.message
        });

        return {
            success: false,
            error: 'System error: ' + error.message
        };
    }
};

Caching AI Results

For frequently requested operations, implement caching:

'use strict';
exports.execute = async function(context, params) {
    const cacheKey = `ai_translate_${params.text}_${params.targetLanguage}`;

    // Check cache first
    let cached = await context.getCache(cacheKey);
    if (cached) {
        return {
            success: true,
            result: cached,
            fromCache: true
        };
    }

    // Call AI agent
    const aiFunctions = context.getAIFunctions();
    const result = await aiFunctions.invokeAgent('translate', {
        arguments: {
            text: params.text,
            targetLanguage: params.targetLanguage
        }
    });

    if (result.success) {
        // Cache for 24 hours
        await context.setCache(cacheKey, result.result, 86400);

        return {
            success: true,
            result: result.result,
            fromCache: false
        };
    }

    return { success: false, error: result.error };
};

Best Practices

Provide Specific Context

// Good: Detailed context
const code = await aiFunctions.invokeAgent('generate-code', {
    arguments: {
        instructions: 'Create validation for order total',
        model: 'Order',
        requirements: 'Total must be positive and not exceed $10,000',
        relatedFields: ['quantity', 'unit_price', 'discount']
    }
});

// Less effective: Vague request
const code = await aiFunctions.invokeAgent('generate-code', {
    arguments: {
        instructions: 'validate order'
    }
});

Choose the Right Model

Task ComplexityRecommended Model
Simple tasksgemini-2.5-flash
Complex analysisgemini-2.5-pro
Code generationgemini-2.5-pro or gpt-4o

Monitor Token Usage

const response = await aiFunctions.invokeAgent('agent-name', params);
if (response.tokenUsage) {
    console.log('Tokens used:', response.tokenUsage.total);
    if (response.tokenUsage.total > 3500) {
        console.warn('High token usage - consider optimizing');
    }
}

Complete Application: AI-Powered Help Desk

Models

Model: Ticket
- subject (Text)
- description (Long Text)
- category (Text) - auto-classified
- priority (Text) - auto-assigned
- suggested_response (Long Text)
- status (Selection)

Model: KnowledgeArticle
- title (Text)
- content (Long Text)
- category (Text)
- keywords (Text) - auto-extracted

Rule: Process New Ticket

Rule: AI Process Ticket
Type: DATA
Model: Ticket
Event: CREATE
'use strict';
exports.execute = async function(context, params) {
    const ticket = params.record;
    const aiFunctions = context.getAIFunctions();

    // Extract keywords from description
    const keywords = await aiFunctions.invokeAgent('extract-keywords', {
        arguments: { text: ticket.description }
    });

    // Search knowledge base
    const docs = await context.searchIndex('KnowledgeArticles', {
        query: ticket.subject + ' ' + ticket.description,
        type: 'BOTH',
        limit: 3
    });

    // Generate suggested response
    const suggestion = await aiFunctions.invokeAgent('generate-response', {
        arguments: {
            question: ticket.description,
            context: docs.documents.map(d => d.content).join('\n'),
            instructions: 'Generate a helpful response to this support ticket'
        }
    });

    // Update ticket with AI insights
    await context.updateRecord('Ticket', ticket.id, {
        keywords: keywords.success ? keywords.result : null,
        suggested_response: suggestion.success ? suggestion.result : null,
        ai_processed: true
    });

    return { success: true };
};

Next Steps