first commit

This commit is contained in:
陈赣
2026-06-03 12:43:14 +08:00
commit ba76cfae28
608 changed files with 120791 additions and 0 deletions

30
third_party/cpp_llmlib/CMakeLists.txt vendored Normal file
View File

@@ -0,0 +1,30 @@
cmake_minimum_required(VERSION 3.10)
project(llmlib_test VERSION 1.0)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_BUILD_TYPE Debug)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -fPIC -w -fdiagnostics-color=always -pthread")
# OpenCV required
find_package(OpenCV REQUIRED)
message(STATUS "OpenCV library status:")
message(STATUS " version: ${OpenCV_VERSION}")
message(STATUS " libraries: ${OpenCV_LIBS}")
message(STATUS " include path: ${OpenCV_INCLUDE_DIRS}")
include_directories(${OpenCV_INCLUDE_DIRS})
find_package(OpenSSL REQUIRED)
message(STATUS "OpenSSL library status:")
message(STATUS " version: ${OPENSSL_VERSION}")
message(STATUS " libraries: ${OPENSSL_LIBRARIES}")
message(STATUS " include path: ${OPENSSL_INCLUDE_DIR}")
include_directories(${OPENSSL_INCLUDE_DIR})
add_executable(llmlib_ollama_test "llmlib_ollama_test.cpp")
target_link_libraries(llmlib_ollama_test ${OpenCV_LIBS} ${OPENSSL_LIBRARIES})
add_executable(llmlib_openai_test "llmlib_openai_test.cpp")
target_link_libraries(llmlib_openai_test ${OpenCV_LIBS} ${OPENSSL_LIBRARIES})
add_executable(llmlib_multi_chat_test "llmlib_multi_chat_test.cpp")
target_link_libraries(llmlib_multi_chat_test ${OpenCV_LIBS} ${OPENSSL_LIBRARIES})

13
third_party/cpp_llmlib/README.md vendored Normal file
View File

@@ -0,0 +1,13 @@
a lightweight LLM Client SDK using modern C++ Language, supports calling OpenAI-compatible online services — such as Alibaba Cloud, OpenAI, and other API providers — as well as locally hosted inference backends like Ollama, vLLM, and Hugging Face TGI.
> NOTE: OpenSSL >= 3.0 required for llmlib.hpp.
```
mkdir build
cd build
cmake ..
make -j8
./llmlib_ollama_test # test chat REST API for Ollama
./llmlib_openai_test # test chat REST API for OpenAI-compatible protocol(aliyun LLM API provider/vLLM/...)
```

294
third_party/cpp_llmlib/llmlib.hpp vendored Normal file
View File

@@ -0,0 +1,294 @@
#define CPPHTTPLIB_OPENSSL_SUPPORT
#include <string>
#include <map>
#include <iostream>
#include <opencv2/opencv.hpp>
#include "../cpp_httplib/httplib.h"
#include "../cpp_base64/base64.h"
#include "../nlohmann/json.hpp"
using json = nlohmann::json;
namespace llmlib {
/**
* LLM backends:
* 1. OpenAI: OpenAI-compatible LLM service API providers
* 2. Ollama: LLM services hosted locally by Ollama framework
*
*/
enum class LLMBackendType {
OpenAI,
Ollama
};
/**
* LLM Client:
*
* support chat with LLM with text & image as input.
*/
class LLMClient {
public:
LLMClient() {}
LLMClient(const std::string& api_base_url,
const std::string& api_key,
LLMBackendType backend_type = LLMBackendType::OpenAI):
__api_base_url(api_base_url),
__api_key(api_key),
__backend_type(backend_type)
{}
/**
* set default headers for all requests.
*/
void set_default_header(const std::string& key, const std::string& value) {
__default_headers[key] = value;
}
/**
* set connection timeout(seconds) for all requests.
*/
void set_connection_timeout(int connection_timeout) {
__connection_timeout = connection_timeout;
}
/**
* simple chat interface.
* support single text prompt and multi images as input, history messages not Supported.
*
* @param model_name LLM to be used.
* @param prompt input text prompt.
* @param images input images.
* @param options LLM parameters: temperature, top_k, etc.
*/
std::string simple_chat(const std::string& model_name,
const std::string& prompt,
const std::vector<cv::Mat>& images,
const json& options) {
// construct json payload
json payload;
payload["model"] = model_name;
payload["stream"] = false;
if (__backend_type == LLMBackendType::OpenAI) {
json message;
message["role"] = "user";
json content = json::array();
content.push_back({{"type", "text"}, {"text", prompt}});
if (images.size() != 0) {
for(auto& image: images) {
auto base64_img = mat_to_base64(image);
content.push_back({{"type", "image_url"}, {"image_url", {{"url", "data:image/jpg;base64," + base64_img}}}});
}
}
message["content"] = content;
payload["messages"] = {message};
if (!options.is_null()) {
payload.update(options);
}
} else if (__backend_type == LLMBackendType::Ollama) {
json message;
message["role"] = "user";
message["content"] = prompt;
if (images.size() != 0) {
json imgs = json::array();
for(auto& image: images) {
auto base64_img = mat_to_base64(image);
imgs.push_back(base64_img);
}
message["images"] = imgs;
}
payload["messages"] = {message};
payload["options"] = options;
}
// send request
auto res = request(payload.dump(4));
auto res_json = json::parse(res);
// std::cout << payload.dump(4) << std::endl;
// std::cout << res << std::endl;
// try to get result extracted from response
try
{
if (__backend_type == LLMBackendType::OpenAI) {
return res_json["choices"][0]["message"]["content"];
} else if (__backend_type == LLMBackendType::Ollama) {
return res_json["message"]["content"];
} else {
return "";
}
}
catch(const std::exception& e)
{
std::cerr << e.what() << '\n';
}
return "";
}
/**
* chat interface.
* support messages(json array) as input, history messages Supported.
*
* @param model_name LLM to be used.
* @param messages a json array containing history messages.
* @param options LLM parameters: temperature, top_k, etc.
*
* NOTE:
* messages MUST be constructed according to appropriate protocols by caller outside of chat.
*/
std::string chat(const std::string& model_name,
const json& messages,
const json& options) {
// construct json payload
json payload;
payload["model"] = model_name;
payload["messages"] = messages;
payload["stream"] = false;
if (__backend_type == LLMBackendType::OpenAI) {
if (!options.is_null()) {
payload.update(options);
}
} else if (__backend_type == LLMBackendType::Ollama) {
payload["options"] = options;
}
// send request
auto res = request(payload.dump(4));
auto res_json = json::parse(res);
//std::cout << payload.dump(4) << std::endl;
//std::cout << res << std::endl;
// try to get result extracted from response
try
{
if (__backend_type == LLMBackendType::OpenAI) {
return res_json["choices"][0]["message"]["content"];
} else if (__backend_type == LLMBackendType::Ollama) {
return res_json["message"]["content"];
} else {
return "";
}
}
catch(const std::exception& e)
{
std::cerr << e.what() << '\n';
}
return "";
}
/**
* convert base64 string to cv::Mat
*/
cv::Mat base64_to_mat(const std::string& base64_data) {
std::string decoded_data = base64_decode(base64_data);
std::vector<uchar> data(decoded_data.begin(), decoded_data.end());
cv::Mat img = cv::imdecode(data, cv::IMREAD_UNCHANGED);
return img;
}
/**
* convert cv::Mat to base64 string
*/
std::string mat_to_base64(const cv::Mat& img, const std::string& ext = ".jpg") {
std::vector<uchar> buf;
cv::imencode(ext, img, buf);
std::string encoded = base64_encode(buf.data(), buf.size());
return encoded;
}
private:
std::string __api_base_url;
std::string __api_key;
LLMBackendType __backend_type = LLMBackendType::OpenAI;
std::map<std::string, std::string> __default_headers;
int __connection_timeout = 1;
/**/
std::string __openai_chat_completions_path = "/chat/completions";
std::string __ollama_chat_completions_path = "/api/chat";
std::string request(const std::string& payload) {
auto parsed_base_url = split_base_url(__api_base_url);
httplib::Client cli(parsed_base_url.base_host.c_str());
cli.set_connection_timeout(__connection_timeout, 0);
httplib::Headers headers;
auto chat_path = __backend_type == LLMBackendType::OpenAI ? __openai_chat_completions_path : __ollama_chat_completions_path;
if (__backend_type == LLMBackendType::OpenAI) {
headers = {
{"Content-Type", "application/json"},
{"Authorization", "Bearer " + __api_key}
};
} else if (__backend_type == LLMBackendType::Ollama) {
headers = {
{"Content-Type", "application/json"}
};
} else {
}
for (const auto& kv : __default_headers) {
headers.emplace(kv.first, kv.second);
}
auto final_path = parsed_base_url.base_path + chat_path;
auto res = cli.Post(final_path, headers, payload, "application/json");
if (res) {
if (res->status == httplib::StatusCode::OK_200) {
return res->body;
}
else {
std::cout << "[llmlib] HTTP status code: " << res->status << std::endl;
return "{}";
}
} else {
auto err = res.error();
std::cout << "[llmlib] HTTP error: " << httplib::to_string(err) << std::endl;
return "{}";
}
}
struct ParsedBaseUrl {
std::string base_host; // protocols + host + portif exists
std::string base_path; // start with '/', not end with '/'
};
ParsedBaseUrl split_base_url(const std::string& url) {
ParsedBaseUrl result;
std::regex re(R"(^(https?)://([^:/\s]+)(?::(\d+))?(/.*|$))", std::regex::icase);
std::smatch match;
if (!std::regex_search(url, match, re)) {
throw std::invalid_argument("Invalid URL format: " + url);
}
std::string protocol = match[1].str();
std::string host = match[2].str();
std::string port_str = match[3].str();
std::string path = match[4].str();
int port = (protocol == "https") ? 443 : 80;
if (!port_str.empty()) {
port = std::stoi(port_str);
}
if (port_str.empty()) {
result.base_host = protocol + "://" + host;
} else {
result.base_host = protocol + "://" + host + ":" + port_str;
}
result.base_path = path.empty() ? "/" : path;
if (result.base_path.length() > 1 && result.base_path.back() == '/') {
result.base_path.pop_back();
}
if (result.base_path == "/") {
result.base_path.clear();
}
return result;
}
};
}

View File

@@ -0,0 +1,35 @@
#include <iostream>
#include "llmlib.hpp"
using namespace llmlib;
int main() {
// create LLMClient
LLMClient llmcli("http://192.168.77.219:11434", "", LLMBackendType::Ollama);
// define parameters
auto model_name = "qwen2.5:7b";
json options = {{"temperature", 0.1}, {"top_k", 1}};
json messages = {{{"role", "system"}, {"content", "你是一个非常专业的聊天助手,你的名字叫小王。"}}};
// chat loop runing on console
std::string input = "";
std::cout << "##let's chat with LLM hosted by Ollama##" << std::endl;
std::cout << "YOU: ";
do
{
std::cin >> input;
if (input != "quit") {
// append user's input to history messages
messages.push_back({{"role", "user"}, {"content", input}});
// call chat()
auto output = llmcli.chat(model_name, messages, options);
std::cout << "-----------------------------------------" << std::endl << "LLM: " << output << std::endl;
std::cout << "-----------------------------------------" << std::endl << "YOU: ";
// append assistant's output to history messages
messages.push_back({{"role", "assistant"}, {"content", output}});
}
} while (input != "quit");
std::cout << "##finish chat with LLM hosted by Ollama##" << std::endl;
}

View File

@@ -0,0 +1,68 @@
#include <iostream>
#include "llmlib.hpp"
using namespace llmlib;
/**
* 1. install Ollama locally
* 2. start Ollama service and get api base url(no api key required for Ollama)
*
*/
int main() {
LLMClient llmcli("http://192.168.77.219:11434", "", LLMBackendType::Ollama);
/**
* 1. test for simple chat
*/
auto res1 = llmcli.simple_chat("qwen2.5:7b", "坐飞机为什么要付机票钱?", {}, {{"temperature", 0.1}, {"top_k", 1}});
std::cout << "------test for simple chat-----" << std::endl;
std::cout << res1 << std::endl;
std::cout << "-------------------------------" << std::endl;
/**
* 2. test for simple chat with images
*/
auto image1 = cv::imread("/windows2/zhzhi/github/vp_data/test_images/vehicle/0.jpg");
auto image2 = cv::imread("/windows2/zhzhi/github/vp_data/test_images/vehicle/27.jpg");
auto res2 = llmcli.simple_chat("minicpm-v:8b", "描述这两幅图片的差异", {image1, image2}, {});
std::cout << "-----test for simple chat with images-----" << std::endl;
std::cout << res2 << std::endl;
std::cout << "------------------------------------------" << std::endl;
/**
* 3. test for chat
*/
auto messages = R"(
[
{
"role": "system",
"content": "You are a helpful assistant."
},
{
"role": "user",
"content": "你是谁?"
}
]
)"_json;
auto options = R"(
{
"temperature": 0.4,
"top_k": 2
}
)"_json;
auto res3 = llmcli.chat("qwen2.5:7b", messages, options);
std::cout << "---------test for chat---------" << std::endl;
std::cout << res3 << std::endl;
std::cout << "-------------------------------" << std::endl;
/**
* 4. test for chat with images
*/
json messages4 = {
{{"role", "system"}, {"content", "You are a helpful assistant."}},
{{"role", "user"}, {"content", "这是一张什么风格的图片?"}, {"images", {"iVBORw0KGgoAAAANSUhEUgAAAG0AAABmCAYAAADBPx+VAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAA3VSURBVHgB7Z27r0zdG8fX743i1bi1ikMoFMQloXRpKFFIqI7LH4BEQ+NWIkjQuSWCRIEoULk0gsK1kCBI0IhrQVT7tz/7zZo888yz1r7MnDl7z5xvsjkzs2fP3uu71nNfa7lkAsm7d++Sffv2JbNmzUqcc8m0adOSzZs3Z+/XES4ZckAWJEGWPiCxjsQNLWmQsWjRIpMseaxcuTKpG/7HP27I8P79e7dq1ars/yL4/v27S0ejqwv+cUOGEGGpKHR37tzJCEpHV9tnT58+dXXCJDdECBE2Ojrqjh071hpNECjx4cMHVycM1Uhbv359B2F79+51586daxN/+pyRkRFXKyRDAqxEp4yMlDDzXG1NPnnyJKkThoK0VFd1ELZu3TrzXKxKfW7dMBQ6bcuWLW2v0VlHjx41z717927ba22U9APcw7Nnz1oGEPeL3m3p2mTAYYnFmMOMXybPPXv2bNIPpFZr1NHn4HMw0KRBjg9NuRw95s8PEcz/6DZELQd/09C9QGq5RsmSRybqkwHGjh07OsJSsYYm3ijPpyHzoiacg35MLdDSIS/O1yM778jOTwYUkKNHWUzUWaOsylE00MyI0fcnOwIdjvtNdW/HZwNLGg+sR1kMepSNJXmIwxBZiG8tDTpEZzKg0GItNsosY8USkxDhD0Rinuiko2gfL/RbiD2LZAjU9zKQJj8RDR0vJBR1/Phx9+PHj9Z7REF4nTZkxzX4LCXHrV271qXkBAPGfP/atWvu/PnzHe4C97F48eIsRLZ9+3a3f/9+87dwP1JxaF7/3r17ba+5l4EcaVo0lj3SBq5kGTJSQmLWMjgYNei2GPT1MuMqGTDEFHzeQSP2wi/jGnkmPJ/nhccs44jvDAxpVcxnq0F6eT8h4ni/iIWpR5lPyA6ETkNXoSukvpJAD3AsXLiwpZs49+fPn5ke4j10TqYvegSfn0OnafC+Tv9ooA/JPkgQysqQNBzagXY55nO/oa1F7qvIPWkRL12WRpMWUvpVDYmxAPehxWSe8ZEXL20sadYIozfmNch4QJPAfeJgW3rNsnzphBKNJM2KKODo1rVOMRYik5ETy3ix4qWNI81qAAirizgMIc+yhTytx0JWZuNI03qsrgWlGtwjoS9XwgUhWGyhUaRZZQNNIEwCiXD16tXcAHUs79co0vSD8rrJCIW98pzvxpAWyyo3HYwqS0+H0BjStClcZJT5coMm6D2LOF8TolGJtK9fvyZpyiC5ePFi9nc/oJU4eiEP0jVoAnHa9wyJycITMP78+eMeP37sXrx44d6+fdt6f82aNdkx1pg9e3Zb5W+RSRE+n+VjksQWifvVaTKFhn5O8my63K8Qabdv33b379/PiAP//vuvW7BggZszZ072/+TJk91YgkafPn166zXB1rQHFvouAWHq9z3SEevSUerqCn2/dDCeta2jxYbr69evk4MHDyY7d+7MjhMnTiTPnz9Pfv/+nfQT2ggpO2dMF8cghuoM7Ygj5iWCqRlGFml0QC/ftGmTmzt3rmsaKDsgBSPh0/8yPeLLBihLkOKJc0jp8H8vUzcxIA1k6QJ/c78tWEyj5P3o4u9+jywNPdJi5rAH9x0KHcl4Hg570eQp3+vHXGyrmEeigzQsQsjavXt38ujRo44LQuDDhw+TW7duRS1HGgMxhNXHgflaNTOsHyKvHK5Ijo2jbFjJBQK9YwFd6RVMzfgRBmEfP37suBBm/p49e1qjEP2mwTViNRo0VJWH1deMXcNK08uUjVUu7s/zRaL+oLNxz1bpANco4npUgX4G2eFbpDFyQoQxojBCpEGSytmOH8qrH5Q9vuzD6ofQylkCUmh8DBAr+q8JCyVNtWQIidKQE9wNtLSQnS4jDSsxNHogzFuQBw4cyM61UKVsjfr3ooBkPSqqQHesUPWVtzi9/vQi1T+rJj7WiTz4Pt/l3LxUkr5P2VYZaZ4URpsE+st/dujQoaBBYokbrz/8TJNQYLSonrPS9kUaSkPeZyj1AWSj+d+VBoy1pIWVNed8P0Ll/ee5HdGRhrHhR5GGN0r4LGZBaj8oFDJitBTJzIZgFcmU0Y8ytWMZMzJOaXUSrUs5RxKnrxmbb5YXO9VGUhtpXldhEUogFr3IzIsvlpmdosVcGVGXFWp2oU9kLFL3dEkSz6NHEY1sjSRdIuDFWEhd8KxFqsRi1uM/nz9/zpxnwlESONdg6dKlbsaMGS4EHFHtjFIDHwKOo46l4TxSuxgDzi+rE2jg+BaFruOX4HXa0Nnf1lwAPufZeF8/r6zD97WK2qFnGjBxTw5qNGPxT+5T/r7/7RawFC3j4vTp09koCxkeHjqbHJqArmH5UrFKKksnxrK7FuRIs8STfBZv+luugXZ2pR/pP9Ois4z+TiMzUUkUjD0iEi1fzX8GmXyuxUBRcaUfykV0YZnlJGKQpOiGB76x5GeWkWWJc3mOrK6S7xdND+W5N6XyaRgtWJFe13GkaZnKOsYqGdOVVVbGupsyA/l7emTLHi7vwTdirNEt0qxnzAvBFcnQF16xh/TMpUuXHDowhlA9vQVraQhkudRdzOnK+04ZSP3DUhVSP61YsaLtd/ks7ZgtPcXqPqEafHkdqa84X6aCeL7YWlv6edGFHb+ZFICPlljHhg0bKuk0CSvVznWsotRu433alNdFrqG45ejoaPCaUkWERpLXjzFL2Rpllp7PJU2a/v7Ab8N05/9t27Z16KUqoFGsxnI9EosS2niSYg9SpU6B4JgTrvVW1flt1sT+0ADIJU2maXzcUTraGCRaL1Wp9rUMk16PMom8QhruxzvZIegJjFU7LLCePfS8uaQdPny4jTTL0dbee5mYokQsXTIWNY46kuMbnt8Kmec+LGWtOVIl9cT1rCB0V8WqkjAsRwta93TbwNYoGKsUSChN44lgBNCoHLHzquYKrU6qZ8lolCIN0Rh6cP0Q3U6I6IXILYOQI513hJaSKAorFpuHXJNfVlpRtmYBk1Su1obZr5dnKAO+L10Hrj3WZW+E3qh6IszE37F6EB+68mGpvKm4eb9bFrlzrok7fvr0Kfv727dvWRmdVTJHw0qiiCUSZ6wCK+7XL/AcsgNyL74DQQ730sv78Su7+t/A36MdY0sW5o40ahslXr58aZ5HtZB8GH64m9EmMZ7FpYw4T6QnrZfgenrhFxaSiSGXtPnz57e9TkNZLvTjeqhr734CNtrK41L40sUQckmj1lGKQ0rC37x544r8eNXRpnVE3ZZY7zXo8NomiO0ZUCj2uHz58rbXoZ6gc0uA+F6ZeKS/jhRDUq8MKrTho9fEkihMmhxtBI1DxKFY9XLpVcSkfoi8JGnToZO5sU5aiDQIW716ddt7ZLYtMQlhECdBGXZZMWldY5BHm5xgAroWj4C0hbYkSc/jBmggIrXJWlZM6pSETsEPGqZOndr2uuuR5rF169a2HoHPdurUKZM4CO1WTPqaDaAd+GFGKdIQkxAn9RuEWcTRyN2KSUgiSgF5aWzPTeA/lN5rZubMmR2bE4SIC4nJoltgAV/dVefZm72AtctUCJU2CMJ327hxY9t7EHbkyJFseq+EJSY16RPo3Dkq1kkr7+q0bNmyDuLQcZBEPYmHVdOBiJyIlrRDq41YPWfXOxUysi5fvtyaj+2BpcnsUV/oSoEMOk2CQGlr4ckhBwaetBhjCwH0ZHtJROPJkyc7UjcYLDjmrH7ADTEBXFfOYmB0k9oYBOjJ8b4aOYSe7QkKcYhFlq3QYLQhSidNmtS2RATwy8YOM3EQJsUjKiaWZ+vZToUQgzhkHXudb/PW5YMHD9yZM2faPsMwoc7RciYJXbGuBqJ1UIGKKLv915jsvgtJxCZDubdXr165mzdvtr1Hz5LONA8jrUwKPqsmVesKa49S3Q4WxmRPUEYdTjgiUcfUwLx589ySJUva3oMkP6IYddq6HMS4o55xBJBUeRjzfa4Zdeg56QZ43LhxoyPo7Lf1kNt7oO8wWAbNwaYjIv5lhyS7kRf96dvm5Jah8vfvX3flyhX35cuX6HfzFHOToS1H4BenCaHvO8pr8iDuwoUL7tevX+b5ZdbBair0xkFIlFDlW4ZknEClsp/TzXyAKVOmmHWFVSbDNw1l1+4f90U6IY/q4V27dpnE9bJ+v87QEydjqx/UamVVPRG+mwkNTYN+9tjkwzEx+atCm/X9WvWtDtAb68Wy9LXa1UmvCDDIpPkyOQ5ZwSzJ4jMrvFcr0rSjOUh+GcT4LSg5ugkW1Io0/SCDQBojh0hPlaJdah+tkVYrnTZowP8iq1F1TgMBBauufyB33x1v+NWFYmT5KmppgHC+NkAgbmRkpD3yn9QIseXymoTQFGQmIOKTxiZIWpvAatenVqRVXf2nTrAWMsPnKrMZHz6bJq5jvce6QK8J1cQNgKxlJapMPdZSR64/UivS9NztpkVEdKcrs5alhhWP9NeqlfWopzhZScI6QxseegZRGeg5a8C3Re1Mfl1ScP36ddcUaMuv24iOJtz7sbUjTS4qBvKmstYJoUauiuD3k5qhyr7QdUHMeCgLa1Ear9NquemdXgmum4fvJ6w1lqsuDhNrg1qSpleJK7K3TF0Q2jSd94uSZ60kK1e3qyVpQK6PVWXp2/FC3mp6jBhKKOiY2h3gtUV64TWM6wDETRPLDfSakXmH3w8g9Jlug8ZtTt4kVF0kLUYYmCCtD/DrQ5YhMGbA9L3ucdjh0y8kOHW5gU/VEEmJTcL4Pz/f7mgoAbYkAAAAAElFTkSuQmCC"}}}
};
auto res4 = llmcli.chat("minicpm-v:8b", messages4, {{"temperature", 0.1}, {"top_k", 1}});
std::cout << "---------test for chat with images---------" << std::endl;
std::cout << res4 << std::endl;
std::cout << "-------------------------------------------" << std::endl;
}

View File

@@ -0,0 +1,79 @@
#include <iostream>
#include "llmlib.hpp"
using namespace llmlib;
/**
* prepared information from https://bailian.console.aliyun.com/#/home (or other OpenAI-compatible Services)
* 1. api base url
* 2. api key
*/
int main() {
LLMClient llmcli("https://dashscope.aliyuncs.com/compatible-mode/v1", "sk-XXX", LLMBackendType::OpenAI);
/**
* 1. test for simple chat
*/
auto res1 = llmcli.simple_chat("qwen2.5-vl-7b-instruct", "坐飞机为什么要付机票钱?", {}, {{"temperature", 0.1}, {"top_k", 1}});
std::cout << "------test for simple chat-----" << std::endl;
std::cout << res1 << std::endl;
std::cout << "-------------------------------" << std::endl;
/**
* 2. test for simple chat with images
*/
auto image1 = cv::imread("/windows2/zhzhi/github/vp_data/test_images/vehicle/0.jpg");
auto image2 = cv::imread("/windows2/zhzhi/github/vp_data/test_images/vehicle/27.jpg");
auto res2 = llmcli.simple_chat("qwen2.5-vl-7b-instruct", "描述这两幅图片的差异", {image1, image2}, {});
std::cout << "-----test for simple chat with images-----" << std::endl;
std::cout << res2 << std::endl;
std::cout << "------------------------------------------" << std::endl;
/**
* 3. test for chat
*/
auto messages = R"(
[
{
"role": "system",
"content": "You are a helpful assistant."
},
{
"role": "user",
"content": "你是谁?"
}
]
)"_json;
auto options = R"(
{
"temperature": 0.4,
"top_k": 2
}
)"_json;
auto res3 = llmcli.chat("qwen2.5-vl-7b-instruct", messages, options);
std::cout << "---------test for chat---------" << std::endl;
std::cout << res3 << std::endl;
std::cout << "-------------------------------" << std::endl;
/**
* 4. test for chat with images
*/
json messages4 = {
{
{"role", "system"},
{"content", "You are a helpful assistant."}
},
{
{"role", "user"},
{"content", {
{{"type", "text"}, {"text", "请描述这张图。"}},
{
{"type", "image_url"},
{"image_url", {{"url", "data:image/jpg;base64,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"}}}
}
}}
}
};
auto res4 = llmcli.chat("qwen2.5-vl-7b-instruct", messages4, {{"temperature", 0.1}, {"top_k", 1}});
std::cout << "---------test for chat with images---------" << std::endl;
std::cout << res4 << std::endl;
std::cout << "-------------------------------------------" << std::endl;
}