wsl support

This commit is contained in:
meelstorm
2025-08-28 16:30:29 +02:00
parent 07002dd875
commit bf13a5ea2d
4 changed files with 169 additions and 45 deletions

View File

@@ -8,6 +8,7 @@ public class CSharpDataTransferHTTP
private readonly HttpClient _client;
private readonly CancellationTokenSource _pingCts = new();
private readonly Thread _pingThread;
private readonly object _lock = new();
public CSharpDataTransferHTTP()
{
@@ -15,22 +16,17 @@ public class CSharpDataTransferHTTP
{
PooledConnectionIdleTimeout = TimeSpan.FromSeconds(10),
MaxConnectionsPerServer = 100
};
_client = new HttpClient(handler)
{
// i've added this
DefaultRequestHeaders =
{
ExpectContinue = false
}
};
_api = new PythonModelAPI("http://localhost:8000",_client);
_api = new PythonModelAPI("http://localhost:8000", _client);
_pingThread = new Thread(PingLoop) { IsBackground = true };
_pingThread.Start();
}
private void PingLoop()
@@ -51,38 +47,40 @@ public class CSharpDataTransferHTTP
public void LoadModel(string path, string modelName)
{
_api.LoadModelAsync(new LoadModelIn()
lock (_lock)
{
Name = modelName,
Path = Path.GetFileName(path)
}).Wait();
_api.LoadModelAsync(new LoadModelIn()
{
Name = modelName,
Path = Path.GetFileName(path)
}).Wait();
}
}
public void ActivateModel(string modelName)
{
_api.ActivateModelAsync(new ActivateModelIn(){Name = modelName}).Wait();
lock (_lock)
{
_api.ActivateModelAsync(new ActivateModelIn() { Name = modelName }).Wait();
}
}
public int[] GetAcceptSize()
{
var response = _api.GetAcceptSizeAsync().Result;
return response.Accept_size.ToArray();
}
public int[] GetOutputSize()
{
var response = _api.GetOutputSizeAsync().Result;
return response.Accept_size.ToArray();
}
public byte[] PredictRaw(byte[] byteArray)
{
var response = _api.PredictRawAsync(new FileParameter(new MemoryStream(byteArray))).Result;
var stream = response.Stream;
// read the stream to byte array
using var memoryStream = new MemoryStream();
stream.CopyTo(memoryStream);
memoryStream.Seek(0, SeekOrigin.Begin);
@@ -92,16 +90,15 @@ public class CSharpDataTransferHTTP
public byte[] Predict(byte[] byteArray)
{
var response = _api.PredictAsync(new FileParameter(new MemoryStream(byteArray))).Result;
var stream = response.Stream;
// read the stream to byte array
using var memoryStream = new MemoryStream();
stream.CopyTo(memoryStream);
memoryStream.Seek(0, SeekOrigin.Begin);
var responseBytes = memoryStream.ToArray();
return responseBytes;
lock (_lock)
{
var response = _api.PredictAsync(new FileParameter(new MemoryStream(byteArray))).Result;
var stream = response.Stream;
using var memoryStream = new MemoryStream();
stream.CopyTo(memoryStream);
memoryStream.Seek(0, SeekOrigin.Begin);
var responseBytes = memoryStream.ToArray();
return responseBytes;
}
}
}

View File

@@ -0,0 +1,78 @@
using System.Diagnostics;
using static IronPython.Modules._ast;
namespace Hawkeye.VisionBuilder.Workflow.DataTransfer;
public class DockerScriptRunner
{
private Process process;
private readonly string _workingDirectory;
public DockerScriptRunner(string workingDirectory)
{
_workingDirectory = workingDirectory;
}
public static string ConvertToWslPath(string windowsPath)
{
if (string.IsNullOrWhiteSpace(windowsPath))
throw new ArgumentException("Path cannot be null or empty.", nameof(windowsPath));
// Replace backslashes with forward slashes
string wslPath = windowsPath.Replace('\\', '/');
// Extract the drive letter and convert it to WSL format
if (wslPath.Length > 1 && wslPath[1] == ':')
{
char driveLetter = char.ToLower(wslPath[0]);
wslPath = $"/mnt/{driveLetter}{wslPath.Substring(2)}";
}
return wslPath;
}
public void Start()
{
var killContainerArg = @"-d ubuntu -u root -e sh -c ""docker rm -f cv || true""";
var killProcess = new Process
{
StartInfo = new ProcessStartInfo("wsl", killContainerArg)
{
UseShellExecute = false
}
};
killProcess.Start();
killProcess.WaitForExit();
killProcess.Dispose();
//startInfo.CreateNoWindow = true;
// create and start the process
process = new Process();
var convertedWd = ConvertToWslPath(_workingDirectory);
var arg =
$@"-d ubuntu -u root -e sh -c ""cd \""{convertedWd}\"" && docker run --rm --name cv --gpus all -it -p 8000:8000 -v \""$(pwd)\"":/app -w /app cv uvicorn --host 0.0.0.0 PythonModelAPI:app """;
Console.WriteLine("args:"+arg);
process.StartInfo = new ProcessStartInfo("wsl", arg)
{
UseShellExecute = false,
CreateNoWindow = true
};
process.Start();
// on windows only
if (Environment.OSVersion.Platform == PlatformID.Win32NT)
ChildProcessTracker.AddProcess(process);
}
public void Stop()
{
if (process != null && !process.HasExited)
{
process.Kill();
process.Dispose();
process = null;
}
}
}

View File

@@ -1,21 +1,53 @@
namespace Hawkeye.VisionBuilder.Workflow.DataTransfer;
using Serilog;
namespace Hawkeye.VisionBuilder.Workflow.DataTransfer;
public class PythonModelProxyHTTP
{
private static bool _isInitialized = false;
private static UvicornScriptRunner _pythonScriptRunner;
private static DockerScriptRunner _pythonScriptRunner;
private static CSharpDataTransferHTTP _cSharpDataTransferHTTP;
static object _lock = new object();
public static void Initialize()
{
if (_isInitialized) return;
lock (_lock)
{
if (_isInitialized) return;
_isInitialized = true;
var workDirAbsPath = Path.GetFullPath(@"..\Data\Models");
_pythonScriptRunner = new UvicornScriptRunner(workDirAbsPath);
_cSharpDataTransferHTTP = new CSharpDataTransferHTTP();
var workDirAbsPath = Path.GetFullPath(@"..\Data\Models");
_pythonScriptRunner = new DockerScriptRunner(workDirAbsPath);
_pythonScriptRunner.Start();
Thread.Sleep(1000); // Wait for the server to start
_pythonScriptRunner.Start();
// Wait for the server to start by checking if port 8000 is open
while (true)
{
try
{
HttpClient http = new HttpClient();
// check if 404 occurs on localhost:8000
var response = http.GetAsync("http://127.0.0.1:8000/").Result;
if (response.StatusCode == System.Net.HttpStatusCode.NotFound ||
response.StatusCode == System.Net.HttpStatusCode.OK)
{
break; // Port is open
}
}
catch
{
Log.Debug("Waiting for port to open");
// Ignore exceptions and retry
}
Thread.Sleep(1000); // Wait before retrying
}
Thread.Sleep(2000);
_cSharpDataTransferHTTP = new CSharpDataTransferHTTP();
}
}
public static CSharpDataTransferHTTP GetInterface()