mirror of
https://github.com/gnh1201/welsonjs.git
synced 2025-05-07 12:16:04 +00:00
commit
426a9d7721
|
@ -62,7 +62,7 @@ WelsonJS is tailored for developers who need a reliable, lightweight JavaScript
|
|||
## Specifications
|
||||
- Built-in transpilers: [TypeScript](https://www.typescriptlang.org/), [Rescript](https://rescript-lang.org/), [CoffeeScript 2](https://coffeescript.org/), [LiveScript](https://livescript.net/)
|
||||
- **Ready to use on Windows machine immediately. No require additional software installation.**
|
||||
- **WelsonJS Launcher**: Manage an instances (Like a container), User-defined variable editor, [Microsoft Monaco Editor](https://github.com/microsoft/monaco-editor) (Pre-embedded rich code editor), [Microsoft Copilot](https://copilot.microsoft.com) on the code editor.
|
||||
- **WelsonJS Launcher**: Manage instances (Like a container), User-defined variable editor, [Microsoft Monaco Editor](https://github.com/microsoft/monaco-editor) (Pre-embedded rich code editor), [Microsoft Copilot](https://copilot.microsoft.com) on the code editor.
|
||||
- ES5(ECMAScript 5), XML, JSON, YAML compatibility: [core-js](https://github.com/zloirock/core-js), [JSON2.js](https://github.com/douglascrockford/JSON-js), [js-yaml](https://github.com/nodeca/js-yaml)
|
||||
- HTML5, CSS3 compatibility: [html5shiv](https://github.com/aFarkas/html5shiv), [jquery-html5-placeholder-shim](https://github.com/parndt/jquery-html5-placeholder-shim), [Respond](https://github.com/scottjehl/Respond), [selectivizr](https://github.com/keithclark/selectivizr), [ExplorerCanvas](https://github.com/arv/ExplorerCanvas), [Modernizr](https://github.com/Modernizr/Modernizr)
|
||||
- Classical CSS Frameworks: [cascadeframework](https://github.com/jslegers/cascadeframework), [golden-layout](https://github.com/golden-layout/golden-layout)
|
||||
|
|
|
@ -242,10 +242,7 @@ namespace WelsonJS.Launcher
|
|||
|
||||
private void startCodeEditorToolStripMenuItem_Click(object sender, EventArgs e)
|
||||
{
|
||||
if (Program.resourceServer == null)
|
||||
{
|
||||
Program.resourceServer = new ResourceServer(Program.GetAppConfig("ResourceServerPrefix"), "editor.html");
|
||||
}
|
||||
Program.StartResourceServer();
|
||||
|
||||
if (!Program.resourceServer.IsRunning())
|
||||
{
|
||||
|
|
|
@ -138,13 +138,24 @@ namespace WelsonJS.Launcher
|
|||
return workingDirectory;
|
||||
}
|
||||
|
||||
public static void StartResourceServer()
|
||||
{
|
||||
lock(typeof(Program))
|
||||
{
|
||||
if (resourceServer == null)
|
||||
{
|
||||
resourceServer = new ResourceServer(GetAppConfig("ResourceServerPrefix"), "editor.html");
|
||||
}
|
||||
}
|
||||
}
|
||||
public static void OpenWebBrowser(string url)
|
||||
{
|
||||
string userDataDir = Path.Combine(GetAppDataPath(), "EdgeUserProfile");
|
||||
string remoteAllowOrigins = "http://localhost:3000";
|
||||
string remoteAllowOrigins = GetAppConfig("ResourceServerPrefix");
|
||||
int remoteDebuggingPort = new Uri(GetAppConfig("DevToolsPrefix")).Port;
|
||||
string[] arguments = {
|
||||
$"\"{url}\"",
|
||||
"--remote-debugging-port=9222",
|
||||
$"--remote-debugging-port={remoteDebuggingPort}",
|
||||
$"--remote-allow-origins={remoteAllowOrigins}", // for security reason
|
||||
$"--user-data-dir=\"{userDataDir}\""
|
||||
};
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.IO.Compression;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Reflection;
|
||||
|
|
139
WelsonJS.Toolkit/WelsonJS.Launcher/ResourceTools/AzureAi.cs
Normal file
139
WelsonJS.Toolkit/WelsonJS.Launcher/ResourceTools/AzureAi.cs
Normal file
|
@ -0,0 +1,139 @@
|
|||
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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -74,6 +74,7 @@
|
|||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="IResourceTool.cs" />
|
||||
<Compile Include="ResourceTools\AzureAi.cs" />
|
||||
<Compile Include="ResourceTools\Config.cs" />
|
||||
<Compile Include="ResourceTools\Completion.cs" />
|
||||
<Compile Include="ResourceTools\DevTools.cs" />
|
||||
|
@ -165,6 +166,5 @@
|
|||
<ItemGroup>
|
||||
<EmbeddedResource Include="editor.html" />
|
||||
</ItemGroup>
|
||||
<ItemGroup />
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
</Project>
|
|
@ -50,16 +50,14 @@
|
|||
<span class="icon mif-floppy-disks"></span>
|
||||
<span class="caption">Save File</span>
|
||||
</button>
|
||||
<button id="btnGenerate" class="ribbon-button">
|
||||
<span class="title">File</span>
|
||||
</div>
|
||||
<div class="group">
|
||||
<button id="btnCopilot" class="ribbon-button">
|
||||
<span class="icon mif-rocket"></span>
|
||||
<span class="caption">Generate</span>
|
||||
<span class="caption">Copilot</span>
|
||||
</button>
|
||||
<button id="btnSponsor" class="ribbon-button">
|
||||
<span class="icon mif-heart"></span>
|
||||
<span class="caption">Sponsor</span>
|
||||
</button>
|
||||
|
||||
<span class="title">Common</span>
|
||||
<span class="title">Generative</span>
|
||||
</div>
|
||||
<div class="group">
|
||||
<button id="btnWhois" class="ribbon-button">
|
||||
|
@ -70,8 +68,7 @@
|
|||
<span class="icon mif-earth"></span>
|
||||
<span class="caption">DNS</span>
|
||||
</button>
|
||||
|
||||
<span class="title">Network tools</span>
|
||||
<span class="title">Network</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -240,18 +237,14 @@
|
|||
document.body.removeChild(a);
|
||||
};
|
||||
|
||||
document.getElementById("btnSponsor").onclick = function () {
|
||||
navigate('https://github.com/sponsors/gnh1201');
|
||||
};
|
||||
|
||||
document.getElementById("btnGenerate").onclick = function () {
|
||||
document.getElementById("btnCopilot").onclick = function () {
|
||||
const promptMessage = prompt("Enter a prompt message:", '');
|
||||
if (!promptMessage || promptMessage.trim() == '') {
|
||||
alert("A prompt message is required.");
|
||||
return;
|
||||
}
|
||||
|
||||
appendTextToEditor(`\n//${promptMessage}... Thinking with Generative AI...`);
|
||||
appendTextToEditor(`\n//${promptMessage}... Generating text with Copilot...`);
|
||||
|
||||
(async function () {
|
||||
const targetWsUrl = await getTargetByUrl('copilot.microsoft.com');
|
||||
|
|
Loading…
Reference in New Issue
Block a user