4 changed files with 232 additions and 11 deletions
@ -0,0 +1,152 @@ |
|||||
|
#pragma once |
||||
|
#include "ofMain.h" |
||||
|
#include "ofThread.h" |
||||
|
#include <condition_variable> |
||||
|
#include <mutex> |
||||
|
#include <atomic> |
||||
|
#include <string> |
||||
|
#include "ofxNetwork.h" |
||||
|
|
||||
|
|
||||
|
class LLMRequestThread : public ofThread { |
||||
|
public: |
||||
|
LLMRequestThread() {} |
||||
|
~LLMRequestThread() { |
||||
|
stop(); |
||||
|
waitForThread(false); |
||||
|
} |
||||
|
|
||||
|
void setup(std::string url_) { |
||||
|
url = url_; |
||||
|
resultReady = false; |
||||
|
startThread(); |
||||
|
} |
||||
|
|
||||
|
void requestPromptTest(std::string newPrompt) { |
||||
|
std::unique_lock<std::mutex> lock(mutex); |
||||
|
prompt = newPrompt; |
||||
|
resultReady = false; |
||||
|
hasNewPrompt = true; |
||||
|
condition.notify_all(); // wake thread to start processing
|
||||
|
} |
||||
|
|
||||
|
void requestPrompt(const std::string& speaker_, const std::string& text_, const std::string& emotion_, const float temp_) { |
||||
|
std::unique_lock<std::mutex> lock(mutex); |
||||
|
speaker = speaker_; |
||||
|
text = text_; |
||||
|
emotion = emotion_; |
||||
|
llmTemperature = temp_; |
||||
|
resultReady = false; |
||||
|
hasNewPrompt = true; |
||||
|
condition.notify_all(); // wake thread to start processing
|
||||
|
} |
||||
|
|
||||
|
std::string getResult() { |
||||
|
std::unique_lock<std::mutex> lock(mutex); |
||||
|
return result; |
||||
|
} |
||||
|
|
||||
|
bool isResultReady() { |
||||
|
return resultReady.load(); |
||||
|
} |
||||
|
|
||||
|
void stop() { |
||||
|
std::unique_lock<std::mutex> lock(mutex); |
||||
|
stopThread(); |
||||
|
condition.notify_all(); |
||||
|
} |
||||
|
|
||||
|
protected: |
||||
|
void threadedFunction() override { |
||||
|
while (isThreadRunning()) { |
||||
|
std::unique_lock<std::mutex> lock(mutex); |
||||
|
condition.wait(lock, [this] { return hasNewPrompt || !isThreadRunning(); }); |
||||
|
|
||||
|
if (!isThreadRunning()) break; |
||||
|
|
||||
|
std::string localSpeaker = speaker; |
||||
|
std::string localBody = text; |
||||
|
std::string localEmotion = emotion; |
||||
|
float localTemp = llmTemperature; |
||||
|
|
||||
|
hasNewPrompt = false; |
||||
|
lock.unlock(); // unlock during HTTP request
|
||||
|
|
||||
|
// Do HTTP POST request to FastAPI
|
||||
|
std::string responseText = makeRequest(localSpeaker, localBody, localEmotion, localTemp); |
||||
|
|
||||
|
lock.lock(); |
||||
|
result = responseText; |
||||
|
resultReady = true; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
std::string makeRequest(const std::string& speaker_, const std::string& text_, const std::string& emotion_, const float temp_) { |
||||
|
ofxTCPClient client; |
||||
|
std::string host = "127.0.0.1"; // or extract from your url
|
||||
|
int port = 8000; // or extract from your url
|
||||
|
|
||||
|
// Connect to server
|
||||
|
if (!client.setup(host, port, false)) { |
||||
|
return "Error: Could not connect"; |
||||
|
} |
||||
|
|
||||
|
// Prepare HTTP POST request
|
||||
|
// Build JSON body with all fields
|
||||
|
std::string body = "{\"speaker\":\"" + speaker_ + "\"," |
||||
|
"\"sentence\":\"" + text_ + "\"," |
||||
|
"\"emotion\":\"" + emotion_ + "\"," |
||||
|
"\"temp\":" + ofToString(temp_) + "}"; |
||||
|
|
||||
|
ofLog() << body; |
||||
|
|
||||
|
std::string request = |
||||
|
"POST /generate HTTP/1.1\r\n" |
||||
|
"Host: " + host + "\r\n" |
||||
|
"Content-Type: application/json\r\n" |
||||
|
"Content-Length: " + std::to_string(body.size()) + "\r\n" |
||||
|
"Connection: close\r\n" |
||||
|
"\r\n" + |
||||
|
body; |
||||
|
|
||||
|
client.sendRaw(request); |
||||
|
|
||||
|
// Wait for response (simple, not robust)
|
||||
|
std::string response; |
||||
|
uint64_t startTime = ofGetElapsedTimeMillis(); |
||||
|
while (ofGetElapsedTimeMillis() - startTime < 3000) { // 3s timeout
|
||||
|
std::string received = client.receiveRaw(); |
||||
|
if (!received.empty()) { |
||||
|
response += received; |
||||
|
} |
||||
|
if (response.find("\r\n\r\n") != std::string::npos) break; // End of headers
|
||||
|
ofSleepMillis(10); |
||||
|
} |
||||
|
client.close(); |
||||
|
|
||||
|
// Extract body (after \r\n\r\n)
|
||||
|
size_t pos = response.find("\r\n\r\n"); |
||||
|
if (pos != std::string::npos) { |
||||
|
std::string body = response.substr(pos + 4); |
||||
|
// Optionally parse JSON here
|
||||
|
return body; |
||||
|
} else { |
||||
|
return "Error: No response body"; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
private: |
||||
|
std::string url; |
||||
|
std::string prompt; |
||||
|
|
||||
|
std::string speaker; |
||||
|
std::string text; |
||||
|
std::string emotion; |
||||
|
float llmTemperature; |
||||
|
|
||||
|
std::string result; |
||||
|
std::condition_variable condition; |
||||
|
std::mutex mutex; |
||||
|
std::atomic<bool> resultReady; |
||||
|
bool hasNewPrompt = false; |
||||
|
}; |
Loading…
Reference in new issue