Mercurial
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 } |