11#include " chat_cmd.h"
22#include " httplib.h"
33
4- #include " cortex_upd_cmd.h"
54#include " database/models.h"
65#include " model_status_cmd.h"
76#include " server_start_cmd.h"
87#include " trantor/utils/Logger.h"
98#include " utils/logging_utils.h"
9+ #include " run_cmd.h"
1010
1111namespace commands {
12- namespace {
13- constexpr const char * kExitChat = " exit()" ;
14- constexpr const auto kMinDataChunkSize = 6u ;
15- constexpr const char * kUser = " user" ;
16- constexpr const char * kAssistant = " assistant" ;
17-
18- } // namespace
19-
20- struct ChunkParser {
21- std::string content;
22- bool is_done = false ;
23-
24- ChunkParser (const char * data, size_t data_length) {
25- if (data && data_length > kMinDataChunkSize ) {
26- std::string s (data + kMinDataChunkSize , data_length - kMinDataChunkSize );
27- if (s.find (" [DONE]" ) != std::string::npos) {
28- is_done = true ;
29- } else {
30- try {
31- content = nlohmann::json::parse (s)[" choices" ][0 ][" delta" ][" content" ];
32- } catch (const nlohmann::json::parse_error& e) {
33- CTL_WRN (" JSON parse error: " << e.what ());
34- }
35- }
36- }
37- }
38- };
39-
4012void ChatCmd::Exec (const std::string& host, int port,
41- const std::string& model_handle, std::string msg) {
42- cortex::db::Models modellist_handler;
43- config::YamlHandler yaml_handler;
44- try {
45- auto model_entry = modellist_handler.GetModelInfo (model_handle);
46- if (model_entry.has_error ()) {
47- CLI_LOG (" Error: " + model_entry.error ());
48- return ;
49- }
50- yaml_handler.ModelConfigFromFile (model_entry.value ().path_to_model_yaml );
51- auto mc = yaml_handler.GetModelConfig ();
52- Exec (host, port, mc, std::move (msg));
53- } catch (const std::exception& e) {
54- CLI_LOG (" Fail to start model information with ID '" + model_handle +
55- " ': " + e.what ());
56- }
13+ const std::string& model_handle) {
14+ RunCmd rc (host, port, model_handle);
15+ rc.Exec (true /* chat_flag*/ );
5716}
58-
59- void ChatCmd::Exec (const std::string& host, int port,
60- const config::ModelConfig& mc, std::string msg) {
61- auto address = host + " :" + std::to_string (port);
62- // Check if server is started
63- {
64- if (!commands::IsServerAlive (host, port)) {
65- CLI_LOG (" Server is not started yet, please run `"
66- << commands::GetCortexBinary () << " start` to start server!" );
67- return ;
68- }
69- }
70-
71- // Only check if llamacpp engine
72- if ((mc.engine .find (" llamacpp" ) != std::string::npos) &&
73- !commands::ModelStatusCmd ().IsLoaded (host, port, mc)) {
74- CLI_LOG (" Model is not loaded yet!" );
75- return ;
76- }
77-
78- // Interactive mode or not
79- bool interactive = msg.empty ();
80-
81- // Some instruction for user here
82- if (interactive) {
83- std::cout << " Inorder to exit, type `exit()`" << std::endl;
84- }
85- // Model is loaded, start to chat
86- {
87- do {
88- std::string user_input = std::move (msg);
89- if (user_input.empty ()) {
90- std::cout << " > " ;
91- std::getline (std::cin, user_input);
92- }
93- if (user_input == kExitChat ) {
94- break ;
95- }
96-
97- if (!user_input.empty ()) {
98- httplib::Client cli (address);
99- nlohmann::json json_data;
100- nlohmann::json new_data;
101- new_data[" role" ] = kUser ;
102- new_data[" content" ] = user_input;
103- histories_.push_back (std::move (new_data));
104- json_data[" engine" ] = mc.engine ;
105- json_data[" messages" ] = histories_;
106- json_data[" model" ] = mc.name ;
107- // TODO: support non-stream
108- json_data[" stream" ] = true ;
109- json_data[" stop" ] = mc.stop ;
110- auto data_str = json_data.dump ();
111- // std::cout << data_str << std::endl;
112- cli.set_read_timeout (std::chrono::seconds (60 ));
113- // std::cout << "> ";
114- httplib::Request req;
115- req.headers = httplib::Headers ();
116- req.set_header (" Content-Type" , " application/json" );
117- req.method = " POST" ;
118- req.path = " /v1/chat/completions" ;
119- req.body = data_str;
120- std::string ai_chat;
121- req.content_receiver = [&](const char * data, size_t data_length,
122- uint64_t offset, uint64_t total_length) {
123- ChunkParser cp (data, data_length);
124- if (cp.is_done ) {
125- std::cout << std::endl;
126- return false ;
127- }
128- std::cout << cp.content << std::flush;
129- ai_chat += cp.content ;
130- return true ;
131- };
132- cli.send (req);
133-
134- nlohmann::json ai_res;
135- ai_res[" role" ] = kAssistant ;
136- ai_res[" content" ] = ai_chat;
137- histories_.push_back (std::move (ai_res));
138- }
139- // std::cout << "ok Done" << std::endl;
140- } while (interactive);
141- }
142- }
143-
14417}; // namespace commands
0 commit comments