Aniket
OMVP
Feb 27, 2023
visibility 4057
star star star star star
(0 votes)

ChatGPT/OpenAI integration for text generation using Prompt in Optimizely

Here's how you can use a simple publishing event to generate content using OpenAI.

The code is pretty simple - I will avoid getting into too many details as Tomas has done a wonderful job of explaining it in his blog post here:
https://www.gulla.net/en/blog/integrating-generative-ai-in-optimizely-cms-a-quick-test-with-openai/

...And from Allan here:
https://www.codeart.dk/blog/2022/11/ai-assisted-content-creation---in-optimizely-cms--commerce-ai-series---part-2/ 

Here's sample code which has been requested by a few people. 

namespace ClientName.CMS.Features.Sample
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Net.Http;
    using System.Threading.Tasks;
    using System.Web;
    using EPiServer;
    using EPiServer.Core;
    using EPiServer.Framework;
    using EPiServer.Framework.Initialization;
    using EPiServer.ServiceLocation;
    using Newtonsoft.Json;
    using ClientName.CMS.Features.Basics.RichTextBlock.Models;
    using ClientName.Common.Features.Foundation.Threading.Utilities;

    [InitializableModule]
    [ModuleDependency(typeof(EPiServer.Web.InitializationModule))]
    public class OpenAIBlockInitialization : IInitializableModule
    {
        private static readonly HttpClient _client = new HttpClient();
        private readonly string _apiKey = "YOUR API KEY GOES HERE"; // You can generate it here: https://platform.openai.com/account/api-keys

        public void Initialize(InitializationEngine context)
        {
            // Add initialization logic, this method is called once after CMS has been initialized
            var contentEvents = ServiceLocator.Current.GetInstance<IContentEvents>();
            contentEvents.PublishingContent += ContentEvents_PublishingContent;
        }

        public async Task<dynamic> SendRequestAsync(string model, string prompt, int maxTokens)
        {
            var requestUrl = "https://api.openai.com/v1/engines/" + model + "/completions";
            var requestData = new
            {
                prompt = prompt,
                max_tokens = maxTokens
            };
            var jsonRequestData = JsonConvert.SerializeObject(requestData);
            var requestContent = new StringContent(jsonRequestData, System.Text.Encoding.UTF8, "application/json");

            _client.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", _apiKey);

            var response = await _client.PostAsync(requestUrl, requestContent);
            response.EnsureSuccessStatusCode();

            var responseContent = await response.Content.ReadAsStringAsync();
            var responseData = JsonConvert.DeserializeObject<dynamic>(responseContent);

            return responseData;
        }

        private void ContentEvents_PublishingContent(object sender, EPiServer.ContentEventArgs e)
        {
            try
            {
                if (e.Content != null)
                {
                    if (e.Content is RichTextBlock richTextBlock)
                    {
                        var blockData = e.Content as RichTextBlock;

                        string textToOpenAI = blockData.OpenAIPrompt;

                        // Call Open AI and get results
                        var response = AsyncHelper.RunSync(async () => await SendRequestAsync("text-davinci-003", textToOpenAI, 3000));

                        blockData.OpenAIGeneratedText = response?.choices[0]?.text;
                    }
                }
            }
            catch (Exception ex)
            {
                // Optinal logging
            }
        }

        public void Uninitialize(InitializationEngine context)
        {
            // Add uninitialization logic
            var contentEvents = ServiceLocator.Current.GetInstance<IContentEvents>();
            contentEvents.PublishingContent -= ContentEvents_PublishingContent;
        }
    }
}

AsyncHelper class to run async method synchronously (due to initialization functions limitations)

namespace ClientName.Common.Features.Foundation.Threading.Utilities
{
    using System;
    using System.Threading;
    using System.Threading.Tasks;

    public static class AsyncHelper
    {
        private static readonly TaskFactory TaskFactory =
            new TaskFactory(CancellationToken.None, TaskCreationOptions.None, TaskContinuationOptions.None, TaskScheduler.Default);

        /// <summary>
        /// Executes an async Task method which has a void return value synchronously
        /// USAGE: AsyncUtil.RunSync(() => AsyncMethod());
        /// </summary>
        /// <param name="task">Task method to execute</param>
        public static void RunSync(Func<Task> task) => TaskFactory.StartNew(task).Unwrap().GetAwaiter().GetResult();

        /// <summary>
        /// Executes an async Task<T> method which has a T return type synchronously
        /// USAGE: T result = AsyncUtil.RunSync(() => AsyncMethod<T>());
        /// </summary>
        /// <typeparam name="TResult">Return Type</typeparam>
        /// <param name="task">Task<T> method to execute</param>
        /// <returns></returns>
        public static TResult RunSync<TResult>(Func<Task<TResult>> task) =>
            TaskFactory.StartNew(task).Unwrap().GetAwaiter().GetResult();
    }
}

Happy coding!

Feb 27, 2023

Comments

error Please login to comment.
Latest blogs
Virtual Teammates in Optimizely Mark: a hands-on first look

Virtual Teammates are the most interesting thing Optimizely has shipped on its agent platform this year, and the hardest to evaluate from a demo....

Minesh Shah (Netcel) | Oct 27, 2026

I Turned My Tech Bookshelf Into an MCP Server (in .NET)

Overview If you are like me you have been buying tech ebooks for years. Manning early access books, Packt and Apress bundles, Humble Bundles, a few...

KennyG | Oct 26, 2026

Time Zone-Aware Scheduled Publishing in Optimizely CMS 13

Scheduling content for audiences in different time zones is a common requirement, especially for websites managed by editors across multiple region...

Mardy | Oct 26, 2026

Focal-point cropping with Cloudflare image resizing in Next.js

What is focal point cropping? When creating content for an article on the web it's inevitable that article is going to be displayed on a wide varie...

Allyn Thomas | Oct 24, 2026

Unit-Level Promotion Exclusions: Updated Behaviour and Developer Guide

Introduction Since Commerce 13, Optimizely Commerce Connect has supported two modes for promotion exclusion: order-level and unit-level. Order-leve...

Viet Anh Nguyen | Oct 23, 2026

Experimentation When the Agent Makes the Decision

When an agent enters the loop, an A/B test loses its obvious unit, its obvious variant and its obvious decision-maker. WebMCP, WebKit's objection, ...

Piotr | Oct 23, 2026 |