从开始接触Novel AI开始我就想写让他自动生成,然后存到电脑里。
今天终于把程序写出来了。
官方说在/docs里面可以看到API接口,但是我进去什么有用的信息也没找到,即便是加上运行参数"--api"也一样。
所以···
抓包分析
前端与后端之间用的是https通信 废话,直接Fiddler抓包。
我需要通过分析前后端的通信得到后端供前端调用的接口。
在进行之前,先确定目标:
- 记录登录状态的方法
- 登录的接口
- 判断是否需要等待的接口
- 运行计算的接口
- 获取进度的接口
- 获取输出的接口
记录登录状态的方法
在每一次提交计算都会传递过去一个参数,叫做“session_hash=XXXX”,所以我怀疑这个就是记录登录状态的,倘若是这样的话,这个值就应该是后端传递过来的,完完整整找了之前的信息也没有找到它的值出现,此时注意到它的名字中有个“hash”,但是尝试把一些信息计数哈希无果。
假如上面那个参数就是记录登录状态的参数的话,那么这个参数应该是由JavaScript记录的,只要刷新网页就会丢失,但是并不会丢失登录状态。
为什么呢?因为Cookie!但是我最不明白的就是cookie了,一直在扣静态网页,完全不懂,不过这一次任务比较简单,技术够用了。
完全禁用浏览器cookie,果然登录不上了。
分析登录的包,登录失败了的话会返回Json的错误信息,成功的话会302跳转,跳转到首页,cookie就藏在回应的http头里面,回应http头里有个修改cookie的信息。
我只需要分析回应头,然后取出cookie信息,下次请求的时候作为请求头
无论是Python还是Go还是什么,http客户端对象都是能记录cookie的,只需要开启cookie记录,其余的事情什么也不用做。
登录的接口
登录的接口非常简单,POST请求,发送帐号和密码,完成。
POST请求与GET请求不同,主要是客户端提交什么到服务器用的,往服务器发送的容量比GET大,比GET复杂一些。
POST请求有格式,在头里面写着。
“Content-Type: XXX”
格式有四种
- application/x-www-form-urlencoded
- application/json
- multipart/form-data
- text/xml
登录用的是“application/x-www-form-urlencoded”。
地址: /login
这个格式的标准到底是什么,我也不知道,但是照着葫芦画瓢就好了,把抓的包替换掉账号密码。
后面四个接口
这四个是同一个接口,比意想中简单得多。
地址: /api/predict
请求
请求方法是POST,格式是“application/json”

内容是:
{
"fn_index": int,
"data":array,
"session_hash":string
}
- fn_index 请求类型代码
- data 携带的信息(应该是解码之后直接交给Python的函数执行)
- session_hash 回话ID(不知道起到了什么具体作用)
fn_index抓包抓到之后,已知有用的有两个:
- 3: 获取任务进度。data为空。
- 14: 请求AI计算,最后计算完成才会返回,计算期间一直挂着。data里面是参数。
返回
返回同样是“application/json”
里面的信息很多,很不条理,大多数信息都用不到。
对于3请求,它返回的进度不是一个值,是一段html代码。
对于14请求,返回生成的文件名,除此之外还有很多无用数据。
调用接口
在进行14请求的时候,页面上可以设置的这些参数全部放进data里面发给后端了。我把其中的生成种子换成%s占位符,放入Go代码。
14请求在最后计算完成才会返回,计算期间一直挂着,这也免去了查询是否完成的麻烦。
我还不会用多线程,所以就只用14请求,不显示进度了。
14请求最终返回一段Json,这段Json很长,垃圾很多,很不规则,其中包括了生成出的文件名。
获取文件的接口
上面成功得到文件路径之后需要下载下来,但是直接访问的话会404,界面以外的文件不允许访问。
根据抓包,获取的方法还是通过接口。
地址: /file
这似乎有点不合标准。
请求方法是GET
直接请求 /file=XXX 就可以了。
Go程序
从登录开始。
发送POST登录请求。
"username=%s&password=%s"
开cookie:
var client = &http.Client{}
jar, err0 := cookiejar.New(nil)
client.Jar = jar
只要cookie记录了,请求一次成功了就不用管了。
然后直接开始请求AI绘图接口。
最终返回的Json Go语言不好解析,所以,我不解析了,直接搜索 "name":"/ 这个字符串,找到就是成功,没有就是失败。
strings.Index(restr, "\"name\":\"/")
可能会生成出来纯黑的图,这样的图在png压缩之后会比一般的图片小很多,所以只要接收到长度小于两万字节的文件直接丢弃就好了。
好了,现在AI就可以无人监督运作了。
项目已开源到Github: https://github.com/FFeng123/stable-diffusion-webui-request-tool