-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathChartsAIService.cs
More file actions
225 lines (195 loc) · 7.87 KB
/
ChartsAIService.cs
File metadata and controls
225 lines (195 loc) · 7.87 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
using Azure;
using Azure.AI.OpenAI;
using ChartGenerator.AIService;
using Microsoft.Extensions.AI;
namespace ChartGenerator
{
internal class ChartAIService : AICredentials
{
#region Fields
/// <summary>
/// The uri result field
/// </summary>
private Uri? uriResult;
#endregion
public ChartAIService()
{
ValidateCredential();
}
#region Properties
internal IChatClient? Client { get; set; }
internal string? ChatHistory { get; set; }
internal static bool IsCredentialValid { get; set; }
#endregion
#region Private Methods
/// <summary>
/// Validate Azure Credentials
/// </summary>
private async void ValidateCredential()
{
this.GetAzureOpenAIKernal();
try
{
if (Client != null)
{
await Client!.CompleteAsync("Hello, Test Check");
ChatHistory = string.Empty;
IsCredentialValid = true;
}
else
{
ShowAlertAsync();
}
}
catch (Exception)
{
return;
}
}
#region Azure OpenAI
/// <summary>
/// To get the Azure open ai kernal method
/// </summary>
private void GetAzureOpenAIKernal()
{
try
{
var client = new AzureOpenAIClient(new Uri(endpoint), new AzureKeyCredential(key)).AsChatClient(modelId: deploymentName);
this.Client = client;
}
catch (Exception)
{
}
}
#endregion
/// <summary>
/// Retrieves an answer from the deployment name model using the provided user prompt.
/// </summary>
/// <param name="userPrompt">The user prompt.</param>
/// <param name="includeClassContext">Whether to include class structure context.</param>
/// <returns>The AI response.</returns>
internal async Task<string> GetAnswerFromGPT(string userPrompt, bool includeClassContext = false)
{
try
{
if (IsCredentialValid && Client != null)
{
ChatHistory = string.Empty;
// Only include class context if specifically requested
if (includeClassContext)
{
var classContext = GetChartClassStructureContext();
ChatHistory = classContext + "\n\n" + userPrompt;
}
else
{
ChatHistory = userPrompt;
}
var response = await Client.CompleteAsync(ChatHistory);
return response.ToString();
}
}
catch
{
// If an exception occurs (e.g., network issues, API errors), return an empty string.
return "";
}
return "";
}
/// <summary>
/// Show Alert Popup
/// </summary>
private async void ShowAlertAsync()
{
var page = Application.Current?.Windows[0].Page;
if (page != null && !IsCredentialValid)
{
await page.DisplayAlert("Alert", "The Azure API key or endpoint is missing or incorrect. Please verify your credentials. You can also continue with the offline data.", "OK");
}
}
/// <summary>
/// Creates a concise context string that explains the structure of chart-related classes
/// </summary>
/// <returns>A string containing class structure information</returns>
private string GetChartClassStructureContext()
{
return @"
Chart class model reference:
ChartConfig{ChartType:enum, Title:string, Series:Collection<SeriesConfig>, XAxis/YAxis:Collection<AxisConfig>, ShowLegend:bool, SideBySidePlacement:bool}
SeriesConfig{Type:enum, Name:string, DataSource:Collection<DataModel>, Tooltip:bool}
AxisConfig{Title:string, Type:string('Numerical'|'DateTime'|'Category'|'Logarithmic'), Minimum/Maximum:double?}";
}
/// <summary>
/// Gets specific context about a particular chart class based on need
/// </summary>
/// <param name="classType">The class type to get context for ("ChartConfig", "SeriesConfig", or "AxisConfig")</param>
/// <returns>Specific context about the requested class</returns>
internal string GetSpecificClassContext(string classType)
{
return classType.ToLower() switch
{
"chartconfig" => "ChartConfig: Controls overall chart appearance with properties for chart type, title, axis collections, series data, and display options like legends.",
"seriesconfig" => "SeriesConfig: Defines a data series with properties for series type, name, data source collection, and tooltip visibility.",
"axisconfig" => "AxisConfig: Configures chart axes with title, axis type (Numerical, DateTime, Category, Logarithmic), and optional min/max range values.",
_ => "Unknown class type. Available classes: ChartConfig, SeriesConfig, AxisConfig"
};
}
internal async Task<string> AnalyzeImageAzureAsync(ImageSource source, string textInput)
{
byte[] imageBytes = await ConvertImageSourceToByteArray(source);
// Convert the byte array to a Base64 string
return await InterpretImageBase64(Convert.ToBase64String(imageBytes), textInput);
}
public static async Task<byte[]> ConvertImageSourceToByteArray(ImageSource imageSource)
{
Stream stream = await ConvertImageSourceToStream(imageSource);
using (MemoryStream memoryStream = new MemoryStream())
{
stream.CopyTo(memoryStream);
return memoryStream.ToArray();
}
}
private static async Task<Stream> ConvertImageSourceToStream(ImageSource imageSource)
{
if (imageSource is FileImageSource fileImageSource)
{
return new FileStream(fileImageSource.File, FileMode.Open, FileAccess.Read);
}
else if (imageSource is UriImageSource uriImageSource)
{
var httpClient = new System.Net.Http.HttpClient();
return await httpClient.GetStreamAsync(uriImageSource.Uri);
}
else if (imageSource is StreamImageSource streamImageSource)
{
return await streamImageSource.Stream(default);
}
else
{
throw new NotSupportedException("Unsupported ImageSource type");
}
}
internal async Task<string> InterpretImageBase64(string base64, string textInput)
{
try
{
var imageDataUri = $"data:image/jpeg;base64,{base64}";
var chatHistory = new Microsoft.Extensions.AI.ChatMessage();
chatHistory.Text = "You are an AI assistant that describes images.";
chatHistory.Contents = (new List<AIContent>
{
new TextContent("Describe this image:"),
new TextContent($"{textInput}"),
new ImageContent(imageDataUri)
});
var result = await Client.CompleteAsync(new[] { chatHistory });
return result?.ToString() ?? "No description generated.";
}
catch (Exception ex)
{
return $"Error generating OpenAI response: {ex.Message}";
}
}
}
#endregion
}