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-03-16 22:46:09 +01:00
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
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-03-16 22:46:09 +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 ;
2025-03-16 22:46:09 +01:00
} else if ( ! strcmp ( argv [ i ], "--py" )){
if ( i + 1 <= c ){
char * py_file_path = expand_home_directory ( argv [ i + 1 ]);
fprintf ( stderr , "Including \" %s \" . \n " , py_file_path );
openai_include ( py_file_path );
free ( py_file_path );
//char * file_content = read_file(py_file_path);
//plugin_run(file_content);
i ++ ;
}
}
else if ( ! strcmp ( argv [ i ], "--context" )){
2025-02-13 19:09:29 +01:00
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 ;
}
2025-03-16 22:46:09 +01:00
void render ( char * content )
{
2025-02-13 19:09:29 +01:00
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-03-16 22:46:09 +01:00
//char *previous_line = NULL;
2025-03-06 00:10:15 +01:00
while ( true ) {
line = line_read ( "> " );
2025-01-04 08:40:31 +01:00
if ( ! line || !* line ) {
2025-03-16 22:46:09 +01:00
continue ;
//line = previous_line;
2025-01-04 06:00:03 +01:00
}
2025-01-04 08:40:31 +01:00
if ( ! line || !* line )
2025-01-04 06:00:03 +01:00
continue ;
2025-03-16 22:46:09 +01:00
// 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-03-16 22:46:09 +01:00
while ( line && * line != '\n' ){
2025-01-26 02:54:45 +01:00
line_add_history ( line );
char * response = openai_chat ( "user" , line );
2025-03-05 23:53:35 +01:00
if ( response ){
render ( response );
printf ( " \n " );
2025-03-16 22:46:09 +01:00
if ( strstr ( response , "_STEP_" )){
line = "continue" ;
} else {
line = NULL ;
}
2025-03-05 23:53:35 +01:00
free ( response );
2025-03-16 22:46:09 +01:00
2025-03-05 23:53:35 +01:00
}
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-03-16 22:46:09 +01:00
2025-01-04 16:54:48 +01:00
bool openai_include ( char * path ) {
2025-03-16 22:46:09 +01:00
char * file_content = read_file ( path );
if ( ! file_content ){
2025-01-04 16:54:48 +01:00
return false ;
2025-01-04 06:00:03 +01:00
}
2025-03-16 22:46:09 +01:00
openai_system ( file_content );
free ( file_content );
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
}