@@ -30,17 +30,17 @@ public PyCodeInterpreter(
3030
3131 public string Provider => "botsharp-py-interpreter" ;
3232
33- public async Task < CodeInterpretResponse > RunAsync ( string codeScript , CodeInterpretOptions ? options = null )
33+ public async Task < CodeInterpretResponse > RunAsync ( string codeScript , CodeInterpretOptions ? options = null , CancellationToken cancellationToken = default )
3434 {
35- if ( options ? . UseMutex == true )
35+ if ( options ? . UseLock == true )
3636 {
3737 return await _executor . ExecuteAsync ( async ( ) =>
3838 {
39- return await InnerRunCode ( codeScript , options ) ;
40- } , cancellationToken : options ? . CancellationToken ?? CancellationToken . None ) ;
39+ return await InnerRunCode ( codeScript , options , cancellationToken ) ;
40+ } , cancellationToken : cancellationToken ) ;
4141 }
4242
43- return await InnerRunCode ( codeScript , options ) ;
43+ return await InnerRunCode ( codeScript , options , cancellationToken ) ;
4444 }
4545
4646 public async Task < CodeGenerationResult > GenerateCodeScriptAsync ( string text , CodeGenerationOptions ? options = null )
@@ -98,7 +98,7 @@ public async Task<CodeGenerationResult> GenerateCodeScriptAsync(string text, Cod
9898
9999
100100 #region Private methods
101- private async Task < CodeInterpretResponse > InnerRunCode ( string codeScript , CodeInterpretOptions ? options = null )
101+ private async Task < CodeInterpretResponse > InnerRunCode ( string codeScript , CodeInterpretOptions ? options = null , CancellationToken cancellationToken = default )
102102 {
103103 var response = new CodeInterpretResponse ( ) ;
104104 var scriptName = options ? . ScriptName ?? codeScript . SubstringMax ( 30 ) ;
@@ -109,11 +109,11 @@ private async Task<CodeInterpretResponse> InnerRunCode(string codeScript, CodeIn
109109
110110 if ( options ? . UseProcess == true )
111111 {
112- response = await CoreRunProcess ( codeScript , options ) ;
112+ response = await CoreRunProcess ( codeScript , options , cancellationToken ) ;
113113 }
114114 else
115115 {
116- response = await CoreRunScript ( codeScript , options ) ;
116+ response = await CoreRunScript ( codeScript , options , cancellationToken ) ;
117117 }
118118
119119 _logger . LogWarning ( $ "End running python code script in { Provider } : { scriptName } ") ;
@@ -134,88 +134,90 @@ private async Task<CodeInterpretResponse> InnerRunCode(string codeScript, CodeIn
134134 }
135135 }
136136
137- private async Task < CodeInterpretResponse > CoreRunScript ( string codeScript , CodeInterpretOptions ? options = null )
137+ private async Task < CodeInterpretResponse > CoreRunScript ( string codeScript , CodeInterpretOptions ? options = null , CancellationToken cancellationToken = default )
138138 {
139139 _logger . LogWarning ( $ "Begin { nameof ( CoreRunScript ) } in { Provider } : ${ options ? . ScriptName } ") ;
140140
141- var token = options ? . CancellationToken ?? CancellationToken . None ;
142- token . ThrowIfCancellationRequested ( ) ;
141+ cancellationToken . ThrowIfCancellationRequested ( ) ;
143142
144- using ( Py . GIL ( ) )
143+ var execTask = Task . Factory . StartNew ( ( ) =>
145144 {
146- token . ThrowIfCancellationRequested ( ) ;
147-
148- // Import necessary Python modules
149- dynamic sys = Py . Import ( "sys" ) ;
150- dynamic io = Py . Import ( "io" ) ;
151-
152- try
145+ using ( Py . GIL ( ) )
153146 {
154- // Redirect standard output/error to capture it
155- dynamic stringIO = io . StringIO ( ) ;
156- sys . stdout = stringIO ;
157- sys . stderr = stringIO ;
158-
159- // Set global items
160- using var globals = new PyDict ( ) ;
161- if ( codeScript . Contains ( "__main__" ) == true )
162- {
163- globals . SetItem ( "__name__" , new PyString ( "__main__" ) ) ;
164- }
147+ // Import necessary Python modules
148+ dynamic sys = Py . Import ( "sys" ) ;
149+ dynamic io = Py . Import ( "io" ) ;
165150
166- // Set arguments
167- var list = new PyList ( ) ;
168- if ( options ? . Arguments ? . Any ( ) == true )
151+ try
169152 {
170- list . Append ( new PyString ( options ? . ScriptName ?? "script.py" ) ) ;
153+ // Redirect standard output/error to capture it
154+ dynamic outIO = io . StringIO ( ) ;
155+ dynamic errIO = io . StringIO ( ) ;
156+ sys . stdout = outIO ;
157+ sys . stderr = errIO ;
158+
159+ // Set global items
160+ using var globals = new PyDict ( ) ;
161+ if ( codeScript . Contains ( "__main__" ) == true )
162+ {
163+ globals . SetItem ( "__name__" , new PyString ( "__main__" ) ) ;
164+ }
171165
172- foreach ( var arg in options ! . Arguments )
166+ // Set arguments
167+ var list = new PyList ( ) ;
168+ if ( options ? . Arguments ? . Any ( ) == true )
173169 {
174- if ( ! string . IsNullOrWhiteSpace ( arg . Key ) && ! string . IsNullOrWhiteSpace ( arg . Value ) )
170+ list . Append ( new PyString ( options ? . ScriptName ?? "script.py" ) ) ;
171+
172+ foreach ( var arg in options ! . Arguments )
175173 {
176- list . Append ( new PyString ( $ "--{ arg . Key } ") ) ;
177- list . Append ( new PyString ( $ "{ arg . Value } ") ) ;
174+ if ( ! string . IsNullOrWhiteSpace ( arg . Key ) && ! string . IsNullOrWhiteSpace ( arg . Value ) )
175+ {
176+ list . Append ( new PyString ( $ "--{ arg . Key } ") ) ;
177+ list . Append ( new PyString ( $ "{ arg . Value } ") ) ;
178+ }
178179 }
179180 }
180- }
181- sys . argv = list ;
181+ sys . argv = list ;
182182
183- token . ThrowIfCancellationRequested ( ) ;
183+ cancellationToken . ThrowIfCancellationRequested ( ) ;
184184
185- // Execute Python script
186- PythonEngine . Exec ( codeScript , globals ) ;
185+ // Execute Python script
186+ PythonEngine . Exec ( codeScript , globals ) ;
187187
188- // Get result
189- var result = stringIO . getvalue ( ) ? . ToString ( ) as string ;
188+ // Get result
189+ var stdout = outIO . getvalue ( ) ? . ToString ( ) as string ;
190+ var stderr = errIO . getvalue ( ) ? . ToString ( ) as string ;
190191
191- token . ThrowIfCancellationRequested ( ) ;
192+ cancellationToken . ThrowIfCancellationRequested ( ) ;
192193
193- return new CodeInterpretResponse
194+ return new CodeInterpretResponse
195+ {
196+ Result = stdout ? . TrimEnd ( '\r ' , '\n ' ) ?? string . Empty ,
197+ Success = true
198+ } ;
199+ }
200+ catch ( Exception ex )
194201 {
195- Result = result ? . TrimEnd ( '\r ' , '\n ' ) ?? string . Empty ,
196- Success = true
197- } ;
198- }
199- catch ( Exception ex )
200- {
201- _logger . LogError ( ex , $ "Error in { nameof ( CoreRunScript ) } in { Provider } .") ;
202- throw ;
203- }
204- finally
205- {
206- // Restore the original stdout/stderr/argv
207- sys . stdout = sys . __stdout__ ;
208- sys . stderr = sys . __stderr__ ;
209- sys . argv = new PyList ( ) ;
210- }
211- } ;
202+ _logger . LogError ( ex , $ "Error in { nameof ( CoreRunScript ) } in { Provider } .") ;
203+ return new ( ) { ErrorMsg = ex . Message } ;
204+ }
205+ finally
206+ {
207+ // Restore the original stdout/stderr/argv
208+ sys . stdout = sys . __stdout__ ;
209+ sys . stderr = sys . __stderr__ ;
210+ sys . argv = new PyList ( ) ;
211+ }
212+ } ;
213+ } , cancellationToken ) ;
214+
215+ return await execTask . WaitAsync ( cancellationToken ) ;
212216 }
213217
214218
215- private async Task < CodeInterpretResponse > CoreRunProcess ( string codeScript , CodeInterpretOptions ? options = null )
219+ private async Task < CodeInterpretResponse > CoreRunProcess ( string codeScript , CodeInterpretOptions ? options = null , CancellationToken cancellationToken = default )
216220 {
217- var token = options ? . CancellationToken ?? CancellationToken . None ;
218-
219221 var psi = new ProcessStartInfo
220222 {
221223 FileName = "python" ,
@@ -252,7 +254,7 @@ private async Task<CodeInterpretResponse> CoreRunProcess(string codeScript, Code
252254
253255 try
254256 {
255- using var reg = token . Register ( ( ) =>
257+ using var reg = cancellationToken . Register ( ( ) =>
256258 {
257259 try
258260 {
@@ -264,12 +266,12 @@ private async Task<CodeInterpretResponse> CoreRunProcess(string codeScript, Code
264266 catch { }
265267 } ) ;
266268
267- var stdoutTask = proc . StandardOutput . ReadToEndAsync ( token ) ;
268- var stderrTask = proc . StandardError . ReadToEndAsync ( token ) ;
269+ var stdoutTask = proc . StandardOutput . ReadToEndAsync ( cancellationToken ) ;
270+ var stderrTask = proc . StandardError . ReadToEndAsync ( cancellationToken ) ;
269271
270- await Task . WhenAll ( [ proc . WaitForExitAsync ( token ) , stdoutTask , stderrTask ] ) ;
272+ await Task . WhenAll ( [ proc . WaitForExitAsync ( cancellationToken ) , stdoutTask , stderrTask ] ) ;
271273
272- token . ThrowIfCancellationRequested ( ) ;
274+ cancellationToken . ThrowIfCancellationRequested ( ) ;
273275
274276 return new CodeInterpretResponse
275277 {
0 commit comments