Initial commit.
This commit is contained in:
commit
4d82322545
10
.gitignore
vendored
Normal file
10
.gitignore
vendored
Normal file
@ -0,0 +1,10 @@
|
||||
.vscode
|
||||
.venv
|
||||
.history
|
||||
.backup*
|
||||
auth.h
|
||||
context.txt
|
||||
gpt
|
||||
gpt.c
|
||||
r
|
||||
.docs
|
7
Makefile
Normal file
7
Makefile
Normal file
@ -0,0 +1,7 @@
|
||||
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
|
||||
|
||||
run:
|
||||
./r
|
32
cgi-bin/gpt.py
Executable file
32
cgi-bin/gpt.py
Executable file
@ -0,0 +1,32 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
# Not written by retoor! This is generated boiler plate to give an example!
|
||||
|
||||
import cgi
|
||||
import cgitb
|
||||
from xmlrpc.client import ServerProxy
|
||||
client = ServerProxy("https://api.molodetz.nl/rpc")
|
||||
ask_gpt = client.gpt4o_mini
|
||||
|
||||
cgitb.enable()
|
||||
|
||||
print("Content-Type: text/html")
|
||||
print()
|
||||
|
||||
import pathlib
|
||||
|
||||
|
||||
form = cgi.FieldStorage()
|
||||
question = form.getvalue("question", "")
|
||||
|
||||
page_source = pathlib.Path(__file__).parent.joinpath("gpt_template.html").read_text()
|
||||
|
||||
if question:
|
||||
try:
|
||||
response = ask_gpt(question)
|
||||
except Exception as e:
|
||||
response = f"Error: {e}"
|
||||
page_source = page_source.replace("...", response)
|
||||
page_source = page_source.replace("display:none;","")
|
||||
|
||||
print(page_source)
|
64
cgi-bin/gpt_template.html
Normal file
64
cgi-bin/gpt_template.html
Normal file
@ -0,0 +1,64 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>GPT Example</title>
|
||||
<style>
|
||||
body {
|
||||
font-family: Arial, sans-serif;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
background-color: #f4f4f9;
|
||||
}
|
||||
.container {
|
||||
max-width: 600px;
|
||||
margin: 50px auto;
|
||||
padding: 20px;
|
||||
background: #fff;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 4px 10px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
h1 {
|
||||
color: #333;
|
||||
text-align: center;
|
||||
}
|
||||
textarea, input {
|
||||
width: 100%;
|
||||
padding: 10px;
|
||||
margin: 10px 0;
|
||||
font-size: 16px;
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 4px;
|
||||
}
|
||||
input[type="submit"] {
|
||||
background-color: #4CAF50;
|
||||
color: white;
|
||||
cursor: pointer;
|
||||
}
|
||||
input[type="submit"]:hover {
|
||||
background-color: #45a049;
|
||||
}
|
||||
.response-box {
|
||||
padding: 10px;
|
||||
background: #f9f9f9;
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 4px;
|
||||
min-height: 100px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<h1>Ask GPT</h1>
|
||||
<div style="display:none;" class="response-box">
|
||||
<p id="response">...</p>
|
||||
</div>
|
||||
<form action="/cgi-bin/gpt.py" method="post">
|
||||
<textarea name="question" rows="4" placeholder="Your prompt.."></textarea>
|
||||
<input type="submit" value="Get Answer">
|
||||
</form>
|
||||
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
31
chat.h
Normal file
31
chat.h
Normal file
@ -0,0 +1,31 @@
|
||||
#ifndef CALPACA_PROMPT_H
|
||||
#define CALPACA_PROMPT_H
|
||||
#include <json-c/json.h>
|
||||
#include "messages.h"
|
||||
#include "http.h"
|
||||
char * prompt_model = "gpt-4o-mini";
|
||||
int prompt_max_tokens = 100;
|
||||
double prompt_temperature = 0.5;
|
||||
|
||||
json_object * _prompt =NULL;
|
||||
|
||||
void chat_free(){
|
||||
if(_prompt == NULL)
|
||||
return;
|
||||
json_object_put(_prompt);
|
||||
_prompt = NULL;
|
||||
}
|
||||
|
||||
|
||||
char * chat_json(char * role, char * message){
|
||||
chat_free();
|
||||
message_add(role,message);
|
||||
struct json_object *root_object = json_object_new_object();
|
||||
json_object_object_add(root_object, "model", json_object_new_string(prompt_model));
|
||||
json_object_object_add(root_object, "messages", message_list());
|
||||
json_object_object_add(root_object, "max_tokens", json_object_new_int(prompt_max_tokens));
|
||||
json_object_object_add(root_object, "temperature", json_object_new_double(prompt_temperature));
|
||||
return (char *)json_object_to_json_string_ext(root_object, JSON_C_TO_STRING_PRETTY);
|
||||
}
|
||||
|
||||
#endif
|
210
http.h
Normal file
210
http.h
Normal file
@ -0,0 +1,210 @@
|
||||
#ifndef CALPACA_HTTP_H
|
||||
#define CALPACA_HTTP_H
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <netdb.h>
|
||||
#include <openssl/ssl.h>
|
||||
#include <openssl/err.h>
|
||||
#include "auth.h"
|
||||
#include <json-c/json.h>
|
||||
|
||||
void init_openssl()
|
||||
{
|
||||
SSL_load_error_strings();
|
||||
OpenSSL_add_ssl_algorithms();
|
||||
}
|
||||
|
||||
void cleanup_openssl()
|
||||
{
|
||||
EVP_cleanup();
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
return ctx;
|
||||
}
|
||||
|
||||
SSL_CTX *create_context2()
|
||||
{
|
||||
const SSL_METHOD *method;
|
||||
SSL_CTX *ctx;
|
||||
|
||||
method = TLS_client_method();
|
||||
ctx = SSL_CTX_new(method);
|
||||
if (!ctx)
|
||||
{
|
||||
perror("Unable to create SSL context");
|
||||
ERR_print_errors_fp(stderr);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
return ctx;
|
||||
}
|
||||
|
||||
int create_socket(const char *hostname, int port)
|
||||
{
|
||||
struct hostent *host;
|
||||
struct sockaddr_in addr;
|
||||
|
||||
host = gethostbyname(hostname);
|
||||
if (!host)
|
||||
{
|
||||
perror("Unable to resolve host");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
int sock = socket(AF_INET, SOCK_STREAM, 0);
|
||||
if (sock < 0)
|
||||
{
|
||||
perror("Unable to create socket");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
addr.sin_family = AF_INET;
|
||||
addr.sin_port = htons(port);
|
||||
addr.sin_addr.s_addr = *(long *)(host->h_addr);
|
||||
|
||||
if (connect(sock, (struct sockaddr *)&addr, sizeof(addr)) != 0)
|
||||
{
|
||||
perror("Unable to connect to host");
|
||||
close(sock);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
return sock;
|
||||
}
|
||||
|
||||
char *http_post(const char *hostname, char *url, char *data)
|
||||
{
|
||||
init_openssl();
|
||||
int port = 443;
|
||||
|
||||
SSL_CTX *ctx = create_context();
|
||||
|
||||
int sock = create_socket(hostname, port);
|
||||
|
||||
SSL *ssl = SSL_new(ctx);
|
||||
SSL_set_connect_state(ssl);
|
||||
|
||||
SSL_set_tlsext_host_name(ssl, hostname);
|
||||
|
||||
SSL_set_fd(ssl, sock);
|
||||
|
||||
int buffer_size = 4096;
|
||||
char *buffer = (char *)malloc(buffer_size);
|
||||
|
||||
|
||||
if (SSL_connect(ssl) <= 0)
|
||||
{
|
||||
ERR_print_errors_fp(stderr);
|
||||
}
|
||||
else
|
||||
{
|
||||
//printf("Connected with %s encryption\n", SSL_get_cipher(ssl));
|
||||
size_t len = strlen(data);
|
||||
char *request = (char *)malloc(len + 4096);
|
||||
request[0] = 0;
|
||||
|
||||
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",
|
||||
url, len, 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)
|
||||
{
|
||||
if (bytes <= 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
bytes_total += bytes;
|
||||
buffer = realloc(buffer, bytes_total + buffer_size);
|
||||
buffer[bytes_total] = '\0';
|
||||
}
|
||||
buffer[bytes_total] = '\0';
|
||||
}
|
||||
|
||||
SSL_free(ssl);
|
||||
close(sock);
|
||||
SSL_CTX_free(ctx);
|
||||
cleanup_openssl();
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
char *http_get(const char *hostname, char *url)
|
||||
{
|
||||
init_openssl();
|
||||
int port = 443;
|
||||
|
||||
SSL_CTX *ctx = create_context();
|
||||
|
||||
int sock = create_socket(hostname, port);
|
||||
|
||||
SSL *ssl = SSL_new(ctx);
|
||||
SSL_set_connect_state(ssl);
|
||||
|
||||
SSL_set_tlsext_host_name(ssl, hostname);
|
||||
|
||||
SSL_set_fd(ssl, sock);
|
||||
|
||||
int buffer_size = 4096;
|
||||
char *buffer = (char *)malloc(buffer_size * sizeof(char));
|
||||
|
||||
if (SSL_connect(ssl) <= 0)
|
||||
{
|
||||
ERR_print_errors_fp(stderr);
|
||||
}
|
||||
else
|
||||
{
|
||||
//printf("Connected with %s encryption\n", SSL_get_cipher(ssl));
|
||||
|
||||
char request[buffer_size];
|
||||
request[0] = 0;
|
||||
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, 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)
|
||||
{
|
||||
if (bytes <= 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
bytes_total += bytes;
|
||||
buffer = realloc(buffer, bytes_total + buffer_size);
|
||||
buffer[bytes_total] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
SSL_free(ssl);
|
||||
close(sock);
|
||||
SSL_CTX_free(ctx);
|
||||
cleanup_openssl();
|
||||
|
||||
return buffer;
|
||||
}
|
||||
#endif
|
53
line.h
Normal file
53
line.h
Normal file
@ -0,0 +1,53 @@
|
||||
#include <readline/readline.h>
|
||||
#include <readline/history.h>
|
||||
|
||||
#define HISTORY_FILE "~/.calpaca_history"
|
||||
|
||||
bool line_initialized =false;
|
||||
|
||||
char *line_command_generator(const char *text, int state) {
|
||||
static int list_index, len;
|
||||
const char *commands[] = {"help", "exit", "list", "review","refactor","opfuscate", NULL};
|
||||
|
||||
if (!state) {
|
||||
list_index = 0;
|
||||
len = strlen(text);
|
||||
}
|
||||
|
||||
while (commands[list_index]) {
|
||||
const char *command = commands[list_index++];
|
||||
if (strncmp(command, text, len) == 0) {
|
||||
return strdup(command);
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char **line_command_completion(const char *text, int start, int end) {
|
||||
rl_attempted_completion_over = 1;
|
||||
return rl_completion_matches(text, line_command_generator);
|
||||
}
|
||||
|
||||
void line_init(){
|
||||
if(!line_initialized)
|
||||
{
|
||||
rl_attempted_completion_function = line_command_completion;
|
||||
line_initialized = true;
|
||||
read_history(HISTORY_FILE);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
char * line_read(char * prefix) {
|
||||
char * data = readline(prefix);
|
||||
if(!(data || *data)){
|
||||
return NULL;
|
||||
}
|
||||
return data;
|
||||
}
|
||||
void line_add_history(char * data){
|
||||
read_history(HISTORY_FILE);
|
||||
add_history(data);
|
||||
write_history(HISTORY_FILE);
|
||||
}
|
185
main.c
Normal file
185
main.c
Normal file
@ -0,0 +1,185 @@
|
||||
#include "openai.h"
|
||||
#include "markdown.h"
|
||||
#include "plugin.h"
|
||||
#include "line.h"
|
||||
#include <locale.h>
|
||||
#include <stdio.h>
|
||||
|
||||
char * get_prompt_from_args(int c, char **argv){
|
||||
char * prompt = malloc(1024*1024 + 1);
|
||||
prompt[0] = 0;
|
||||
for(int i = 1; i < c; i++){
|
||||
if(argv[i][0] == '-')
|
||||
break;
|
||||
strncat(prompt, argv[i], 1024*1024);
|
||||
if(i < c - 1){
|
||||
strncat(prompt, " ", 1024*1024);
|
||||
}else{
|
||||
strncat(prompt, ".", 1024*1024);
|
||||
}
|
||||
}
|
||||
if(!*prompt){
|
||||
free(prompt);
|
||||
return NULL;
|
||||
}
|
||||
return prompt;
|
||||
}
|
||||
|
||||
bool try_prompt(int argc,char*argv[]){
|
||||
char * prompt = get_prompt_from_args(argc, argv);
|
||||
if(prompt != NULL){
|
||||
char * response = openai_chat("user",prompt);
|
||||
parse_markdown_to_ansi(response);
|
||||
printf("\n");
|
||||
free(response);
|
||||
free(prompt);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void help();
|
||||
void render(char *);
|
||||
void serve(){
|
||||
render("Starting server. *Put executables in a dir named cgi-bin and they will behave as webpages.*");
|
||||
int res = system("python3 -m http.server --cgi");
|
||||
// Thanks tsoding!
|
||||
(void)res;
|
||||
}
|
||||
|
||||
|
||||
void render(char * content){
|
||||
parse_markdown_to_ansi(content);
|
||||
printf("\n\n");
|
||||
}
|
||||
|
||||
void repl(){
|
||||
line_init();
|
||||
setbuf(stdout, NULL);
|
||||
char *line;
|
||||
char *previous_line = NULL;
|
||||
while((line = line_read("> "))){
|
||||
if(!line || !*line){
|
||||
line = previous_line;
|
||||
}
|
||||
if(!line || !*line)
|
||||
continue;
|
||||
previous_line = line;
|
||||
if(line[0] == '!'){
|
||||
plugin_run(line + 1);
|
||||
continue;
|
||||
}
|
||||
if(!strncmp(line,"exit", 4)){
|
||||
exit(0);
|
||||
}
|
||||
if(!strncmp(line,"help",4)){
|
||||
help();
|
||||
continue;
|
||||
}
|
||||
if(!strncmp(line,"serve",5)){
|
||||
serve();
|
||||
}
|
||||
if(!strncmp(line,"spar ",5)){
|
||||
char * response = line+5;
|
||||
while(true){
|
||||
render(response);
|
||||
sleep(2);
|
||||
//line = line_read("> ");
|
||||
//if(!*line)
|
||||
response = openai_chat("user",response);
|
||||
|
||||
}
|
||||
}
|
||||
if(!strncmp(line,"ls",2) || !strncmp(line,"list",4)){
|
||||
int offset = 2;
|
||||
if(!strncmp(line,"list",4)){
|
||||
offset = 4;
|
||||
}
|
||||
char * command = (char *)malloc(strlen(line) + 42);
|
||||
command[0] = 0;
|
||||
strcpy(command, "ls ");
|
||||
strcat(command, line + offset);
|
||||
int res = system(command);
|
||||
(void)res;
|
||||
free(command);
|
||||
continue;
|
||||
}
|
||||
|
||||
line_add_history(line);
|
||||
char * response = openai_chat("user", line);
|
||||
render(response);
|
||||
free(response);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void help(){
|
||||
char help_text[1024*1024] = {0};
|
||||
char * template = "# Help\n"
|
||||
"Written by retoor@molodetz.nl.\n\n"
|
||||
"## Features\n"
|
||||
" - navigate trough history using `arrows`.\n"
|
||||
" - navigate trough history with **recursive search** using `ctrl+r`.\n"
|
||||
" - **inception with python** for *incomming* and *outgoing* content.\n"
|
||||
" - markdown and **syntax highlighting**.\n"
|
||||
" - **execute python commands** with prefixing `!`\n"
|
||||
" - list files of current workdirectory using `ls`.\n"
|
||||
" - type `serve` to start a webserver with directory listing. Easy for network transfers.\n\n"
|
||||
"## Configuration\n"
|
||||
" - model temperature is %f.\n"
|
||||
" - model name is %s.\n"
|
||||
" - max tokens is %d.\n\n"
|
||||
"## In development\n"
|
||||
" - **google search** and actions with those results.\n"
|
||||
" - **reminders**.\n"
|
||||
" - predefined **templates** for **reviewing** / **refactoring** so you can personalize.\n";
|
||||
sprintf(help_text,template,prompt_temperature,prompt_model,prompt_max_tokens);
|
||||
render(help_text);
|
||||
}
|
||||
|
||||
void openai_include(char * path){
|
||||
FILE * file = fopen(path,"r");
|
||||
if(file == NULL){
|
||||
return;
|
||||
}
|
||||
fseek(file, 0, SEEK_END);
|
||||
long size = ftell(file);
|
||||
fseek(file, 0, SEEK_SET);
|
||||
|
||||
char * buffer = (char *)malloc(size);
|
||||
size_t read = fread(buffer,1,size,file);
|
||||
if(read == 0){
|
||||
return;
|
||||
}
|
||||
|
||||
fclose(file);
|
||||
buffer[read] = 0;
|
||||
openai_system(buffer);
|
||||
|
||||
free(buffer);
|
||||
}
|
||||
|
||||
void init(){
|
||||
line_init();
|
||||
const char *locale = setlocale(LC_ALL, NULL);
|
||||
char payload[4096] = {0};
|
||||
sprintf(payload, "User locale is %s. User lang is %s.\n"
|
||||
"You are Retoor. Use a lot of markdown in response.\n"
|
||||
"Be confident and short in answers.\n"
|
||||
"You divide things by zero if you have to."
|
||||
, locale, locale);
|
||||
|
||||
printf("%s","Loading...");
|
||||
openai_system(payload);
|
||||
openai_include("context.txt");
|
||||
printf("%s", "\rLoaded! Type help for feautures.\n");
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]){
|
||||
init();
|
||||
if(try_prompt(argc,argv))
|
||||
return 0;
|
||||
|
||||
repl();
|
||||
return 0;
|
||||
}
|
115
markdown.h
Normal file
115
markdown.h
Normal file
@ -0,0 +1,115 @@
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#define RESET "\033[0m"
|
||||
#define BOLD "\033[1m"
|
||||
#define ITALIC "\033[3m"
|
||||
#define FG_YELLOW "\033[33m"
|
||||
#define FG_BLUE "\033[34m"
|
||||
#define FG_CYAN "\033[36m"
|
||||
|
||||
int is_keyword(const char *word) {
|
||||
const char *keywords[] = {"int", "float", "double", "char", "void", "if", "else", "while", "for", "return", "struct", "printf"};
|
||||
for (size_t i = 0; i < sizeof(keywords) / sizeof(keywords[0]); i++) {
|
||||
if (strcmp(word, keywords[i]) == 0) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void highlight_code(const char *code) {
|
||||
const char *ptr = code;
|
||||
char buffer[256];
|
||||
size_t index = 0;
|
||||
|
||||
while (*ptr) {
|
||||
if ((*ptr >= 'a' && *ptr <= 'z') || (*ptr >= 'A' && *ptr <= 'Z') || (*ptr == '_')) {
|
||||
while ((*ptr >= 'a' && *ptr <= 'z') || (*ptr >= 'A' && *ptr <= 'Z') || (*ptr >= '0' && *ptr <= '9') || (*ptr == '_')) {
|
||||
buffer[index++] = *ptr++;
|
||||
}
|
||||
buffer[index] = '\0';
|
||||
|
||||
if (is_keyword(buffer)) {
|
||||
printf(FG_BLUE "%s" RESET, buffer);
|
||||
} else {
|
||||
printf("%s", buffer);
|
||||
}
|
||||
index = 0;
|
||||
} else if (*ptr >= '0' && *ptr <= '9') {
|
||||
while (*ptr >= '0' && *ptr <= '9') {
|
||||
buffer[index++] = *ptr++;
|
||||
}
|
||||
buffer[index] = '\0';
|
||||
printf(FG_CYAN "%s" RESET, buffer);
|
||||
index = 0;
|
||||
} else {
|
||||
putchar(*ptr);
|
||||
ptr++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void parse_markdown_to_ansi(const char *markdown) {
|
||||
const char *ptr = markdown;
|
||||
bool inside_code = false;
|
||||
|
||||
while (*ptr) {
|
||||
if (*ptr == '`') {
|
||||
inside_code = !inside_code;
|
||||
if (inside_code) {
|
||||
printf(FG_YELLOW);
|
||||
} else {
|
||||
printf(RESET);
|
||||
}
|
||||
ptr++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (inside_code) {
|
||||
char code_buffer[256];
|
||||
size_t index = 0;
|
||||
|
||||
while (*ptr && *ptr != '`') {
|
||||
code_buffer[index++] = *ptr++;
|
||||
}
|
||||
code_buffer[index] = '\0';
|
||||
highlight_code(code_buffer);
|
||||
} else {
|
||||
if (strncmp(ptr, "**", 2) == 0) {
|
||||
printf(BOLD);
|
||||
ptr += 2;
|
||||
while (*ptr && strncmp(ptr, "**", 2) != 0) putchar(*ptr++);
|
||||
if (*ptr == '*' && *(ptr + 1) == '*') ptr += 2;
|
||||
printf(RESET);
|
||||
}
|
||||
else if (*ptr == '*' && (ptr == markdown || *(ptr - 1) != '*')) {
|
||||
printf(ITALIC);
|
||||
ptr++;
|
||||
while (*ptr && *ptr != '*') putchar(*ptr++);
|
||||
if (*ptr == '*') ptr++;
|
||||
printf(RESET);
|
||||
}
|
||||
else if (strncmp(ptr, "### ", 4) == 0) {
|
||||
printf(BOLD FG_YELLOW);
|
||||
ptr += 4;
|
||||
while (*ptr && *ptr != '\n') putchar(*ptr++);
|
||||
printf(RESET "\n");
|
||||
} else if (strncmp(ptr, "## ", 3) == 0) {
|
||||
printf(BOLD FG_YELLOW);
|
||||
ptr += 3;
|
||||
while (*ptr && *ptr != '\n') putchar(*ptr++);
|
||||
printf(RESET "\n");
|
||||
} else if (strncmp(ptr, "# ", 2) == 0) {
|
||||
printf(BOLD FG_YELLOW);
|
||||
ptr += 2;
|
||||
while (*ptr && *ptr != '\n') putchar(*ptr++);
|
||||
printf(RESET "\n");
|
||||
} else {
|
||||
putchar(*ptr);
|
||||
ptr++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
32
messages.h
Normal file
32
messages.h
Normal file
@ -0,0 +1,32 @@
|
||||
#ifndef CALPACA_MESSAGES_H
|
||||
#define CALPACA_MESSAGES_H
|
||||
#include "json-c/json.h"
|
||||
struct json_object *_message_array = NULL;
|
||||
|
||||
struct json_object *message_list(){
|
||||
if(_message_array == NULL){
|
||||
_message_array = json_object_new_array();
|
||||
}
|
||||
return _message_array;
|
||||
}
|
||||
|
||||
struct json_object *message_add(char * role, char * content){
|
||||
struct json_object *messages = message_list();
|
||||
struct json_object *message = json_object_new_object();
|
||||
json_object_object_add(message, "role", json_object_new_string(role));
|
||||
json_object_object_add(message, "content", json_object_new_string(content));
|
||||
json_object_array_add(messages, message);
|
||||
return message;
|
||||
}
|
||||
|
||||
char * message_json(){
|
||||
return (char *)json_object_to_json_string_ext(message_list(), JSON_C_TO_STRING_PRETTY);
|
||||
}
|
||||
|
||||
void message_free(){
|
||||
if(_message_array != NULL){
|
||||
json_object_put(_message_array);
|
||||
_message_array = NULL;
|
||||
}
|
||||
}
|
||||
#endif
|
84
openai.h
Normal file
84
openai.h
Normal file
@ -0,0 +1,84 @@
|
||||
#ifndef CALPACA_OPENAI_H
|
||||
#define CALPACA_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";
|
||||
char *result = http_get(hostname, url);
|
||||
return result;
|
||||
}
|
||||
|
||||
bool openai_system(char * content){
|
||||
bool is_done = false;
|
||||
const char *hostname = "api.openai.com";
|
||||
char *url = "/v1/chat/completions";
|
||||
char *data = chat_json("system", content);
|
||||
char *result = http_post(hostname, url, data);
|
||||
if(result){
|
||||
is_done = true;
|
||||
|
||||
free(result);
|
||||
}
|
||||
return is_done;
|
||||
}
|
||||
|
||||
|
||||
char *openai_chat(char * role, char * content){
|
||||
const char *hostname = "api.openai.com";
|
||||
char *url = "/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);
|
||||
if (!parsed_json) {
|
||||
fprintf(stderr, "Failed to parse JSON.\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct json_object *choices_array;
|
||||
if (!json_object_object_get_ex(parsed_json, "choices", &choices_array)) {
|
||||
fprintf(stderr, "Failed to get 'choices' array.\n");
|
||||
json_object_put(parsed_json);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Get the first element of the "choices" array
|
||||
struct json_object *first_choice = json_object_array_get_idx(choices_array, 0);
|
||||
if (!first_choice) {
|
||||
fprintf(stderr, "Failed to get the first element of 'choices'.\n");
|
||||
json_object_put(parsed_json);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Extract the "message" object
|
||||
struct json_object *message_object;
|
||||
if (!json_object_object_get_ex(first_choice, "message", &message_object)) {
|
||||
fprintf(stderr, "Failed to get 'message' object.\n");
|
||||
json_object_put(parsed_json);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Print the "message" object
|
||||
// printf("Message object:\n%s\n", json_object_to_json_string_ext(message_object, JSON_C_TO_STRING_PRETTY));
|
||||
message_add("assistant",(char *)json_object_get_string(json_object_object_get(message_object, "content")));
|
||||
// Clean up
|
||||
free(data);
|
||||
free(result);
|
||||
result = strdup((char *)json_object_get_string(json_object_object_get(message_object, "content")));
|
||||
|
||||
json_object_put(parsed_json);
|
||||
|
||||
//printf("Parsed JSON:\n%s\n", json_object_to_json_string_ext(parsed_json, JSON_C_TO_STRING_PRETTY));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
#endif
|
43
plugin.h
Normal file
43
plugin.h
Normal file
@ -0,0 +1,43 @@
|
||||
#include <python3.14/Python.h>
|
||||
#include <python3.14/structmember.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
bool plugin_initialized = false;
|
||||
|
||||
bool plugin_construct(){
|
||||
if(plugin_initialized)
|
||||
return true;
|
||||
|
||||
Py_Initialize();
|
||||
|
||||
// Check if Python initialized successfully
|
||||
if (!Py_IsInitialized()) {
|
||||
fprintf(stderr, "Failed to initialize Python interpreter\n");
|
||||
return plugin_initialized;
|
||||
}
|
||||
plugin_initialized = true;
|
||||
return plugin_initialized;
|
||||
}
|
||||
|
||||
void plugin_run(char * src){
|
||||
plugin_construct();
|
||||
char * basics = "import sys\n"
|
||||
"import os\n"
|
||||
"import math\n"
|
||||
"import pathlib\n"
|
||||
"import subprocess\n"
|
||||
"import time\n"
|
||||
"from datetime import datetime\n"
|
||||
"%s";
|
||||
size_t length = strlen(basics) + strlen(src);
|
||||
char * script = (char *)malloc(length + 1);
|
||||
sprintf(script, basics, src);
|
||||
script[length] = 0;
|
||||
PyRun_SimpleString(script);
|
||||
free(script);
|
||||
}
|
||||
|
||||
void plugin_destruct(){
|
||||
if(plugin_initialized)
|
||||
Py_Finalize();
|
||||
}
|
Loading…
Reference in New Issue
Block a user