先上图
!
如何实现
1.板子发送post请求。stable diffusion webui 这边图片默认是512\\_512 .板子内存有限。需要flask 接收图片后进行一次缩放到240\\_240.(未填充满,板子资源太紧张了)
ps。都在本地。webui可以部署到云服务器。
2.webui 使用lora 调整图片风格,还有 lcm 加快出图速度。正常是20step 出图,加上lcm 可以4-6step 出图
python webui.py --port 8903 --xformers --share --device-id 1 --api --listen
3.flask 服务器中转调用webui time curl -X POST http://10.162.88.10:5000/post -H "Content-Type: application/json" -d '{"prompt":"dog"}'
单3090显卡 4G 显存占用出图时间0.5s
聆思大模型AI开发套件
开发环境搭建
安装lisa工具包
wget -qO- https://cdn.iflyos.cn/public/cskTools/lisa-zephyr-install-v2.sh | bash
lisa info zephyr
下载源码
git clone --branch v1.6.0 https://cloud.listenai.com/CSKG962172/duomotai\\\_ap.git
初始化
lisa zep init-app
lisa zep update
编译工程
lisa zep build -b csk6\\\_duomotai\\\_devkit apps\LLM\\\_control -p
板子下载程序
lisa zep exec cskburn -s .\COM54 -C 6 -b 1500000 0x000000 Z:\06\\\_iot\07\\\_lisa\duomotai\\\_ap\build\zephyr\zephyr.bin
总体评价 简洁,快速,多平台,点赞。。
使用linux gpu 服务器编译。然后windows samba服务下载。
代码修改
1.使用串口触发post请求
\\\`
static void cmd\\\_aigc\\\_sdwebui(const struct shell shell, size\\\_t argc, char *argv)
{
if(argc != 2 || argv == NULL){
LOG_ERR("cmd_aigc_sdwebui error, argc = %d, argv = %p", argc, argv);
return;
}
char *prompt = argv[1];
LOG_INF("YYJJ cmd_aigc_sdwebui = %s", prompt);
int ret = 0;
uint8_t *out_data = NULL;
int out_len = 0;
//char png_download_url[256] = "http://10.162.88.10:5000/output/dog_20240319153542.png";
char png_download_url[256];
int ret = app_aigc_post("http://10.162.88.10:5000/post", prompt, &png_download_url);
if(ret == 0)
{
uint8_t *out_data = NULL;
int out_len = 0;
int ret = app_download(png_download_url, &out_data, &out_len);
if(ret != 0){
LOG_ERR("app download failed: %d", ret);
}else{
LOG_INF("app download succeeded: addr: %p, len: %d", (void *)out_data, out_len);
if((out_len != 0) && (out_data != NULL)){
ui_set_img(out_data, out_len);
csk_free(out_data);
}
}
}
}
#define AIGC_SD_PROMPT_TEXT "<wifi> aigc sd prompt text"
SHELL_STATIC_SUBCMD_SET_CREATE(sub_wifi,
SHELL_CMD_ARG(connect, NULL, WIFI_CONNECT_TEXT, cmd_wifi_connect, 3, 0),
SHELL_CMD_ARG(disconnect, NULL, WIFI_DISCONNECT_TEXT, cmd_wifi_disconnect,1, 0),
SHELL_CMD_ARG(add, NULL, WIFI_ADD_TEXT, cmd_wifi_add, 3, 0),
SHELL_CMD_ARG(delete, NULL, WIFI_DELETE_TEXT, cmd_wifi_delete, 2, 0),
SHELL_CMD_ARG(list, NULL, WIFI_LIST_TEXT, cmd_wifi_list, 1, 0),
SHELL_CMD_ARG(aigc, NULL, AIGC_SD_PROMPT_TEXT, cmd_aigc_sdwebui, 2, 0),
SHELL_SUBCMD_SET_END
);~~~~
`
2.获取下载地址
`int parse_json_response(const char *response_buf, char **aigc_url) {
// 参数校验
if (response_buf == NULL || aigc_url == NULL) {
return -1; // 无效参数
}
// 解析JSON
cJSON *json = cJSON_Parse(response_buf);
if (json == NULL) {
const char *error_ptr = cJSON_GetErrorPtr();
if (error_ptr != NULL) {
fprintf(stderr, "Error before: %s\n", error_ptr);
}
return -1; // 解析失败
}
cJSON *file_url = cJSON_GetObjectItemCaseSensitive(json, "file_url");
if (cJSON_IsString(file_url) && (file_url->valuestring != NULL)) {
*aigc_url = strdup(file_url->valuestring);
cJSON_Delete(json);
return 0;
} else {
cJSON_Delete(json);
return -1;
}
}
int app_aigc_post(const char *url, char * prompt , uint8_t **aigc_url)
{
int ret = 0;
int client_socket = -1;
if(url == NULL){
LOG_ERR("%s: %d", __FUNCTION__, __LINE__);
return -1;
}
ret = http_parse_url(&http_client, url);
if(ret < 0){
LOG_ERR("%s: %d", __FUNCTION__, __LINE__);
return ret;
}
client_socket = connect_socket(http_client.host, http_client.port);
if(client_socket < 0){
LOG_ERR("%s: %d", __FUNCTION__, __LINE__);
ret = client_socket;
goto failed;
}
char req_buf[128] = "{\"prompt\":\" dog \"}"; // 根据需要修改负载
scanf(req_buf,"{\"prompt\":\" %s \"}",prompt);
size_t req_buf_len = strlen(req_buf);
LOG_INF("Start Post");
char *response_buf = csk_malloc(MAX_IAMGE_SIZE);
if(!req_buf){
LOG_ERR("%s: %d", __FUNCTION__, __LINE__);
close(client_socket);
ret = -1;
goto failed;
}
struct http_request req = {
.method = HTTP_POST,
.url = "/post", // Flask定义的路径
.host = "10.162.88.10",
.protocol = "HTTP/1.1",
.header_fields = (const char *[]){"Content-Type", "application/json", NULL},
.response = response_aigc_cb,
.recv_buf = response_buf,
.recv_buf_len = MAX_IAMGE_SIZE,
.payload = req_buf,
.payload_len = req_buf_len,
};
ret = http_client_req(client_socket, &req, 5000, "IPv4 POST");
if(ret < 0){
LOG_ERR("%s: %d", __FUNCTION__, __LINE__);
}
close(client_socket);
ret = k_sem_take(&http_rsp_sem, K_SECONDS(10));
if(ret != 0){
LOG_ERR("get image timeout: %d", ret);
goto closed;
}
parse_json_response(response_buf, aigc_url);
closed:
if(response_buf) csk_free(response_buf);
failed:
if(http_client.scheme) csk_free(http_client.scheme);
if(http_client.host) csk_free(http_client.host);
if(http_client.path) csk_free(http_client.path);
memset(&http_client, 0, sizeof(http_client_handle_t));
return ret;
}
`
3.下载并且显示
`
int ret = app_download(png_download_url, &out_data, &out_len);
if(ret != 0){
LOG_ERR("app download failed: %d", ret);
}else{
LOG_INF("app download succeeded: addr: %p, len: %d", (void *)out_data, out_len);
if((out_len != 0) && (out_data != NULL)){
ui_set_img(out_data, out_len);
csk_free(out_data);
}
}
`
\\`\\`
\\`
中间框架 flask
stable diffusion webui 接口
post 和get 方法。
代码较少。直接全部贴源码
\`
from flask import Flask, request, jsonify, url\_for
import datetime
import base64
import os
import requests
import json
from PIL import Image
import io
app = Flask(\_\_name\_\_)
from flask import send\_from\_directory
def save\_encoded\_image(b64\_image: str, output\_path: str):
"""
Save the given image to the given output path.
:param b64_image: base64 encoded image
:param output_path: output path
:return: None
"""
# 判断当前目录下是否存在 output 文件夹,如果不存在则创建
if not os.path.exists("output"):
os.mkdir("output")
timestamp = datetime.datetime.now().strftime("%Y%m%d%H%M%S")
output_path = f"{output_path[0:5]}_{timestamp}" + ".png"
# 将文件放入当前目录下的 output 文件夹中
output_path = f"output/{output_path}"
# Decode the base64 image
image_data = base64.b64decode(b64_image)
image = Image.open(io.BytesIO(image_data))
# Resize the image
image = image.resize((240, 240), Image.ANTIALIAS)
# Save the resized image
image.save(output_path)
print(output_path)
return output_path
def webui\_txt2img(prompt='dog'):
txt2img_url = "http://10.162.89.10:8903/sdapi/v1/txt2img" # 服务器地址
prompt_lora_lcm = prompt + r", <lora:PixelStyle:1>,<lora:pytorch_lora_weights:1>"
data = {
'prompt': prompt_lora_lcm,
'negative_prompt': '',
"sampler_index": "LCM",
'width': 512,
'height': 512,
"steps": 6,
"cfg_scale": 1.5,
}
print(data)
response = requests.post(txt2img_url, data=json.dumps(data))
image_path = save_encoded_image(response.json()['images'][0], prompt)
return image_path
@app.route('/post', methods=['POST'])
def handle\_post():
data = request.json
print(data)
if not data or 'prompt' not in data:
return jsonify({"error": "Missing 'prompt' field"}), 400
prompt = data['prompt']
print(f"Received prompt: {prompt}")
image_file_name = webui_txt2img(prompt)
root_url = request.url_root.rstrip('/') # 移除尾部的斜杠(如果有的话)
file_url = f'{root_url}/{image_file_name}'
return jsonify({"file_url": file_url})
@app.route('/output/<path:filename>')
def custom\_static(filename):
return send_from_directory('output', filename)
if name == '\_\_main\_\_':
app.run(host='0.0.0.0', port=5000, debug=True)
\`
!
总结
上手体验快。同级别芯片对比乐鑫只有不好用的chatgpt。总体来说资源太紧了,建议加大psram。
后续弄一下LVGL,添加chagpt,完成lvgl,然后语音转文字,tts。然后开源出来。。