@@ -373,7 +373,24 @@ ov::Any py_object_to_any(const py::object& py_obj, std::string property_name) {
373373 } else if (py::isinstance<ov::genai::Generator>(py_obj)) {
374374 return py::cast<std::shared_ptr<ov::genai::Generator>>(py_obj);
375375 } else if (py::isinstance<py::function>(py_obj) && property_name == " callback" ) {
376- return py::cast<std::function<bool (size_t , size_t , ov::Tensor&)>>(py_obj);
376+ auto py_callback = py::cast<py::function>(py_obj);
377+ auto shared_callback = std::shared_ptr<py::function>(
378+ new py::function (py_callback),
379+ [](py::function* f) {
380+ if (Py_IsInitialized ()) {
381+ PyGILState_STATE gstate = PyGILState_Ensure ();
382+ delete f;
383+ PyGILState_Release (gstate);
384+ }
385+ }
386+ );
387+
388+ return std::function<bool (size_t , size_t , ov::Tensor&)>(
389+ [shared_callback](size_t step, size_t num_steps, ov::Tensor& latent) -> bool {
390+ py::gil_scoped_acquire acquire;
391+ return (*shared_callback)(step, num_steps, latent).cast <bool >();
392+ }
393+ );
377394 } else if ((py::isinstance<py::function>(py_obj) || py::isinstance<ov::genai::StreamerBase>(py_obj) || py::isinstance<std::monostate>(py_obj)) && property_name == " streamer" ) {
378395 auto streamer = py::cast<ov::genai::pybind::utils::PyBindStreamerVariant>(py_obj);
379396 return ov::genai::streamer (pystreamer_to_streamer (streamer)).second ;
@@ -437,12 +454,25 @@ ov::genai::StreamerVariant pystreamer_to_streamer(const PyBindStreamerVariant& p
437454
438455 std::visit (overloaded {
439456 [&streamer](const std::function<std::optional<uint16_t >(py::str)>& py_callback){
440- // Wrap python streamer with manual utf-8 decoding. Do not rely
441- // on pybind automatic decoding since it raises exceptions on incomplete strings.
442- auto callback_wrapped = [py_callback](std::string subword) -> ov::genai::StreamingStatus {
457+ auto shared_callback = std::shared_ptr<std::function<std::optional<uint16_t >(py::str)>>(
458+ new std::function<std::optional<uint16_t >(py::str)>(py_callback),
459+ [](std::function<std::optional<uint16_t >(py::str)>* f) {
460+ if (Py_IsInitialized ()) {
461+ PyGILState_STATE gstate = PyGILState_Ensure ();
462+ delete f;
463+ PyGILState_Release (gstate);
464+ }
465+ }
466+ );
467+
468+ auto callback_wrapped = [shared_callback](std::string subword) -> ov::genai::StreamingStatus {
443469 py::gil_scoped_acquire acquire;
444- auto py_str = PyUnicode_DecodeUTF8 (subword.data (), subword.length (), " replace" );
445- std::optional<uint16_t > callback_output = py_callback (py::reinterpret_borrow<py::str>(py_str));
470+ PyObject* py_str = PyUnicode_DecodeUTF8 (subword.data (), subword.length (), " replace" );
471+ if (!py_str) {
472+ PyErr_Clear ();
473+ return StreamingStatus::RUNNING;
474+ }
475+ std::optional<uint16_t > callback_output = (*shared_callback)(py::reinterpret_steal<py::str>(py_str));
446476 if (callback_output.has_value ()) {
447477 if (*callback_output == (uint16_t )StreamingStatus::RUNNING)
448478 return StreamingStatus::RUNNING;
0 commit comments