Compare commits

...

3 Commits

Author SHA1 Message Date
c64c92e1cc Update. 2025-03-30 01:09:06 +01:00
8d0ed4f185 Working version. 2025-03-30 00:13:42 +01:00
e0c4d650c6 Update indexer.h 2025-03-28 23:22:57 +01:00
9 changed files with 412 additions and 471 deletions

37
Dockerfile Normal file
View File

@ -0,0 +1,37 @@
# 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,28 +1,35 @@
all: build build_rd build_free build_rpylib run_free all: build build_rd build_free build_rpylib run build_mingw
# 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
@ -31,3 +38,14 @@ 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

10
compose.yml Normal file
View File

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

211
indexer.h
View File

@ -7,151 +7,106 @@
#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",
static size_t ext_count = ".go", ".rb", ".swift", ".php", ".pl", ".sh", ".bash", ".sql",
sizeof(extensions) / ".xml", ".yaml", ".yml", ".kt", ".dart", ".scala", ".clj", ".asm",
sizeof( ".m", ".r", ".lua", ".groovy", ".v", ".pas", ".d", ".f90", ".f95",
extensions[0]); // Updated count to reflect the new number of extensions ".for", ".s", ".tcl", ".vhdl", ".verilog", ".coffee", ".less", ".scss",
".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;
FileInfo file_list[MAX_FILES]; static FileInfo file_list[MAX_FILES];
size_t file_count = 0; static size_t file_count = 0;
int is_valid_extension(const char *filename, const char *extensions[], static int is_valid_extension(const char *filename) {
size_t ext_count) { const char *dot = strrchr(filename, '.');
const char *dot = strrchr(filename, '.'); if (!dot) dot = filename;
if (!dot) { for (size_t i = 0; i < ext_count; i++) {
dot = filename; if (strcmp(dot, extensions[i]) == 0) return 1;
}
for (size_t i = 0; i < ext_count; i++) {
if (strcmp(dot, extensions[i]) == 0) {
return 1;
} }
} return 0;
return 0;
} }
int is_ignored_directory(const char *dir_name) { static int is_ignored_directory(const char *dir_name) {
const char *ignored_dirs[] = {"env", ".venv", "node_modules", "venv", const char *ignored_dirs[] = {"env", ".venv", "node_modules", "venv", "virtualenv"};
"virtualenv"}; for (size_t i = 0; i < sizeof(ignored_dirs) / sizeof(ignored_dirs[0]); i++) {
for (size_t i = 0; i < sizeof(ignored_dirs) / sizeof(ignored_dirs[0]); i++) { if (strcmp(dir_name, ignored_dirs[i]) == 0) return 1;
if (strcmp(dir_name, ignored_dirs[i]) == 0) {
return 1;
} }
} return 0;
return 0;
} }
void get_file_info(const char *path) { static 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, strncpy(info.name, path, MAX_PATH - 1);
MAX_PATH - info.name[MAX_PATH - 1] = '\0';
1); // Copy with one less to leave space for null terminator strftime(info.modification_date, sizeof(info.modification_date), "%Y-%m-%d %H:%M:%S", localtime(&file_stat.st_mtime));
info.name[MAX_PATH - 1] = '\0'; // Ensure null termination strftime(info.creation_date, sizeof(info.creation_date), "%Y-%m-%d %H:%M:%S", localtime(&file_stat.st_ctime));
strftime(info.modification_date, sizeof(info.modification_date), strncpy(info.type, S_ISDIR(file_stat.st_mode) ? "directory" : "file", sizeof(info.type) - 1);
"%Y-%m-%d %H:%M:%S", localtime(&file_stat.st_mtime)); info.type[sizeof(info.type) - 1] = '\0';
strftime(info.creation_date, sizeof(info.creation_date), info.size_bytes = file_stat.st_size;
"%Y-%m-%d %H:%M:%S", localtime(&file_stat.st_ctime)); file_list[file_count++] = info;
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);
struct dirent *entry; if (!dir) {
if (dir == NULL) { perror("Failed to open directory");
perror("Failed to open directory"); return NULL;
return NULL;
}
json_object *jarray = json_object_new_array();
while ((entry = readdir(dir)) != NULL) {
if (strcmp(entry->d_name, ".") != 0 && strcmp(entry->d_name, "..") != 0) {
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);
if (entry->d_type == DT_DIR) {
char *subdir_json = index_directory(full_path);
if (subdir_json) {
json_object *jsubdir = json_object_new_string(subdir_json);
json_object_array_add(jarray, jsubdir);
free(subdir_json);
}
} else if (is_valid_extension(entry->d_name, extensions, ext_count)) {
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));
// Read the file contents
FILE *fp = fopen(file_list[file_count - 1].name, "r");
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)); struct dirent *entry;
json_object_put(jarray); json_object *jarray = json_object_new_array();
return result;
} while ((entry = readdir(dir)) != NULL) {
if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) 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);
if (entry->d_type == DT_DIR) {
char *subdir_json = index_directory(full_path);
if (subdir_json) {
json_object *jsubdir = json_object_new_string(subdir_json);
json_object_array_add(jarray, jsubdir);
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);
}
}
closedir(dir);
char *result = strdup(json_object_to_json_string(jarray));
json_object_put(jarray);
return result;
}

506
main.c
View File

@ -1,381 +1,261 @@
// 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(char *); void render(const char *);
bool openai_include(char *path); bool openai_include(const char *);
char *strreplace(char *content, char *what, char *with); char *strreplace(const char *, const char *, const char *);
char *get_prompt_from_stdin(char *prompt) { char *get_prompt_from_stdin(char *prompt) {
int index = 0; int index = 0;
prompt[index] = '\0'; char c;
char c = 0; while ((c = getchar()) != EOF) {
while ((c = getchar()) != EOF) { prompt[index++] = c;
prompt[index++] = c; }
} prompt[index] = '\0';
prompt[index++] = '\0'; return prompt;
return prompt;
} }
char *get_prompt_from_args(int c, char **argv) { char *get_prompt_from_args(int argc, char **argv) {
char *prompt = (char *)malloc(1024 * 1024 * 10 + 1); char *prompt = malloc(10 * 1024 * 1024 + 1);
char *system = (char *)malloc(1024 * 1024); char *system = malloc(1024 * 1024);
bool get_from_std_in = false;
system[0] = 0; for (int i = 1; i < argc; i++) {
prompt[0] = 0; if (strcmp(argv[i], "--stdin") == 0) {
bool get_from_std_in = false; fprintf(stderr, "Reading from stdin.\n");
for (int i = 1; i < c; i++) { get_from_std_in = true;
if (!strcmp(argv[i], "--stdin")) { } else if (strcmp(argv[i], "--verbose") == 0) {
fprintf(stderr, "%s\n", "Reading from stdin."); is_verbose = true;
get_from_std_in = true; } else if (strcmp(argv[i], "--py") == 0 && i + 1 < argc) {
} else if (!strcmp(argv[i], "--verbose")) { char *py_file_path = expand_home_directory(argv[++i]);
is_verbose = true; fprintf(stderr, "Including \"%s\".\n", py_file_path);
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) ? " " : ".");
}
} }
else if (!strcmp(argv[i], "--py")) { if (get_from_std_in) {
if (i + 1 <= c) { if (*system) openai_system(system);
char *py_file_path = expand_home_directory(argv[i + 1]); free(system);
fprintf(stderr, "Including \"%s\".\n", py_file_path); prompt = get_prompt_from_stdin(prompt);
openai_include(py_file_path); } else {
free(py_file_path); free(prompt);
// char * file_content = read_file(py_file_path); prompt = system;
// plugin_run(file_content);
i++;
}
} else if (!strcmp(argv[i], "--free")) {
auth_free();
continue;
} }
else if (!strcmp(argv[i], "--context")) { if (!*prompt) {
if (i + 1 <= c) { free(prompt);
char *context_file_path = argv[i + 1]; return NULL;
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 != NULL) { if (prompt) {
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;
} }
render(response); return false;
free(response);
free(prompt);
return true;
}
return false;
} }
void serve() {
render("Starting server. *Put executables in a dir named cgi-bin and they " char **get_parameters(const char *content, const char *delimiter) {
"will behave as web pages.*"); char *start = NULL;
int res = system("python3 -m http.server --cgi"); char **parameters = NULL;
(void)res; int count = 0;
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;
} }
char **get_parameters(char *content, char *delimiter) { void render(const char *content) {
char *start = NULL; if (SYNTAX_HIGHLIGHT_ENABLED) {
char **parameters = NULL; //(char **)malloc(sizeof(char *) * 2); parse_markdown_to_ansi(content);
int count = 0; } else {
while ((start = strstr(content, delimiter)) != NULL) { printf("%s", content);
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) {
line = line_read("> ");
if (!line || !*line) {
continue;
// line = previous_line;
}
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); while (true) {
} line = line_read("> ");
if (!strncmp(line, "!models", 7)) { if (!line || !*line) continue;
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 { 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);
line = NULL; 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;
} }
free(response); while (line && *line != '\n') {
} else { char *response = openai_chat("user", line);
exit(0); if (response) {
} render(response);
printf("\n");
if (strstr(response, "_STEP_")) {
line = "continue";
} else {
line = NULL;
}
free(response);
} else {
exit(0);
}
}
} }
}
} }
void help() { void help() {
char help_text[1024 * 1024] = {0}; const char * help_text = "Written by retoor@molodetz.nl\n\n";
char *template = render(help_text);
"# 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(char *content, char *what, char *with) { char *strreplace(const char *content, const char *what, const char *with) {
char *pos = strstr(content, what); char *pos = strstr(content, what);
if (!pos) { if (!pos) return strdup(content);
return strdup(content);
} size_t result_size = strlen(content) + strlen(with) - strlen(what) + 1;
char *result = (char *)malloc(strlen(content) + strlen(with) + 5); char *result = malloc(result_size);
memset(result, 0, strlen(content) + strlen(with) + 3); snprintf(result, result_size, "%.*s%s%s", (int)(pos - content), content, with, pos + strlen(what));
memcpy(result, content, pos - content); return result;
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;
} }
char *linux_instructions = bool openai_include(const char *path) {
"You are a linux master and are able to transform the prompt of " char *file_content = read_file(path);
"user into shell commands that will be executed on a debian " if (!file_content) return false;
"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.";
bool openai_include(char *path) { openai_system(file_content);
char *file_content = read_file(path); free(file_content);
if (!file_content) { return true;
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};
sprintf(payload, snprintf(payload, sizeof(payload),
"Your have a database that you can mutate using the query tool and " "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.",
"the get and set tool. This is the schema in json format: %s. " schema);
"Dialect is sqlite.", free(schema);
schema);
free(schema); fprintf(stderr, "Loading... ⏳");
fprintf(stderr, "%s", "Loading... ⏳"); openai_system(payload);
openai_system(payload); if (!openai_include(".rcontext.txt")) {
if (!openai_include(".rcontext.txt")) { 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 {
sigint_count = 1; if (difftime(current_time, first_sigint_time) <= 1) {
first_sigint_time = current_time; exit(0);
} 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)) if (try_prompt(argc, argv)) return 0;
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,6 +77,9 @@ 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,7 +38,6 @@ 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,38 +20,77 @@
#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>
char *expand_home_directory(const char *path) {
if (path == NULL)
return NULL;
if (path[0] == '~' && path[1] == '/') {
const char *home_dir = getenv("HOME");
if (home_dir == NULL) {
#include <pwd.h> #include <pwd.h>
#include <unistd.h> #endif
struct passwd *pw = getpwuid(getuid());
if (pw == NULL) void get_current_directory() {
return NULL; char buffer[PATH_MAX];
home_dir = pw->pw_dir;
#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 ~
} }
size_t home_len = strlen(home_dir); char* home_dir;
size_t path_len = strlen(path) - 1;
char *expanded_path = malloc(home_len + path_len + 1);
if (expanded_path == NULL) #ifdef _WIN32
return NULL; 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
strcpy(expanded_path, home_dir); if (home_dir == NULL) {
strcat(expanded_path, path + 1); return NULL; // Error getting home directory
}
// Allocate memory for the expanded path
size_t expanded_size = strlen(home_dir) + strlen(path);
char* expanded_path = (char *)malloc(expanded_size);
if (expanded_path == NULL) {
return NULL; // Memory allocation error
}
// 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");