754 lines
33 KiB
C#
754 lines
33 KiB
C#
using System.Text.Json;
|
|
using System.Text.RegularExpressions;
|
|
using Microsoft.Extensions.Options;
|
|
using ChatRAG.Services.Confidence;
|
|
using ChatRAG.Settings;
|
|
using Microsoft.Extensions.Configuration;
|
|
|
|
namespace ChatRAG.Services.PromptConfiguration
|
|
{
|
|
/// <summary>
|
|
/// Serviço para configuração e carregamento de prompts por domínio e idioma
|
|
/// </summary>
|
|
public class PromptConfigurationService
|
|
{
|
|
private readonly ILogger<PromptConfigurationService> _logger;
|
|
private readonly string _configurationPath;
|
|
private readonly LanguageSettings _languageSettings;
|
|
private readonly CacheSettings _cacheSettings;
|
|
|
|
private Dictionary<string, DomainPromptConfig> _domainConfigs = new();
|
|
private BasePromptConfig _baseConfig = new();
|
|
private readonly Dictionary<string, DateTime> _fileLastModified = new();
|
|
private readonly object _lockObject = new object();
|
|
|
|
public PromptConfigurationService(
|
|
ILogger<PromptConfigurationService> logger,
|
|
IConfiguration configuration,
|
|
IOptions<ConfidenceAwareSettings> settings)
|
|
{
|
|
_logger = logger;
|
|
_configurationPath = configuration["PromptConfiguration:Path"] ?? "Configuration/Prompts";
|
|
_languageSettings = settings.Value.Languages;
|
|
_cacheSettings = settings.Value.Cache;
|
|
|
|
// Carregar configurações na inicialização
|
|
_ = Task.Run(LoadConfigurations);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Obtém prompts configurados para um domínio e idioma específicos
|
|
/// </summary>
|
|
public PromptTemplates GetPrompts(string? domain = null, string language = "pt")
|
|
{
|
|
// Verificar se precisa recarregar arquivos (se habilitado)
|
|
if (_cacheSettings.AutoReloadOnFileChange)
|
|
{
|
|
CheckForFileChanges();
|
|
}
|
|
|
|
// Detectar idioma se auto-detecção estiver habilitada
|
|
var detectedLanguage = _languageSettings.AutoDetectLanguage
|
|
? DetectOrValidateLanguage(language)
|
|
: language;
|
|
|
|
var domainConfig = domain != null && _domainConfigs.ContainsKey(domain)
|
|
? _domainConfigs[domain]
|
|
: null;
|
|
|
|
return new PromptTemplates
|
|
{
|
|
QueryAnalysis = GetPrompt("QueryAnalysis", domainConfig, detectedLanguage),
|
|
Overview = GetPrompt("Overview", domainConfig, detectedLanguage),
|
|
Specific = GetPrompt("Specific", domainConfig, detectedLanguage),
|
|
Detailed = GetPrompt("Detailed", domainConfig, detectedLanguage),
|
|
Response = GetPrompt("Response", domainConfig, detectedLanguage),
|
|
Summary = GetPrompt("Summary", domainConfig, detectedLanguage),
|
|
GapAnalysis = GetPrompt("GapAnalysis", domainConfig, detectedLanguage)
|
|
};
|
|
}
|
|
|
|
/// <summary>
|
|
/// Detecta o domínio baseado na pergunta e descrição do projeto
|
|
/// </summary>
|
|
public string? DetectDomain(string question, string? projectDescription = null)
|
|
{
|
|
var content = $"{question} {projectDescription}".ToLower();
|
|
var domainScores = new Dictionary<string, int>();
|
|
|
|
foreach (var (domain, config) in _domainConfigs)
|
|
{
|
|
var score = 0;
|
|
|
|
// Pontuação por palavras-chave (peso 2)
|
|
foreach (var keyword in config.Keywords)
|
|
{
|
|
if (content.Contains(keyword.ToLower()))
|
|
{
|
|
score += 2;
|
|
}
|
|
}
|
|
|
|
// Pontuação por conceitos (peso 1)
|
|
foreach (var concept in config.Concepts)
|
|
{
|
|
if (content.Contains(concept.ToLower()))
|
|
{
|
|
score += 1;
|
|
}
|
|
}
|
|
|
|
if (score > 0)
|
|
{
|
|
domainScores[domain] = score;
|
|
}
|
|
}
|
|
|
|
if (domainScores.Any())
|
|
{
|
|
var bestDomain = domainScores.OrderByDescending(x => x.Value).First();
|
|
_logger.LogDebug("Domínio detectado: {Domain} com score {Score}", bestDomain.Key, bestDomain.Value);
|
|
return bestDomain.Key;
|
|
}
|
|
|
|
_logger.LogDebug("Nenhum domínio detectado, usando padrão");
|
|
return null;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Detecta o idioma da pergunta
|
|
/// </summary>
|
|
public string DetectLanguage(string question)
|
|
{
|
|
if (string.IsNullOrWhiteSpace(question))
|
|
return _languageSettings.DefaultLanguage;
|
|
|
|
var languageScores = new Dictionary<string, int>();
|
|
var words = Regex.Split(question.ToLower(), @"\W+")
|
|
.Where(w => w.Length > 2)
|
|
.ToList();
|
|
|
|
foreach (var (language, keywords) in _languageSettings.LanguageKeywords)
|
|
{
|
|
var score = words.Count(word => keywords.Contains(word));
|
|
if (score > 0)
|
|
{
|
|
languageScores[language] = score;
|
|
}
|
|
}
|
|
|
|
if (languageScores.Any())
|
|
{
|
|
var detectedLanguage = languageScores.OrderByDescending(x => x.Value).First().Key;
|
|
_logger.LogDebug("Idioma detectado: {Language}", detectedLanguage);
|
|
return detectedLanguage;
|
|
}
|
|
|
|
_logger.LogDebug("Idioma não detectado, usando padrão: {DefaultLanguage}", _languageSettings.DefaultLanguage);
|
|
return _languageSettings.DefaultLanguage;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Lista domínios disponíveis
|
|
/// </summary>
|
|
public List<string> GetAvailableDomains()
|
|
{
|
|
return _domainConfigs.Keys.ToList();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Lista idiomas suportados
|
|
/// </summary>
|
|
public List<string> GetSupportedLanguages()
|
|
{
|
|
return _languageSettings.SupportedLanguages;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Força recarregamento das configurações
|
|
/// </summary>
|
|
public async Task ReloadConfigurations()
|
|
{
|
|
await LoadConfigurations();
|
|
}
|
|
|
|
// === MÉTODOS PRIVADOS ===
|
|
|
|
private void LoadBaseConfigurationSync()
|
|
{
|
|
var basePath = Path.Combine(_configurationPath, "base-prompts.json");
|
|
|
|
if (File.Exists(basePath))
|
|
{
|
|
try
|
|
{
|
|
var json = File.ReadAllText(basePath);
|
|
_baseConfig = JsonSerializer.Deserialize<BasePromptConfig>(json) ?? new BasePromptConfig();
|
|
_fileLastModified[basePath] = File.GetLastWriteTime(basePath);
|
|
_logger.LogDebug("Configuração base carregada de {Path}", basePath);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogError(ex, "Erro ao carregar configuração base de {Path}", basePath);
|
|
_baseConfig = GetDefaultBaseConfig();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
_logger.LogInformation("Arquivo base não encontrado, criando padrão em {Path}", basePath);
|
|
_baseConfig = GetDefaultBaseConfig();
|
|
SaveBaseConfigurationSync(basePath);
|
|
}
|
|
}
|
|
|
|
private void LoadDomainConfigurationsSync()
|
|
{
|
|
var domainsPath = Path.Combine(_configurationPath, "Domains");
|
|
|
|
if (!Directory.Exists(domainsPath))
|
|
{
|
|
_logger.LogInformation("Pasta de domínios não encontrada, criando em {Path}", domainsPath);
|
|
Directory.CreateDirectory(domainsPath);
|
|
CreateDefaultDomainConfigurationsSync(domainsPath);
|
|
}
|
|
|
|
var domainFiles = Directory.GetFiles(domainsPath, "*.json");
|
|
var loadedDomains = new Dictionary<string, DomainPromptConfig>();
|
|
|
|
foreach (var file in domainFiles)
|
|
{
|
|
try
|
|
{
|
|
var json = File.ReadAllText(file);
|
|
var config = JsonSerializer.Deserialize<DomainPromptConfig>(json);
|
|
if (config != null)
|
|
{
|
|
var domainName = Path.GetFileNameWithoutExtension(file);
|
|
loadedDomains[domainName] = config;
|
|
_fileLastModified[file] = File.GetLastWriteTime(file);
|
|
_logger.LogDebug("Domínio {Domain} carregado de {File}", domainName, file);
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogWarning(ex, "Erro ao carregar configuração do domínio: {File}", file);
|
|
}
|
|
}
|
|
|
|
_domainConfigs = loadedDomains;
|
|
}
|
|
|
|
private void CheckForFileChanges()
|
|
{
|
|
if (!_cacheSettings.AutoReloadOnFileChange) return;
|
|
|
|
var needsReload = false;
|
|
var filesToCheck = new List<string> { Path.Combine(_configurationPath, "base-prompts.json") };
|
|
|
|
var domainsPath = Path.Combine(_configurationPath, "Domains");
|
|
if (Directory.Exists(domainsPath))
|
|
{
|
|
filesToCheck.AddRange(Directory.GetFiles(domainsPath, "*.json"));
|
|
}
|
|
|
|
foreach (var file in filesToCheck)
|
|
{
|
|
if (File.Exists(file))
|
|
{
|
|
var lastModified = File.GetLastWriteTime(file);
|
|
if (!_fileLastModified.ContainsKey(file) || _fileLastModified[file] < lastModified)
|
|
{
|
|
_logger.LogInformation("Arquivo modificado detectado: {File}", file);
|
|
needsReload = true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (needsReload)
|
|
{
|
|
_ = Task.Run(LoadConfigurations);
|
|
}
|
|
}
|
|
|
|
private string DetectOrValidateLanguage(string language)
|
|
{
|
|
// Se o idioma é suportado, usar ele
|
|
if (_languageSettings.SupportedLanguages.Contains(language))
|
|
{
|
|
return language;
|
|
}
|
|
|
|
_logger.LogWarning("Idioma não suportado: {Language}, usando padrão: {DefaultLanguage}",
|
|
language, _languageSettings.DefaultLanguage);
|
|
return _languageSettings.DefaultLanguage;
|
|
}
|
|
|
|
private string GetPrompt(string promptType, DomainPromptConfig? domainConfig, string language)
|
|
{
|
|
// 1. Tentar buscar no domínio específico e idioma específico
|
|
if (domainConfig?.Prompts.ContainsKey(language) == true &&
|
|
domainConfig.Prompts[language].ContainsKey(promptType))
|
|
{
|
|
return domainConfig.Prompts[language][promptType];
|
|
}
|
|
|
|
// 2. Tentar buscar no domínio específico no idioma padrão
|
|
if (domainConfig?.Prompts.ContainsKey(_languageSettings.DefaultLanguage) == true &&
|
|
domainConfig.Prompts[_languageSettings.DefaultLanguage].ContainsKey(promptType))
|
|
{
|
|
var prompt = domainConfig.Prompts[_languageSettings.DefaultLanguage][promptType];
|
|
return _languageSettings.AlwaysRespondInRequestedLanguage && language != _languageSettings.DefaultLanguage
|
|
? AddLanguageInstruction(prompt, language)
|
|
: prompt;
|
|
}
|
|
|
|
// 3. Fallback para configuração base no idioma solicitado
|
|
if (_baseConfig.Prompts.ContainsKey(language) &&
|
|
_baseConfig.Prompts[language].ContainsKey(promptType))
|
|
{
|
|
return _baseConfig.Prompts[language][promptType];
|
|
}
|
|
|
|
// 4. Fallback para configuração base no idioma padrão
|
|
if (_baseConfig.Prompts.ContainsKey(_languageSettings.DefaultLanguage) &&
|
|
_baseConfig.Prompts[_languageSettings.DefaultLanguage].ContainsKey(promptType))
|
|
{
|
|
var prompt = _baseConfig.Prompts[_languageSettings.DefaultLanguage][promptType];
|
|
return _languageSettings.AlwaysRespondInRequestedLanguage && language != _languageSettings.DefaultLanguage
|
|
? AddLanguageInstruction(prompt, language)
|
|
: prompt;
|
|
}
|
|
|
|
// 5. Fallback final
|
|
return GetFallbackPrompt(promptType, language);
|
|
}
|
|
|
|
private string AddLanguageInstruction(string prompt, string targetLanguage)
|
|
{
|
|
var instruction = targetLanguage switch
|
|
{
|
|
"en" => "\n\nIMPORTANT: Respond in English.",
|
|
"pt" => "\n\nIMPORTANTE: Responda em português.",
|
|
_ => $"\n\nIMPORTANT: Respond in {targetLanguage}."
|
|
};
|
|
|
|
return prompt + instruction;
|
|
}
|
|
|
|
private void SaveBaseConfigurationSync(string basePath)
|
|
{
|
|
try
|
|
{
|
|
Directory.CreateDirectory(Path.GetDirectoryName(basePath)!);
|
|
|
|
var options = new JsonSerializerOptions
|
|
{
|
|
WriteIndented = true,
|
|
Encoder = System.Text.Encodings.Web.JavaScriptEncoder.UnsafeRelaxedJsonEscaping
|
|
};
|
|
|
|
var json = JsonSerializer.Serialize(_baseConfig, options);
|
|
File.WriteAllText(basePath, json);
|
|
_logger.LogInformation("Configuração base salva em {Path}", basePath);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogError(ex, "Erro ao salvar configuração base em {Path}", basePath);
|
|
}
|
|
}
|
|
|
|
private void CreateDefaultDomainConfigurationsSync(string domainsPath)
|
|
{
|
|
var domains = new Dictionary<string, DomainPromptConfig>
|
|
{
|
|
["TI"] = GetTIDomainConfig(),
|
|
["RH"] = GetRHDomainConfig(),
|
|
["Financeiro"] = GetFinanceiroDomainConfig(),
|
|
["QA"] = GetQADomainConfig()
|
|
};
|
|
|
|
var options = new JsonSerializerOptions
|
|
{
|
|
WriteIndented = true,
|
|
Encoder = System.Text.Encodings.Web.JavaScriptEncoder.UnsafeRelaxedJsonEscaping
|
|
};
|
|
|
|
foreach (var (domain, config) in domains)
|
|
{
|
|
try
|
|
{
|
|
var filePath = Path.Combine(domainsPath, $"{domain}.json");
|
|
var json = JsonSerializer.Serialize(config, options);
|
|
File.WriteAllText(filePath, json);
|
|
_logger.LogInformation("Configuração de domínio {Domain} criada em {Path}", domain, filePath);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogError(ex, "Erro ao criar configuração do domínio {Domain}", domain);
|
|
}
|
|
}
|
|
}
|
|
|
|
private BasePromptConfig GetDefaultBaseConfig()
|
|
{
|
|
return new BasePromptConfig
|
|
{
|
|
Prompts = new Dictionary<string, Dictionary<string, string>>
|
|
{
|
|
["pt"] = new Dictionary<string, string>
|
|
{
|
|
["QueryAnalysis"] = @"Analise esta pergunta e classifique com precisão:
|
|
PERGUNTA: ""{0}""
|
|
|
|
Responda APENAS no formato JSON:
|
|
{{
|
|
""strategy"": ""overview|specific|detailed"",
|
|
""complexity"": ""simple|medium|complex"",
|
|
""scope"": ""global|filtered|targeted"",
|
|
""concepts"": [""conceito1"", ""conceito2""],
|
|
""needs_hierarchy"": true|false
|
|
}}
|
|
|
|
DEFINIÇÕES PRECISAS:
|
|
STRATEGY:
|
|
- overview: Pergunta sobre o PROJETO COMO UM TODO
|
|
- specific: Pergunta sobre MÓDULO/FUNCIONALIDADE ESPECÍFICA
|
|
- detailed: Pergunta técnica específica que precisa de CONTEXTO PROFUNDO",
|
|
|
|
["Response"] = @"Você é um especialista em análise de software e QA.
|
|
|
|
PROJETO: {0}
|
|
PERGUNTA: ""{1}""
|
|
CONTEXTO HIERÁRQUICO: {2}
|
|
ETAPAS EXECUTADAS: {3}
|
|
|
|
Responda à pergunta de forma precisa e estruturada, aproveitando todo o contexto hierárquico coletado.",
|
|
|
|
["Summary"] = @"Resuma os pontos principais destes documentos sobre {0}:
|
|
|
|
{1}
|
|
|
|
Responda apenas com uma lista concisa dos pontos mais importantes:",
|
|
|
|
["GapAnalysis"] = @"Baseado na pergunta e contexto atual, identifique que informações ainda faltam para uma resposta completa.
|
|
|
|
PERGUNTA: {0}
|
|
CONTEXTO ATUAL: {1}
|
|
|
|
Responda APENAS com palavras-chave dos conceitos/informações que ainda faltam, separados por vírgula.
|
|
Se o contexto for suficiente, responda 'SUFICIENTE'."
|
|
},
|
|
["en"] = new Dictionary<string, string>
|
|
{
|
|
["QueryAnalysis"] = @"Analyze this question and classify precisely:
|
|
QUESTION: ""{0}""
|
|
|
|
Answer ONLY in JSON format:
|
|
{{
|
|
""strategy"": ""overview|specific|detailed"",
|
|
""complexity"": ""simple|medium|complex"",
|
|
""scope"": ""global|filtered|targeted"",
|
|
""concepts"": [""concept1"", ""concept2""],
|
|
""needs_hierarchy"": true|false
|
|
}}
|
|
|
|
PRECISE DEFINITIONS:
|
|
STRATEGY:
|
|
- overview: Question about the PROJECT AS A WHOLE
|
|
- specific: Question about SPECIFIC MODULE/FUNCTIONALITY
|
|
- detailed: Technical specific question needing DEEP CONTEXT",
|
|
|
|
["Response"] = @"You are a software analysis and QA expert.
|
|
|
|
PROJECT: {0}
|
|
QUESTION: ""{1}""
|
|
HIERARCHICAL CONTEXT: {2}
|
|
EXECUTED STEPS: {3}
|
|
|
|
Answer the question precisely and structured, leveraging all the hierarchical context collected.",
|
|
|
|
["Summary"] = @"Summarize the main points of these documents about {0}:
|
|
|
|
{1}
|
|
|
|
Answer only with a concise list of the most important points:",
|
|
|
|
["GapAnalysis"] = @"Based on the question and current context, identify what information is still missing for a complete answer.
|
|
|
|
QUESTION: {0}
|
|
CURRENT CONTEXT: {1}
|
|
|
|
Answer ONLY with keywords of missing concepts/information, separated by commas.
|
|
If the context is sufficient, answer 'SUFFICIENT'."
|
|
}
|
|
}
|
|
};
|
|
}
|
|
|
|
private DomainPromptConfig GetTIDomainConfig()
|
|
{
|
|
return new DomainPromptConfig
|
|
{
|
|
Name = "Tecnologia da Informação",
|
|
Description = "Configurações para projetos de TI e desenvolvimento de software",
|
|
Keywords = ["api", "backend", "frontend", "database", "arquitetura", "código", "classe", "método", "endpoint", "sistema", "software"],
|
|
Concepts = ["mvc", "rest", "microservices", "clean architecture", "design patterns", "authentication", "authorization", "crud"],
|
|
Prompts = new Dictionary<string, Dictionary<string, string>>
|
|
{
|
|
["pt"] = new Dictionary<string, string>
|
|
{
|
|
["Response"] = @"Você é um especialista em desenvolvimento de software e arquitetura de sistemas.
|
|
|
|
PROJETO TÉCNICO: {0}
|
|
PERGUNTA TÉCNICA: ""{1}""
|
|
CONTEXTO TÉCNICO: {2}
|
|
ANÁLISE REALIZADA: {3}
|
|
|
|
Responda com foco técnico, incluindo:
|
|
- Implementação prática
|
|
- Boas práticas de código
|
|
- Considerações de arquitetura
|
|
- Exemplos de código quando relevante
|
|
|
|
Seja preciso e técnico na resposta."
|
|
},
|
|
["en"] = new Dictionary<string, string>
|
|
{
|
|
["Response"] = @"You are a software development and system architecture expert.
|
|
|
|
TECHNICAL PROJECT: {0}
|
|
TECHNICAL QUESTION: ""{1}""
|
|
TECHNICAL CONTEXT: {2}
|
|
ANALYSIS PERFORMED: {3}
|
|
|
|
Answer with technical focus, including:
|
|
- Practical implementation
|
|
- Code best practices
|
|
- Architecture considerations
|
|
- Code examples when relevant
|
|
|
|
Be precise and technical in your response."
|
|
}
|
|
}
|
|
};
|
|
}
|
|
|
|
private DomainPromptConfig GetRHDomainConfig()
|
|
{
|
|
return new DomainPromptConfig
|
|
{
|
|
Name = "Recursos Humanos",
|
|
Description = "Configurações para projetos de RH e gestão de pessoas",
|
|
Keywords = ["funcionário", "colaborador", "cargo", "departamento", "folha", "benefícios", "treinamento", "employee", "hr"],
|
|
Concepts = ["gestão de pessoas", "recrutamento", "seleção", "avaliação", "desenvolvimento", "human resources"],
|
|
Prompts = new Dictionary<string, Dictionary<string, string>>
|
|
{
|
|
["pt"] = new Dictionary<string, string>
|
|
{
|
|
["Response"] = @"Você é um especialista em Recursos Humanos e gestão de pessoas.
|
|
|
|
SISTEMA DE RH: {0}
|
|
PERGUNTA: ""{1}""
|
|
CONTEXTO: {2}
|
|
PROCESSOS ANALISADOS: {3}
|
|
|
|
Responda considerando:
|
|
- Políticas de RH
|
|
- Fluxos de trabalho
|
|
- Compliance e regulamentações
|
|
- Melhores práticas em gestão de pessoas
|
|
|
|
Seja claro e prático nas recomendações."
|
|
},
|
|
["en"] = new Dictionary<string, string>
|
|
{
|
|
["Response"] = @"You are a Human Resources and people management expert.
|
|
|
|
HR SYSTEM: {0}
|
|
QUESTION: ""{1}""
|
|
CONTEXT: {2}
|
|
ANALYZED PROCESSES: {3}
|
|
|
|
Answer considering:
|
|
- HR policies
|
|
- Workflows
|
|
- Compliance and regulations
|
|
- Best practices in people management
|
|
|
|
Be clear and practical in recommendations."
|
|
}
|
|
}
|
|
};
|
|
}
|
|
|
|
private DomainPromptConfig GetFinanceiroDomainConfig()
|
|
{
|
|
return new DomainPromptConfig
|
|
{
|
|
Name = "Financeiro",
|
|
Description = "Configurações para projetos financeiros e contábeis",
|
|
Keywords = ["financeiro", "contábil", "faturamento", "cobrança", "pagamento", "receita", "despesa", "financial", "accounting"],
|
|
Concepts = ["fluxo de caixa", "conciliação", "relatórios financeiros", "impostos", "audit trail", "cash flow"],
|
|
Prompts = new Dictionary<string, Dictionary<string, string>>
|
|
{
|
|
["pt"] = new Dictionary<string, string>
|
|
{
|
|
["Response"] = @"Você é um especialista em sistemas financeiros e contabilidade.
|
|
|
|
SISTEMA FINANCEIRO: {0}
|
|
PERGUNTA: ""{1}""
|
|
CONTEXTO FINANCEIRO: {2}
|
|
ANÁLISE REALIZADA: {3}
|
|
|
|
Responda considerando:
|
|
- Controles financeiros
|
|
- Auditoria e compliance
|
|
- Fluxos de aprovação
|
|
- Relatórios gerenciais
|
|
- Segurança de dados financeiros
|
|
|
|
Seja preciso e considere aspectos regulatórios."
|
|
},
|
|
["en"] = new Dictionary<string, string>
|
|
{
|
|
["Response"] = @"You are a financial systems and accounting expert.
|
|
|
|
FINANCIAL SYSTEM: {0}
|
|
QUESTION: ""{1}""
|
|
FINANCIAL CONTEXT: {2}
|
|
ANALYSIS PERFORMED: {3}
|
|
|
|
Answer considering:
|
|
- Financial controls
|
|
- Audit and compliance
|
|
- Approval workflows
|
|
- Management reports
|
|
- Financial data security
|
|
|
|
Be precise and consider regulatory aspects."
|
|
}
|
|
}
|
|
};
|
|
}
|
|
|
|
private DomainPromptConfig GetQADomainConfig()
|
|
{
|
|
return new DomainPromptConfig
|
|
{
|
|
Name = "Quality Assurance",
|
|
Description = "Configurações para projetos de QA e testes",
|
|
Keywords = ["teste", "qa", "qualidade", "bug", "defeito", "validação", "verificação", "quality", "testing"],
|
|
Concepts = ["test cases", "automation", "regression", "performance", "security testing", "casos de teste"],
|
|
Prompts = new Dictionary<string, Dictionary<string, string>>
|
|
{
|
|
["pt"] = new Dictionary<string, string>
|
|
{
|
|
["Response"] = @"Você é um especialista em Quality Assurance e testes de software.
|
|
|
|
PROJETO: {0}
|
|
PERGUNTA DE QA: ""{1}""
|
|
CONTEXTO DE TESTES: {2}
|
|
ANÁLISE EXECUTADA: {3}
|
|
|
|
Responda com foco em:
|
|
- Estratégias de teste
|
|
- Casos de teste específicos
|
|
- Automação e ferramentas
|
|
- Critérios de aceitação
|
|
- Cobertura de testes
|
|
|
|
Seja detalhado e metodológico na abordagem."
|
|
},
|
|
["en"] = new Dictionary<string, string>
|
|
{
|
|
["Response"] = @"You are a Quality Assurance and software testing expert.
|
|
|
|
PROJECT: {0}
|
|
QA QUESTION: ""{1}""
|
|
TESTING CONTEXT: {2}
|
|
ANALYSIS EXECUTED: {3}
|
|
|
|
Answer focusing on:
|
|
- Testing strategies
|
|
- Specific test cases
|
|
- Automation and tools
|
|
- Acceptance criteria
|
|
- Test coverage
|
|
|
|
Be detailed and methodical in your approach."
|
|
}
|
|
}
|
|
};
|
|
}
|
|
|
|
private string GetFallbackPrompt(string promptType, string language)
|
|
{
|
|
return language == "en" ? promptType switch
|
|
{
|
|
"QueryAnalysis" => "Analyze the question: {0}",
|
|
"Response" => "Answer based on context: {2}",
|
|
"Summary" => "Summarize: {1}",
|
|
"GapAnalysis" => "Identify gaps for: {0}",
|
|
_ => "Process the request: {0}"
|
|
} : promptType switch
|
|
{
|
|
"QueryAnalysis" => "Analise a pergunta: {0}",
|
|
"Response" => "Responda baseado no contexto: {2}",
|
|
"Summary" => "Resuma: {1}",
|
|
"GapAnalysis" => "Identifique lacunas para: {0}",
|
|
_ => "Processe a solicitação: {0}"
|
|
};
|
|
}
|
|
|
|
/// Carrega todas as configurações de prompts
|
|
/// </summary>
|
|
public async Task LoadConfigurations()
|
|
{
|
|
lock (_lockObject)
|
|
{
|
|
try
|
|
{
|
|
LoadBaseConfigurationSync();
|
|
LoadDomainConfigurationsSync();
|
|
_logger.LogInformation("Carregados {DomainCount} domínios de prompt em {ConfigPath}",
|
|
_domainConfigs.Count, _configurationPath);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogError(ex, "Erro ao carregar configurações de prompt");
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
}
|
|
|
|
// === MODELOS DE DADOS ===
|
|
|
|
public class PromptTemplates
|
|
{
|
|
public string QueryAnalysis { get; set; } = "";
|
|
public string Overview { get; set; } = "";
|
|
public string Specific { get; set; } = "";
|
|
public string Detailed { get; set; } = "";
|
|
public string Response { get; set; } = "";
|
|
public string Summary { get; set; } = "";
|
|
public string GapAnalysis { get; set; } = "";
|
|
}
|
|
|
|
public class BasePromptConfig
|
|
{
|
|
public Dictionary<string, Dictionary<string, string>> Prompts { get; set; } = new();
|
|
}
|
|
|
|
public class DomainPromptConfig
|
|
{
|
|
public string Name { get; set; } = "";
|
|
public string Description { get; set; } = "";
|
|
public List<string> Keywords { get; set; } = new();
|
|
public List<string> Concepts { get; set; } = new();
|
|
public Dictionary<string, Dictionary<string, string>> Prompts { get; set; } = new();
|
|
}
|
|
}
|