Create a python interop service and wire it up

This commit is contained in:
2026-02-15 21:24:05 -08:00
parent daa61fabf3
commit 1343e93a59
4 changed files with 97 additions and 42 deletions
+9 -6
View File
@@ -1,12 +1,15 @@
import os
import yfinance as yf import yfinance as yf
import pandas as pd import pandas as pd
class DataPuller:
@staticmethod
def pull(): def pull():
# Get the CWD for pathing due to being called from C# now
SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
DATA_DIR = os.path.join(SCRIPT_DIR, "data")
# Import the S&P 500 symbols # Import the S&P 500 symbols
symbols = pd.read_excel("./data/stock_symbols.xlsx") symbols = pd.read_excel(os.path.join(DATA_DIR, "stock_symbols.xlsx"))
symbols.columns = symbols.columns.str.strip() symbols.columns = symbols.columns.str.strip()
tickers = symbols['Symbol'].tolist() tickers = symbols['Symbol'].tolist()
@@ -49,5 +52,5 @@ class DataPuller:
final_df.dropna(inplace=True) final_df.dropna(inplace=True)
print("Writing data to file") print("Writing data to file")
final_df.to_parquet("./data/stocks.parquet") final_df.to_parquet(os.path.join(DATA_DIR, "stocks.parquet"))
final_df.head(200).to_csv("./data/stocks_preview.csv") final_df.head(200).to_csv(os.path.join(DATA_DIR, "stocks.preview.csv"))
+36
View File
@@ -0,0 +1,36 @@
using Python.Runtime;
namespace PythonInterop {
public class AIModule {
public AIModule(string PythonPath = "/usr/lib/libpython3.11.so") {
// Use the user provided python runner
Runtime.PythonDLL = PythonPath;
string baseDir = AppDomain.CurrentDomain.BaseDirectory;
string pythonFiles = Path.Combine(baseDir, "AIPython");
string venvRoot = Path.Combine(pythonFiles, "python");
string venvPkgs = Path.Combine(venvRoot, "lib/python3.11/site-packages");
// Use our local environment for the python libraries
PythonEngine.PythonHome = venvRoot;
// Include all the paths for python packages most importantly our venv
PythonEngine.PythonPath = $"/usr/lib/python3.11:/usr/lib/python3.11/lib-dynload:{pythonFiles}:{venvPkgs}";
// Initiilize python
PythonEngine.Initialize();
}
// This is thread blocking, runs on the main thread, and takes multiple minutes so probabaly need to run on a background thread at some point
public void PullData() {
using (Py.GIL()) {
dynamic datapuller = Py.Import("datapuller");
dynamic result = datapuller.pull();
}
}
}
}
+9 -3
View File
@@ -1,4 +1,5 @@
using WebServer.Components; using WebServer.Components;
using PythonInterop;
var builder = WebApplication.CreateBuilder(args); var builder = WebApplication.CreateBuilder(args);
@@ -9,15 +10,20 @@ builder.Services.AddRazorComponents()
var app = builder.Build(); var app = builder.Build();
// Configure the HTTP request pipeline. // Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment()) if (!app.Environment.IsDevelopment()) {
{
app.UseExceptionHandler("/Error", createScopeForErrors: true); app.UseExceptionHandler("/Error", createScopeForErrors: true);
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts. // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts(); app.UseHsts();
} }
app.UseHttpsRedirection(); // Load the module in globally
AIModule interopModule = new AIModule();
// Run this for testing purposes
interopModule.PullData();
app.UseHttpsRedirection();
app.UseAntiforgery(); app.UseAntiforgery();
+10
View File
@@ -6,4 +6,14 @@
<ImplicitUsings>enable</ImplicitUsings> <ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup> </PropertyGroup>
<ItemGroup>
<PackageReference Include="pythonnet" Version="3.0.5" />
</ItemGroup>
<ItemGroup>
<None Update="AIPython\**\*">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>
</Project> </Project>