comparison mrjunejune/main.c @ 260:1f9877b637e9

Add Copilot-powered cyberpunk JRPG chat Integrate the production JRPG chat with Seobeo streaming, Deita persistence, and a Bazel-managed Copilot SDK and LiteLLM inference stack. Co-authored-by: Copilot <[email protected]>
author MrJuneJune <mrjunejune@users.noreply.github.com>
date Wed, 05 Aug 2026 09:19:41 -0700
parents 667156fcd3e3
children ee04e4e69fed
comparison
equal deleted inserted replaced
259:667156fcd3e3 260:1f9877b637e9
1 #include "seobeo/seobeo.h" 1 #include "seobeo/seobeo.h"
2 #include "markdown_converter/markdown_to_html.h" 2 #include "markdown_converter/markdown_to_html.h"
3 #include "s3/s3_uploader.h" 3 #include "s3/s3_uploader.h"
4 #include "deita/deita.h" 4 #include "deita/deita.h"
5 #include "mrjunejune/latex_renderer.h" 5 #include "mrjunejune/latex_renderer.h"
6 #include "mrjunejune/conversation_api.h"
6 #include <time.h> 7 #include <time.h>
7 #include <sys/stat.h> 8 #include <sys/stat.h>
8 #include <stdarg.h> 9 #include <stdarg.h>
9 #include <stdatomic.h> 10 #include <stdatomic.h>
10 #include <pthread.h> 11 #include <pthread.h>
189 } 190 }
190 } 191 }
191 192
192 void handle_sigint(int sig) 193 void handle_sigint(int sig)
193 { 194 {
194 printf("Failed\n"); 195 (void)sig;
195 stop_server = 1; 196 stop_server = 1;
197 Seobeo_Web_Server_Stop();
196 } 198 }
197 199
198 void Seobeo_Render_Html( 200 void Seobeo_Render_Html(
199 char *final_body, 201 char *final_body,
200 char *template, 202 char *template,
829 Seobeo_Render_Html_FilePath(final_body, "/talk/index.html", arena); 831 Seobeo_Render_Html_FilePath(final_body, "/talk/index.html", arena);
830 Dowa_HashMap_Push_Arena(resp, "body", final_body, arena); 832 Dowa_HashMap_Push_Arena(resp, "body", final_body, arena);
831 return resp; 833 return resp;
832 } 834 }
833 835
834 #if defined(MRJUNEJUNE_ENABLE_DEV_PAGES)
835 Seobeo_Request_Entry *GetJrpg(Seobeo_Request_Entry *req, Dowa_Arena *arena) 836 Seobeo_Request_Entry *GetJrpg(Seobeo_Request_Entry *req, Dowa_Arena *arena)
836 { 837 {
837 Seobeo_Request_Entry *resp = NULL; 838 Seobeo_Request_Entry *resp = NULL;
838 char *final_body = Dowa_Arena_Allocate(arena, 50 * 1024); 839 char *final_body = Dowa_Arena_Allocate(arena, 50 * 1024);
839 Seobeo_Render_Html_FilePath(final_body, "/jrpg/index.html", arena); 840 Seobeo_Render_Html_FilePath(final_body, "/jrpg/index.html", arena);
840 Dowa_HashMap_Push_Arena(resp, "body", final_body, arena); 841 Dowa_HashMap_Push_Arena(resp, "body", final_body, arena);
841 return resp; 842 return resp;
842 } 843 }
843 #endif
844 844
845 Seobeo_Request_Entry *GetNotesLogin(Seobeo_Request_Entry *req, Dowa_Arena *arena) 845 Seobeo_Request_Entry *GetNotesLogin(Seobeo_Request_Entry *req, Dowa_Arena *arena)
846 { 846 {
847 Seobeo_Request_Entry *resp = NULL; 847 Seobeo_Request_Entry *resp = NULL;
848 char *final_body = Dowa_Arena_Allocate(arena, 50 * 1024); 848 char *final_body = Dowa_Arena_Allocate(arena, 50 * 1024);
876 CREATE_REDIRECT_HANDLER(MarkDownToHtml, "/tools/markdown_to_html") 876 CREATE_REDIRECT_HANDLER(MarkDownToHtml, "/tools/markdown_to_html")
877 CREATE_REDIRECT_HANDLER(FileConverter, "/tools/file_converter") 877 CREATE_REDIRECT_HANDLER(FileConverter, "/tools/file_converter")
878 CREATE_REDIRECT_HANDLER(HlsPlayer, "/tools/hls_player") 878 CREATE_REDIRECT_HANDLER(HlsPlayer, "/tools/hls_player")
879 CREATE_REDIRECT_HANDLER(LatexEditor, "/tools/latex_editor") 879 CREATE_REDIRECT_HANDLER(LatexEditor, "/tools/latex_editor")
880 CREATE_REDIRECT_HANDLER(Talk, "/talk") 880 CREATE_REDIRECT_HANDLER(Talk, "/talk")
881 #if defined(MRJUNEJUNE_ENABLE_DEV_PAGES)
882 CREATE_REDIRECT_HANDLER(Jrpg, "/jrpg") 881 CREATE_REDIRECT_HANDLER(Jrpg, "/jrpg")
883 #endif
884 CREATE_REDIRECT_HANDLER(Editor, "/editor") 882 CREATE_REDIRECT_HANDLER(Editor, "/editor")
885 883
886 // S3 Upload URL API 884 // S3 Upload URL API
887 // POST /api/s3/upload-url 885 // POST /api/s3/upload-url
888 // Headers: Authorization: Bearer <token>, Content-Type: application/json 886 // Headers: Authorization: Bearer <token>, Content-Type: application/json
1957 return resp; 1955 return resp;
1958 } 1956 }
1959 1957
1960 int main(void) 1958 int main(void)
1961 { 1959 {
1960 signal(SIGINT, handle_sigint);
1961 signal(SIGTERM, handle_sigint);
1962
1962 // Load server config 1963 // Load server config
1963 load_config("mrjunejune/.config"); 1964 load_config("mrjunejune/.config");
1965 const char *database_override = getenv("MRJUNEJUNE_DB_PATH");
1966 if (database_override && database_override[0] != '\0')
1967 {
1968 snprintf(g_db_path, sizeof(g_db_path), "%s", database_override);
1969 }
1964 1970
1965 // Load S3 credentials from .env 1971 // Load S3 credentials from .env
1966 FILE *env_file = fopen(".env", "r"); 1972 FILE *env_file = fopen(".env", "r");
1967 static char s3_access_key[128] = {0}; 1973 static char s3_access_key[128] = {0};
1968 static char s3_secret_key[128] = {0}; 1974 static char s3_secret_key[128] = {0};
2009 printf("[STARTUP] Database path (relative): %s\n", g_db_path); 2015 printf("[STARTUP] Database path (relative): %s\n", g_db_path);
2010 } 2016 }
2011 2017
2012 // Initialize database 2018 // Initialize database
2013 init_database(); 2019 init_database();
2020 if (!Conversation_API_Init(g_db_path))
2021 Seobeo_Log(SEOBEO_ERROR, "[CONVERSATION] Store unavailable\n");
2022 const char *sidecar_path = getenv("MRJUNEJUNE_INFERENCE_SIDECAR_PATH");
2023 const char *copilot_cli_path = getenv("MRJUNEJUNE_COPILOT_CLI_PATH");
2024 if (sidecar_path && copilot_cli_path)
2025 {
2026 if (!Conversation_API_Enable_Inference(sidecar_path, copilot_cli_path))
2027 Seobeo_Log(SEOBEO_ERROR, "[INFERENCE] Sidecar unavailable\n");
2028 }
2029 else
2030 {
2031 Seobeo_Log(
2032 SEOBEO_WARNING,
2033 "[INFERENCE] Runtime paths not configured; turns return 503\n");
2034 }
2014 2035
2015 g_media_worker_pool = Seobeo_Worker_Pool_Create(2, 16); 2036 g_media_worker_pool = Seobeo_Worker_Pool_Create(2, 16);
2016 if (!g_media_worker_pool) 2037 if (!g_media_worker_pool)
2017 { 2038 {
2018 Seobeo_Log( 2039 Seobeo_Log(
2019 SEOBEO_ERROR, 2040 SEOBEO_ERROR,
2020 "[MEDIA] Unable to initialize the media worker pool\n"); 2041 "[MEDIA] Unable to initialize the media worker pool\n");
2021 } 2042 }
2022 2043
2023 Seobeo_Router_Init(); 2044 Seobeo_Router_Init();
2045 Conversation_API_Register_Routes();
2024 2046
2025 Seobeo_Router_Register("GET", "/", GetHomePage); 2047 Seobeo_Router_Register("GET", "/", GetHomePage);
2026 Seobeo_Router_Register("GET", "/index.html", GetRedirectHomePage); 2048 Seobeo_Router_Register("GET", "/index.html", GetRedirectHomePage);
2027 2049
2028 Seobeo_Router_Register("GET", "/resume", GetResume); 2050 Seobeo_Router_Register("GET", "/resume", GetResume);
2065 2087
2066 // -- Talk --/ 2088 // -- Talk --/
2067 Seobeo_Router_Register("GET", "/talk", GetTalk); 2089 Seobeo_Router_Register("GET", "/talk", GetTalk);
2068 Seobeo_Router_Register("GET", "/talk/index.html", GetRedirectTalk); 2090 Seobeo_Router_Register("GET", "/talk/index.html", GetRedirectTalk);
2069 2091
2070 #if defined(MRJUNEJUNE_ENABLE_DEV_PAGES) 2092 // -- JRPG agent chat --/
2071 // -- Development pages --/
2072 Seobeo_Router_Register("GET", "/jrpg", GetJrpg); 2093 Seobeo_Router_Register("GET", "/jrpg", GetJrpg);
2073 Seobeo_Router_Register("GET", "/jrpg/index.html", GetRedirectJrpg); 2094 Seobeo_Router_Register("GET", "/jrpg/index.html", GetRedirectJrpg);
2074 #endif
2075 2095
2076 // -- Notes --/ 2096 // -- Notes --/
2077 Seobeo_Router_Register("GET", "/notes", GetNotes); 2097 Seobeo_Router_Register("GET", "/notes", GetNotes);
2078 Seobeo_Router_Register("GET", "/notes/", GetNotes); 2098 Seobeo_Router_Register("GET", "/notes/", GetNotes);
2079 Seobeo_Router_Register("GET", "/notes/index.html", GetNotes); 2099 Seobeo_Router_Register("GET", "/notes/index.html", GetNotes);
2089 if (!server_port || server_port[0] == '\0') 2109 if (!server_port || server_port[0] == '\0')
2090 server_port = "6969"; 2110 server_port = "6969";
2091 Seobeo_Web_Server_Start("mrjunejune/src", server_port, SEOBEO_MODE_EDGE, 4); 2111 Seobeo_Web_Server_Start("mrjunejune/src", server_port, SEOBEO_MODE_EDGE, 4);
2092 Seobeo_Worker_Pool_Destroy(g_media_worker_pool); 2112 Seobeo_Worker_Pool_Destroy(g_media_worker_pool);
2093 g_media_worker_pool = NULL; 2113 g_media_worker_pool = NULL;
2094 } 2114 Conversation_API_Destroy();
2115 }