From 2770c4fe22865853339fb95f51ada01ea236eef9 Mon Sep 17 00:00:00 2001 From: Jicheng Lu <103353@smsassist.com> Date: Tue, 30 Sep 2025 12:10:02 -0500 Subject: [PATCH] init code interpret service --- .../CodeInterpreter/ICodeInterpretService.cs | 10 +++ .../Models/CodeInterpretOptions.cs | 5 ++ .../Models/CodeInterpretResult.cs | 8 ++ .../Functions/PyProgrammerFn.cs | 2 +- .../PythonInterpreterPlugin.cs | 1 + .../Services/PyInterpretService.cs | 87 +++++++++++++++++++ .../Using.cs | 3 + 7 files changed, 115 insertions(+), 1 deletion(-) create mode 100644 src/Infrastructure/BotSharp.Abstraction/CodeInterpreter/ICodeInterpretService.cs create mode 100644 src/Infrastructure/BotSharp.Abstraction/CodeInterpreter/Models/CodeInterpretOptions.cs create mode 100644 src/Infrastructure/BotSharp.Abstraction/CodeInterpreter/Models/CodeInterpretResult.cs create mode 100644 src/Plugins/BotSharp.Plugin.PythonInterpreter/Services/PyInterpretService.cs diff --git a/src/Infrastructure/BotSharp.Abstraction/CodeInterpreter/ICodeInterpretService.cs b/src/Infrastructure/BotSharp.Abstraction/CodeInterpreter/ICodeInterpretService.cs new file mode 100644 index 00000000..05afe3c1 --- /dev/null +++ b/src/Infrastructure/BotSharp.Abstraction/CodeInterpreter/ICodeInterpretService.cs @@ -0,0 +1,10 @@ +using BotSharp.Abstraction.CodeInterpreter.Models; + +namespace BotSharp.Abstraction.CodeInterpreter; + +public interface ICodeInterpretService +{ + string Provider { get; } + + Task RunCode(string code, List? arguments = null, CodeInterpretOptions? options = null); +} diff --git a/src/Infrastructure/BotSharp.Abstraction/CodeInterpreter/Models/CodeInterpretOptions.cs b/src/Infrastructure/BotSharp.Abstraction/CodeInterpreter/Models/CodeInterpretOptions.cs new file mode 100644 index 00000000..ded31cbe --- /dev/null +++ b/src/Infrastructure/BotSharp.Abstraction/CodeInterpreter/Models/CodeInterpretOptions.cs @@ -0,0 +1,5 @@ +namespace BotSharp.Abstraction.CodeInterpreter.Models; + +public class CodeInterpretOptions +{ +} diff --git a/src/Infrastructure/BotSharp.Abstraction/CodeInterpreter/Models/CodeInterpretResult.cs b/src/Infrastructure/BotSharp.Abstraction/CodeInterpreter/Models/CodeInterpretResult.cs new file mode 100644 index 00000000..30b44a97 --- /dev/null +++ b/src/Infrastructure/BotSharp.Abstraction/CodeInterpreter/Models/CodeInterpretResult.cs @@ -0,0 +1,8 @@ +namespace BotSharp.Abstraction.CodeInterpreter.Models; + +public class CodeInterpretResult +{ + public object Result { get; set; } + public bool Success { get; set; } + public string? ErrorMsg { get; set; } +} diff --git a/src/Plugins/BotSharp.Plugin.PythonInterpreter/Functions/PyProgrammerFn.cs b/src/Plugins/BotSharp.Plugin.PythonInterpreter/Functions/PyProgrammerFn.cs index 43820cc3..477778a0 100644 --- a/src/Plugins/BotSharp.Plugin.PythonInterpreter/Functions/PyProgrammerFn.cs +++ b/src/Plugins/BotSharp.Plugin.PythonInterpreter/Functions/PyProgrammerFn.cs @@ -99,7 +99,7 @@ public class PyProgrammerFn : IFunctionCallback Language = "python" } }; - //message.StopCompletion = true; + message.StopCompletion = true; // Restore the original stdout/stderr sys.stdout = sys.__stdout__; diff --git a/src/Plugins/BotSharp.Plugin.PythonInterpreter/PythonInterpreterPlugin.cs b/src/Plugins/BotSharp.Plugin.PythonInterpreter/PythonInterpreterPlugin.cs index 14ae5dc2..168d83f8 100644 --- a/src/Plugins/BotSharp.Plugin.PythonInterpreter/PythonInterpreterPlugin.cs +++ b/src/Plugins/BotSharp.Plugin.PythonInterpreter/PythonInterpreterPlugin.cs @@ -22,6 +22,7 @@ public class PythonInterpreterPlugin : IBotSharpAppPlugin services.AddSingleton(x => settings); services.AddScoped(); + services.AddScoped(); } public void Configure(IApplicationBuilder app) diff --git a/src/Plugins/BotSharp.Plugin.PythonInterpreter/Services/PyInterpretService.cs b/src/Plugins/BotSharp.Plugin.PythonInterpreter/Services/PyInterpretService.cs new file mode 100644 index 00000000..5fe00abf --- /dev/null +++ b/src/Plugins/BotSharp.Plugin.PythonInterpreter/Services/PyInterpretService.cs @@ -0,0 +1,87 @@ +using BotSharp.Abstraction.Models; +using Microsoft.Extensions.Logging; +using Python.Runtime; +using System.Threading.Tasks; + +namespace BotSharp.Plugin.PythonInterpreter.Services; + +public class PyInterpretService : ICodeInterpretService +{ + private readonly IServiceProvider _services; + private readonly ILogger _logger; + + public PyInterpretService( + IServiceProvider services, + ILogger logger) + { + _services = services; + _logger = logger; + } + + public string Provider => "python-interpreter"; + + public async Task RunCode(string code, List? arguments = null, CodeInterpretOptions? options = null) + { + try + { + using (Py.GIL()) + { + // Import necessary Python modules + dynamic sys = Py.Import("sys"); + dynamic io = Py.Import("io"); + + // Redirect standard output/error to capture it + dynamic stringIO = io.StringIO(); + sys.stdout = stringIO; + sys.stderr = stringIO; + + // Set global items + using var globals = new PyDict(); + if (code.Contains("__main__") == true) + { + globals.SetItem("__name__", new PyString("__main__")); + } + + // Set arguments + if (!arguments.IsNullOrEmpty()) + { + sys.argv = new PyList(); + sys.argv.Append("code.py"); + + foreach (var arg in arguments) + { + sys.argv.Append($"--{arg.Key}"); + sys.argv.Append($"{arg.Value}"); + } + } + + // Execute Python script + PythonEngine.Exec(code, globals); + + // Get result + var result = stringIO.getvalue().ToString(); + + // Restore the original stdout/stderr + sys.stdout = sys.__stdout__; + sys.stderr = sys.__stderr__; + + return new CodeInterpretResult + { + Result = result, + Success = true + }; + } + } + catch (Exception ex) + { + var errorMsg = $"Error when executing python code in {nameof(PyInterpretService)}-{Provider}. {ex.Message}"; + _logger.LogError(ex, errorMsg); + + return new CodeInterpretResult + { + Success = false, + ErrorMsg = errorMsg + }; + } + } +} diff --git a/src/Plugins/BotSharp.Plugin.PythonInterpreter/Using.cs b/src/Plugins/BotSharp.Plugin.PythonInterpreter/Using.cs index 73d0bc86..11a023fe 100644 --- a/src/Plugins/BotSharp.Plugin.PythonInterpreter/Using.cs +++ b/src/Plugins/BotSharp.Plugin.PythonInterpreter/Using.cs @@ -20,6 +20,8 @@ global using BotSharp.Abstraction.Messaging; global using BotSharp.Abstraction.Messaging.Models.RichContent; global using BotSharp.Abstraction.Messaging.Models.RichContent.Template; global using BotSharp.Abstraction.Routing; +global using BotSharp.Abstraction.CodeInterpreter.Models; +global using BotSharp.Abstraction.CodeInterpreter; global using BotSharp.Core.Infrastructures; @@ -30,3 +32,4 @@ global using BotSharp.Plugin.PythonInterpreter.Functions; global using BotSharp.Plugin.PythonInterpreter.Hooks; global using BotSharp.Plugin.PythonInterpreter.Models; global using BotSharp.Plugin.PythonInterpreter.Helpers; +global using BotSharp.Plugin.PythonInterpreter.Services; \ No newline at end of file