2025-01-04 08:40:31 +01:00
// 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.
2025-01-04 06:00:03 +01:00
# include "openai.h"
# include "markdown.h"
# include "line.h"
# include <locale.h>
# include <stdio.h>
2025-01-04 08:40:31 +01:00
# include <stdlib.h>
# include <string.h>
# include <unistd.h>
2025-03-05 23:53:35 +01:00
# include "utils.h"
2025-01-04 06:00:03 +01:00
2025-02-13 19:09:29 +01:00
bool SYNTAX_HIGHLIGHT_ENABLED = true ;
bool API_MODE = false ;
void help ( ) ;
void render ( char * ) ;
bool openai_include ( char * path ) ;
char * strreplace ( char * content , char * what , char * with ) ;
2025-01-26 02:54:45 +01:00
char * get_prompt_from_stdin ( char * prompt ) {
int index = 0 ;
prompt [ index ] = ' \0 ' ;
2025-01-25 14:19:01 +01:00
char c = 0 ;
while ( ( c = getchar ( ) ) ! = EOF ) {
prompt [ index + + ] = c ;
}
2025-01-26 02:54:45 +01:00
prompt [ index + + ] = ' \0 ' ;
2025-01-25 14:19:01 +01:00
return prompt ;
}
2025-01-04 08:40:31 +01:00
char * get_prompt_from_args ( int c , char * * argv ) {
2025-02-13 19:09:29 +01:00
char * prompt = ( char * ) malloc ( 1024 * 1024 * 10 + 1 ) ;
char * system = ( char * ) malloc ( 1024 * 1024 ) ;
system [ 0 ] = 0 ;
2025-01-04 06:00:03 +01:00
prompt [ 0 ] = 0 ;
2025-02-13 19:09:29 +01:00
bool get_from_std_in = false ;
2025-01-04 08:40:31 +01:00
for ( int i = 1 ; i < c ; i + + ) {
2025-01-25 14:19:01 +01:00
if ( ! strcmp ( argv [ i ] , " --stdin " ) ) {
2025-02-13 19:09:29 +01:00
fprintf ( stderr , " %s \n " , " Reading from stdin. " ) ;
get_from_std_in = true ;
} else if ( ! strcmp ( argv [ i ] , " --context " ) ) {
if ( i + 1 < = c ) {
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 ] ) ;
2025-01-25 14:19:01 +01:00
if ( i < c - 1 ) {
2025-02-13 19:09:29 +01:00
strcat ( system , " " ) ;
2025-01-25 14:19:01 +01:00
} else {
2025-02-13 19:09:29 +01:00
strcat ( system , " . " ) ;
2025-01-25 14:19:01 +01:00
}
2025-01-04 06:00:03 +01:00
}
}
2025-02-13 19:09:29 +01:00
if ( get_from_std_in ) {
if ( * system ) {
openai_system ( system ) ;
}
free ( system ) ;
prompt = get_prompt_from_stdin ( prompt ) ;
} else {
free ( prompt ) ;
prompt = system ;
}
2025-01-04 08:40:31 +01:00
if ( ! * prompt ) {
2025-01-04 06:00:03 +01:00
free ( prompt ) ;
return NULL ;
}
return prompt ;
}
2025-01-04 08:40:31 +01:00
bool try_prompt ( int argc , char * argv [ ] ) {
char * prompt = get_prompt_from_args ( argc , argv ) ;
if ( prompt ! = NULL ) {
char * response = openai_chat ( " user " , prompt ) ;
2025-01-26 02:54:45 +01:00
if ( ! response ) {
printf ( " Could not get response from server \n " ) ;
free ( prompt ) ;
return false ;
}
2025-02-13 19:09:29 +01:00
render ( response ) ;
2025-01-04 06:00:03 +01:00
free ( response ) ;
free ( prompt ) ;
return true ;
}
return false ;
}
2025-01-04 08:35:39 +01:00
void serve ( ) {
2025-01-04 08:40:31 +01:00
render ( " Starting server. *Put executables in a dir named cgi-bin and they will behave as web pages.* " ) ;
2025-01-04 06:00:03 +01:00
int res = system ( " python3 -m http.server --cgi " ) ;
( void ) res ;
}
2025-02-13 19:09:29 +01:00
char * * get_parameters ( char * content , char * delimiter ) {
char * start = NULL ;
char * * parameters = NULL ; //(char **)malloc(sizeof(char *) * 2);
int count = 0 ;
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 ) {
char * * parameters = get_parameters ( content , " \" \" \" " ) ;
int parameter_index = 0 ;
bool print_result = true ;
while ( parameters ) {
char * parameter = parameters [ parameter_index ] ;
if ( ! parameter )
break ;
print_result = false ;
if ( ! strcmp ( parameter , " !find_note " ) ) {
char * note_name = parameters [ parameter_index + 1 ] ;
FILE * file = fopen ( " notes.txt " , " r " ) ;
fseek ( file , 0 , SEEK_END ) ;
long size = ftell ( file ) ;
fseek ( file , 0 , SEEK_SET ) ;
char * buffer = ( char * ) malloc ( size + 1 ) ;
size = fread ( buffer , 1 , size , file ) ;
buffer [ size ] = ' \0 ' ;
fclose ( file ) ;
char * prompt = ( char * ) malloc ( size + 1000 ) ;
prompt [ 0 ] = 0 ;
sprintf ( prompt , " This are records seperated by newline: ```%s```. Respond to use with record that is about ```%s```. Rspond in plain text, do not execute command. " , buffer , note_name ) ;
char * result = openai_chat ( " user " , prompt ) ;
2025-03-05 23:53:35 +01:00
2025-02-13 19:09:29 +01:00
free ( buffer ) ;
2025-03-05 23:53:35 +01:00
free ( prompt ) ;
if ( result ) {
printf ( " %s \n " , result ) ;
free ( result ) ;
}
2025-02-13 19:09:29 +01:00
}
if ( ! strcmp ( parameter , " !write_note " ) ) {
char * file_name = " notes.txt " ;
char * file_content = parameters [ parameter_index + 1 ] ;
FILE * file = fopen ( file_name , " a+ " ) ;
fprintf ( file , " %s \n \n " , file_content ) ;
fclose ( file ) ;
}
if ( ! strcmp ( parameter , " !write_file " ) ) {
char * file_name = parameters [ parameter_index + 1 ] ;
printf ( " Writing to file: %s \n " , file_name ) ;
char * file_content = parameters [ parameter_index + 2 ] ;
FILE * file = fopen ( file_name , " w " ) ;
fprintf ( file , " %s " , file_content ) ;
fclose ( file ) ;
}
if ( ! strcmp ( parameter , " !system " ) ) {
// printf("%s\n",parameters[parameter_index+1]);
char * command = parameters [ parameter_index + 1 ] ;
FILE * f = popen ( command , " r " ) ; ;
if ( ! f ) {
printf ( " Execution failed: %s \n " , command ) ;
}
char buffer [ 4096 ] ;
char * full_buffer = ( char * ) malloc ( 1 ) ;
int bytes_read = 0 ;
while ( fgets ( buffer , sizeof ( buffer ) , f ) ! = NULL ) {
full_buffer = realloc ( full_buffer , bytes_read + strlen ( buffer ) + 1 ) ;
memcpy ( full_buffer + bytes_read , buffer , strlen ( buffer ) ) ;
bytes_read + = strlen ( buffer ) ;
printf ( " %s " , buffer ) ;
fflush ( stdout ) ;
}
pclose ( f ) ;
full_buffer [ bytes_read ] = ' \0 ' ;
//printf("%s",full_buffer);
char * prompt = ( char * ) malloc ( strlen ( full_buffer ) + 1000 ) ;
prompt [ 0 ] = 0 ;
printf ( prompt , " Last execution result and thus current context is: ```%s``` \n " , full_buffer ) ;
char * rmsg = openai_chat ( " system " , full_buffer ) ;
//printf("%s\n",rmsg);
free ( prompt ) ;
free ( rmsg ) ;
free ( full_buffer ) ;
} else if ( parameter [ 0 ] = = ' ! ' ) {
printf ( " %s \n " , parameter ) ;
}
parameter_index + = 1 ;
}
if ( ! print_result ) {
return ;
}
if ( SYNTAX_HIGHLIGHT_ENABLED )
{
parse_markdown_to_ansi ( content ) ;
printf ( " \n \n " ) ;
} else {
printf ( " %s " , content ) ;
}
2025-01-04 06:00:03 +01:00
}
2025-01-04 08:35:39 +01:00
void repl ( ) {
2025-01-04 06:00:03 +01:00
line_init ( ) ;
2025-01-26 02:54:45 +01:00
char * line = NULL ;
2025-01-04 06:00:03 +01:00
char * previous_line = NULL ;
2025-01-04 08:40:31 +01:00
while ( ( line = line_read ( " > " ) ) ) {
if ( ! line | | ! * line ) {
2025-01-04 06:00:03 +01:00
line = previous_line ;
}
2025-01-04 08:40:31 +01:00
if ( ! line | | ! * line )
2025-01-04 06:00:03 +01:00
continue ;
previous_line = line ;
2025-02-13 19:09:29 +01:00
2025-01-04 08:40:31 +01:00
if ( ! strncmp ( line , " exit " , 4 ) ) {
2025-01-04 06:00:03 +01:00
exit ( 0 ) ;
}
2025-01-04 08:40:31 +01:00
if ( ! strncmp ( line , " help " , 4 ) ) {
2025-01-04 06:00:03 +01:00
help ( ) ;
continue ;
}
2025-01-04 08:40:31 +01:00
if ( ! strncmp ( line , " serve " , 5 ) ) {
2025-02-13 19:09:29 +01:00
continue ;
2025-01-04 06:00:03 +01:00
serve ( ) ;
}
2025-02-13 19:09:29 +01:00
if ( ! strncmp ( line , " retoor " , 6 ) ) {
openai_include ( " retoor " ) ;
}
2025-01-04 08:40:31 +01:00
if ( ! strncmp ( line , " spar " , 5 ) ) {
char * response = line + 5 ;
while ( true ) {
2025-01-04 06:00:03 +01:00
render ( response ) ;
sleep ( 2 ) ;
2025-01-04 08:40:31 +01:00
response = openai_chat ( " user " , response ) ;
2025-01-04 08:35:39 +01:00
}
2025-01-04 06:00:03 +01:00
}
2025-02-13 19:09:29 +01:00
if ( ! strncmp ( line , " /_ " , 2 ) | | ! strncmp ( line , " ____ " , 4 ) ) {
continue ;
2025-01-04 06:00:03 +01:00
int offset = 2 ;
2025-01-04 08:40:31 +01:00
if ( ! strncmp ( line , " list " , 4 ) ) {
2025-01-04 06:00:03 +01:00
offset = 4 ;
}
2025-01-04 08:40:31 +01:00
char * command = ( char * ) malloc ( strlen ( line ) + 42 ) ;
2025-01-26 02:54:45 +01:00
command [ 0 ] = ' \0 ' ;
2025-01-04 06:00:03 +01:00
strcpy ( command , " ls " ) ;
strcat ( command , line + offset ) ;
int res = system ( command ) ;
( void ) res ;
free ( command ) ;
continue ;
}
2025-01-26 02:54:45 +01:00
if ( * line ) {
line_add_history ( line ) ;
char * response = openai_chat ( " user " , line ) ;
2025-03-05 23:53:35 +01:00
if ( response ) {
render ( response ) ;
printf ( " \n " ) ;
free ( response ) ;
}
2025-01-26 02:54:45 +01:00
}
2025-01-04 06:00:03 +01:00
}
}
2025-01-04 08:35:39 +01:00
void help ( ) {
2025-01-04 08:40:31 +01:00
char help_text [ 1024 * 1024 ] = { 0 } ;
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 , prompt_model , prompt_max_tokens ) ;
2025-01-04 08:35:39 +01:00
render ( help_text ) ;
2025-01-04 06:00:03 +01:00
}
2025-02-13 19:09:29 +01:00
char * strreplace ( char * content , char * what , char * with ) {
char * pos = strstr ( content , what ) ;
if ( ! pos ) {
return strdup ( content ) ;
}
char * result = ( char * ) malloc ( strlen ( content ) + strlen ( with ) + 5 ) ;
memset ( result , 0 , strlen ( content ) + strlen ( with ) + 3 ) ;
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 ;
}
char * linux_instructions =
" You are a linux master and are able to transform the prompt of "
" 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. " ;
2025-01-04 16:54:48 +01:00
bool openai_include ( char * path ) {
2025-02-13 19:09:29 +01:00
if ( ! strcmp ( path , " retoor " ) ) {
render ( " **Loading retoor.** " ) ;
size_t new_size = strlen ( linux_instructions ) + strlen ( retoor_instructions ) + 10 ;
char * all = ( char * ) malloc ( new_size ) ;
memset ( all , 0 , new_size ) ;
strcpy ( all , linux_instructions ) ;
strcat ( all , retoor_instructions ) ;
openai_chat ( " system " , all ) ;
free ( all ) ;
render ( " **Retoor is loaded. Retoor can do bash. Retoor can do all the bash.** " ) ;
render ( " Let's diagnose your computer and network together by asking things like: \n "
" 1. how many devices are there on my network? Check also MDNS devices. \n "
" 2 does my network does something suspicious? \n "
" 3. can you benchmark https://molodetz.nl? \n "
" 4. do i run strange processes? \n "
" 5. what is the performance of my pc? \n "
" 6. describe my hardware. \n "
" 7. please make a backup from my current directory. \n "
" 8. find ten largest folders on my pc using sudo. " ) ;
return true ;
}
2025-03-05 23:53:35 +01:00
char * expanded_path = expand_home_directory ( path ) ;
FILE * file = fopen ( expanded_path , " r " ) ;
free ( expanded_path ) ;
2025-01-04 08:40:31 +01:00
if ( file = = NULL ) {
2025-01-04 16:54:48 +01:00
return false ;
2025-01-04 06:00:03 +01:00
}
fseek ( file , 0 , SEEK_END ) ;
long size = ftell ( file ) ;
fseek ( file , 0 , SEEK_SET ) ;
2025-01-26 02:54:45 +01:00
char * buffer = ( char * ) malloc ( size + 1 ) ;
2025-01-04 08:40:31 +01:00
size_t read = fread ( buffer , 1 , size , file ) ;
if ( read = = 0 ) {
2025-01-04 16:54:48 +01:00
return false ;
2025-01-04 06:00:03 +01:00
}
fclose ( file ) ;
2025-01-26 02:54:45 +01:00
buffer [ read ] = ' \0 ' ;
2025-02-13 19:09:29 +01:00
char * replaced_linux = strreplace ( buffer , " [linux] " , linux_instructions ) ;
char * replaced_retoor = strreplace ( replaced_linux , " [retoor] " , retoor_instructions ) ;
openai_system ( replaced_retoor ) ;
free ( replaced_retoor ) ;
free ( replaced_linux ) ;
2025-01-04 06:00:03 +01:00
free ( buffer ) ;
2025-01-04 16:54:48 +01:00
return true ;
2025-01-04 06:00:03 +01:00
}
2025-01-04 08:35:39 +01:00
void init ( ) {
2025-01-04 16:54:48 +01:00
setbuf ( stdout , NULL ) ;
2025-01-04 08:35:39 +01:00
line_init ( ) ;
const char * locale = setlocale ( LC_ALL , NULL ) ;
char payload [ 4096 ] = { 0 } ;
2025-01-04 16:54:48 +01:00
sprintf ( payload , " Your locale is %s. User lang is %s. " , locale , locale ) ;
2025-02-13 19:09:29 +01:00
fprintf ( stderr , " %s " , " Loading... ⏳ " ) ;
2025-01-04 08:35:39 +01:00
openai_system ( payload ) ;
2025-01-04 16:54:48 +01:00
if ( ! openai_include ( " .rcontext.txt " ) ) {
openai_include ( " ~/.rcontext.txt " ) ;
}
2025-01-05 22:59:51 +01:00
# ifndef FREE_VERSION
2025-02-13 19:09:29 +01:00
fprintf ( stderr , " %s " , " \r ✅ Commercial version. Type help for features. \n " ) ;
2025-01-05 22:59:51 +01:00
# else
2025-02-13 19:09:29 +01:00
fprintf ( stderr , " %s " , " \r ✅ Free version (GPT-3.5 Turbo), for you by retoor. \n " ) ;
2025-01-05 22:59:51 +01:00
# endif
2025-01-04 06:00:03 +01:00
}
2025-01-04 08:35:39 +01:00
int main ( int argc , char * argv [ ] ) {
2025-01-04 06:00:03 +01:00
init ( ) ;
2025-01-04 08:40:31 +01:00
if ( try_prompt ( argc , argv ) )
2025-01-04 06:00:03 +01:00
return 0 ;
2025-01-04 08:40:31 +01:00
2025-01-04 06:00:03 +01:00
repl ( ) ;
return 0 ;
2025-01-25 14:19:01 +01:00
}