跳转:项目文档&研究日志




当你在用AI生成代码、方案或内容时,是否常遇到这样的场景:
你写了一长串需求,AI却给出了完全跑偏的答案;
你反复修改提示词,但生成结果始终“差点意思”;
你觉得自己说清楚了,但AI理解的是另一个版本……这不是AI不够聪明,而是你的需求还不够“结构化”。
ClarityAI 正是为此而生——它通过多轮智能问答,帮你把零散的想法梳理成一份逻辑清晰、细节完备的需求报告,让下游任何AI都能精准理解你的意图。
我在自己的服务器上部署了后端,可以直接访问使用:链接直达ClarityAI
由于资金有限,我设置了单日token使用限额,如达到限额,请在“设置”中填写自己的API BaseURL和API-Key
[photos]

[/photos]
我们正处在AI应用爆发期,从代码生成、文案创作到产品设计,人人都想借助AI提高效率。但一个普遍存在的误区是:我们常常高估了自己表达需求的能力,也低估了AI准确理解模糊语言的门槛。
结果就是:AI输出的内容不符合预期 → 反复修改提示词 → 耗费大量时间 → 最终可能还是手动重写。这不是AI能力不行,而是我们缺少一个把模糊需求转化为精确指令的中间层。
ClarityAI 的角色就是这一中间层。它不直接生成最终产品,而是通过系统化提问,引导你一步步补充功能边界、技术约束、用户场景、优先级等关键信息,最终输出一份结构化的需求报告。这份报告可以直接喂给任何下游AI(如ChatGPT、Claude、Copilot、Midjourney等),让它们基于完整的上下文给出更贴合你初衷的结果。
ClarityAI 的核心价值不是替代AI,而是增强你与AI之间的沟通效率。它像一位专业的需求分析师,帮你把脑子里“一团乱麻”的想法梳理成清晰条理的需求文档。
项目采用前后端分离架构,代码仓库分置,便于独立部署和扩展。
基于 Vue 3 + Vite + Element Plus,注重交互流畅性和界面清晰度:
markdown-it,结果页清晰展示报告基于 Flask 3.0.3,提供RESTful API,并集成Qwen(通义千问)或OpenAI作为智能引擎:
主要API端点:
GET /api/health # 服务状态
POST /api/generate-questions # 根据初始想法生成问卷
GET /api/session/<id> # 获取会话所有数据
POST /api/submit-answers # 提交当前轮答案
POST /api/continue-with-feedback # 继续追问细化
POST /api/generate-pdf # 生成PDF报告
GET /api/download-pdf/<id> # 下载PDF
DELETE /api/session/<id> # 删除会话
在首页输入框中写下你最粗颗粒的想法,哪怕只有一句话也可以。例如:“我想做一个在线教育平台”。
后端AI会根据你的输入,自动生成一组结构清晰的问题,可能会根据你的想法涵盖:
所有问答完成后,后端会自动汇总所有信息,生成一份结构化的Markdown报告。报告包含以下典型章节:
# 后端
git clone https://github.com/kazuky233/ClarityAI-Backend.git
cd ClarityAI-Backend
python -m venv .venv
source .venv/bin/activate # Windows: .venv\Scripts\activate
pip install -r requirements.txt
# 配置 .env 文件,填写 QWEN_API_KEY(或 OPENAI_API_KEY)
python run.py
# 前端
git clone https://github.com/kazuky233/ClarityAI-Frontend.git
cd ClarityAI-Frontend
npm i
npm run dev
访问 http://localhost:5173 即可体验。
ClarityAI 不试图替代任何AI,而是为AI“指路”。在AI能力日益强大的今天,清晰的输入比复杂的提示词技巧更重要。通过将模糊想法转化为结构化需求,ClarityAI 让你与任何下游AI的对话都变得更高效、更精准。
如果你也曾因需求没说清楚而让AI“翻车”,不妨试试 ClarityAI。欢迎访问GitHub仓库,点个Star,也期待你的Issue!
当前无线 Mesh 网络普遍存在“信号强却连接不稳定”的问题。传统 Zigbee、WIFI Mesh 等协议依赖单一信号强度因素进行路由选择,无法全面感知链路丢包率、物理遮挡及节点负载等关键因素。一旦遭遇墙体遮挡、人员移动等动态干扰,网络容易中断,不能适应变化/复杂的环境,难以满足特殊环境下的通信需求。
本项目改变了传统单一因素决策模式,搭建“AI 智能决策”架构。通过将随机森林算法部署至 ESP32-C6 芯片,赋予每个节点独立决策的能力,无需云端参与。系统融合信号质量、链路跳数、节点负载、链路稳定性等多维特征,实现从“被动连接”到“主动优化”的跨越,确保在复杂多变环境下网络依然稳健、高效、可自愈。
本项目构建了一种基于 AI 算法的自适应路由优化系统。
通过 OMNet++无线网络物理仿真软件构建含有若干墙体与通信节点的场景,获得了 6959 条仿真训练数据。之后,采用随机森林算法拟合训练集数据,得出了拟合效果较好的数学模型。
该模型可用函数近似表示(f 由随机森林近似):
$$DeliveryRatio = f(RSSI, Hop, Child, Loss)$$
研究后,将得到的预测算法部署至 ESP32-C6 单片机并进行实验,结果表明本文得出的模型在选择上级节点时能够更好地兼顾信号强度、链路跳数、节点负载等信息进而选择综合质量更优的节点进行组网。
该算法能够应用于大型复杂环境的快速组网部署等场景,具有一定的实用前景。
突破传统仅依赖信号强度的路由方式,综合 RSSI、传输距离、链路质量、能耗等多维特征,提升路径决策准确性。
每个 ESP32-C6 为一个独立的单元,单元之间彼此通信协商,通过训练的决策模型综合多方面实际数据推算节点质量指标,最终能够形成最优的拓补网络。
组网后,不论是 ESP32(C6/S3/C3/8266),还是手机、平板、电脑,都可以通过这些节点进行网络访问。此时这些节点起到了网络中继路由作用。
通过 OMNeT++无线物理仿真工具采集数据,使用随机森林训练路由选择模型,决定系数:
$$\mathrm{R}^2 = 0.965047, \mathrm{MSE} = 0.001571$$
实现高精度路径质量预测。
[photos]



[/photos]
将模型部署到 ESP32-C6 节点,实现本地实时推理,无需云端参与,提升模型决策响应速度与便捷性。
将采用 3D 建模打印技术设计终端外壳,集成锂电池与充放电模块,通过将各个部件焊接到设计并打样的 PCB 电路板上,实现电路集成。
[photos]



[/photos]
结合 Python Flask 框架搭建服务端(后端),并将服务端通过 Docker 容器化部署于 Linux 云服务器(Debian-12.0),通过 Vue.JS 编写前端页面,实现网络拓补结构及节点信息的实时监控。
[photos]


[/photos]


对比图解 1,2:该创新方案优势明显,由于结合了训练的 AI 模型,在多变环境下本项目拥有自适应环境、自动优化网络拓补结构的能力,具备更强的适应性、灵活性、预见性。
现状:
当前无线 Mesh 网络普遍存在“信号强却不稳定”的现象。
问题所在:
传统协议依赖单一信号强度进行路由选择,无法全面感知链路丢包率、物理遮挡及节点负载等关键因素。
研究目标:
搭建稳健、高效、可自愈的智能 Mesh 网络体系。
选用 OMNet++ 无线网络物理仿真软件构建场景。
仿真逻辑基于以下假设:
$$PL = PL_0 + 10n \log_{10}\left(\frac{d}{d_0}\right) + N_{\text{wall}} \cdot A_{\text{wall}}$$
基于以上假设:
使用 C++ 编写仿真逻辑,包括随机环境生成(网关、终端、中继节点与墙体位置)、终端到各中继及中继到网关路径的 RSSI 与跳数计算、子设备负载对链路成功率的影响、中继概率丢包、统计仿真发数据包可达率,以及 CSV 结果输出(RSSI、跳数、子设备数、节点到网关丢包率、可达率)
数据共包含 6959 条记录,每条记录由 5 个字段组成:
随机划分数据中 20% 为测试集,另外 80% 为训练集。
利用 Python 中 scikit-learn 库,分别构建线性回归、多项式回归和随机森林算法。
$$\mathrm{R}^2 = 0.622295, \mathrm{MSE} = 0.016977$$
拟合效果较弱,特征数据与标签数据线性关系不明显。
[photos]


[/photos]
$$\mathrm{R}^2 = 0.836970, \mathrm{MSE} = 0.007328$$
根据图像得出拟合效果略优于线性回归,但在真实值较小处预测出现了负值,模型存在过拟合现象。
[photos]


[/photos]
$$\mathrm{R}^2 = 0.965047, \mathrm{MSE} = 0.001571$$
由于特征与标签之间存在非线性关系,且样本中存在噪声,经分析该算法是符合要求的预测方式。
[photos]


[/photos]
核心:
选定 ESP32-C6 单片机作为核心控制单元。将训练好的预测算法部署至 ESP32-C6 节点。完善基本逻辑。
结构:
采用 3D 建模打印技术设计终端外壳。完成 PCB 电路板设计与打样。
功能:
集成锂电池与充放电模块,开关,OLED 屏幕。
组网能力:
每个 ESP32-C6 为独立单元,彼此通信协商,形成最优拓扑网络。
兼容 ESP32 系列(C6/S3/C3/8266)及手机、平板、电脑等终端接入。
[photos]



[/photos]
后端:
结合 Python Flask 框架搭建服务端。
通过 Docker 容器化部署于 Linux 云服务器(Debian-12.0)。
前端:
使用 Vue.JS 编写前端页面。
实现了网络拓扑结构及节点信息的实时监控(包括节点编号、子设备数、丢包率、RSSI 等数据展示)。
后端日志可实时记录数据接收情况(如 POST /api/data 请求处理)。
[photos]


[/photos]
整理各部分程序,查找并修复逻辑和细节错误,优化系统,同时增加一些有意义的功能。
一套覆盖用户APP、智能车锁、管理后台的完整共享单车解决方案,技术栈全面,实测抗压 89.7 次/秒
为了参加2025全国青少年信息素养大赛总决赛,我们按照给定题目要求完成了基本开关锁功能,但为了更贴近生活、做成完整成熟的产品,我们开发了更多分支及创新功能,包括但不限于:GPS定位、事故检测报警、车辆故障上报、车辆数据集群管理、后台管理大屏、以用户为单位的数据管理、行程数据记录展示。涵盖用户端APP、嵌入式智能锁、后台管理系统以及API服务。
本文将深入解析这套系统的技术架构与实现亮点。
|——|——–|——|
| 我(XHL) | 服务器运维、前后端搭建、APP、全部软件部分等 | 个人网站
| The Sandy | 车锁3D结构设计与打印、硬件结构构建、协助完成ESP32程序开发等 | 个人网站
项目三层架构:
| 层级 | 技术栈 | 功能 |
|---|---|---|
| 客户端 | Vue + Android + 高德地图 SDK | 地图展示、扫码开锁、行程记录、用户中心 |
| 单车端 | MicroPython + ESP32 + GPS/MPU6050 | 定位上报、姿态检测、开锁执行 |
| API 服务 | Python Flask | 业务逻辑处理、数据接口 |
| 数据层 | MySQL + 连接池 | 数据存储 |
| 基础设施 | Docker + Nginx + Debian | 容器化部署、负载均衡 |
[photos]


[/photos]
服务端基于 Python Flask 开发,数据库方面我自己封装了 SQL 类
from dbutils.pooled_db import PooledDB
class SQL:
def __init__(self, db_address, db_username, db_passwd, db_name):
self.pool = PooledDB(
creator=pymysql,
maxconnections=10,
host=db_address,
user=db_username,
password=db_passwd,
database=db_name
)
实测数据:系统可承受约 89次/秒 的数据请求,在网络攻击测试中服务端从未崩溃。
所有 API 请求都会通过 server_log() 函数记录到数据库,日志类型分为:
事故报警和防盗报警会通过钉钉机器人实时推送:
[photos]

[/photos]
[photos]

[/photos]
建模设计与3D打印部分由The Sandy完成(个人网站)
外壳经历了五代迭代:
| 版本 | 材料 | 改进点 |
|---|---|---|
| 初代 | PLA | 验证基础结构可行性 |
| 二代 | PLA | 优化润滑油方案 |
| 三代 | PLA | 固定方案优化 |
| 四代 | PETG-CF | 强度大幅提升 |
| 四+代 | PETG-CF + PETG 开窗 | 解决 GPS 信号屏蔽问题 |
技术细节:碳纤维增强 PETG 会屏蔽 GPS 信号,因此天线区域专门采用 PETG 开窗设计。
使用 MPU6050 六轴传感器实时检测车辆姿态。当检测到异常冲击(如摔车),系统会:
/bike/accident 接口太阳能板 → 充电IC → 7.4V锂电池
↓
DC-DC降压 → 5.06V → ESP32
↓
继电器直连 → 电磁铁(大电流)

后台采用 Vue3 + ECharts + 高德地图API 构建,功能包括:
| 接口 | 路径 | 说明 |
|---|---|---|
| 用户登录 | POST /client/login | 返回昵称和状态 |
| 附近单车 | POST /client/nearby | 经纬度范围查询 |
| 解锁单车 | POST /client/unlock | 创建骑行记录 |
| 获取记录 | POST /client/getrecord | 历史订单 |
| 接口 | 路径 | 说明 |
|---|---|---|
| 状态检查 | POST /bike/check | 返回 lock/unlock |
| 位置更新 | POST /bike/update | 实时上报轨迹 |
| 事故报警 | POST /bike/accident | 触发钉钉推送 |
后台接口统一验证 Token:
{"token": "AABBCC"}
项目采用 Docker 容器化部署,运行在云服务器上:
欢迎技术交流。如需完整源代码与硬件文件,请联系
2024 年湖北的夏天格外难熬,家里空调制冷效果奇差,基本形同虚设。
一番折腾后,通过 控制变量法 逐项排查,最终锁定真凶——外机背板散热不畅(被柜板挡住,热量排不出去)。
临时想到的解决方案简单粗暴:用水泵朝外机喷水,强制降温。

TB 采购水泵、继电器等模块,接通电源,能跑起来,第一步成功!
手动开关不仅麻烦,人不在家时要么干烧要么浪费水。
我开始思考如何让系统根据温度自动启停。
忽然想起去年做火箭姿态矫正时留下的 MPU6050 六轴传感器,它内部集成了一颗 NTC 温度模块。
虽然原本是用来检测芯片温度的,但 MPU6050 自身发热极小,完全可以近似看作环境温度。
于是把它从火箭上“拆借”过来,搭配 ESP32-C3 实现温控。
MPU6050 与 ESP32-C3 的接线非常简单(左:MPU6050,右:ESP32-C3):
| MPU6050 | ESP32-C3 |
|---|---|
| VCC | 3V3 |
| GND | GND |
| SDA | P8 (SDA) |
| SCL | P9 (SCL) |

开发环境:Arduino IDE
核心思路:ESP32-C3 启动一个轻量 Web 服务器,手机或电脑连上后即可看到实时温度与浇水状态,并可通过按钮手动控制或开启自动化。
主要功能:
/ 返回控制页面/dht 接口返回传感器数据(实时温度、浇水状态、自动状态)/set 接口切换浇水开关(同时关闭自动模式)/auto 接口切换自动模式以下为完整代码:
#include <Adafruit_MPU6050.h>
#include <Adafruit_Sensor.h>
#include <WiFi.h>
#include <ESPAsyncWebServer.h>
AsyncWebServer server(80); // 端口80,可直接通过IP访问
// 网页 HTML(存储于 Flash)
const char index_html[] PROGMEM = R"rawliteral(
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<title>空调浇水控制</title>
</head>
<body>
<h2>空调浇水控制</h2>
<div id="dht"></div>
<button onclick="set()">开启/关闭浇水</button>
<button onclick="autoset()">开启/关闭自动</button>
</body>
<script>
function set() {
var xhr = new XMLHttpRequest();
xhr.open("GET", "/set?value=ESP32", true);
xhr.send();
}
function autoset() {
var xhr = new XMLHttpRequest();
xhr.open("GET", "/auto?value=ESP32", true);
xhr.send();
}
// 每秒更新一次数据
setInterval(function () {
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function () {
if (this.readyState == 4 && this.status == 200) {
document.getElementById("dht").innerHTML = this.responseText;
}
};
xhttp.open("GET", "/dht", true);
xhttp.send();
}, 1000);
</script>
</html>
)rawliteral";
Adafruit_MPU6050 mpu;
#define MPU6050_INTERVAL 100 // 传感器读取间隔(毫秒)
unsigned long mpu6050Times = 0;
float mpu6050Temp = 0;
float xAcceleration, yAcceleration, zAcceleration;
float xAccele, yAccele, zAccele;
float xGyro = 0, yGyro = 0, zGyro = 0;
float gravity = 9.8;
bool iswater = false; // 浇水状态
bool isauto = true; // 自动模式默认开启
// 构造返回给网页的 HTML 数据
String Merge_Data(void) {
String dataBuffer = "<p>";
dataBuffer += "<h1>传感器数据</h1>";
dataBuffer += "<b>温度: </b>";
dataBuffer += String(mpu6050Temp, 1) + " ℃";
dataBuffer += "<br />";
dataBuffer += "<b>当前浇水状态: </b>";
dataBuffer += iswater ? "开启" : "关闭";
dataBuffer += "<br />";
dataBuffer += "<b>当前自动状态: </b>";
dataBuffer += isauto ? "开启" : "关闭";
dataBuffer += "<br /></p>";
return dataBuffer;
}
// 手动切换浇水(同时关闭自动模式)
void Config_Callback(AsyncWebServerRequest *request) {
iswater = !iswater;
isauto = false;
request->send(200, "text/plain", "OK");
}
// 切换自动模式
void Auto_Callback(AsyncWebServerRequest *request) {
isauto = !isauto;
request->send(200, "text/plain", "OK");
}
void setup() {
Serial.begin(115200);
// 连接 WiFi(请替换为实际 SSID 和密码)
WiFi.begin("你的WiFi名", "你的WiFi密码");
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.println("正在连接WiFi...");
}
Serial.println("WiFi 连接成功!");
Serial.print("IP 地址: ");
Serial.println(WiFi.localIP());
pinMode(1, OUTPUT); // GPIO1 控制继电器(水泵)
// 配置 Web 服务器路由
server.on("/", HTTP_GET, [](AsyncWebServerRequest *request) {
request->send_P(200, "text/html", index_html);
});
server.on("/dht", HTTP_GET, [](AsyncWebServerRequest *request) {
request->send_P(200, "text/plain", Merge_Data().c_str());
});
server.on("/set", HTTP_GET, Config_Callback);
server.on("/auto", HTTP_GET, Auto_Callback);
server.begin();
Serial.println("HTTP 服务器已启动");
// 初始化 MPU6050
if (!mpu.begin()) {
Serial.println("未找到 MPU6050 芯片!");
while (1) { delay(1000); } // 停止运行
}
mpu.setAccelerometerRange(MPU6050_RANGE_16_G);
mpu.setGyroRange(MPU6050_RANGE_250_DEG);
mpu.setFilterBandwidth(MPU6050_BAND_21_HZ);
Serial.println("MPU6050 初始化成功!");
}
void loop() {
getMpu6050Data(); // 读取温度及姿态数据
if (isauto) {
// 自动模式:根据温度控制水泵
if (mpu6050Temp >= 30.0) {
digitalWrite(1, HIGH);
iswater = true;
} else {
digitalWrite(1, LOW);
iswater = false;
}
} else {
// 手动模式:直接遵从按钮状态
digitalWrite(1, iswater ? HIGH : LOW);
}
}
void getMpu6050Data() {
if (millis() - mpu6050Times >= MPU6050_INTERVAL) {
mpu6050Times = millis();
sensors_event_t a, g, temp;
mpu.getEvent(&a, &g, &temp);
mpu6050Temp = temp.temperature;
xAcceleration = a.acceleration.x;
yAcceleration = a.acceleration.y;
zAcceleration = a.acceleration.z;
xAccele = xAcceleration / gravity; // 转换为 g 为单位
yAccele = yAcceleration / gravity;
zAccele = zAcceleration / gravity;
xGyro = g.gyro.x;
yGyro = g.gyro.y;
zGyro = g.gyro.z;
// 串口输出,便于调试(保留了姿态数据,方便后续扩展)
Serial.print("温度: "); Serial.print(mpu6050Temp);
Serial.print(" , x加速: "); Serial.print(xAccele);
Serial.print(" , y加速: "); Serial.print(yAccele);
Serial.print(" , z加速: "); Serial.print(zAccele);
Serial.print(" , x角速度: "); Serial.print(xGyro);
Serial.print(" , y角速度: "); Serial.print(yGyro);
Serial.print(" , z角速度: "); Serial.println(zGyro);
}
}
