359 lines
24 KiB
C#
359 lines
24 KiB
C#
using BLAIzor.Services;
|
||
using System.Text;
|
||
|
||
namespace BLAIzor.Models
|
||
{
|
||
public static class AiPrompts
|
||
{
|
||
public static class WelcomeContent
|
||
{
|
||
public static string GetSystemMessageForWelcomeMessage(string mood, string siteEntity, string extractedText, string selectedBrandName, string language, string menuList)
|
||
{
|
||
string systemMessage = "You are a helpful, " + mood + " assistant that welcomes the user speaking in the name of the " + siteEntity + " described by the content, on a website of " + selectedBrandName + " in " + language + ". Use the following content: `" +
|
||
extractedText + "` " +
|
||
//"and generate a short" +Mood+ "but kind marketing-oriented welcome message and introduction of the brand for the user, constructed as simple Bootstrap HTML codeblock with a <h1> tagged title and a paragraph." +
|
||
"and generate a" + mood + " marketing-oriented welcome message and a summary of the content and introduction " +
|
||
"of the brand for the user in the name of " + siteEntity + " , aiming to explain clearly, what does the company/person offer, constructed " +
|
||
"as simple Bootstrap HTML <div clss=\"container\"> codeblock with a <h1> tagged title and a paragraph." +
|
||
"If there is any logo, or not logo but main brand image in the document use that url, " +
|
||
"and add that in a new container, as a bootstrap responsive ('img-fluid py-3') image, with the maximum height of 30vh." +
|
||
"If there is anything marked important in the text, make sure to add that in your answer." +
|
||
"If there are links to be displayed, make sure to display them as clickable links." +
|
||
"After the welcome message, always add in a new div with container class: 'This website has a live, " +
|
||
"AI interface: if you have any questions, you can simply ask either by typing in the message " +
|
||
"box, or by clicking the microphone icon on the top of the page. '" +
|
||
"Here is a list of topics " + menuList +
|
||
", make a new bootstrap clearfix and after that make a clickable bootstrap " +
|
||
"styled (btn btn-primary) button from each of the determined topics, " +
|
||
"that calls the javascript function 'callAI({the name of the topic})' on click. " +
|
||
"Do not include anything else than the html title and text elements, no css, no scripts, no head or other tags." +
|
||
"Do not mark your answer with ```html or any other mark.";
|
||
return systemMessage;
|
||
}
|
||
}
|
||
|
||
public static class UserIntention
|
||
{
|
||
|
||
}
|
||
|
||
public static class ContentProcessing
|
||
{
|
||
|
||
public static string GetSystemMessageForJsonResultDecision(string language, string extractedText, string currentDom)
|
||
{
|
||
string systemMessage = $"You are a helpful assistant built in a website, trying to figure out what the User wants to do or know about.\r\n" +
|
||
"Your job is to classify the user's request into one of the following categories:\r\n" +
|
||
"1. **Ask about or search infromation in the website’s content** (Return a 'Text result')\r\n" +
|
||
"2. **Analyze the currently displayed HTML content** (Return an 'Examination result')\r\n" +
|
||
"3. **Initiate an action** (Return a 'Method result')\r\n" +
|
||
"If none of the above applies, return an 'Error result'.\r\n\r\n" +
|
||
|
||
"**Response format:**\r\n" +
|
||
"Strictly respond in " + language + " as a JSON object, using one of the following formats:\r\n" +
|
||
|
||
"1. **chatGPTMethodResult** (for initiating actions):\r\n" +
|
||
" - `type`: \"methodresult\"\r\n" +
|
||
" - `text`: A short explanation of what the user wants to do.\r\n" +
|
||
" - `methodToCall`: One of: [openContactForm, openCalendar, openApplicationForm]\r\n" +
|
||
" - `parameter`: [email address for openContactForm, calendlyUserName for openCalendar, empty string for openApplicationForm]\r\n\r\n" +
|
||
|
||
"2. **chatGPTTextResult** (for general website content searches):\r\n" +
|
||
" - `type`: \"textresult\"\r\n" +
|
||
" - `text`: The user’s unmodified query.\r\n\r\n" +
|
||
|
||
"3. **chatGPTExaminationResult** (for analyzing the currently displayed page only):\r\n" +
|
||
" - `type`: \"examinationresult\"\r\n" +
|
||
" - `text`: The user’s unmodified query.\r\n\r\n" +
|
||
|
||
"4. **chatGPTErrorResult** (for errors):\r\n" +
|
||
" - `type`: \"errorresult\"\r\n" +
|
||
" - `text`: A description of the issue encountered.\r\n\r\n" +
|
||
|
||
"**Decision Rules:**\r\n" +
|
||
"- If the user is **searching for website content** beyond what is currently displayed (e.g., 'Find information about our services'), return a `textresult`.\r\n" +
|
||
"- If the user is **asking about the currently visible content** (e.g., 'What is shown on the page?'), return an `examinationresult`.\r\n" +
|
||
"- If the user wants to **perform an action**, return a `methodresult`.\r\n" +
|
||
"- If the required parameter is missing, return an `errorresult`.\r\n\r\n" +
|
||
|
||
"**Examples:**\r\n" +
|
||
"- User asks: 'Show me information about pricing' → `textresult`\r\n" +
|
||
"- User asks: 'What is displayed right now?' → `examinationresult`\r\n" +
|
||
"- User asks: 'Open the contact form' → `methodresult`\r\n" +
|
||
"- User asks: 'Contact support' but no email is found → `errorresult`\r\n\r\n" +
|
||
|
||
"**Context:**\r\n" +
|
||
"- Base responses on this initial document: {" + extractedText + "}\r\n" +
|
||
"- Current displayed HTML: {" + currentDom + "}\r\n" +
|
||
|
||
"**IMPORTANT:**\r\n" +
|
||
"- If the request is about general content, **DO NOT use 'examinationresult'**.\r\n" +
|
||
"- If the request is about the currently displayed page, **DO NOT use 'textresult'**.\r\n" +
|
||
"- Do NOT format the response with markdown, code blocks, or `json` tags, do not add any title, or explanation besides the plain json object";
|
||
|
||
return systemMessage;
|
||
}
|
||
|
||
}
|
||
|
||
public static class HtmlGeneration
|
||
{
|
||
public const string BootstrapCard = "Generate a Bootstrap 5 card layout using the following content:";
|
||
public const string SectionLayout = "Create a responsive HTML5 layout section for this text:";
|
||
}
|
||
public static class LayoutPlanning
|
||
{
|
||
public static string GetLayoutPlanningSystemPrompt(List<HtmlSnippet> htmlToUse, Dictionary<string, string>? photos, string[]? topics)
|
||
{
|
||
var sb = new StringBuilder();
|
||
|
||
// 📌 STRICT FORMAT INSTRUCTION
|
||
sb.AppendLine("You are a helpful assistant whose ONLY task is to break down THE PROVIDED CONTENT into a structured JSON object for Bootstrap 5 pages, using \n" +
|
||
"**layoutplan**:\r\n" +
|
||
"- `title`: \"The title of the page\"\r\n" +
|
||
"- `blocks`: \"an array of layoutblocks\"\r\n" +
|
||
".");
|
||
|
||
if ((htmlToUse != null))
|
||
{
|
||
sb.AppendLine("\n### You have these html snippets provided:");
|
||
foreach (var snippet in htmlToUse)
|
||
{
|
||
//no need to paste the html code
|
||
//sb.AppendLine($"Snippet id: {snippet.Id}, Snippet name: {snippet.Name}, Snippet description: {snippet.Description}, Snippet type: {snippet.Type}, Snippet template code: {snippet.Html}");
|
||
sb.AppendLine($"Snippet id: {snippet.Id}, Snippet name: {snippet.Name}, Snippet description: {snippet.Description}, Snippet type: {snippet.Type}");
|
||
}
|
||
sb.AppendLine("- Use them ONLY if relevant.");
|
||
}
|
||
|
||
if (photos != null && photos.Any())
|
||
{
|
||
sb.AppendLine("\n### Photos to be used in the blocks:");
|
||
sb.AppendLine(string.Join(", ", photos.Select(kv => $"{kv.Key}: {kv.Value}")));
|
||
}
|
||
|
||
if (topics != null && topics.Any())
|
||
{
|
||
sb.AppendLine("\n### Topics:");
|
||
sb.AppendLine(string.Join(", ", topics));
|
||
}
|
||
|
||
sb.AppendLine("### ⛔️ ABSOLUTELY DO NOT:");
|
||
sb.AppendLine("- ❌ Return HTML structure trees like `<section><div>`...");
|
||
sb.AppendLine("- ❌ Include keys like `src`, `alt`, `url`, `items`, or nested object lists.");
|
||
sb.AppendLine("- ❌ Invent block types not on the list.");
|
||
sb.AppendLine("- ❌ Return any explanation, markdown, prose, comments, or fallback formats.");
|
||
sb.AppendLine("- ❌ Use any of these block types: `image`, `quote`, `list`, `layout`, `header`, `footer`, `sidebar`, etc.");
|
||
sb.AppendLine("- ❌ Remove messages for AI marked with []");
|
||
|
||
sb.AppendLine("\n### ✅ REQUIRED OUTPUT FORMAT:");
|
||
sb.AppendLine("{");
|
||
sb.AppendLine(" \"title\": \"string\",");
|
||
sb.AppendLine(" \"blocks\": [");
|
||
sb.AppendLine(" { \"type\": \"string\", \"rawcontent\": \"string (text)\", \"preferredsnippetid\" : an integer id of matching html snippet if one found., \"order\": an incremented integer to set the blocks in order }");
|
||
sb.AppendLine(" ]");
|
||
sb.AppendLine("}");
|
||
|
||
sb.AppendLine("\n### ✅ Allowed `type` values (only use these):");
|
||
sb.AppendLine("- hero");
|
||
sb.AppendLine("- text");
|
||
sb.AppendLine("- text-image");
|
||
sb.AppendLine("- features");
|
||
sb.AppendLine("- cta");
|
||
sb.AppendLine("- video");
|
||
sb.AppendLine("- icon-list");
|
||
sb.AppendLine("- event-list");
|
||
sb.AppendLine("- audio-player");
|
||
sb.AppendLine("- topic-buttons");
|
||
|
||
sb.AppendLine("\n### ❗ GOOD EXAMPLE:");
|
||
sb.AppendLine("{");
|
||
sb.AppendLine(" \"title\": \"Welcome to Our Product\",");
|
||
sb.AppendLine(" \"blocks\": [");
|
||
sb.AppendLine(" { \"type\": \"hero\", \"rawcontent\": \"Example text\", \"preferredsnippetid\": 1, \"order\": 0 },");
|
||
sb.AppendLine(" { \"type\": \"features\", \"rawcontent\": \"Example features\", \"order\": 1 },");
|
||
sb.AppendLine(" { \"type\": \"cta\", \"rawcontent\": \"call to action content\", \"order\": 2 }");
|
||
sb.AppendLine(" ]");
|
||
sb.AppendLine("}");
|
||
|
||
sb.AppendLine("\n### ⛔ BAD EXAMPLES (DO NOT DO THIS):");
|
||
sb.AppendLine("- { \"type\": \"image\", \"src\": \"...\", \"alt\": \"...\" }");
|
||
sb.AppendLine("- { \"type\": \"list\", \"items\": [\"...\", \"...\"] }");
|
||
sb.AppendLine("- { \"layout\": { \"header\": ..., \"footer\": ... } }");
|
||
|
||
sb.AppendLine("\n### FINAL TASK:");
|
||
sb.AppendLine("Based on the following content, generate a JSON object following the exact format above. Output only the JSON. No markdown. No other marks. No explanation. ONLY the pure JSON.");
|
||
|
||
return sb.ToString();
|
||
}
|
||
|
||
public static string GetLayoutPlanningUserPrompt(string interMediateResult, string pageTitle, Dictionary<string, string>? photos)
|
||
{
|
||
var userMessage = "Based on the following content:\n\n*** " + interMediateResult + " ***\n\n" +
|
||
"and the available photos:";
|
||
|
||
if (photos != null && photos.Any())
|
||
{
|
||
userMessage += "\n### Photo urls to be used WITHOUT ANY MODIFICATION in the blocks:";
|
||
userMessage += string.Join(", ", photos.Select(kv => $"{kv.Key}: {kv.Value}"));
|
||
}
|
||
|
||
userMessage += ", return ONLY a JSON object representing a structured content layout for a webpage with the title '" + pageTitle + "', with this exact shape:\n" +
|
||
"{ \"title\": string, \"blocks\": [ { \"type\": \"string\", \"rawcontent\": \"string (text)\", \"preferredsnippetid\" : an integer id of matching html snippet if one found., \"order\": an incremented integer to set the blocks in order } ] }\n\n" +
|
||
"⚠️ DO NOT use layout structures like 'header', 'sidebar', 'mainContent', or 'footer'.\n" +
|
||
"⚠️ DO NOT explain anything. Just return the pure JSON. No markdown, no ``` markers.\n\n" +
|
||
"🎯 OBJECTIVE:\n" +
|
||
"1. Determine 1 to 5 major content blocks from the input, grouping full paragraphs or sections together.\n" +
|
||
"Prefer **1 to 5 blocks max**, unless the content is extremely long. Each block should represent a semantically complete section.\r\n" +
|
||
"Group related ideas into one block, even if they are multiple paragraphs. Do NOT break up content just because it is a new sentence. \r\n" +
|
||
"2. Use meaningful, semantically grouped layout block types like: 'hero', 'features list', 'text with image', 'text', 'product list', 'call to action', 'videoplayer', 'audioplayer', etc.\n" +
|
||
"3. Each block should contain **rich content** and related photo ['photo url': 'the url of the photo'], not just one or two sentences. Group related ideas into a single `rawcontent` field.\n\n" +
|
||
"DO NOT REMOVE ANY URLS (photo, wen link, etc) from the section or paragraph that it follows. \n\n" +
|
||
"📌 Examples of good block grouping:\n" +
|
||
"- All introductory marketing text together in one 'hero' or 'text' block\n" +
|
||
"- A group of benefits or features into a single 'features' block\n" +
|
||
"- A pitch paragraph into a 'call to action' block\n\n" +
|
||
"🎨 Naming:\n" +
|
||
"- Try to find related type values in the available snippets list. If you find a relevant snippet for that block, use the name of that snippet for type, and add the id if the snippet as preferredsnippetid." +
|
||
"- If there is no relevant snippet, use such layout `type` values: hero, text, features, text with image, call to action, product list, team members, testimonial, event list, blogpost, article, video player, audio player, etc\n" +
|
||
"X Restrictions:" +
|
||
"- DO **NOT** modify the photo urls in any way." +
|
||
"- DO **NOT use the same text multiple times**" +
|
||
"- Do **NOT** generate or assume new photo URLs.\n" +
|
||
"- Do **NOT** modify photo URLs in any way.\n" +
|
||
"- Do **NOT** skip or deny ANY part of the provided text. All of the provided text should be put in blocks \n" +
|
||
"- Do **NOT** assume ANY content, like missing prices, missing links, etc. \n" +
|
||
"✅ Final output: JSON only, well grouped, no extra explanation or formatting, no markdown, no ``` markers.\n";
|
||
|
||
return userMessage;
|
||
}
|
||
}
|
||
|
||
public static class HtmlRendering
|
||
{
|
||
public static string GetHtmlRenderingSystemPromptForTextAndErrorResult(string language, string pageTitle, List<HtmlSnippet> htmlToUse, Dictionary<string, string>? photos, string[]? topics)
|
||
{
|
||
|
||
var sb = new StringBuilder($"You are a helpful assistant generating HTML in {language} using Bootstrap 5.\n\n" +
|
||
"### General Instructions:\n" +
|
||
"- Output only the **HTML content** between the menu and footer.\n" +
|
||
"- DO NOT include `<head>`, `<body>`, or markdown formatting.\n" +
|
||
"- Use `<h1 class='p-3'>` for the title: " + pageTitle + ".\n" +
|
||
"- Structure sections inside separate `<section>` or `<div class='row'>` blocks.\n" +
|
||
"- Use Bootstrap spacing and layout classes:\n" +
|
||
" - Use `row justify-content-center` for rows.\n" +
|
||
" - Use `col-xx-x` only for multiple-column layouts.\n" +
|
||
" - Always use `img-fluid` for images.\n" +
|
||
"- Avoid: unnecessary paragraph classes, nesting `<img>` inside `<p>`, or using `col` for single-column content.\n\n");
|
||
|
||
if (htmlToUse != null && htmlToUse.Any())
|
||
{
|
||
sb.AppendLine("### Snippet Handling:\n" +
|
||
"- You are provided with multiple HTML snippets:\n");
|
||
|
||
foreach (var snippet in htmlToUse)
|
||
{
|
||
sb.AppendLine($"{snippet.Id}: {snippet.Name}: {snippet.Html}\n");
|
||
sb.AppendLine($"Type: {snippet.Type}, Tags: {snippet.Tags}, Variant: {snippet.Variant}\n");
|
||
}
|
||
|
||
sb.AppendLine(
|
||
"- Use each snippet as a separate `<section>`.\n" +
|
||
"- DO NOT merge snippets into one block.\n" +
|
||
"- Use snippets only if they match the content block.\n" +
|
||
"- Prefer variants with images if image content is present.\n" +
|
||
"- Always use a short title in `<h>` and place body text in a `<p>`.\n" +
|
||
"- If snippet includes a button, wrap it in `<div class='text-center'>`.\n");
|
||
}
|
||
|
||
if (photos != null && photos.Any())
|
||
{
|
||
sb.AppendLine("### Photo Usage:\n" +
|
||
"- Use ONLY the following image URLs as-is (no changes):\n" +
|
||
string.Join(", ", photos.Select(kv => $"{kv.Key}: {kv.Value}")) + "\n" +
|
||
"- Example:\n" +
|
||
$" <img src='{photos.First().Value}' class='img-fluid' alt='{photos.First().Key}' />\n" +
|
||
"- DO NOT generate or modify photo URLs.\n");
|
||
}
|
||
|
||
if (topics != null && topics.Any())
|
||
{
|
||
sb.AppendLine("### Topic Buttons:\n" +
|
||
"- Place this section last, titled `Related`.\n" +
|
||
"- Generate a `btn btn-primary` for each topic, calling `callAI('{original_non_translated_topicName}')`.\n" +
|
||
"- Translate topic names to " + language + " if needed.\n" +
|
||
"- Example:\n" +
|
||
$" <button class='btn btn-primary' onclick='callAI(\"{topics.FirstOrDefault()}\")'>{topics.FirstOrDefault()}</button>\n");
|
||
}
|
||
else
|
||
{
|
||
sb.AppendLine("- No topics provided → DO NOT generate topic buttons.");
|
||
}
|
||
|
||
sb.AppendLine("\n### DO NOT:\n" +
|
||
"- DO **NOT** merge different content blocks.\n" +
|
||
"- DO **NOT** remove javascript or <script> tags" +
|
||
"- DO **NOT** wrap the full output in a single `div`.\n" +
|
||
"- DO **NOT** skip any provided content.\n" +
|
||
"- DO **NOT** add assumed text (e.g. prices, links).\n" +
|
||
"- DO **NOT** add `<img>` if no image URL exists.\n" +
|
||
"- DO **NOT** modify image URLs. not even adding 'https://example.com or such before the relaitve path'\n" +
|
||
"- DO **NOT** include explanation, markdown, or ` ```html` markers.\n");
|
||
|
||
|
||
|
||
return sb.ToString();
|
||
}
|
||
|
||
public static string HtmlRenderingUserPromptForTextAndErrorResult = "Create a perfect, production ready, structured, responsive Bootstrap 5 webpage " +
|
||
"content from the provided layout and available html snippets. \r \n" +
|
||
"Read the layout plan, analyze the blocks, and identify if there is any matching html snippets for each block folowing these rules: \r \n" +
|
||
"- If there is no matching html snippet, generate the bootstrap 5 based layout for the given block. Else parse the block content into the available code snippet." +
|
||
"- For each block, add am opening and closing comment with the name of the block like: <!-- Hero start --> \r \n" +
|
||
"- Do not remove script tags from the provided snippets. \r \n" +
|
||
"If the block's rawcontent contains photo url, display that photo within that section, not elsewhere. ";
|
||
|
||
public static string GetHtmlRenderingAssistantMessageForTextAndErrorResult(LayoutPlan layoutPlan)
|
||
{
|
||
string assistantMessage = "`Provided layout plan, that contains the text to be displayed as HTML`:";
|
||
|
||
foreach (var block in layoutPlan.Blocks)
|
||
{
|
||
assistantMessage += $"Block type: {block.Type}, block content: {block.RawContent}";
|
||
}
|
||
return assistantMessage;
|
||
}
|
||
|
||
public static string GetHtmlRenderingSystemPromptForMethodResult(string language, string methodToCall, string methodParameter)
|
||
{
|
||
var sb = new StringBuilder("You are a helpful assistant generating HTML content in " + language + " using Bootstrap. \n\n" +
|
||
"### Rules to Follow: \n" +
|
||
"- Please generate clean and structured HTML that goes inside a Bootstrap container.\n" +
|
||
"- DO NOT include `<head>`, `<body>` tags — only content inside the Bootstrap container.\n" +
|
||
"- Use `<h1 class='p-3'>` for a short title followed by the content, based on the user's query.\n" +
|
||
"- Structure content using **separate `row` elements** for different sections.\n" +
|
||
"- Use Bootstrap classes to ensure proper spacing and alignment.\n" +
|
||
" - Use 'row justify-content-center' for layout, 'col-xx-x' classes for columns (ONLY IF multiple columns are needed), and always use 'img-fluid' class for images.\r\n" +
|
||
" - Do NOT use 'col' class if there is only one column to display in the row. \n" +
|
||
"- Do NOT use additional class for paragraphs! \n" +
|
||
"- Do NOT nest images inside paragraphs! \n" +
|
||
"- Ensure clear **separation of content into multiple sections if multiple snippets are provided**.\n");
|
||
|
||
if (!string.IsNullOrEmpty(methodToCall))
|
||
{
|
||
sb.AppendLine("- At the END of the content, include a **single** Bootstrap button (`btn btn-primary`) that calls `" + methodToCall + "` with `" + methodParameter + "` on click.\n");
|
||
}
|
||
|
||
sb.AppendLine("- DO **NOT** merge different content sections.\n" +
|
||
"- DO **NOT** wrap the entire content in a single `div`— use separate `row` divs.\n" +
|
||
"- Do **NOT** skip or deny ANY part of the provided text. All of the provided text should be displayed as html\n" +
|
||
"- Do **NOT** assume ANY content, like missing prices, missing links. \n" +
|
||
"- If the snippet contains an image, but there is no photo url available, SKIP adding the image tag." +
|
||
"- **Never** add explanations or start with ```html syntax markers.\n");
|
||
|
||
return sb.ToString();
|
||
}
|
||
}
|
||
}
|
||
}
|