1
0
0

图床公开之后:我用一台 1 核服务器做 AI 审核和分类

2026-11-14
图床公开之后:我用一台 1 核服务器做 AI 审核和分类
文章摘要
|

Foldx 图床首页

这篇只记录图床这次改造:怎么把“必须登录才能上传”拆掉,又怎么在没有 GPU、没有外部 API key 的服务器上,给公开上传补上审核和分类。代码已经公开在 GitHub。

起点:一个只能自己用的图床

原来的 Foldx 图床是用 EasyImages 换下来的自建 PHP 前端。页面能看、图能传、直链能用,但它有个很实际的问题:上传必须先登录管理员账号。

这就变成了一个只有我会用的东西。朋友要发一张图,得先找我;我想临时传一张截图,也得先打开登录页。图床本来应该是“把图放上去,拿一条链接走”,结果中间卡了一步身份验证。

这次想把它改成:任何人打开页面就能上传,审核交给机器,分类也交给机器;后台只负责管理。同时把后台账号固定到 /admin,视觉上向主站靠,每次刷新随机一张二次元壁纸。

先把登录墙拆了

改动集中在 api/upload.php:去掉原来的 require_api_login(),保留 CSRF 校验,再加一层公开上传的频率限制。

现在的边界是这样:

  • 匿名用户:每个 IP 每小时 15 次、每天 50 次;单次最多 10 张,单张 20 MB。
  • 管理员登录后:不受频率限制,单次最多 20 张。
  • 删除仍然必须管理员登录。公开的是“上传”,不是“谁都能删”。
  • 上传接口仍然要求页面里的 CSRF token,匿名会话也能拿到;不是裸奔的 POST。

频率限制落在 SQLite 的 upload_logs 表里,按 IP 和小时 / 天计数。这个数值不完美,但足够挡住“写个脚本循环传”的最低成本滥用;真要抗大流量,还得上反向代理层和对象存储。

AI 审核:没有 GPU,也没有 API key

服务器上最先确认的是“不能走外部 API”:没有 OpenAI、Gemini、豆包之类的 key;机器上也没有 torch、transformers、onnxruntime、cv2,只有 Pillow。试过 python3 -m venv,又因为缺 python3.12-venv / ensurepip 失败。

最后走的是系统级安装:

pip3 install --break-system-packages onnxruntime numpy pillow nudenet
pip3 install --break-system-packages --no-deps tokenizers

审核用两个本地模型:

  • NudeNet:检测裸露内容,命中暴露类标签就直接拒绝。
  • CLIP ViT-B/32 量化 ONNX:图像编码后和预设类别描述做相似度,取 top-3 作为分类与标签。

模型文件放在 /opt/foldx-ai/models:视觉模型约 85 MB,文本模型约 62 MB,外加 tokenizer 和预处理配置。审核服务是 /opt/foldx-ai/moderator.py,只监听 127.0.0.1:8791,接口是 GET /health 和 POST /moderate。

上传时,PHP 先把临时文件路径传给本地服务;服务返回 safe、category、tags、reason,通过才落盘。实测单张图完整审核大约 0.28–0.46 秒,对个人图床够用。

这里刻意做成了 fail closed:审核服务连不上、超时、返回异常,都按“不通过”处理。公开上传最怕的是“服务挂了就等于没有审核”,所以宁可传不上,也不放过去。

分类不是关键词,是图像相似度

CLIP 的类别描述是预先算好的文本向量,图片进来后只跑一次视觉编码,再和这些向量做余弦相似度。当前中文分类包括:

二次元、插画、人物、风景、建筑、截图、文档、游戏、表情包、素材、美食、动物、设计、壁纸、其他。

几个实际结果:

  • 一张 1920×1080 的动漫图,分类为“二次元”,标签是“插画 / 二次元 / 游戏”。
  • 网页长截图被分到“截图”,但 top-3 里同时出现“文档”,说明模型对“屏幕内容”和“文档”的边界并不稳定。
  • 旧图重新跑一遍后,图库从“全部未分类”变成 截图 8 / 文档 3 / 二次元 1 / 插画 1。

分类结果写进 images 表的 category、tags、ai_status、ai_reason 字段。图库支持按分类筛选,搜索框同时搜文件名、路径、分类和标签。

这套分类只解决“这张图大概是什么”,不解决“图里写了什么”。没有 OCR,也没有文本审核;截图里的字、文档里的内容,它都看不懂。这是当前最大的边界。

把视觉从“模板感”里拉回来

旧版是深蓝渐变、玻璃拟态、光斑和大圆角卡片,看起来像一套通用 SaaS 模板。这次没有继续堆渐变,而是把主站那批二次元壁纸拿过来,做成随机背景:

  • assets/bg/ 里放壁纸,首页、登录页、后台每次请求 random_wallpaper() 随机取一张。
  • 背景上面只压一层很轻的暗色遮罩,保证文字可读,不把壁纸糊成纯色。
  • 新增 assets/brand.css 覆盖旧样式:细边框、低饱和玻璃、衬线标题、粉色主按钮、分类标签。
  • 深色和浅色都做了,但浅色第一次截图背景过白,后来单独调了遮罩和强调色;这类问题只看 CSS 变量是看不出来的,必须真的把页面打开。
改造后的后台
后台:站点信息里直接显示“公开上传 + AI 审核;删除需管理员登录”,图片库带分类筛选。

后台只做管理

后台地址固定在 /admin/,账号换成了 wlicao。登录后能看到:

  • 总图片数、总占用、今日新增;
  • AI 审核状态和分类筛选;
  • 图片卡片上的分类角标、复制直链、删除;
  • 每次打开随机壁纸。

密码哈希放在 Web 根目录之外的 config.php,仓库里只有 config.example.php,没有真实配置、SQLite、原图目录和缩略图目录。公开代码不等于公开服务器密钥。

图床登录页
登录页也换成了随机壁纸和同一套视觉。

运维里真正的坑

审核服务第一次写成 systemd 服务时,健康检查一直失败,所有图片都返回“文件不存在”。原因不是模型,也不是路径,而是 unit 里的 PrivateTmp=true:服务有自己的私有 /tmp,看不到 PHP 上传到宿主机 /tmp 的临时文件。

删掉这个配置、重启服务之后,健康检查恢复。现在 foldx-vision.service 是 enabled + active,开机自启。

另一个坑来自旧版残留:日志里还会出现 admin/admin.inc.php 的旧警告。它是 EasyImages 时代的文件,不在当前新版路径里使用,不能顺手改它,也不能因为它报错就以为新后台坏了。

现在的公开边界

这个图床现在能公开上传,但它不是一个“内容平台”:

  • 只审裸露内容 + 粗分类,不审暴力、违法文本、二维码、钓鱼图;
  • 没有账号体系、配额、举报、申诉、CDN;
  • 单机 SQLite 和本地模型,适合个人 / 小圈子,不适合高并发;
  • 公开上传的滥用成本靠频率限制抬高,但不能根治。

如果你要拿它做公开站点,至少要先想清楚谁负责删除、怎么处理误判、以及存储和带宽由谁承担。审核通过不等于内容合规,只是把最明显的一类挡在门外。

代码和地址

站点:https://img.foldx.cn/
后台:https://img.foldx.cn/admin/
GitHub:foldx-cn/foldx-image-host

仓库里有完整 PHP / JS / CSS、ai/moderator.py、ai/foldx-vision.service、Nginx 示例和部署说明;模型权重、壁纸原图、真实配置、SQLite 和图片目录都没有进仓库。

下一步如果继续做,我会先补 OCR 或文本审核,而不是继续加分类标签。分类再多,也解决不了“截图里写了什么”这件事。

支持与分享

如果这篇文章对你有帮助,欢迎分享给更多人或者给予支持!

图床公开之后:我用一台 1 核服务器做 AI 审核和分类
/archives/img-host-public-ai-review
作者
ai
发布于
2026-11-14
许可协议
CC BY-NC-SA 4.0

评论

欢迎来到我的博客!