博客 (54)

  1. 使 lua 支持 resty.http

  2. 在 access_by_lua_block 代码块中实现远程鉴权:

    #鉴权-START
    resolver 223.5.5.5;  # 使用公共 DNS
    access_by_lua_block {
        local http = require("resty.http")
        local httpc = http.new()
        httpc:set_timeout(500)  -- 连接超时
        local res, err = httpc:request_uri("https://鉴权地址/", {
            method = "GET",
            headers = {
                ["X-Real-IP"] = ngx.var.remote_addr,
                ["User-Agent"] = ngx.var.http_user_agent,
                ["X-Forwarded-Host"] = ngx.var.host,
                ["X-Forwarded-Uri"] = ngx.var.request_uri,
            },
            ssl_verify = false, -- 禁用 SSL 验证
            timeout = 500,     -- 读取超时
        })
    
        if not res then
            ngx.log(ngx.ERR, "Failed to request: " .. err)
        end
            
        if res and res.status == 403 then
            ngx.exit(ngx.HTTP_FORBIDDEN)
            -- return ngx.redirect("https://一个显示403友好信息的页面.html")
        end
    }
    #鉴权-END

    注意更改接口地址和友情显示 403 页面地址。

    本示例仅捕获 403 状态码,500、408 等其它异常情况视为允许访问,请根据业务需求自行添加状态码的判断。

    若超时也会进入 if not res then 代码块。

    建议将此代码部署在 nginx 主配置文件的 http 代码块中(宝塔面板中的路径:/www/server/nginx/nginx/conf/nginx.conf),如果你只想为单个网站鉴权,也可以放在网站配置文件的 server 块中。

  3. 若鉴权接口在私网中,建议将鉴权接口域名和私网 IP 添加到 hosts 文件中。


  1. 直接输出字符串

    ngx.header.content_type = "text/plain";
    ngx.say("hello world!")
  2. 输出到日志

    ngx.log(ngx.ERR, "Response status: " .. res.status)

    日志在网站的 站名.error.log 中查看。

    宝塔面板查看方式:日志 - 网站日志 - 异常

  3. 若想获取服务器 CPU 使用率等信息并传递给远程鉴权接口,请参考此文

  4. 常见问题

    no resolver defined to resolve

    原因:没有定义 DNS 解析器

    解决方法:在 http 块或 server 块中添加 resolver 8.8.8.8 valid=30s;,当然使用接入商自己的公共 DNS 可能更合适。

    unable to get local issuer certificate

    原因:没有配置 SSL 证书信息

    解决方法:添加 request_uri 参数:

    ssl_verify = true,  -- 启用 SSL 验证
    ssl_trusted_certificate = "证书路径",  -- 指定 CA 证书路径

    ssl_verify = false,  -- 禁用 SSL 验证
  5. 若您不想用 lua,可以用 nginx 原生自带的  auth_request 模块来实现

xoyozo 6 天前
115

鉴权方式有许多,譬如可以用 lua 的 access_by_lua 来实现,这里用 nginx 自带的 auth_request,虽然功能简单,但效率更高。

第一步,确保 nginx 已编译安装 auth_request 模块,见此文

第二步,打开需要鉴权的网站的 nginx 配置文件,添加以下代码块:

    #鉴权-START
    location / {
        auth_request /auth;
        error_page 403 = @error403;
        
        #PHP-INFO-START  PHP引用配置,可以注释或修改
        include enable-php-**.conf;
        #PHP-INFO-END
    }
    location = /auth {
        internal;
        proxy_pass https://鉴权地址;
        proxy_pass_request_body off;
        proxy_set_header Content-Length "";
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header User-Agent $http_user_agent;
        proxy_set_header X-Forwarded-Host $host;
        proxy_set_header X-Forwarded-Uri $request_uri;
        proxy_intercept_errors on;
        #proxy_read_timeout 1s; # 超时会报 500
    }
    location @error403 {
        #default_type text/plain;
        #return 403 'forbidden';
        return 302 https://一个显示403友好信息的页面.html;
    }
    #鉴权-END

一般放在所有的 location 之前。

这里自定义请求头 X-Forwarded-HostX-Forwarded-Uri 用来传递 host 与 uri。API 应从 Header 中相应取值。

宝塔面板中是通过 include enable-php-**.conf; 的方式调用 PHP ,那么可以将此行移入上面的 location / 代码块中,因为此代码块能匹配所有的请求路径。

最后,若鉴权接口在私网中,将鉴权接口域名和私网 IP 添加到 hosts 文件中。

xoyozo 10 天前
113

本文记录于 2024 年 11 月。



升级前期望(最新正式版)最终选择
操作系统Alibaba Cloud Linux 3Alibaba Cloud Linux 3Alibaba Cloud Linux 3
管理面板宝塔面板 Linux 版 9.2.0宝塔面板 Linux 版 9.2.0宝塔面板 Linux 版 9.2.0
Web 服务nginx 1.24nginx 1.24nginx 1.24
脚本语言PHP 7.4PHP 8.2PHP 8.2
数据库
PolarDB MySQL 5.6RDS MySQL 9.1PolarDB MySQL 8.0
论坛程序
Discuz! X3.4 GBKDiscuz! X5.0Discuz! X3.5 UTF8


版本选择原因:

  • Discuz! X5 刚刚发布,生态尚未成熟,考虑到是老论坛升级,所以选择 X3.5。

  • Discuz! X3.5 目前最高支持 PHP 8.2、MySQL 8.0。


完整升级步骤:

  1. 购买新的 ECS、PolarDB,具体环境配置步骤参此文

  2. 安装宝塔面板并配置;

  3. 安装 nginx 及 PHP;

  4. 创建网站、配置 SSL、伪静态、防盗链、可写目录禁执行仅允许部分入口文件执行等(.conf);

  5. 配置 hosts;

  6. 如果是正式升级阶段,关闭论坛,防止产生新数据。

  7. 备份原网站程序、PolarDB 数据库;

  8. PolarDB 创建快照。

    测试阶段:从快照还原到新实例(MySQL 5.6 不能直接恢复到 MySQL 8.0),然后从 5.6 迁移到 8.0.x;

    正式阶段:全量模式直接从原实例迁移到 8.0.x,若增量模式且存在触发器,建议从快照还原;

  9. 上传原网站程序到新的站点目录下;

  10. 按 Discuz! X 升级文档升级 X3.4 至 X3.5;详情见下文 ↓;

  11. 升级完成后切换到 PHP 8;

  12. 配置 OSS、Redis、更新缓存等;

  13. 测试论坛基本功能是否正常;检查附件是否能够正常上传检查附件是否正常显示;全面检查控制台配置;

  14. 逐个开启插件并检查兼容性(短信通、马甲引擎等);

  15. 按二开备忘录逐个按需进行二开;

  16. 逐个修改调用论坛接口的项目及直接调用论坛数据库的项目;

  17. 调试 MAGAPP 接口;

  18. 尝试强制 https 访问;

  19. 将以上所有修改后的程序保留备份;发布升级公告并关闭论坛;重复以上步骤;修改域名解析;开启论坛;

  20. 配置 IP 封禁、定时器、日志、自动备份、配置其它 ECS 的 hosts 等;

  21. 查看搜索引擎中收录的地址,是否有无法访问的情况;

  22. 尝试将历史遗留的本地附件全部转移到 OSS;

  23. 建议 在新服上创建 3 个网站:

    1. 第 1 个用来尝试迁移、升级、二开,并测试所有功能

    2. 第 2 个用来再次重复这些步骤,最终保留程序代码及 UGC 文件,作为最终的网站程序,以正式域名作为网站根目录路径;

    3. 第 3 个用来正式升级,主要功能是升级最新数据库。完成后修改第 2 个网站的数据库连接指向到最新的数据库,差异化同步新增的 UGC 文件到第 2 个网站。


Discuz! X 升级步骤及注意点:

  • 因 PolarDB MySQL 不支持压缩,所以应移除 Discuz! 和 UCenter 代码中所有的 MYSQLI_CLIENT_COMPRESS,将 , MYSQLI_CLIENT_COMPRESS 替换为 /*, MYSQLI_CLIENT_COMPRESS*/

  • 升级前务必先修改 ./config/ 目录下的数据库/缓存连接信息,以防出现新站连接老库的情况;

  • 官方文档进行升级,升级前先修改一下:

  • 【UC】先升级 UCenter 1.6 至 1.7。

    将 /uc_server/data 权限改为 777 并递归。

    打开 update_ucenter_adult.php 修改 $limit 值为 10000 以免执行超时

    因通信失败的“发送通知失败”可以直接改 URL 参数跳过就完成了,原因可能是因数据量大,发送改名通知执行改名时超时。等DZ升级完成后UC会自动重试改名通知,或单独写个 php 文件将 UCenter 的用户名同步到应用的数据库。

  • 【DZ】运行到 /install/update_adult.php?step=innodb&table=pre_common_member_grouppm 时报错:Duplicate key name 'gpmid' ALTER TABLE common_member_grouppm ADD INDEX gpmid(gpmid);

    解决方法:先删除索引,因保存时提示失败,应同时取消 gpmid 字段的自增,转换成功后再设置自增。

  • 【DZ】运行到 /install/update_adult.php?step=file 一片空白而停止

    正在解决

  • 【问题】common_menber 表用户名字段编码转换失败

    原因是部分用户名包含特殊字符(如全角空格),用以下语句查看两个表同一 uid 的不同用户:

    SELECT 
        u.uid, 
        u.username AS ucenter_username, 
        c.username AS common_username
    FROM 
        pre_ucenter_members u
    JOIN 
        pre_common_member c ON u.uid = c.uid
    WHERE 
        u.username <> c.username

    Discuz! 用户登录都是以 UCenter 中的用户名为主,所以可以写个小程序直接将 pre_ucenter_members 的用户名同步到 pre_common_member 中,另外 pre_ucenter_members 的用户数少于 pre_common_member 是正常的。若 pre_common_member_archive 表遇到错误同理。

  • 如果用户登录慢,或打开 UCenter 慢,是因为 UC 正在通知 DZ 改用户名,每次打开一个页面会更改一个用户名,具体可以查看 pre_ucenter_notelist 中 closed 为 0 的队列,或进入 UC 后台-数据列表-通知列表 查看。

  • 【问题】发布主题遇到错误:(1062) Duplicate entry '*' for key 'pid'

    【原因】forum_post 中的 pid 不是自动增长的,而是由表 forum_post_tableid 中自动增长的 pid 生成的。如果生成的 pid 值已在 forum_post 表中存在,则会出现此错误。

  • 【解决】迁移数据库时应关闭论坛,以防止 forum_post 表有新数据插入。

  • 【问题】打开帖子页面 ./thread-***-1-1.html 显示 404 Not Found,而 ./forum.php?mod=viewthread&tid=*** 可以正常打开

    【原因】未配置伪静态(可在宝塔面板中选择)

  • 【问题】打开 UCenter 时报错:UCenter info: MySQL Query Error SQL:SELECT value FROM [Table]vars WHERE name='noteexists'

    【解决】打开文件 ./uc_server/data/config.inc.php 配置数据库连接

  • 【问题】打开登录 UCenter 后一片空白

    【解决】将目录 ./uc_server/data/ 设为可写

  • 需要将原来安装的插件文件移回 ./source/plugin/ 目录,并设置可写;

  • 界面-表情管理,界面-编辑器设置-Discuz!代码


后续 Discuz! X3.5 小版本升级注意事项:

  1. 确认插件是否支持新版本(如短信通)

  2. 先创建一个新网站测试二开代码

  3. 保留 /config/、/data/、/uc_client/data/、/uc_server/data/、/source/plugin/,其它移入 old

  4. 上传文件

  5. 移回其它需要的文件,如:

  6. -- 勋章/loading/logo/nv 等:/static/image/common/

  7. -- 表情:/static/image/smiley/

  8. -- 水印:/static/image/common/watermark.*

  9. -- 风格:/template/default/style/t2/nv.png 等

  10. -- 默认头像:/uc_server/images/noavatar_***.gif

  11. -- 根目录 favicon.ico 等

  12. -- 及其它非 DZ 文件

  13. 再次检查可写目录的写入权限和禁止运行 PHP 效果。


xoyozo 2 个月前
208

POST

$.post('AjaxCases', {
    following: true,
    success: null,
    page: 1,
}, function (response) {
    console.log(response.data)
}, 'json').fail(function (xhr, status, error) {
    console.log(xhr.responseText);
});
[HttpPost]
public IActionResult AjaxCases([FromForm] AjaxCasesRequestModel req)
{
    bool? following = req.following;
    bool? success = req.success;
    int page = req.page;
}

提示:只能传输对象(Object),不能传输数组(Array)。


相关:axios 请求 .NET Core / .NET 5 / .NET 6

xoyozo 6 个月前
850

因 MySQL 8 默认使用 utf8mb4 字符集,如果是从 MySQL 5-7 等低版本迁移的,那么仍然是 utf8(相当于 utf8mb3)。

这在保存字符串时有可能会报错:

An error occurred while saving the entity changes. See the inner exception for details.

Incorrect string value: '\xF0\xA1\x90\x93\xE6\x9D...' for column 'Html' at row 1

即使连接字符串上加上 CharSet=utf8 或 CharSet=utf8mb3 或 CharSet=utf8mb4 也没用。

那么只能把数据库的字符集改为 utf8mb4。


更改字符集和排序方式前必须先备份数据库!


  1. 更改现有数据库的字符集和排序规则

    ALTER DATABASE mydatabase 
    CHARACTER SET utf8mb4 
    COLLATE utf8mb4_unicode_ci;
  2. 更改现有表的字符集和排序规则

    ALTER TABLE mytable 
    CONVERT TO CHARACTER SET utf8mb4 
    COLLATE utf8mb4_unicode_ci;
  3. 更改现有列的字符集和排序规则

    当列单独设置了字符集时执行,未设置的不需要执行,会继承表的字符集

    ALTER TABLE mytable 
    MODIFY mycolumn VARCHAR(255) 
    CHARACTER SET utf8mb4 
    COLLATE utf8mb4_unicode_ci


数据库中可能存在许多表,数据表中可能存在许多列,使用下面的命令可以生成批量执行的命令:

  1. 更改所有表的默认字符集和排序规则

    USE database_name; -- 替换为你的数据库名
    
    SELECT CONCAT('ALTER TABLE `', TABLE_SCHEMA, '`.`', TABLE_NAME, '` CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;') 
    FROM information_schema.TABLES 
    WHERE TABLE_SCHEMA = 'database_name'; -- 再次替换为你的数据库名
  2. 更改所有列的字符集和排序规则

    USE database_name; -- 使用你的数据库名
    
    SELECT CONCAT('ALTER TABLE `', TABLE_SCHEMA, '`.`', TABLE_NAME, '` MODIFY `', COLUMN_NAME, '` ', COLUMN_TYPE, ' CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;') 
    FROM information_schema.COLUMNS 
    WHERE TABLE_SCHEMA = 'database_name'; -- 使用你的数据库名


另外给出几条查询语句:

  1. 查看特定数据库的字符集和排序规则

    SELECT DEFAULT_CHARACTER_SET_NAME, DEFAULT_COLLATION_NAME
    FROM information_schema.SCHEMATA
    WHERE SCHEMA_NAME = 'your_database_name';
  2. 查看特定表的字符集和排序规则

    SELECT TABLE_SCHEMA, TABLE_NAME, TABLE_COLLATION
    FROM information_schema.TABLES
    WHERE TABLE_SCHEMA = 'your_database_name';
  3. 查看特定列的字符集和排序规则

    SELECT COLUMN_NAME, CHARACTER_SET_NAME, COLLATION_NAME 
    FROM information_schema.COLUMNS 
    WHERE TABLE_SCHEMA = 'your_database_name' AND TABLE_NAME = 'your_table_name';
xoyozo 8 个月前
1,556

SignalR 是一个开源的实时通信库,用于构建实时 Web 应用程序。它提供了一个简单的 API,可以在客户端和服务器之间建立持久连接,以便实时地推送数据。

与传统的 WebSocket 相比,SignalR 提供了更高级的功能和更简单的开发体验。下面是一些主要区别:

  • 支持多种传输方式:SignalR 可以使用多种传输方式,包括 WebSocket、Server-Sent Events(SSE)、长轮询和 Forever Frame。这使得 SignalR 在不同的环境中都能提供实时通信的能力,即使某些浏览器不支持 WebSocket,也可以使用其他传输方式。

  • 自动处理连接管理:SignalR 管理连接的生命周期,包括连接的建立、断开和重新连接。它会自动处理连接的失败和重新连接的逻辑,简化了开发人员的工作。

  • 服务器端推送:SignalR 允许服务器端主动推送消息给客户端,而不需要客户端发起请求。这使得实时通信变得更加高效和实时,适用于聊天应用、实时监控等场景。

  • 跨平台支持:SignalR 可以在多个平台上使用,包括 .NET、Java、JavaScript 等。这使得开发人员可以使用自己熟悉的语言和框架来构建实时应用程序。


微软官方提供了针对 ASP.NET Core Web 应用(Razor 页面)的详细教程,这里给出 MVC 版本入门教程。


最终将创建一个正常运行的聊天应用:

signalr-get-started-finished.png


创建 Web 应用项目

image.png

image.png


添加 SignalR 客户端库

在“解决方案资源管理器”>中,右键单击项目,然后选择“添加”“客户端库”。

在“添加客户端库”对话框中:

  • “提供程序”选择“unpkg”

  • “库”,请输入 @microsoft/signalr@latest。

  • 选择“选择特定文件”,展开“dist/browser”文件夹,然后选择 signalr.js 和 signalr.min.js。

  • 点击“安装” 。

image.png


创建 SignalR Hubs 类

using Microsoft.AspNetCore.SignalR;

/// <summary>
/// Hub 类管理连接、组和消息
/// </summary>
public class ChatHub : Hub
{
        /// <summary>
        /// 可通过已连接客户端调用 SendMessage,以向所有客户端发送消息
        /// </summary>
    public async Task SendMessage(string user, string message)
    {
        // Clients.All 向所有的客户端发送消息
        // ReceiveMessage 是客户端监听的方法
        await Clients.All.SendAsync("ReceiveMessage", user, message);
    }
}

其父类 Hub 可管理连接、组和消息。这里演示的是向所有客户端发送消息。


配置 SignalR

打开 Program.cs,添加注入:

builder.Services.AddSignalR();

添加路由:

app.MapHub<ChatHub>("/chatHub");


添加 SignalR 客户端代码

视图页面:

<div class="container">
    <div class="row p-1">
        <div class="col-1">用户</div>
        <div class="col-5"><input type="text" id="userInput" /></div>
    </div>
    <div class="row p-1">
        <div class="col-1">消息</div>
        <div class="col-5"><input type="text" class="w-100" id="messageInput" /></div>
    </div>
    <div class="row p-1">
        <div class="col-6 text-end">
            <input type="button" id="sendButton" value="发送消息" />
        </div>
    </div>
    <div class="row p-1">
        <div class="col-6">
            <hr />
        </div>
    </div>
    <div class="row p-1">
        <div class="col-6">
            <ul id="messagesList"></ul>
        </div>
    </div>
</div>
<script src="~/lib/microsoft/signalr/dist/browser/signalr.min.js"></script>
<script src="~/js/chat.js"></script>

chat.js 文件:

"use strict";

var connection = new signalR.HubConnectionBuilder().withUrl("/chatHub").build();

// 在连接建立之前禁用发送按钮
document.getElementById("sendButton").disabled = true;

connection.on("ReceiveMessage", function (user, message) {
    var li = document.createElement("li");
    document.getElementById("messagesList").appendChild(li);
    // 修改此处时应注意脚本注入问题
    li.textContent = `${user} says ${message}`;
});

connection.start().then(function () {
    document.getElementById("sendButton").disabled = false;
}).catch(function (err) {
    return console.error(err.toString());
});

document.getElementById("sendButton").addEventListener("click", function (event) {
    var user = document.getElementById("userInput").value;
    var message = document.getElementById("messageInput").value;
    connection.invoke("SendMessage", user, message).catch(function (err) {
        return console.error(err.toString());
    });
    event.preventDefault();
});


完成。在线示例:https://xoyozo.net/Demo/SignalRDemo






xoyozo 1 年前
1,196

客户端:Failed to connect to host.

服务端:无任何日志

原因:可能是域名、IP 或端口有误,或端口未开放。


客户端/服务端:530 Login incorrect.

原因:用户名或密码错误。


客户端/服务端503 Use AUTH first.

原因:服务端开启了 FTPS 协议(FTP over TLS),且禁止了 FTP 协议(plain FTP)。

解决方法:不建议服务端恢复不安全的 FTP 协议,客户端应配置 client.Config 的 EncryptionMode、DataConnectionEncryption、SslProtocols、ValidateCertificate 等参数。


客户端/服务端:530 This server does not allow plain FTP. You have to use FTP over TLS.

原因:服务端启用了 FTPS。

解决方法:给 client.Config.EncryptionMode 正确的赋值(FtpEncryptionMode.Explicit 或 FtpEncryptionMode.Auto)。


服务端:[Error] TLS session of data connection not resumed.

原因:证书版本有误。

解决方法:给 client.Config.SslProtocols 赋值正确的 TLS 版本。


服务端:521 PROT P required

原因:服务端开启了Require TLS session resumption on data connection when using PROT P”

解决方法:client.Config.DataConnectionEncryption = true;


客户端/服务端450 TLS session of data connection has not resumed or the session does not match the control connection

原因:TLS 与控制连接不匹配,即服务端开启了“Require TLS session resumption on data connection when using PROT P”

解决方法:我暂时还不知道原因,临时关闭了Require TLS session resumption on data connection when using PROT P”(不建议)。该问题出现在 FileZilla Server 0.x 版本,在 1.x 版本中没有该配置选项。

xoyozo 1 年前
1,668

有一个项目,在 VS2022 中正常打开,在 VS2019 中无法加载项目,项目目标框架是 .NET Standard 2.0。报错内容:

error: 无法打开项目文件。 .NET SDK 的版本 7.0.306 至少需要 MSBuild 的 17.4.0 版本。当前可用的 MSBuild 版本为 16.11.2.50704。请将在 global.json 中指定的 .NET SDK 更改为需要当前可用的 MSBuild 版本的旧版本。

解决方法:

运行 Visual Studio Installer,选择 Visual Studio 2019 进行修改,切换到“单个组件”,勾选“.NET SDK (out of support)”,会联动勾选“.NET 5.0 Runtime (Out of support)”与“.NET Core 3.1 Runtime (Out of support)”。

QQ截图20230728135007.png

xoyozo 1 年前
7,405

本文将详细介绍 stable diffusion webui 的下载、安装及问题解决。
Stable Diffusion 是 2022 年发布的深度学习文本到图像生成模型。它主要用于根据文本的描述产生详细图像,尽管它也可以应用于其他任务,如内补绘制、外补绘制,以及在提示词(英语)指导下产生图生图的翻译。它是一种潜在扩散模型,由慕尼黑大学的 CompVis 研究团体开发的各种生成性人工神经网络。它是由初创公司 StabilityAI,CompVis 与 Runway 合作开发的,并得到 EleutherAI 和 LAION 的支持。
其它问题请参考

一、环境准备

(一)硬件方面:

1. 显存

4G 起步,4G 显存支持生成 512*512 大小图片,超过这个大小将卡爆失败。

2. 硬盘

10G 起步,模型基本都在 5G 以上,有个 30G 硬盘不为过吧?现在硬盘容量应该不是个问题。

(二)软件方面:

1. Git

https://git-scm.com/download/win
下载最新版即可,对版本没有要求。

2. Python

https://www.python.org/downloads/
截止发稿(2023.3.6)时,最高版本只能用 3.10.*,用 3.11.* 会出问题。

3. Nvidia CUDA

https://developer.download.nvidia.cn/compute/cuda/11.7.1/local_installers/cuda_11.7.1_516.94_windows.exe
版本 11.7.1,搭配 Nvidia 驱动 516.94,可使用最新版。

4. stable-diffusion-webui

https://github.com/AUTOMATIC1111/stable-diffusion-webui
核心部件当然用最新版本~~但注意上面三个的版本的兼容性。

5. 中文语言包

https://github.com/VinsonLaro/stable-diffusion-webui-chinese
下载 chinese-all-0306.jsonchinese-english-0306.json 文件

6. 扩展(可选)

https://github.com/Mikubill/sd-webui-controlnet
下载整个 sd-webui-controlnet 压缩包

https://huggingface.co/Hetaneko/Controlnet-models/tree/main/controlnet_safetensors
https://huggingface.co/lllyasviel/ControlNet/tree/main/models
https://huggingface.co/TencentARC/T2I-Adapter/tree/main
试用时先下载第一个链接中的 control_openpose.safetensors 或 第二个链接中的 control_sd15_openpose.pth 文件

7. 模型

https://huggingface.co/models
https://civitai.com
可以网上去找推荐的一些模型,一般后缀名为 ckptptpthsafetensors ,有时也会附带 VAE(.vae.pt)或配置文件(.yaml)。

类型文件格式存放目录备注
check point.ckpt,.safetensors\models\Stable-diffusion文件较大
vae名字带有 vae 的\models\vae细节更好地恢复,特别是眼睛和文字
Textual Inversion*.pt\embeddings一般文件很小,额外的 tag
Lora*.pt\models\Lora调整模型,理解为风格化也可以
Hypernetworks.pt,.ckpt,*.safetensors\models\hypernetworks和 lora 工作方式相似,算法不同

这里可以学习一下模型的基本概念《解析不同种类的 Stable Diffusion 模型 Models,再也不用担心该用什么了

二、安装流程

1. 安装 Git

就正常安装,无问题。

2. 安装 Python

建议安装在非 program files、非 C 盘目录,以防出现目录权限问题。
注意安装时勾选 Add Python to PATH,这样可以在安装时自动加入 windows 环境变量 PATH 所需的 Python 路径。

3. 安装 Nvidia CUDA

正常安装,无问题。

4. 安装 stable-diffusion-webui

国内需要用到代理和镜像,请按照下面的步骤操作:

a) 编辑根目录下 launch.py 文件
将 https://github.com  替换为 https://ghproxy.com/https://github.com,即使用  Ghproxy 代理,加速国内 Git。
如图将代码中所有类似地址都改掉(注意:不仅仅是图中所展示的这些)。

b) 执行根目录下 webui.bat 文件
根目录下将生成 tmp 和 venv 目录。

c) 编辑 venv 目录下 pyvenv.cfg 文件
将 include-system-site-packages = false 改为 include-system-site-packages = true

d) 配置 python 库管理器 pip
方便起见,在 \venv\Scripts 下打开 cmd 后执行如下命令:

pip config set global.index-url https://mirrors.aliyun.com/pypi/simple/ # 镜像
pip freeze > requirements_versions.txt # 创建文件
pip install -r requirements_versions.txt # 执行此条命令前,请检查你的剩余磁盘空间
pip install xformer # 如果不执行此条命令,启动 Stable Diffusion 时可能会出现错误。xformer 还可以在后续使用中降低显卡占用。

xformer 会安装到 \venv\Lib\site-packages 中,安装失败可以用 pip install -U xformers 命试试。

e) 安装语言包
将文件 chinese-all-0306.jsonchinese-english-0306.json 放到目录 \localizations 目录中。
运行 webui 后进行配置,操作方法见下。

f) 安装扩展(可选)
将 sd-webui-controlnet 解压缩到 \extensions 目录中。
将 control_sd15_openpose.pth 文件复制到 /extensions/sd-webui-controlnet/models 目录中。
不同的扩展可能还需要安装对应的系统,比如 controlnet 要正常使用则还需要安装 ffmpeg 等。

g) 安装模型
下载的各种模型放在 \models\Stable-diffusion 目录中即可。

h) 再次执行根目录下 webui.bat 文件
用浏览器打开 webui.bat 所提供的网址即可运行。

其中提供了网址:http://127.0.0.1:7860

打开该网址后在 Settings -> User interface -> Localization (requires restart) 设置语言,在菜单中选择 chinese-all-0220(前提是已经在目录中放入了对应语言包,见上),点击 Apply Settings 确定,并且点击 Reload UI 重启界面后即可。

好了,现在可以开始使用了~~

三、问题及注意点

1. python 版本错误

错误

ERROR: Could not find a version that satisfies the requirement torch==1.13.1+cu117
ERROR: No matching distribution found for torch==1.13.1+cu117

这是由于 python 版本不对导致的(上面提过了,截止发稿时不能追求新版本),要用 python 3.10.* 版本。
解决来源:https://github.com/AUTOMATIC1111/stable-diffusion-webui/issues/7166

2. pip版本错误

警告:

[notice] A new release of pip available: 22.3.1 -> 23.0.1
[notice] To update, run: D:\stable-diffusion-webui\venv\Scripts\python.exe -m pip install --upgrade pip

提示中已经给出了解决方案:
在 \venv\Scripts\ 目录中打开 cmd,执行

python.exe -m pip install --upgrade pip

3. 安装或执行停滞

如果在执行 webui.bat 进行包下载安装时或者生成图片时会卡很久都没反应,那么这时可以复制包名,进入 python 安装目录或 \venv\Scripts\ 目录中打开 cmd,执行

pip install 包名

也可以通过任务管理查看网络状态,如果网络在玩命下载,那么就等着吧~~

4. xFormers 安装不上

很多同学都反应 xformers 无法安装,可以用以下的方法试试:

  • 检查 Dreambooth 要求的 Python 版本:
    如果您的 Python 版本低于 3.6,请安装最新的 Python 版本,并重复尝试安装 xformers。

# 据此可以在终端中运行以下命令,以检查您的 Python 版本:
python --version
  • 安装依赖项:xformers 有许多依赖项,如果这些依赖项没有正确安装可能会导致升级失败。您可以尝试安装以下依赖项:

pip install numpy scipy torch torchaudio transformers
  • 清除 pip 缓存并重新安装:

# 清除 xformers 缓存:运行以下命令清除 xformers 缓存。
pip uninstall -y xformers
pip cache purge

# 更新 pip:确保您正在使用最新版本的 pip,可以运行以下命令更新 pip。
pip install --upgrade pip

# 安装 xformers:在清除了缓存并更新了 pip 之后,重新安装 xformers。
pip install xformers
  • 手动安装 xformers 指定版本
    如果上述步骤仍然无法解决问题,可尝试手动安装 Dreambooth 所需的 xformers 版本。在 Dreambooth 的文档中,可以找到 xformers 的版本要求。

pip install xformers==0.0.17.dev465
  • 使用 conda 环境
    如果您使用的是 conda 环境,请尝试在 conda 环境中安装 xformers。

# 创建 conda 环境
conda create --name myenv

# 激活 conda 环境并安装 xformers
conda activate myenv
pip install xformers
  • 网络问题
    如果已经配置好了代理,就不要考虑这个了。
    检查网络连接:请确保您的计算机与互联网连接,并且网络连接没有被防火墙或代理服务器阻止:

# 检查网络连接是否正常
ping google.com
  • 非必要
    你确定需要使用 xformers 么?如果不需要,可以在 webui-user.bat 中把 --xformers 去掉试试。

  • 其它
    如果上述方法还是无法解决问题,请尝试在 OpenAI 的论坛或者 Dreambooth 的 GitHub 页面上寻求更多帮助。-_-!

5. 其他安装问题

删除 /tmp 和 /venv 目录后重启 webui.bat 试试。

6. 硬件问题

一般显卡不达标,就会爆卡,解决办法就是编辑根目录下 webui-user.bat 文件,试一下修改参数 COMMANDLINE_ARGS 即可。

以下几个设置逐一测试看看哪个适合自己。

set COMMANDLINE_ARGS=--lowvram --precision full --no-half --skip-torch-cuda-test
set COMMANDLINE_ARGS=--lowvram --precision full --no-half
set COMMANDLINE_ARGS=--lowvram

本机显存 4G,使用最后一个配置方法,可以烧出 2048*1080 的图,前两种方法反而会在最后爆卡。

最后,预祝各位成功~~

dog drink~~ where is dog?

在这里插入图片描述

参考:
【AI 繪畫】Stable-Diffusion 通過骨架分析插件 ControlNet 來製作超有意境的圖片
Stable Diffusion 2.1 + WebUI 的安装与使用(极详细)
低配显卡想玩 Stable Diffusion?修改一个配置就行
整合包

转自 暂时先用这个名字 2 年前
3,789

不知道从哪个版本的 Chrome 或 Edge 开始,我们无法通过 ctrl+v 快捷键将时间格式的字符串粘贴到 type 为 date 的 input 框中,我们想办法用 JS 来实现。


方式一、监听 paste 事件:

const input = document.querySelector('input[type="date"]');
input.addEventListener('paste', (event) => {
    input.value = event.clipboardData.getData('text');
});

这段代码实现了从页面获取这个 input 元素,监听它的 paste 事件,然后将粘贴板的文本内容赋值给 input。

经测试,当焦点在“年”的位置时可以粘贴成功,但焦点在“月”或“日”上不会触发 paste 事件。


方式二、监听 keydown 事件:

const input = document.querySelector('input[type="date"]');
input.addEventListener('keydown', (event) => {
    if ((navigator.platform.match("Mac") ? event.metaKey : event.ctrlKey) && event.key === 'v') {
        event.preventDefault();
        var clipboardData = (event.clipboardData || event.originalEvent.clipboardData);
        input.value = clipboardData.getData('text');
    }
});

测试发现报错误:

Uncaught TypeError: Cannot read properties of undefined (reading 'getData')

Uncaught TypeError: Cannot read properties of undefined (reading 'clipboardData')

看来 event 中没有 clipboardData 对象,改为从 window.navigator 获取:

const input = document.querySelector('input[type="date"]');
input.addEventListener('keydown', (event) => {
    if ((navigator.platform.match("Mac") ? event.metaKey : event.ctrlKey) && event.key === 'v') {
        event.preventDefault();
        window.navigator.clipboard.readText().then(text => {
            input.value = text;
        });
    }
});

缺点是需要用户授权:

image.png

仅第一次需要授权,如果用户拒绝,那么以后就默认拒绝了。


以上两种方式各有优缺点,选择一种适合你的方案就行。接下来继续完善。


兼容更多时间格式,并调整时区

<input type="date" /> 默认的日期格式是 yyyy-MM-dd,如果要兼容 yyyy-M-d 等格式,那么:

const parsedDate = new Date(text);
if (!isNaN(parsedDate.getTime())) {
    input.value = parsedDate.toLocaleDateString('en-GB', { year: 'numeric', month: '2-digit', day: '2-digit' }).split('/').reverse().join('-');
}

以 text 为“2023-4-20”举例,先转为 Date,如果成功,再转为英国时间格式“20-04-2023”,以“/”分隔,逆序,再以“-”连接,就变成了“2023-04-20”。

当然如果希望支持中文的年月日,可以先用正则表达式替换一下:

text = text.replace(/\s*(\d{4})\s*年\s*(\d{1,2})\s*月\s*(\d{1,2})\s*日\s*/, "$1-$2-$3");


处理页面上的所有 <input type="date" />

const inputs = document.querySelectorAll('input[type="date"]');
inputs.forEach((input) => {
    input.addEventListener(...);
});


封装为独立域

避免全局变量污染,使用 IIFE 函数表达式:

(function() {
  // 将代码放在这里
})();

或者封装为函数,在 jQuery 的 ready 中,或 Vue 的 mounted 中调用。


在 Vue 中使用

如果将粘贴板的值直接赋值到 input.value,在 Vue 中是不能同步更新 v-model 绑定的变量的,所以需要直接赋值给变量:

<div id="app">
    <input type="date" v-model="a" data-model="a" v-on:paste="fn_pasteToDateInput" />
    {{a}}
</div>
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
<script>
    const app = Vue.createApp({
        data: function () {
            return {
                a: null,
            }
        },
        methods: {
            fn_pasteToDateInput: function (event) {
                const text = event.clipboardData.getData('text');
                const parsedDate = new Date(text);
                if (!isNaN(parsedDate.getTime())) {
                    const att = event.target.getAttribute('data-model');
                    this[att] = parsedDate.toLocaleDateString('en-GB', { year: 'numeric', month: '2-digit', day: '2-digit' }).split('/').reverse().join('-');
                }
            },
        }
    });
    const vm = app.mount('#app');
</script>

示例中 <input /> 添加了 data- 属性,值同 v-model,并使用 getAttribute() 获取,利用 this 对象的属性名赋值。 

如果你的 a 中还有嵌套对象 b,那么 data- 属性填写 a.b,方法中以“.”分割逐级查找对象并赋值

let atts = att.split('.');
let target = this;
for (let i = 0; i < atts.length - 1; i++) {
    target = target[atts[i]];
}
this.$set(target, atts[atts.length - 1], text);


xoyozo 2 年前
1,362