From 8cdeacaad8ec66ddc7b6efb2a700c043ddf8d30c Mon Sep 17 00:00:00 2001 From: Milkey Tan <24996957+mili-tan@users.noreply.github.com> Date: Sun, 5 Jan 2025 20:06:17 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E9=A1=B9=E7=9B=AE=E6=96=87?= =?UTF-8?q?=E4=BB=B6=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Onllama.MondrianGateway.csproj | 17 ++++ Onllama.MondrianGateway.sln | 22 +++++ Program.cs | 165 +++++++++++++++++++++++++++++++++ 3 files changed, 204 insertions(+) create mode 100644 Onllama.MondrianGateway.csproj create mode 100644 Onllama.MondrianGateway.sln create mode 100644 Program.cs diff --git a/Onllama.MondrianGateway.csproj b/Onllama.MondrianGateway.csproj new file mode 100644 index 0000000..a1e28a8 --- /dev/null +++ b/Onllama.MondrianGateway.csproj @@ -0,0 +1,17 @@ + + + + Exe + net8.0 + enable + enable + + + + + + + + + + diff --git a/Onllama.MondrianGateway.sln b/Onllama.MondrianGateway.sln new file mode 100644 index 0000000..c2581cd --- /dev/null +++ b/Onllama.MondrianGateway.sln @@ -0,0 +1,22 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.12.35527.113 d17.12 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Onllama.MondrianGateway", "Onllama.MondrianGateway.csproj", "{A02922EF-22BD-4526-A6E3-3A5C7B20E618}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {A02922EF-22BD-4526-A6E3-3A5C7B20E618}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {A02922EF-22BD-4526-A6E3-3A5C7B20E618}.Debug|Any CPU.Build.0 = Debug|Any CPU + {A02922EF-22BD-4526-A6E3-3A5C7B20E618}.Release|Any CPU.ActiveCfg = Release|Any CPU + {A02922EF-22BD-4526-A6E3-3A5C7B20E618}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/Program.cs b/Program.cs new file mode 100644 index 0000000..b1664f4 --- /dev/null +++ b/Program.cs @@ -0,0 +1,165 @@ +using System.Net; +using System.Text; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Routing; +using Microsoft.AspNetCore.Server.Kestrel.Core; +using Microsoft.Extensions.DependencyInjection; +using Newtonsoft.Json.Linq; +using OllamaSharp; +using OllamaSharp.Models.Chat; +using ProxyKit; + + +namespace Onllama.MondrianGateway +{ + internal class Program + { + static void Main(string[] args) + { + try + { + var ollama = new OllamaApiClient(new Uri("http://localhost:11434")); + var paths = new List + { + "/api/generate", "/api/chat", "/api/tags", "/api/embed", "/api/show", "/api/ps", "/api/embeddings" + }; + + var host = new WebHostBuilder() + .UseKestrel() + .UseContentRoot(AppDomain.CurrentDomain.SetupInformation.ApplicationBase) + .ConfigureServices(services => + { + services.AddRouting(); + services.AddProxy(httpClientBuilder => + httpClientBuilder.ConfigureHttpClient(client => + client.Timeout = TimeSpan.FromMinutes(5))); + }) + .ConfigureKestrel(options => + { + options.ListenAnyIP(18080, + listenOptions => listenOptions.Protocols = HttpProtocols.Http1AndHttp2); + }) + .Configure(app => + { + app.Use(async (context, next) => + { + var token = context.Request.Headers.ContainsKey("Authorization") + ? context.Request.Headers.Authorization.ToString().Split(' ').Last().ToString() + : string.Empty; + //if (token != "sk-") + if (false) + { + context.Response.Headers.ContentType = "application/json"; + context.Response.StatusCode = (int) HttpStatusCode.Forbidden; + await context.Response.WriteAsync(new JObject() + { + { + "error", new JObject() + { + { + "message", + "Authentication Fails, You need to provide a valid API key in the Authorization header using Bearer authentication (i.e. Authorization: Bearer YOUR_KEY)." + }, + {"type", "invalid_request_error"} + } + } + }.ToString()); + } + else + { + context.Items["Token"] = token; + await next.Invoke(); + } + }); + + foreach (var path in paths) + app.Map(path, svr => + { + svr.RunProxy(async context => + { + var response = new HttpResponseMessage(); + try + { + response = await context.ForwardTo(new Uri("http://127.0.0.1:11434" + path)) + .Send(); + response.Headers.Add("X-Forwarder-By", "MondrianGateway/0.1"); + return response; + } + catch (Exception e) + { + Console.WriteLine(e); + return response; + } + }); + }); + + app.Map("/v1", svr => + { + svr.RunProxy(async context => + { + HttpResponseMessage response; + try + { + if (context.Request.Method.ToUpper() == "POST") + { + var body = await new StreamReader(context.Request.Body).ReadToEndAsync(); + var jBody = JObject.Parse(body); + + if (jBody["model"]?.ToString() == "gpt-3.5-turbo") jBody["model"] = "qwen2.5:7b"; + Console.WriteLine(jBody.ToString()); + + var msgs = jBody["messages"]?.ToObject>(); + await foreach (var res in ollama.ChatAsync(new ChatRequest() + {Model = "shieldgemma:2b", Messages = msgs, Stream = false})) + { + Console.WriteLine(res?.Message.Content); + var risks = res?.Message.Content?.ToLower(); + if (risks != null && (risks.Contains("yes") || risks.Contains("unsafe"))) + { + return new HttpResponseMessage(HttpStatusCode.UnavailableForLegalReasons) + { + Content = new StringContent(new JObject() + { + { + "error", new JObject() + { + {"message", "Messages with content security risks. Unable to continue."}, + {"type", "content_risks"}, + {"risk_model", res?.Model}, + {"risk_raw_msg", res?.Message.Content} + } + } + }.ToString()) + }; + } + } + + context.Request.Body = new MemoryStream(Encoding.UTF8.GetBytes(jBody.ToString())); + context.Request.ContentLength = context.Request.Body.Length; + } + + response = await context.ForwardTo(new Uri("http://127.0.0.1:11434/v1")).Send(); + response.Headers.Add("X-Forwarder-By", "MondrianGateway/0.1"); + return response; + } + catch (Exception e) + { + Console.WriteLine(e); + response = await context.ForwardTo(new Uri("http://127.0.0.1:11434/v1")).Send(); + return response; + } + }); + }); + }).Build(); + + host.Run(); + } + catch (Exception e) + { + Console.WriteLine(e); + } + } + } +}