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:
- Create a new .NET Worker Service project in the
AnalysisLayerdirectory of the CodeProject.AI solution - Add a
modulesettings.jsonfile to define module configuration and the exposed API endpoint - Copy the pre-trained AI model and base code into your new project
- Add all required NuGet and SDK dependencies
- Refactor the base code to expose a callable API for your adapter
- Create a CodeProject.AI request adapter class to handle incoming requests
- Update your project’s entry point to wire up all dependencies
- 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:
- Right-click the
src/AnalysisLayerfolder in Solution Explorer - Select Add > New Project
- Choose the Worker Service C# project template
- Set the project name to
SentimentAnalysisand set the location tosrc/AnalysisLayerin your local CodeProject.AI copy - 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.MLMicrosoft.ML.SampleUtilsMicrosoft.ML.TensorFlowSciSharp.TensorFlow.RedistCodeProject.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:
- Convert the original
Mainmethod into theTextClassifierclass constructor - Promote local variables required for prediction to class fields
- Create a
PredictSentimentmethod 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:
- Build your module in Release mode
- Create a new folder named
SentimentAnalysis(matching the folder name in yourFilePathconfiguration) inC:\Program Files\CodeProject\AI\AnalysisLayer - Copy all contents from your module's
bin\Release\net6.0directory to the new folder you created - Restart the CodeProject.AI Server Windows service. The new endpoint will be available automatically once the server restarts.