A critical vulnerability was discovered in React Server Components (Next.js). Our systems remain protected but we advise to update packages to newest version. Learn More

Aniket
Feb 27, 2023
  3363
(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

Please login to comment.
Latest blogs
From 12 to 13 preview: A Developer's Guide to testing an Optimizely CMS 13 Alloy Site

The release of Optimizely CMS 13 marks a significant step forward, embracing a more composable and headless-first architecture. While this unlocks...

Robert Svallin | Jan 23, 2026

A day in the life of an Optimizely OMVP: Opti North Manchester - January 2026 Meetup Recap

There's something special about the Optimizely community in the North. On 22nd January, we gathered at the Everyman Cinema in Manchester for the...

Graham Carr | Jan 23, 2026

Beyond the widget - making Optimizely Content Recommendations work for you

Optimizely recommendation data you can render your way. A frontend-focused guide to bypassing the widget, with practical query filtering advise and...

Tom Robinson | Jan 22, 2026 |

Announcing the Jhoose Commerce API for Optimizely Commerce Connect

A layered framework for Optimizely Commerce Connect that accelerates delivery, supports headless architecture, and simplifies carts, checkout, and...

Andrew Markham | Jan 22, 2026 |