Compare commits

..

No commits in common. "c64c92e1cc2713990869d7b1008bb1cc9ef0a53c" and "619b231e8d72b9151e8755b4251075db3445460e" have entirely different histories.

9 changed files with 475 additions and 416 deletions

View File

@ -1,37 +0,0 @@
# Use an official Ubuntu as a base image
FROM ubuntu:latest
# Set environment variables to avoid interactive prompts during package installation
ENV DEBIAN_FRONTEND=noninteractive
# Update the package list and install required packages
RUN apt-get update -y && \
apt-get install -y \
gcc \
make \
libreadline-dev \
libncurses5-dev \
libcurl4-openssl-dev \
libssl-dev \
libjson-c-dev \
libsqlite3-dev \
python3-dev \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/*
RUN mkdir /r
# Set the working directory
WORKDIR /r
# Copy the source files into the container
COPY . .
# Build the application
RUN make build
RUN cp r /usr/local/bin/r
WORKDIR /app
# Command to run the application (optional, can be overridden)
CMD ["r", "--verbose"]

View File

@ -1,35 +1,28 @@
all: build build_rd build_free build_rpylib run build_mingw all: build build_rd build_free build_rpylib run_free
# Variables for compiler and flags # Variables for compiler and flags
CC = gcc CC = gcc
CFLAGS = -Ofast -Werror -Wall -lreadline -lncurses -lcurl -lssl -lcrypto -ljson-c -lm -lsqlite3 CFLAGS = -Ofast -Werror -Wall -lreadline -lncurses -lcurl -lssl -lcrypto -ljson-c -lm -lsqlite3
# MinGW Variables
MINGW_CC = x86_64-w64-mingw32-gcc # Change to x86_64-w64-mingw32-gcc for 64-bit
MINGW_CFLAGS = -Ofast -Werror -Wall -lreadline -lcurl -lssl -lcrypto -ljson-c -lm -lglob
# Targets # Targets
build: build:
$(CC) main.c $(CFLAGS) -o r $(CC) main.c $(CFLAGS) -o r
-@publish r publish r
build_free: build_free:
$(CC) -DOLLAMA main.c $(CFLAGS) -o rf $(CC) -DOLLAMA main.c $(CFLAGS) -o rf
@publish rf publish rf
build_rd: build_rd:
$(CC) -DRD main.c $(CFLAGS) -o rd $(CC) -DRD main.c $(CFLAGS) -o rd
publish rd publish rd
build_rpylib: build_rpylib:
$(CC) -shared -o rpylib.so -fPIC rpylib.c -lpython3.12 `python3-config --includes` -I/usr/include/CL -ljson-c -lcurl -lsqlite3 $(CC) -shared -o rpylib.so -fPIC rpylib.c -lpython3.12 `python3-config --includes` -I/usr/include/CL -ljson-c -lcurl -lsqlite3
publish rpylib.so publish rpylib.so
# New MinGW build target
build_mingw:
$(MINGW_CC) main.c $(MINGW_CFLAGS) -o r.exe
publish r.exe
run: run:
./r --verbose ./r --verbose
@ -38,14 +31,3 @@ run_free:
run_rd: run_rd:
./rd --verbose ./rd --verbose
run_mingw:
./r.exe --verbose
docker: docker_make docker_run
docker_make:
docker build -t r .
docker_run:
docker run -v .:/app --rm -it r

View File

@ -1,10 +0,0 @@
services:
shell:
build: .
command: sh
tty: true
stdin_open: true
working_dir: /home
volumes:
- ./:/home

207
indexer.h
View File

@ -7,106 +7,151 @@
#include <sys/stat.h> #include <sys/stat.h>
#include <time.h> #include <time.h>
#include <unistd.h> #include <unistd.h>
#define MAX_FILES 20000 #define MAX_FILES 20000
#define MAX_PATH 4096 #define MAX_PATH 4096
static const char *extensions[] = { static const char *extensions[] = {
".c", ".cpp", ".h", ".py", ".java", ".js", ".mk", ".html", ".c", ".cpp", ".h", ".py", ".java", ".js", ".mk", ".html",
"Makefile", ".css", ".json", ".cs", ".csproj", ".sln", ".toml", ".rs", "Makefile", ".css", ".json", ".cs", ".csproj", ".sln", ".toml", ".rs"};
".go", ".rb", ".swift", ".php", ".pl", ".sh", ".bash", ".sql", static size_t ext_count =
".xml", ".yaml", ".yml", ".kt", ".dart", ".scala", ".clj", ".asm", sizeof(extensions) /
".m", ".r", ".lua", ".groovy", ".v", ".pas", ".d", ".f90", ".f95", sizeof(
".for", ".s", ".tcl", ".vhdl", ".verilog", ".coffee", ".less", ".scss", extensions[0]); // Updated count to reflect the new number of extensions
".ps1", ".psm1", ".cmd", ".bat", ".json5", ".cxx", ".cc", ".hpp",
".hxx", ".inc", ".nsi", ".ninja", ".cmake", ".cmake.in", ".mk.in",
".make", ".makefile", ".gyp", ".gypi", ".pro", ".qml", ".ui", ".wxs",
".wxl", ".wxi", ".wxl", ".wxs", ".wxi", ".wxl", ".wxs", ".wxi"
};
static const size_t ext_count = sizeof(extensions) / sizeof(extensions[0]);
typedef struct { typedef struct {
char name[MAX_PATH]; char name[MAX_PATH];
char modification_date[20]; char modification_date[20];
char creation_date[20]; char creation_date[20];
char type[10]; char type[10];
size_t size_bytes; size_t size_bytes;
} FileInfo; } FileInfo;
static FileInfo file_list[MAX_FILES]; FileInfo file_list[MAX_FILES];
static size_t file_count = 0; size_t file_count = 0;
static int is_valid_extension(const char *filename) { int is_valid_extension(const char *filename, const char *extensions[],
const char *dot = strrchr(filename, '.'); size_t ext_count) {
if (!dot) dot = filename; const char *dot = strrchr(filename, '.');
for (size_t i = 0; i < ext_count; i++) { if (!dot) {
if (strcmp(dot, extensions[i]) == 0) return 1; dot = filename;
}
for (size_t i = 0; i < ext_count; i++) {
if (strcmp(dot, extensions[i]) == 0) {
return 1;
} }
return 0; }
return 0;
} }
static int is_ignored_directory(const char *dir_name) { int is_ignored_directory(const char *dir_name) {
const char *ignored_dirs[] = {"env", ".venv", "node_modules", "venv", "virtualenv"}; const char *ignored_dirs[] = {"env", ".venv", "node_modules", "venv",
for (size_t i = 0; i < sizeof(ignored_dirs) / sizeof(ignored_dirs[0]); i++) { "virtualenv"};
if (strcmp(dir_name, ignored_dirs[i]) == 0) return 1; for (size_t i = 0; i < sizeof(ignored_dirs) / sizeof(ignored_dirs[0]); i++) {
if (strcmp(dir_name, ignored_dirs[i]) == 0) {
return 1;
} }
return 0; }
return 0;
} }
static void get_file_info(const char *path) { void get_file_info(const char *path) {
struct stat file_stat; struct stat file_stat;
if (stat(path, &file_stat) == 0) { if (stat(path, &file_stat) == 0) {
FileInfo info; FileInfo info;
strncpy(info.name, path, MAX_PATH - 1); strncpy(info.name, path,
info.name[MAX_PATH - 1] = '\0'; MAX_PATH -
strftime(info.modification_date, sizeof(info.modification_date), "%Y-%m-%d %H:%M:%S", localtime(&file_stat.st_mtime)); 1); // Copy with one less to leave space for null terminator
strftime(info.creation_date, sizeof(info.creation_date), "%Y-%m-%d %H:%M:%S", localtime(&file_stat.st_ctime)); info.name[MAX_PATH - 1] = '\0'; // Ensure null termination
strncpy(info.type, S_ISDIR(file_stat.st_mode) ? "directory" : "file", sizeof(info.type) - 1); strftime(info.modification_date, sizeof(info.modification_date),
info.type[sizeof(info.type) - 1] = '\0'; "%Y-%m-%d %H:%M:%S", localtime(&file_stat.st_mtime));
info.size_bytes = file_stat.st_size; strftime(info.creation_date, sizeof(info.creation_date),
file_list[file_count++] = info; "%Y-%m-%d %H:%M:%S", localtime(&file_stat.st_ctime));
} strncpy(info.type, S_ISDIR(file_stat.st_mode) ? "directory" : "file", 10);
info.type[9] = '\0'; // Ensure null termination
info.size_bytes = file_stat.st_size;
file_list[file_count++] = info;
}
} }
char *index_directory(const char *dir_path) { char *index_directory(const char *dir_path) {
DIR *dir = opendir(dir_path); DIR *dir = opendir(dir_path);
if (!dir) { struct dirent *entry;
perror("Failed to open directory"); if (dir == NULL) {
return NULL; perror("Failed to open directory");
} return NULL;
}
struct dirent *entry; json_object *jarray = json_object_new_array();
json_object *jarray = json_object_new_array();
while ((entry = readdir(dir)) != NULL) { while ((entry = readdir(dir)) != NULL) {
if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) continue; if (strcmp(entry->d_name, ".") != 0 && strcmp(entry->d_name, "..") != 0) {
if (entry->d_name[0] == '.' || is_ignored_directory(entry->d_name)) continue; if (entry->d_name[0] == '.' || is_ignored_directory(entry->d_name)) {
continue;
char full_path[MAX_PATH]; }
snprintf(full_path, sizeof(full_path), "%s/%s", dir_path, entry->d_name); char full_path[MAX_PATH];
snprintf(full_path, sizeof(full_path), "%s/%s", dir_path, entry->d_name);
if (entry->d_type == DT_DIR) { if (entry->d_type == DT_DIR) {
char *subdir_json = index_directory(full_path); char *subdir_json = index_directory(full_path);
if (subdir_json) { if (subdir_json) {
json_object *jsubdir = json_object_new_string(subdir_json); json_object *jsubdir = json_object_new_string(subdir_json);
json_object_array_add(jarray, jsubdir); json_object_array_add(jarray, jsubdir);
free(subdir_json); free(subdir_json);
}
} else if (is_valid_extension(entry->d_name)) {
get_file_info(full_path);
json_object *jfile = json_object_new_object();
json_object_object_add(jfile, "file_name", json_object_new_string(file_list[file_count - 1].name));
json_object_object_add(jfile, "modification_date", json_object_new_string(file_list[file_count - 1].modification_date));
json_object_object_add(jfile, "creation_date", json_object_new_string(file_list[file_count - 1].creation_date));
json_object_object_add(jfile, "type", json_object_new_string(file_list[file_count - 1].type));
json_object_object_add(jfile, "size_bytes", json_object_new_int64(file_list[file_count - 1].size_bytes));
json_object_array_add(jarray, jfile);
} }
} } else if (is_valid_extension(entry->d_name, extensions, ext_count)) {
closedir(dir); get_file_info(full_path);
json_object *jfile = json_object_new_object();
json_object_object_add(
jfile, "file_name",
json_object_new_string(file_list[file_count - 1].name));
json_object_object_add(
jfile, "modification_date",
json_object_new_string(
file_list[file_count - 1].modification_date));
json_object_object_add(
jfile, "creation_date",
json_object_new_string(file_list[file_count - 1].creation_date));
json_object_object_add(
jfile, "type",
json_object_new_string(file_list[file_count - 1].type));
json_object_object_add(
jfile, "size_bytes",
json_object_new_int64(file_list[file_count - 1].size_bytes));
char *result = strdup(json_object_to_json_string(jarray)); // Read the file contents
json_object_put(jarray); FILE *fp = fopen(file_list[file_count - 1].name, "r");
return result; if (fp != NULL) {
} fseek(fp, 0, SEEK_END);
long length = ftell(fp);
fseek(fp, 0, SEEK_SET);
char *content = malloc(length + 1);
if (content) {
size_t bytesRead = fread(content, 1, length, fp);
if (bytesRead != length) {
free(content);
content = NULL;
json_object_object_add(
jfile, "file_current_content_data",
json_object_new_string("Error reading file"));
} else {
content[length] = '\0'; // Null-terminate the string
// json_object_object_add(jfile, "file_current_content_data",
// json_object_new_string(content));
}
free(content);
}
fclose(fp);
} else {
// json_object_object_add(jfile, "content",
// json_object_new_string("Unable to read file"));
}
json_object_array_add(jarray, jfile);
}
}
}
closedir(dir);
char *result = strdup(json_object_to_json_string(jarray));
json_object_put(jarray);
return result;
}

518
main.c
View File

@ -1,261 +1,381 @@
// Written by retoor@molodetz.nl
// This source code initializes a command-line application that uses OpenAI for
// chat interactions, handles user inputs, and can start a simple HTTP server
// with CGI support. The code allows command execution, markdown parsing, and
// OpenAI chat integration.
// External imports used in this code:
// - openai.h
// - markdown.h
// - plugin.h
// - line.h
// MIT License
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation 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.
#include "r.h" #include "r.h"
#include <signal.h> #include <signal.h>
#include <stdbool.h> #include <stdbool.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <locale.h>
#include <unistd.h>
#include "line.h" #include "line.h"
#include "markdown.h" #include "markdown.h"
#include "openai.h" #include "openai.h"
#include "utils.h" #include "utils.h"
#include <locale.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "db_utils.h" #include "db_utils.h"
volatile sig_atomic_t sigint_count = 0; volatile sig_atomic_t sigint_count = 0;
time_t first_sigint_time = 0; time_t first_sigint_time = 0;
bool SYNTAX_HIGHLIGHT_ENABLED = true; bool SYNTAX_HIGHLIGHT_ENABLED = true;
bool API_MODE = false; bool API_MODE = false;
void help(); void help();
void render(const char *); void render(char *);
bool openai_include(const char *); bool openai_include(char *path);
char *strreplace(const char *, const char *, const char *); char *strreplace(char *content, char *what, char *with);
char *get_prompt_from_stdin(char *prompt) { char *get_prompt_from_stdin(char *prompt) {
int index = 0; int index = 0;
char c; prompt[index] = '\0';
while ((c = getchar()) != EOF) { char c = 0;
prompt[index++] = c; while ((c = getchar()) != EOF) {
} prompt[index++] = c;
prompt[index] = '\0'; }
return prompt; prompt[index++] = '\0';
return prompt;
} }
char *get_prompt_from_args(int argc, char **argv) { char *get_prompt_from_args(int c, char **argv) {
char *prompt = malloc(10 * 1024 * 1024 + 1); char *prompt = (char *)malloc(1024 * 1024 * 10 + 1);
char *system = malloc(1024 * 1024); char *system = (char *)malloc(1024 * 1024);
bool get_from_std_in = false;
for (int i = 1; i < argc; i++) { system[0] = 0;
if (strcmp(argv[i], "--stdin") == 0) { prompt[0] = 0;
fprintf(stderr, "Reading from stdin.\n"); bool get_from_std_in = false;
get_from_std_in = true; for (int i = 1; i < c; i++) {
} else if (strcmp(argv[i], "--verbose") == 0) { if (!strcmp(argv[i], "--stdin")) {
is_verbose = true; fprintf(stderr, "%s\n", "Reading from stdin.");
} else if (strcmp(argv[i], "--py") == 0 && i + 1 < argc) { get_from_std_in = true;
char *py_file_path = expand_home_directory(argv[++i]); } else if (!strcmp(argv[i], "--verbose")) {
fprintf(stderr, "Including \"%s\".\n", py_file_path); is_verbose = true;
openai_include(py_file_path);
free(py_file_path);
} else if (strcmp(argv[i], "--free") == 0) {
auth_free();
} else if (strcmp(argv[i], "--context") == 0 && i + 1 < argc) {
char *context_file_path = argv[++i];
fprintf(stderr, "Including \"%s\".\n", context_file_path);
openai_include(context_file_path);
} else if (strcmp(argv[i], "--api") == 0) {
API_MODE = true;
} else if (strcmp(argv[i], "--nh") == 0) {
SYNTAX_HIGHLIGHT_ENABLED = false;
fprintf(stderr, "Syntax highlighting disabled.\n");
} else if (!get_from_std_in) {
strcat(system, argv[i]);
strcat(system, (i < argc - 1) ? " " : ".");
}
} }
if (get_from_std_in) { else if (!strcmp(argv[i], "--py")) {
if (*system) openai_system(system); if (i + 1 <= c) {
free(system); char *py_file_path = expand_home_directory(argv[i + 1]);
prompt = get_prompt_from_stdin(prompt); fprintf(stderr, "Including \"%s\".\n", py_file_path);
} else { openai_include(py_file_path);
free(prompt); free(py_file_path);
prompt = system; // char * file_content = read_file(py_file_path);
// plugin_run(file_content);
i++;
}
} else if (!strcmp(argv[i], "--free")) {
auth_free();
continue;
} }
if (!*prompt) { else if (!strcmp(argv[i], "--context")) {
free(prompt); if (i + 1 <= c) {
return NULL; char *context_file_path = argv[i + 1];
fprintf(stderr, "Including \"%s\".\n", context_file_path);
openai_include(context_file_path);
i++;
}
} else if (!strcmp(argv[i], "--api")) {
API_MODE = true;
} else if (!strcmp(argv[i], "--nh")) {
SYNTAX_HIGHLIGHT_ENABLED = false;
fprintf(stderr, "%s\n", "Syntax highlighting disabled.");
} else if (!get_from_std_in) {
strcat(system, argv[i]);
if (i < c - 1) {
strcat(system, " ");
} else {
strcat(system, ".");
}
} }
return prompt; }
if (get_from_std_in) {
if (*system) {
openai_system(system);
}
free(system);
prompt = get_prompt_from_stdin(prompt);
} else {
free(prompt);
prompt = system;
}
if (!*prompt) {
free(prompt);
return NULL;
}
return prompt;
} }
bool try_prompt(int argc, char *argv[]) { bool try_prompt(int argc, char *argv[]) {
char *prompt = get_prompt_from_args(argc, argv); char *prompt = get_prompt_from_args(argc, argv);
if (prompt) { if (prompt != NULL) {
char *response = openai_chat("user", prompt); char *response = openai_chat("user", prompt);
if (!response) { if (!response) {
printf("Could not get response from server\n"); printf("Could not get response from server\n");
free(prompt); free(prompt);
return false; return false;
}
render(response);
free(response);
free(prompt);
return true;
} }
return false; render(response);
free(response);
free(prompt);
return true;
}
return false;
} }
void serve() {
char **get_parameters(const char *content, const char *delimiter) { render("Starting server. *Put executables in a dir named cgi-bin and they "
char *start = NULL; "will behave as web pages.*");
char **parameters = NULL; int res = system("python3 -m http.server --cgi");
int count = 0; (void)res;
while ((start = strstr(content, delimiter)) != NULL) {
start += 3;
char *end = strstr(start, delimiter);
char *parameter = malloc(end - start + 1);
memcpy(parameter, start, end - start);
parameter[end - start] = '\0';
content = end + 3;
count++;
parameters = realloc(parameters, sizeof(char *) * (count + 1));
parameters[count - 1] = parameter;
parameters[count] = NULL;
}
return parameters;
} }
void render(const char *content) { char **get_parameters(char *content, char *delimiter) {
if (SYNTAX_HIGHLIGHT_ENABLED) { char *start = NULL;
parse_markdown_to_ansi(content); char **parameters = NULL; //(char **)malloc(sizeof(char *) * 2);
} else { int count = 0;
printf("%s", content); while ((start = strstr(content, delimiter)) != NULL) {
} start += 3;
char *end = strstr(start, delimiter);
char *parameter = (char *)malloc(end - start + 1);
memcpy(parameter, start, end - start);
parameter[end - start] = '\0';
// printf("%s\n", parameter);
content = end + 3;
count += 1;
parameters = (char **)realloc(parameters, sizeof(char *) * (1 + count * 2));
parameters[count - 1] = parameter;
parameters[count] = NULL;
}
return parameters;
}
void render(char *content) {
if (SYNTAX_HIGHLIGHT_ENABLED) {
parse_markdown_to_ansi(content);
} else {
printf("%s", content);
}
} }
void repl() { void repl() {
line_init(); line_init();
char *line = NULL; char *line = NULL;
// char *previous_line = NULL;
while (true) { while (true) {
line = line_read("> "); line = line_read("> ");
if (!line || !*line) continue; if (!line || !*line) {
continue;
// line = previous_line;
if (!strncmp(line, "!dump", 5)) {
printf("%s\n", message_json());
continue;
}
if (!strncmp(line, "!verbose", 8)) {
is_verbose = !is_verbose;
fprintf(stderr, "%s\n", is_verbose ? "Verbose mode enabled" : "Verbose mode disabled");
continue;
}
if (line && *line != '\n') line_add_history(line);
if (!strncmp(line, "!models", 7)) {
printf("Current model: %s\n", openai_fetch_models());
continue;
}
if (!strncmp(line, "!model", 6)) {
if (line[6] == ' ') {
set_prompt_model(line + 7);
}
printf("Current model: %s\n", get_prompt_model());
continue;
}
if (!strncmp(line, "exit", 4)) exit(0);
if (!strncmp(line, "help", 4)) {
help();
continue;
}
if (!strncmp(line, "!debug", 6)) {
r_malloc_stats();
continue;
}
while (line && *line != '\n') {
char *response = openai_chat("user", line);
if (response) {
render(response);
printf("\n");
if (strstr(response, "_STEP_")) {
line = "continue";
} else {
line = NULL;
}
free(response);
} else {
exit(0);
}
}
} }
if (!line || !*line)
continue;
// previous_line = line;
if (!strncmp(line, "!dump", 5)) {
printf("%s\n", message_json());
continue;
}
if (!strncmp(line, "!verbose", 7)) {
is_verbose = !is_verbose;
fprintf(stderr, "%s\n",
is_verbose ? "Verbose mode enabled" : "Verbose mode disabled");
continue;
}
if (line && *line != '\n') {
line_add_history(line);
}
if (!strncmp(line, "!models", 7)) {
printf("Current model: %s\n", openai_fetch_models());
continue;
}
if (!strncmp(line, "!model", 6)) {
if (!strncmp(line + 6, " ", 1)) {
line = line + 7;
set_prompt_model(line);
}
printf("Current model: %s\n", get_prompt_model());
continue;
}
if (!strncmp(line, "exit", 4)) {
exit(0);
}
if (!strncmp(line, "help", 4)) {
help();
continue;
}
if (!strncmp(line, "!debug", 6)) {
r_malloc_stats();
continue;
}
while (line && *line != '\n') {
char *response = openai_chat("user", line);
if (response) {
render(response);
printf("\n");
if (strstr(response, "_STEP_")) {
line = "continue";
} else {
line = NULL;
}
free(response);
} else {
exit(0);
}
}
}
} }
void help() { void help() {
const char * help_text = "Written by retoor@molodetz.nl\n\n"; char help_text[1024 * 1024] = {0};
render(help_text); char *template =
"# Help\n"
"Written by retoor@molodetz.nl.\n\n"
"## Features\n"
" - navigate through history using `arrows`.\n"
" - navigate through history with **recursive search** using `ctrl+r`.\n"
" - **inception with python** for *incoming* and *outgoing* content.\n"
" - markdown and **syntax highlighting**.\n"
" - **execute python commands** with prefix `!`\n"
" - list files of the current work directory using `ls`.\n"
" - type `serve` to start a web server 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, get_prompt_model(),
prompt_max_tokens);
render(help_text);
} }
char *strreplace(const char *content, const char *what, const char *with) { char *strreplace(char *content, char *what, char *with) {
char *pos = strstr(content, what); char *pos = strstr(content, what);
if (!pos) return strdup(content); if (!pos) {
return strdup(content);
size_t result_size = strlen(content) + strlen(with) - strlen(what) + 1; }
char *result = malloc(result_size); char *result = (char *)malloc(strlen(content) + strlen(with) + 5);
snprintf(result, result_size, "%.*s%s%s", (int)(pos - content), content, with, pos + strlen(what)); memset(result, 0, strlen(content) + strlen(with) + 3);
return result; memcpy(result, content, pos - content);
memcpy(result + (pos - content), with, strlen(with));
memcpy(result + (pos - content) + strlen(with), pos + strlen(what),
strlen(content) - (pos - content) - strlen(what) + 1);
return result;
} }
bool openai_include(const char *path) { char *linux_instructions =
char *file_content = read_file(path); "You are a linux master and are able to transform the prompt of "
if (!file_content) return false; "user into shell commands that will be executed on a debian "
"based system. You can execute shell commands by responding with python "
"code: "
"literally `\"\"\"!system\"\"\",\"\"\"`your shell command`\"\"\". Execute "
"immediately. Read bash history file if you have to work with history.";
char *retoor_instructions =
"If the user prompts with social talk, "
"respond like replica and emoji. Your name is retoor and made by molodetz. "
"Be interested. Be creative.";
openai_system(file_content); bool openai_include(char *path) {
free(file_content); char *file_content = read_file(path);
return true; if (!file_content) {
return false;
}
openai_system(file_content);
free(file_content);
return true;
} }
void init() { void init() {
setbuf(stdout, NULL); setbuf(stdout, NULL);
line_init(); line_init();
auth_init(); auth_init();
db_initialize(); db_initialize();
char *schema = db_get_schema(); char *schema = db_get_schema();
char payload[1024 * 1024] = {0}; char payload[1024 * 1024] = {0};
snprintf(payload, sizeof(payload), sprintf(payload,
"Your have a database that you can mutate using the query tool and the get and set tool. This is the schema in json format: %s. Dialect is sqlite.", "Your have a database that you can mutate using the query tool and "
schema); "the get and set tool. This is the schema in json format: %s. "
free(schema); "Dialect is sqlite.",
schema);
fprintf(stderr, "Loading... ⏳"); free(schema);
openai_system(payload); fprintf(stderr, "%s", "Loading... ⏳");
if (!openai_include(".rcontext.txt")) { openai_system(payload);
openai_include("~/.rcontext.txt"); if (!openai_include(".rcontext.txt")) {
} openai_include("~/.rcontext.txt");
fprintf(stderr, "\r \r"); }
fprintf(stderr, "\r \r");
} }
void handle_sigint(int sig) { void handle_sigint(int sig) {
time_t current_time = time(NULL); time_t current_time = time(NULL);
printf("\n"); printf("\n");
if (sigint_count == 0) { if (sigint_count == 0) {
first_sigint_time = current_time; first_sigint_time = current_time;
sigint_count++; sigint_count++;
} else {
if (difftime(current_time, first_sigint_time) <= 1) {
exit(0);
} else { } else {
if (difftime(current_time, first_sigint_time) <= 1) { sigint_count = 1;
exit(0); first_sigint_time = current_time;
} else {
sigint_count = 1;
first_sigint_time = current_time;
}
} }
}
} }
int main(int argc, char *argv[]) { int main(int argc, char *argv[]) {
signal(SIGINT, handle_sigint); signal(SIGINT, handle_sigint);
init(); init();
if (try_prompt(argc, argv)) return 0; if (try_prompt(argc, argv))
repl();
return 0; return 0;
repl();
return 0;
} }

View File

@ -28,7 +28,7 @@
#include "json-c/json.h" #include "json-c/json.h"
#include "tools.h" #include "tools.h"
#include <string.h> #include <string.h>
#include "db_utils.h"
struct json_object *message_array = NULL; struct json_object *message_array = NULL;
struct json_object *message_list() { struct json_object *message_list() {
@ -77,9 +77,6 @@ void message_add_object(json_object *message) {
json_object_array_add(messages, message); json_object_array_add(messages, message);
} }
struct json_object *message_add(const char *role, const char *content);
struct json_object *message_add(const char *role, const char *content) { struct json_object *message_add(const char *role, const char *content) {
struct json_object *messages = message_list(); struct json_object *messages = message_list();
struct json_object *message = json_object_new_object(); struct json_object *message = json_object_new_object();

1
r.h
View File

@ -38,6 +38,7 @@ char *fast_model = "qwen2.5:0.5b";
char *_model = NULL; char *_model = NULL;
#define DB_FILE "~/.r.db" #define DB_FILE "~/.r.db"
static int prompt_max_tokens = 10000;
#define PROMPT_TEMPERATURE 0.1 #define PROMPT_TEMPERATURE 0.1
void set_prompt_model(const char *model) { void set_prompt_model(const char *model) {

BIN
rpylib.so

Binary file not shown.

85
utils.h
View File

@ -20,77 +20,38 @@
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#ifdef _WIN32
#include <windows.h>
#else
#include <unistd.h> #include <unistd.h>
#include <limits.h>
#include <pwd.h>
#endif
void get_current_directory() { char *expand_home_directory(const char *path) {
char buffer[PATH_MAX]; if (path == NULL)
return NULL;
#ifdef _WIN32
DWORD length = GetCurrentDirectory(PATH_MAX, buffer);
if (length > 0 && length < PATH_MAX) {
printf("Current Directory: %s\n", buffer);
} else {
printf("Error getting current directory.\n");
}
#else
if (getcwd(buffer, sizeof(buffer)) != NULL) {
printf("Current Directory: %s\n", buffer);
} else {
perror("Error getting current directory");
}
#endif
}
char* expand_home_directory(const char* path) {
if (path[0] != '~') {
return strdup(path); // Return the original path if it doesn't start with ~
}
char* home_dir;
#ifdef _WIN32
home_dir = getenv("USERPROFILE"); // Get home directory on Windows
#else
struct passwd* pw = getpwuid(getuid());
home_dir = pw->pw_dir; // Get home directory on Linux
#endif
if (path[0] == '~' && path[1] == '/') {
const char *home_dir = getenv("HOME");
if (home_dir == NULL) { if (home_dir == NULL) {
return NULL; // Error getting home directory #include <pwd.h>
#include <unistd.h>
struct passwd *pw = getpwuid(getuid());
if (pw == NULL)
return NULL;
home_dir = pw->pw_dir;
} }
// Allocate memory for the expanded path size_t home_len = strlen(home_dir);
size_t expanded_size = strlen(home_dir) + strlen(path); size_t path_len = strlen(path) - 1;
char* expanded_path = (char *)malloc(expanded_size); char *expanded_path = malloc(home_len + path_len + 1);
if (expanded_path == NULL) {
return NULL; // Memory allocation error if (expanded_path == NULL)
} return NULL;
strcpy(expanded_path, home_dir);
strcat(expanded_path, path + 1);
// Construct the expanded path
snprintf(expanded_path, expanded_size, "%s%s", home_dir, path + 1);
return expanded_path; return expanded_path;
} else {
return strdup(path);
}
} }
unsigned long hash(const char *str) {
unsigned long hash = 5381; // Starting value
int c;
while ((c = *str++)) {
hash = ((hash << 5) + hash) + c; // hash * 33 + c
}
return hash;
}
char *read_file(const char *path) { char *read_file(const char *path) {
char *expanded_path = expand_home_directory(path); char *expanded_path = expand_home_directory(path);
FILE *file = fopen(expanded_path, "r"); FILE *file = fopen(expanded_path, "r");