2025-01-04 07:40:31 +00: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 05:00:03 +00:00
# include "openai.h"
# include "markdown.h"
# include "plugin.h"
# include "line.h"
# include <locale.h>
# include <stdio.h>
2025-01-04 07:40:31 +00:00
# include <stdlib.h>
# include <string.h>
# include <unistd.h>
2025-01-04 05:00:03 +00:00
2025-01-04 07:40:31 +00:00
char * get_prompt_from_args ( int c , char * * argv ) {
char * prompt = malloc ( 1024 * 1024 + 1 ) ;
2025-01-04 05:00:03 +00:00
prompt [ 0 ] = 0 ;
2025-01-04 07:40:31 +00:00
for ( int i = 1 ; i < c ; i + + ) {
if ( argv [ i ] [ 0 ] = = ' - ' )
2025-01-04 05:00:03 +00:00
break ;
2025-01-04 07:40:31 +00:00
strncat ( prompt , argv [ i ] , 1024 * 1024 ) ;
if ( i < c - 1 ) {
strncat ( prompt , " " , 1024 * 1024 ) ;
2025-01-04 07:35:39 +00:00
} else {
2025-01-04 07:40:31 +00:00
strncat ( prompt , " . " , 1024 * 1024 ) ;
2025-01-04 05:00:03 +00:00
}
}
2025-01-04 07:40:31 +00:00
if ( ! * prompt ) {
2025-01-04 05:00:03 +00:00
free ( prompt ) ;
return NULL ;
}
return prompt ;
}
2025-01-04 07:40:31 +00: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-04 05:00:03 +00:00
parse_markdown_to_ansi ( response ) ;
printf ( " \n " ) ;
free ( response ) ;
free ( prompt ) ;
return true ;
}
return false ;
}
void help ( ) ;
void render ( char * ) ;
2025-01-04 07:35:39 +00:00
void serve ( ) {
2025-01-04 07:40:31 +00:00
render ( " Starting server. *Put executables in a dir named cgi-bin and they will behave as web pages.* " ) ;
2025-01-04 05:00:03 +00:00
int res = system ( " python3 -m http.server --cgi " ) ;
( void ) res ;
}
2025-01-04 07:40:31 +00:00
void render ( char * content ) {
2025-01-04 05:00:03 +00:00
parse_markdown_to_ansi ( content ) ;
printf ( " \n \n " ) ;
}
2025-01-04 07:35:39 +00:00
void repl ( ) {
2025-01-04 05:00:03 +00:00
line_init ( ) ;
char * line ;
char * previous_line = NULL ;
2025-01-04 07:40:31 +00:00
while ( ( line = line_read ( " > " ) ) ) {
if ( ! line | | ! * line ) {
2025-01-04 05:00:03 +00:00
line = previous_line ;
}
2025-01-04 07:40:31 +00:00
if ( ! line | | ! * line )
2025-01-04 05:00:03 +00:00
continue ;
previous_line = line ;
2025-01-04 07:40:31 +00:00
if ( line [ 0 ] = = ' ! ' ) {
2025-01-04 05:00:03 +00:00
plugin_run ( line + 1 ) ;
continue ;
}
2025-01-04 07:40:31 +00:00
if ( ! strncmp ( line , " exit " , 4 ) ) {
2025-01-04 05:00:03 +00:00
exit ( 0 ) ;
}
2025-01-04 07:40:31 +00:00
if ( ! strncmp ( line , " help " , 4 ) ) {
2025-01-04 05:00:03 +00:00
help ( ) ;
continue ;
}
2025-01-04 07:40:31 +00:00
if ( ! strncmp ( line , " serve " , 5 ) ) {
2025-01-04 05:00:03 +00:00
serve ( ) ;
}
2025-01-04 07:40:31 +00:00
if ( ! strncmp ( line , " spar " , 5 ) ) {
char * response = line + 5 ;
while ( true ) {
2025-01-04 05:00:03 +00:00
render ( response ) ;
sleep ( 2 ) ;
2025-01-04 07:40:31 +00:00
response = openai_chat ( " user " , response ) ;
2025-01-04 07:35:39 +00:00
}
2025-01-04 05:00:03 +00:00
}
2025-01-04 07:40:31 +00:00
if ( ! strncmp ( line , " ls " , 2 ) | | ! strncmp ( line , " list " , 4 ) ) {
2025-01-04 05:00:03 +00:00
int offset = 2 ;
2025-01-04 07:40:31 +00:00
if ( ! strncmp ( line , " list " , 4 ) ) {
2025-01-04 05:00:03 +00:00
offset = 4 ;
}
2025-01-04 07:40:31 +00:00
char * command = ( char * ) malloc ( strlen ( line ) + 42 ) ;
2025-01-04 05:00:03 +00:00
command [ 0 ] = 0 ;
strcpy ( command , " ls " ) ;
strcat ( command , line + offset ) ;
int res = system ( command ) ;
( void ) res ;
free ( command ) ;
continue ;
}
line_add_history ( line ) ;
2025-01-04 07:40:31 +00:00
char * response = openai_chat ( " user " , line ) ;
2025-01-04 05:00:03 +00:00
render ( response ) ;
free ( response ) ;
}
}
2025-01-04 07:35:39 +00:00
void help ( ) {
2025-01-04 07:40:31 +00: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 07:35:39 +00:00
render ( help_text ) ;
2025-01-04 05:00:03 +00:00
}
2025-01-04 15:54:48 +00:00
bool openai_include ( char * path ) {
2025-01-04 07:40:31 +00:00
FILE * file = fopen ( path , " r " ) ;
if ( file = = NULL ) {
2025-01-04 15:54:48 +00:00
return false ;
2025-01-04 05:00:03 +00:00
}
fseek ( file , 0 , SEEK_END ) ;
long size = ftell ( file ) ;
fseek ( file , 0 , SEEK_SET ) ;
2025-01-04 07:40:31 +00:00
char * buffer = ( char * ) malloc ( size ) ;
size_t read = fread ( buffer , 1 , size , file ) ;
if ( read = = 0 ) {
2025-01-04 15:54:48 +00:00
return false ;
2025-01-04 05:00:03 +00:00
}
fclose ( file ) ;
buffer [ read ] = 0 ;
openai_system ( buffer ) ;
2025-01-04 07:40:31 +00:00
2025-01-04 05:00:03 +00:00
free ( buffer ) ;
2025-01-04 15:54:48 +00:00
return true ;
2025-01-04 05:00:03 +00:00
}
2025-01-04 07:35:39 +00:00
void init ( ) {
2025-01-04 15:54:48 +00:00
setbuf ( stdout , NULL ) ;
2025-01-04 07:35:39 +00:00
line_init ( ) ;
const char * locale = setlocale ( LC_ALL , NULL ) ;
char payload [ 4096 ] = { 0 } ;
2025-01-04 15:54:48 +00:00
sprintf ( payload , " Your locale is %s. User lang is %s. " , locale , locale ) ;
printf ( " %s " , " Loading... ⏳ " ) ;
2025-01-04 07:35:39 +00:00
openai_system ( payload ) ;
2025-01-04 15:54:48 +00:00
if ( ! openai_include ( " .rcontext.txt " ) ) {
openai_include ( " ~/.rcontext.txt " ) ;
}
2025-01-05 21:59:51 +00:00
# ifndef FREE_VERSION
printf ( " %s " , " \r ✅ Commercial version. Type help for features. \n " ) ;
# else
printf ( " %s " , " \r ✅ Free version (GPT-3.5 Turbo), for you by retoor. \n " ) ;
# endif
2025-01-04 05:00:03 +00:00
}
2025-01-04 07:35:39 +00:00
int main ( int argc , char * argv [ ] ) {
2025-01-04 05:00:03 +00:00
init ( ) ;
2025-01-04 07:40:31 +00:00
if ( try_prompt ( argc , argv ) )
2025-01-04 05:00:03 +00:00
return 0 ;
2025-01-04 07:40:31 +00:00
2025-01-04 05:00:03 +00:00
repl ( ) ;
return 0 ;
2025-01-04 07:35:39 +00:00
}