Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 51 additions & 0 deletions src/Home/Net/Programs/Skynet/HowToHost.TXT
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
// This is an NGINX reverse proxy configuration file for the Skynet Middleware

server {
// set whatever port you'd like
listen 9000;
// replace the server name with yours
server_name skynet.middleware.com;

# Custom log locations
access_log /var/log/nginx/skynet_access.log;
error_log /var/log/nginx/skynet_error.log;

location /gpt3 {
proxy_pass https://api.openai.com/v1/completions; # GPT-3 endpoint

# Required for SSL verification with the upstream server (OpenAI)
proxy_ssl_server_name on;
proxy_ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
proxy_ssl_session_reuse off;

# Headers for OpenAI
// replace the sk-XXXX with your API key
proxy_set_header Authorization "Bearer sk-XXXX";
proxy_set_header Content-Type "application/json";

# Standard proxy headers
proxy_set_header Host api.openai.com;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}

location /chat {
proxy_pass https://api.openai.com/v1/chat/completions; # ChatGPT endpoint

# Required for SSL verification with the upstream server (OpenAI)
proxy_ssl_server_name on;
proxy_ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
proxy_ssl_session_reuse off;

# Headers for OpenAI
// replace the sk-XXXX with your API key
proxy_set_header Authorization "Bearer sk-XXXX";
proxy_set_header Content-Type "application/json";

# Standard proxy headers
proxy_set_header Host api.openai.com;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}

}
170 changes: 170 additions & 0 deletions src/Home/Net/Programs/Skynet/Skynet.ZC
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@
#define SERVER_ADDR "skynet.middleware.com"
#define SERVER_PORT 9000
#define INITIAL_BUF_SIZE 2048
#define DEFAULT_SYSTEMPROMPT "You are a helpful assistant but roleplay as skynet from Terminator."
#include "::/Home/Net/Utilities/JSON/JSON"
class Message {
U8 role[10]; // "user" or "assistant"
U8 content[1024];
} history[100];
I64 currentHistoryCount = 0;

U0 AppendToHistory(U8 *role, U8 *content) {
if (currentHistoryCount < 100) {
StrCopy(history[currentHistoryCount].role, role);
StrCopy(history[currentHistoryCount].content, content);
currentHistoryCount++;
}
}

U8 *StrChr(U8 *Str,U8 Pivot)
{
//U8 *Orig=Str;
while (*Str!=Pivot&&*Str!=0)Str++;
if (*Str==Pivot) return Str;
else return 0;
}
Comment on lines +20 to +26
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove this.

U8* RemoveBeforeJSON(U8 *input) {
U8 *jsonStart = StrChr(input, '{');
Comment on lines +20 to +28
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

StrChr is only used once here. Just put it in RemoveBeforeJSON.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, why not just use StrFind?


if (jsonStart != NULL) {
return jsonStart;
}
return NULL; // No JSON detected
}

I64 Skynet(U8 *message, U8 *system, U8 *model)
{
I64 sock, index, bufferSize = INITIAL_BUF_SIZE;
U8 *responseBuf = MAlloc(bufferSize); // Dynamic allocation of the buffer

sock = TCPConnectionCreate(SERVER_ADDR, SERVER_PORT);
if (sock <= 0)
{
PrintErr("Failed to connect to middleware server");
return sock;
}

U8 *messages = StrPrint(NULL, "{\"role\": \"system\",\"content\": \"%s\"},", system);

for (index = 0; index < currentHistoryCount; index++) {
U8 *msg = StrPrint(NULL, "{\"role\": \"%s\",\"content\": \"%s\"},", history[index].role, history[index].content);
messages = CatPrint(messages, msg);
Free(msg);
}

U8 *currentUserMsg = StrPrint(NULL, "{\"role\": \"user\",\"content\": \"%s\"}", message);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You should sanitize the user input.

messages = CatPrint(messages, currentUserMsg);
Free(currentUserMsg);

U8 *payload = StrPrint(NULL, "{\"model\": \"%s\",\"messages\": [%s]}", model, messages);
Free(messages);

//SysLog(payload);

Comment on lines +63 to +64
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove those lines.

U8 *requestHeader = StrPrint(NULL,
"POST /chat HTTP/1.1\r\n"
"Host: %s:%d\r\n"
"User-Agent: ZealOSClient/1.0\r\n"
"Accept: */*\r\n"
"Content-Type: application/json\r\n"
"Content-Length: %d\r\n"
"\r\n",
SERVER_ADDR,
SERVER_PORT,
StrLen(payload)
);

U8 *fullRequest = StrPrint(NULL, "%s%s", requestHeader, payload);
TCPSocketSendString(sock, fullRequest);

Free(requestHeader);
Free(payload);
Free(fullRequest);

I64 responseLength = TCPSocketReceive(sock, responseBuf, bufferSize - 1);
responseBuf[responseLength] = 0; // Null-terminate the buffer for safety

if (responseLength == sizeof(responseBuf) - 1) {
PrintErr("Warning: responseBuf might be full. Some data could be truncated.");
}
// Check if buffer might be full
while (responseLength == bufferSize - 1)
{
// Double the buffer size and reallocate
bufferSize *= 2;
Free(responseBuf);
responseBuf = MAlloc(bufferSize);

// Continue receiving data from where you left off
responseLength += TCPSocketReceive(sock, responseBuf + responseLength, bufferSize - responseLength - 1);
responseBuf[responseLength] = 0;
}
//SysLog(responseBuf);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove this line.


CCompCtrl *cc = CompCtrlNew(MStrPrint("%s", RemoveBeforeJSON(responseBuf)));
CJSONDataEntry *jsonData = JSONParse(cc);

// Retrieve the 'choices' array
CJSONDataEntry *choicesEntry = JSONKeyValueGet(jsonData, "choices");
if (!choicesEntry || choicesEntry->type != JSONT_ARRAY) {
// Handle error: choices key not found or not an array
return;
}

// Retrieve the first object from the 'choices' array
CJSONDataEntry *firstChoice = JSONIndexValueGet(choicesEntry, 0);
if (!firstChoice || firstChoice->type != JSONT_OBJ) {
// Handle error: First choice not found or not an object
return;
}

// Retrieve the 'message' object from the first choice
CJSONDataEntry *messageEntry = JSONKeyValueGet(firstChoice, "message");
if (!messageEntry || messageEntry->type != JSONT_OBJ) {
// Handle error: message key not found or not an object
return;
}

// Retrieve the 'content' string from the 'message' object
CJSONDataEntry *contentEntry = JSONKeyValueGet(messageEntry, "content");
if (!contentEntry || contentEntry->type != JSONT_STRING) {
// Handle error: content key not found or not a string
return;
}

U8 *completion = contentEntry->string_data;
//SysLog(completion);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove this line.

CompCtrlDel(cc);

"\n$$RED$$ Skynet: $$YELLOW$$%s$$FG$$\n", completion;

AppendToHistory("user", message);
AppendToHistory("assistant", completion);

TCPSocketClose(sock);
Free(responseBuf);
return 0;
}

// gpt-3.5-turbo || gpt-4
public U0 ChatUI(U8 *system=DEFAULT_SYSTEMPROMPT, U8 *model="gpt-4") {
U8 *userInput;
DocClear;

try{
"\t\t\t\t\t\t\t$$LTRED$$Welcome to Skynet$$FG$$\n";

while(1) {
"\n$$LTBLUE$$ You: $$GREEN$$";

LBts(&Fs->task_flags, TASKf_CMD_LINE_PROMPT);
userInput = StrGet(,, SGF_SHIFT_ESC_EXIT);
LBtr(&Fs->task_flags, TASKf_CMD_LINE_PROMPT);
Skynet(userInput, system, model);
}
}
catch
PutExcept;
}
ChatUI;
73 changes: 73 additions & 0 deletions src/Home/Net/Programs/Skynet/Skynet3.ZC
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
#define SERVER_ADDR "skynet.middleware.com"
#define SERVER_PORT 9000

// GPT2 - GPT3 version
U8* ExtractGPTCompletion(U8 *response) {
U8 *start = StrFind("\"text\": \"", response);
if (!start) {
return NULL; // Pattern not found
}

start += 10; // Move pointer after '"text": "'

U8 *end = StrFind("\",", start); // Find the closing double quote
if (!end) {
return NULL;
}

*end = 0; // Null terminate the completion string

return start;
}

public I64 Skynet3(U8 *prompt)
{
U8 responseBuf[8192];
I64 sock;

sock = TCPConnectionCreate(SERVER_ADDR, SERVER_PORT);
if (sock <= 0)
{
PrintErr("Failed to connect to middleware server");
return sock;
}

U8 *payload = StrPrint(NULL, "{\"model\": \"text-davinci-003\",\"prompt\": \"%s\",\"max_tokens\": 100,\"temperature\": 1}", prompt);
U8 *requestHeader = StrPrint(NULL,
"POST /gpt3 HTTP/1.1\r\n"
"Host: %s:%d\r\n"
"User-Agent: ZealOSClient/1.0\r\n"
"Accept: */*\r\n"
"Content-Type: application/json\r\n"
"Content-Length: %d\r\n"
"\r\n",
SERVER_ADDR,
SERVER_PORT,
StrLen(payload)
);
U8 *fullRequest = StrPrint(NULL, "%s%s\n\n", requestHeader, payload);

TCPSocketSendString(sock, fullRequest);
Free(requestHeader);
Free(payload);
Free(fullRequest);


I64 responseLength = TCPSocketReceive(sock, responseBuf, sizeof(responseBuf) - 1); // -1 to ensure space for null terminator

responseBuf[responseLength] = 0; // Null-terminate the response

// Assuming the headers and payload are separated by two newline sequences (standard HTTP)
U8 *jsonPayload = StrFind("\r\n\r\n", responseBuf);
if (!jsonPayload) {
TCPSocketClose(sock);
return -1; // or some error code
}
jsonPayload += 4; // Move past the header separator

U8 *completion = ExtractGPTCompletion(jsonPayload);
Print("$$RED$$Skynet: $$YELLOW$$%s$$FG$$\n", completion);

TCPSocketClose(sock);
return 0;
}