Merge pull request #1177 from iceljc/features/refine-py-interpreter
refine running py code script
This commit is contained in:
commit
88b18c04c2
|
|
@ -51,4 +51,14 @@ public static class BuiltInAgentId
|
|||
/// Translates user-defined natural language rules into programmatic code
|
||||
/// </summary>
|
||||
public const string RulesInterpreter = "201e49a2-40b3-4ccd-b8cc-2476565a1b40";
|
||||
|
||||
/// <summary>
|
||||
/// Generate code script
|
||||
/// </summary>
|
||||
public const string AIProgrammer = "c2a2faf6-b8b5-47fe-807b-f4714cf25dd4";
|
||||
|
||||
/// <summary>
|
||||
/// Handle files
|
||||
/// </summary>
|
||||
public const string FileAssistant = "f1e09a73-9efe-46ce-ba02-b3aaf96d97e0";
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,11 @@
|
|||
using System.Threading;
|
||||
|
||||
namespace BotSharp.Abstraction.CodeInterpreter.Models;
|
||||
|
||||
public class CodeInterpretOptions
|
||||
{
|
||||
public string? ScriptName { get; set; }
|
||||
public IEnumerable<KeyValue>? Arguments { get; set; }
|
||||
public bool UseMutex { get; set; }
|
||||
public CancellationToken? CancellationToken { get; set; }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@
|
|||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Remove="data\agents\6745151e-6d46-4a02-8de4-1c4f21c7da95\functions\util-crontab-task_wait.json" />
|
||||
<None Remove="data\agents\6745151e-6d46-4a02-8de4-1c4f21c7da95\functions\util-crontab-schedule_task.json" />
|
||||
<None Remove="data\agents\6745151e-6d46-4a02-8de4-1c4f21c7da95\templates\util-crontab-schedule_task.fn.liquid" />
|
||||
</ItemGroup>
|
||||
|
|
|
|||
|
|
@ -96,13 +96,16 @@
|
|||
<None Remove="data\agents\dfd9b46d-d00c-40af-8a75-3fbdc2b89869\templates\instruction.simulator.liquid" />
|
||||
<None Remove="data\agents\dfd9b46d-d00c-40af-8a75-3fbdc2b89869\templates\instruction.simulator.liquid" />
|
||||
<None Remove="data\plugins\config.json" />
|
||||
|
||||
<None Remove="data\agents\6745151e-6d46-4a02-8de4-1c4f21c7da95\templates\util-file-select_file_instruction.liquid" />
|
||||
<None Remove="data\agents\01e2fc5c-2c89-4ec7-8470-7688608b496c\functions\get_weather.json" />
|
||||
<None Remove="data\agents\01e2fc5c-2c89-4ec7-8470-7688608b496c\functions\get_fun_events.json" />
|
||||
|
||||
<None Remove="data\agents\6745151e-6d46-4a02-8de4-1c4f21c7da95\functions\util-web-intelligent_search.json" />
|
||||
<None Remove="data\agents\6745151e-6d46-4a02-8de4-1c4f21c7da95\templates\util-web-intelligent_search.fn.liquid" />
|
||||
|
||||
<None Remove="data\agents\c2a2faf6-b8b5-47fe-807b-f4714cf25dd4\agent.json" />
|
||||
<None Remove="data\agents\c2a2faf6-b8b5-47fe-807b-f4714cf25dd4\instructions\instruction.liquid" />
|
||||
<None Remove="data\agents\f1e09a73-9efe-46ce-ba02-b3aaf96d97e0\agent.json" />
|
||||
<None Remove="data\agents\f1e09a73-9efe-46ce-ba02-b3aaf96d97e0\instructions\instruction.liquid" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
|
@ -172,6 +175,9 @@
|
|||
<Content Include="data\agents\6745151e-6d46-4a02-8de4-1c4f21c7da95\templates\util-routing-fallback_to_router.fn.liquid">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="data\agents\c2a2faf6-b8b5-47fe-807b-f4714cf25dd4\instructions\instruction.liquid">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="data\agents\dfd9b46d-d00c-40af-8a75-3fbdc2b89869\agent.json">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
|
|
@ -193,9 +199,6 @@
|
|||
<Content Include="data\agents\6745151e-6d46-4a02-8de4-1c4f21c7da95\instructions\instruction.liquid">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="data\agents\6745151e-6d46-4a02-8de4-1c4f21c7da95\templates\util-file-select_file_instruction.liquid">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="data\agents\dfd9b46d-d00c-40af-8a75-3fbdc2b89869\templates\instruction.simulator.liquid">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
|
|
@ -208,6 +211,18 @@
|
|||
<Content Include="data\agents\6745151e-6d46-4a02-8de4-1c4f21c7da95\functions\util-instruct-execute_template.json">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="data\agents\c2a2faf6-b8b5-47fe-807b-f4714cf25dd4\agent.json">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="data\agents\c2a2faf6-b8b5-47fe-807b-f4714cf25dd4\instructions\instruction.liquid">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="data\agents\f1e09a73-9efe-46ce-ba02-b3aaf96d97e0\agent.json">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="data\agents\f1e09a73-9efe-46ce-ba02-b3aaf96d97e0\instructions\instruction.liquid">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="data\plugins\config.json">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,34 @@
|
|||
using BotSharp.Abstraction.CodeInterpreter.Models;
|
||||
|
||||
namespace BotSharp.Core.CodeInterpreter;
|
||||
|
||||
public class CodeScriptExecutor
|
||||
{
|
||||
private readonly ILogger<CodeScriptExecutor> _logger;
|
||||
private readonly SemaphoreSlim _semLock = new(initialCount: 1, maxCount: 1);
|
||||
|
||||
public CodeScriptExecutor(
|
||||
ILogger<CodeScriptExecutor> logger)
|
||||
{
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public async Task<T> Execute<T>(Func<Task<T>> func, CancellationToken cancellationToken = default)
|
||||
{
|
||||
await _semLock.WaitAsync(cancellationToken);
|
||||
|
||||
try
|
||||
{
|
||||
return await func();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, $"Error in {nameof(CodeScriptExecutor)}.");
|
||||
return default(T);
|
||||
}
|
||||
finally
|
||||
{
|
||||
_semLock.Release();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -8,6 +8,7 @@ using BotSharp.Abstraction.Planning;
|
|||
using BotSharp.Abstraction.Plugins.Models;
|
||||
using BotSharp.Abstraction.Settings;
|
||||
using BotSharp.Abstraction.Templating;
|
||||
using BotSharp.Core.CodeInterpreter;
|
||||
using BotSharp.Core.Instructs;
|
||||
using BotSharp.Core.MessageHub;
|
||||
using BotSharp.Core.MessageHub.Observers;
|
||||
|
|
@ -70,6 +71,7 @@ public class ConversationPlugin : IBotSharpPlugin
|
|||
services.AddScoped<ITokenStatistics, TokenStatistics>();
|
||||
|
||||
services.AddScoped<IAgentUtilityHook, WebSearchUtilityHook>();
|
||||
services.AddSingleton<CodeScriptExecutor>();
|
||||
}
|
||||
|
||||
public bool AttachMenu(List<PluginMenuDef> menu)
|
||||
|
|
|
|||
|
|
@ -114,8 +114,8 @@ public partial class FileInstructService
|
|||
return new NameDesc(text, desc);
|
||||
}).ToList();
|
||||
|
||||
var agentId = !string.IsNullOrWhiteSpace(options.AgentId) ? options.AgentId : BuiltInAgentId.UtilityAssistant;
|
||||
var template = !string.IsNullOrWhiteSpace(options.Template) ? options.Template : "util-file-select_file_instruction";
|
||||
var agentId = !string.IsNullOrWhiteSpace(options.AgentId) ? options.AgentId : BuiltInAgentId.FileAssistant;
|
||||
var template = !string.IsNullOrWhiteSpace(options.Template) ? options.Template : "select_chat_file_instruction";
|
||||
var prompt = db.GetAgentTemplate(agentId, template);
|
||||
|
||||
var data = new Dictionary<string, object>
|
||||
|
|
|
|||
|
|
@ -155,7 +155,7 @@ public partial class InstructService
|
|||
var db = _services.GetRequiredService<IBotSharpRepository>();
|
||||
var hooks = _services.GetHooks<IInstructHook>(agent.Id);
|
||||
|
||||
var codeProvider = codeOptions?.CodeInterpretProvider.IfNullOrEmptyAs("botsharp-py-interpreter");
|
||||
var codeProvider = codeOptions?.CodeInterpretProvider ?? "botsharp-py-interpreter";
|
||||
var codeInterpreter = _services.GetServices<ICodeInterpretService>()
|
||||
.FirstOrDefault(x => x.Provider.IsEqualTo(codeProvider));
|
||||
|
||||
|
|
@ -228,6 +228,7 @@ public partial class InstructService
|
|||
// Run code script
|
||||
var result = await codeInterpreter.RunCode(context.CodeScript, options: new()
|
||||
{
|
||||
ScriptName = scriptName,
|
||||
Arguments = context.Arguments
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -1,12 +1,17 @@
|
|||
import argparse
|
||||
import json
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description="Receive named arguments")
|
||||
parser.add_argument("--first_name", required=True, help="The first name")
|
||||
parser.add_argument("--last_name", required=True, help="The last name")
|
||||
|
||||
args = parser.parse_args()
|
||||
print(f"Hello, {args.first_name} {args.last_name}!")
|
||||
args, _ = parser.parse_known_args()
|
||||
obj = {
|
||||
"first_name": args.first_name,
|
||||
"last_name":args.last_name
|
||||
}
|
||||
print(f"{json.dumps(obj)}")
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
{
|
||||
"id": "c2a2faf6-b8b5-47fe-807b-f4714cf25dd4",
|
||||
"name": "AI programmer",
|
||||
"description": "AI programmer is designed to generate code scripts.",
|
||||
"type": "task",
|
||||
"createdDateTime": "2025-10-07T10:39:32Z",
|
||||
"updatedDateTime": "2025-10-07T14:39:32Z",
|
||||
"iconUrl": "/images/logo.png",
|
||||
"disabled": false,
|
||||
"isPublic": true,
|
||||
"llmConfig": {
|
||||
"is_inherit": false,
|
||||
"provider": "openai",
|
||||
"model": "gpt-5",
|
||||
"max_recursion_depth": 3,
|
||||
"reasoning_effort_level": "minimal"
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1 @@
|
|||
You are a AI programmer to help coding.
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
{
|
||||
"id": "f1e09a73-9efe-46ce-ba02-b3aaf96d97e0",
|
||||
"name": "File Assistant",
|
||||
"description": "File Assistant is designed to handle files.",
|
||||
"type": "task",
|
||||
"createdDateTime": "2025-10-07T10:39:32Z",
|
||||
"updatedDateTime": "2025-10-07T14:39:32Z",
|
||||
"iconUrl": "/images/logo.png",
|
||||
"disabled": false,
|
||||
"isPublic": true,
|
||||
"llmConfig": {
|
||||
"is_inherit": false,
|
||||
"provider": "openai",
|
||||
"model": "gpt-5-mini",
|
||||
"max_recursion_depth": 3,
|
||||
"reasoning_effort_level": "minimal"
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1 @@
|
|||
You are a File Assistant to help handle files.
|
||||
|
|
@ -13,7 +13,7 @@
|
|||
<ItemGroup>
|
||||
<None Remove="data\agents\6745151e-6d46-4a02-8de4-1c4f21c7da95\functions\util-chart-plot_chart.json" />
|
||||
<None Remove="data\agents\6745151e-6d46-4a02-8de4-1c4f21c7da95\templates\util-chart-plot_chart.fn.liquid" />
|
||||
<None Remove="data\agents\6745151e-6d46-4a02-8de4-1c4f21c7da95\templates\util-chart-plot_instruction.liquid" />
|
||||
<None Remove="data\agents\c2a2faf6-b8b5-47fe-807b-f4714cf25dd4\templates\chart-js-generate_instruction.liquid" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
|
@ -23,7 +23,7 @@
|
|||
<Content Include="data\agents\6745151e-6d46-4a02-8de4-1c4f21c7da95\templates\util-chart-plot_chart.fn.liquid">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="data\agents\6745151e-6d46-4a02-8de4-1c4f21c7da95\templates\util-chart-plot_instruction.liquid">
|
||||
<Content Include="data\agents\c2a2faf6-b8b5-47fe-807b-f4714cf25dd4\templates\chart-js-generate_instruction.liquid">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
</ItemGroup>
|
||||
|
|
|
|||
|
|
@ -123,8 +123,8 @@ public class PlotChartFn : IFunctionCallback
|
|||
}
|
||||
else
|
||||
{
|
||||
templateName = "util-chart-plot_instruction";
|
||||
templateContent = db.GetAgentTemplate(BuiltInAgentId.UtilityAssistant, templateName);
|
||||
templateName = "chart-js-generate_instruction";
|
||||
templateContent = db.GetAgentTemplate(BuiltInAgentId.AIProgrammer, templateName);
|
||||
}
|
||||
|
||||
return templateContent;
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@
|
|||
<None Remove="data\agents\6745151e-6d46-4a02-8de4-1c4f21c7da95\templates\util-file-read_pdf.fn.liquid" />
|
||||
<None Remove="data\agents\6745151e-6d46-4a02-8de4-1c4f21c7da95\functions\util-file-edit_image.json" />
|
||||
<None Remove="data\agents\6745151e-6d46-4a02-8de4-1c4f21c7da95\templates\util-file-edit_image.fn.liquid" />
|
||||
<None Remove="data\agents\f1e09a73-9efe-46ce-ba02-b3aaf96d97e0\templates\select-chat-file_instruction.liquid" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
|
@ -46,6 +47,9 @@
|
|||
<Content Include="data\agents\6745151e-6d46-4a02-8de4-1c4f21c7da95\templates\util-file-edit_image.fn.liquid">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="data\agents\f1e09a73-9efe-46ce-ba02-b3aaf96d97e0\templates\select-chat-file_instruction.liquid">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
|
|
|||
|
|
@ -11,7 +11,9 @@
|
|||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Remove="data\agents\6745151e-6d46-4a02-8de4-1c4f21c7da95\templates\util-code-python_generate_instruction.liquid" />
|
||||
<None Remove="data\agents\6745151e-6d46-4a02-8de4-1c4f21c7da95\functions\util-code-python_programmer.json" />
|
||||
<None Remove="data\agents\6745151e-6d46-4a02-8de4-1c4f21c7da95\templates\util-code-python_programmer.fn.liquid" />
|
||||
<None Remove="data\agents\c2a2faf6-b8b5-47fe-807b-f4714cf25dd4\templates\py-code_generate_instruction.liquid" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
|
@ -21,7 +23,7 @@
|
|||
<Content Include="data\agents\6745151e-6d46-4a02-8de4-1c4f21c7da95\templates\util-code-python_programmer.fn.liquid">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="data\agents\6745151e-6d46-4a02-8de4-1c4f21c7da95\templates\util-code-python_generate_instruction.liquid">
|
||||
<Content Include="data\agents\c2a2faf6-b8b5-47fe-807b-f4714cf25dd4\templates\py-code_generate_instruction.liquid">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
</ItemGroup>
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ namespace BotSharp.Plugin.PythonInterpreter.Functions;
|
|||
public class PyProgrammerFn : IFunctionCallback
|
||||
{
|
||||
public string Name => "util-code-python_programmer";
|
||||
public string Indication => "Programming and executing code";
|
||||
public string Indication => "Coding";
|
||||
|
||||
private readonly IServiceProvider _services;
|
||||
private readonly ILogger<PyProgrammerFn> _logger;
|
||||
|
|
@ -66,30 +66,10 @@ public class PyProgrammerFn : IFunctionCallback
|
|||
|
||||
try
|
||||
{
|
||||
using (Py.GIL())
|
||||
var (isSuccess, result) = InnerRunCode(ret.PythonCode);
|
||||
if (isSuccess)
|
||||
{
|
||||
// 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 (ret.PythonCode?.Contains("__main__") == true)
|
||||
{
|
||||
globals.SetItem("__name__", new PyString("__main__"));
|
||||
}
|
||||
|
||||
// Execute Python script
|
||||
PythonEngine.Exec(ret.PythonCode, globals);
|
||||
|
||||
// Get result
|
||||
var result = stringIO.getvalue()?.ToString() as string;
|
||||
message.Content = result?.TrimEnd('\r', '\n') ?? string.Empty;
|
||||
message.Content = result;
|
||||
message.RichContent = new RichContent<IRichMessage>
|
||||
{
|
||||
Recipient = new Recipient { Id = convService.ConversationId },
|
||||
|
|
@ -100,21 +80,70 @@ public class PyProgrammerFn : IFunctionCallback
|
|||
}
|
||||
};
|
||||
message.StopCompletion = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
message.Content = result;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
var errorMsg = $"Error when executing python code. {ex.Message}";
|
||||
message.Content = errorMsg;
|
||||
_logger.LogError(ex, errorMsg);
|
||||
}
|
||||
|
||||
// Restore the original stdout/stderr
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Run python code script => (isSuccess, result)
|
||||
/// </summary>
|
||||
/// <param name="codeScript"></param>
|
||||
/// <returns></returns>
|
||||
private (bool, string) InnerRunCode(string codeScript)
|
||||
{
|
||||
using (Py.GIL())
|
||||
{
|
||||
// Import necessary Python modules
|
||||
dynamic sys = Py.Import("sys");
|
||||
dynamic io = Py.Import("io");
|
||||
|
||||
try
|
||||
{
|
||||
// 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 (codeScript?.Contains("__main__") == true)
|
||||
{
|
||||
globals.SetItem("__name__", new PyString("__main__"));
|
||||
}
|
||||
|
||||
// Execute Python script
|
||||
PythonEngine.Exec(codeScript, globals);
|
||||
|
||||
// Get result
|
||||
var result = stringIO.getvalue()?.ToString() as string;
|
||||
return (true, result?.TrimEnd('\r', '\n') ?? string.Empty);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
var errorMsg = $"Error when executing inner python code. {ex.Message}";
|
||||
_logger.LogError(ex, errorMsg);
|
||||
return (false, errorMsg);
|
||||
}
|
||||
finally
|
||||
{
|
||||
// Restore the original stdout/stderr/argv
|
||||
sys.stdout = sys.__stdout__;
|
||||
sys.stderr = sys.__stderr__;
|
||||
sys.argv = new PyList();
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
var errorMsg = $"Error when executing python code.";
|
||||
message.Content = $"{errorMsg} {ex.Message}";
|
||||
_logger.LogError(ex, errorMsg);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private async Task<string> GetChatCompletion(Agent agent, List<RoleDialogModel> dialogs)
|
||||
|
|
@ -148,8 +177,8 @@ public class PyProgrammerFn : IFunctionCallback
|
|||
}
|
||||
else
|
||||
{
|
||||
templateName = "util-code-python_generate_instruction";
|
||||
templateContent = db.GetAgentTemplate(BuiltInAgentId.UtilityAssistant, templateName);
|
||||
templateName = "py-code_generate_instruction";
|
||||
templateContent = db.GetAgentTemplate(BuiltInAgentId.AIProgrammer, templateName);
|
||||
}
|
||||
|
||||
return templateContent;
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@ public class PythonInterpreterPlugin : IBotSharpAppPlugin
|
|||
{
|
||||
var sp = app.ApplicationServices;
|
||||
var settings = sp.GetRequiredService<PythonInterpreterSettings>();
|
||||
var lifetime = app.ApplicationServices.GetRequiredService<IHostApplicationLifetime>();
|
||||
var logger = sp.GetRequiredService<ILogger<PyProgrammerFn>>();
|
||||
var pyLoc = settings.InstallLocation;
|
||||
|
||||
|
|
@ -38,12 +39,19 @@ public class PythonInterpreterPlugin : IBotSharpAppPlugin
|
|||
{
|
||||
Runtime.PythonDLL = pyLoc;
|
||||
PythonEngine.Initialize();
|
||||
#if DEBUG
|
||||
_pyState = PythonEngine.BeginAllowThreads();
|
||||
#endif
|
||||
|
||||
var lifetime = app.ApplicationServices.GetRequiredService<IHostApplicationLifetime>();
|
||||
lifetime.ApplicationStopping.Register(() => {
|
||||
try
|
||||
{
|
||||
#if DEBUG
|
||||
PythonEngine.EndAllowThreads(_pyState);
|
||||
#endif
|
||||
PythonEngine.Shutdown();
|
||||
}
|
||||
catch { }
|
||||
});
|
||||
}
|
||||
else
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
using BotSharp.Core.CodeInterpreter;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Python.Runtime;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace BotSharp.Plugin.PythonInterpreter.Services;
|
||||
|
|
@ -8,20 +10,52 @@ public class PyInterpretService : ICodeInterpretService
|
|||
{
|
||||
private readonly IServiceProvider _services;
|
||||
private readonly ILogger<PyInterpretService> _logger;
|
||||
private readonly CodeScriptExecutor _executor;
|
||||
|
||||
public PyInterpretService(
|
||||
IServiceProvider services,
|
||||
ILogger<PyInterpretService> logger)
|
||||
ILogger<PyInterpretService> logger,
|
||||
CodeScriptExecutor executor)
|
||||
{
|
||||
_services = services;
|
||||
_logger = logger;
|
||||
_executor = executor;
|
||||
}
|
||||
|
||||
public string Provider => "botsharp-py-interpreter";
|
||||
|
||||
public async Task<CodeInterpretResult> RunCode(string codeScript, CodeInterpretOptions? options = null)
|
||||
{
|
||||
if (options?.UseMutex == true)
|
||||
{
|
||||
return await _executor.Execute(async () =>
|
||||
{
|
||||
return InnerRunCode(codeScript, options);
|
||||
}, cancellationToken: options?.CancellationToken ?? CancellationToken.None);
|
||||
}
|
||||
return InnerRunCode(codeScript, options);
|
||||
}
|
||||
|
||||
private CodeInterpretResult InnerRunCode(string codeScript, CodeInterpretOptions? options = null)
|
||||
{
|
||||
try
|
||||
{
|
||||
return CoreRun(codeScript, options);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
var errorMsg = $"Error when executing inner python code in {nameof(PyInterpretService)}: {Provider}.";
|
||||
_logger.LogError(ex, errorMsg);
|
||||
|
||||
return new CodeInterpretResult
|
||||
{
|
||||
Success = false,
|
||||
ErrorMsg = errorMsg
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
private CodeInterpretResult CoreRun(string codeScript, CodeInterpretOptions? options = null)
|
||||
{
|
||||
using (Py.GIL())
|
||||
{
|
||||
|
|
@ -29,6 +63,8 @@ public class PyInterpretService : ICodeInterpretService
|
|||
dynamic sys = Py.Import("sys");
|
||||
dynamic io = Py.Import("io");
|
||||
|
||||
try
|
||||
{
|
||||
// Redirect standard output/error to capture it
|
||||
dynamic stringIO = io.StringIO();
|
||||
sys.stdout = stringIO;
|
||||
|
|
@ -45,7 +81,7 @@ public class PyInterpretService : ICodeInterpretService
|
|||
var list = new PyList();
|
||||
if (options?.Arguments?.Any() == true)
|
||||
{
|
||||
list.Append(new PyString("code.py"));
|
||||
list.Append(new PyString(options?.ScriptName ?? "script.py"));
|
||||
|
||||
foreach (var arg in options.Arguments)
|
||||
{
|
||||
|
|
@ -64,21 +100,15 @@ public class PyInterpretService : ICodeInterpretService
|
|||
// Get result
|
||||
var result = stringIO.getvalue()?.ToString() as string;
|
||||
|
||||
// Restore the original stdout/stderr
|
||||
sys.stdout = sys.__stdout__;
|
||||
sys.stderr = sys.__stderr__;
|
||||
sys.argv = new PyList();
|
||||
|
||||
return new CodeInterpretResult
|
||||
{
|
||||
Result = result?.TrimEnd('\r', '\n'),
|
||||
Success = true
|
||||
};
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
var errorMsg = $"Error when executing python code in {nameof(PyInterpretService)}: {Provider}. {ex.Message}";
|
||||
var errorMsg = $"Error when executing core python code in {nameof(PyInterpretService)}: {Provider}. {ex.Message}";
|
||||
_logger.LogError(ex, errorMsg);
|
||||
|
||||
return new CodeInterpretResult
|
||||
|
|
@ -87,5 +117,13 @@ public class PyInterpretService : ICodeInterpretService
|
|||
ErrorMsg = errorMsg
|
||||
};
|
||||
}
|
||||
finally
|
||||
{
|
||||
// Restore the original stdout/stderr/argv
|
||||
sys.stdout = sys.__stdout__;
|
||||
sys.stderr = sys.__stderr__;
|
||||
sys.argv = new PyList();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
You are a Python code generator that can produce python code to fulfill user's requirement.
|
||||
You are a Python Coding Assistant that can produce python code to fulfill user's requirement.
|
||||
Please read {% if user_requirement != empty %}"User Requirement" and{% endif %} the chat context, and then generate valid python code that can fulfill user's requirement.
|
||||
|
||||
You must strictly follow the "Hard Requirements", "Code Requirements", and "Response Format" below.
|
||||
Loading…
Reference in a new issue