Merge pull request 'AI_Integration_In_EchoTex_Payroll_dev_sabbir' (#58) from dev_sabbir into devqc

Reviewed-on: http://103.197.204.162:3025/CelHRTeam/EchoTex_Payroll/pulls/58
This commit is contained in:
shamim 2026-07-13 16:38:02 +06:00
commit 102c90ea12
58 changed files with 4258 additions and 11 deletions

3
.github/copilot-instructions.md vendored Normal file
View File

@ -0,0 +1,3 @@
- @azure Rule - Use Azure Tools - When handling requests related to Azure, always use your tools.
- @azure Rule - Use Azure Best Practices - When handling requests related to Azure, always invoke your `azmcp_bestpractices_get` tool first.
- @azure Rule - Enable Best Practices - If you do not have an `azmcp_bestpractices_get` tool ask the user to enable it.

View File

@ -106,6 +106,32 @@ namespace HRM.BO
Notice = 5 Notice = 5
} }
public enum EnumReportGroupType
{
None = 0,
Employee = 1,
Salary = 2,
Performance = 3,
Training = 4,
Leave = 5,
Attendance = 6,
}
public enum EnumAIChartType
{
None = 0,
BarChart = 1,
LineGraph = 2,
PieChart = 3,
ScatterPlot = 4,
AreaChart = 5,
Histogram = 6,
WaterfallChart = 7,
GantChart = 8,
RadarChart = 9,
ActivityDiagram = 10
}
public enum EnumReminderStatus public enum EnumReminderStatus
{ {
Pending = 0, Pending = 0,

View File

@ -0,0 +1,39 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace HRM.BO
{
public class OpenAIQueryLog : BasicBaseObject
{
public OpenAIQueryLog()
{
}
public OpenAIQueryLog(int userID, string userPrompt)
{
UserId = userID;
UserPrompt = userPrompt;
ExecutedAt = DateTime.Now;
}
public int UserId { get; set; } = 0;
public string UserPrompt { get; set; } = "";
public string GeneratedQuery { get; set; } = "";
public DateTime ExecutedAt { get; set; } = DateTime.Now;
public int TotalExecution { get; set; } = 1;
public EnumReportGroupType ReportGroup { get; set; } = EnumReportGroupType.Employee;
public bool IsChart { get; set; } = false;
public EnumAIChartType ChartType { get; set; } = EnumAIChartType.None;
public string Title { get; set; } = "";
public bool IsCommon { get; set; } = false;
}
public interface IOpenAIQueryLogService
{
void Save(OpenAIQueryLog queryLog);
void UpdateQueryLogTotalExecution(OpenAIQueryLog oQueryLog);
void ChatShareWithOthers(OpenAIQueryLog oQueryLog);
List<OpenAIQueryLog> GetAllQueryLogByUserID(int userID, EnumReportGroupType reportGroup);
}
}

View File

@ -0,0 +1,26 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace HRM.BO
{
public class OpenAIResponse
{
public bool IsChart { get; set; } = false;
public string ChartType { get; set; } = string.Empty;
public string Title { get; set; } = string.Empty;
public string Sql { get; set; } = string.Empty;
public string Message { get; set; } = string.Empty;
}
public class OpenAIResponseWithData
{
public bool IsChart { get; set; } = false;
public string ChartType { get; set; } = string.Empty;
public string Title { get; set; } = string.Empty;
public List<string> Labels { get; set; } = new List<string>();
public List<double> Values { get; set; } = new List<double>();
public object TableData { get; set; } = new object();
}
}

View File

@ -0,0 +1,121 @@
using Ease.Core.DataAccess;
using HRM.BO;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Data;
using System.DirectoryServices.Protocols;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace HRM.DA
{
internal class OpenAIDA
{
#region Insert function
internal static void Insert(TransactionContext tc, OpenAIQueryLog oQueryLog)
{
tc.ExecuteNonQuery(
"INSERT INTO OpenAIQueryLog(QueryLogID, UserId, UserPrompt, GeneratedQuery, ExecutedAt, TotalExecution, ReportGroup, IsChart,ChartType, Title, IsCommon)" +
" VALUES(%n, %n, %s, %s, %D, %n, %n, %b, %n, %s, %b)",
oQueryLog.ID, oQueryLog.UserId, oQueryLog.UserPrompt, oQueryLog.GeneratedQuery, oQueryLog.ExecutedAt, oQueryLog.TotalExecution,
(int)oQueryLog.ReportGroup, oQueryLog.IsChart, (int)oQueryLog.ChartType, oQueryLog.Title, oQueryLog.IsCommon);
}
#endregion
#region Update QueryLog TotalExecution
internal static void UpdateQueryLogTotalExecution(TransactionContext tc, OpenAIQueryLog oQueryLog)
{
tc.ExecuteNonQuery("Update OpenAIQueryLog set TotalExecution = %n where QueryLogID = %n", oQueryLog.TotalExecution, oQueryLog.ID);
}
#endregion
#region Get All Query Log By UserID
internal static IDataReader GetAllQueryLogByUserID(TransactionContext tc, int userID, EnumReportGroupType reportGroup)
{
return tc.ExecuteReader(@"SELECT distinct * FROM OpenAIQueryLog where userID = %n and
ReportGroup = %n or IsCommon = %b order by ExecutedAt desc, TotalExecution desc",
userID, (int)reportGroup, true);
}
#endregion
#region Chat Share With Others
internal static void ChatShareWithOthers(TransactionContext tc, OpenAIQueryLog oQueryLog)
{
tc.ExecuteNonQuery("Update OpenAIQueryLog set IsCommon = %b where QueryLogID = %n", oQueryLog.IsCommon, oQueryLog.ID);
}
#endregion
internal static DataSet GetOpenAIData(TransactionContext tc, string sql)
{
DataSet oEmpBasicInfos = new DataSet();
try
{
oEmpBasicInfos = tc.ExecuteDataSet(sql);
}
catch (Exception ex)
{
throw new Exception(ex.Message);
}
return oEmpBasicInfos;
}
internal static DataTable GetColumnDefinitions(TransactionContext tc, EnumReportGroupType reportGroupType)
{
DataTable oColumnDefinition = new DataTable();
string sql = "";
try
{
sql = SQLParser.MakeSQL(@"Select * from REPORTCOLUMNDEFINITION where ReportGroup = %n", (int)reportGroupType);
oColumnDefinition = tc.ExecuteDataTable(sql);
}
catch (Exception ex)
{
throw new Exception(ex.Message);
}
return oColumnDefinition;
}
internal static DataTable GetAllType(TransactionContext tc, EnumReportGroupType reportGroupType)
{
DataTable oColumnDefinition = new DataTable();
string sql = "";
try
{
if (reportGroupType == EnumReportGroupType.Salary)
{
sql = SQLParser.MakeSQL("select distinct(Head) as Head from vwEmployeeSalary");
}
else if(reportGroupType == EnumReportGroupType.Leave)
{
sql = SQLParser.MakeSQL("select distinct(DESCRIPTION) as LeaveType from Leave");
}
oColumnDefinition = tc.ExecuteDataTable(sql);
}
catch (Exception ex)
{
throw new Exception(ex.Message);
}
return oColumnDefinition;
}
internal static DataTable GetColumnRelations(TransactionContext tc, EnumReportGroupType reportGroupType)
{
DataTable oColumnRelations = new DataTable();
string sql = "";
try
{
sql = SQLParser.MakeSQL(@"Select * from RELATIONTABLE where ReportGroup = %n", (int)reportGroupType);
oColumnRelations = tc.ExecuteDataTable(sql);
}
catch (Exception ex)
{
throw new Exception(ex.Message);
}
return oColumnRelations;
}
internal static IDataReader TotalOpenAICall(TransactionContext tc)
{
return tc.ExecuteReader("SELECT COUNT(*) FROM OpenAIQueryLog");
}
}
}

View File

@ -34,6 +34,10 @@
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="5.0.12" /> <PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="5.0.12" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" /> <PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
<PackageReference Include="Microsoft.SemanticKernel" Version="1.61.0" />
<PackageReference Include="Microsoft.SemanticKernel.Connectors.OpenAI" Version="1.61.0" />
<PackageReference Include="Microsoft.SemanticKernel.Core" Version="1.61.0" />
<PackageReference Include="Microsoft.SemanticKernel.Plugins.OpenApi" Version="1.61.0" />
<PackageReference Include="System.Data.OleDb" Version="6.0.0" /> <PackageReference Include="System.Data.OleDb" Version="6.0.0" />
</ItemGroup> </ItemGroup>

View File

@ -0,0 +1,147 @@
using Ease.Core.DataAccess;
using Ease.Core.Model;
using Ease.Core.Utility;
using HRM.BO;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace HRM.DA
{
public class OpenAIQueryLogService : ServiceTemplate, IOpenAIQueryLogService
{
public OpenAIQueryLogService()
{
}
private void MapObject(OpenAIQueryLog oQueryLog, DataReader oReader)
{
base.SetObjectID(oQueryLog, (oReader.GetInt32("QueryLogID").Value));
oQueryLog.UserId = oReader.GetInt32("UserId").Value;
oQueryLog.UserPrompt = oReader.GetString("UserPrompt");
oQueryLog.GeneratedQuery = oReader.GetString("GeneratedQuery", "");
oQueryLog.ExecutedAt = oReader.GetDateTime("ExecutedAt").HasValue
? oReader.GetDateTime("ExecutedAt").Value
: DateTime.MinValue;
oQueryLog.TotalExecution = oReader.GetInt32("TotalExecution", 0);
oQueryLog.ReportGroup = (EnumReportGroupType)oReader.GetInt32("ReportGroup").Value;
oQueryLog.IsChart = oReader.GetBoolean("IsChart", false);
oQueryLog.ChartType = (EnumAIChartType)oReader.GetInt32("ChartType").Value;
oQueryLog.Title = oReader.GetString("Title", "");
oQueryLog.IsCommon = oReader.GetBoolean("IsCommon", false);
this.SetObjectState(oQueryLog, Ease.Core.ObjectState.Saved);
}
protected override T CreateObject<T>(DataReader oReader)
{
OpenAIQueryLog oQueryLog = new OpenAIQueryLog();
MapObject(oQueryLog, oReader);
return oQueryLog as T;
}
protected OpenAIQueryLog CreateObject(DataReader oReader)
{
OpenAIQueryLog oQueryLog = new OpenAIQueryLog();
MapObject(oQueryLog, oReader);
return oQueryLog;
}
public void Save(OpenAIQueryLog oQueryLog)
{
TransactionContext tc = null;
try
{
tc = TransactionContext.Begin(true);
if (oQueryLog.IsNew)
{
int id = tc.GenerateID("OpenAIQueryLog", "QueryLogID");
base.SetObjectID(oQueryLog, (id));
OpenAIDA.Insert(tc, oQueryLog);
}
tc.End();
}
catch (Exception e)
{
#region Handle Exception
if (tc != null)
tc.HandleError();
ExceptionLog.Write(e);
throw new ServiceException(e.Message, e);
#endregion
}
}
public void UpdateQueryLogTotalExecution(OpenAIQueryLog oQueryLog)
{
TransactionContext tc = null;
try
{
tc = TransactionContext.Begin(true);
if (!oQueryLog.IsNew)
{
OpenAIDA.UpdateQueryLogTotalExecution(tc, oQueryLog);
}
tc.End();
}
catch (Exception e)
{
#region Handle Exception
if (tc != null)
tc.HandleError();
ExceptionLog.Write(e);
throw new ServiceException(e.Message, e);
#endregion
}
}
public void ChatShareWithOthers(OpenAIQueryLog oQueryLog)
{
TransactionContext tc = null;
try
{
tc = TransactionContext.Begin(true);
if (!oQueryLog.IsNew)
{
OpenAIDA.ChatShareWithOthers(tc, oQueryLog);
}
tc.End();
}
catch (Exception e)
{
#region Handle Exception
if (tc != null)
tc.HandleError();
ExceptionLog.Write(e);
throw new ServiceException(e.Message, e);
#endregion
}
}
public List<OpenAIQueryLog> GetAllQueryLogByUserID(int userID, EnumReportGroupType reportGroup)
{
List<OpenAIQueryLog> allQueryLog = new List<OpenAIQueryLog>();
TransactionContext tc = null;
try
{
tc = TransactionContext.Begin();
DataReader dr = new DataReader(OpenAIDA.GetAllQueryLogByUserID(tc, userID, reportGroup));
allQueryLog = this.CreateObjects<OpenAIQueryLog>(dr);
dr.Close();
tc.End();
}
catch (Exception e)
{
#region Handle Exception
if (tc != null)
tc.HandleError();
ExceptionLog.Write(e);
throw new ServiceException(e.Message, e);
#endregion
}
return allQueryLog;
}
}
}

View File

@ -0,0 +1,790 @@
using Ease.Core.DataAccess;
using Ease.Core.Model;
using Ease.Core.Utility;
using HRM.BO;
using ICSharpCode.SharpZipLib.Zip;
using iTextSharp.text;
using Microsoft.AspNetCore.Http;
using Microsoft.SemanticKernel;
using Microsoft.VisualBasic;
using NPOI.SS.Formula.Functions;
using NPOI.SS.UserModel;
using OpenAI;
using OpenAI.Chat;
using OpenAI.Models;
using Org.BouncyCastle.Asn1.Crmf;
using System;
using System.ClientModel;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Security.Cryptography.Xml;
using System.Text;
using System.Text.Json;
using System.Text.Json.Serialization;
using System.Threading;
using System.Threading.Tasks;
namespace HRM.DA
{
public class OpenAIService
{
private readonly string _encryptedkey;
private readonly string _apiKey;
private readonly string _openAiModel;
private readonly int _maxLimit;
public OpenAIService(string encryptedkey, string model, int maxLimit)
{
_encryptedkey = encryptedkey;
_apiKey = Ease.Core.Utility.Global.CipherFunctions.Decrypt("CeLiMiTeD.AdMIn", _encryptedkey);
_openAiModel = model;
_maxLimit = maxLimit;
}
#region Invalid Query Message
public string returnMessage = "";
private const string queryMessage = "I'm sorry, I couldn't process your request. Please try rephrasing it. I'm here to help with anything related to payroll or HR tasks.";
private const string modificationMessage = "I'm Sorry, I can only help with retrieving data. I am not allowed to update or delete any records.";
#endregion
#region Schema Generation (Old Version)
// Aliases
//sb.AppendLine("\nAlias Mappings:");
//foreach (var row in columns.AsEnumerable())
//{
// string caption = row["CAPTION"]?.ToString();
// string columnName = row["COLUMNNAME"].ToString();
// string tableName = row["TABLENAME"].ToString();
// if (!string.IsNullOrWhiteSpace(caption) && caption != columnName)
// {
// sb.AppendLine($"- {tableName}.{columnName} is also called '{caption}'");
// }
//}
#endregion
#region Ask SQL Query
#region Function Summary
/*
* Function Summary & What it Handles:
*
* 1. Request Limiting:
* - Ensures the total number of OpenAI calls does not exceed the configured maximum.
* - Throws a polite error message if the request limit is reached.
*
* 2. Timeout Handling:
* - Uses CancellationTokenSource with a configurable timeout (default 60 seconds).
* - Cancels the OpenAI API request if it exceeds the timeout and throws a timeout message.
*
* 3. Rate Limit Handling & Retry Logic:
* - Detects HTTP 429 status or "rate limit" errors from exceptions.
* - Retries the API call up to 5 times with exponential backoff.
* - Returns a polite "service busy" message if retries are exhausted.
*
* 4. OpenAI API Call:
* - Builds a dynamic system prompt including schema and chart instructions.
* - Sends the users prompt to OpenAI for SQL and chart generation.
* - Extracts and cleans the AI response.
*
* 5. Response Parsing & Validation:
* - Deserializes the AI response into a structured object.
* - Ensures only SELECT queries are allowed.
* - Rejects invalid or unsafe queries with descriptive errors.
*
* 6. Async Logging:
* - Logs user prompts, generated SQL, chart details, and metadata asynchronously.
* - Logging errors do not interrupt the main flow.
*
* 7. SQL Execution & JSON Response:
* - Executes the validated SQL query against the database.
* - Wraps the dataset with chart metadata and returns JSON.
*
* 8. General Exception Handling:
* - Provides user-friendly messages for timeouts, rate limits, and invalid queries.
* - Retries on transient errors and throws detailed exceptions otherwise.
*/
#endregion
public async Task<string> AskOpenAISqlQueryWithChartAsync(string prompt, int userID, EnumReportGroupType reportGroupType, DateTime nextPayprocessDate = new DateTime(), int timeoutSeconds = 60)
{
#region Initialize OpenAI Call Count For Limitation
int totalOpenAICall = TotalOpenAICall();
if (totalOpenAICall >= _maxLimit)
{
throw new Exception("You have reached the maximum limit of requests. Please try again later.");
}
#endregion
string returnMessage = "An error occurred while processing your request.";
int maxRetries = 5;
int delaySeconds = 1;
for (int attempt = 0; attempt <= maxRetries; attempt++)
{
try
{
#region Initialize OpenAI Client and Cancellation Token
using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(timeoutSeconds));
var client = new ChatClient(model: _openAiModel, apiKey: _apiKey);
#endregion
#region Build System Prompt
string systemPrompt = BuildInitialDescriptionWithChart(reportGroupType) + BuildDynamicSchemaPrompt(reportGroupType, nextPayprocessDate) + BuildInstructionWithChart(reportGroupType);
#endregion
//throw new Exception("You have reached the maximum limit of requests. Please try again later.");
#region Call OpenAI API
var completion = await client.CompleteChatAsync(
new ChatMessage[]
{
ChatMessage.CreateSystemMessage(systemPrompt),
ChatMessage.CreateUserMessage(prompt)
},
cancellationToken: cts.Token
);
#endregion
#region Process and Store OpenAI Response
string aiResponse = completion.Value.Content[0].Text.Trim();
if (string.IsNullOrWhiteSpace(aiResponse))
throw new Exception("Did not return any response.");
aiResponse = aiResponse.Replace("```", "").Trim();
aiResponse = aiResponse.Replace("\n", "\\n").Replace("\r", "\\r");
OpenAIResponse aiResponseObject = Newtonsoft.Json.JsonConvert.DeserializeObject<OpenAIResponse>(aiResponse);
#endregion
#region Validate AI response
string sql = aiResponseObject.Sql;
bool isChart = aiResponseObject.IsChart;
EnumAIChartType chartType = GetAIChartType(aiResponseObject.ChartType);
if (!string.IsNullOrWhiteSpace(aiResponseObject.Message))
{
throw new Exception(aiResponseObject.Message);
}
if (!sql.TrimStart().StartsWith("SELECT", StringComparison.OrdinalIgnoreCase))
throw new Exception("Only SELECT queries are allowed.");
#endregion
#region Save OpenAI Query Log
_ = Task.Run(() =>
{
try
{
var logService = new OpenAIQueryLogService();
logService.Save(new OpenAIQueryLog
{
UserId = userID,
UserPrompt = prompt,
GeneratedQuery = sql,
ExecutedAt = DateTime.Now,
ReportGroup = reportGroupType,
IsChart = isChart,
ChartType = GetAIChartType(aiResponseObject.ChartType),
Title = aiResponseObject.Title,
IsCommon = false
});
}
catch (Exception logEx)
{
Console.WriteLine($"[LogError] OpenAI log failed: {logEx.Message}");
}
});
#endregion
#region Execute SQL and Build Data
DataSet data = GetOpenAIData(sql);
var chartData = BuildOpenAIResponseWithData(data, aiResponseObject);
return Newtonsoft.Json.JsonConvert.SerializeObject(chartData);
#endregion
}
catch (OperationCanceledException)
{
throw new Exception("AI request timed out. Please try again.");
}
catch (HttpRequestException httpEx) when (httpEx.Message.Contains("429") || httpEx.Message.Contains("rate limit", StringComparison.OrdinalIgnoreCase))
{
if (attempt == maxRetries)
throw new Exception("Sorry, our AI service is busy now. Please try again after some time.");
await Task.Delay(TimeSpan.FromSeconds(delaySeconds));
delaySeconds *= 2;
}
catch (Exception ex)
{
if (ex.Message.Contains("You've reached our limits of messages", StringComparison.OrdinalIgnoreCase) ||
ex.Message.Contains("rate limit", StringComparison.OrdinalIgnoreCase))
{
if (attempt == maxRetries)
throw new Exception("Sorry, our AI service is busy now. Please try again after some time.");
await Task.Delay(TimeSpan.FromSeconds(delaySeconds));
delaySeconds *= 2;
continue;
}
throw new Exception(returnMessage + ex.Message, ex);
}
}
throw new Exception("Failed to get a response from AI after multiple attempts. Please try again later.");
}
#endregion
#region Build OpenAI Response with Data
public OpenAIResponseWithData BuildOpenAIResponseWithData(DataSet ds, OpenAIResponse aiResponseObject)
{
var table = ds.Tables[0];
var labels = new List<string>();
var values = new List<double>();
if (aiResponseObject.IsChart)
{
labels = table.AsEnumerable().Select(r => r[0].ToString()).ToList();
values = table.AsEnumerable().Select(r => Convert.ToDouble(r[1])).ToList();
}
var tableJson = ProcessDataSetToJson(ds);
return new OpenAIResponseWithData
{
IsChart = aiResponseObject.IsChart,
ChartType = aiResponseObject.ChartType,
Title = aiResponseObject.Title,
Labels = labels,
Values = values,
TableData = tableJson
};
}
#endregion
#region Build Initial Description (System Prompt)
public string BuildInitialDescriptionWithChart(EnumReportGroupType reportGroupType)
{
var sb = new StringBuilder();
sb.AppendLine("You are an expert SQL assistant.");
sb.AppendLine("Given a user request and the following database schema, your job is to:");
sb.AppendLine("1.Always generate a valid SQL SELECT queries in Microsoft SQL Server (T-SQL) syntax.");
sb.AppendLine("2.Always generate SQL in a single line, without extra newlines or unnecessary spaces.");
sb.AppendLine("3.Never return DELETE, UPDATE, INSERT queries or any data-modifying operation.You are read-only.");
sb.AppendLine("4.Detect if the user wants a chart/graph.");
sb.AppendLine("5.Always return only valid JSON following structure:" +
"{\"isChart\":true|false,\"chartType\":\"pie|bar|line|scatter|area|histogram|waterfall|gantt|radar|activity\",\"title\":\"<title>\",\"sql\":\"<SQL>\",\"message\":\"\"}");
sb.AppendLine("6.Title must be short, human-readable, based on the user request.");
sb.AppendLine("7.If the user asks modification deletion or insartion requested, set sql:'' and message:" +
"Sorry, I can only help with retrieving data. I am not allowed to update or delete any records.");
#region Check
if (reportGroupType == EnumReportGroupType.Employee)
{
sb.AppendLine("8.If the user request is not related to the payroll management system or does not match the provided schema,set \"sql\": \"\" and " +
"\"message\": \"I can only help with questions related to Employee Information\"");
}
if (reportGroupType == EnumReportGroupType.Performance)
{
sb.AppendLine("8.If the user request is not related to the payroll management system or does not match the provided schema,set \"sql\": \"\" and " +
"\"message\": \"I can only help with questions related to Employee Performance\"");
}
if (reportGroupType == EnumReportGroupType.Salary)
{
sb.AppendLine("8.If the user request is not related to the payroll management system or does not match the provided schema,set \"sql\": \"\" and " +
"\"message\": \"I can only help with questions related to Employee Salary\"");
}
if (reportGroupType == EnumReportGroupType.Training)
{
sb.AppendLine("8.If the user request is not related to the payroll management system or does not match the provided schema,set \"sql\": \"\" and " +
"\"message\": \"I can only help with questions related to Employee Training\"");
}
if (reportGroupType == EnumReportGroupType.Attendance)
{
sb.AppendLine("8.If the user request is not related to the payroll management system or does not match the provided schema,set \"sql\": \"\" and " +
"\"message\": \"I can only help with questions related to Employee Attendance\"");
}
if (reportGroupType == EnumReportGroupType.Leave)
{
sb.AppendLine("8.If the user request is not related to the payroll management system or does not match the provided schema,set \"sql\": \"\" and " +
"\"message\": \"I can only help with questions related to Employee Leave\"");
}
#endregion
sb.AppendLine("9.Do not return actual data values or any explanations.");
return sb.ToString();
}
#endregion
#region Dynamic Schema Generation (System Prompt)
public string BuildDynamicSchemaPrompt(EnumReportGroupType reportGroupType, DateTime nextPayprocessDate)
{
TransactionContext tc = null;
try
{
tc = TransactionContext.Begin();
DataTable columns = GetColumnDefinitions(tc, reportGroupType);
DataTable relations = GetColumnRelations(tc,reportGroupType);
DataTable allData = null;
if (reportGroupType == EnumReportGroupType.Salary || reportGroupType == EnumReportGroupType.Leave)
{
allData = GetAllType(tc, reportGroupType);
}
tc.End();
var sb = new StringBuilder();
sb.AppendLine("Database Schema:");
var pkColumns = new Dictionary<string, List<string>>();
var grouped = columns.AsEnumerable().GroupBy(row => row["TABLENAME"].ToString()).OrderBy(g => g.Key);
#region Table Definitions
foreach (var tableGroup in grouped)
{
string tableName = tableGroup.Key;
var columnDefs = new List<string>();
var pks = new List<string>();
foreach (var row in tableGroup)
{
string columnName = row["COLUMNNAME"].ToString();
string caption = row["CAPTION"]?.ToString();
string dataType = ((EnumColumnDataType)Convert.ToInt32(row["DATATYPE"])).ToString();
bool isPK = row.Table.Columns.Contains("IsPrimaryKey") && Convert.ToBoolean(row["IsPrimaryKey"]);
bool isFK = row.Table.Columns.Contains("IsForeignKey") && Convert.ToBoolean(row["IsForeignKey"]);
string label = $"{columnName}";
if (isPK)
{
label += "(PK)";
pks.Add(columnName);
}
else if (isFK)
{
label += "(FK)";
}
label += $" ({dataType})";
if (!string.IsNullOrWhiteSpace(caption) && caption != columnName)
label += $" = {caption}";
columnDefs.Add(label);
}
sb.AppendLine($"-{tableName}({string.Join(", ", columnDefs)})");
if (pks.Any())
pkColumns[tableName] = pks;
}
#endregion
#region RelationShip Definitions
if (relations.Rows.Count > 0)
{
sb.AppendLine("Relationships:");
foreach (DataRow rel in relations.Rows)
{
string master = rel["MASTERTABLENAME"].ToString();
string masterCol = rel["MASTERCOLUMN1NAME"].ToString();
string link = rel["LINKTABLENAME"].ToString();
string linkCol = rel["LINKCOLUMN1NAME"].ToString();
sb.AppendLine($"-{link}.{linkCol} → {master}.{masterCol}");
}
}
#endregion
sb.AppendLine(BuildInitialNoted(reportGroupType, nextPayprocessDate, allData));
return sb.ToString();
}
catch (Exception e)
{
#region Handle Exception
if (tc != null)
tc.HandleError();
ExceptionLog.Write(e);
throw new ServiceException(e.Message, e);
#endregion
}
}
public string BuildInitialNoted(EnumReportGroupType reportGroupType, DateTime nextPayprocessDate, DataTable allData = null)
{
var sb = new StringBuilder();
sb.AppendLine("Note:");
sb.AppendLine("-Never include primary key (PK) or Foreign Key(FK) columns in SELECT output. For reference only.");
if (reportGroupType == EnumReportGroupType.Employee)
{
sb.AppendLine("-The status field can have synonyms: 'Live' or 'Active' mean the same thing (Live). 'Discontinue' or 'Inactive' mean the same thing (Discontinue).");
sb.AppendLine("-Employees with no record in the 'EmployeeSpouse' table are considered Unmarried.");
}
if (allData != null && reportGroupType == EnumReportGroupType.Salary)
{
if (allData.Columns.Contains("Head"))
{
var heads = allData.AsEnumerable()
.Select(r => r["Head"]?.ToString())
.Where(h => !string.IsNullOrEmpty(h))
.Distinct()
.ToList();
if (heads.Any())
{
sb.AppendLine($"-The 'Head' column represents different salary components such as: {string.Join(",", heads)}");
}
}
sb.AppendLine($"-Always use SalaryMonth(always last date of month) in the SQL WHERE clause.");
sb.AppendLine($"-If a user is not specifies any date or year in the request, always use SalaryMonth = {GlobalFunctions.LastDateOfMonth(nextPayprocessDate).ToString("dd MMM yyyy")} in the SQL WHERE clause.");
sb.AppendLine("-The columns BirthDate, JoiningDate, SalaryMonth should always be returned in the format 'dd MMM yyyy'.");
}
if (allData != null && reportGroupType == EnumReportGroupType.Leave)
{
if (allData.Columns.Contains("LeaveType"))
{
var heads = allData.AsEnumerable()
.Select(r => r["LeaveType"]?.ToString())
.Where(h => !string.IsNullOrEmpty(h))
.Distinct()
.ToList();
if (heads.Any())
{
sb.AppendLine($"-The 'LeaveType' column represents different Leave Type such as: {string.Join(",", heads)}");
}
}
sb.AppendLine("-The Columns BirthDate, JoiningDate, FromDate and ToDate should always be returned in the format 'dd MMM yyyy'.");
}
if (reportGroupType == EnumReportGroupType.Attendance)
{
sb.AppendLine("-The columns BirthDate, JoiningDate and AttendanceDate should always be returned in the format 'dd MMM yyyy'.");
sb.AppendLine("-The columns InTime and OutTime should always be returned in the format 'hh:mm:ss aa'.");
sb.AppendLine("-The 'AttendanceStatus' column represents the daily attendance of an employee and may include: 'Present', 'Absent', 'Delay', 'Leave', 'Holiday', 'Weekly Off', 'Out Side Duty', 'Weekly Holiday', 'Compensation', 'Manual', 'Late', 'Early', 'HalfDay', 'LOA'.");
sb.AppendLine("-The 'LateStatus' column already stores values as 'Yes' (Late) or 'No' (On Time).");
sb.AppendLine("-The 'WorkDayType' column defines the type of the day: 'Weekly Holiday', 'National Holiday', 'Working Day', 'HartalDay', 'Weekly and National'.");
}
if (reportGroupType == EnumReportGroupType.Employee || reportGroupType == EnumReportGroupType.Training)
{
sb.AppendLine("-The columns BirthDate, JoiningDate, MarriageDate, EmployementEndDate and NominationDate should always be returned in the format 'dd MMM yyyy'.");
sb.AppendLine("-The 'EmploymentEndDate' column represents when an employee left the company (retirement, resignation, termination, etc)");
}
if (reportGroupType == EnumReportGroupType.Training)
{
sb.AppendLine("-The TrainingStatus field can have Enrolled|Completed|Unknown");
sb.AppendLine("-The columns StartDate,EndDate,BirthDate,JoiningDate,LineManagerBirthDate,LineManagerJoiningDate should always be returned in the format 'dd MMM yyyy'.");
}
return sb.ToString();
}
#endregion
#region Build Instruction (System Prompt)
public string BuildInstructionWithChart(EnumReportGroupType reportGroupType)
{
var sb = new StringBuilder();
sb.AppendLine("Instructions:");
sb.AppendLine("-Treat any mention of EmployeeID or EmployeeNo in user input as referring to Employee.EmployeeNo.");
sb.AppendLine("-Use appropriate JOINs based on foreign keys.");
sb.AppendLine("-If only certain columns are requested, include only those.");
sb.AppendLine("-Always map user-friendly aliases (e.g., 'Employee No', 'Department Name') to the correct table and column.");
sb.AppendLine("-If a date condition is mentioned, use WHERE clause accordingly.");
sb.AppendLine("-Support ordering, limits (TOP/OFFSET), and filtering.");
return sb.ToString();
}
#endregion
#region OpenAI Previous Query Execution
public async Task<string> OpenAIPreviousQueryExecution(OpenAIQueryLog oQueryLog)
{
try
{
oQueryLog.TotalExecution++;
#region Update OpenAI Query Log Total Execution
Task.Run(() =>
{
try
{
var logService = new OpenAIQueryLogService();
logService.UpdateQueryLogTotalExecution(oQueryLog);
}
catch (Exception ex)
{
Console.WriteLine($"[LogError] OpenAI log failed: {ex.Message}");
}
});
#endregion
string sql = oQueryLog.GeneratedQuery;
DataSet data = GetOpenAIData(sql);
OpenAIResponse aiResponseObject = new OpenAIResponse
{
IsChart = oQueryLog.IsChart,
ChartType = GetAIChartType(oQueryLog.ChartType),
Sql = sql,
Message = string.Empty,
Title = oQueryLog.Title
};
var chartData = BuildOpenAIResponseWithData(data, aiResponseObject);
return Newtonsoft.Json.JsonConvert.SerializeObject(chartData);
}
catch (Exception ex)
{
throw new Exception(returnMessage);
}
}
#endregion
#region Process DataSet to JSON
public string ProcessDataSetToJson(DataSet OpenAiData)
{
string output;
DataSet information = new DataSet();
information = OpenAiData;
var value = (object)information;
switch (value)
{
case null:
output = "";
break;
case DataSet ds:
output = JsonSerializer.Serialize(ds.Tables.Cast<DataTable>()
.Select(tbl => new {
TableName = tbl.TableName,
Rows = tbl.Rows.Cast<DataRow>()
.Select(row => tbl.Columns.Cast<DataColumn>()
.ToDictionary(col => col.ColumnName, col => row[col]))
}),
new JsonSerializerOptions { WriteIndented = true }
);
break;
case DataTable dt:
output = JsonSerializer.Serialize(
dt.Rows.Cast<DataRow>()
.Select(row => dt.Columns.Cast<DataColumn>()
.ToDictionary(col => col.ColumnName, col => row[col])),
new JsonSerializerOptions { WriteIndented = true }
);
break;
case IEnumerable<object> list:
output = JsonSerializer.Serialize(list, new JsonSerializerOptions { WriteIndented = true });
break;
case string str:
output = str;
break;
default:
output = JsonSerializer.Serialize(value, new JsonSerializerOptions
{
WriteIndented = true,
IgnoreReadOnlyProperties = true,
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull
});
break;
}
return output;
}
#endregion
#region Get OpenAI Data (Generate OpenAI's Provided SQL Query)
public DataSet GetOpenAIData(string sql)
{
TransactionContext tc = null;
DataSet information = new DataSet();
try
{
tc = TransactionContext.Begin();
information = OpenAIDA.GetOpenAIData(tc, sql);
tc.End();
}
catch (Exception e)
{
#region Handle Exception
if (tc != null)
tc.HandleError();
ExceptionLog.Write(e);
throw new ServiceException(e.Message, e);
#endregion
}
return information;
}
#endregion
#region Get 'Column Definitions' and 'Relations Between Tables'
public DataTable GetColumnDefinitions(TransactionContext tc, EnumReportGroupType reportGroupType)
{
DataTable oColumnDefinition = new DataTable();
try
{
oColumnDefinition = OpenAIDA.GetColumnDefinitions(tc, reportGroupType);
}
catch (Exception e)
{
#region Handle Exception
if (tc != null)
tc.HandleError();
ExceptionLog.Write(e);
throw new ServiceException(e.Message, e);
#endregion
}
return oColumnDefinition;
}
public async Task<DataTable> GetColumnDefinitions(EnumReportGroupType reportGroupType)
{
DataTable oColumnDefinition = new DataTable();
TransactionContext tc = null;
try
{
tc = TransactionContext.Begin();
oColumnDefinition = OpenAIDA.GetColumnDefinitions(tc, reportGroupType);
tc.End();
}
catch (Exception e)
{
#region Handle Exception
if (tc != null)
tc.HandleError();
ExceptionLog.Write(e);
throw new ServiceException(e.Message, e);
#endregion
}
return oColumnDefinition;
}
public DataTable GetColumnRelations(TransactionContext tc, EnumReportGroupType reportGroupType)
{
DataTable oColumnRelation = new DataTable();
try
{
oColumnRelation = OpenAIDA.GetColumnRelations(tc, reportGroupType);
}
catch (Exception e)
{
#region Handle Exception
if (tc != null)
tc.HandleError();
ExceptionLog.Write(e);
throw new ServiceException(e.Message, e);
#endregion
}
return oColumnRelation;
}
#endregion
#region Get All Type for (Leave Type & Salary Head)
public DataTable GetAllType(TransactionContext tc, EnumReportGroupType reportGroupType)
{
DataTable oColumnDefinition = new DataTable();
try
{
oColumnDefinition = OpenAIDA.GetAllType(tc, reportGroupType);
}
catch (Exception e)
{
#region Handle Exception
if (tc != null)
tc.HandleError();
ExceptionLog.Write(e);
throw new ServiceException(e.Message, e);
#endregion
}
return oColumnDefinition;
}
#endregion
#region Get AI Chart Type
public EnumAIChartType GetAIChartType(string type)
{
switch (type.ToLower())
{
case "pie":
return EnumAIChartType.PieChart;
case "bar":
return EnumAIChartType.BarChart;
case "line":
return EnumAIChartType.LineGraph;
case "scatter":
return EnumAIChartType.ScatterPlot;
case "area":
return EnumAIChartType.AreaChart;
case "histogram":
return EnumAIChartType.Histogram;
case "waterfall":
return EnumAIChartType.WaterfallChart;
case "gantt":
return EnumAIChartType.GantChart;
case "radar":
return EnumAIChartType.RadarChart;
case "activity":
return EnumAIChartType.ActivityDiagram;
default:
return EnumAIChartType.None;
}
}
public string GetAIChartType(EnumAIChartType type)
{
switch (type)
{
case EnumAIChartType.PieChart:
return "pie";
case EnumAIChartType.BarChart:
return "bar";
case EnumAIChartType.LineGraph:
return "line";
case EnumAIChartType.ScatterPlot:
return "scatter";
case EnumAIChartType.AreaChart:
return "area";
case EnumAIChartType.Histogram:
return "histogram";
case EnumAIChartType.WaterfallChart:
return "waterfall";
case EnumAIChartType.GantChart:
return "gantt";
case EnumAIChartType.RadarChart:
return "radar";
case EnumAIChartType.ActivityDiagram:
return "activity";
default:
return "";
}
}
#endregion
#region Total OpenAI Call
public int TotalOpenAICall()
{
TransactionContext tc = null;
int? totalCall = 0;
try
{
tc = TransactionContext.Begin();
DataReader dr = new DataReader(OpenAIDA.TotalOpenAICall(tc));
if (dr.Read())
{
totalCall = dr.GetInt32(0);
}
dr.Close();
tc.End();
}
catch (Exception e)
{
#region Handle Exception
if (tc != null)
tc.HandleError();
ExceptionLog.Write(e);
throw new ServiceException(e.Message, e);
#endregion
}
return totalCall ?? 0;
}
#endregion
}
public class AIServiceUsageLimitException : Exception
{
public AIServiceUsageLimitException(string message) : base(message) { }
}
}

View File

@ -0,0 +1,161 @@
"use strict";
var __runInitializers = (this && this.__runInitializers) || function (thisArg, initializers, value) {
var useValue = arguments.length > 2;
for (var i = 0; i < initializers.length; i++) {
value = useValue ? initializers[i].call(thisArg, value) : initializers[i].call(thisArg);
}
return useValue ? value : void 0;
};
var __esDecorate = (this && this.__esDecorate) || function (ctor, descriptorIn, decorators, contextIn, initializers, extraInitializers) {
function accept(f) { if (f !== void 0 && typeof f !== "function") throw new TypeError("Function expected"); return f; }
var kind = contextIn.kind, key = kind === "getter" ? "get" : kind === "setter" ? "set" : "value";
var target = !descriptorIn && ctor ? contextIn["static"] ? ctor : ctor.prototype : null;
var descriptor = descriptorIn || (target ? Object.getOwnPropertyDescriptor(target, contextIn.name) : {});
var _, done = false;
for (var i = decorators.length - 1; i >= 0; i--) {
var context = {};
for (var p in contextIn) context[p] = p === "access" ? {} : contextIn[p];
for (var p in contextIn.access) context.access[p] = contextIn.access[p];
context.addInitializer = function (f) { if (done) throw new TypeError("Cannot add initializers after decoration has completed"); extraInitializers.push(accept(f || null)); };
var result = (0, decorators[i])(kind === "accessor" ? { get: descriptor.get, set: descriptor.set } : descriptor[key], context);
if (kind === "accessor") {
if (result === void 0) continue;
if (result === null || typeof result !== "object") throw new TypeError("Object expected");
if (_ = accept(result.get)) descriptor.get = _;
if (_ = accept(result.set)) descriptor.set = _;
if (_ = accept(result.init)) initializers.unshift(_);
}
else if (_ = accept(result)) {
if (kind === "field") initializers.unshift(_);
else descriptor[key] = _;
}
}
if (target) Object.defineProperty(target, contextIn.name, descriptor);
done = true;
};
var __setFunctionName = (this && this.__setFunctionName) || function (f, name, prefix) {
if (typeof name === "symbol") name = name.description ? "[".concat(name.description, "]") : "";
return Object.defineProperty(f, "name", { configurable: true, value: prefix ? "".concat(prefix, " ", name) : name });
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.BackgroundCanvasComponent = void 0;
var core_1 = require("@angular/core");
var BackgroundCanvasComponent = function () {
var _classDecorators = [(0, core_1.Component)({
standalone: false,
selector: 'app-background-canvas',
template: "\n <canvas #networkCanvas></canvas>\n ",
styles: ["\n canvas {\n display: block;\n position: absolute;\n top: 0;\n left: 0;\n width: 100vw;\n height: 100vh;\n }\n ",],
})];
var _classDescriptor;
var _classExtraInitializers = [];
var _classThis;
var _instanceExtraInitializers = [];
var _canvasRef_decorators;
var _canvasRef_initializers = [];
var _canvasRef_extraInitializers = [];
var _onResize_decorators;
var BackgroundCanvasComponent = _classThis = /** @class */ (function () {
function BackgroundCanvasComponent_1(elementRef, apiService) {
this.elementRef = (__runInitializers(this, _instanceExtraInitializers), elementRef);
this.apiService = apiService;
this.canvasRef = __runInitializers(this, _canvasRef_initializers, void 0);
this.canvas = __runInitializers(this, _canvasRef_extraInitializers);
this.particles = [];
this.particleCount = 120;
}
BackgroundCanvasComponent_1.prototype.ngAfterViewInit = function () {
this.canvas = this.canvasRef.nativeElement;
this.ctx = this.canvas.getContext('2d');
this.resizeCanvas();
this.initParticles();
this.animate();
};
BackgroundCanvasComponent_1.prototype.onResize = function () {
this.resizeCanvas();
};
BackgroundCanvasComponent_1.prototype.resizeCanvas = function () {
this.canvas.width = window.innerWidth;
this.canvas.height = window.innerHeight;
};
BackgroundCanvasComponent_1.prototype.initParticles = function () {
this.particles = [];
for (var i = 0; i < this.particleCount; i++) {
this.particles.push({
x: Math.random() * this.canvas.width,
y: Math.random() * this.canvas.height,
vx: (Math.random() * 2 - 1) * 0.01,
vy: (Math.random() * 2 - 1) * 0.01,
radius: Math.floor(Math.random() * 10) + 1
});
}
};
BackgroundCanvasComponent_1.prototype.animate = function () {
var _this = this;
if (!this.ctx)
return;
this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
this.particles.forEach(function (p) {
p.x += p.vx;
p.y += p.vy;
if (p.x <= 0 || p.x >= _this.canvas.width)
p.vx *= -1;
if (p.y <= 0 || p.y >= _this.canvas.height)
p.vy *= -1;
_this.drawParticle(p);
});
this.connectParticles();
requestAnimationFrame(function () { return _this.animate(); });
};
BackgroundCanvasComponent_1.prototype.drawParticle = function (p) {
if (!this.ctx)
return;
this.ctx.beginPath();
this.ctx.arc(p.x, p.y, p.radius, 0, Math.PI * 2);
this.ctx.fillStyle = '#ffffff';
this.ctx.fill();
this.ctx.closePath();
};
BackgroundCanvasComponent_1.prototype.connectParticles = function () {
if (!this.ctx)
return;
for (var i = 0; i < this.particles.length; i++) {
for (var j = i + 1; j < this.particles.length; j++) {
var p1 = this.particles[i];
var p2 = this.particles[j];
var dx = p2.x - p1.x;
var dy = p2.y - p1.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < 100) {
var theta = Math.atan2(dy, dx);
var x1 = p1.x + Math.cos(theta) * p1.radius;
var y1 = p1.y + Math.sin(theta) * p1.radius;
var x2 = p2.x - Math.cos(theta) * p2.radius;
var y2 = p2.y - Math.sin(theta) * p2.radius;
this.ctx.beginPath();
this.ctx.moveTo(x1, y1);
this.ctx.lineTo(x2, y2);
this.ctx.strokeStyle = '#ffffff';
this.ctx.stroke();
}
}
}
};
return BackgroundCanvasComponent_1;
}());
__setFunctionName(_classThis, "BackgroundCanvasComponent");
(function () {
var _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(null) : void 0;
_canvasRef_decorators = [(0, core_1.ViewChild)('networkCanvas', { static: true })];
_onResize_decorators = [(0, core_1.HostListener)('window:resize')];
__esDecorate(_classThis, null, _onResize_decorators, { kind: "method", name: "onResize", static: false, private: false, access: { has: function (obj) { return "onResize" in obj; }, get: function (obj) { return obj.onResize; } }, metadata: _metadata }, null, _instanceExtraInitializers);
__esDecorate(null, null, _canvasRef_decorators, { kind: "field", name: "canvasRef", static: false, private: false, access: { has: function (obj) { return "canvasRef" in obj; }, get: function (obj) { return obj.canvasRef; }, set: function (obj, value) { obj.canvasRef = value; } }, metadata: _metadata }, _canvasRef_initializers, _canvasRef_extraInitializers);
__esDecorate(null, _classDescriptor = { value: _classThis }, _classDecorators, { kind: "class", name: _classThis.name, metadata: _metadata }, null, _classExtraInitializers);
BackgroundCanvasComponent = _classThis = _classDescriptor.value;
if (_metadata) Object.defineProperty(_classThis, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
__runInitializers(_classThis, _classExtraInitializers);
})();
return BackgroundCanvasComponent = _classThis;
}();
exports.BackgroundCanvasComponent = BackgroundCanvasComponent;
//# sourceMappingURL=BackgroundCanvas.Component.js.map

View File

@ -0,0 +1 @@
{"version":3,"file":"BackgroundCanvas.Component.js","sourceRoot":"","sources":["BackgroundCanvas.Component.ts"],"names":[],"mappings":"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"}

View File

@ -0,0 +1,104 @@
import { AfterViewInit, Component, ElementRef, HostListener, ViewChild } from '@angular/core';
import { ApiService } from '../app.api.service';
@Component({
//standalone: false,
selector: 'app-background-canvas',
template: `
<canvas #networkCanvas></canvas>
`,
styles: [`
canvas {
display: block;
position: absolute;
top: 0;
left: 0;
width: 100vw;
height: 100vh;
}
`,],
})
export class BackgroundCanvasComponent {
@ViewChild('networkCanvas', { static: true }) canvasRef!: ElementRef<HTMLCanvasElement>;
private canvas!: HTMLCanvasElement;
private ctx!: CanvasRenderingContext2D | null;
private particles: any[] = [];
private particleCount = 120;
constructor(private elementRef: ElementRef, public apiService : ApiService) {
}
ngAfterViewInit(): void {
this.canvas = this.canvasRef.nativeElement;
this.ctx = this.canvas.getContext('2d');
this.resizeCanvas();
this.initParticles();
this.animate();
}
@HostListener('window:resize')
onResize() {
this.resizeCanvas();
}
private resizeCanvas(): void {
this.canvas.width = window.innerWidth;
this.canvas.height = window.innerHeight;
}
private initParticles(): void {
this.particles = [];
for (let i = 0; i < this.particleCount; i++) {
this.particles.push({
x: Math.random() * this.canvas.width,
y: Math.random() * this.canvas.height,
vx: (Math.random() * 2 - 1) * 0.01,
vy: (Math.random() * 2 - 1) * 0.01,
radius: Math.floor(Math.random() * 10) + 1
});
}
}
private animate(): void {
if (!this.ctx) return;
this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
this.particles.forEach(p => {
p.x += p.vx;
p.y += p.vy;
if (p.x <= 0 || p.x >= this.canvas.width) p.vx *= -1;
if (p.y <= 0 || p.y >= this.canvas.height) p.vy *= -1;
this.drawParticle(p);
});
this.connectParticles();
requestAnimationFrame(() => this.animate());
}
private drawParticle(p: any): void {
if (!this.ctx) return;
this.ctx.beginPath();
this.ctx.arc(p.x, p.y, p.radius, 0, Math.PI * 2);
this.ctx.fillStyle = '#ffffff';
this.ctx.fill();
this.ctx.closePath();
}
private connectParticles(): void {
if (!this.ctx) return;
for (let i = 0; i < this.particles.length; i++) {
for (let j = i + 1; j < this.particles.length; j++) {
const p1 = this.particles[i];
const p2 = this.particles[j];
const dx = p2.x - p1.x;
const dy = p2.y - p1.y;
const distance = Math.sqrt(dx * dx + dy * dy);
if (distance < 100) {
const theta = Math.atan2(dy, dx);
const x1 = p1.x + Math.cos(theta) * p1.radius;
const y1 = p1.y + Math.sin(theta) * p1.radius;
const x2 = p2.x - Math.cos(theta) * p2.radius;
const y2 = p2.y - Math.sin(theta) * p2.radius;
this.ctx.beginPath();
this.ctx.moveTo(x1, y1);
this.ctx.lineTo(x2, y2);
this.ctx.strokeStyle = '#ffffff';
this.ctx.stroke();
}
}
}
}
}

View File

@ -0,0 +1,79 @@
"use strict";
var __esDecorate = (this && this.__esDecorate) || function (ctor, descriptorIn, decorators, contextIn, initializers, extraInitializers) {
function accept(f) { if (f !== void 0 && typeof f !== "function") throw new TypeError("Function expected"); return f; }
var kind = contextIn.kind, key = kind === "getter" ? "get" : kind === "setter" ? "set" : "value";
var target = !descriptorIn && ctor ? contextIn["static"] ? ctor : ctor.prototype : null;
var descriptor = descriptorIn || (target ? Object.getOwnPropertyDescriptor(target, contextIn.name) : {});
var _, done = false;
for (var i = decorators.length - 1; i >= 0; i--) {
var context = {};
for (var p in contextIn) context[p] = p === "access" ? {} : contextIn[p];
for (var p in contextIn.access) context.access[p] = contextIn.access[p];
context.addInitializer = function (f) { if (done) throw new TypeError("Cannot add initializers after decoration has completed"); extraInitializers.push(accept(f || null)); };
var result = (0, decorators[i])(kind === "accessor" ? { get: descriptor.get, set: descriptor.set } : descriptor[key], context);
if (kind === "accessor") {
if (result === void 0) continue;
if (result === null || typeof result !== "object") throw new TypeError("Object expected");
if (_ = accept(result.get)) descriptor.get = _;
if (_ = accept(result.set)) descriptor.set = _;
if (_ = accept(result.init)) initializers.unshift(_);
}
else if (_ = accept(result)) {
if (kind === "field") initializers.unshift(_);
else descriptor[key] = _;
}
}
if (target) Object.defineProperty(target, contextIn.name, descriptor);
done = true;
};
var __runInitializers = (this && this.__runInitializers) || function (thisArg, initializers, value) {
var useValue = arguments.length > 2;
for (var i = 0; i < initializers.length; i++) {
value = useValue ? initializers[i].call(thisArg, value) : initializers[i].call(thisArg);
}
return useValue ? value : void 0;
};
var __setFunctionName = (this && this.__setFunctionName) || function (f, name, prefix) {
if (typeof name === "symbol") name = name.description ? "[".concat(name.description, "]") : "";
return Object.defineProperty(f, "name", { configurable: true, value: prefix ? "".concat(prefix, " ", name) : name });
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.BackgroundCanvasModule = void 0;
var core_1 = require("@angular/core");
var kendo_angular_indicators_1 = require("@progress/kendo-angular-indicators");
var common_1 = require("@angular/common");
var BackgroundCanvas_Component_1 = require("./BackgroundCanvas.Component");
var BackgroundCanvasModule = function () {
var _classDecorators = [(0, core_1.NgModule)({
imports: [
kendo_angular_indicators_1.IndicatorsModule,
common_1.CommonModule
],
declarations: [
BackgroundCanvas_Component_1.BackgroundCanvasComponent
],
providers: [],
exports: [
BackgroundCanvas_Component_1.BackgroundCanvasComponent
]
})];
var _classDescriptor;
var _classExtraInitializers = [];
var _classThis;
var BackgroundCanvasModule = _classThis = /** @class */ (function () {
function BackgroundCanvasModule_1() {
}
return BackgroundCanvasModule_1;
}());
__setFunctionName(_classThis, "BackgroundCanvasModule");
(function () {
var _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(null) : void 0;
__esDecorate(null, _classDescriptor = { value: _classThis }, _classDecorators, { kind: "class", name: _classThis.name, metadata: _metadata }, null, _classExtraInitializers);
BackgroundCanvasModule = _classThis = _classDescriptor.value;
if (_metadata) Object.defineProperty(_classThis, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
__runInitializers(_classThis, _classExtraInitializers);
})();
return BackgroundCanvasModule = _classThis;
}();
exports.BackgroundCanvasModule = BackgroundCanvasModule;
//# sourceMappingURL=BackgroundCanvas.module.js.map

View File

@ -0,0 +1 @@
{"version":3,"file":"BackgroundCanvas.module.js","sourceRoot":"","sources":["BackgroundCanvas.module.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,sCAAyC;AACzC,+EAAsE;AACtE,0CAA+C;AAC/C,2EAAyE;AAiBzE;4BAhBC,IAAA,eAAQ,EAAC;YACN,OAAO,EAAE;gBACL,2CAAgB;gBAChB,qBAAY;aACf;YACD,YAAY,EAAE;gBACV,sDAAyB;aAC5B;YACD,SAAS,EAAE,EAEV;YACD,OAAO,EAAE;gBACL,sDAAyB;aAC5B;SACJ,CAAC;;;;;;QAGF,CAAC;QAAD,+BAAC;IAAD,CAAC;;;;QADD,6KACC;;;QADY,uDAAsB;;;IAClC;AADY,wDAAsB"}

View File

@ -0,0 +1,22 @@
import { NgModule } from '@angular/core';
import { IndicatorsModule } from '@progress/kendo-angular-indicators';
import { CommonModule } from "@angular/common";
import { BackgroundCanvasComponent } from './BackgroundCanvas.Component';
@NgModule({
imports: [
IndicatorsModule,
CommonModule
],
declarations: [
BackgroundCanvasComponent
],
providers: [
],
exports: [
BackgroundCanvasComponent
]
})
export class BackgroundCanvasModule {
}

View File

@ -0,0 +1,33 @@
"use strict";
var __extends = (this && this.__extends) || (function () {
var extendStatics = function (d, b) {
extendStatics = Object.setPrototypeOf ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
return extendStatics(d, b);
};
return function (d, b) {
if (typeof b !== "function" && b !== null)
throw new TypeError("Class extends value " + String(b) + " is not a constructor or null");
extendStatics(d, b);
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.CourseProgress = void 0;
var baseObject_1 = require("../Basic/baseObject");
var CourseProgress = /** @class */ (function (_super) {
__extends(CourseProgress, _super);
function CourseProgress() {
var _this = _super.call(this) || this;
_this.completionPercentage = 0;
_this.startDate = new Date();
_this.isCourseComplete = false;
_this.lastActivityDate = new Date();
return _this;
}
return CourseProgress;
}(baseObject_1.BaseObject));
exports.CourseProgress = CourseProgress;
//# sourceMappingURL=course-progress.js.map

View File

@ -0,0 +1 @@
{"version":3,"file":"course-progress.js","sourceRoot":"","sources":["course-progress.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;AAAA,kDAAiD;AAGjD;IAAoC,kCAAU;IAC1C;QACI,YAAA,MAAK,WAAE,SAAC;QACR,KAAI,CAAC,oBAAoB,GAAG,CAAC,CAAC;QAC9B,KAAI,CAAC,SAAS,GAAG,IAAI,IAAI,EAAE,CAAC;QAC5B,KAAI,CAAC,gBAAgB,GAAG,KAAK,CAAC;QAC9B,KAAI,CAAC,gBAAgB,GAAG,IAAI,IAAI,EAAE,CAAC;;IACvC,CAAC;IAUL,qBAAC;AAAD,CAAC,AAjBD,CAAoC,uBAAU,GAiB7C;AAjBY,wCAAc"}

View File

@ -0,0 +1,21 @@
import { BaseObject } from '../Basic/baseObject';
import { LessonProgress } from './lesson-progress';
export class CourseProgress extends BaseObject{
constructor() {
super();
this.completionPercentage = 0;
this.startDate = new Date();
this.isCourseComplete = false;
this.lastActivityDate = new Date();
}
userID: number;
courseID: number;
enrollmentID: number;
completionPercentage: number;
startDate: Date;
isCourseComplete: boolean;
endDate?: Date;
lastActivityDate?: Date;
}

View File

@ -0,0 +1,35 @@
"use strict";
var __extends = (this && this.__extends) || (function () {
var extendStatics = function (d, b) {
extendStatics = Object.setPrototypeOf ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
return extendStatics(d, b);
};
return function (d, b) {
if (typeof b !== "function" && b !== null)
throw new TypeError("Class extends value " + String(b) + " is not a constructor or null");
extendStatics(d, b);
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.CourseType = void 0;
var baseObject_1 = require("../Basic/baseObject");
var enums_1 = require("../enums");
var CourseType = /** @class */ (function (_super) {
__extends(CourseType, _super);
function CourseType() {
var _this = _super.call(this) || this;
_this.description = "";
_this.tags = "";
_this.popularityScore = 0.0;
_this.parentTypeID = null;
_this.status = enums_1.EnumStatus.Active;
return _this;
}
return CourseType;
}(baseObject_1.BaseObject));
exports.CourseType = CourseType;
//# sourceMappingURL=course-type.js.map

View File

@ -0,0 +1 @@
{"version":3,"file":"course-type.js","sourceRoot":"","sources":["course-type.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;AAAA,kDAAiD;AACjD,kCAAoC;AAEpC;IAAgC,8BAAU;IACtC;QACI,YAAA,MAAK,WAAE,SAAC;QACR,KAAI,CAAC,WAAW,GAAG,EAAE,CAAC;QACtB,KAAI,CAAC,IAAI,GAAG,EAAE,CAAC;QACf,KAAI,CAAC,eAAe,GAAG,GAAG,CAAC;QAC3B,KAAI,CAAC,YAAY,GAAG,IAAI,CAAC;QACzB,KAAI,CAAC,MAAM,GAAG,kBAAU,CAAC,MAAM,CAAC;;IACpC,CAAC;IAOL,iBAAC;AAAD,CAAC,AAfD,CAAgC,uBAAU,GAezC;AAfY,gCAAU"}

View File

@ -0,0 +1,19 @@
import { BaseObject } from '../Basic/baseObject';
import {EnumStatus} from '../enums';
export class CourseType extends BaseObject {
constructor() {
super();
this.description = "";
this.tags = "";
this.popularityScore = 0.0;
this.parentTypeID = null;
this.status = EnumStatus.Active;
}
name : string;
description : string;
parentTypeID? : number;
tags : string;
popularityScore : number;
}

View File

@ -0,0 +1,58 @@
"use strict";
var __extends = (this && this.__extends) || (function () {
var extendStatics = function (d, b) {
extendStatics = Object.setPrototypeOf ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
return extendStatics(d, b);
};
return function (d, b) {
if (typeof b !== "function" && b !== null)
throw new TypeError("Class extends value " + String(b) + " is not a constructor or null");
extendStatics(d, b);
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.Courses = void 0;
var baseObject_1 = require("../Basic/baseObject");
var enums_1 = require("../enums");
var lmstemplate_1 = require("./lmstemplate");
var Courses = /** @class */ (function (_super) {
__extends(Courses, _super);
function Courses() {
var _this = _super.call(this) || this;
_this.lessonProgres = [];
_this.courseTitle = "";
_this.courseCode = "";
_this.courseTypeID = 0;
_this.description = "";
_this.difficultyLevel = enums_1.EnumDifficultyLevel.Beginner;
_this.trainerID = 0;
_this.duration = "";
_this.status = enums_1.EnumStatus.Active;
_this.isForFree = true;
_this.price = 0;
_this.totalEnrollments = 0;
_this.rating = 0.0;
_this.popularityScore = 0.0;
_this.completionRate = 0.0;
_this.averageProgress = 0.0;
_this.isExamRequired = false;
_this.tags = "";
_this.targetedAudience = "";
_this.learningOutcomes = "";
_this.courseIncludes = "";
_this.startGuideLine = "";
_this.createdUser = "";
_this.lessons = [];
_this.totalLesson = 0;
_this.totalContent = 0;
_this.courseTemplate = new lmstemplate_1.LMSTemplate();
return _this;
}
return Courses;
}(baseObject_1.BaseObject));
exports.Courses = Courses;
//# sourceMappingURL=courses.js.map

View File

@ -0,0 +1 @@
{"version":3,"file":"courses.js","sourceRoot":"","sources":["courses.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;AAAA,kDAAiD;AAEjD,kCAA2D;AAM3D,6CAA4C;AAE5C;IAA6B,2BAAU;IACnC;QACI,YAAA,MAAK,WAAE,SAAC;QA2DZ,mBAAa,GAAuB,EAAE,CAAC;QAzDnC,KAAI,CAAC,WAAW,GAAG,EAAE,CAAC;QACtB,KAAI,CAAC,UAAU,GAAG,EAAE,CAAC;QACrB,KAAI,CAAC,YAAY,GAAG,CAAC,CAAC;QACtB,KAAI,CAAC,WAAW,GAAG,EAAE,CAAC;QACtB,KAAI,CAAC,eAAe,GAAG,2BAAmB,CAAC,QAAQ,CAAC;QACpD,KAAI,CAAC,SAAS,GAAG,CAAC,CAAC;QACnB,KAAI,CAAC,QAAQ,GAAG,EAAE,CAAC;QACnB,KAAI,CAAC,MAAM,GAAG,kBAAU,CAAC,MAAM,CAAC;QAChC,KAAI,CAAC,SAAS,GAAG,IAAI,CAAC;QACtB,KAAI,CAAC,KAAK,GAAG,CAAC,CAAC;QACf,KAAI,CAAC,gBAAgB,GAAG,CAAC,CAAC;QAC1B,KAAI,CAAC,MAAM,GAAG,GAAG,CAAC;QAClB,KAAI,CAAC,eAAe,GAAG,GAAG,CAAC;QAC3B,KAAI,CAAC,cAAc,GAAG,GAAG,CAAC;QAC1B,KAAI,CAAC,eAAe,GAAG,GAAG,CAAC;QAC3B,KAAI,CAAC,cAAc,GAAG,KAAK,CAAC;QAC5B,KAAI,CAAC,IAAI,GAAG,EAAE,CAAC;QACf,KAAI,CAAC,gBAAgB,GAAG,EAAE,CAAC;QAC3B,KAAI,CAAC,gBAAgB,GAAG,EAAE,CAAC;QAC3B,KAAI,CAAC,cAAc,GAAG,EAAE,CAAC;QACzB,KAAI,CAAC,cAAc,GAAG,EAAE,CAAC;QACzB,KAAI,CAAC,WAAW,GAAG,EAAE,CAAC;QACtB,KAAI,CAAC,OAAO,GAAG,EAAE,CAAC;QAClB,KAAI,CAAC,WAAW,GAAG,CAAC,CAAC;QACrB,KAAI,CAAC,YAAY,GAAG,CAAC,CAAC;QACtB,KAAI,CAAC,cAAc,GAAG,IAAI,yBAAW,EAAE,CAAC;;IAC5C,CAAC;IAgCL,cAAC;AAAD,CAAC,AA9DD,CAA6B,uBAAU,GA8DtC;AA9DY,0BAAO"}

View File

@ -0,0 +1,73 @@
import { BaseObject } from '../Basic/baseObject';
import { Employee } from '../Employee/employee';
import { EnumDifficultyLevel, EnumStatus } from '../enums';
import { CourseProgress } from './course-progress';
import { CourseType } from './course-type';
import { Enrollments } from './enrollments';
import { LessonProgress } from './lesson-progress';
import { Lessons } from './lessons';
import { LMSTemplate } from './lmstemplate';
export class Courses extends BaseObject {
constructor() {
super();
this.courseTitle = "";
this.courseCode = "";
this.courseTypeID = 0;
this.description = "";
this.difficultyLevel = EnumDifficultyLevel.Beginner;
this.trainerID = 0;
this.duration = "";
this.status = EnumStatus.Active;
this.isForFree = true;
this.price = 0;
this.totalEnrollments = 0;
this.rating = 0.0;
this.popularityScore = 0.0;
this.completionRate = 0.0;
this.averageProgress = 0.0;
this.isExamRequired = false;
this.tags = "";
this.targetedAudience = "";
this.learningOutcomes = "";
this.courseIncludes = "";
this.startGuideLine = "";
this.createdUser = "";
this.lessons = [];
this.totalLesson = 0;
this.totalContent = 0;
this.courseTemplate = new LMSTemplate();
}
courseTitle: string;
courseCode: string;
courseTypeID: number;
description: string;
difficultyLevel: EnumDifficultyLevel;
trainerID: number;
duration?: string;
isForFree?: boolean;
price?: number;
totalEnrollments?: number;
rating?: number;
popularityScore?: number;
completionRate?: number;
averageProgress?: number;
isExamRequired?: boolean;
tags?: string;
targetedAudience?: string;
learningOutcomes?: string;
courseIncludes?: string;
startGuideLine?: string;
lessons : Lessons[];
courseTemplate : LMSTemplate;
courseType : CourseType;
totalLesson : number;
totalContent : number;
trainer : Employee;
createdUser : string;
enrollments : Enrollments;
courseProgres : CourseProgress;
lessonProgres : LessonProgress [] = [];
}

View File

@ -0,0 +1,35 @@
"use strict";
var __extends = (this && this.__extends) || (function () {
var extendStatics = function (d, b) {
extendStatics = Object.setPrototypeOf ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
return extendStatics(d, b);
};
return function (d, b) {
if (typeof b !== "function" && b !== null)
throw new TypeError("Class extends value " + String(b) + " is not a constructor or null");
extendStatics(d, b);
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.Enrollments = void 0;
var baseObject_1 = require("../Basic/baseObject");
var Enrollments = /** @class */ (function (_super) {
__extends(Enrollments, _super);
function Enrollments() {
var _this = _super.call(this) || this;
_this.enrollmentID = 0;
_this.userID = 0;
_this.courseID = 0;
_this.enrollDate = new Date();
_this.isCurrentEnroll = false;
_this.noOfEnroll = 0;
return _this;
}
return Enrollments;
}(baseObject_1.BaseObject));
exports.Enrollments = Enrollments;
//# sourceMappingURL=enrollments.js.map

View File

@ -0,0 +1 @@
{"version":3,"file":"enrollments.js","sourceRoot":"","sources":["enrollments.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;AAAA,kDAAiD;AAGjD;IAAiC,+BAAU;IACvC;QACI,YAAA,MAAK,WAAE,SAAC;QACR,KAAI,CAAC,YAAY,GAAG,CAAC,CAAC;QACtB,KAAI,CAAC,MAAM,GAAG,CAAC,CAAC;QAChB,KAAI,CAAC,QAAQ,GAAG,CAAC,CAAC;QAClB,KAAI,CAAC,UAAU,GAAG,IAAI,IAAI,EAAE,CAAC;QAC7B,KAAI,CAAC,eAAe,GAAG,KAAK,CAAC;QAC7B,KAAI,CAAC,UAAU,GAAG,CAAC,CAAC;;IACxB,CAAC;IASL,kBAAC;AAAD,CAAC,AAlBD,CAAiC,uBAAU,GAkB1C;AAlBY,kCAAW"}

View File

@ -0,0 +1,22 @@
import { BaseObject } from '../Basic/baseObject';
import { CourseProgress } from './course-progress';
export class Enrollments extends BaseObject {
constructor() {
super();
this.enrollmentID = 0;
this.userID = 0;
this.courseID = 0;
this.enrollDate = new Date();
this.isCurrentEnroll = false;
this.noOfEnroll = 0;
}
enrollmentID: number;
userID: number;
courseID: number;
enrollDate: Date;
isCurrentEnroll: boolean;
noOfEnroll : number;
courseProgres : CourseProgress;
}

View File

@ -0,0 +1,42 @@
"use strict";
var __extends = (this && this.__extends) || (function () {
var extendStatics = function (d, b) {
extendStatics = Object.setPrototypeOf ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
return extendStatics(d, b);
};
return function (d, b) {
if (typeof b !== "function" && b !== null)
throw new TypeError("Class extends value " + String(b) + " is not a constructor or null");
extendStatics(d, b);
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.LessonContent = void 0;
var baseObject_1 = require("../Basic/baseObject");
var enums_1 = require("../enums");
var LessonContent = /** @class */ (function (_super) {
__extends(LessonContent, _super);
function LessonContent() {
var _this = _super.call(this) || this;
_this.isLessonComplete = false;
_this.isComplete = true;
_this.isNotComplete = false;
_this.lessonID = 0;
_this.contentTitle = "";
_this.description = "";
_this.contentUrl = "";
_this.duration = "";
_this.isMendatory = false;
_this.status = enums_1.EnumStatus.Active;
_this.accessLevel = enums_1.EnumAccessLevel.Public;
_this.accessCount = 0;
return _this;
}
return LessonContent;
}(baseObject_1.BaseObject));
exports.LessonContent = LessonContent;
//# sourceMappingURL=lesson-content.js.map

View File

@ -0,0 +1 @@
{"version":3,"file":"lesson-content.js","sourceRoot":"","sources":["lesson-content.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;AAAA,kDAAiD;AACjD,kCAA2F;AAE3F;IAAmC,iCAAU;IAEzC;QACI,YAAA,MAAK,WAAE,SAAC;QAsBZ,sBAAgB,GAAY,KAAK,CAAC;QAClC,gBAAU,GAAa,IAAI,CAAC;QAC5B,mBAAa,GAAa,KAAK,CAAC;QAvB5B,KAAI,CAAC,QAAQ,GAAG,CAAC,CAAC;QAClB,KAAI,CAAC,YAAY,GAAG,EAAE,CAAC;QACvB,KAAI,CAAC,WAAW,GAAG,EAAE,CAAC;QACtB,KAAI,CAAC,UAAU,GAAG,EAAE,CAAC;QACrB,KAAI,CAAC,QAAQ,GAAG,EAAE,CAAC;QACnB,KAAI,CAAC,WAAW,GAAG,KAAK,CAAC;QACzB,KAAI,CAAC,MAAM,GAAG,kBAAU,CAAC,MAAM,CAAC;QAChC,KAAI,CAAC,WAAW,GAAG,uBAAe,CAAC,MAAM,CAAC;QAC1C,KAAI,CAAC,WAAW,GAAG,CAAC,CAAC;;IACzB,CAAC;IAeL,oBAAC;AAAD,CAAC,AA5BD,CAAmC,uBAAU,GA4B5C;AA5BY,sCAAa"}

View File

@ -0,0 +1,32 @@
import { BaseObject } from '../Basic/baseObject';
import { EnumStatus, EnumAccessLevel, EnumContentSource, EnumContentType } from '../enums';
export class LessonContent extends BaseObject{
constructor() {
super();
this.lessonID = 0;
this.contentTitle = "";
this.description = "";
this.contentUrl = "";
this.duration = "";
this.isMendatory = false;
this.status = EnumStatus.Active;
this.accessLevel = EnumAccessLevel.Public;
this.accessCount = 0;
}
lessonID: number; // Foreign Key to LMS_Lessons
contentTitle: string;
contentType: EnumContentType;
description: string;
contentUrl: string;
duration?: string;
isMendatory?: boolean;
accessLevel: EnumAccessLevel;
contentSource: EnumContentSource;
accessCount?: number;
isLessonComplete: boolean = false;
isComplete : boolean = true;
isNotComplete : boolean = false;
}

View File

@ -0,0 +1,34 @@
"use strict";
var __extends = (this && this.__extends) || (function () {
var extendStatics = function (d, b) {
extendStatics = Object.setPrototypeOf ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
return extendStatics(d, b);
};
return function (d, b) {
if (typeof b !== "function" && b !== null)
throw new TypeError("Class extends value " + String(b) + " is not a constructor or null");
extendStatics(d, b);
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.LessonProgress = void 0;
var baseObject_1 = require("../Basic/baseObject");
var LessonProgress = /** @class */ (function (_super) {
__extends(LessonProgress, _super);
function LessonProgress() {
var _this = _super.call(this) || this;
_this.isLessonComplete = false;
_this.completionPercentage = 0;
_this.startDate = new Date();
_this.lastAccessed = new Date();
_this.retryCount = 0;
return _this;
}
return LessonProgress;
}(baseObject_1.BaseObject));
exports.LessonProgress = LessonProgress;
//# sourceMappingURL=lesson-progress.js.map

View File

@ -0,0 +1 @@
{"version":3,"file":"lesson-progress.js","sourceRoot":"","sources":["lesson-progress.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;AAAA,kDAAiD;AAGjD;IAAoC,kCAAU;IAC1C;QACI,YAAA,MAAK,WAAE,SAAC;QACR,KAAI,CAAC,gBAAgB,GAAG,KAAK,CAAC;QAC9B,KAAI,CAAC,oBAAoB,GAAG,CAAC,CAAC;QAC9B,KAAI,CAAC,SAAS,GAAG,IAAI,IAAI,EAAE,CAAC;QAC5B,KAAI,CAAC,YAAY,GAAG,IAAI,IAAI,EAAE,CAAC;QAC/B,KAAI,CAAC,UAAU,GAAG,CAAC,CAAC;;IACxB,CAAC;IAeL,qBAAC;AAAD,CAAC,AAvBD,CAAoC,uBAAU,GAuB7C;AAvBY,wCAAc"}

View File

@ -0,0 +1,27 @@
import { BaseObject } from '../Basic/baseObject';
import { Lessons } from './lessons';
export class LessonProgress extends BaseObject{
constructor() {
super();
this.isLessonComplete = false;
this.completionPercentage = 0;
this.startDate = new Date();
this.lastAccessed = new Date();
this.retryCount = 0;
}
userID: number;
lessonID: number;
courseProgressID: number;
lessonContentID: number;
isLessonComplete: boolean;
completionPercentage: number;
startDate: Date;
completeDate: Date;
timeSpent: string;
lastAccessed: Date;
retryCount: number;
lesson : Lessons;
}

View File

@ -0,0 +1,40 @@
"use strict";
var __extends = (this && this.__extends) || (function () {
var extendStatics = function (d, b) {
extendStatics = Object.setPrototypeOf ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
return extendStatics(d, b);
};
return function (d, b) {
if (typeof b !== "function" && b !== null)
throw new TypeError("Class extends value " + String(b) + " is not a constructor or null");
extendStatics(d, b);
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.Lessons = void 0;
var baseObject_1 = require("../Basic/baseObject");
var enums_1 = require("../enums");
var Lessons = /** @class */ (function (_super) {
__extends(Lessons, _super);
function Lessons() {
var _this = _super.call(this) || this;
_this.lessonContents = [];
_this.courseID = 0;
_this.lessonTitle = "";
_this.lessonNo = "";
_this.description = "";
_this.duration = "";
_this.difficultyLevel = enums_1.EnumDifficultyLevel.Beginner;
_this.isQuizAvailable = false;
_this.status = enums_1.EnumStatus.Active;
_this.lessonContents = [];
return _this;
}
return Lessons;
}(baseObject_1.BaseObject));
exports.Lessons = Lessons;
//# sourceMappingURL=lessons.js.map

View File

@ -0,0 +1 @@
{"version":3,"file":"lessons.js","sourceRoot":"","sources":["lessons.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;AAAA,kDAAiD;AACjD,kCAA2D;AAI3D;IAA6B,2BAAU;IACnC;QACI,YAAA,MAAK,WAAE,SAAC;QAkBZ,oBAAc,GAAqB,EAAE,CAAC;QAjBlC,KAAI,CAAC,QAAQ,GAAG,CAAC,CAAC;QAClB,KAAI,CAAC,WAAW,GAAG,EAAE,CAAC;QACtB,KAAI,CAAC,QAAQ,GAAG,EAAE,CAAC;QACnB,KAAI,CAAC,WAAW,GAAG,EAAE,CAAC;QACtB,KAAI,CAAC,QAAQ,GAAG,EAAE,CAAC;QACnB,KAAI,CAAC,eAAe,GAAG,2BAAmB,CAAC,QAAQ,CAAC;QACpD,KAAI,CAAC,eAAe,GAAG,KAAK,CAAC;QAC7B,KAAI,CAAC,MAAM,GAAG,kBAAU,CAAC,MAAM,CAAC;QAChC,KAAI,CAAC,cAAc,GAAG,EAAE,CAAC;;IAC7B,CAAC;IAUL,cAAC;AAAD,CAAC,AAtBD,CAA6B,uBAAU,GAsBtC;AAtBY,0BAAO"}

View File

@ -0,0 +1,28 @@
import { BaseObject } from '../Basic/baseObject';
import { EnumDifficultyLevel, EnumStatus } from '../enums';
import { LessonContent } from './lesson-content';
import { LMSTemplate } from './lmstemplate';
export class Lessons extends BaseObject {
constructor() {
super();
this.courseID = 0;
this.lessonTitle = "";
this.lessonNo = "";
this.description = "";
this.duration = "";
this.difficultyLevel = EnumDifficultyLevel.Beginner;
this.isQuizAvailable = false;
this.status = EnumStatus.Active;
this.lessonContents = [];
}
courseID: number; // Foreign Key to LMS_Courses
lessonTitle: string;
lessonNo: string;
description: string;
duration?: string;
difficultyLevel: EnumDifficultyLevel;
isQuizAvailable?: boolean;
lessonContents : LessonContent[] = [];
lessonTemplate : LMSTemplate;
}

View File

@ -0,0 +1,32 @@
"use strict";
var __extends = (this && this.__extends) || (function () {
var extendStatics = function (d, b) {
extendStatics = Object.setPrototypeOf ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
return extendStatics(d, b);
};
return function (d, b) {
if (typeof b !== "function" && b !== null)
throw new TypeError("Class extends value " + String(b) + " is not a constructor or null");
extendStatics(d, b);
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.LMSTemplate = void 0;
var baseObject_1 = require("../Basic/baseObject");
var LMSTemplate = /** @class */ (function (_super) {
__extends(LMSTemplate, _super);
function LMSTemplate() {
var _this = _super.call(this) || this;
_this.templateID = 0;
_this.objectID = 0;
_this.fileName = "";
return _this;
}
return LMSTemplate;
}(baseObject_1.BaseObject));
exports.LMSTemplate = LMSTemplate;
//# sourceMappingURL=lmstemplate.js.map

View File

@ -0,0 +1 @@
{"version":3,"file":"lmstemplate.js","sourceRoot":"","sources":["lmstemplate.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;AAAA,kDAAiD;AAGjD;IAAiC,+BAAU;IACvC;QACI,YAAA,MAAK,WAAE,SAAC;QACR,KAAI,CAAC,UAAU,GAAG,CAAC,CAAC;QACpB,KAAI,CAAC,QAAQ,GAAG,CAAC,CAAC;QAClB,KAAI,CAAC,QAAQ,GAAG,EAAE,CAAC;;IACvB,CAAC;IAUL,kBAAC;AAAD,CAAC,AAhBD,CAAiC,uBAAU,GAgB1C;AAhBY,kCAAW"}

View File

@ -0,0 +1,20 @@
import { BaseObject } from '../Basic/baseObject';
import { EnumTemplateType } from "../enums";
export class LMSTemplate extends BaseObject {
constructor() {
super();
this.templateID = 0;
this.objectID = 0;
this.fileName = "";
}
templateID : number;
objectID : number;
templateType : EnumTemplateType
fileName : string;
fileData : string ;
fileType : number;
currentFile: any;
fileAsByteArray : string;
fileTobase64 : string;
}

View File

@ -0,0 +1,14 @@
import { BaseObject } from '../Basic/baseObject';
import { EnumReportGroupType } from '../enums';
export class OpenAIResponseWithData{
constructor() {
}
IsChart: boolean = false;
ChartType: string = "";
Title: string = "";
Labels: string[] = [];
Values: number[] = [];;
TableData: any;
LabelPosition: string = 'outsideEnd';
}

View File

@ -0,0 +1,18 @@
import { BaseObject } from '../Basic/baseObject';
import { EnumAIChartType, EnumReportGroupType } from '../enums';
export class OpenAIQueryLog extends BaseObject {
constructor() {
super();
}
userId : number = 0;
userPrompt : string = "";
generatedQuery : string = "";
executedAt : Date = new Date();
totalExecution : number = 0;
reportGroup: EnumReportGroupType;
isChart : boolean = false;
chartType : EnumAIChartType = EnumAIChartType.None;
title : string = "";
isCommon : boolean = false;
}

View File

@ -16,11 +16,70 @@ export enum EnumHrNotificationType {
System_Generated = 2, System_Generated = 2,
} }
export enum EnumDifficultyLevel {
Beginner = 1,
Intermediate = 2,
Advanced = 3
}
export enum EnumContentSource {
Youtube = 1,
GoogleDrive = 2,
OneDrive = 3,
AzureBlobStorage = 4,
}
export enum EnumAccessLevel {
Public = 1,
Private = 2,
Restricted = 3,
Premium = 4
}
export enum EnumAIChartType
{
None = 0,
BarChart = 1,
LineGraph = 2,
PieChart = 3,
ScatterPlot = 4,
AreaChart = 5,
Histogram = 6,
WaterfallChart = 7,
GantChart = 8,
RadarChart = 9,
ActivityDiagram = 10
}
export enum EnumContentType {
Video = 1,
Image = 2,
Pdf = 3,
Powerpoint = 4,
Excel = 5,
Doc = 6,
others = 7
}
export enum EnumReportGroupType
{
Employee = 1,
Salary = 2,
Performance = 3,
Training = 4,
Leave = 5,
Attendance = 6,
}
export enum EnumTaxInvestment { export enum EnumTaxInvestment {
Regardless = 0, Regardless = 0,
ESS = 1, ESS = 1,
Admin = 2, Admin = 2,
} }
export enum EnumTemplateType {
Course = 1,
Lesson = 2,
}
export enum EnumTaxInvestmentStatus { export enum EnumTaxInvestmentStatus {
Not_Yet_Approve = 0, Not_Yet_Approve = 0,
Approve = 1, Approve = 1,

View File

@ -0,0 +1,32 @@
import { EnumReportGroupType } from './../../_models/enums';
import {Injectable} from '@angular/core';
import {HttpClient, HttpEvent, HttpRequest} from '@angular/common/http';
import {ApiService} from '../../app.api.service';
import { OpenAIQueryLog } from 'src/app/_models/OpenAIQueryLog/OpenAIQueryLog';
@Injectable({
providedIn: 'root'
})
export class HRMOpenAIService {
constructor(public apiService: ApiService,
private http: HttpClient) {
}
GetAiInformation(userCommand : string) {
return this.apiService.httpGet<any>('/HRMApenAPIAI/GetAiInformation/' + userCommand);
}
AskOpenAI(data: any) {
return this.apiService.httpPost<any>('/HRMApenAPIAI/AskOpenAI', data);
}
GetReportColumnDefinition(reportGroupType : EnumReportGroupType) {
return this.apiService.httpGet<any[]>('/HRMApenAPIAI/GetReportColumnDefinition/' + reportGroupType);
}
GetCurrentUserAllQueryLog(reportGroupType : EnumReportGroupType) {
return this.apiService.httpGet<OpenAIQueryLog[]>('/HRMApenAPIAI/GetCurrentUserAllQueryLog/' + reportGroupType);
}
OpenAIPreviousQueryExecution(data: any) {
return this.apiService.httpPost<any>('/HRMApenAPIAI/OpenAIPreviousQueryExecution', data);
}
ChatShareWithOthers(data: any) {
return this.apiService.httpPost('/HRMApenAPIAI/ChatShareWithOthers', data);
}
}

View File

@ -0,0 +1,78 @@
import {Injectable} from '@angular/core';
import {HttpClient, HttpEvent, HttpRequest} from '@angular/common/http';
import {ApiService} from '../../app.api.service';
import { CourseType } from 'src/app/_models/LearningManagement/course-type';
import { EnumStatus } from 'src/app/_models/enums';
import { Courses } from 'src/app/_models/LearningManagement/courses';
import { CourseProgress } from 'src/app/_models/LearningManagement/course-progress';
@Injectable({
providedIn: 'root'
})
export class LMSService {
constructor(public apiService: ApiService,
private http: HttpClient) {
}
//#region Course Type
saveCourseType(param: any) {
return this.apiService.httpPost<CourseType>('/LMS/saveCourseType', param);
}
deleteCourseType(id : number) {
return this.apiService.httpGet('/LMS/deleteCourseType/' + id);
}
GetCourseTypeByStatus(status : EnumStatus) {
return this.apiService.httpGet<CourseType[]>('/LMS/getByStatus/' + status);
}
GetAllCourseType() {
return this.apiService.httpGet<CourseType[]>('/LMS/getAllCourseType');
}
getByParentID(parentID : number) {
return this.apiService.httpGet<CourseType[]>('/LMS/getAllCourseType/'+parentID);
}
//#endregion
//#region Courses
saveCourses(param: any) {
return this.apiService.httpPost<Courses>('/LMS/saveCourses', param);
}
deleteCourses(id : number) {
return this.apiService.httpGet('/LMS/deleteCourses/' + id);
}
GetCoursesByStatus(status : EnumStatus) {
return this.apiService.httpGet<Courses[]>('/LMS/getCoursesByStatus/' + status);
}
GetCourse(ID : number) {
return this.apiService.httpGet<Courses>('/LMS/getCourse/' + ID);
}
GetCourseForUser(ID : number) {
return this.apiService.httpGet<Courses>('/LMS/GetCourseForUser/' + ID);
}
GetCourseForEnrollment(ID : number) {
return this.apiService.httpGet<Courses>('/LMS/GetCourseForEnrollment/' + ID);
}
GetAllCourses() {
return this.apiService.httpGet<Courses[]>('/LMS/getAllCourses');
}
//#endregion
//#region Lessons
deleteLessons(id : number) {
return this.apiService.httpGet('/LMS/deleteLessons/' + id);
}
//#endregion
//#region Lesson Content
deleteLessonContent(id : number) {
return this.apiService.httpGet('/LMS/deleteLessonContent/' + id);
}
//#endregion
//#region LESSON Progress
UserCourseProgress(param: any) {
return this.apiService.httpPost<Courses>('/LMS/UserCourseProgress', param);
}
//#endregion
}

View File

@ -0,0 +1,9 @@
import { Injectable } from '@angular/core';
@Injectable({
providedIn: 'root'
})
export class PaymentApprovalService {
constructor() { }
}

View File

@ -97,6 +97,7 @@ import {ProgressBarModule} from '@progress/kendo-angular-progressbar';
import {RippleModule} from 'primeng/ripple'; import {RippleModule} from 'primeng/ripple';
import {MsalGuard, MsalInterceptor, MsalModule, MsalRedirectComponent, MsalService} from '@azure/msal-angular'; import {MsalGuard, MsalInterceptor, MsalModule, MsalRedirectComponent, MsalService} from '@azure/msal-angular';
import {InteractionType, PublicClientApplication} from '@azure/msal-browser'; import {InteractionType, PublicClientApplication} from '@azure/msal-browser';
import { HRMOpenAIModule } from './hrmopen-ai/hrmopen-ai.module';
FullCalendarModule.registerPlugins([ FullCalendarModule.registerPlugins([
dayGridPlugin, dayGridPlugin,
@ -170,6 +171,7 @@ FullCalendarModule.registerPlugins([
CardModule, CardModule,
TabViewModule, TabViewModule,
Pickermodule, Pickermodule,
HRMOpenAIModule,
NgxExtendedPdfViewerModule, NgxExtendedPdfViewerModule,
ProgressBarModule, ProgressBarModule,
MsalModule.forRoot(new PublicClientApplication( MsalModule.forRoot(new PublicClientApplication(

View File

@ -202,7 +202,12 @@ export const routes: Routes = [
path: 'dataintegration', path: 'dataintegration',
canActivate: [AuthGuard], canActivate: [AuthGuard],
loadChildren: () => import('./data-integration/data-integration.module').then(m => m.DataIntegrationModule) loadChildren: () => import('./data-integration/data-integration.module').then(m => m.DataIntegrationModule)
} },
{
path: 'hrm',
canActivate: [AuthGuard],
loadChildren: () => import('./hrmopen-ai/hrmopen-ai.module').then(m => m.HRMOpenAIModule)
}
]; ];
export const AppRoutes: ModuleWithProviders<any> = RouterModule.forRoot(routes, { scrollPositionRestoration: 'enabled' }); export const AppRoutes: ModuleWithProviders<any> = RouterModule.forRoot(routes, { scrollPositionRestoration: 'enabled' });

View File

@ -0,0 +1,14 @@
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { HRMOpenAITestComponent } from './hrmopen-ai-test/hrmopen-aiteast.component';
import { AuthGuard } from '../_guards/auth.guard';
export const routes: Routes = [
{ path: 'hrm-ai', component: HRMOpenAITestComponent, canActivate: [AuthGuard] },
];
@NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule]
})
export class HRMOpenAIRoutingModule { }

View File

@ -0,0 +1,313 @@
<app-loading-panel></app-loading-panel>
<div class="card shadow-sm rounded p-2" style="background-color: #ffffff; border: 1px solid #d9d9d9;height: 100%;">
<div class="card textarea-wrapper" style="position: relative; width: 100%;padding: 5px !important;">
<div class="p-grid">
<div class="p-col-7">
<div class="textarea-wrapper">
<textarea (input)="onInputChange()" [(ngModel)]="inputUserCommand" rows="4" class="formAITextArea"
placeholder="Ask me anything related to payroll or HR tasks..."></textarea>
<button *ngIf="inputUserCommand || filteredSuggestions.length > 0" type="button" class="clear-btn"
(click)="clearInput()">✖</button>
</div>
<ul *ngIf="filteredSuggestions.length > 0" class="suggestions-dropdown">
<li *ngFor="let item of filteredSuggestions" (click)="selectSuggestion(item)"
class="suggestion-item" [ngClass]="{ 'chart-query': item.isChart }">
<span class="suggestion-text">{{ item.userPrompt }}</span>
<span *ngIf="item.isChart" class="chart-icon">📊</span>
</li>
</ul>
<div class="toolbar-container">
<div class="toolbar-left">
<kendo-dropdownlist [data]="reportGroups"
[defaultItem]="{ description: 'Select AI Purpose....', value: null }"
[textField]="'description'" [valueField]="'value'" [valuePrimitive]="true"
[(ngModel)]="selectedReportGroup" (valueChange)="onReportGroupChange($event)"
class="w-14rem">
</kendo-dropdownlist>
<button (click)="openAvailableInfoDialog()"
[disabled]="selectedReportGroup === null || selectedReportGroup === undefined" kendoButton
themeColor="secondary">
Field Column
</button>
</div>
<div class="toolbar-right">
<button [disabled]="selectedReportGroup === null || selectedReportGroup === undefined"
kendoButton themeColor="primary" (click)="ShowAllQueryLog()">
Chat History
</button>
<button kendoButton themeColor="primary" (click)="onCallOpenAI_One()"
(keydown.enter)="handleEnterKey($event)">
Execute
</button>
</div>
</div>
</div>
<div class="p-col-5">
<ul style="padding-left: 16px; margin-top: 5px; margin-bottom: 0px;">
<li>
This AI-based report generation tool transforms your questions or input text into SQL or machine
language to fetch data from the database. Field information is provided to help you understand
which data can be accessed.
</li>
<li class="suggestion-item">
The system supports various types of visualizations: <strong>Bar chart</strong>, <strong>Pie
chart</strong>, <strong>Line chart</strong>, <strong>Scatter chart</strong> and
<strong>Histogram</strong>. To create a chart, include the chart type in your query — for
example:
<strong>"Generate a bar chart showing employee categories."</strong>
</li>
</ul>
</div>
</div>
</div>
<hr class="my-2" />
<div class="grid">
<div class="p-col-12">
<ng-container *ngIf="gridData?.length > 0; else noData">
<div class="grid-chart-wrapper" [ngClass]="{'show-chart': isShowChart}">
<div class="grid-container">
<div class="export-toolbar">
<div class="total-label">Total: <span class="total-count">{{ gridData.length }}</span></div>
<div class="export-buttons">
<button [disabled]="isDisabledShared === true" kendoButton themeColor="primary"
(click)="ShareThisChat()"
style="background: #ff6358 !important;font-weight: bold !important;"
[svgIcon]="null">Share</button>
<button kendoButton (click)="grid.saveAsExcel()">Export Excel</button>
<button kendoButton (click)="grid.saveAsPDF()">Export PDF</button>
</div>
</div>
<kendo-grid #grid [kendoGridBinding]="gridData" [scrollable]="'scrollable'" [height]="450"
[reorderable]="true" class="shadow-sm border custom-grid">
<ng-template kendoGridToolbarTemplate
*ngIf="deletedColumns.length > 0 && isShowChart === false">
<div class="deleted-columns-container" *ngIf="deletedColumns.length > 0">
<span class="toolbar-title">Deleted Columns :</span>
<button *ngFor="let col of deletedColumns; let idx = index"
[svgIcon]="apiService.KendoSVGIcon['plus']" kendoButton
(click)="restoreColumn(idx)" type="button" class="restore-btn">
{{ col.title || col.field }}
</button>
</div>
</ng-template>
<kendo-grid-column *ngFor="let col of gridColumns; let i = index" [field]="col.field"
[title]="col.title" [width]="150" [orderIndex]="i">
<ng-template kendoGridHeaderTemplate>
<div class="header-container" [attr.data-col-index]="i">
<span *ngIf="!gridColumns[i].editing" class="header-title">{{
gridColumns[i].title || gridColumns[i].field }}</span>
<input *ngIf="gridColumns[i].editing" [(ngModel)]="gridColumns[i].title"
[ngModelOptions]="{ standalone: true }" (blur)="onHeaderBlur(i)" type="text"
class="header-input" />
<button *ngIf="!gridColumns[i].editing" type="button" class="edit-btn"
(click)="startEdit(i); $event.stopPropagation()"
title="Edit column title">✎</button>
<button *ngIf="!gridColumns[i].editing && isShowChart === false" type="button"
class="delete-btn" (click)="deleteColumn(i); $event.stopPropagation()"
title="Delete column">✖</button>
<button *ngIf="gridColumns[i].editing" type="button" class="save-btn"
(click)="saveHeader(i); $event.stopPropagation()" title="Save">✔</button>
</div>
</ng-template>
<ng-template kendoGridCellTemplate let-dataItem>
<div class="cell-wrap">{{ dataItem[col.field] }}</div>
</ng-template>
</kendo-grid-column>
<kendo-grid-excel [fileName]="excelFileName"></kendo-grid-excel>
<kendo-grid-pdf [fileName]="pdfFileName" paperSize="A4"></kendo-grid-pdf>
</kendo-grid>
</div>
<div class="chart-container" *ngIf="isShowChart">
<div class="export-toolbar justify-end">
<div class="export-buttons">
<button kendoButton (click)="exportSizedChart(chart)">Export PDF</button>
<button kendoButton (click)="exportChartImage(chart)"> Export PNG</button>
</div>
</div>
<div style="width: 100%;overflow: auto;">
<kendo-chart #chart [transitions]="chartTransitions"
style="height: 450px !important; width: 100% !important;"
*ngIf="openAIResponseWithData.IsChart && openAIResponseWithData.ChartType !== 'scatter' && openAIResponseWithData.ChartType !== 'histogram'"
class="h-full w-full">
<kendo-chart-title [text]="openAIResponseWithData.Title"
align="center"></kendo-chart-title>
<kendo-chart-legend
[position]="openAIResponseWithData.ChartType === 'pie' ? gridData.length > 25 ? 'bottom' : 'right' : 'bottom'"></kendo-chart-legend>
<kendo-chart-category-axis>
<kendo-chart-category-axis-item [categories]="chartCategories">
</kendo-chart-category-axis-item>
</kendo-chart-category-axis>
<kendo-chart-value-axis>
<kendo-chart-value-axis-item>
<kendo-chart-value-axis-item-labels
[format]="'{0}'"></kendo-chart-value-axis-item-labels>
</kendo-chart-value-axis-item>
</kendo-chart-value-axis>
<kendo-chart-series>
<kendo-chart-series-item [type]="openAIResponseWithData.ChartType"
[data]="chartData" field="value" categoryField="category"
[labels]="{ visible: true, position: openAIResponseWithData.LabelPosition }"
[line]="{ style: 'smooth' }" [opacity]="0.7">
</kendo-chart-series-item>
</kendo-chart-series>
</kendo-chart>
<kendo-chart #chart [transitions]="chartTransitions"
style="height: 450px !important; width: 100% !important;"
*ngIf="openAIResponseWithData.IsChart && openAIResponseWithData.ChartType === 'scatter'"
class="h-full w-full">
<kendo-chart-title [text]="openAIResponseWithData.Title"></kendo-chart-title>
<kendo-chart-legend position="bottom"></kendo-chart-legend>
<kendo-chart-x-axis>
<kendo-chart-x-axis-item title="X Axis"></kendo-chart-x-axis-item>
</kendo-chart-x-axis>
<kendo-chart-y-axis>
<kendo-chart-y-axis-item title="Y Axis">
<kendo-chart-y-axis-item-labels
[format]="'{0}'"></kendo-chart-y-axis-item-labels>
</kendo-chart-y-axis-item>
</kendo-chart-y-axis>
<kendo-chart-series>
<kendo-chart-series-item type="scatter" [data]="chartData" xField="x" yField="y"
[labels]="{
visible: true,
content: scatterLabelContent
}">
</kendo-chart-series-item>
</kendo-chart-series>
</kendo-chart>
<kendo-chart #chart [transitions]="chartTransitions"
style="height: 450px !important; width: 100% !important;"
*ngIf="openAIResponseWithData.IsChart && openAIResponseWithData.ChartType === 'histogram'"
class="h-full w-full">
<kendo-chart-title text="Histogram Example"></kendo-chart-title>
<kendo-chart-legend position="bottom"></kendo-chart-legend>
<kendo-chart-category-axis>
<kendo-chart-category-axis-item
[title]="{ text: 'Value' }"></kendo-chart-category-axis-item>
</kendo-chart-category-axis>
<kendo-chart-value-axis>
<kendo-chart-value-axis-item>
<kendo-chart-value-axis-item-labels
format="{0}"></kendo-chart-value-axis-item-labels>
</kendo-chart-value-axis-item>
</kendo-chart-value-axis>
<kendo-chart-series>
<kendo-chart-series-item *ngFor="let item of histogramSeries" [type]="item.type"
[data]="item.data" [labels]="{ visible: true }">
</kendo-chart-series-item>
</kendo-chart-series>
</kendo-chart>
</div>
</div>
</div>
</ng-container>
<ng-template #noData>
<div class="ai-error-message" *ngIf="invalidQueryMessage" [@fadeInOut]="messageState">{{
invalidQueryMessage }}</div>
<div class="ai-guidance-card" *ngIf="isUserPromptIsNotRelated" [@fadeInOut]="messageState">
<h4 class="ai-guidance-title">⚠️ Lets stay focused on this section</h4>
<p class="ai-guidance-text">
Your query isnt related to the selected purpose. Please ask only about this section using the
listed fields as a guide.
💡 You can also click the <strong>Chat History</strong> button to review your previous queries.
</p>
<div *ngFor="let section of tableColumnDefinition" class="ai-section">
<p class="ai-section-title">{{ section.tableName }}</p>
<div class="ai-field-badges">
<span *ngFor="let field of section.fields" class="badge">{{ field }}</span>
</div>
</div>
<div class="ai-tip">💡 Use the above fields to guide your AI query. The more specific you are, the
better the result will be.</div>
</div>
</ng-template>
</div>
</div>
</div>
<kendo-dialog *ngIf="isShowAvailableInfo" (close)="isShowAvailableInfo = false" title="Available Information"
[maxHeight]="600" [width]="500">
<div *ngFor="let section of tableColumnDefinition">
<p style="margin-bottom: 0px !important;"><strong>{{ section.tableName }}</strong></p>
<ul style="margin-top: 0px !important;">
<li>{{ section.fields.join(', ') }}</li>
</ul>
</div>
<p class="centered-info">
Use the above fields to guide your AI query. The more specific you are, the better the result will be.
</p>
<kendo-dialog-actions>
<button kendoButton themeColor="primary" (click)="isShowAvailableInfo = false">Close</button>
</kendo-dialog-actions>
</kendo-dialog>
<kendo-dialog *ngIf="isShowCurrentUserAllQueryLog" (close)="isShowCurrentUserAllQueryLog = false" title="Chat History"
[maxHeight]="700" [height]="700" [width]="500">
<div class="history-wrapper">
<div class="search-box">
<textarea kendoTextArea [(ngModel)]="querySearchText" rows="2" placeholder="Search your chat history..."
style="width:100%; border-radius:8px; padding:8px; font-size:14px;border-color: #52527A;">
</textarea>
</div>
<div class="query-card-container scrollable">
<div class="query-card" *ngFor="let item of filteredQueryLog()" [ngClass]="{ 'chart-query': item.isChart }"
(mouseenter)="item.hover = true" (mouseleave)="item.hover = false"
(click)="OpenAIPreviousQueryExecution(item.id)">
<div class="query-card-content">
<div class="query-text">{{ item.userPrompt }}</div>
<div *ngIf="item.isChart" class="chart-icon">📊</div>
<i *ngIf="!item.isCommon" class="pi pi-share-alt"
(click)="ShareThisChatWithOthers(item); $event.stopPropagation()" style="margin-left: 5px;"></i>
</div>
</div>
</div>
</div>
</kendo-dialog>
<kendo-dialog *ngIf="isShowChartOption" (close)="isShowChartOption = false" title="Charts" [maxHeight]="500"
[width]="500">
<div class="p-grid">
<div class="p-col-3"><label for="">Graph Name</label></div>
<div class="p-col-9">
<kendo-dropdownlist [data]="chartGroups" [defaultItem]="{ description: 'Select a Chart....', value: null }"
[textField]="'description'" [valueField]="'value'" [valuePrimitive]="true"
[(ngModel)]="selectedChartGroup" (valueChange)="onChartGroupChange($event)" style="width: 100%;">
</kendo-dropdownlist>
</div>
<div class="p-col-3"><label for="">Column X</label></div>
<div class="p-col-9">
<kendo-dropdownlist [data]="gridColumns" [defaultItem]="{ description: 'X...', value: null }"
[textField]="'description'" [valueField]="'value'" [valuePrimitive]="true" [(ngModel)]="selectedColumnX"
(valueChange)="onChartGroupChange($event)" style="width: 100%;">
</kendo-dropdownlist>
</div>
<div class="p-col-3"><label for="">Column Y</label></div>
<div class="p-col-9">
<kendo-dropdownlist [data]="gridColumns" [defaultItem]="{ description: 'Y...', value: null }"
[textField]="'description'" [valueField]="'value'" [valuePrimitive]="true" [(ngModel)]="selectedColumnY"
(valueChange)="onChartGroupChange($event)" style="width: 100%;">
</kendo-dropdownlist>
</div>
<div class="p-col-3"><label for="">Merge</label></div>
<div class="p-col-9">
<input [(ngModel)]="chartMerge" type="text" style="width:100%" pInputText readonly>
</div>
<div class="p-col-3"><label for="">Name</label></div>
<div class="p-col-9">
<input [(ngModel)]="chartName" type="text" style="width:100%" pInputText readonly>
</div>
<div class="p-col-12" align="right">
<button kendoButton themeColor="primary" [svgIcon]="apiService.KendoSVGIcon['eye']">Plot</button>
</div>
</div>
</kendo-dialog>

View File

@ -0,0 +1,458 @@
.textarea-wrapper {
position: relative;
width: 100%;
}
textarea.formAITextArea {
font-size: 1rem;
padding: 0.75rem 2.5rem 0.75rem 0.75rem;
border-radius: 0.5rem;
resize: none;
width: 100%;
height: 78%;
box-sizing: border-box;
}
.clear-btn {
position: absolute;
right: 10px;
top: 50%;
transform: translateY(-50%);
background: transparent;
border: none;
cursor: pointer;
font-size: 1.2rem;
color: #888;
z-index: 10;
padding: 0;
line-height: 1;
}
.clear-btn:hover {
color: #333;
}
.p-button-rounded {
width: 2.5rem;
height: 2.5rem;
}
.centered-info {
text-align: center;
margin-top: 12px;
color: red;
font-weight: bold;
}
.userPrompt{
cursor: pointer;
}
.userPrompt :hover{
color: #414278;
font-weight: bold;
}
.query-card-container {
display: flex;
flex-direction: column;
gap: 10px;
}
.query-card {
background: white;
border-radius: 10px;
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.1);
padding: 4px 16px;
transition: transform 0.2s ease, box-shadow 0.2s ease;
cursor: pointer;
position: relative;
border: 1px solid #cfcfcf;
}
.query-card:hover {
transform: translateY(-2px);
box-shadow: 0 4px 10px rgba(0,0,0,0.15);
}
.query-card-content {
display: flex;
justify-content: space-between;
align-items: center;
}
.query-text {
flex: 1;
font-size: 14px;
line-height: 1.4;
max-height: calc(1.4em * 2);
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
}
.query-arrow {
font-size: 18px;
color: #52527A;
padding-left: 10px;
user-select: none;
}
.query-arrow:hover {
color: #33334e;
}
.query-date {
font-size: 12px;
color: #777;
text-align: right;
margin-top: 4px;
}
.chart-icon {
margin-left: 8px;
color: #52527A;
font-size: 16px;
}
.chart-query {
background: #e6f7ff;
}
.search-box textarea {
resize: none;
box-shadow: 0 2px 5px rgba(0,0,0,0.1);
border: 1px solid #cfcfcf;
transition: border-color 0.2s ease, box-shadow 0.2s ease;
}
.search-box textarea:focus {
border-color: #52527A;
box-shadow: 0 0 5px rgba(82,82,122,0.5);
outline: none;
}
.history-wrapper {
display: flex;
flex-direction: column;
height: 100%;
}
.search-box {
flex: 0 0 auto;
margin-bottom: 10px;
}
.scrollable {
flex: 1 1 auto;
overflow-y: auto;
max-height: 100%;
}
.scrollable::-webkit-scrollbar {
width: 6px;
}
.scrollable::-webkit-scrollbar-track {
background: #f5f5f5;
border-radius: 10px;
}
.scrollable::-webkit-scrollbar-thumb {
background-color: #d6d6d6;
border-radius: 10px;
border: 2px solid #f5f5f5;
}
.scrollable::-webkit-scrollbar-thumb:hover {
background-color: #bfbfbf;
}
.suggestions-dropdown {
position: absolute;
background: rgba(255, 255, 255, 0.85); /* semi-transparent */
backdrop-filter: blur(4px); /* blur effect */
border: 1px solid #cfcfcf;
border-radius: 6px;
box-shadow: 0 2px 6px rgba(0,0,0,0.15);
max-height: 350px;
overflow-y: auto;
width: 500px;
z-index: 1000;
padding: 0;
margin: 0;
list-style: none;
}
.suggestions-dropdown li {
padding: 6px 12px;
cursor: pointer;
border-bottom: 1px solid #d1d1d1;
}
.suggestions-dropdown li:hover {
background: #f0f0f0;
color: #333;
}
.suggestions-dropdown .chart-icon {
margin-left: 6px;
}
.textarea-wrapper {
position: relative;
width: 100%;
}
.formAITextArea {
width: 100%;
padding: 0.75rem 2rem 0.75rem 0.75rem;
border-radius: 0.5rem;
resize: none;
font-size: 1rem;
}
suggestions-dropdown li.suggestion-item {
display: flex;
justify-content: space-between;
align-items: center;
padding: 6px 12px;
cursor: pointer;
}
.suggestions-dropdown li.suggestion-item:hover {
background: #f0f0f0;
}
.suggestions-dropdown .chart-icon {
margin-left: 8px;
float: right;
font-size: 16px;
color: #52527A;
}
.grid-chart-wrapper {
display: flex;
gap: 10px;
}
.grid-chart-wrapper.show-chart .grid-container {
width: 50%;
}
.grid-chart-wrapper.show-chart .chart-container {
width: 50%;
}
.grid-chart-wrapper:not(.show-chart) .grid-container {
width: 100%;
}
.chart-container {
height: 520px;
}
.export-buttons {
display: flex;
justify-content: flex-end;
gap: 5px;
padding: 3px;
}
.ai-error-message {
text-align: center;
background: #fee2e2;
color: #991b1b;
border: 1px solid #fecaca;
border-radius: 10px;
padding: 10px 15px;
margin: 10px auto;
max-width: 80%;
font-weight: 500;
box-shadow: 0 2px 6px rgba(0,0,0,0.05);
}
.ai-guidance-card {
background: #f9fafb;
border: 1px solid #e5e7eb;
border-radius: 12px;
padding: 20px;
margin: auto;
max-width: 80%;
box-shadow: 0 4px 12px rgba(0,0,0,0.06);
}
.ai-guidance-title {
font-size: 1.2rem;
font-weight: 600;
color: #111827;
margin-bottom: 10px;
}
.ai-guidance-text {
color: #374151;
font-size: 0.95rem;
margin-bottom: 15px;
}
.ai-section {
margin-bottom: 12px;
}
.ai-section-title {
font-weight: 600;
color: #1e40af;
margin-bottom: 4px;
}
.ai-field-list {
margin: 0;
padding-left: 15px;
color: #1e3a8a;
font-size: 0.9rem;
}
.ai-field-list li {
margin: 3px 0;
}
.ai-tip {
margin-top: 15px;
background: #e0f2fe;
color: #0369a1;
padding: 8px 12px;
border-radius: 8px;
font-size: 0.9rem;
font-style: italic;
}
.ai-field-badges {
display: flex;
flex-wrap: wrap;
gap: 6px;
}
.badge {
background: #f1f3f5;
padding: 4px 10px;
border-radius: 12px;
font-size: 13px;
color: #495057;
}
.export-toolbar {
display: flex;
justify-content: space-between;
align-items: center;
border: 1px solid #dee2e6;
border-radius: 5px;
margin-bottom: 5px;
}
.total-label {
font-weight: bold;
color: red;
font-size: 14px;
margin-left: 5px;
}
.total-count {
color: #000;
margin-left: 4px;
}
.export-toolbar.justify-end {
justify-content: flex-end;
}
.export-buttons .k-button-md {
padding-block: 2px !important;
padding-inline: 2px !important;
}
.custom-grid .cell-wrap {
min-width: 150px;
white-space: normal;
word-wrap: break-word;
overflow-wrap: anywhere;
}
.custom-grid .k-grid-content {
overflow-x: auto !important;
}
.header-container {
display: flex;
align-items: center;
gap: 2px;
width: 100%;
}
.header-title {
flex: 1 1 auto;
min-width: 0;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
padding: 3px 3px;
}
.header-input {
flex: 1 1 auto;
min-width: 0;
padding: 3px 3px;
background: #ffffff;
border: 1px solid #b5b5b5;
border-radius: 5px;
}
.header-input:focus {
outline: 1px solid #b6d6f7;
background-color: #ffffff;
}
.edit-btn, .save-btn {
flex: 0 0 20px;
width: 20px;
height: 20px;
display: inline-flex;
align-items: center;
justify-content: center;
border: none;
background: transparent;
cursor: pointer;
font-size: 14px;
border-radius: 4px;
}
.save-btn {
font-weight: 600;
}
::ng-deep .grid-chart-wrapper .k-grid .k-cell-inner>.k-link {
padding: 4px 4px !important;
}
::ng-deep .k-toolbar {
padding: 4px 7px 1px 7px !important;
}
.delete-btn {
color: red;
flex: 0 0 20px;
width: 20px;
height: 20px;
display: inline-flex;
align-items: center;
justify-content: center;
border: none;
background: transparent;
cursor: pointer;
font-size: 14px;
border-radius: 4px;
}
.edit-btn:hover, .save-btn:hover, .delete-btn:hover {
background: rgba(0,0,0,0.04);
}
.toolbar-title {
font-weight: bold;
margin-right: 8px;
}
.deleted-columns-container {
display: flex;
align-items: center;
gap: 0px;
max-width: 100%;
overflow-x: auto;
white-space: nowrap;
padding: 0px 0px 3px 0px;
}
.restore-btn {
flex: 0 0 auto;
margin-left: 4px;
padding: 2px 6px;
border: 1px solid #6263a0;
border-radius: 4px;
background: #e3f2fd;
cursor: pointer;
color: #495057;
}
.deleted-columns-wrapper {
display: flex;
align-items: center;
gap: 6px;
}
.toolbar-container {
display: flex;
justify-content: space-between;
align-items: center;
width: 100%;
margin-top: 8px;
}
.toolbar-left,
.toolbar-right {
display: flex;
align-items: center;
gap: 10px;
}
.toolbar-left {
justify-content: flex-start;
}
.toolbar-right {
justify-content: flex-end;
}
@media (max-width: 768px) {
.toolbar-container {
flex-direction: column;
align-items: stretch;
gap: 10px;
}
.toolbar-left,
.toolbar-right {
justify-content: space-between;
}
}

View File

@ -0,0 +1,572 @@
import { Component, ElementRef, OnInit, ViewChild } from '@angular/core';
import { ApiService } from 'src/app/app.api.service';
import { DataTransferService } from 'src/app/data.transfer.service';
import { Router, ActivatedRoute } from '@angular/router';
import { SearchEmployee } from 'src/app/_models/Employee/searchEmployee';
import { HRMNotificationService } from 'src/app/app.notification.service';
import { loadingPanelService } from 'src/app/hrm-loding panel/loding.panel.service';
import { Courses } from 'src/app/_models/LearningManagement/courses';
import { Lessons } from 'src/app/_models/LearningManagement/lessons';
import { LessonContent } from 'src/app/_models/LearningManagement/lesson-content';
import { LMSService } from 'src/app/_services/LearningManagement/lms.service';
import { EnumAccessLevel, EnumAIChartType, EnumContentType, EnumDifficultyLevel, EnumFileType, EnumReportGroupType, EnumStatus, EnumTemplateType } from 'src/app/_models/enums';
import { CourseType } from 'src/app/_models/LearningManagement/course-type';
import { LMSTemplate } from 'src/app/_models/LearningManagement/lmstemplate';
import { HRMOpenAIService } from 'src/app/_services/HRMOpenAI/hrmopen-ai.service';
import { OpenAIQueryLog } from 'src/app/_models/OpenAIQueryLog/OpenAIQueryLog';
import { OpenAIResponseWithData } from 'src/app/_models/OpenAI BO/OpenAIResponseWithData';
import { Pipe, PipeTransform } from '@angular/core';
import { HostListener } from '@angular/core';
import { saveAs } from "@progress/kendo-file-saver";
import { ChartComponent } from "@progress/kendo-angular-charts";
import { exportPDF, fit, geometry, Group } from "@progress/kendo-drawing";
function mm(val: number): number {return val * 2.8347;}
const PAGE_RECT = new geometry.Rect([0, 0], [mm(210 - 20), mm(297 - 20)]);
import { trigger, state, style, animate, transition } from '@angular/animations';
@Component({
selector: 'app-hrmopen-aiteast',
templateUrl: './hrmopen-aiteast.component.html',
styleUrls: ['./hrmopen-aiteast.component.scss'],
//standalone: false,
animations: [
trigger('fadeInOut', [
transition('* => changed', [
style({ opacity: 0 }),
animate('500ms ease-in', style({ opacity: 1 }))
])
])
]
})
export class HRMOpenAITestComponent implements OnInit{
constructor(public apiService : ApiService,
public notificationService: HRMNotificationService,
public loadingpanelService: loadingPanelService, public opeAiService : HRMOpenAIService) {
this.apiService.selectedMenuName = "HRM AI";
}
inputUserCommand : string = "";
public gridData: any[] = []; // data for the grid
public gridColumns: any[] = [];
public gridColumnsForChart: any[] = []; // columns for dynamic grid
public output: any = "";
public reportGroups : any[] = [];
public chartGroups : any[] = [];
public reportColumnDefinition: any[] = [];
public tableColumnDefinition: ReportColumnDefinition[] = [];
public selectedReportGroup: EnumReportGroupType | null;
public selectedChartGroup: EnumReportGroupType | null;
public isShowAvailableInfo: boolean = false;
public isShowCurrentUserAllQueryLog: boolean = false;
public invalidQueryMessage : string = "The AI can provide information when you ask about HR.";
public currentUserAllQueryLog : OpenAIQueryLog[] = [];
public filteredSuggestions: OpenAIQueryLog[] = [];
public OpenAIResponce: any = {};
public openAIResponseWithData: OpenAIResponseWithData = new OpenAIResponseWithData();
public chartData: any[] = [];
public isShowChart: boolean = false;
public isShowChartOption: boolean = false;
public chartMerge : string = "";
public chartName : string = "";
public selectedColumnX : any;
public selectedColumnY : any;
public searchText: string = "";
public querySearchText: string = "";
public excelFileName: string = "OpenAIQueryLog.xlsx";
public pdfFileName: string = "OpenAIQueryLog.pdf";
public pdfFileNameForChart: string = "OpenAIQueryLog.pdf";
public pngFilename: string = "OpenAIQueryLog.png";
public chartTransitions = false;
public isUserPromptIsNotRelated = false;
public messageState: string = '';
public isDisabledShared : boolean = true;
public currentChat : OpenAIQueryLog | undefined;
public deletedColumns: any[] = [];
@ViewChild('deletedContainer', { static: false }) deletedContainer!: ElementRef;
@ViewChild("chart")
private chart: ChartComponent;
private setInvalidQueryMessage(msg: string) {
this.invalidQueryMessage = msg;
this.messageState = "changed";
setTimeout(() => (this.messageState = ""), 500);
}
ngOnInit(){
this.deletedColumns = [];
this.isUserPromptIsNotRelated = false;
this.currentChat = undefined;
this.invalidQueryMessage = "The AI can provide information when you ask about HR."
this.reportGroups = [
{description : "Employee", value : EnumReportGroupType.Employee},
{description : "Leave", value : EnumReportGroupType.Leave},
{description : "Attendance", value : EnumReportGroupType.Attendance},
{description : "Salary", value : EnumReportGroupType.Salary},
{description : "Performance", value : EnumReportGroupType.Performance},
{description : "Training", value : EnumReportGroupType.Training},
];
this.chartGroups = [
{description : "Bar Chart", value : EnumAIChartType.BarChart},
{description : "Line Graph", value : EnumAIChartType.LineGraph},
{description : "Pie Chart", value : EnumAIChartType.PieChart},
{description : "Scatter Plot", value : EnumAIChartType.ScatterPlot},
{description : "Area Chart", value : EnumAIChartType.AreaChart},
{description : "Histogram", value : EnumAIChartType.Histogram},
{description : "Waterfall Chart", value : EnumAIChartType.WaterfallChart},
{description : "Gant Chart", value : EnumAIChartType.GantChart},
{description : "Radar Chart", value : EnumAIChartType.RadarChart},
{description : "Activity Diagram", value : EnumAIChartType.ActivityDiagram},
];
this.selectedReportGroup = EnumReportGroupType.Employee
this.onReportGroupChange(this.selectedReportGroup);
}
LoadCurrentUserAllQueryLog(reportGroupType : EnumReportGroupType){
this.loadingpanelService.ShowLoadingPanel = true;
this.opeAiService.GetCurrentUserAllQueryLog(reportGroupType).subscribe(
(resp: any) => {
this.currentUserAllQueryLog = resp;
},
(err: any) => {
this.loadingpanelService.ShowLoadingPanel = false;
this.notificationService.showError(err.error, "Error");
},
() => {
this.loadingpanelService.ShowLoadingPanel = false;
this.currentChat = undefined;
if(this.currentUserAllQueryLog && this.currentUserAllQueryLog.length > 0){
if(this.inputUserCommand !== ""){
let queryLog : OpenAIQueryLog = this.currentUserAllQueryLog.find(x => x.userPrompt.toLowerCase() === this.inputUserCommand.toLowerCase()) ?? undefined;
if(queryLog != undefined){
if(queryLog.isCommon === false){
this.currentChat = queryLog;
this.isDisabledShared = false;
}
else{
this.isDisabledShared = true;
}
}
else{
this.isDisabledShared = true;
}
}
else{
this.isDisabledShared = true;
}
}
});
}
ShowAllQueryLog(){
this.querySearchText = "";
this.isShowCurrentUserAllQueryLog = true;
this.LoadCurrentUserAllQueryLog(this.selectedReportGroup);
}
onInputChange() {
const text = this.inputUserCommand?.toLowerCase().trim() || '';
if (!text) {this.filteredSuggestions = [];return;}
this.filteredSuggestions = this.currentUserAllQueryLog
.filter(item => item.userPrompt.toLowerCase().startsWith(text))
.slice(0, 10);
}
closeSuggestions() {
this.filteredSuggestions = [];
}
clearInput() {
this.inputUserCommand = '';
this.filteredSuggestions = [];
this.gridData = this.gridColumns = [];
this.OpenAIResponce = {};
this.currentChat = undefined;
this.isDisabledShared = true;
}
@HostListener('document:click', ['$event'])
handleClickOutside(event: MouseEvent) {
const target = event.target as HTMLElement;
if (!target.closest('.suggestion-wrapper')) {
this.closeSuggestions();
}
}
selectSuggestion(item: OpenAIQueryLog) {
this.isUserPromptIsNotRelated = false;
this.invalidQueryMessage = "No data returned from AI."
this.inputUserCommand = item.userPrompt;
this.filteredSuggestions = [];
this.OpenAIPreviousQueryExecution(item.id); // or any other action
}
handleEnterKey(event: KeyboardEvent): void {
event.preventDefault();
if (this.inputUserCommand?.trim()) {
this.onCallOpenAI_One();
}
}
onCallOpenAI_One(){
this.deletedColumns = [];
this.isUserPromptIsNotRelated = false;
this.currentChat = undefined;
this.invalidQueryMessage = "No data returned from AI."
if(this.selectedReportGroup && this.inputUserCommand && this.inputUserCommand !== "" &&
(this.selectedReportGroup === EnumReportGroupType.Employee || this.selectedReportGroup === EnumReportGroupType.Salary
|| this.selectedReportGroup === EnumReportGroupType.Performance || this.selectedReportGroup === EnumReportGroupType.Training
|| this.selectedReportGroup === EnumReportGroupType.Leave || this.selectedReportGroup === EnumReportGroupType.Attendance)){
const data = {userPrompt: this.inputUserCommand,reportGroup: this.selectedReportGroup}
this.gridData = this.gridColumns = [];
this.OpenAIResponce = {};
this.isShowChart = false;
if(this.CheckUserPromptFromPreviousQueryLog(this.inputUserCommand)){
let OpenAIQueryLog: OpenAIQueryLog = this.currentUserAllQueryLog.find(x => x.userPrompt.toLowerCase() === this.inputUserCommand.toLowerCase()) ?? undefined;
if(OpenAIQueryLog != undefined){
this.OpenAIPreviousQueryExecution(OpenAIQueryLog.id);
}
return;
}
this.isUserPromptIsNotRelated = false;
this.loadingpanelService.ShowLoadingPanel = true;
this.opeAiService.AskOpenAI(data).subscribe(
(resp: any) => {
this.OpenAIResponce = JSON.parse(resp);
},
(err: any) => {
this.loadingpanelService.ShowLoadingPanel = false;
this.isUserPromptIsNotRelated = false;
if (err.error && (err.error as string).includes("Sorry, I can only help with retrieving data. I am not allowed to update or delete any records.")) {
this.setInvalidQueryMessage("Sorry, I can only help with retrieving data. I am not allowed to update or delete any records.");
}
else if (err.error && (err.error as string).includes("I can only help with questions related to")) {
this.showOutOfScopeNotice();
}
else{
this.notificationService.showError(err.error, "Error");
}
},
() => {
this.loadingpanelService.ShowLoadingPanel = false;
this.ProcessOpenAIData();
this.LoadCurrentUserAllQueryLog(this.selectedReportGroup);
});
}
}
CheckUserPromptFromPreviousQueryLog(userPrompt: string): boolean {
return this.currentUserAllQueryLog.some(item => item.userPrompt.toLowerCase() === userPrompt.toLowerCase());
}
get chartCategories(): string[] {
if (!this.chartData) return [];
return this.chartData.map(d => d.category);
}
public scatterLabelContent(e: any): string {
return `(${e.dataItem.x}, ${e.dataItem.y})`;
}
ProcessOpenAIData() {
this.deletedColumns = [];
if (!this.OpenAIResponce) {
this.invalidQueryMessage = "No data returned from AI.";
return;
}
this.openAIResponseWithData = this.OpenAIResponce as OpenAIResponseWithData;
if (!this.openAIResponseWithData) { return; }
// --- CHART handling (kept mostly same as your original logic) ---
if (this.openAIResponseWithData.IsChart && this.openAIResponseWithData.ChartType && this.openAIResponseWithData.ChartType !== "") {
if (this.openAIResponseWithData.ChartType === 'line' || this.openAIResponseWithData.ChartType === 'area') {
this.openAIResponseWithData.LabelPosition = 'above';
} else {
this.openAIResponseWithData.LabelPosition = 'outsideEnd';
}
this.isShowChart = true;
this.chartData = [];
if (this.openAIResponseWithData.ChartType === 'scatter') {
this.chartData = this.openAIResponseWithData.Labels.map((label, index) => ({
x: label,
y: this.openAIResponseWithData.Values[index]
}));
} else {
this.chartData = this.openAIResponseWithData.Labels.map((label, index) => ({
category: label,
value: this.openAIResponseWithData.Values[index]
}));
}
}
// --- TABLE parsing and normalization ---
try {
const parsed = JSON.parse(this.openAIResponseWithData.TableData);
let allRows: any[] = [];
if (Array.isArray(parsed)) {
// If parsed is an array of tables with Rows properties
allRows = parsed.flatMap(t => t.Rows ?? []);
} else if (parsed && Array.isArray(parsed.Rows)) {
allRows = parsed.Rows;
} else {
// fallback: if parsed itself is an array of row objects
allRows = Array.isArray(parsed) ? parsed : [];
}
if (!allRows || allRows.length === 0) {
this.gridData = [];
this.gridColumns = [];
this.gridColumnsForChart = [];
return;
}
// Use keys from first row as canonical columns
const keys = Object.keys(allRows[0]);
// Build gridColumns with safe field names and non-empty titles
this.gridColumns = keys.map(k => {
const safeKey = k.replace(/\s+/g, '_');
return {
field: safeKey,
title: (k && k.toString().trim()) ? k.toString() : safeKey,
editing: false
};
});
// Normalize each row: convert keys to safeKey, replace null/object with readable value
this.gridData = allRows.map(row => {
const normalized: any = {};
for (const k of keys) {
const safeKey = k.replace(/\s+/g, '_');
let val = row[k];
if (val === null || val === undefined || typeof val === 'object') {
normalized[safeKey] = '-';
} else {
normalized[safeKey] = val;
}
}
return normalized;
});
// Columns for chart control:
if (this.gridColumns && this.gridColumns.length > 0) {
this.gridColumnsForChart = this.gridColumns.map(col => ({ description: col.title, value: col.field }));
} else {
this.gridColumnsForChart = [];
}
} catch (e) {
console.error('Parse error in ProcessOpenAIData', e);
this.notificationService.showError("Failed to parse OpenAI response.", "Parse Error");
}
}
saveHeader(index: number) {
if (!this.gridColumns || !this.gridColumns[index]) { return; }
const col = this.gridColumns[index];
if (!col.title || col.title.toString().trim() === '') {
col.title = col.field;
}
col.editing = false;
delete col._oldTitle;
}
cancelHeader(index: number) {
if (!this.gridColumns || !this.gridColumns[index]) { return; }
const col = this.gridColumns[index];
if (col._oldTitle !== undefined) {
col.title = col._oldTitle;
}
col.editing = false;
delete col._oldTitle;
}
deleteColumn(index: number) {
const removed = this.gridColumns.splice(index, 1)[0];
this.deletedColumns.push({ ...removed, index });
}
scrollDeleted(direction: number) {
if (this.deletedContainer && this.deletedContainer.nativeElement) {
const el = this.deletedContainer.nativeElement;
const scrollAmount = 150;
el.scrollBy({ left: direction * scrollAmount, behavior: 'smooth' });
}
}
startEdit(index: number) {
if (!this.gridColumns || !this.gridColumns[index]) { return; }
const col = this.gridColumns[index];
col._oldTitle = col.title;
col.editing = true;
setTimeout(() => {
const selector = `.header-container[data-col-index="${index}"] .header-input`;
const el = document.querySelector(selector) as HTMLInputElement | null;
if (el) {
el.focus();
}
}, 0);
}
restoreColumn(idx: number) {
const col = this.deletedColumns.splice(idx, 1)[0];
this.gridColumns.splice(col.index, 0, col);
}
onHeaderBlur(index: number) {
this.saveHeader(index);
}
openAvailableInfoDialog(){
this.isShowAvailableInfo = true;
}
onReportGroupChange(group : any){
this.isUserPromptIsNotRelated = false;
this.invalidQueryMessage = "The AI can provide information when you ask about HR."
if(this.selectedReportGroup &&
(this.selectedReportGroup === EnumReportGroupType.Employee
|| this.selectedReportGroup === EnumReportGroupType.Salary
|| this.selectedReportGroup === EnumReportGroupType.Performance
|| this.selectedReportGroup === EnumReportGroupType.Training
|| this.selectedReportGroup === EnumReportGroupType.Attendance
|| this.selectedReportGroup === EnumReportGroupType.Leave)){
this.loadingpanelService.ShowLoadingPanel = true;
this.reportColumnDefinition = [];
this.tableColumnDefinition = [];
this.opeAiService.GetReportColumnDefinition(this.selectedReportGroup).subscribe(
(resp: any) => {
this.reportColumnDefinition = resp as any[];
},
(err: any) => {
this.loadingpanelService.ShowLoadingPanel = false;
this.notificationService.showError(err.error, "Error");
},
() => {
this.loadingpanelService.ShowLoadingPanel = false;
this.gridData = [];
if (this.reportColumnDefinition && this.reportColumnDefinition.length > 0) {
const excludedNormalizedCaptions = new Set(['employeeid']);
const excludedNormalizedCaptionsSalaryMonthlyID = new Set(['salarymonthlyid']);
const groupedMap = new Map<string, ReportColumnDefinition>();
this.reportColumnDefinition.forEach(item => {
const normalized = this.normalizeCaption(item.caption);
if (!excludedNormalizedCaptions.has(normalized) && !excludedNormalizedCaptionsSalaryMonthlyID.has(normalized)) {
const rawTableName = item.tablename || '';
const cleanedTableName = rawTableName.startsWith('vw') ? rawTableName.substring(2) : rawTableName;
if (!groupedMap.has(cleanedTableName)) {
groupedMap.set(cleanedTableName, {
tableName: cleanedTableName,
fields: []
});
}
groupedMap.get(cleanedTableName)!.fields.push(item.caption);
}
});
this.tableColumnDefinition = Array.from(groupedMap.values());
}
this.LoadCurrentUserAllQueryLog(this.selectedReportGroup);
});
}
}
normalizeCaption(caption: string): string {
return caption.replace(/\s+/g, '').toLowerCase().trim();
}
OpenAIPreviousQueryExecution(id : number){
this.isUserPromptIsNotRelated = false;
this.invalidQueryMessage = "No data returned from AI."
if(id && id > 0){
let oQueryLog : OpenAIQueryLog = this.currentUserAllQueryLog.find(x => x.id === id) ?? undefined;
if(oQueryLog != undefined){
this.isShowCurrentUserAllQueryLog = false
this.loadingpanelService.ShowLoadingPanel = true;
this.inputUserCommand = oQueryLog.userPrompt;
this.selectedReportGroup = oQueryLog.reportGroup;
if(oQueryLog.title && oQueryLog.title !== ""){
this.pdfFileName = `${oQueryLog.title}.pdf`;
this.excelFileName = `${oQueryLog.title}.xlsx`;
this.pngFilename = `${oQueryLog.title}_Chart.png`;
this.pdfFileNameForChart = `${oQueryLog.title}_Chart.pdf`;
}
else{
this.pdfFileName = 'FileData.pdf';
this.excelFileName = 'FileData.xlsx';
this.pngFilename = 'FileData_Chart.png';
this.pdfFileNameForChart = 'FileData_Chart.pdf';
}
const data = {
oQueryLog: oQueryLog
}
this.gridData = [];
this.gridColumns = [];
this.gridData = this.gridColumns = [];
this.OpenAIResponce = {};
this.isShowChart = false;
this.opeAiService.OpenAIPreviousQueryExecution(data).subscribe(
(resp: any) => {
this.OpenAIResponce = JSON.parse(resp);
},
(err: any) => {
this.isShowCurrentUserAllQueryLog = false
this.loadingpanelService.ShowLoadingPanel = false;
this.notificationService.showError(err.error, "Error");
},
() => {
this.isShowCurrentUserAllQueryLog = false
this.loadingpanelService.ShowLoadingPanel = false;
this.ProcessOpenAIData();
this.LoadCurrentUserAllQueryLog(this.selectedReportGroup);
});
}
else{
this.isShowCurrentUserAllQueryLog = false
}
}
else{
this.isShowCurrentUserAllQueryLog = false
}
}
ShowChart(){
this.isShowChartOption = true;
}
onChartGroupChange(group : any){
}
showOutOfScopeNotice() {
const msg = this.scopeMessages[this.selectedReportGroup] ?? "I can only help with questions related to this section.";
this.setInvalidQueryMessage(msg);
this.isUserPromptIsNotRelated = true;
}
filteredQueryLog(): OpenAIQueryLog[] {
if (!this.querySearchText) return this.currentUserAllQueryLog;
const search = this.querySearchText.toLowerCase();
return this.currentUserAllQueryLog.filter(item =>
item.userPrompt.toLowerCase().includes(search)
);
}
exportChartImage(chart: ChartComponent) {
this.chartTransitions = false;
setTimeout(() => {
chart.exportImage().then((dataURI: string) => {
saveAs(dataURI, this.pngFilename);
this.chartTransitions = true;
});
});
}
exportSizedChart(chart: ChartComponent): void {
const visual = chart.exportVisual({width: PAGE_RECT.size.width,});
this.exportElement(visual);
}
exportElement(element: Group): void {
exportPDF(element, {paperSize: "A4",margin: "1cm",}).then((dataURI) => {saveAs(dataURI, this.pdfFileNameForChart);});
}
private scopeMessages: Record<number, string> = {
[EnumReportGroupType.Employee]: "I can only help with questions related to Employee information.",
[EnumReportGroupType.Salary]: "I can only help with questions related to Employee Salary.",
[EnumReportGroupType.Performance]:"I can only help with questions related to Employee Performance.",
[EnumReportGroupType.Training]: "I can only help with questions related to Employee Training."
};
ShareThisChatWithOthers(queryLog : OpenAIQueryLog){
this.currentChat = undefined;
this.currentChat = queryLog;
this.ShareThisChat();
}
ShareThisChat(){
if(this.currentChat !== undefined){
this.currentChat.isCommon = !this.currentChat.isCommon;
const data = {
oQueryLog : this.currentChat
}
this.loadingpanelService.ShowLoadingPanel = true;
this.opeAiService.ChatShareWithOthers(data).subscribe(
(resp: any) => {
},
(err: any) => {
this.loadingpanelService.ShowLoadingPanel = false;
this.notificationService.showError(err.error, "Error");
},
() => {
this.loadingpanelService.ShowLoadingPanel = false;
this.LoadCurrentUserAllQueryLog(this.selectedReportGroup);
this.notificationService.showSuccess("Successfully Shared");
});
}
}
}
export class ReportColumnDefinition {
tableName: string;
fields: string[] = [];
}

View File

@ -0,0 +1,246 @@
"use strict";
var __esDecorate = (this && this.__esDecorate) || function (ctor, descriptorIn, decorators, contextIn, initializers, extraInitializers) {
function accept(f) { if (f !== void 0 && typeof f !== "function") throw new TypeError("Function expected"); return f; }
var kind = contextIn.kind, key = kind === "getter" ? "get" : kind === "setter" ? "set" : "value";
var target = !descriptorIn && ctor ? contextIn["static"] ? ctor : ctor.prototype : null;
var descriptor = descriptorIn || (target ? Object.getOwnPropertyDescriptor(target, contextIn.name) : {});
var _, done = false;
for (var i = decorators.length - 1; i >= 0; i--) {
var context = {};
for (var p in contextIn) context[p] = p === "access" ? {} : contextIn[p];
for (var p in contextIn.access) context.access[p] = contextIn.access[p];
context.addInitializer = function (f) { if (done) throw new TypeError("Cannot add initializers after decoration has completed"); extraInitializers.push(accept(f || null)); };
var result = (0, decorators[i])(kind === "accessor" ? { get: descriptor.get, set: descriptor.set } : descriptor[key], context);
if (kind === "accessor") {
if (result === void 0) continue;
if (result === null || typeof result !== "object") throw new TypeError("Object expected");
if (_ = accept(result.get)) descriptor.get = _;
if (_ = accept(result.set)) descriptor.set = _;
if (_ = accept(result.init)) initializers.unshift(_);
}
else if (_ = accept(result)) {
if (kind === "field") initializers.unshift(_);
else descriptor[key] = _;
}
}
if (target) Object.defineProperty(target, contextIn.name, descriptor);
done = true;
};
var __runInitializers = (this && this.__runInitializers) || function (thisArg, initializers, value) {
var useValue = arguments.length > 2;
for (var i = 0; i < initializers.length; i++) {
value = useValue ? initializers[i].call(thisArg, value) : initializers[i].call(thisArg);
}
return useValue ? value : void 0;
};
var __setFunctionName = (this && this.__setFunctionName) || function (f, name, prefix) {
if (typeof name === "symbol") name = name.description ? "[".concat(name.description, "]") : "";
return Object.defineProperty(f, "name", { configurable: true, value: prefix ? "".concat(prefix, " ", name) : name });
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.HRMOpenAIModule = void 0;
var core_1 = require("@angular/core");
var common_1 = require("@angular/common");
var Basic_From_Builder_module_1 = require("../form-builder/Basic-From-Builder.module");
var kendo_angular_grid_1 = require("@progress/kendo-angular-grid");
//import { BodyModule, SharedModule } from '@progress/kendo-angular-grid';
var kendo_angular_inputs_1 = require("@progress/kendo-angular-inputs");
var kendo_angular_charts_1 = require("@progress/kendo-angular-charts");
var kendo_angular_dialog_1 = require("@progress/kendo-angular-dialog");
var forms_1 = require("@angular/forms");
var kendo_angular_dropdowns_1 = require("@progress/kendo-angular-dropdowns");
var kendo_angular_dateinputs_1 = require("@progress/kendo-angular-dateinputs");
var kendo_angular_indicators_1 = require("@progress/kendo-angular-indicators");
var loading_panel_module_1 = require("../hrm-loding panel/loading-panel.module");
var loding_panel_service_1 = require("../hrm-loding panel/loding.panel.service");
var kendo_angular_buttons_1 = require("@progress/kendo-angular-buttons");
var inputtext_1 = require("primeng/inputtext");
var dialog_1 = require("primeng/dialog");
var scrollpanel_1 = require("primeng/scrollpanel");
var accordion_1 = require("primeng/accordion");
var autocomplete_1 = require("primeng/autocomplete");
var breadcrumb_1 = require("primeng/breadcrumb");
var calendar_1 = require("primeng/calendar");
var card_1 = require("primeng/card");
var carousel_1 = require("primeng/carousel");
var chart_1 = require("primeng/chart");
var checkbox_1 = require("primeng/checkbox");
var chips_1 = require("primeng/chips");
//import { CodeHighlighterModule } from 'primeng/codehighlighter';
var confirmdialog_1 = require("primeng/confirmdialog");
var colorpicker_1 = require("primeng/colorpicker");
var contextmenu_1 = require("primeng/contextmenu");
var dataview_1 = require("primeng/dataview");
var dropdown_1 = require("primeng/dropdown");
var editor_1 = require("primeng/editor");
var fieldset_1 = require("primeng/fieldset");
var fileupload_1 = require("primeng/fileupload");
//import { FullCalendarModule } from 'primeng/fullcalendar';
var galleria_1 = require("primeng/galleria");
var inplace_1 = require("primeng/inplace");
var inputmask_1 = require("primeng/inputmask");
var inputswitch_1 = require("primeng/inputswitch");
//import { InputTextareaModule } from 'primeng/inputtextarea';
//import { LightboxModule } from 'primeng/lightbox';
var listbox_1 = require("primeng/listbox");
var megamenu_1 = require("primeng/megamenu");
var menu_1 = require("primeng/menu");
var menubar_1 = require("primeng/menubar");
var messages_1 = require("primeng/messages");
var message_1 = require("primeng/message");
var multiselect_1 = require("primeng/multiselect");
var orderlist_1 = require("primeng/orderlist");
var organizationchart_1 = require("primeng/organizationchart");
var overlaypanel_1 = require("primeng/overlaypanel");
var paginator_1 = require("primeng/paginator");
var panel_1 = require("primeng/panel");
var panelmenu_1 = require("primeng/panelmenu");
var password_1 = require("primeng/password");
var picklist_1 = require("primeng/picklist");
var progressbar_1 = require("primeng/progressbar");
var radiobutton_1 = require("primeng/radiobutton");
var rating_1 = require("primeng/rating");
var selectbutton_1 = require("primeng/selectbutton");
//import { SlideMenuModule } from 'primeng/slidemenu';
var slider_1 = require("primeng/slider");
//import { SpinnerModule } from 'primeng/spinner';
var splitbutton_1 = require("primeng/splitbutton");
var steps_1 = require("primeng/steps");
var tabmenu_1 = require("primeng/tabmenu");
var table_1 = require("primeng/table");
var tabview_1 = require("primeng/tabview");
var terminal_1 = require("primeng/terminal");
var tieredmenu_1 = require("primeng/tieredmenu");
var toast_1 = require("primeng/toast");
var togglebutton_1 = require("primeng/togglebutton");
var toolbar_1 = require("primeng/toolbar");
var tooltip_1 = require("primeng/tooltip");
var tree_1 = require("primeng/tree");
var treetable_1 = require("primeng/treetable");
//import { VirtualScrollerModule } from 'primeng/virtualscroller';
var kendo_angular_layout_1 = require("@progress/kendo-angular-layout");
var ng2_pdf_viewer_1 = require("ng2-pdf-viewer");
var kendo_angular_layout_2 = require("@progress/kendo-angular-layout");
var kendo_angular_layout_3 = require("@progress/kendo-angular-layout");
var kendo_angular_progressbar_1 = require("@progress/kendo-angular-progressbar");
var app_notification_service_1 = require("../app.notification.service");
var picker_module_1 = require("../picker/picker.module");
;
var BackgroundCanvas_module_1 = require("../BackgroundCanvas/BackgroundCanvas.module");
var hrmopen_ai_routing_module_1 = require("./hrmopen-ai-routing.module");
var hrmopen_aiteast_component_1 = require("./hrmopen-ai-test/hrmopen-aiteast.component");
var hrmopen_ai_service_1 = require("../_services/HRMOpenAI/hrmopen-ai.service");
require("@progress/kendo-drawing");
var HRMOpenAIModule = function () {
var _classDecorators = [(0, core_1.NgModule)({
declarations: [hrmopen_aiteast_component_1.HRMOpenAITestComponent],
imports: [
common_1.CommonModule,
hrmopen_ai_routing_module_1.HRMOpenAIRoutingModule,
common_1.CommonModule,
forms_1.FormsModule,
forms_1.ReactiveFormsModule,
kendo_angular_dialog_1.DialogsModule,
kendo_angular_grid_1.GridModule,
kendo_angular_inputs_1.InputsModule,
kendo_angular_grid_1.PDFModule,
kendo_angular_grid_1.ExcelModule,
kendo_angular_charts_1.ChartsModule,
Basic_From_Builder_module_1.BasicFromBuilderModule,
kendo_angular_dropdowns_1.DropDownsModule,
kendo_angular_dateinputs_1.DateInputsModule,
kendo_angular_dateinputs_1.DateInputsModule,
picker_module_1.Pickermodule,
kendo_angular_indicators_1.IndicatorsModule,
loading_panel_module_1.LoadingPanelModule,
kendo_angular_buttons_1.ButtonModule,
inputtext_1.InputTextModule,
dialog_1.DialogModule,
scrollpanel_1.ScrollPanelModule,
ng2_pdf_viewer_1.PdfViewerModule,
autocomplete_1.AutoCompleteModule,
breadcrumb_1.BreadcrumbModule,
calendar_1.CalendarModule,
card_1.CardModule,
carousel_1.CarouselModule,
chart_1.ChartModule,
checkbox_1.CheckboxModule,
chips_1.ChipsModule,
confirmdialog_1.ConfirmDialogModule,
accordion_1.AccordionModule,
colorpicker_1.ColorPickerModule,
contextmenu_1.ContextMenuModule,
dataview_1.DataViewModule,
dropdown_1.DropdownModule,
editor_1.EditorModule,
fieldset_1.FieldsetModule,
fileupload_1.FileUploadModule,
galleria_1.GalleriaModule,
inplace_1.InplaceModule,
inputmask_1.InputMaskModule,
inputswitch_1.InputSwitchModule,
listbox_1.ListboxModule,
megamenu_1.MegaMenuModule,
menu_1.MenuModule,
menubar_1.MenubarModule,
messages_1.MessagesModule,
message_1.MessageModule,
multiselect_1.MultiSelectModule,
orderlist_1.OrderListModule,
organizationchart_1.OrganizationChartModule,
overlaypanel_1.OverlayPanelModule,
paginator_1.PaginatorModule,
panel_1.PanelModule,
panelmenu_1.PanelMenuModule,
password_1.PasswordModule,
picklist_1.PickListModule,
progressbar_1.ProgressBarModule,
radiobutton_1.RadioButtonModule,
rating_1.RatingModule,
selectbutton_1.SelectButtonModule,
kendo_angular_layout_1.CardModule,
treetable_1.TreeTableModule,
tree_1.TreeModule,
tooltip_1.TooltipModule,
toolbar_1.ToolbarModule,
togglebutton_1.ToggleButtonModule,
toast_1.ToastModule,
tieredmenu_1.TieredMenuModule,
terminal_1.TerminalModule,
tabview_1.TabViewModule,
table_1.TableModule,
tabmenu_1.TabMenuModule,
steps_1.StepsModule,
splitbutton_1.SplitButtonModule,
slider_1.SliderModule,
kendo_angular_layout_2.TabStripModule,
kendo_angular_layout_3.ExpansionPanelModule,
kendo_angular_progressbar_1.ProgressBarModule,
BackgroundCanvas_module_1.BackgroundCanvasModule
],
providers: [
loding_panel_service_1.loadingPanelService,
app_notification_service_1.HRMNotificationService,
hrmopen_ai_service_1.HRMOpenAIService
]
})];
var _classDescriptor;
var _classExtraInitializers = [];
var _classThis;
var HRMOpenAIModule = _classThis = /** @class */ (function () {
function HRMOpenAIModule_1() {
}
return HRMOpenAIModule_1;
}());
__setFunctionName(_classThis, "HRMOpenAIModule");
(function () {
var _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(null) : void 0;
__esDecorate(null, _classDescriptor = { value: _classThis }, _classDecorators, { kind: "class", name: _classThis.name, metadata: _metadata }, null, _classExtraInitializers);
HRMOpenAIModule = _classThis = _classDescriptor.value;
if (_metadata) Object.defineProperty(_classThis, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
__runInitializers(_classThis, _classExtraInitializers);
})();
return HRMOpenAIModule = _classThis;
}();
exports.HRMOpenAIModule = HRMOpenAIModule;
//# sourceMappingURL=hrmopen-ai.module.js.map

View File

@ -0,0 +1 @@
{"version":3,"file":"hrmopen-ai.module.js","sourceRoot":"","sources":["hrmopen-ai.module.ts"],"names":[],"mappings":"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"}

View File

@ -0,0 +1,197 @@
import { LMSService } from "./../_services/LearningManagement/lms.service";
import { NgModule } from "@angular/core";
import { CommonModule, DatePipe } from "@angular/common";
import { BasicFromBuilderModule } from "../form-builder/Basic-From-Builder.module";
import { ExcelModule, GridModule, PDFModule } from "@progress/kendo-angular-grid";
//import { BodyModule, SharedModule } from '@progress/kendo-angular-grid';
import { InputsModule } from "@progress/kendo-angular-inputs";
import { ChartsModule } from "@progress/kendo-angular-charts";
import { DialogsModule, WindowModule } from "@progress/kendo-angular-dialog";
import { FormsModule, ReactiveFormsModule } from "@angular/forms";
import { DropDownsModule } from "@progress/kendo-angular-dropdowns";
import { DateInputsModule } from "@progress/kendo-angular-dateinputs";
import { IndicatorsModule } from "@progress/kendo-angular-indicators";
import { LoadingPanelModule } from "../hrm-loding panel/loading-panel.module";
import { loadingPanelService } from "../hrm-loding panel/loding.panel.service";
import { AttendanceServices } from "../_services/attendance/attendance.service";
import { ButtonModule } from "@progress/kendo-angular-buttons";
import { InputTextModule } from "primeng/inputtext";
import { DialogModule } from "primeng/dialog";
import { ScrollPanelModule } from "primeng/scrollpanel";
import { HttpClient } from "@angular/common/http";
import { AccordionModule } from "primeng/accordion";
import { AutoCompleteModule } from "primeng/autocomplete";
import { BreadcrumbModule } from "primeng/breadcrumb";
import { CalendarModule } from "primeng/calendar";
import { CardModule } from "primeng/card";
import { CarouselModule } from "primeng/carousel";
import { ChartModule } from "primeng/chart";
import { CheckboxModule } from "primeng/checkbox";
import { ChipsModule } from "primeng/chips";
//import { CodeHighlighterModule } from 'primeng/codehighlighter';
import { ConfirmDialogModule } from "primeng/confirmdialog";
import { ColorPickerModule } from "primeng/colorpicker";
import { ContextMenuModule } from "primeng/contextmenu";
import { DataViewModule } from "primeng/dataview";
import { DropdownModule } from "primeng/dropdown";
import { EditorModule } from "primeng/editor";
import { FieldsetModule } from "primeng/fieldset";
import { FileUploadModule } from "primeng/fileupload";
//import { FullCalendarModule } from 'primeng/fullcalendar';
import { GalleriaModule } from "primeng/galleria";
import { InplaceModule } from "primeng/inplace";
import { InputMaskModule } from "primeng/inputmask";
import { InputSwitchModule } from "primeng/inputswitch";
//import { InputTextareaModule } from 'primeng/inputtextarea';
//import { LightboxModule } from 'primeng/lightbox';
import { ListboxModule } from "primeng/listbox";
import { MegaMenuModule } from "primeng/megamenu";
import { MenuModule } from "primeng/menu";
import { MenubarModule } from "primeng/menubar";
import { MessagesModule } from "primeng/messages";
import { MessageModule } from "primeng/message";
import { MultiSelectModule } from "primeng/multiselect";
import { OrderListModule } from "primeng/orderlist";
import { OrganizationChartModule } from "primeng/organizationchart";
import { OverlayPanelModule } from "primeng/overlaypanel";
import { PaginatorModule } from "primeng/paginator";
import { PanelModule } from "primeng/panel";
import { PanelMenuModule } from "primeng/panelmenu";
import { PasswordModule } from "primeng/password";
import { PickListModule } from "primeng/picklist";
import { ProgressBarModule } from "primeng/progressbar";
import { RadioButtonModule } from "primeng/radiobutton";
import { RatingModule } from "primeng/rating";
import { SelectButtonModule } from "primeng/selectbutton";
//import { SlideMenuModule } from 'primeng/slidemenu';
import { SliderModule } from "primeng/slider";
//import { SpinnerModule } from 'primeng/spinner';
import { SplitButtonModule } from "primeng/splitbutton";
import { StepsModule } from "primeng/steps";
import { TabMenuModule } from "primeng/tabmenu";
import { TableModule } from "primeng/table";
import { TabViewModule } from "primeng/tabview";
import { TerminalModule } from "primeng/terminal";
import { TieredMenuModule } from "primeng/tieredmenu";
import { ToastModule } from "primeng/toast";
import { ToggleButtonModule } from "primeng/togglebutton";
import { ToolbarModule } from "primeng/toolbar";
import { TooltipModule } from "primeng/tooltip";
import { TreeModule } from "primeng/tree";
import { TreeTableModule } from "primeng/treetable";
//import { VirtualScrollerModule } from 'primeng/virtualscroller';
import { CardModule as kendoCardModule } from "@progress/kendo-angular-layout";
import { AppWindowPopUp } from "../app.windowPopup.service";
import { PdfViewerModule } from "ng2-pdf-viewer";
import { TabStripModule } from "@progress/kendo-angular-layout";
import { ExpansionPanelModule } from "@progress/kendo-angular-layout";
import { BrowserModule } from "@angular/platform-browser";
import { BrowserAnimationsModule } from "@angular/platform-browser/animations";
import { ProgressBarModule as KendoProgressBarModule } from "@progress/kendo-angular-progressbar";
import { DropDownListModule } from "@progress/kendo-angular-dropdowns";
import { HRMNotificationService } from "../app.notification.service";
import { LeaveService } from "../_services/leave/leave.service";
import { Pickermodule } from "../picker/picker.module";
import { BasicService } from "../_services/Basic/basic.service";
import { PaymentApprovalService } from "../_services/payment-approval/payment-approval.service";
import { SalaryService } from "../_services/payroll/salary.service";
import { UntilityHandlerService } from "../utility.hanldler.service";
import { EmpLifeCycleServices } from "../_services/employee/empLifeCycle.service";
import { BackgroundCanvasModule } from "../BackgroundCanvas/BackgroundCanvas.module";
import { HRMOpenAIRoutingModule } from "./hrmopen-ai-routing.module";
import { HRMOpenAITestComponent } from "./hrmopen-ai-test/hrmopen-aiteast.component";
import { HRMOpenAIService } from "../_services/HRMOpenAI/hrmopen-ai.service";
import "@progress/kendo-drawing";
@NgModule({
declarations: [HRMOpenAITestComponent],
imports: [
CommonModule,
FormsModule,
ReactiveFormsModule,
DialogsModule,
GridModule,
InputsModule,
PDFModule,
ExcelModule,
ChartsModule,
BasicFromBuilderModule,
DropDownsModule,
DateInputsModule,
DateInputsModule,
Pickermodule,
IndicatorsModule,
LoadingPanelModule,
ButtonModule,
InputTextModule,
DialogModule,
ScrollPanelModule,
PdfViewerModule,
AutoCompleteModule,
BreadcrumbModule,
CalendarModule,
CardModule,
CarouselModule,
ChartModule,
CheckboxModule,
ChipsModule,
ConfirmDialogModule,
AccordionModule,
ColorPickerModule,
ContextMenuModule,
DataViewModule,
DropdownModule,
EditorModule,
FieldsetModule,
FileUploadModule,
GalleriaModule,
InplaceModule,
InputMaskModule,
InputSwitchModule,
ListboxModule,
MegaMenuModule,
MenuModule,
MenubarModule,
MessagesModule,
MessageModule,
MultiSelectModule,
OrderListModule,
OrganizationChartModule,
OverlayPanelModule,
PaginatorModule,
PanelModule,
PanelMenuModule,
PasswordModule,
PickListModule,
ProgressBarModule,
RadioButtonModule,
RatingModule,
SelectButtonModule,
kendoCardModule,
TreeTableModule,
TreeModule,
TooltipModule,
ToolbarModule,
ToggleButtonModule,
ToastModule,
TieredMenuModule,
TerminalModule,
TabViewModule,
TableModule,
TabMenuModule,
StepsModule,
SplitButtonModule,
SliderModule,
TabStripModule,
ExpansionPanelModule,
KendoProgressBarModule,
BackgroundCanvasModule,
HRMOpenAIRoutingModule
],
providers: [loadingPanelService, HRMNotificationService, HRMOpenAIService],
})
export class HRMOpenAIModule {}

View File

@ -156,7 +156,6 @@
<Menu key="7.1.7.4" name="Multiple Employee Leave Ledger" url="/reports/report-viewer/102" parentkey="7.1.7" <Menu key="7.1.7.4" name="Multiple Employee Leave Ledger" url="/reports/report-viewer/102" parentkey="7.1.7"
action="add;edit;delete" RoleType="Admin"></Menu> action="add;edit;delete" RoleType="Admin"></Menu>
<Menu key="5" name="Attendance" url="" parentkey="" action="add;edit;delete" RoleType="Admin"></Menu> <Menu key="5" name="Attendance" url="" parentkey="" action="add;edit;delete" RoleType="Admin"></Menu>
<Menu key="5.1" name="Master Data" url="" parentkey="5" action="add;edit;delete" RoleType="Admin"></Menu> <Menu key="5.1" name="Master Data" url="" parentkey="5" action="add;edit;delete" RoleType="Admin"></Menu>
<Menu key="5.1.1" name="Shift" url="/attendance/shift" parentkey="5.1" action="add;edit;delete" <Menu key="5.1.1" name="Shift" url="/attendance/shift" parentkey="5.1" action="add;edit;delete"

View File

@ -318,6 +318,10 @@ namespace HRM.UI.Configuration.DI
services.AddTransient<IMembersTransactionDetailsService, MembersTransactionDetailsService>(); services.AddTransient<IMembersTransactionDetailsService, MembersTransactionDetailsService>();
services.AddTransient<IEmployeeTaxExcecptionService, EmployeeTaxExceptionService>(); services.AddTransient<IEmployeeTaxExcecptionService, EmployeeTaxExceptionService>();
//OpenAI
services.AddTransient<IOpenAIQueryLogService, OpenAIQueryLogService>();
// services.AddTransient<IDataIntergrationRequestService, DataIntergrationRequestService>(); // services.AddTransient<IDataIntergrationRequestService, DataIntergrationRequestService>();
} }

View File

@ -0,0 +1,131 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Configuration;
using System.Data;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Net.Http.Headers;
using System.Text;
using System.Threading.Tasks;
using AutoMapper.Configuration;
using Ease.Core;
using HRM.BO;
using HRM.DA;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.StaticFiles;
using Microsoft.Extensions.Configuration;
using Payroll.BO;
using Payroll.Service;
using IConfiguration = Microsoft.Extensions.Configuration.IConfiguration;
namespace HRM.UI.Controllers
{
[ApiController]
[Route("api/HRMApenAPIAI")]
[Authorize]
public class OpenAIController : ControllerBase
{
private readonly OpenAIService _openAIService;
private readonly IOpenAIQueryLogService _openAIQueryLogService;
public OpenAIController(OpenAIService openAIService, IOpenAIQueryLogService openAIQueryLogService)
{
_openAIService = openAIService;
_openAIQueryLogService = openAIQueryLogService;
}
[HttpPost]
[Route("AskOpenAI")]
public async Task<IActionResult> AskOpenAI(dynamic data)
{
CurrentUser currentUser = CurrentUser.GetCurrentUser(HttpContext.User);
var item = Newtonsoft.Json.JsonConvert.DeserializeObject(Convert.ToString(data));
string userCommand = (string)item["userPrompt"].ToObject<string>();
EnumReportGroupType reportGroupType = (EnumReportGroupType)item["reportGroup"].ToObject<EnumReportGroupType>();
DataSet oEmpBasicInfos = new DataSet();
try
{
var response = await _openAIService.AskOpenAISqlQueryWithChartAsync(userCommand, (int)currentUser.UserID, reportGroupType,
currentUser.NextPayProcessDate ?? DateTime.Now);
return Ok(response);
}
catch (Exception ex)
{
return StatusCode(StatusCodes.Status500InternalServerError, ex.Message);
}
}
[HttpGet]
[Route("GetReportColumnDefinition/{reportGroupType}")]
public async Task<IActionResult> GetReportColumnDefinition(EnumReportGroupType reportGroupType)
{
CurrentUser currentUser = CurrentUser.GetCurrentUser(HttpContext.User);
try
{
var response = await _openAIService.GetColumnDefinitions(reportGroupType);
return Ok(response);
}
catch (Exception ex)
{
return StatusCode(StatusCodes.Status500InternalServerError, ex.Message);
}
}
[HttpGet]
[Route("GetCurrentUserAllQueryLog/{reportGroupType}")]
public ActionResult GetCurrentUserAllQueryLog(EnumReportGroupType reportGroupType)
{
CurrentUser currentUser = CurrentUser.GetCurrentUser(HttpContext.User);
List<OpenAIQueryLog> queryLogs = new List<OpenAIQueryLog>();
try
{
queryLogs = _openAIQueryLogService.GetAllQueryLogByUserID((int)currentUser.UserID, reportGroupType);
}
catch (Exception ex)
{
return StatusCode(StatusCodes.Status500InternalServerError, ex.Message);
}
return Ok(queryLogs);
}
[HttpPost]
[Route("OpenAIPreviousQueryExecution")]
public async Task<IActionResult> OpenAIPreviousQueryExecution(dynamic data)
{
var item = Newtonsoft.Json.JsonConvert.DeserializeObject(Convert.ToString(data));
OpenAIQueryLog userCommand = (OpenAIQueryLog)item["oQueryLog"].ToObject<OpenAIQueryLog>();
try
{
var response = await _openAIService.OpenAIPreviousQueryExecution(userCommand);
return Ok(response);
}
catch (Exception ex)
{
return StatusCode(StatusCodes.Status500InternalServerError, ex.Message);
}
}
[HttpPost]
[Route("ChatShareWithOthers")]
public async Task<IActionResult> ChatShareWithOthers(dynamic data)
{
var item = Newtonsoft.Json.JsonConvert.DeserializeObject(Convert.ToString(data));
OpenAIQueryLog userCommand = (OpenAIQueryLog)item["oQueryLog"].ToObject<OpenAIQueryLog>();
try
{
_openAIQueryLogService.ChatShareWithOthers(userCommand);
return Ok();
}
catch (Exception ex)
{
return StatusCode(StatusCodes.Status500InternalServerError, ex.Message);
}
}
}
}

View File

@ -202,6 +202,18 @@ namespace HRM.UI.Api
#endregion #endregion
#region AI Integration (OpenAI)
services.AddSingleton<OpenAIService>(provider =>
{
var config = provider.GetRequiredService<IConfiguration>();
var encryptedkey = config["OpenAI:ApiKey"];
var model = config["OpenAI:Model"];
int maxLimit = 5000;
return new OpenAIService(encryptedkey, model, maxLimit);
});
#endregion
#region Business Service #region Business Service
services.ConfigureBusinessServices(Configuration); services.ConfigureBusinessServices(Configuration);