Adding a Custom .NET AI Module to CodeProject.AI Server

Selecting a Base AI Module

You can build an AI module entirely from scratch, or adapt one of the thousands of existing open-source .NET AI projects available online. For this walkthrough, we’ll adapt Microsoft’s TextClassificationTF sentiment analysis example from the official .NET samples repository, which classifies input text as having either positive or negative sentiment.

Add the Module to the CodeProject.AI Codebase

First, clone or download the main CodeProject.AI Server source code from GitHub to your local development environment. To add your custom module, you will complete these high-level steps:

  1. Create a new .NET Worker Service project in the AnalysisLayer directory of the CodeProject.AI solution
  2. Add a modulesettings.json file to define module configuration and the exposed API endpoint
  3. Copy the pre-trained AI model and base code into your new project
  4. Add all required NuGet and SDK dependencies
  5. Refactor the base code to expose a callable API for your adapter
  6. Create a CodeProject.AI request adapter class to handle incoming requests
  7. Update your project’s entry point to wire up all dependencies
  8. Test the new endpoint

Create the New Module Project

CodeProject.AI .NET modules are built as Worker Services that poll a request queue managed by the main CodeProject.AI Server. To create your project:

  1. Right-click the src/AnalysisLayer folder in Solution Explorer
  2. Select Add > New Project
  3. Choose the Worker Service C# project template
  4. Set the project name to SentimentAnalysis and set the location to src/AnalysisLayer in your local CodeProject.AI copy
  5. Click Next then Create to generate the base project structure.

Create the modulesettings.json Configuration File

The modulesettings.json file tells CodeProject.AI Server how to run your module, what endpoints to expose, and what inputs/outputs to expect. For our sentiment analysis module, we will expose the endpoint http://localhost:5000/v1/text/sentiment that accepts a POST request with a form-ancoded text input, and returns a JSON response with success status, sentiment classification, and positive sentiment probability.

{
  "Modules": {
    "SentimentAnalysis": {
      "Name": "Sentiment Analysis",
      "Activate": true,
      "Description": "Classifies input text as positive or negative sentiment",
      "FilePath": "SentimentAnalysis\\SentimentAnalysis.dll",
      "Runtime": "dotnet",
      "Platforms": [ "windows", "linux", "docker" ],
      "RouteMaps": [
        {
          "Name": "Sentiment Analysis",
          "Path": "text/sentiment",
          "Method": "POST",
          "Queue": "sentiment_analysis_queue",
          "Command": "analyze_sentiment",
          "Description": "Determines the sentiment of input text",
          "Inputs": [
            {
              "Name": "text",
              "Type": "Text",
              "Description": "The text content to analyze"
            }
          ],
          "Outputs": [
            {
              "Name": "success",
              "Type": "Boolean",
              "Description": "True if analysis completed successfully"
            },
            {
              "Name": "is_positive",
              "Type": "Boolean",
              "Description": "Flag indicating if the input has positive sentiment"
            },
            {
              "Name": "positive_probability",
              "Type": "Float",
              "Description": "Probability the input is positive, 0.5 = neutral"
            }
          ]
        }
      ]
    }
  }
}

modulesettings.development.json Override

This file overrides values from modulesettings.json for local development, pointing CodeProject.AI to your local build output directory instead of the project root:

{
  "Modules": {
    "SentimentAnalysis": {
      "FilePath": "SentimentAnalysis\\bin\\debug\\net6.0\\SentimentAnalysis.dll"
    }
  }
}

Copy Base Code and Model Assets

The pre-trained TensorFlow model and data for the sentiment classifier is stored in the sentiment_model folder of the original sample. Copy this entire folder into the root of your new SentimentAnalysis project.

The sample’s prediction logic is stored in the original Program.cs file. Create a new class file called TextClassifier.cs in your project, and paste the content of the original sample’s Program class into your new TextClassifier class.

Add Required Dependencies

To build your module, add the following NuGet packages to your project:

  • Microsoft.ML
  • Microsoft.ML.SampleUtils
  • Microsoft.ML.TensorFlow
  • SciSharp.TensorFlow.Redist
  • CodeProject.AI.AnalysisLayer.SDK

Refactor the Base Sample Code

The original sample code is designed to run as a standalone console app with hard-coded inputs and debug output. Refactor it to work as a reusable class:

  1. Convert the original Main method into the TextClassifier class constructor
  2. Promote local variables required for prediction to class fields
  3. Create a PredictSentiment method that accepts an input text string and returns the prediction result, instead of using hard-coded values.

Create the Request Processing Worker

The CodeProject.AI SDK provides an abstract CommandQueueWorker base class that handles all queue polling and communication with the main server. You only need to implement the request processing logic. Create a new class file SentimentAnalysisWorker.cs:

using CodeProject.AI.AnalysisLayer.SDK;

namespace SentimentAnalysis
{
    class SentimentAnalysisResponse : BackendSuccessResponse
    {
        /// <summary>
        /// Flag indicating if the input text is positive sentiment
        /// </summary>
        public bool? is_positive { get; set; }

        /// <summary>
        /// Probability the input text is positive sentiment
        /// </summary>
        public float? positive_probability { get; set; }
    }

    public class SentimentAnalysisWorker : CommandQueueWorker
    {
        private const string _defaultModuleId  = "sentiment-analysis";
        private const string _defaultQueueName = "sentiment_analysis_queue";
        private const string _moduleName       = "Sentiment Analysis";

        private readonly TextClassifier _classifier;

        /// <summary>
        /// Create a new SentimentAnalysisWorker instance
        /// </summary>
        /// <param name="logger">Logging instance</param>
        /// <param name="textClassifier">Sentiment classifier instance</param>
        /// <param name="config">Application configuration</param>
        public SentimentAnalysisWorker(ILogger<SentimentAnalysisWorker> logger,
                                       TextClassifier textClassifier,  
                                       IConfiguration config)
            : base(logger, config, _moduleName, _defaultQueueName, _defaultModuleId)
        {
            _classifier = textClassifier;
        }

        /// <summary>
        /// Process an incoming sentiment analysis request
        /// </summary>
        /// <param name="request">Incoming request object</param>
        /// <returns>Analysis response</returns>
        public override BackendResponseBase ProcessRequest(BackendRequest request)
        {
            string inputText = request.payload.GetValue("text");
            if (string.IsNullOrWhiteSpace(inputText))
                return new BackendErrorResponse(-1, $"{ModuleName} missing required 'text' parameter.");

            var prediction = _classifier.PredictSentiment(inputText);

            if (prediction is null)
                return new BackendErrorResponse(-1, $"{ModuleName} failed to return a prediction.");

            return new SentimentAnalysisResponse
            {
                is_positive          = prediction.Prediction[1] > 0.5f,
                positive_probability = prediction.Prediction[1]
            };
        }
    }
}

Wire Up Dependencies in Program.cs

Update your project's entry point to register the classifier and worker with the dependency injection container:

using SentimentAnalysis;

IHost host = Host.CreateDefaultBuilder(args)
    .ConfigureServices(services =>
    {
        services.AddSingleton<TextClassifier>();
        services.AddHostedService<SentimentAnalysisWorker>();
    })
    .Build();

await host.RunAsync();

Add SentimentAnalysis as a build dependency to the main CodeProject.AI Server frontend project so it builds when you build the full solution.

Test Your New Module

Create a simple HTML test page to call the new endpoint:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8" />
    <title>Sentiment Analysis Test</title>
    <script>
        async function runAnalysis() {
            const textInput = document.getElementById('textToAnalyze');
            const resultDiv = document.getElementById('result');
            const formData = new FormData();
            formData.append('text', textInput.value);

            try {
                const response = await fetch('http://localhost:5000/v1/text/sentiment', {
                    method: 'POST',
                    body: formData,
                    cache: "no-cache"
                });

                if (!response.ok) {
                    resultDiv.innerText = `Request failed with status: ${response.status}`;
                    return;
                }

                const data = await response.json();
                if (!data.success) {
                    resultDiv.innerText = `Analysis failed: ${data.error}`;
                    return;
                }

                const prob = data.is_positive 
                    ? data.positive_probability 
                    : 1 - data.positive_probability;
                const sentiment = data.is_positive ? "positive" : "negative";
                resultDiv.innerHTML = `<p>Result: <strong>${sentiment}</strong> sentiment (confidence: ${prob.toFixed(2)})</p>`;
            } catch (err) {
                resultDiv.innerText = `Error: ${err.message}`;
            }
        }
    </script>
</head>
<body>
    <h1>CodeProject.AI Sentiment Analysis Test</h1>
    <div>
        <label for="textToAnalyze">Enter text to analyze:</label>
        <br />
        <textarea id="textToAnalyze" rows="8" cols="80" style="border: 1px solid #333; padding: 0.5rem;"></textarea>
    </div>
    <br />
    <button type="button" onclick="runAnalysis()">Analyze Sentiment</button>
    <br />
    <div>
        <h3>Result:</h3>
        <div id="result" style="border: 1px solid #333; padding: 1rem; min-height: 2rem; width: 80ch;"></div>
    </div>
</body>
</html>

To test, run the main CodeProject.AI Server project in your debugger, then open the test HTML file in your browser. Enter any text (like product reviews) and click the button to see your classification result.

XCOPY Deployment on Windows

.NET 6 modules do not require separate runtime installation or virtual environment setup, since the main CodeProject.AI Server instaler already includes the required .NET runtime. To deploy your compiled module to an existing production CodeProject.AI installation on Windows:

  1. Build your module in Release mode
  2. Create a new folder named SentimentAnalysis (matching the folder name in your FilePath configuration) in C:\Program Files\CodeProject\AI\AnalysisLayer
  3. Copy all contents from your module's bin\Release\net6.0 directory to the new folder you created
  4. Restart the CodeProject.AI Server Windows service. The new endpoint will be available automatically once the server restarts.

Tags: dotnet AI codeproject-ai machine-learning sentiment-analysis

Posted on Sun, 20 Sep 2026 16:32:20 +0000 by show8bbs