C++ web开发框架 paozhu 发布1.15.0 继续添加企业开发周边
目前使用 paozhu全家桶开发企业管理后台,遇到的需要后台功能也顺手添加了
paozhu 对AI还是非常友好,基本上可以让AI在paozhu框架基础上生成立即,马上可以使用后台。
你一行代码都不用写,先把系统设计文档、数据库设计好,然后放到项目docx目录,然后AI读取并开工。
1 本次主要更新了ORM文件和view视图问题更新方式
./bin/paozhu_cli view 是更新所有需要更新的视图文件
./bin/paozhu_cli orm <dbtag> 更新数据库表结构到CPP文件,<dbtag> 是conf/orm.conf 里面 [dbtag] 的数据库标签
./bin/paozhu_cli json 是框架搜索libs目录下 struct 结构体生成 json_encode json_decode,或者根据json文件生成相应的
c++结构体,然后再生成json_encode json_decode 让json和结构体互相转化
2 添加webpay,支持微信和支付宝,阿里云和腾讯云短信接口
#include <chrono> #include <thread> #include <filesystem> #include "httppeer.h" #include "test_wxpay.h" #include "func.h" #include "request.h" #include "httpclient.h" #ifdef ENABLE_WEBPAY #include "wxpay.h" #endif #ifdef ENABLE_IMAGE #include "qrcode.h" #include "pzpng.h" #endif namespace http { //@urlpath(null,testwxpaynative) std::string test_wxpay_native(std::shared_ptr<httppeer> peer) { httppeer &client = peer->get_peer(); #ifdef ENABLE_WEBPAY std::string out_trade_no = get_date("%Y%m%d%H%M%S") + rand_string(4, 4); pay::wxpay wp; wp.setAppId("你的微信APPID"); wp.setMchId("你的微信商户号"); wp.setPrivateKey("你的微信商户私钥路径或内容"); wp.setPublicKey("你的微信平台证书路径或内容"); wp.setApiKey("你的微信API密钥"); wp.setSerialNo("你的证书序列号"); wp.setOutTradeNo(out_trade_no); wp.setDescription("测试商品"); wp.setTotalAmount("1"); wp.setNotifyUrl("https://yourdomain.com/wxpaynotify"); std::string response = wp.createNative(); client.output = response; #ifdef ENABLE_IMAGE http::obj_val resp_json; resp_json.from_json(response); std::string qrcontent = resp_json["code_url"].to_string(); if (!qrcontent.empty()) { namespace fs = std::filesystem; qr::qrcode q; q.text(qrcontent, qr::Ecc::M, 1); image::png img; unsigned char scale = 10; img.create(q.width()*scale + 40, q.height()*scale + 40, 6, 8); img.fillColor({255, 255, 255, 255}); img.qrdata(q.data,q.width(),q.height(),scale, 20 ,20); std::string wwwpath; wwwpath.append(client.get_sitepath()); wwwpath.append("/upload"); fs::path paths = wwwpath; bool is_success = fs::create_directories(paths); if (is_success) { fs::permissions(paths, fs::perms::owner_all | fs::perms::group_all | fs::perms::others_read, fs::perm_options::add); } wwwpath.append("/wxpay_qr.png"); img.save(wwwpath); client << "<img src=\"/upload/wxpay_qr.png?token=" << rand_string(6, 6) << "\">"; } #endif #else client.output = "{\"code\":\"-1\",\"msg\":\"ENABLE_WEBPAY not enabled\"}"; #endif return ""; } //@urlpath(null,testwxpayjsapi) std::string test_wxpay_jsapi(std::shared_ptr<httppeer> peer) { httppeer &client = peer->get_peer(); #ifdef ENABLE_WEBPAY std::string out_trade_no = get_date("%Y%m%d%H%M%S") + rand_string(4, 4); pay::wxpay wp; wp.setAppId("你的微信APPID"); wp.setMchId("你的微信商户号"); wp.setPrivateKey("你的微信商户私钥路径或内容"); wp.setPublicKey("你的微信平台证书路径或内容"); wp.setApiKey("你的微信API密钥"); wp.setSerialNo("你的证书序列号"); wp.setOutTradeNo(out_trade_no); wp.setDescription("测试商品"); wp.setTotalAmount("1"); wp.setNotifyUrl("https://yourdomain.com/wxpaynotify"); wp.setOpenId("用户的OpenID"); std::string response = wp.createJSAPI(); client.output = response; #else client.output = "{\"code\":\"-1\",\"msg\":\"ENABLE_WEBPAY not enabled\"}"; #endif return ""; } //@urlpath(null,testwxpayapp) std::string test_wxpay_app(std::shared_ptr<httppeer> peer) { httppeer &client = peer->get_peer(); #ifdef ENABLE_WEBPAY std::string out_trade_no = get_date("%Y%m%d%H%M%S") + rand_string(4, 4); pay::wxpay wp; wp.setAppId("你的微信APPID"); wp.setMchId("你的微信商户号"); wp.setPrivateKey("你的微信商户私钥路径或内容"); wp.setPublicKey("你的微信平台证书路径或内容"); wp.setApiKey("你的微信API密钥"); wp.setSerialNo("你的证书序列号"); wp.setOutTradeNo(out_trade_no); wp.setDescription("测试商品"); wp.setTotalAmount("1"); wp.setNotifyUrl("https://yourdomain.com/wxpaynotify"); std::string response = wp.createAPP(); client.output = response; #else client.output = "{\"code\":\"-1\",\"msg\":\"ENABLE_WEBPAY not enabled\"}"; #endif return ""; } //@urlpath(null,testwxpayh5) std::string test_wxpay_h5(std::shared_ptr<httppeer> peer) { httppeer &client = peer->get_peer(); #ifdef ENABLE_WEBPAY std::string out_trade_no = get_date("%Y%m%d%H%M%S") + rand_string(4, 4); pay::wxpay wp; wp.setAppId("你的微信APPID"); wp.setMchId("你的微信商户号"); wp.setPrivateKey("你的微信商户私钥路径或内容"); wp.setPublicKey("你的微信平台证书路径或内容"); wp.setApiKey("你的微信API密钥"); wp.setSerialNo("你的证书序列号"); wp.setOutTradeNo(out_trade_no); wp.setDescription("测试商品"); wp.setTotalAmount("1"); wp.setNotifyUrl("https://yourdomain.com/wxpaynotify"); std::string response = wp.createH5(); client.output = response; #else client.output = "{\"code\":\"-1\",\"msg\":\"ENABLE_WEBPAY not enabled\"}"; #endif return ""; } //@urlpath(null,testwxpayquery) std::string test_wxpay_query(std::shared_ptr<httppeer> peer) { httppeer &client = peer->get_peer(); #ifdef ENABLE_WEBPAY std::string out_trade_no = client.get["out_trade_no"].to_string(); if (out_trade_no.empty()) { client.output = "{\"code\":\"-1\",\"msg\":\"缺少out_trade_no\"}"; return ""; } pay::wxpay wp; wp.setAppId("你的微信APPID"); wp.setMchId("你的微信商户号"); wp.setPrivateKey("你的微信商户私钥路径或内容"); wp.setPublicKey("你的微信平台证书路径或内容"); wp.setApiKey("你的微信API密钥"); wp.setSerialNo("你的证书序列号"); std::string response = wp.queryTrade(out_trade_no); client.output = response; #else client.output = "{\"code\":\"-1\",\"msg\":\"ENABLE_WEBPAY not enabled\"}"; #endif return ""; } //@urlpath(null,testwxpayclose) std::string test_wxpay_close(std::shared_ptr<httppeer> peer) { httppeer &client = peer->get_peer(); #ifdef ENABLE_WEBPAY std::string out_trade_no = client.get["out_trade_no"].to_string(); if (out_trade_no.empty()) { client.output = "{\"code\":\"-1\",\"msg\":\"缺少out_trade_no\"}"; return ""; } pay::wxpay wp; wp.setAppId("你的微信APPID"); wp.setMchId("你的微信商户号"); wp.setPrivateKey("你的微信商户私钥路径或内容"); wp.setPublicKey("你的微信平台证书路径或内容"); wp.setApiKey("你的微信API密钥"); wp.setSerialNo("你的证书序列号"); std::string response = wp.closeTrade(out_trade_no); client.output = response; #else client.output = "{\"code\":\"-1\",\"msg\":\"ENABLE_WEBPAY not enabled\"}"; #endif return ""; } //@urlpath(null,testwxpayrefund) std::string test_wxpay_refund(std::shared_ptr<httppeer> peer) { httppeer &client = peer->get_peer(); #ifdef ENABLE_WEBPAY std::string out_trade_no = client.get["out_trade_no"].to_string(); std::string refund_amount = client.get["refund_amount"].to_string(); if (out_trade_no.empty()) { client.output = "{\"code\":\"-1\",\"msg\":\"缺少out_trade_no\"}"; return ""; } if (refund_amount.empty()) { client.output = "{\"code\":\"-1\",\"msg\":\"缺少refund_amount\"}"; return ""; } pay::wxpay wp; wp.setAppId("你的微信APPID"); wp.setMchId("你的微信商户号"); wp.setPrivateKey("你的微信商户私钥路径或内容"); wp.setPublicKey("你的微信平台证书路径或内容"); wp.setApiKey("你的微信API密钥"); wp.setSerialNo("你的证书序列号"); wp.setTotalAmount("1"); std::string response = wp.refundTrade(refund_amount, "测试退款", out_trade_no); client.output = response; #else client.output = "{\"code\":\"-1\",\"msg\":\"ENABLE_WEBPAY not enabled\"}"; #endif return ""; } //@urlpath(null,wxpaynotify) std::string test_wxpay_notify(std::shared_ptr<httppeer> peer) { httppeer &client = peer->get_peer(); client.type("Content-Type: application/json; charset=utf-8"); #ifdef ENABLE_WEBPAY std::map<std::string, std::string> headers; headers["Wechatpay-Timestamp"] = client.get_header("Wechatpay-Timestamp"); headers["Wechatpay-Nonce"] = client.get_header("Wechatpay-Nonce"); headers["Wechatpay-Signature"] = client.get_header("Wechatpay-Signature"); headers["Wechatpay-Serial"] = client.get_header("Wechatpay-Serial"); pay::wxpay wp; wp.setAppId("你的微信APPID"); wp.setMchId("你的微信商户号"); wp.setPrivateKey("你的微信商户私钥路径或内容"); wp.setPublicKey("你的微信平台证书路径或内容"); wp.setApiKey("你的微信API密钥"); auto resp = wp.handleNotify(client.rawcontent, headers); if (resp["status_code"] == "0") { std::string out_trade_no = resp["out_trade_no"]; std::string transaction_id = resp["transaction_id"]; std::string amount = resp["amount"]; client.output = "{\"code\":\"SUCCESS\",\"message\":\"成功\"}"; } else { client.output = "{\"code\":\"FAIL\",\"message\":\"" + resp["error_msg"] + "\"}"; } #else client.output = "{\"code\":\"FAIL\",\"message\":\"ENABLE_WEBPAY not enabled\"}"; #endif return ""; } //@urlpath(null,wxpaydownloadcert) std::string test_wxpay_download_cert(std::shared_ptr<httppeer> peer) { httppeer &client = peer->get_peer(); #ifdef ENABLE_WEBPAY pay::wxpay wp; wp.setAppId("你的微信APPID"); wp.setMchId("你的微信商户号"); wp.setPrivateKey("你的微信商户私钥路径或内容"); wp.setApiKey("你的微信API密钥"); std::string response = wp.downloadCertificates(); client.output = response; #else client.output = "{\"code\":\"-1\",\"msg\":\"ENABLE_WEBPAY not enabled\"}"; #endif return ""; } }
3 添加图表生成,满足企业后台开发需要,支持20种图表,算法来自echarts, 目前使用纯c++生成svg图片,添加了正态分布 九宫格 乔哈里视窗图等
//@urlpath(null,test_svgstats)
std::string test_svgstats(std::shared_ptr<httppeer> peer)
{
httppeer &client = peer->get_peer();
#ifdef ENABLE_CHART
client << "<h2>========== 原始数据 & 统计结果 ==========</h2>";
// ============================================================
// 一、LinearRegression 示例(原始数据)
// ============================================================
client << "<h3>LinearRegression 示例</h3>";
// ---- 示例 1: 线性回归 y = ax + b ----
{
std::ostringstream oss;
oss << std::fixed << std::setprecision(4);
// 面积(m²) → 价格(万元)
std::vector<std::vector<double>> data = {
{50, 150},
{70, 210},
{90, 270},
{110, 330},
{130, 390}};
auto result = LinearRegression::linear(data);
oss << "<b>【线性回归】房价 = a * 面积 + b</b><br>";
oss << " 公式: " << result.expression << "<br>";
oss << " 斜率 a: " << result.parameters.gradient << "<br>";
oss << " 截距 b: " << result.parameters.intercept << "<br>";
oss << " 预测点: ";
for (const auto &p : result.points)
{
oss << "(" << p[0] << "," << p[1] << ") ";
}
oss << "<br><br>";
client << "<pre>" << oss.str() << "</pre>";
}
// ---- 示例 2: 指数回归 y = a * e^(bx) ----
{
std::ostringstream oss;
oss << std::fixed << std::setprecision(4);
std::vector<std::vector<double>> data = {
{1, 4862},
{2, 5294},
{3, 5934},
{4, 7171},
{5, 8964},
{6, 10202},
{7, 11962},
{8, 14928},
{9, 16909},
{10, 18547},
{11, 21617},
{12, 26638},
{13, 34634},
{14, 46759},
{15, 58478},
{16, 67884},
{17, 74462},
{18, 79395}};
auto result = LinearRegression::exponential(data);
oss << "<b>【指数回归】GDP = a * e^(b*年份)</b><br>";
oss << " 公式: " << result.expression << "<br>";
oss << " 系数 a: " << result.parameters.intercept << "<br>";
oss << " 指数 b: " << result.parameters.gradient << "<br>";
oss << " 预测第 20 年: " << result.parameters.intercept
<< " * e^(" << result.parameters.gradient << " * 20) = "
<< result.parameters.intercept * std::exp(result.parameters.gradient * 20)
<< "<br><br>";
client << "<pre>" << oss.str() << "</pre>";
}
// ---- 示例 3: 对数回归 y = a + b*ln(x) ----
{
std::ostringstream oss;
oss << std::fixed << std::setprecision(4);
std::vector<std::vector<double>> data = {
{1, 5},
{2, 12},
{3, 17},
{5, 22},
{10, 29},
{20, 35},
{50, 42}};
auto result = LinearRegression::logarithmic(data);
oss << "<b>【对数回归】收益 = a + b*ln(投入)</b><br>";
oss << " 公式: " << result.expression << "<br>";
oss << " 截距 a: " << result.parameters.intercept << "<br>";
oss << " 斜率 b: " << result.parameters.gradient << "<br>";
oss << " 投入 100 时预测收益: " << result.parameters.intercept
<< " + " << result.parameters.gradient << " * ln(100) = "
<< result.parameters.intercept + result.parameters.gradient * std::log(100)
<< "<br><br>";
client << "<pre>" << oss.str() << "</pre>";
}
// ---- 示例 4: 多项式回归 y = a0 + a1*x + a2*x^2 + ... ----
{
std::ostringstream oss;
oss << std::fixed << std::setprecision(4);
std::vector<std::vector<double>> data = {
{0, 0},
{1, 1.2},
{2, 3.8},
{3, 8.9},
{4, 16.1},
{5, 25.0}};
auto result = LinearRegression::polynomial(data, 2);
oss << "<b>【多项式回归 (order=2)】抛物线拟合</b><br>";
oss << " 公式: " << result.expression << "<br>";
oss << " 系数: ";
for (size_t i = 0; i < result.parameters.coefficients.size(); ++i)
{
oss << "a" << i << "=" << result.parameters.coefficients[i] << " ";
}
oss << "<br><br>";
client << "<pre>" << oss.str() << "</pre>";
}
// ---- 示例 5: 过原点线性回归 y = ax ----
{
std::ostringstream oss;
oss << std::fixed << std::setprecision(4);
std::vector<std::vector<double>> data = {
{1, 3.1},
{2, 5.9},
{3, 9.2},
{4, 11.8},
{5, 15.2}};
LinearRegression::Config config;
config.method = LinearRegression::LINEAR_THROUGH_ORIGIN;
auto result = LinearRegression::run(data, config);
oss << "<b>【过原点线性回归】距离 = a * 时间</b><br>";
oss << " 公式: " << result.expression << "<br>";
oss << " 速度 a: " << result.parameters.gradient << " m/s<br><br>";
client << "<pre>" << oss.str() << "</pre>";
}
// ---- 示例 6: 多维指定列 ----
{
std::ostringstream oss;
oss << std::fixed << std::setprecision(4);
std::vector<std::vector<double>> data = {
{1, 0, 3},
{2, 0, 5},
{3, 0, 7},
{4, 0, 9},
{5, 0, 11}};
LinearRegression::Config config;
config.method = LinearRegression::LINEAR;
config.dimensions = {0, 2};// x=第0列, y=第2列
auto result = LinearRegression::run(data, config);
oss << "<b>【指定维度】x=col0, y=col2</b><br>";
oss << " 公式: " << result.expression << "<br>";
oss << " 预测点: ";
for (const auto &p : result.points)
{
oss << "(" << p[0] << "," << p[1] << ") ";
}
oss << "<br><br>";
client << "<pre>" << oss.str() << "</pre>";
}
// ============================================================
// 二、ClusteringProcess 示例(原始数据)
// ============================================================
client << "<h3>ClusteringProcess 示例</h3>";
// ---- 示例 1: 客户分群 ----
{
std::ostringstream oss;
oss << std::fixed << std::setprecision(1);
std::vector<std::vector<double>> data = {
{2, 1},
{3, 2},
{2.5, 1},// 低价值客户
{15, 8},
{18, 10},
{16, 9},// 中等客户
{50, 25},
{55, 30},
{48, 28}// 高价值客户
};
auto result = ClusteringProcess::simpleKMeans(data, 3);
oss << "<b>【客户分群】k=3</b><br>";
oss << " 原始数据: {消费额(千元), 月访问次数}<br>";
for (size_t i = 0; i < data.size(); ++i)
{
oss << " 点" << i << ": (" << data[i][0] << ", " << data[i][1] << ")<br>";
}
oss << " 聚类结果:<br>";
for (size_t c = 0; c < result.centroids.size(); ++c)
{
oss << " 群 " << c << " 中心: (消费="
<< result.centroids[c][0] << "k, 访问="
<< result.centroids[c][1] << "次) "
<< result.pointsInCluster[c].size() << " 人<br>";
}
oss << "<br>";
client << "<pre>" << oss.str() << "</pre>";
}
// ---- 示例 2: 二维散点聚类 + 每个点的分配 ----
{
std::ostringstream oss;
oss << std::fixed << std::setprecision(4);
std::vector<std::vector<double>> data = {
{0.1, 0.2},
{0.2, 0.1},
{0.3, 0.3},
{0.1, 0.4},
{0.5, 0.2},
{9.8, 9.9},
{9.9, 9.8},
{10.1, 10.0},
{10.0, 10.2},
{9.7, 10.1}};
auto result = ClusteringProcess::simpleKMeans(data, 2);
oss << "<b>【二维散点聚类】k=2,10 个点</b><br>";
oss << " 各点分配: ";
for (size_t i = 0; i < result.clusterAssigned.size(); ++i)
{
oss << "点" << i << "→群" << result.clusterAssigned[i].clusterIndex << " ";
}
oss << "<br>";
oss << " 群 0 中心: (" << result.centroids[0][0] << ", " << result.centroids[0][1] << ")<br>";
oss << " 群 1 中心: (" << result.centroids[1][0] << ", " << result.centroids[1][1] << ")<br><br>";
client << "<pre>" << oss.str() << "</pre>";
}
// ---- 示例 3: 多维数据聚类 + 指定维度 ----
{
std::ostringstream oss;
oss << std::fixed << std::setprecision(4);
std::vector<std::vector<double>> data = {
{1.0, 2.0, 100},
{1.1, 2.1, 101},
{10.0, 20.0, 200},
{10.1, 20.1, 201}};
ClusteringProcess::Config config;
config.clusterCount = 2;
config.dimensions = {0, 1};// 只用第 0 和第 1 列做聚类
auto result = ClusteringProcess::run(data, config);
oss << "<b>【多维聚类】3D 数据,用前 2 维聚类</b><br>";
oss << " 群 0 中心: (" << result.centroids[0][0] << ", " << result.centroids[0][1] << ")<br>";
oss << " 群 1 中心: (" << result.centroids[1][0] << ", " << result.centroids[1][1] << ")<br>";
oss << " 点 0,1 → 群 " << result.clusterAssigned[0].clusterIndex << "<br>";
oss << " 点 2,3 → 群 " << result.clusterAssigned[2].clusterIndex << "<br><br>";
client << "<pre>" << oss.str() << "</pre>";
}
// ---- 示例 4: 每个点的距离信息 ----
{
std::ostringstream oss;
oss << std::fixed << std::setprecision(4);
std::vector<std::vector<double>> data = {
{0.1, 0.2},
{1.0, 1.0},
{0.3, 0.1},
{9.8, 9.9},
{9.9, 9.8},
{10.0, 10.0}};
auto result = ClusteringProcess::simpleKMeans(data, 2);
oss << "<b>【距离信息】每个点到其所在群中心的距离</b><br>";
for (size_t i = 0; i < result.clusterAssigned.size(); ++i)
{
oss << " 点" << i << " (" << data[i][0] << "," << data[i][1]
<< ") → 群" << result.clusterAssigned[i].clusterIndex
<< " 距离²=" << result.clusterAssigned[i].distance << "<br>";
}
oss << "<br>";
client << "<pre>" << oss.str() << "</pre>";
}
// ============================================================
// 三、KernelDensity 测试(原始数据)
// ============================================================
client << "<h3>KernelDensity 测试</h3>";
{
std::ostringstream oss;
oss << std::fixed << std::setprecision(4);
std::vector<double> data = {1.0, 2.0, 2.5, 3.0, 3.5, 4.0, 5.0};
KernelDensity kde(data, 0);
oss << " 原始数据: ";
for (size_t i = 0; i < data.size(); ++i)
{
oss << data[i] << " ";
}
oss << "<br>";
oss << " density(2.5) = " << kde.density(2.5) << "<br>";
double q50 = kde.quantile(0.5);
oss << " quantile(0.5) = " << q50 << " (data range: " << kde.dataMin() << " ~ " << kde.dataMax() << ")<br>";
oss << " generateCurve(10).size() = " << kde.generateCurve(10).size() << "<br>";
auto ci = kde.centralInterval(0.5);
oss << " centralInterval(0.5) = (" << ci.first << ", " << ci.second << ")<br><br>";
client << "<pre>" << oss.str() << "</pre>";
}
// ============================================================
// 四、LinearRegression 单元测试
// ============================================================
client << "<h3>LinearRegression 单元测试</h3>";
{
std::ostringstream oss;
oss << std::fixed << std::setprecision(4);
// Test 1: Simple linear regression y = 2x + 1
{
std::vector<std::vector<double>> data = {
{1, 3},
{2, 5},
{3, 7},
{4, 9},
{5, 11}};
auto result = LinearRegression::linear(data);
bool pass = std::abs(result.parameters.gradient - 2.0) < 0.01 && std::abs(result.parameters.intercept - 1.0) < 0.01;
oss << " " << (pass ? "PASS" : "FAIL") << ": linear y = 2x + 1, "
<< "a=" << result.parameters.gradient << " b=" << result.parameters.intercept << "<br>";
}
// Test 2: Linear through origin y = 3x
{
std::vector<std::vector<double>> data = {
{1, 3},
{2, 6},
{3, 9},
{4, 12},
{5, 15}};
LinearRegression::Config config;
config.method = LinearRegression::LINEAR_THROUGH_ORIGIN;
auto result = LinearRegression::run(data, config);
bool pass = std::abs(result.parameters.gradient - 3.0) < 0.01;
oss << " " << (pass ? "PASS" : "FAIL") << ": linear through origin y = 3x, "
<< "a=" << result.parameters.gradient << "<br>";
}
// Test 3: Exponential regression y = 2 * e^(0.5*x)
{
std::vector<std::vector<double>> data;
for (int i = 1; i <= 10; ++i)
{
data.push_back({static_cast<double>(i), 2.0 * std::exp(0.5 * i)});
}
auto result = LinearRegression::exponential(data);
bool pass = std::abs(result.parameters.gradient - 0.5) < 0.05 && std::abs(result.parameters.intercept - 2.0) < 0.5;
oss << " " << (pass ? "PASS" : "FAIL") << ": exponential y = 2e^(0.5x), "
<< "a=" << result.parameters.intercept << " b=" << result.parameters.gradient << "<br>";
}
// Test 4: Logarithmic regression y = 1 + 2*ln(x)
{
std::vector<std::vector<double>> data;
for (int i = 1; i <= 10; ++i)
{
data.push_back({static_cast<double>(i), 1.0 + 2.0 * std::log(i)});
}
auto result = LinearRegression::logarithmic(data);
bool pass = std::abs(result.parameters.intercept - 1.0) < 0.01 && std::abs(result.parameters.gradient - 2.0) < 0.01;
oss << " " << (pass ? "PASS" : "FAIL") << ": logarithmic y = 1 + 2ln(x), "
<< "a=" << result.parameters.intercept << " b=" << result.parameters.gradient << "<br>";
}
// Test 5: Polynomial regression y = x^2
{
std::vector<std::vector<double>> data;
for (int i = 0; i <= 5; ++i)
{
data.push_back({static_cast<double>(i), static_cast<double>(i * i)});
}
auto result = LinearRegression::polynomial(data, 2);
bool pass = result.parameters.coefficients.size() == 3 && std::abs(result.parameters.coefficients[2] - 1.0) < 0.01;
oss << " " << (pass ? "PASS" : "FAIL") << ": polynomial y = x^2, "
<< "a2=" << result.parameters.coefficients[2] << "<br>";
}
// Test 6: Real-world data (ECharts example)
{
std::vector<std::vector<double>> data = {
{1, 4862.4},
{2, 5294.7},
{3, 5934.5},
{4, 7171.0},
{5, 8964.4},
{6, 10202.2},
{7, 11962.5},
{8, 14928.3},
{9, 16909.2},
{10, 18547.9},
{11, 21617.8},
{12, 26638.1},
{13, 34634.4},
{14, 46759.4},
{15, 58478.1},
{16, 67884.6},
{17, 74462.6},
{18, 79395.7}};
auto result = LinearRegression::exponential(data);
bool pass = result.points.size() == 18;
oss << " " << (pass ? "PASS" : "FAIL") << ": real-world exponential (18 points), "
<< "expression=" << result.expression << "<br>";
}
oss << "<br>";
client << "<pre>" << oss.str() << "</pre>";
}
// ============================================================
// 五、Clustering 单元测试
// ============================================================
client << "<h3>Clustering 单元测试</h3>";
{
std::ostringstream oss;
oss << std::fixed << std::setprecision(4);
// Test 1: Two clearly separated clusters
{
std::vector<std::vector<double>> data = {
{0.1, 0.2},
{0.2, 0.1},
{0.3, 0.3},
{0.1, 0.4},
{0.5, 0.2},
{9.8, 9.9},
{9.9, 9.8},
{10.1, 10.0},
{10.0, 10.2},
{9.7, 10.1}};
auto result = ClusteringProcess::simpleKMeans(data, 2);
int c0 = result.clusterAssigned[0].clusterIndex;
int c1 = result.clusterAssigned[5].clusterIndex;
bool pass = result.centroids.size() == 2 && c0 != c1;
oss << " " << (pass ? "PASS" : "FAIL") << ": 2-cluster separation (c0=" << c0 << " c1=" << c1 << ")<br>";
}
// Test 2: Three clusters
{
std::vector<std::vector<double>> data = {
{0.1, 0.2},
{0.2, 0.3},
{0.3, 0.1},
{5.0, 5.1},
{5.1, 5.0},
{4.9, 5.2},
{9.8, 9.9},
{9.9, 9.7},
{10.0, 10.1}};
auto result = ClusteringProcess::simpleKMeans(data, 3);
bool allNonEmpty = true;
for (size_t c = 0; c < result.pointsInCluster.size(); ++c)
{
if (result.pointsInCluster[c].size() < 1)
allNonEmpty = false;
}
bool pass = result.centroids.size() == 3 && allNonEmpty;
oss << " " << (pass ? "PASS" : "FAIL") << ": 3-cluster, all non-empty<br>";
}
// Test 3: Multi-dimensional data
{
std::vector<std::vector<double>> data = {
{1.0, 2.0, 3.0},
{1.1, 2.1, 3.1},
{10.0, 20.0, 30.0},
{10.1, 20.1, 30.1}};
auto result = ClusteringProcess::simpleKMeans(data, 2);
bool pass = result.centroids.size() == 2 && result.clusterAssigned[0].clusterIndex != result.clusterAssigned[2].clusterIndex;
oss << " " << (pass ? "PASS" : "FAIL") << ": 3D clustering<br>";
}
// Test 4: Edge case - tight data
{
std::vector<std::vector<double>> data = {
{1.0, 2.0},
{1.1, 2.1},
{0.9, 1.9}};
auto result = ClusteringProcess::simpleKMeans(data, 2);
bool pass = result.centroids.size() >= 1;
oss << " " << (pass ? "PASS" : "FAIL") << ": tight data edge case<br>";
}
oss << "<br>";
client << "<pre>" << oss.str() << "</pre>";
}
// ============================================================
// 六、SVG 图表输出
// ============================================================
client << "<hr><h2>========== SVG 图表 ==========</h2>";
client << "<p>21. 线性回归图 - 房价预测</p>";
{
SvgRegressionChart chart(800, 500);
chart.setTitle("Linear Regression - House Price Prediction");
chart.setData({{50, 150}, {60, 175}, {70, 210}, {80, 240}, {90, 270}, {100, 300}, {110, 330}, {120, 360}, {130, 390}, {140, 420}});
chart.setMethod(LinearRegression::LINEAR);
chart.setPointColor(SvgColor(84, 112, 198));
chart.setLineColor(SvgColor(238, 102, 102));
client << chart.render();
}
client << "<p>22. 指数回归图 - GDP 增长</p>";
{
SvgRegressionChart chart(800, 500);
chart.setTitle("Exponential Regression - GDP Growth");
chart.setData({{1, 2.1}, {2, 2.5}, {3, 3.1}, {4, 4.0}, {5, 5.2}, {6, 6.8}, {7, 8.9}, {8, 11.5}, {9, 14.8}, {10, 19.0}});
chart.setMethod(LinearRegression::EXPONENTIAL);
chart.setPointColor(SvgColor(60, 162, 131));
chart.setLineColor(SvgColor(238, 102, 102));
client << chart.render();
}
client << "<p>23. 对数回归图 - 学习曲线</p>";
{
SvgRegressionChart chart(800, 500);
chart.setTitle("Logarithmic Regression - Learning Curve");
chart.setData({{1, 20}, {2, 35}, {3, 45}, {4, 52}, {5, 57}, {6, 61}, {8, 67}, {10, 71}, {15, 78}, {20, 83}});
chart.setMethod(LinearRegression::LOGARITHMIC);
chart.setPointColor(SvgColor(250, 200, 88));
chart.setLineColor(SvgColor(238, 102, 102));
client << chart.render();
}
client << "<p>24. 多项式回归图 - 二次曲线</p>";
{
SvgRegressionChart chart(800, 500);
chart.setTitle("Polynomial Regression - Quadratic");
chart.setData({{0, 2.1}, {1, 7.7}, {2, 13.6}, {3, 27.2}, {4, 40.9}, {5, 61.1}, {6, 82.3}, {7, 108.5}, {8, 138.2}, {9, 170.0}});
chart.setMethod(LinearRegression::POLYNOMIAL);
chart.setPolynomialOrder(2);
chart.setPointColor(SvgColor(154, 96, 180));
chart.setLineColor(SvgColor(238, 102, 102));
client << chart.render();
}
client << "<p>25. 聚类散点图 - 客户分群 (3 类)</p>";
{
SvgClusteringChart chart(800, 500);
chart.setTitle("K-Means Clustering - Customer Segmentation");
chart.setData({{2, 1}, {3, 2}, {2.5, 1.5}, {4, 3}, {3.5, 2.5}, {1.5, 1}, {2, 2.5}, {3, 1.5}, {12, 8}, {15, 10}, {14, 7}, {13, 9}, {16, 11}, {11, 8}, {15, 8.5}, {14, 10}, {45, 25}, {50, 30}, {48, 28}, {52, 32}, {55, 30}, {47, 26}, {50, 27}, {53, 31}});
chart.setClusterCount(3);
chart.setPointSize(7);
chart.setCentroidSize(12);
client << chart.render();
}
client << "<p>26. 聚类散点图 - 4 类</p>";
{
SvgClusteringChart chart(800, 500);
chart.setTitle("K-Means Clustering - 4 Clusters");
chart.setData({{5, 5}, {6, 4}, {4, 6}, {5, 7}, {6, 5}, {7, 4}, {4, 5}, {5, 25}, {6, 26}, {4, 24}, {5, 27}, {7, 25}, {6, 24}, {4, 26}, {25, 5}, {26, 4}, {24, 6}, {25, 7}, {27, 5}, {26, 6}, {24, 5}, {25, 25}, {26, 26}, {24, 24}, {25, 27}, {27, 25}, {26, 24}, {24, 26}});
chart.setClusterCount(4);
chart.setPointSize(7);
chart.setCentroidSize(12);
client << chart.render();
}
client << "<p>27. 多元线性回归 - 房价预测(面积+卧室数+房龄)</p>";
{
SvgRegressionChart chart(800, 500);
chart.setTitle("Multivariate Linear Regression - House Price");
chart.setData({{60, 2, 20, 180},
{80, 2, 15, 230},
{100, 3, 10, 310},
{120, 3, 8, 360},
{140, 3, 5, 420},
{160, 4, 15, 440},
{180, 4, 12, 500},
{200, 4, 10, 560},
{90, 2, 25, 200},
{110, 3, 18, 290},
{130, 3, 20, 340},
{150, 4, 8, 430},
{170, 4, 6, 490},
{190, 4, 5, 530},
{70, 2, 30, 160},
{85, 3, 22, 250},
{105, 3, 12, 320},
{125, 3, 7, 380},
{145, 4, 10, 410},
{165, 4, 8, 470}});
chart.setMethod(LinearRegression::MULTIVARIATE_LINEAR);
chart.setPointColor(SvgColor(84, 112, 198));
chart.setLineColor(SvgColor(238, 102, 102));
chart.setPointSize(6);
client << chart.render();
}
client << "<p>All SVG stats tests completed!</p>";
#else
client << "<p>Please: cmake .. -DENABLE_CHART=ON </p>";
#endif// ENABLE_CHART
return "";
}
4 添加pzword html转word(docx格式) word(docx格式)到html, 支持文字颜色 大小 表格和图片简单核心功能读写
#include "httppeer.h" #include "serverconfig.h" #include "server_localvar.h" #include "test_pzword.h" #include "func.h" #include <memory> #include <string> #ifdef ENABLE_OFFICE #include "pz_word.h" #endif// ENABLE_OFFICE namespace http { //@urlpath(null,test_pzword) std::string test_pzword(std::shared_ptr<httppeer> peer) { httppeer &client = peer->get_peer(); #ifdef ENABLE_OFFICE server_loaclvar &static_server_var = get_server_global_var(); if (static_server_var.config_path.size() < 5) { client << "<p> static_server_var.config_path empty </p>"; return ""; } std::string file_conf = dir_name(static_server_var.config_path); if (file_conf.size() > 0 && file_conf.back() != '/') { file_conf.push_back('/'); } file_conf.append("docs/"); std::string zipfile; zipfile = file_conf + "ww.docx"; client << "<p>=== Reading " << zipfile << " ===</p></p>"; pz::word pzw; if (!pzw.read(zipfile)) { client << "Read error: " << pzw.error_msg; client << "Trying to read from unzipped directory..."; if (!pzw.read_from_unzipped(".")) { client << "Read from unzipped error: " << pzw.error_msg; return ""; } else { client << "Read from unzipped directory success"; } } else { client << "Read from docx file success"; } std::string html = pzw.to_html(); std::ofstream html_file(file_conf + "word.html"); if (html_file) { html_file << html; html_file.close(); client << "\n=== HTML saved to word.html ==="; } else { client << "Error: Unable to write word.html"; } pz::word pzww; if (!pzww.read_html(file_conf + "word.html")) { client << "Read HTML error: " << pzww.error_msg; return ""; } if (!pzww.write(file_conf + "www.docx")) { client << "Write DOCX error: " << pzww.error_msg; return ""; } client << "<p>Successfully wrote www.docx</p>"; client << html; #else client << "<p>Please: cmake .. -DENABLE_OFFICE=ON </p>"; #endif// ENABLE_OFFICE return ""; } }// namespace http
5 支持验证码和图片绘文字功能
6 支持SSE 收发,目前可以使用deepseek api
7 添加zip文件 压缩和解压
8 添加新的admin后台,目前是演示,以后慢慢使用新的后台
更多可以看官方地址
https://github.com/hggq/paozhu

浙公网安备 33010602011771号