309 lines
15 KiB
C#
309 lines
15 KiB
C#
using BLAIzor.Data;
|
|
using BLAIzor.Models;
|
|
using Microsoft.DotNet.Scaffolding.Shared;
|
|
using Microsoft.EntityFrameworkCore;
|
|
using Microsoft.Identity.Client;
|
|
|
|
namespace BLAIzor.Services
|
|
{
|
|
public class ContentEditorAIService
|
|
{
|
|
//private readonly AIService _aiService;
|
|
private readonly OpenAIApiService _openAIApiService;
|
|
private readonly OpenAiRealtimeService _openAIRealtimeService;
|
|
private readonly DeepSeekApiService _deepSeekApiService;
|
|
private readonly CerebrasAPIService _cerebrasAPIService;
|
|
private readonly KimiApiService _kimiApiService;
|
|
//private readonly ApplicationDbContext _context;
|
|
private readonly QDrantService _qDrantService;
|
|
private readonly HtmlSnippetProcessor _htmlSnippetProcessor;
|
|
private readonly IServiceScopeFactory _serviceScopeFactory;
|
|
private readonly ScopedContentService _scopedContentService;
|
|
private readonly ContentEditorService _contentEditorService;
|
|
private readonly ISimpleLogger _logger;
|
|
|
|
public static IConfiguration? _configuration;
|
|
|
|
public bool UseWebsocket = false;
|
|
private string AiProvider = "";
|
|
|
|
public ContentEditorAIService(
|
|
OpenAIApiService openAIApiService,
|
|
DeepSeekApiService deepSeekApiService,
|
|
OpenAiRealtimeService openAIRealtimeService,
|
|
CerebrasAPIService cerebrasAPIService,
|
|
KimiApiService kimiApiService,
|
|
/*ApplicationDbContext context,*/
|
|
QDrantService qDrantService,
|
|
HtmlSnippetProcessor htmlSnippetProcessor,
|
|
IServiceScopeFactory serviceScopeFactory,
|
|
ScopedContentService scopedContentService,
|
|
ISimpleLogger logger,
|
|
IConfiguration? configuration,
|
|
ContentEditorService contentEditorService)
|
|
{
|
|
//_aiService = aiService;
|
|
_openAIApiService = openAIApiService;
|
|
_deepSeekApiService = deepSeekApiService;
|
|
_openAIRealtimeService = openAIRealtimeService;
|
|
_cerebrasAPIService = cerebrasAPIService;
|
|
_kimiApiService = kimiApiService;
|
|
//_context = context;
|
|
_qDrantService = qDrantService;
|
|
_htmlSnippetProcessor = htmlSnippetProcessor;
|
|
_serviceScopeFactory = serviceScopeFactory;
|
|
_scopedContentService = scopedContentService;
|
|
_logger = logger;
|
|
_configuration = configuration;
|
|
_contentEditorService = contentEditorService;
|
|
}
|
|
|
|
private string GetAiEmbeddingSettings() =>
|
|
_configuration?.GetSection("AiSettings")?.GetValue<string>("EmbeddingService") ?? string.Empty;
|
|
|
|
private string GetAiSettings() =>
|
|
_configuration?.GetSection("AiSettings")?.GetValue<string>("Provider") ?? string.Empty;
|
|
|
|
// Existing methods
|
|
public async Task<string> GetMenuSuggestionsAsync(string sessionId, string prompt)
|
|
{
|
|
string systemMessage = "You are a helpful assistant that helps the user in creating a website.";
|
|
var result = await _openAIApiService.GetSimpleChatGPTResponse(sessionId, systemMessage, prompt);
|
|
|
|
//return result.Split('\n', StringSplitOptions.RemoveEmptyEntries)
|
|
// .Select(line => line.Trim('-').Trim())
|
|
// .ToList() ?? new List<string>();
|
|
return result;
|
|
}
|
|
|
|
public async Task<string> GetFacebookContentAsync(string sessionId, string prompt)
|
|
{
|
|
string systemMessage = "You are a helpful assistant that helps the user in creating a website content from facebook posts.";
|
|
var result = await _openAIApiService.GetSimpleChatGPTResponse(sessionId, systemMessage, prompt);
|
|
await _logger.InfoAsync("Facebook content: " + result);
|
|
//return result.Split('\n', StringSplitOptions.RemoveEmptyEntries)
|
|
// .Select(line => line.Trim('-').Trim())
|
|
// .ToList() ?? new List<string>();
|
|
return result;
|
|
}
|
|
|
|
public async Task<string> GetGeneratedContentAsync(string sessionId, string prompt)
|
|
{
|
|
string systemMessage = "You are a helpful assistant that helps the user plan the content of a website. Do not generate html, just plain text.";
|
|
//var result = await _openAIApiService.GetSimpleChatGPTResponse(sessionId, systemMessage, prompt);
|
|
string result = "";
|
|
|
|
AiProvider = GetAiSettings();
|
|
if (AiProvider == "cerebras")
|
|
{
|
|
result = await _cerebrasAPIService.GetSimpleCerebrasResponse(sessionId, systemMessage, prompt);
|
|
|
|
}
|
|
else if (AiProvider == "chatgpt")
|
|
{
|
|
result = await _openAIApiService.GetSimpleChatGPTResponse(sessionId, systemMessage, prompt);
|
|
|
|
}
|
|
else if (AiProvider == "deepseek")
|
|
{
|
|
//await _deepSeekApiService.GetChatGPTStreamedResponse(systemMessage, userMessage);
|
|
result = await _deepSeekApiService.GetSimpleChatGPTResponse(sessionId, systemMessage, prompt);
|
|
}
|
|
if (AiProvider == "kimi")
|
|
{
|
|
result = await _kimiApiService.GetSimpleChatGPTResponse(sessionId, systemMessage, prompt);
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
public async Task<string> GetPhotoPromptAsync(string sessionId, string prompt)
|
|
{
|
|
string systemMessage = "You are a helpful assistant that writes image prompts. Respond only with the image prompt, no explanation, or information added.";
|
|
//var result = await _openAIApiService.GetSimpleChatGPTResponse(sessionId, systemMessage, prompt);
|
|
string result = "";
|
|
|
|
AiProvider = GetAiSettings();
|
|
if (AiProvider == "cerebras")
|
|
{
|
|
result = await _cerebrasAPIService.GetSimpleCerebrasResponse(sessionId, systemMessage, prompt);
|
|
|
|
}
|
|
else if (AiProvider == "chatgpt")
|
|
{
|
|
result = await _openAIApiService.GetSimpleChatGPTResponse(sessionId, systemMessage, prompt);
|
|
|
|
}
|
|
else if (AiProvider == "deepseek")
|
|
{
|
|
//await _deepSeekApiService.GetChatGPTStreamedResponse(systemMessage, userMessage);
|
|
result = await _deepSeekApiService.GetSimpleChatGPTResponse(sessionId, systemMessage, prompt);
|
|
}
|
|
if (AiProvider == "kimi")
|
|
{
|
|
result = await _kimiApiService.GetSimpleChatGPTResponse(sessionId, systemMessage, prompt);
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
|
|
public async Task<string> ProcessMenuItems(int SiteId, bool hasCollection, List<MenuItemModel> ExtractedMenuItems, string subject, bool menuItemsSaved, bool updateVectorDatabase)
|
|
{
|
|
try
|
|
{
|
|
|
|
|
|
if (!hasCollection)
|
|
{
|
|
//create colection
|
|
await _qDrantService.CreateQdrantCollectionAsync("Site" + SiteId.ToString());
|
|
hasCollection = true;
|
|
}
|
|
else
|
|
{
|
|
//check if Collection is really created already
|
|
var collection = await _qDrantService.GetCollectionCount("Site" + SiteId.ToString());
|
|
if (collection != null)
|
|
{
|
|
var siteInfo = await _contentEditorService.GetSiteInfoByIdAsync(SiteId);
|
|
if (siteInfo.EmbeddingService != null)
|
|
{
|
|
var currentEmbeddingServiceName = GetAiEmbeddingSettings();
|
|
if (siteInfo.EmbeddingService == currentEmbeddingServiceName)
|
|
{
|
|
//drop existing collection
|
|
await _qDrantService.DeleteCollectionAsync("Site" + SiteId.ToString());
|
|
//create will automatically handle the new vector size
|
|
await _qDrantService.CreateQdrantCollectionAsync("Site" + SiteId.ToString());
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
var updateQdrantList = ExtractedMenuItems.OrderBy(mi => mi.MenuItem.ContentGroup.Items.FirstOrDefault().Id).ToList(); //FIXXXXXXX
|
|
|
|
for (int i = 0; i < updateQdrantList.Count(); i++)
|
|
{
|
|
MenuItem menuItem = new MenuItem();
|
|
menuItem.Name = ExtractedMenuItems[i].MenuItem.Name;
|
|
menuItem.SortOrder = i;
|
|
menuItem.SiteInfoId = SiteId;
|
|
menuItem.ShowInMainMenu = true;
|
|
if (!string.IsNullOrEmpty(ExtractedMenuItems[i].Content)) //if we have content in the menuItem, let's update the vector DB
|
|
{
|
|
if (updateVectorDatabase)
|
|
{
|
|
Guid guid = Guid.NewGuid();
|
|
WebPageContent content = new WebPageContent();
|
|
content.Id = guid;
|
|
content.UId = guid.ToString();
|
|
content.Type = "page";
|
|
content.SiteId = SiteId;
|
|
content.Name = ExtractedMenuItems[i].MenuItem.Name;
|
|
if (ExtractedMenuItems[i].ContentDescription == null)
|
|
{
|
|
content.Description = $"A section called {ExtractedMenuItems[i].MenuItem.Name} of a website of {subject}";
|
|
}
|
|
else
|
|
{
|
|
content.Description = ExtractedMenuItems[i].ContentDescription;
|
|
}
|
|
content.Content = ExtractedMenuItems[i].Content;
|
|
content.LastUpdated = DateTime.UtcNow;
|
|
//menuItem.QdrantPointId = guid; //FIXXXXXXX
|
|
//menuItem.PointId = i; //FIXXXXXXX
|
|
await _htmlSnippetProcessor.ProcessAndStoreWebContentAsync(guid, content, SiteId);
|
|
}
|
|
else
|
|
{
|
|
//menuItem.PointId = i; //FIXXXXXXX
|
|
//menuItem.QdrantPointId = ExtractedMenuItems[i].MenuItem.QdrantPointId; //FIXXXXXXX
|
|
}
|
|
|
|
}
|
|
|
|
if (!menuItemsSaved) //menuItems just extracted, no content yet because that can be generated only after menuItems have been saved first
|
|
{
|
|
//menuItem.Name = ExtractedMenuItems[i].MenuItem.Name;
|
|
//menuItem.SortOrder = i;
|
|
//menuItem.SiteInfoId = SiteId;
|
|
//menuItem.ShowInMainMenu = true;
|
|
await _contentEditorService.AddMenuItemAsync(menuItem);
|
|
}
|
|
else //menuItems available already
|
|
{
|
|
var menuItems = await _contentEditorService.GetMenuItemsBySiteIdAsync(SiteId);
|
|
var thisItem = menuItems.FirstOrDefault(x => x.SiteInfoId == SiteId && x.Id == ExtractedMenuItems[i].MenuItem.Id);
|
|
if (thisItem == null)
|
|
{
|
|
//new menu item?
|
|
await _contentEditorService.AddMenuItemAsync(menuItem);
|
|
}
|
|
else
|
|
{
|
|
//thisItem.PointId = menuItem.PointId; //FIXXXXXXX
|
|
//thisItem.QdrantPointId = menuItem.QdrantPointId; //FIXXXXXXX
|
|
thisItem.SortOrder = ExtractedMenuItems[i].MenuItem.SortOrder;
|
|
thisItem.ShowInMainMenu = ExtractedMenuItems[i].MenuItem.ShowInMainMenu;
|
|
await _contentEditorService.UpdateMenuItemAsync(thisItem);
|
|
}
|
|
}
|
|
|
|
}
|
|
//await ContentEditorService.SaveMenuItemsAsync(menuItems);
|
|
//menuItemsSaved = true;
|
|
return "OK";
|
|
}
|
|
catch
|
|
{
|
|
return "Error";
|
|
}
|
|
}
|
|
|
|
//public async Task<string> AnalyzeFormFieldsFromText(string text)
|
|
//{
|
|
// string systemMessage = "You are a helpful assistant that extracts structured form field data from plain text.";
|
|
|
|
// string userMessage =
|
|
// "This is the plain text extracted from a form document. " +
|
|
// "Please extract all input fields a user is expected to fill in and return a JSON array of objects.\n\n" +
|
|
// "Each object should have the following structure:\n" +
|
|
// "- `label`: The label or prompt for the input\n" +
|
|
// "- `type`: One of `text`, `number`, `date`, `checkbox`, `radio`, or `textarea`\n" +
|
|
// "- `options`: If type is `radio` or `checkbox`, include the possible options as a list of strings; otherwise, return an empty list\n" +
|
|
// "- `section`: The section title this field belongs to (if any)\n" +
|
|
// "- `repeatable`: true if this field (or set of fields) is expected to be repeated for multiple entries (like multiple employers or qualifications), otherwise false\n\n" +
|
|
// "Return only the JSON array, without any explanation or formatting like ```json.\n\n" +
|
|
// "Here is the form text:\n\n" +
|
|
// $"---\n{text}\n---";
|
|
|
|
// return await _openAIApiService.GetSimpleChatGPTResponseNoSession(systemMessage, userMessage).ConfigureAwait(false);
|
|
//}
|
|
|
|
public async Task<string> AnalyzeGroupedFormFieldsFromText(string text)
|
|
{
|
|
string systemMessage = "You are a helpful assistant that analyzes plain form text and extracts structured, grouped form field definitions.";
|
|
|
|
string userMessage =
|
|
"This is a plain text version of a printed form. Your task is to extract the **input fields** that a user must fill in. " +
|
|
"Group related fields under sections where applicable, and return them in a JSON structure.\n\n" +
|
|
"Each group should follow this structure:\n" +
|
|
"- `groupName`: Name of the logical section or group (e.g. 'Work Experience')\n" +
|
|
"- `repeatable`: true if this section can appear multiple times (e.g. multiple employers, qualifications)\n" +
|
|
"- `fields`: an array of fields within the group\n\n" +
|
|
"Each field must have:\n" +
|
|
"- `label`: The field label/question\n" +
|
|
"- `type`: one of `text`, `number`, `date`, `textarea`, `checkbox`, or `radio`\n" +
|
|
"- `options`: list of string values if type is `radio` or `checkbox`, or an empty list otherwise\n" +
|
|
"- `section`: optional section name (can match group name or be more specific)\n\n" +
|
|
"Return only the JSON array. Do not include any explanation or formatting like ```json.\n\n" +
|
|
$"Here is the form text:\n\n---\n{text}\n---";
|
|
|
|
return await _openAIApiService.GetSimpleChatGPTResponseNoSession(systemMessage, userMessage).ConfigureAwait(false);
|
|
}
|
|
|
|
}
|
|
}
|