#include "prompt.h" TsfnContext::TsfnContext(Napi::Env env, const PromptWorkContext& pc) : deferred_(Napi::Promise::Deferred::New(env)), pc(pc) { } namespace { static std::string *res; } bool response_callback(int32_t token_id, const char *response) { *res += response; return token_id != -1; } bool recalculate_callback (bool isrecalculating) { return isrecalculating; }; bool prompt_callback (int32_t tid) { return true; }; // The thread entry point. This takes as its arguments the specific // threadsafe-function context created inside the main thread. void threadEntry(TsfnContext* context) { static std::mutex mtx; std::lock_guard lock(mtx); res = &context->pc.res; // Perform a call into JavaScript. napi_status status = context->tsfn.BlockingCall(&context->pc, [](Napi::Env env, Napi::Function jsCallback, PromptWorkContext* pc) { llmodel_prompt( *pc->inference_, pc->question.c_str(), &prompt_callback, &response_callback, &recalculate_callback, &pc->prompt_params ); }); if (status != napi_ok) { Napi::Error::Fatal( "ThreadEntry", "Napi::ThreadSafeNapi::Function.NonBlockingCall() failed"); } // Release the thread-safe function. This decrements the internal thread // count, and will perform finalization since the count will reach 0. context->tsfn.Release(); } void FinalizerCallback(Napi::Env env, void* finalizeData, TsfnContext* context) { // Resolve the Promise previously returned to JS context->deferred_.Resolve(Napi::String::New(env, context->pc.res)); // Wait for the thread to finish executing before proceeding. context->nativeThread.join(); delete context; }