Calling python script from C# - c#

I have a C# code which helps to run python environment first and then it executes my python process. But the problem is it takes a lot of time to execute.
Actually i just want to pass my values and execute single line of code in python script. But need to execute all python code every time. Is there a way to run python process out side and just run the single line when i want.
I attached both C# code and python process with this
C# Code
public String Insert(float[] values)
{
// full path of python interpreter
string python = #"C:\ProgramData\Anaconda2\python.exe";
// python app to call
string myPythonApp = #"C:\classification.py";
// dummy parameters to send Python script
//int x = 2;
//int y = 5;
// Create new process start info
ProcessStartInfo myProcessStartInfo = new ProcessStartInfo(python);
// make sure we can read the output from stdout
myProcessStartInfo.UseShellExecute = false;
myProcessStartInfo.RedirectStandardOutput = true;
myProcessStartInfo.CreateNoWindow = true;
myProcessStartInfo.WindowStyle = ProcessWindowStyle.Minimized;
// start python app with 3 arguments
// 1st arguments is pointer to itself, 2nd and 3rd are actual arguments we want to send
myProcessStartInfo.Arguments = myPythonApp + " " + values[0] + " " + values[1] + " " + values[2] + " " + values[3] + " " + values[4] + " " + values[5];
Process myProcess = new Process();
// assign start information to the process
myProcess.StartInfo = myProcessStartInfo;
myProcess.Start();
// Read the standard output of the app we called.
// in order to avoid deadlock we will read output first and then wait for process terminate:
StreamReader myStreamReader = myProcess.StandardOutput;
string myString = myStreamReader.ReadLine();
/*if you need to read multiple lines, you might use:
string myString = myStreamReader.ReadToEnd() */
// wait exit signal from the app we called and then close it.
myProcess.WaitForExit();
myProcess.Close();
// write the output we got from python app
Console.WriteLine("Value received from script: " + myString);
Console.WriteLine("Value received from script: " + myString);
And python Script
import numpy as np
import sys
val1 = float(sys.argv[1])
val2 = float(sys.argv[2])
val3 = float(sys.argv[3])
val4 = float(sys.argv[4])
val5 = float(sys.argv[5])
val6 = float(sys.argv[6])
# Load dataset
url = "F:\FINAL YEAR PROJECT\Amila\data2.csv"
names = ['JawLower', 'BrowLower', 'BrowRaiser', 'LipCornerDepressor', 'LipRaiser','LipStretcher','Emotion_Id']
dataset = pandas.read_csv(url, names=names)
# shape
# print(dataset.shape)
# class distribution
# print(dataset.groupby('Emotion_Id').size())
# Split-out validation dataset
array = dataset.values
X = array[:,0:6]
Y = array[:,6]
neigh = KNeighborsClassifier(n_neighbors=3)
neigh.fit(X, Y)
print(neigh.predict([[val1,val2,val3,val4,val5,val6]]))
print(neigh.predict([[val1,val2,val3,val4,val5,val6]])) this is the line of code i want to execute separatly.

I would suggest you to use REST API to call python code from C# application.
To achieve that you need to use two libraries: CPickle and flask
Expose line of code as a function and annotate
Serialise your model after training and load when predicting
Please refer to this code, I have created in python 3.5
from sklearn import datasets
from sklearn.ensemble import RandomForestClassifier
import pickle
from flask import Flask, abort, jsonify, request
import numpy as np
import json
app = Flask(__name__)
#app.route('/api/create', methods=['GET'])
def create_model():
iris = datasets.load_iris()
x = iris.data
y = iris.target
model = RandomForestClassifier(n_estimators=100, n_jobs=2)
model.fit(x, y)
pickle.dump(model, open("iris_model.pkl", "wb"))
return "done"
def default(o):
if isinstance(o, np.integer):
return int(o)
raise TypeError
#app.route('/api/predict', methods=['POST'])
def make_predict():
my_rfm = pickle.load(open("iris_model.pkl", "rb"))
data = request.get_json(force=True)
predict_request = [data['sl'], data['sw'], data['pl'], data['pw']]
predict_request = np.array(predict_request)
output = my_rfm.predict(predict_request)[0]
return json.dumps({'result': np.int32(output)}, default=default)
if __name__ == '__main__':
app.run(port=8000, debug=True)
you can run it as:

You'll need to create a new process in order to call your program.
look at this : C# equivalent to fork()/exec()

Why don't you actually use Python to run the code instead of embedding in C#? How are you going to deploy on another machine with Python dependencies?
If you would like to build machine learning models there are many frameworks like http://accord-framework.net/ for classic machine learning algorithms
Also try my project as well: deepakkumar1984/SiaNet (https://github.com/deepakkumar1984/SiaNet) Its a C# wrapper with CNTK backend. Trying to implement keras like wrapper. Hope it helps!

Related

.NET: C# System.Diagnostics.Process fails to access Shared drive images if being launch as Service, but works correctly launched as a normal.exe

1-) I create a Python .exe which includes this code:
def main():
args = parse_arguments()
result = []
paths = args.files
regions = args.regions
oddplate = args.oddplate
result = []
#print ("Input args ")
#print (args)
#print ("\n")
if not args.sdk_url and not args.api_key:
raise Exception('api-key is required')
if len(paths) == 0:
print('File {} does not exist.'.format(args.FILE))
return
elif args.blur_dir and not os.path.exists(args.blur_dir):
print('{} does not exist'.format(args.blur_dir))
return
....
print(result)
return result
2-) Then, i create a c# function from .net (lets call it ProcessFunc), which includes this code
ProcessStartInfo myProcessStartInfo = new ProcessStartInfo();
// make sure we can read the output from stdout and that window is not shown
myProcessStartInfo.UseShellExecute = false;
myProcessStartInfo.RedirectStandardOutput = true;
myProcessStartInfo.CreateNoWindow = true;
myProcessStartInfo.FileName = dir_app;
// start python app with 9 arguments
myProcessStartInfo.Arguments = " " + Iapi_key + " " + Isdk_url + " " + Iregions + " " + Iblur_amount + " " + Ioddplate + " " + Iblur_dir;
Process myProcess = new Process();
// assign start information to the process
myProcess.StartInfo = myProcessStartInfo;
// start the process
myProcess.Start();
// Read the standard output of the app we called.
// in order to avoid deadlock we will read output first
// and then wait for process terminate:
StreamReader myStreamReader = myProcess.StandardOutput;
string myString = myStreamReader.ReadLine();
/*if you need to read multiple lines, you might use:
string myString = myStreamReader.ReadToEnd() */
// wait exit signal from the app we called and then close it.
myProcess.WaitForExit();
myProcess.Close();
// write the output we got from python app
//Console.WriteLine("Value received from script: " + myString);
return myString;
3-) I have 3 drives, C,N(local machine) and Z (net shared drive)
Having c# code compiled (which generates a .exe) i called the python generated .exe 2 ways:
Double clicking the c# .exe after introducing that code in a main program (lets call it MyCProgramMain)
static void Main()
{
ProcessFunc();
}
This works correctly (Iblur_dir parameter path is accepted)
Generating a service:
static void Main()
{
System.Threading.Thread.CurrentThread.CurrentCulture = new
System.Globalization.CultureInfo("es-ES");
ServiceBase[] ServicesToRun;
ServicesToRun = new ServiceBase[]
{
new MyService()
};
ServiceBase.Run(ServicesToRun);
}
Which will create a Thead:
public MyService()
{
InitializeComponent();
HEjecucion = new Thread(classEjecucion.ProcessFunc);
HEjecucion.Start();
Afterwards i will start the generated Service.
When doing it this way, i will get this message in my log (for example):
Z:\2021-08-18\14 does not exist
This will only happen with paths in Z:\ drive, N:\ and C:\ will be accepted.
So, when calling the Python.exe through a Main program focused generated c# .exe
*os.path.exists(args.blur_dir)* understands the path exists
but if i call that same Python.exe through a Service generated with C#, it is unable to access args.blur_dir path
I have tried:
Creating a app.manifest in c#project which includes
(perhaps it was related to priviliges)
Playing around with myProcessStartInfo parameters to see if something could make
I have spent lot of time trying multiple things related to C# Process() parameters, but nothing seems to work in order to make the Service 'reach' the dir_blur path. ¿What else could i try?
You are alright guys! Problem was i was working on a remote desktop in where i was login with an specific user.
Service was automatically installed as 'Local system', and all i had to do was go to Services, in my service "properties" and in 'login' tab introduce credentials i use for remote desktop access.

How to mimic Stdin input when running an exe from C# using create process?

I have an audio converter .exe that i want to wrap in a C# program, for UI and inputs etc.
To use the AudioConverter.exe, it is ran from the console with the suffix " < inputFile > ouputFile".
So the full line reads something like
C:\\User\Audioconverter.exe < song.wav > song.ogg
So far i have been able to start the converter succesfully outside of C#, I have managed to have the converter run via create process in C# in a hang state (without input and output files).
My code in C# thus far is pretty similar to the answers given on this site:
using System;
using System.Diagnostics;
namespace ConverterWrapper2
{
class Program
{
static void Main()
{
LaunchCommandLineApp();
}
static void LaunchCommandLineApp()
{
// For the example
const string ex1 = "C:\\Users\\AudioConverter.exe";
const string ex2 = "C:\\Users\\res\\song.wav";
const string ex3 = "C:\\Users\\out\\song.ogg";
// Use ProcessStartInfo class
ProcessStartInfo startInfo = new ProcessStartInfo();
startInfo.CreateNoWindow = false;
startInfo.UseShellExecute = false;
startInfo.FileName = "AudioConverter2.exe";
startInfo.WindowStyle = ProcessWindowStyle.Normal;
startInfo.Arguments = ex1 + " < " + ex2 + " > " + ex3; \\Process is ran successfully without the addition of input and output files, but hangs waiting for files.
try
{
using (Process exeProcess = Process.Start(startInfo))
{
exeProcess.WaitForExit();
}
}
catch
{
// Log error.
}
}
}
}
So far the converter exe hasnt been able to start up correctly, this leads me to ask the question are inputs for stdin different from arguments?
Regardless i need to mimic this style of input and would appreciate any information. I had assumed that i could just pass the input and output files as arguments but i havent had much luck.
startInfo.Arguments = ex1 + " < " + ex2 + " > " + ex3; \\Process is ran successfully without the addition of input and output files, but hangs waiting for files.
That won't work.
A.exe < B > C is not process A.exe called with arguments < B > C. It's rather a shell instruction to:
start A.exe without arguments,
read file B and redirect its contents to the new process' stdin and
write the new process' stdout to file C.
You have two options to do that in C#:
You can use the help of the shell, i.e., you can start cmd.exe with arguments /c C:\User\Audioconverter.exe < song.wav > song.ogg or
you can re-implement what the shell is doing in C#. A code example for that can be found in this related question:
redirecting output to the text file c#

Passing Variable Between C# And Python (IronPython?)

I am trying to pass a variable from a C# application, which is being used as an API connection.
Essentially Outsystems produces a signal, which the C# applications picks up. I then want to pass this (single integer) variable onto my python code (labelled msg in my code below), so that it can run the function using it.
I have researched, and it looks like ironpython has a solution:
{
ScriptRuntimeSetup setup = Python.CreateRuntimeSetup(null);
ScriptRuntime runtime = new ScriptRuntime(setup);
ScriptEngine engine = Python.GetEngine(runtime);
ScriptSource source = engine.CreateScriptSourceFromFile("C:\\Scripts\\12\\Testpy\\Testpy\\Testpy.py");
ScriptScope scope = engine.CreateScope();
List<String> argv = new List<String>();
//Do some stuff and fill argv
argv.Add(msg);
engine.GetSysModule().SetVariable("argv", argv);
source.Execute(scope);
}
However, it seems to do nothing (no error, just stops executing) when it gets the the source.Execute(scope) side.
I'd imagine (?) it's because my python code isn't set up to receive variables yet. However, this is the part that I am unsure on how to write.
I - unfortunately - have little experience in passing values into python scripts, but have set up the following simple example (that is python script to python script) that seems to be working okay:
pyA
import pyB
pyB.some_func(2)
pyB
def some_func(a):
print(a)
some_func()
Alternatively, if anyone can recommend another non-Iron Python way, that would also be amazing!
Thanks in advance!! Much appreciated!
From code link in this vid: https://www.youtube.com/watch?v=g1VWGdHRkHs
var psi = new ProcessStartInfo();
psi.FileName = #"C:\PythonInstall\python.exe";
// 2) Provide script and arguments
var script = #"C:\AllTech\Code\DaysBetweenDates.py";
var start = "2019-1-1";
var end = "2019-1-22";
psi.Arguments = $"\"{script}\" \"{start}\" \"{end}\"";
// 3) Process configuration
psi.UseShellExecute = false;
psi.CreateNoWindow = true;
psi.RedirectStandardOutput = true;
psi.RedirectStandardError = true;
// 4) Execute process and get output
var errors = "";
var results = "";
using(var process = Process.Start(psi))
{
errors = process.StandardError.ReadToEnd();
results = process.StandardOutput.ReadToEnd();
}
// 5) Display output
Console.WriteLine("ERRORS:");
Console.WriteLine(errors);
Console.WriteLine();
Console.WriteLine("Results:");
Console.WriteLine(results);

Communicating between C# and Python

I'm having a little bit of a problem with communication between C# and Python.
I'm passing some arguments to Python from C# using the following hacky code:
string path = Path.GetDirectoryName(Assembly.GetExecutingAssembly().CodeBase).Substring(6);
string pyUnintelligibilityPath = "\\unintelligibility.py";
string pyNeuralPredictorPath = "\\predict.py";
string clf = "\\clf.pkl";
public double unintelligibleProbability(string pyLocation, string msg)
{
FileStream tempMessage = new FileStream(path + "\\tempMessage.txt", FileMode.Create);
StreamWriter writer = new StreamWriter(tempMessage);
writer.WriteLine(msg);
writer.Close();
string args = path + pyUnintelligibilityPath + " " + path + clf + " " + path + "\\tempMessage.txt" + " " + path + "\\tempCoefficient.txt";
ProcessStartInfo start = new ProcessStartInfo();
start.FileName = pyLocation;
start.Arguments = args;
start.UseShellExecute = false;
start.RedirectStandardOutput = false;
start.RedirectStandardError = false;
Process process = Process.Start(start);
Thread.Sleep(5000);
double unintelligibility = Convert.ToDouble(File.ReadAllText(path + "\\tempCoefficient.txt").Replace('.', ','));
return unintelligibility;
}
Unfortunately, this solution is very inefficient in my situation (not even due to the fact that I don't have any code that checks if the file changes as that will be added later and it's not really the problem I'm having).
The thing is, the Python code takes a very long time to load the .pkl file before it can actually do anything useful (don't mind the unnecessary imports, I just reused this thing from some other file):
from sklearn.feature_extraction.text import TfidfTransformer, CountVectorizer, TfidfVectorizer
from sklearn.linear_model import LogisticRegression, SGDClassifier
from sklearn.svm import LinearSVC
from sklearn.cross_validation import cross_val_score
from sklearn.pipeline import Pipeline
from sklearn.decomposition import NMF, TruncatedSVD
from sklearn.ensemble import RandomForestClassifier, GradientBoostingClassifier
from sklearn.pipeline import FeatureUnion
from sklearn.externals import joblib
import numpy as np
import pandas as pd
import codecs
import sys
clf = joblib.load(sys.argv[1])
data = codecs.open(sys.argv[2], encoding='utf-8', mode='r')
text = data.readlines()
data.close()
text = [x.strip() for x in text]
f = open(sys.argv[3], mode='w')
proba = clf.predict_proba(text)
for i in range(0, len(text)):
meme = proba[i,:]
memeNum = meme[1]/(meme[0]+meme[1])
f.write(str(memeNum.round(4)) + "\n")
f.close()
My question is, is it possible to re-write the code in a way that allows me to keep a Python script running in the background and C# just passing commands to it since reinitializing the script every single time I need to process a single message takes way too long.
Keep in mind that I would really like to not to use any network protocol-based solutions as that overcomplicates things to a point where it's not really worth it to me, I really don't care about doing this remotely or anything like that, everything's happenning locally. However, if it's the only option, then I guess I have no choice.
Try IronPython, it's a .Net - Python bridge. Or basicly you can access .net stuff from python or interpret python from c#.

execute python functions return results to c#

I have a python file filled with functions that I need to post using jsonrpc. Currently I can post the functions to the desired site and get results in python. But now I want to run the the python script from C#, get the results and do something with them. I am having troubles getting the python script to run and return the results to C#
I prefer to not download IronPython, so a solution that doesn't use it would be helpful.
What happens now is it there is a shell that pop ups quick then disappears when the Process.Start(start)) line is hit. Then nothing is returned to the reader.
Python Code:
#!usr/bin/python
import sys
import json
import jsonrpclib
def dc_906(orderid, givexNum, amount):
jsonrpclib.config.use_jsonclass = True
server = jsonrpclib.Server('https://dev-dataconnect.com:50')
ping1 = server.dc_906('en', orderid, 'userid', 'password', num, amount)
print jsonrpclib.history.response #this could be a "return" instead of print, not sure.
if __name__ == "__main__":
function = sys.argv[1]
orderid = sys.argv[2]
num = sys.argv[3]
amount = sys.argv[4]
if function == 'dc_906':
dc_906(orderid, num, amount)
C# code to execute the process (gotten from: How do I run a Python script from C#?)
try
{
ProcessStartInfo start = new ProcessStartInfo();
start.FileName = #"C:\Python27\python.exe"; //full path to python.exe
//start.FileName = #"C:\Windows\system32\cmd.exe";
//start.Arguments = string.Format("{0} {1} {2} {3}", #"C:\Users\J1035\Documents\Python27\GiveX_python\test.py", "123456789", "603628982592000186162", 20.00);
start.Arguments = string.Format("{0} {1}", #"C:\Users\J1035\Documents\Python27\GiveX_python\test.py", "123456789 603628982592000186162 20.00");
start.UseShellExecute = false;
start.RedirectStandardOutput = true;
using(Process process = Process.Start(start))
using (StreamReader reader = process.StandardOutput)
{
string foo = reader.ReadToEnd();
TxtResultOutput.Text += foo;
}
}
catch (Exception ex)
{
var foo = ex.Message;
}
Results from running the python script on the command line:
It looks like you're forgetting the "dc_906" in your arguments line. Your function isn't being called without it.

Categories

Resources