mirror of
				https://github.com/gnh1201/welsonjs.git
				synced 2025-10-30 20:41:18 +00:00 
			
		
		
		
	Add support the Azure AI, Optimize the HTTPClient object uses.
This commit is contained in:
		
							parent
							
								
									b26d979b8d
								
							
						
					
					
						commit
						5b2863058a
					
				|  | @ -70,11 +70,20 @@ namespace WelsonJS.Launcher.Properties { | ||||||
|         } |         } | ||||||
|          |          | ||||||
|         /// <summary> |         /// <summary> | ||||||
|         ///   https://ai-catswords656881030318.services.ai.azure.com/models/chat/completions?api-version=2024-05-01-preview과(와) 유사한 지역화된 문자열을 찾습니다. |         ///   2024-05-01-preview과(와) 유사한 지역화된 문자열을 찾습니다. | ||||||
|         /// </summary> |         /// </summary> | ||||||
|         internal static string AzureAiServiceUrl { |         internal static string AzureAiServiceApiVersion { | ||||||
|             get { |             get { | ||||||
|                 return ResourceManager.GetString("AzureAiServiceUrl", resourceCulture); |                 return ResourceManager.GetString("AzureAiServiceApiVersion", resourceCulture); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |          | ||||||
|  |         /// <summary> | ||||||
|  |         ///   https://ai-catswords656881030318.services.ai.azure.com/과(와) 유사한 지역화된 문자열을 찾습니다. | ||||||
|  |         /// </summary> | ||||||
|  |         internal static string AzureAiServicePrefix { | ||||||
|  |             get { | ||||||
|  |                 return ResourceManager.GetString("AzureAiServicePrefix", resourceCulture); | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|          |          | ||||||
|  |  | ||||||
|  | @ -163,8 +163,8 @@ | ||||||
|   <data name="AzureAiServiceApiKey" xml:space="preserve"> |   <data name="AzureAiServiceApiKey" xml:space="preserve"> | ||||||
|     <value /> |     <value /> | ||||||
|   </data> |   </data> | ||||||
|   <data name="AzureAiServiceUrl" xml:space="preserve"> |   <data name="AzureAiServicePrefix" xml:space="preserve"> | ||||||
|     <value>https://ai-catswords656881030318.services.ai.azure.com/models/chat/completions?api-version=2024-05-01-preview</value> |     <value>https://ai-catswords656881030318.services.ai.azure.com/</value> | ||||||
|   </data> |   </data> | ||||||
|   <data name="DnsServerAddress" xml:space="preserve"> |   <data name="DnsServerAddress" xml:space="preserve"> | ||||||
|     <value>1.1.1.1</value> |     <value>1.1.1.1</value> | ||||||
|  | @ -181,4 +181,7 @@ | ||||||
|   <data name="BlobServerPrefix" xml:space="preserve"> |   <data name="BlobServerPrefix" xml:space="preserve"> | ||||||
|     <value>https://catswords.blob.core.windows.net/welsonjs/</value> |     <value>https://catswords.blob.core.windows.net/welsonjs/</value> | ||||||
|   </data> |   </data> | ||||||
|  |   <data name="AzureAiServiceApiVersion" xml:space="preserve"> | ||||||
|  |     <value>2024-05-01-preview</value> | ||||||
|  |   </data> | ||||||
| </root> | </root> | ||||||
|  | @ -23,8 +23,8 @@ namespace WelsonJS.Launcher | ||||||
|         private string _prefix; |         private string _prefix; | ||||||
|         private string _resourceName; |         private string _resourceName; | ||||||
|         private List<IResourceTool> _tools = new List<IResourceTool>(); |         private List<IResourceTool> _tools = new List<IResourceTool>(); | ||||||
|         private const int _blobTimeout = 5000; |         private const int _httpClientTimeout = 5000; | ||||||
|         private readonly HttpClient _blobClient = new HttpClient(); |         private readonly HttpClient _httpClient = new HttpClient(); | ||||||
|         private readonly string _defaultMimeType = "application/octet-stream"; |         private readonly string _defaultMimeType = "application/octet-stream"; | ||||||
| 
 | 
 | ||||||
|         public ResourceServer(string prefix, string resourceName) |         public ResourceServer(string prefix, string resourceName) | ||||||
|  | @ -33,15 +33,15 @@ namespace WelsonJS.Launcher | ||||||
|             _listener = new HttpListener(); |             _listener = new HttpListener(); | ||||||
|             _listener.Prefixes.Add(prefix); |             _listener.Prefixes.Add(prefix); | ||||||
|             _resourceName = resourceName; |             _resourceName = resourceName; | ||||||
|             _blobClient.Timeout = TimeSpan.FromMilliseconds(_blobTimeout); |             _httpClient.Timeout = TimeSpan.FromMilliseconds(_httpClientTimeout); | ||||||
| 
 | 
 | ||||||
|             // Add resource tools |             // Add resource tools | ||||||
|             _tools.Add(new ResourceTools.Completion(this)); |             _tools.Add(new ResourceTools.Completion(this, _httpClient)); | ||||||
|             _tools.Add(new ResourceTools.Config(this)); |             _tools.Add(new ResourceTools.Settings(this, _httpClient)); | ||||||
|             _tools.Add(new ResourceTools.DevTools(this)); |             _tools.Add(new ResourceTools.DevTools(this, _httpClient)); | ||||||
|             _tools.Add(new ResourceTools.DnsQuery(this)); |             _tools.Add(new ResourceTools.DnsQuery(this, _httpClient)); | ||||||
|             _tools.Add(new ResourceTools.Tfa(this)); |             _tools.Add(new ResourceTools.Tfa(this, _httpClient)); | ||||||
|             _tools.Add(new ResourceTools.Whois(this)); |             _tools.Add(new ResourceTools.Whois(this, _httpClient)); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         public string GetPrefix() |         public string GetPrefix() | ||||||
|  | @ -158,7 +158,7 @@ namespace WelsonJS.Launcher | ||||||
| 
 | 
 | ||||||
|                 HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, url); |                 HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, url); | ||||||
|                 request.Headers.UserAgent.ParseAdd(context.Request.UserAgent); |                 request.Headers.UserAgent.ParseAdd(context.Request.UserAgent); | ||||||
|                 HttpResponseMessage response = await _blobClient.SendAsync(request); |                 HttpResponseMessage response = await _httpClient.SendAsync(request); | ||||||
| 
 | 
 | ||||||
|                 if (!response.IsSuccessStatusCode) |                 if (!response.IsSuccessStatusCode) | ||||||
|                 { |                 { | ||||||
|  |  | ||||||
|  | @ -1,139 +0,0 @@ | ||||||
| using System; |  | ||||||
| using System.IO; |  | ||||||
| using System.Net; |  | ||||||
| using System.Net.Http; |  | ||||||
| using System.Text; |  | ||||||
| using System.Threading.Tasks; |  | ||||||
| 
 |  | ||||||
| namespace WelsonJS.Launcher.ResourceTools |  | ||||||
| { |  | ||||||
|     public class AzureAi : IResourceTool |  | ||||||
|     { |  | ||||||
|         private ResourceServer Server; |  | ||||||
|         private const string Prefix = "azure-ai/"; |  | ||||||
|         private const int ChunkSize = 4096; |  | ||||||
|         private readonly string AzureAiServiceUrl; |  | ||||||
|         private readonly string AzureAiServiceApiKey; |  | ||||||
| 
 |  | ||||||
|         public AzureAi(ResourceServer server) |  | ||||||
|         { |  | ||||||
|             Server = server; |  | ||||||
| 
 |  | ||||||
|             AzureAiServiceUrl = Program.GetAppConfig("AzureAiServiceUrl"); |  | ||||||
|             AzureAiServiceApiKey = Program.GetAppConfig("AzureAiServiceApiKey"); |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         public bool CanHandle(string path) |  | ||||||
|         { |  | ||||||
|             return path.StartsWith(Prefix, StringComparison.OrdinalIgnoreCase); |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         public async Task HandleAsync(HttpListenerContext context, string path) |  | ||||||
|         { |  | ||||||
|             string apiKey = AzureAiServiceApiKey; |  | ||||||
|             if (string.IsNullOrEmpty(apiKey)) |  | ||||||
|             { |  | ||||||
|                 WriteError(context, "Missing the API key.", HttpStatusCode.BadRequest); |  | ||||||
|                 return; |  | ||||||
|             } |  | ||||||
| 
 |  | ||||||
|             string requestBody = ReadRequestBody(context); |  | ||||||
|             bool isStreaming = ContainsSequentialKeywords(requestBody, new[] { "\"stream\"", "true" }, 30); |  | ||||||
| 
 |  | ||||||
|             try |  | ||||||
|             { |  | ||||||
|                 using (var response = await SendAzureRequestAsync(apiKey, requestBody, isStreaming)) |  | ||||||
|                 { |  | ||||||
|                     await ForwardResponseAsync(context, response, isStreaming); |  | ||||||
|                 } |  | ||||||
|             } |  | ||||||
|             catch (HttpRequestException ex) |  | ||||||
|             { |  | ||||||
|                 WriteError(context, "Request error: " + ex.Message, HttpStatusCode.BadGateway); |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         private string ReadRequestBody(HttpListenerContext context) |  | ||||||
|         { |  | ||||||
|             using (var reader = new StreamReader(context.Request.InputStream, context.Request.ContentEncoding)) |  | ||||||
|             { |  | ||||||
|                 return reader.ReadToEnd(); |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         private async Task<HttpResponseMessage> SendAzureRequestAsync(string apiKey, string requestBody, bool isStreaming) |  | ||||||
|         { |  | ||||||
|             using (var client = new HttpClient()) |  | ||||||
|             { |  | ||||||
|                 var requestMessage = new HttpRequestMessage(HttpMethod.Post, AzureAiServiceUrl); |  | ||||||
|                 requestMessage.Headers.Add("api-key", apiKey); |  | ||||||
|                 requestMessage.Content = new StringContent(requestBody, Encoding.UTF8, "application/json"); |  | ||||||
| 
 |  | ||||||
|                 var completionOption = isStreaming |  | ||||||
|                     ? HttpCompletionOption.ResponseHeadersRead |  | ||||||
|                     : HttpCompletionOption.ResponseContentRead; |  | ||||||
| 
 |  | ||||||
|                 return await client.SendAsync(requestMessage, completionOption); |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         private async Task ForwardResponseAsync(HttpListenerContext context, HttpResponseMessage response, bool isStreaming) |  | ||||||
|         { |  | ||||||
|             context.Response.StatusCode = (int)response.StatusCode; |  | ||||||
|             context.Response.ContentType = response.Content.Headers.ContentType?.ToString() ?? "application/json"; |  | ||||||
| 
 |  | ||||||
|             using (var responseStream = await response.Content.ReadAsStreamAsync()) |  | ||||||
|             { |  | ||||||
|                 if (isStreaming) |  | ||||||
|                 { |  | ||||||
|                     context.Response.SendChunked = true; |  | ||||||
|                     context.Response.Headers.Add("Transfer-Encoding", "chunked"); |  | ||||||
|                     context.Response.Headers.Add("Cache-Control", "no-cache"); |  | ||||||
| 
 |  | ||||||
|                     byte[] buffer = new byte[ChunkSize]; |  | ||||||
|                     int bytesRead; |  | ||||||
|                     while ((bytesRead = await responseStream.ReadAsync(buffer, 0, buffer.Length)) > 0) |  | ||||||
|                     { |  | ||||||
|                         await context.Response.OutputStream.WriteAsync(buffer, 0, bytesRead); |  | ||||||
|                         context.Response.OutputStream.Flush(); |  | ||||||
|                     } |  | ||||||
|                 } |  | ||||||
|                 else |  | ||||||
|                 { |  | ||||||
|                     await responseStream.CopyToAsync(context.Response.OutputStream); |  | ||||||
|                 } |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         private void WriteError(HttpListenerContext context, string message, HttpStatusCode statusCode) |  | ||||||
|         { |  | ||||||
|             context.Response.StatusCode = (int)statusCode; |  | ||||||
|             using (var writer = new StreamWriter(context.Response.OutputStream, Encoding.UTF8)) |  | ||||||
|             { |  | ||||||
|                 writer.Write(message); |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         public static bool ContainsSequentialKeywords(string input, string[] keywords, int maxDistance) |  | ||||||
|         { |  | ||||||
|             if (input == null || keywords == null || keywords.Length < 2) |  | ||||||
|                 return false; |  | ||||||
| 
 |  | ||||||
|             int position = 0; |  | ||||||
| 
 |  | ||||||
|             for (int i = 0; i < keywords.Length; i++) |  | ||||||
|             { |  | ||||||
|                 int index = input.IndexOf(keywords[i], position, StringComparison.OrdinalIgnoreCase); |  | ||||||
|                 if (index < 0) |  | ||||||
|                     return false; |  | ||||||
| 
 |  | ||||||
|                 if (i > 0 && (index - position) > maxDistance) |  | ||||||
|                     return false; |  | ||||||
| 
 |  | ||||||
|                 position = index + keywords[i].Length; |  | ||||||
|             } |  | ||||||
| 
 |  | ||||||
|             return true; |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  | @ -8,18 +8,21 @@ using System.Linq; | ||||||
| using System.Text.RegularExpressions; | using System.Text.RegularExpressions; | ||||||
| using System.Threading.Tasks; | using System.Threading.Tasks; | ||||||
| using System.Xml.Linq; | using System.Xml.Linq; | ||||||
|  | using System.Net.Http; | ||||||
| 
 | 
 | ||||||
| namespace WelsonJS.Launcher.ResourceTools | namespace WelsonJS.Launcher.ResourceTools | ||||||
| { | { | ||||||
|     public class Completion : IResourceTool |     public class Completion : IResourceTool | ||||||
|     { |     { | ||||||
|         private ResourceServer Server; |         private readonly ResourceServer Server; | ||||||
|  |         private readonly HttpClient _httpClient; | ||||||
|         private const string Prefix = "completion/"; |         private const string Prefix = "completion/"; | ||||||
|         private List<string> Executables = new List<string>(); |         private List<string> Executables = new List<string>(); | ||||||
| 
 | 
 | ||||||
|         public Completion(ResourceServer server) |         public Completion(ResourceServer server, HttpClient httpClient) | ||||||
|         { |         { | ||||||
|             Server = server; |             Server = server; | ||||||
|  |             _httpClient = httpClient; | ||||||
| 
 | 
 | ||||||
|             new Task(() => |             new Task(() => | ||||||
|             { |             { | ||||||
|  |  | ||||||
|  | @ -1,39 +0,0 @@ | ||||||
| using System; |  | ||||||
| using System.Net; |  | ||||||
| using System.Threading.Tasks; |  | ||||||
| 
 |  | ||||||
| namespace WelsonJS.Launcher.ResourceTools |  | ||||||
| { |  | ||||||
|     public class Config : IResourceTool |  | ||||||
|     { |  | ||||||
|         private ResourceServer Server; |  | ||||||
|         private const string Prefix = "config/"; |  | ||||||
| 
 |  | ||||||
|         public Config(ResourceServer server) |  | ||||||
|         { |  | ||||||
|             Server = server; |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         public bool CanHandle(string path) |  | ||||||
|         { |  | ||||||
|             return path.StartsWith(Prefix, StringComparison.OrdinalIgnoreCase); |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         public async Task HandleAsync(HttpListenerContext context, string path) |  | ||||||
|         { |  | ||||||
|             await Task.Delay(0); |  | ||||||
| 
 |  | ||||||
|             string configName = path.Substring(Prefix.Length); |  | ||||||
| 
 |  | ||||||
|             try |  | ||||||
|             { |  | ||||||
|                 string configValue = Program.GetAppConfig(configName); |  | ||||||
|                 Server.ServeResource(context, configValue, "text/plain"); |  | ||||||
|             } |  | ||||||
|             catch (Exception ex) |  | ||||||
|             { |  | ||||||
|                 Server.ServeResource(context, $"<error>Failed to process Config request. {ex.Message}</error>", "application/xml", 500); |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  | @ -8,12 +8,13 @@ namespace WelsonJS.Launcher.ResourceTools | ||||||
|     public class DevTools : IResourceTool |     public class DevTools : IResourceTool | ||||||
|     { |     { | ||||||
|         private ResourceServer Server; |         private ResourceServer Server; | ||||||
|  |         private readonly HttpClient _httpClient; | ||||||
|         private const string Prefix = "devtools/"; |         private const string Prefix = "devtools/"; | ||||||
|         private const double Timeout = 5000; |  | ||||||
| 
 | 
 | ||||||
|         public DevTools(ResourceServer server) |         public DevTools(ResourceServer server, HttpClient httpClient) | ||||||
|         { |         { | ||||||
|             Server = server; |             Server = server; | ||||||
|  |             _httpClient = httpClient; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         public bool CanHandle(string path) |         public bool CanHandle(string path) | ||||||
|  | @ -27,16 +28,11 @@ namespace WelsonJS.Launcher.ResourceTools | ||||||
| 
 | 
 | ||||||
|             try |             try | ||||||
|             { |             { | ||||||
|                 using (HttpClient client = new HttpClient()) |  | ||||||
|                 { |  | ||||||
|                     client.Timeout = TimeSpan.FromMilliseconds(Timeout); |  | ||||||
| 
 |  | ||||||
|                 string url = Program.GetAppConfig("DevToolsPrefix") + endpoint; |                 string url = Program.GetAppConfig("DevToolsPrefix") + endpoint; | ||||||
|                     string data = await client.GetStringAsync(url); |                 string data = await _httpClient.GetStringAsync(url); | ||||||
| 
 | 
 | ||||||
|                 Server.ServeResource(context, data, "application/json"); |                 Server.ServeResource(context, data, "application/json"); | ||||||
|             } |             } | ||||||
|             } |  | ||||||
|             catch (Exception ex) |             catch (Exception ex) | ||||||
|             { |             { | ||||||
|                 Server.ServeResource(context, $"<error>Failed to process DevTools request. {ex.Message}</error>", "application/xml", 500); |                 Server.ServeResource(context, $"<error>Failed to process DevTools request. {ex.Message}</error>", "application/xml", 500); | ||||||
|  |  | ||||||
|  | @ -2,6 +2,7 @@ | ||||||
| using System.Collections.Generic; | using System.Collections.Generic; | ||||||
| using System.Linq; | using System.Linq; | ||||||
| using System.Net; | using System.Net; | ||||||
|  | using System.Net.Http; | ||||||
| using System.Net.Sockets; | using System.Net.Sockets; | ||||||
| using System.Text; | using System.Text; | ||||||
| using System.Threading.Tasks; | using System.Threading.Tasks; | ||||||
|  | @ -10,16 +11,19 @@ namespace WelsonJS.Launcher.ResourceTools | ||||||
| { | { | ||||||
|     public class DnsQuery : IResourceTool |     public class DnsQuery : IResourceTool | ||||||
|     { |     { | ||||||
|         private ResourceServer Server; |         private readonly ResourceServer Server; | ||||||
|  |         private readonly HttpClient _httpClient; | ||||||
|         private const string Prefix = "dns-query/"; |         private const string Prefix = "dns-query/"; | ||||||
|         private string DnsServer; |         private string DnsServer; | ||||||
|         private const int DnsPort = 53; |         private const int DnsPort = 53; | ||||||
|         private const int Timeout = 5000; |         private const int Timeout = 5000; | ||||||
|         private static readonly Random _random = new Random(); |         private static readonly Random _random = new Random(); | ||||||
| 
 | 
 | ||||||
|         public DnsQuery(ResourceServer server) |         public DnsQuery(ResourceServer server, HttpClient httpClient) | ||||||
|         { |         { | ||||||
|             Server = server; |             Server = server; | ||||||
|  |             _httpClient = httpClient; | ||||||
|  | 
 | ||||||
|             DnsServer = Program.GetAppConfig("DnsServerAddress"); |             DnsServer = Program.GetAppConfig("DnsServerAddress"); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
							
								
								
									
										85
									
								
								WelsonJS.Toolkit/WelsonJS.Launcher/ResourceTools/Settings.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										85
									
								
								WelsonJS.Toolkit/WelsonJS.Launcher/ResourceTools/Settings.cs
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,85 @@ | ||||||
|  | using System; | ||||||
|  | using System.Collections.Generic; | ||||||
|  | using System.Configuration; | ||||||
|  | using System.Linq; | ||||||
|  | using System.Net; | ||||||
|  | using System.Net.Http; | ||||||
|  | using System.Reflection; | ||||||
|  | using System.Resources; | ||||||
|  | using System.Threading.Tasks; | ||||||
|  | using System.Xml.Linq; | ||||||
|  | 
 | ||||||
|  | namespace WelsonJS.Launcher.ResourceTools | ||||||
|  | { | ||||||
|  |     public class Settings : IResourceTool | ||||||
|  |     { | ||||||
|  |         private readonly ResourceServer Server; | ||||||
|  |         private readonly HttpClient _httpClient; | ||||||
|  |         private const string Prefix = "settings"; | ||||||
|  | 
 | ||||||
|  |         public Settings(ResourceServer server, HttpClient httpClient) | ||||||
|  |         { | ||||||
|  |             Server = server; | ||||||
|  |             _httpClient = httpClient; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         public bool CanHandle(string path) | ||||||
|  |         { | ||||||
|  |             return path.Equals(Prefix, StringComparison.OrdinalIgnoreCase); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         public async Task HandleAsync(HttpListenerContext context, string path) | ||||||
|  |         { | ||||||
|  |             await Task.Delay(0); | ||||||
|  |              | ||||||
|  |             // Get current namespace (e.g., WelsonJS.Launcher) | ||||||
|  |             string ns = typeof(Program).Namespace; | ||||||
|  | 
 | ||||||
|  |             // Build resource base name (e.g., WelsonJS.Launcher.Properties.Resources) | ||||||
|  |             string resourceBaseName = ns + ".Properties.Resources"; | ||||||
|  | 
 | ||||||
|  |             // Load resource strings using ResourceManager | ||||||
|  |             var resourceManager = new ResourceManager(resourceBaseName, Assembly.GetExecutingAssembly()); | ||||||
|  |             var resourceSet = resourceManager.GetResourceSet( | ||||||
|  |                 System.Globalization.CultureInfo.CurrentCulture, | ||||||
|  |                 true, | ||||||
|  |                 true | ||||||
|  |             ); | ||||||
|  | 
 | ||||||
|  |             var resourceStrings = new Dictionary<string, string>(); | ||||||
|  |             foreach (System.Collections.DictionaryEntry entry in resourceSet) | ||||||
|  |             { | ||||||
|  |                 string key = (string)entry.Key; | ||||||
|  |                 object value = entry.Value; | ||||||
|  | 
 | ||||||
|  |                 if (value is string strValue) | ||||||
|  |                 { | ||||||
|  |                     resourceStrings[key] = strValue; | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             // Load settings from app.config | ||||||
|  |             var appConfig = ConfigurationManager.AppSettings.AllKeys | ||||||
|  |                 .ToDictionary(k => k, k => ConfigurationManager.AppSettings[k]); | ||||||
|  | 
 | ||||||
|  |             // Merge keys from both sources (app.config has priority) | ||||||
|  |             var allKeys = new HashSet<string>(resourceStrings.Keys.Concat(appConfig.Keys)); | ||||||
|  |             var finalConfig = new Dictionary<string, string>(); | ||||||
|  | 
 | ||||||
|  |             foreach (var key in allKeys) | ||||||
|  |             { | ||||||
|  |                 if (appConfig.ContainsKey(key)) | ||||||
|  |                     finalConfig[key] = appConfig[key]; | ||||||
|  |                 else if (resourceStrings.ContainsKey(key)) | ||||||
|  |                     finalConfig[key] = resourceStrings[key]; | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             // Generate XML using XElement | ||||||
|  |             XElement xml = new XElement("settings", | ||||||
|  |                 finalConfig.Select(kv => new XElement(kv.Key, kv.Value)) | ||||||
|  |             ); | ||||||
|  | 
 | ||||||
|  |             Server.ServeResource(context, xml.ToString(), "application/xml"); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | @ -4,18 +4,21 @@ using System.Security.Cryptography; | ||||||
| using System.Collections.Generic; | using System.Collections.Generic; | ||||||
| using System.Net; | using System.Net; | ||||||
| using System.Threading.Tasks; | using System.Threading.Tasks; | ||||||
|  | using System.Net.Http; | ||||||
| 
 | 
 | ||||||
| namespace WelsonJS.Launcher.ResourceTools | namespace WelsonJS.Launcher.ResourceTools | ||||||
| { | { | ||||||
|     public class Tfa : IResourceTool |     public class Tfa : IResourceTool | ||||||
|     { |     { | ||||||
|         private ResourceServer Server; |         private readonly ResourceServer Server; | ||||||
|  |         private readonly HttpClient _httpClient; | ||||||
|         private const string Prefix = "tfa/"; |         private const string Prefix = "tfa/"; | ||||||
|         private const string Base32Chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567"; |         private const string Base32Chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567"; | ||||||
| 
 | 
 | ||||||
|         public Tfa(ResourceServer server) |         public Tfa(ResourceServer server, HttpClient httpClient) | ||||||
|         { |         { | ||||||
|             Server = server; |             Server = server; | ||||||
|  |             _httpClient = httpClient; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         public bool CanHandle(string path) |         public bool CanHandle(string path) | ||||||
|  |  | ||||||
|  | @ -8,13 +8,14 @@ namespace WelsonJS.Launcher.ResourceTools | ||||||
| { | { | ||||||
|     public class Whois : IResourceTool |     public class Whois : IResourceTool | ||||||
|     { |     { | ||||||
|         private ResourceServer Server; |         private readonly ResourceServer Server; | ||||||
|  |         private readonly HttpClient _httpClient; | ||||||
|         private const string Prefix = "whois/"; |         private const string Prefix = "whois/"; | ||||||
|         private const int Timeout = 5000; |  | ||||||
| 
 | 
 | ||||||
|         public Whois(ResourceServer server) |         public Whois(ResourceServer server, HttpClient httpClient) | ||||||
|         { |         { | ||||||
|             Server = server; |             Server = server; | ||||||
|  |             _httpClient = httpClient; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         public bool CanHandle(string path) |         public bool CanHandle(string path) | ||||||
|  | @ -32,10 +33,6 @@ namespace WelsonJS.Launcher.ResourceTools | ||||||
|                 return; |                 return; | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             using (var client = new HttpClient()) |  | ||||||
|             { |  | ||||||
|                 client.Timeout = TimeSpan.FromMilliseconds(Timeout); |  | ||||||
| 
 |  | ||||||
|             string clientAddress = Program.GetAppConfig("WhoisClientAddress"); |             string clientAddress = Program.GetAppConfig("WhoisClientAddress"); | ||||||
| 
 | 
 | ||||||
|             HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, Program.GetAppConfig("WhoisServerUrl")) |             HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, Program.GetAppConfig("WhoisServerUrl")) | ||||||
|  | @ -45,11 +42,11 @@ namespace WelsonJS.Launcher.ResourceTools | ||||||
| 
 | 
 | ||||||
|             request.Headers.Add("Accept", "*/*"); |             request.Headers.Add("Accept", "*/*"); | ||||||
|             request.Headers.Add("User-Agent", context.Request.UserAgent); |             request.Headers.Add("User-Agent", context.Request.UserAgent); | ||||||
|                 client.DefaultRequestHeaders.Referrer = new Uri(Program.GetAppConfig("WhoisReferrerUrl")); |             _httpClient.DefaultRequestHeaders.Referrer = new Uri(Program.GetAppConfig("WhoisReferrerUrl")); | ||||||
| 
 | 
 | ||||||
|             try |             try | ||||||
|             { |             { | ||||||
|                     HttpResponseMessage response = await client.SendAsync(request); |                 HttpResponseMessage response = await _httpClient.SendAsync(request); | ||||||
|                 string responseBody = await response.Content.ReadAsStringAsync(); |                 string responseBody = await response.Content.ReadAsStringAsync(); | ||||||
| 
 | 
 | ||||||
|                 Server.ServeResource(context, responseBody, "text/plain", (int)response.StatusCode); |                 Server.ServeResource(context, responseBody, "text/plain", (int)response.StatusCode); | ||||||
|  | @ -61,4 +58,3 @@ namespace WelsonJS.Launcher.ResourceTools | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
| } |  | ||||||
|  |  | ||||||
|  | @ -74,8 +74,7 @@ | ||||||
|   </ItemGroup> |   </ItemGroup> | ||||||
|   <ItemGroup> |   <ItemGroup> | ||||||
|     <Compile Include="IResourceTool.cs" /> |     <Compile Include="IResourceTool.cs" /> | ||||||
|     <Compile Include="ResourceTools\AzureAi.cs" /> |     <Compile Include="ResourceTools\Settings.cs" /> | ||||||
|     <Compile Include="ResourceTools\Config.cs" /> |  | ||||||
|     <Compile Include="ResourceTools\Completion.cs" /> |     <Compile Include="ResourceTools\Completion.cs" /> | ||||||
|     <Compile Include="ResourceTools\DevTools.cs" /> |     <Compile Include="ResourceTools\DevTools.cs" /> | ||||||
|     <Compile Include="ResourceTools\DnsQuery.cs" /> |     <Compile Include="ResourceTools\DnsQuery.cs" /> | ||||||
|  |  | ||||||
|  | @ -5,8 +5,9 @@ | ||||||
|     <add key="RepositoryUrl" value="https://github.com/gnh1201/welsonjs"/> |     <add key="RepositoryUrl" value="https://github.com/gnh1201/welsonjs"/> | ||||||
|     <add key="CopilotUrl" value="https://copilot.microsoft.com/"/> |     <add key="CopilotUrl" value="https://copilot.microsoft.com/"/> | ||||||
|     <add key="DevToolsPrefix" value="http://localhost:9222/"/> |     <add key="DevToolsPrefix" value="http://localhost:9222/"/> | ||||||
|     <add key="AzureAiServiceUrl" value="https://ai-catswords656881030318.services.ai.azure.com/models/chat/completions?api-version=2024-05-01-preview"/> |     <add key="AzureAiServicePrefix" value="https://ai-catswords656881030318.services.ai.azure.com/"/> | ||||||
|     <add key="AzureAiServiceApiKey" value=""/> |     <add key="AzureAiServiceApiKey" value=""/> | ||||||
|  |     <add key="AzureAiServiceApiVersion" value="2024-05-01-preview"/> | ||||||
|     <add key="WhoisServerUrl" value="https://xn--c79as89aj0e29b77z.xn--3e0b707e/kor/whois.jsc"/> |     <add key="WhoisServerUrl" value="https://xn--c79as89aj0e29b77z.xn--3e0b707e/kor/whois.jsc"/> | ||||||
|     <add key="WhoisReferrerUrl" value="https://xn--c79as89aj0e29b77z.xn--3e0b707e/kor/whois/whois.jsp"/> |     <add key="WhoisReferrerUrl" value="https://xn--c79as89aj0e29b77z.xn--3e0b707e/kor/whois/whois.jsp"/> | ||||||
|     <add key="WhoisClientAddress" value="141.101.82.1"/> |     <add key="WhoisClientAddress" value="141.101.82.1"/> | ||||||
|  |  | ||||||
|  | @ -57,7 +57,19 @@ | ||||||
|                         <span class="icon mif-rocket"></span> |                         <span class="icon mif-rocket"></span> | ||||||
|                         <span class="caption">Copilot</span> |                         <span class="caption">Copilot</span> | ||||||
|                     </button> |                     </button> | ||||||
|                     <span class="title">Generative</span> |                     <button id="btnAzureAi" class="ribbon-button"> | ||||||
|  |                         <span class="icon mif-rocket"></span> | ||||||
|  |                         <span class="caption">Azure AI</span> | ||||||
|  |                     </button> | ||||||
|  |                     <button id="btnSavePrompt" class="ribbon-button"> | ||||||
|  |                         <span class="icon mif-floppy-disks"></span> | ||||||
|  |                         <span class="caption">Save</span> | ||||||
|  |                     </button> | ||||||
|  |                     <button id="btnLoadPrompt" class="ribbon-button"> | ||||||
|  |                         <span class="icon mif-file-upload"></span> | ||||||
|  |                         <span class="caption">Load</span> | ||||||
|  |                     </button> | ||||||
|  |                     <span class="title">Generative AI</span> | ||||||
|                 </div> |                 </div> | ||||||
|                 <div class="group"> |                 <div class="group"> | ||||||
|                     <button id="btnWhois" class="ribbon-button"> |                     <button id="btnWhois" class="ribbon-button"> | ||||||
|  | @ -93,25 +105,36 @@ | ||||||
|     <script src="http://localhost:3000/ajax/libs/monaco-editor/0.52.2/min/vs/loader.js" integrity="sha384-pHG02SG8pId94Np3AbPmBEJ1yPqaH0IkJGLSNGXYmuGhkazT8Lr/57WYpbkGjJtu" crossorigin="anonymous"></script> |     <script src="http://localhost:3000/ajax/libs/monaco-editor/0.52.2/min/vs/loader.js" integrity="sha384-pHG02SG8pId94Np3AbPmBEJ1yPqaH0IkJGLSNGXYmuGhkazT8Lr/57WYpbkGjJtu" crossorigin="anonymous"></script> | ||||||
|     <script src="http://localhost:3000/ajax/libs/monaco-editor/0.52.2/min/vs/editor/editor.main.js" integrity="sha384-fj9z+NUc93I3woCCy5IRQfrQ8Amu1E27tllwgb5gz3d9Vr1ymS13xcF6two3e4KH" crossorigin="anonymous"></script> |     <script src="http://localhost:3000/ajax/libs/monaco-editor/0.52.2/min/vs/editor/editor.main.js" integrity="sha384-fj9z+NUc93I3woCCy5IRQfrQ8Amu1E27tllwgb5gz3d9Vr1ymS13xcF6two3e4KH" crossorigin="anonymous"></script> | ||||||
|     <script> |     <script> | ||||||
|         var editor; |         let editor; | ||||||
|         var currentFileName = "sayhello.js"; |         let currentFileName = "sayhello.js"; | ||||||
|         var serverBaseUrl = "http://localhost:3000"; |         const serverPrefix = "http://localhost:3000/"; | ||||||
|  |         let settings = {}; | ||||||
|  |         let promptMessages = []; | ||||||
|  | 
 | ||||||
|  |         function fetchSettings() { | ||||||
|  |             axios.get(`${serverPrefix}settings`) | ||||||
|  |                 .then(response => { | ||||||
|  |                     const parser = new XMLParser(); | ||||||
|  |                     const result = parser.parse(response.data); | ||||||
|  |                     settings = result.settings; | ||||||
|  |                 }); | ||||||
|  |         } | ||||||
| 
 | 
 | ||||||
|         function resizeEditor() { |         function resizeEditor() { | ||||||
|             if (editor) { |             if (editor) { | ||||||
|                 var ribbonHeight = document.querySelector('nav').offsetHeight; |                 const ribbonHeight = document.querySelector('nav').offsetHeight; | ||||||
|                 var bannerHeight = document.querySelector('.banner').offsetHeight; |                 const bannerHeight = document.querySelector('.banner').offsetHeight; | ||||||
|                 var containerHeight = document.documentElement.clientHeight - ribbonHeight - bannerHeight; |                 const containerHeight = document.documentElement.clientHeight - ribbonHeight - bannerHeight; | ||||||
|                 document.getElementById('container').style.height = containerHeight + 'px'; |                 document.getElementById('container').style.height = containerHeight + 'px'; | ||||||
|                 editor.layout(); |                 editor.layout(); | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         function getSuggestions(word, range) { |         function getSuggestions(word, range) { | ||||||
|             return axios.get(`${serverBaseUrl}/completion/${encodeURIComponent(word)}`) |             return axios.get(`${serverPrefix}completion/${encodeURIComponent(word)}`) | ||||||
|                 .then(function (response) { |                 .then(response => { | ||||||
|                     var parser = new XMLParser(); |                     const parser = new XMLParser(); | ||||||
|                     var result = parser.parse(response.data); |                     const result = parser.parse(response.data); | ||||||
| 
 | 
 | ||||||
|                     if (!result.suggestions || !result.suggestions.item) { |                     if (!result.suggestions || !result.suggestions.item) { | ||||||
|                         return { |                         return { | ||||||
|  | @ -119,8 +142,8 @@ | ||||||
|                         }; |                         }; | ||||||
|                     } |                     } | ||||||
| 
 | 
 | ||||||
|                     var items = Array.isArray(result.suggestions.item) ? result.suggestions.item : [result.suggestions.item]; |                     const items = Array.isArray(result.suggestions.item) ? result.suggestions.item : [result.suggestions.item]; | ||||||
|                     var suggestions = items.map(function (item) { |                     const suggestions = items.map(function (item) { | ||||||
|                         return { |                         return { | ||||||
|                             label: item.label, |                             label: item.label, | ||||||
|                             kind: monaco.languages.CompletionItemKind.Text, |                             kind: monaco.languages.CompletionItemKind.Text, | ||||||
|  | @ -149,8 +172,8 @@ | ||||||
| 
 | 
 | ||||||
|             monaco.languages.registerCompletionItemProvider('javascript', { |             monaco.languages.registerCompletionItemProvider('javascript', { | ||||||
|                 provideCompletionItems: function (model, position) { |                 provideCompletionItems: function (model, position) { | ||||||
|                     var word = model.getWordUntilPosition(position); |                     const word = model.getWordUntilPosition(position); | ||||||
|                     var range = { |                     const range = { | ||||||
|                         startLineNumber: position.lineNumber, |                         startLineNumber: position.lineNumber, | ||||||
|                         endLineNumber: position.lineNumber, |                         endLineNumber: position.lineNumber, | ||||||
|                         startColumn: word.startColumn, |                         startColumn: word.startColumn, | ||||||
|  | @ -165,8 +188,8 @@ | ||||||
|         window.addEventListener('resize', resizeEditor); |         window.addEventListener('resize', resizeEditor); | ||||||
| 
 | 
 | ||||||
|         function getFileLanguage(fileName) { |         function getFileLanguage(fileName) { | ||||||
|             var extension = fileName.split('.').pop().toLowerCase(); |             const extension = fileName.split('.').pop().toLowerCase(); | ||||||
|             var languageMap = { |             const languageMap = { | ||||||
|                 'js': 'javascript', |                 'js': 'javascript', | ||||||
|                 'ts': 'typescript', |                 'ts': 'typescript', | ||||||
|                 'html': 'html', |                 'html': 'html', | ||||||
|  | @ -186,7 +209,7 @@ | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         function navigate(href) { |         function navigate(href) { | ||||||
|             var a = document.createElement("a"); |             const a = document.createElement("a"); | ||||||
|             a.href = href; |             a.href = href; | ||||||
|             a.target = "_blank"; |             a.target = "_blank"; | ||||||
|             document.body.appendChild(a); |             document.body.appendChild(a); | ||||||
|  | @ -205,13 +228,14 @@ | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         document.getElementById("fileInput").onchange = function (event) { |         document.getElementById("fileInput").onchange = function (event) { | ||||||
|             var file = event.target.files[0]; |             const file = event.target.files[0]; | ||||||
|             if (!file) return; |             if (!file) return; | ||||||
| 
 | 
 | ||||||
|             currentFileName = file.name; |             currentFileName = file.name; | ||||||
|             var reader = new FileReader(); | 
 | ||||||
|  |             const reader = new FileReader(); | ||||||
|             reader.onload = function (e) { |             reader.onload = function (e) { | ||||||
|                 var language = getFileLanguage(file.name); |                 let language = getFileLanguage(file.name); | ||||||
|                 monaco.editor.setModelLanguage(editor.getModel(), language); |                 monaco.editor.setModelLanguage(editor.getModel(), language); | ||||||
|                 editor.setValue(e.target.result); |                 editor.setValue(e.target.result); | ||||||
|             }; |             }; | ||||||
|  | @ -223,13 +247,14 @@ | ||||||
|         }; |         }; | ||||||
| 
 | 
 | ||||||
|         document.getElementById("btnSaveFile").onclick = function () { |         document.getElementById("btnSaveFile").onclick = function () { | ||||||
|             var text = editor.getValue(); |             const text = editor.getValue(); | ||||||
|             var fileName = prompt("Enter file name:", currentFileName); |             const fileName = prompt("Enter file name:", currentFileName); | ||||||
|             if (!fileName) return; |             if (!fileName) return; | ||||||
| 
 | 
 | ||||||
|             currentFileName = fileName; |             currentFileName = fileName; | ||||||
|             var blob = new Blob([text], { type: 'text/plain' }); | 
 | ||||||
|             var a = document.createElement('a'); |             const blob = new Blob([text], { type: 'text/plain' }); | ||||||
|  |             const a = document.createElement('a'); | ||||||
|             a.href = URL.createObjectURL(blob); |             a.href = URL.createObjectURL(blob); | ||||||
|             a.download = fileName; |             a.download = fileName; | ||||||
|             document.body.appendChild(a); |             document.body.appendChild(a); | ||||||
|  | @ -246,6 +271,11 @@ | ||||||
| 
 | 
 | ||||||
|             appendTextToEditor(`\n// ${promptMessage}... Generating text with Copilot...`); |             appendTextToEditor(`\n// ${promptMessage}... Generating text with Copilot...`); | ||||||
| 
 | 
 | ||||||
|  |             promptMessages.push({ | ||||||
|  |                 role: 'user', | ||||||
|  |                 content: promptMessage | ||||||
|  |             }) | ||||||
|  | 
 | ||||||
|             (async function () { |             (async function () { | ||||||
|                 const targetWsUrl = await getTargetByUrl('copilot.microsoft.com'); |                 const targetWsUrl = await getTargetByUrl('copilot.microsoft.com'); | ||||||
|                 if (targetWsUrl) { |                 if (targetWsUrl) { | ||||||
|  | @ -256,16 +286,94 @@ | ||||||
|             })(); |             })(); | ||||||
|         }; |         }; | ||||||
| 
 | 
 | ||||||
|         document.getElementById("btnWhois").onclick = function () { |         document.getElementById("btnAzureAi").onclick = function () { | ||||||
|             const hostname = prompt("Enter a hostname or IP address:", ''); |             const promptMessage = prompt("Enter a prompt message:", ''); | ||||||
|             if (!hostname || hostname.trim() == '') { |             if (!promptMessage || promptMessage.trim() == '') { | ||||||
|                 alert("A hostname or IP address is required."); |                 alert("A prompt message is required."); | ||||||
|                 return; |                 return; | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             axios.get(`${serverBaseUrl}/whois/${hostname}`).then(response => { |             appendTextToEditor(`\n// ${promptMessage}... Generating text with Azure AI...`); | ||||||
|                 const responseText = DOMPurify.sanitize(response.data, { ALLOWED_TAGS: [], ALLOWED_ATTR: [] }); |  | ||||||
| 
 | 
 | ||||||
|  |             const apiKey = settings.AzureAiServiceApiKey; | ||||||
|  |             const url = `${settings.AzureAiServicePrefix}models/chat/completions?api-version=${settings.AzureAiServiceApiVersion}`; | ||||||
|  | 
 | ||||||
|  |             promptMessages.push({ | ||||||
|  |                 role: 'user', | ||||||
|  |                 content: promptMessage | ||||||
|  |             }) | ||||||
|  | 
 | ||||||
|  |             const data = { | ||||||
|  |                 messages: promptMessages, | ||||||
|  |                 max_tokens: 2048, | ||||||
|  |                 temperature: 0.8, | ||||||
|  |                 top_p: 0.1, | ||||||
|  |                 presence_penalty: 0, | ||||||
|  |                 frequency_penalty: 0, | ||||||
|  |                 model: 'Phi-4' | ||||||
|  |             }; | ||||||
|  | 
 | ||||||
|  |             axios.post(url, data, { | ||||||
|  |                     headers: { | ||||||
|  |                         'Content-Type': 'application/json', | ||||||
|  |                         'api-key': apiKey | ||||||
|  |                     } | ||||||
|  |                 }) | ||||||
|  |                 .then(response => { | ||||||
|  |                     response.data.choices.forEach(x => { | ||||||
|  |                         const responseContent = x.message.content; | ||||||
|  |                         promptMessages.push({ | ||||||
|  |                             role: 'assistant', | ||||||
|  |                             content: responseContent | ||||||
|  |                         }); | ||||||
|  | 
 | ||||||
|  |                         const responseText = DOMPurify.sanitize(responseContent, { ALLOWED_TAGS: [], ALLOWED_ATTR: [] }); | ||||||
|  |                         appendTextToEditor(`/*\n${responseText}\n*/`); | ||||||
|  |                     }); | ||||||
|  |                 }) | ||||||
|  |                 .catch(error => { | ||||||
|  |                     console.error('Error:', error.response?.data || error.message); | ||||||
|  |                 }); | ||||||
|  |         }; | ||||||
|  | 
 | ||||||
|  |         document.getElementById("btnSavePrompt").onclick = function () { | ||||||
|  |             const text = JSON.stringify(promptMessages, null, 4); | ||||||
|  |             const blob = new Blob([text], { type: 'text/plain' }); | ||||||
|  |             const a = document.createElement('a'); | ||||||
|  |             a.href = URL.createObjectURL(blob); | ||||||
|  |             a.download = "prompt.json"; | ||||||
|  |             document.body.appendChild(a); | ||||||
|  |             a.click(); | ||||||
|  |             document.body.removeChild(a); | ||||||
|  |         }; | ||||||
|  | 
 | ||||||
|  |         document.getElementById("btnLoadPrompt").onclick = function () { | ||||||
|  |             const fileInput = document.createElement('input'); | ||||||
|  |             fileInput.type = 'file'; | ||||||
|  |             fileInput.accept = '.json'; | ||||||
|  |             fileInput.onchange = function (event) { | ||||||
|  |                 const file = event.target.files[0]; | ||||||
|  |                 if (!file) return; | ||||||
|  | 
 | ||||||
|  |                 let reader = new FileReader(); | ||||||
|  |                 reader.onload = function (e) { | ||||||
|  |                     promptMessages = JSON.parse(e.target.result); | ||||||
|  |                     appendTextToEditor("\n//Prompt loaded successfully."); | ||||||
|  |                 }; | ||||||
|  |                 reader.readAsText(file); | ||||||
|  |             }; | ||||||
|  |             fileInput.click(); | ||||||
|  |         }; | ||||||
|  | 
 | ||||||
|  |         document.getElementById("btnWhois").onclick = function () { | ||||||
|  |             const hostname = prompt("Enter a hostname or IP address:", ''); | ||||||
|  |             if (!hostname || hostname.trim() == '') { | ||||||
|  |                 appendTextToEditor("\n// A hostname or IP address is required."); | ||||||
|  |                 return; | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             axios.get(`${serverPrefix}whois/${hostname}`).then(response => { | ||||||
|  |                 const responseText = DOMPurify.sanitize(response.data, { ALLOWED_TAGS: [], ALLOWED_ATTR: [] }); | ||||||
|                 appendTextToEditor(`/*\n${responseText}\n*/`); |                 appendTextToEditor(`/*\n${responseText}\n*/`); | ||||||
|             }).catch(error => { |             }).catch(error => { | ||||||
|                 console.error(error); |                 console.error(error); | ||||||
|  | @ -275,11 +383,11 @@ | ||||||
|         document.getElementById("btnDnsQuery").onclick = function () { |         document.getElementById("btnDnsQuery").onclick = function () { | ||||||
|             const hostname = prompt("Enter a hostname or IP address:", ''); |             const hostname = prompt("Enter a hostname or IP address:", ''); | ||||||
|             if (!hostname || hostname.trim() == '') { |             if (!hostname || hostname.trim() == '') { | ||||||
|                 alert("A hostname or IP address is required."); |                 appendTextToEditor("\n// A hostname or IP address is required."); | ||||||
|                 return; |                 return; | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             axios.get(`${serverBaseUrl}/dns-query/${hostname}`).then(response => { |             axios.get(`${serverPrefix}dns-query/${hostname}`).then(response => { | ||||||
|                 const responseText = response.data; |                 const responseText = response.data; | ||||||
|                 appendTextToEditor(`/*\n${responseText}\n*/`); |                 appendTextToEditor(`/*\n${responseText}\n*/`); | ||||||
|             }).catch(error => { |             }).catch(error => { | ||||||
|  | @ -288,7 +396,7 @@ | ||||||
|         }; |         }; | ||||||
| 
 | 
 | ||||||
|         async function getTargetByUrl(urlPart) { |         async function getTargetByUrl(urlPart) { | ||||||
|             const response = await fetch(`${serverBaseUrl}/devtools/json`); |             const response = await fetch(`${serverPrefix}devtools/json`); | ||||||
|             const targets = await response.json(); |             const targets = await response.json(); | ||||||
| 
 | 
 | ||||||
|             const target = targets.find(target => target.url.includes(urlPart)); |             const target = targets.find(target => target.url.includes(urlPart)); | ||||||
|  | @ -347,11 +455,20 @@ | ||||||
|                 console.log("Sent successfully:", response.result); |                 console.log("Sent successfully:", response.result); | ||||||
| 
 | 
 | ||||||
|                 if (response.id == 3) { |                 if (response.id == 3) { | ||||||
|                     appendTextToEditor(response.result.result.value); |                     const responseContent = response.result.result.value; | ||||||
|  | 
 | ||||||
|  |                     promptMessages.push({ | ||||||
|  |                         role: 'assistant', | ||||||
|  |                         content: responseContent | ||||||
|  |                     }); | ||||||
|  | 
 | ||||||
|  |                     appendTextToEditor(responseContent); | ||||||
|                     socket.close(); |                     socket.close(); | ||||||
|                 } |                 } | ||||||
|             }; |             }; | ||||||
|         } |         } | ||||||
|  | 
 | ||||||
|  |         fetchSettings(); | ||||||
|     </script> |     </script> | ||||||
| </body> | </body> | ||||||
| </html> | </html> | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue
	
	Block a user