This commit is contained in:
retoor 2025-01-05 22:59:51 +01:00
parent 574edaeb17
commit b2435720c1
9 changed files with 335 additions and 66 deletions

3
.gitignore vendored
View File

@ -5,4 +5,7 @@
gpt
gpt.c
r
rf
.docs
auth.h
.rcontext

View File

@ -1,7 +1,12 @@
all: build run
build:
gcc main.c -lssl -lcrypto -ljson-c -Ofast -o r -Werror -Wall -lpython3.14 -I/usr/include/python3.14 -lreadline -lncurses
gcc main.c -lssl -lcrypto -ljson-c -Ofast -o r -Werror -Wall -lpython3.14 -I/usr/include/python3.14 -lreadline -lncurses
publish r
build_free:
gcc main.c -DFREE_VERSION -lssl -lcrypto -ljson-c -Ofast -o rf -Werror -Wall -lpython3.14 -I/usr/include/python3.14 -lreadline -lncurses
publish rf
run:
./r

9
auth.h
View File

@ -9,7 +9,9 @@
#include <stdlib.h>
const char * resolve_api_key(){
char * api_key = getenv("R_KEY");
char * api_key;
#ifndef FREE_VERSION
api_key = getenv("R_KEY");
if(api_key)
{
return api_key;
@ -20,5 +22,8 @@ const char * resolve_api_key(){
return api_key;
}
fprintf(stderr, "\nThere is no API key configured in environment.\n");
return "";
exit(1);
#endif
api_key = "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";
return api_key;
}

10
chat.h
View File

@ -28,15 +28,19 @@
// SOFTWARE.
#ifndef CALPACA_PROMPT_H
#define CALPACA_PROMPT_H
#ifndef R_PROMPT_H
#define R_PROMPT_H
#include <json-c/json.h>
#include "messages.h"
#include "http.h"
#ifndef FREE_VERSION
char *prompt_model = "gpt-4o-mini";
int prompt_max_tokens = 100;
#else
char *prompt_model = "gpt-3.5-turbo";
#endif
int prompt_max_tokens = 2048;
double prompt_temperature = 0.5;
json_object *_prompt = NULL;

320
http.h
View File

@ -6,8 +6,8 @@
// MIT License
#ifndef CALPACA_HTTP_H
#define CALPACA_HTTP_H
#ifndef R_HTTP_H
#define R_HTTP_H
#include <stdio.h>
#include <string.h>
@ -19,17 +19,22 @@
#include <openssl/err.h>
#include "auth.h"
#include <json-c/json.h>
#include <stdbool.h>
#include "url.h"
void init_openssl() {
void init_openssl()
{
SSL_load_error_strings();
OpenSSL_add_ssl_algorithms();
}
void cleanup_openssl() {
void cleanup_openssl()
{
EVP_cleanup();
}
SSL_CTX *create_context() {
SSL_CTX *create_context()
{
const SSL_METHOD *method = TLS_method();
SSL_CTX *ctx = SSL_CTX_new(method);
SSL_CTX_load_verify_locations(ctx, "/etc/ssl/certs/ca-certificates.crt", NULL);
@ -37,10 +42,12 @@ SSL_CTX *create_context() {
return ctx;
}
SSL_CTX *create_context2() {
SSL_CTX *create_context2()
{
const SSL_METHOD *method = TLS_client_method();
SSL_CTX *ctx = SSL_CTX_new(method);
if (!ctx) {
if (!ctx)
{
perror("Unable to create SSL context");
ERR_print_errors_fp(stderr);
exit(EXIT_FAILURE);
@ -49,18 +56,21 @@ SSL_CTX *create_context2() {
return ctx;
}
int create_socket(const char *hostname, int port) {
int create_socket(const char *hostname, int port)
{
struct hostent *host;
struct sockaddr_in addr;
host = gethostbyname(hostname);
if (!host) {
if (!host)
{
perror("Unable to resolve host");
exit(EXIT_FAILURE);
}
int sock = socket(AF_INET, SOCK_STREAM, 0);
if (sock < 0) {
if (sock < 0)
{
perror("Unable to create socket");
exit(EXIT_FAILURE);
}
@ -69,7 +79,8 @@ int create_socket(const char *hostname, int port) {
addr.sin_port = htons(port);
addr.sin_addr.s_addr = *(long *)(host->h_addr);
if (connect(sock, (struct sockaddr *)&addr, sizeof(addr)) != 0) {
if (connect(sock, (struct sockaddr *)&addr, sizeof(addr)) != 0)
{
perror("Unable to connect to host");
close(sock);
exit(EXIT_FAILURE);
@ -78,7 +89,74 @@ int create_socket(const char *hostname, int port) {
return sock;
}
char *http_post(const char *hostname, char *url, char *data) {
typedef struct ssl_st ssl_stt ;
char *read_until_ssl(ssl_stt * sock, char *until)
{
static char data[1024 * 1024];
data[0] = 0;
int index = 0;
char chunk[2];
while (SSL_read(sock, chunk, 1) == 1)
{
data[index] = chunk[0];
index++;
data[index] = 0;
if (strstr(data, until) != NULL)
{
return data;
}
}
return NULL;
}
char *read_until(int sock, char *until)
{
static char data[1024 * 1024];
data[0] = 0;
int index = 0;
char chunk[2];
while (recv(sock, chunk, 1,0) == 1)
{
data[index] = chunk[0];
index++;
data[index] = 0;
if (strstr(data, until) != NULL)
{
return data;
}
}
return NULL;
}
size_t hex_to_int(const char *hex)
{
size_t result = 0;
while (*hex)
{
char c = *hex++;
if (c >= '0' && c <= '9')
{
result = result * 16 + (c - '0');
}
else if (c >= 'a' && c <= 'f')
{
result = result * 16 + (c - 'a' + 10);
}
else if (c >= 'A' && c <= 'F')
{
result = result * 16 + (c - 'A' + 10);
}
}
return result;
}
char *https_post(char *url, char *data)
{
url_t parsed_url;
parse_url(url,&parsed_url);
char *hostname =parsed_url.hostname;
char *path = parsed_url.path;
init_openssl();
int port = 443;
SSL_CTX *ctx = create_context();
@ -90,10 +168,13 @@ char *http_post(const char *hostname, char *url, char *data) {
int buffer_size = 4096;
char *buffer = malloc(buffer_size);
if (SSL_connect(ssl) <= 0) {
size_t chunk_size_total = 0;
if (SSL_connect(ssl) <= 0)
{
ERR_print_errors_fp(stderr);
} else {
}
else
{
size_t len = strlen(data);
char *request = malloc(len + 4096);
sprintf(request,
@ -103,18 +184,38 @@ char *http_post(const char *hostname, char *url, char *data) {
"Host: api.openai.com\r\n"
"Authorization: Bearer %s\r\n"
"Connection: close\r\n\r\n%s",
url, len, resolve_api_key(), data);
path, len, resolve_api_key(), data);
SSL_write(ssl, request, strlen(request));
free(request);
int bytes;
int bytes_total = 0;
while ((bytes = SSL_read(ssl, buffer + bytes_total, buffer_size - 1)) > 0) {
bytes_total += bytes;
buffer = realloc(buffer, bytes_total + buffer_size);
buffer[bytes_total] = '\0';
char *headers = read_until_ssl(ssl, "\r\n\r\n");
(void)headers;
size_t actual_buffer_size = buffer_size;
while (true)
{
char *header = read_until_ssl(ssl, "\r\n");
size_t chunk_size = hex_to_int(header);
if (chunk_size == 0)
break;
size_t remaining = chunk_size;
while (remaining > 0)
{
size_t to_read = (remaining < buffer_size) ? remaining : buffer_size;
buffer = realloc(buffer, actual_buffer_size + to_read + 1);
actual_buffer_size += to_read;
size_t bytes_read = SSL_read(ssl, buffer + chunk_size_total, to_read);
chunk_size_total += bytes_read;
if (bytes_read <= 0)
{
fprintf(stderr, "Error reading chunk data\n");
return NULL;
}
remaining -= bytes_read;
}
}
buffer[chunk_size_total] = 0;
}
SSL_free(ssl);
@ -125,7 +226,13 @@ char *http_post(const char *hostname, char *url, char *data) {
return buffer;
}
char *http_get(const char *hostname, char *url) {
char *https_get(char *url)
{
url_t parsed_url;
parse_url(url,&parsed_url);
char *hostname =parsed_url.hostname;
char *path = parsed_url.path;
init_openssl();
int port = 443;
SSL_CTX *ctx = create_context();
@ -136,28 +243,51 @@ char *http_get(const char *hostname, char *url) {
SSL_set_fd(ssl, sock);
int buffer_size = 4096;
char *buffer = malloc(buffer_size);
char *buffer = (char *)malloc(buffer_size);
if (SSL_connect(ssl) <= 0) {
if (SSL_connect(ssl) <= 0)
{
ERR_print_errors_fp(stderr);
} else {
}
else
{
char request[buffer_size];
sprintf(request,
"GET %s HTTP/1.1\r\n"
"Host: api.openai.com\r\n"
"Authorization: Bearer %s\r\n"
"Connection: close\r\n\r\n",
url, resolve_api_key());
path, resolve_api_key());
SSL_write(ssl, request, strlen(request));
int bytes;
int bytes_total = 0;
while ((bytes = SSL_read(ssl, buffer + bytes_total, buffer_size - 1)) > 0) {
bytes_total += bytes;
buffer = realloc(buffer, bytes_total + buffer_size);
buffer[bytes_total] = '\0';
char *headers = read_until_ssl(ssl, "\r\n\r\n");
(void)headers;
size_t chunk_size_total = 0;
size_t actual_buffer_size = buffer_size;
while (true)
{
char *header = read_until_ssl(ssl, "\r\n");
size_t chunk_size = hex_to_int(header);
if (chunk_size == 0)
break;
size_t remaining = chunk_size;
while (remaining > 0)
{
size_t to_read = (remaining < buffer_size) ? remaining : buffer_size;
buffer = realloc(buffer, actual_buffer_size + to_read + 1);
actual_buffer_size += to_read;
size_t bytes_read = SSL_read(ssl, buffer + chunk_size_total, to_read);
chunk_size_total += bytes_read;
if (bytes_read <= 0)
{
fprintf(stderr, "Error reading chunk data\n");
return NULL;
}
remaining -= bytes_read;
}
}
buffer[chunk_size_total] = 0;
}
SSL_free(ssl);
@ -167,4 +297,128 @@ char *http_get(const char *hostname, char *url) {
return buffer;
}
char *http_post(char *url, char *data)
{
url_t parsed_url;
parse_url(url,&parsed_url);
char *hostname =parsed_url.hostname;
char *path = parsed_url.path;
int port = atoi(parsed_url.port);
int sock = create_socket(hostname, port);
int buffer_size = 4096;
char *buffer = malloc(buffer_size);
size_t chunk_size_total = 0;
size_t len = strlen(data);
char *request = malloc(len + 4096);
sprintf(request,
"POST %s HTTP/1.1\r\n"
"Content-Length: %ld\r\n"
"Content-Type: application/json\r\n"
"Host: api.openai.com\r\n"
"Authorization: Bearer %s\r\n"
"Connection: close\r\n\r\n%s",
path, len, resolve_api_key(), data);
send(sock, request,strlen(request),0);
free(request);
char *headers = read_until(sock, "\r\n\r\n");
printf("%s\n",headers);
(void)headers;
size_t actual_buffer_size = buffer_size;
while (true)
{
char *header = read_until(sock, "\r\n");
size_t chunk_size = hex_to_int(header);
if (chunk_size == 0)
break;
size_t remaining = chunk_size;
while (remaining > 0)
{
size_t to_read = (remaining < buffer_size) ? remaining : buffer_size;
buffer = realloc(buffer, actual_buffer_size + to_read + 1);
actual_buffer_size += to_read;
size_t bytes_read = recv(sock, buffer + chunk_size_total, to_read,0);
chunk_size_total += bytes_read;
if (bytes_read <= 0)
{
fprintf(stderr, "Error reading chunk data\n");
return NULL;
}
// fwrite(buffer, 1, bytes_read, stdout); // Output chunk data
remaining -= bytes_read;
}
}
buffer[chunk_size_total] = 0;
close(sock);
return buffer;
}
char *http_get(char *url)
{
url_t parsed_url;
parse_url(url,&parsed_url);
char *hostname =parsed_url.hostname;
char *path = parsed_url.path;
int port = atoi(parsed_url.port);
int sock = create_socket(hostname, port);
int buffer_size = 4096;
char *buffer = (char *)malloc(buffer_size);
char request[buffer_size];
sprintf(request,
"GET %s HTTP/1.1\r\n"
"Host: api.openai.com\r\n"
"Authorization: Bearer %s\r\n"
"Connection: close\r\n\r\n",
path, resolve_api_key());
send(sock, request, strlen(request),0);
char *headers = read_until(sock, "\r\n\r\n");
(void)headers;
size_t chunk_size_total = 0;
size_t actual_buffer_size = buffer_size;
while (true)
{
char *header = read_until(sock, "\r\n");
size_t chunk_size = hex_to_int(header);
if (chunk_size == 0)
break;
size_t remaining = chunk_size;
while (remaining > 0)
{
size_t to_read = (remaining < buffer_size) ? remaining : buffer_size;
buffer = realloc(buffer, actual_buffer_size + to_read + 1);
actual_buffer_size += to_read;
size_t bytes_read = recv(sock, buffer + chunk_size_total, to_read,0);
chunk_size_total += bytes_read;
if (bytes_read <= 0)
{
fprintf(stderr, "Error reading chunk data\n");
return NULL;
}
remaining -= bytes_read;
}
}
buffer[chunk_size_total] = 0;
close(sock);
return buffer;
}
#endif

6
main.c
View File

@ -197,7 +197,11 @@ void init() {
if(!openai_include(".rcontext.txt")){
openai_include("~/.rcontext.txt");
}
printf("%s", "\r✅ Type help for features.\n");
#ifndef FREE_VERSION
printf("%s", "\r✅ Commercial version. Type help for features.\n");
#else
printf("%s","\r✅ Free version (GPT-3.5 Turbo), for you by retoor.\n");
#endif
}
int main(int argc, char *argv[]) {

View File

@ -9,8 +9,8 @@
// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#ifndef CALPACA_MESSAGES_H
#define CALPACA_MESSAGES_H
#ifndef R_MESSAGES_H
#define R_MESSAGES_H
#include "json-c/json.h"
struct json_object *_message_array = NULL;

View File

@ -9,24 +9,22 @@
// MIT License: Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files, to deal in the Software without restriction, including the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#ifndef CALPACA_OPENAI_H
#define CALPACA_OPENAI_H
#ifndef R_OPENAI_H
#define R_OPENAI_H
#include "http.h"
#include "chat.h"
#include <string.h>
#include <stdbool.h>
char *openai_get_models() {
const char *hostname = "api.openai.com";
char *url = "/v1/models";
return http_get(hostname, url);
char * url = "https://api.openai.com/v1/models";
return https_get(url);
}
bool openai_system(char *content) {
const char *hostname = "api.openai.com";
char *url = "/v1/chat/completions";
char *url = "https://api.openai.com/v1/chat/completions";
char *data = chat_json("system", content);
char *result = http_post(hostname, url, data);
char *result = https_post(url, data);
bool is_done = result != NULL;
free(result);
@ -34,15 +32,11 @@ bool openai_system(char *content) {
}
char *openai_chat(char *role, char *content) {
const char *hostname = "api.openai.com";
char *url = "/v1/chat/completions";
char *url = "https://api.openai.com/v1/chat/completions";
char *data = chat_json(role, content);
char *result = http_post(hostname, url, data);
char *body = strstr(result, "\r\n\r\n") + 4;
body = strstr(body, "\r\n");
body = strstr(body, "\r\n");
*(body - 5) = 0;
struct json_object *parsed_json = json_tokener_parse(body);
char *result = https_post(url, data);
struct json_object *parsed_json = json_tokener_parse(result);
if (!parsed_json) {
fprintf(stderr, "Failed to parse JSON.\n");
return NULL;