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#.
Related
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.
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#
I have the following code for converting xml to csv by using perl script. When I run the perl script through c# but there is no files are created and string output become empty.
What is the problem?
I have the perl script with .txt extention, Is this ok or not?
string filePath = Path.GetDirectoryName(Path.GetDirectoryName(Directory.GetCurrentDirectory())) + "/Files/SAVVIS_CDR_1806012231.XML";
if (Path.GetExtension(filePath) != "csv")
{
ProcessStartInfo perlStartInfo = new ProcessStartInfo(#"C:\Strawberry\perl\bin\perl.exe");
string perlScriptFilePath = Path.GetDirectoryName(Path.GetDirectoryName(Directory.GetCurrentDirectory())) + "/PerlScript/formatter_savvis.pl.txt";
string csvFilePath = Path.GetDirectoryName(Path.GetDirectoryName(Directory.GetCurrentDirectory())) + "/PerlScript/";
perlStartInfo.Arguments = perlScriptFilePath + " " + filePath + " " + csvFilePath;
perlStartInfo.UseShellExecute = false;
perlStartInfo.RedirectStandardOutput = true;
perlStartInfo.RedirectStandardError = true;
perlStartInfo.CreateNoWindow = false;
Process perl = new Process();
perl.StartInfo = perlStartInfo;
perl.Start();
perl.WaitForExit();
string output = perl.StandardOutput.ReadToEnd();
}
Could you please anyone help me to solve this problem?
Thanks in advance.
First, to find out what went wrong:
string error = perl.StandardError.ReadToEnd();
Also, make sure you have necessary permissions to create files in the output directory. You may try to run your process with Admin privileges to find out if it's a permission issue:
perlStartInfo.Verb = "runas";
You may want to run your entire host process with elevated permissions for this.
(This is only to figure out if it's a permission issue! If it's the case, grant the output directory the necessary permissions, and if possible don't automatically run scripts with admin privileges in production environment)
There also may be errors in the perl script itself.
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!
Can someone help me with this issue?
I currently working on my project for final year of my honors degree. And we are developing a application to evaluate programming assignments of student ( for 1st year student level)
I just want to know how to integrate C++ compiler using C# code to compile C++ code.
In our case we are loading a student C++ code into text area, then with a click on button we want to compile the code. And if there any compilation errors it will be displayed on text area nearby. (Interface is attached herewith.)
And finally it able to execute the code if there aren't any compilation errors. And results will be displayed in console.
We were able to do this with a C#(C# code will be loaded to text area intead of C++ code) code using inbuilt compiler. But still not able to do for C# code.
Can anyone suggest a method to do this? It is possible to integrate external compiler to VS C# code? If possible how to achieve it?
Very grateful if anyone will contributing to solve this matter?
This is code for Build button which we proceed with C# code compiling
CodeDomProvider codeProvider = CodeDomProvider.CreateProvider("csharp");
string Output = "Out.exe";
Button ButtonObject = (Button)sender;
rtbresult.Text = "";
System.CodeDom.Compiler.CompilerParameters parameters = new CompilerParameters();
//Make sure we generate an EXE, not a DLL
parameters.GenerateExecutable = true;
parameters.OutputAssembly = Output;
CompilerResults results = codeProvider.CompileAssemblyFromSource(parameters, rtbcode.Text);
if (results.Errors.Count > 0)
{
rtbresult.ForeColor = Color.Red;
foreach (CompilerError CompErr in results.Errors)
{
rtbresult.Text = rtbresult.Text +
"Line number " + CompErr.Line +
", Error Number: " + CompErr.ErrorNumber +
", '" + CompErr.ErrorText + ";" +
Environment.NewLine + Environment.NewLine;
}
}
else
{
//Successful Compile
rtbresult.ForeColor = Color.Blue;
rtbresult.Text = "Success!";
//If we clicked run then launch our EXE
if (ButtonObject.Text == "Run") Process.Start(Output); // Run button
}
there is unfortunately no default implementation for CodeDom for C++, you can always define your own if you want to use the same code as the above to compile C++.
Or you can call cl.exe directly, In both cases you would have to manually invoke cl.exe
http://msdn.microsoft.com/en-us/library/19z1t1wy(v=VS.71).aspx
It shouldn't that hard. write the code to a temporary file, call cl.exe pipe any output to a window you want (or not) and the end, check if a exe has been produced, if it has compilation succeeded and you can run the exe, if not it failed and the error should be in the log you created earlier.
It's less structured than above but it's by far the easiest way.
-- more detailed
the following code assumes your environment vars are properly set. http://msdn.microsoft.com/en-us/library/f2ccy3wt(VS.80).aspx
class CL
{
private const string clexe = #"cl.exe";
private const string exe = "Test.exe", file = "test.cpp";
private string args;
public CL(String[] args)
{
this.args = String.Join(" ", args);
this.args += (args.Length > 0 ? " " : "") + "/Fe" + exe + " " + file;
}
public Boolean Compile(String content, ref string errors)
{
//remove any old copies
if (File.Exists(exe))
File.Delete(exe);
if(File.Exists(file))
File.Delete(file);
File.WriteAllText(file, content);
Process proc = new Process();
proc.StartInfo.UseShellExecute = false;
proc.StartInfo.RedirectStandardOutput = true;
proc.StartInfo.RedirectStandardError = true;
proc.StartInfo.FileName = clexe;
proc.StartInfo.Arguments = this.args;
proc.StartInfo.CreateNoWindow = true;
proc.Start();
//errors += proc.StandardError.ReadToEnd();
errors += proc.StandardOutput.ReadToEnd();
proc.WaitForExit();
bool success = File.Exists(exe);
return success;
}
}
this will compile the code given to it, but it's just a sample, everytime compilation succeeds there will be a file "Test.exe" which you can run. when it fails the "errors" variable will contain the error message.
hope this helps,
for more information on running processes, take a look at http://www.codeproject.com/KB/cs/ProcessStartDemo.aspx