文章摘要moonshot-v1-8k
Standby API Responsing..
2026年,AI确实越来越聪明了。如果说早期的AI需要非常专业的prompt来辅助,现在已经发展到不太需要那么专业了,不论日常交流,学术研讨还是技术实现,从文字到音频,再从图片到视频,AI“猜”用户需求的能力毫无疑问已经越来越强了,AI能帮我们做的也越来越多。
最近做了两个事,一个是迁移valine评论,另一个是给wordpress的评论系统加了一些AI辅助。促使这次改版的是偶然看到了corrain 博文评论区中@AI自动回复,觉得和微信元宝很像,很方便,就想着改进一下wp评论。(其实凡哥那早就做了ai评论,当然,后续增强AI评论也是参考了该逻辑)
开发的时候我都没用最强coding claude,用的国产deepseek的专家模式,开启深度思考,现在实际体验真的很不错了。他的模型数据很大,我直接把问题抛给它,其中很多没提供的细节都是他自己拿到的。虽然不是什么一次成功,但效率提升不是一点半点。
@2BER AI
因为 Valine 即将关闭服务,故此项在 wordpress 基础上开发。
先说下这个 @2BER 评论增强AI,2BER被设计用来评论用户交流互动,支持文章摘要。一开始设计他的目的还是文章总结,不过后来发现当AI被设计到评论交互系统里后就变得特别灵活,可扩展性特别强。当你在文章下 @2BER (但不回复任何内容)时会自动返回当前文章摘要,在其他页面 @2BER 时,他会作为一名普通AI助手和你聊天。后面我发现这样功能还有点单一,就再增强了他的属性,设计了多楼层评论、解析其他用户评论、多轮对话等复杂结构。

期间AI回复体验比之前好很多,很多你没考虑到的东西他会自己去设计并告知你具体用途,其实开启深度思考也有用,看看他的思路是什么,有时候他会抛弃掉部分实现思路,但是你能看见,就可以在他后续代码出错时尝试他之前的思路,有时候有奇效👍。
基础需求
// 需求:wordpress评论系统增加`@2BER`关键词触发AI自动回复用户评论内容,思路:通过`comment_post`钩子,截取检测评论内容若包含该关键词,则携带文章内容+用户需求发送到指定api请求给ai的api(如kimi),并等待api返回结果,将此结果(文本)作为该用户的子评论回复。
..
新增 REST API
// 对了,我想把这个功能设计成一个可调用的api接口,例如提供一个评论id,就可以去执行以上ai回复(如该评论已回复,则返回已回复内容)。请你保持上述代码不动的基础上修改
...
增强 API 响应
// 好的。现在我们来增强前端用户体验:目前执行ai回复时,前端不会有任何响应或提示,我的想法是可以先写入评论列表,显示等待响应(实际是否写入数据库,你来决定),等api响应后,再将实际返回结果写入前端评论。关于前端实现你不用管,把后端响应给我就行。
AI 反垃圾
这个想法是我在 obaby 那偶然看到的,当时就觉得这个思路特别新颖,现在刚好给评论系统接入AI了,正好试试效果。其实这个反垃圾的效果和接入的模式应该有很大关系,后面怕误判又把被AI判定的评论搞到后台列表手动审核了,这个测试还有很大的改进空间。
AI 评论过滤
// 我最近发现被刷了很多垃圾评论,刚好我们评论钩子中加入了AI系统,所以我想加入AI评论审核。新需求:在原有基础上,新增一个AI内容审核函数,这个函数主要通过用户提交的评论内容进行审查过滤,垃圾评论的规则可以参考数据库中被标定为“垃圾评论”的评论数据,进行自我学习和判定。
开这个AI助手用了几天时间,但实际开发成本很低,人工介入少,效果还好。现在,你可以在评论区尝试`@2BER`来获取你的专属AI回复啦!
所有更新已同步到github.
Valine 迁移
在Wordpress适配完2BER AI,想到现在还在用Valie的评论,虽然leancloud还有半年才关闭服务,想着干脆一次性迁移过去了事,反正之前都迁移实验过了,没啥问题。
之前提到,leancloud将于27年初关停baas服务,届时valine依存的后端储存服务就没了,再早之前(23年)也提前做过迁移预演,只是时隔数年,再打开那篇文章的时候,很多东西自己都看不太懂了😂… 有不少bug和错误,记得那年还去研究了sql的好多语法来实现,搞得既复杂效率又底下。

Leancloud 服务关停预告
关服公告 昨天查看 leancloud 后台数据的时候,一条公告映入眼帘:LeanCloud 将于 2027 年 1 月 12 日停止对外提供服务,详情...
不过好在,我们还有AI!
一开始只是尝试着问下,他刚开始搜了下网上的通用转换脚本,发现没有,就自定义写了匹配(这里他自己拿到了objectId, nick, mail, link, comment, insertedAt, url(文章路径),rid(父评论的objectId),ua等)。
基础需求
// 你有什么好办法把valine.js.org的评论jsonl数据,迁移到wordpress中吗?评论数据需要关联文章id(valine用的url),关联父级评论,以及关联评论数量。
Python+SQL 批处理
// 我在windows环境,”请确保已安装 mysql-connector-python(或 pymysql)“,我现在有comment.jsonl,也有mysql数据库信息,给我一个windows只需你的脚本的步骤
AI给出的方案方便多了,本地Python脚本连接SQL远程数据库,全自动批量建立评论关联,插入wordpress数据库,一气呵成。虽然刚开始的方案不成熟,但几轮对话下来,很快便改进了实现方式。这里需要注意一点:如果他提供代码出问题了,要把全部报错信息和你的代码全部复制给AI。虽然AI支持长对话,但这样能最大程度减少隐形BUG出现。只要解题思路正确,AI能很快产出答案,但注意不用无脑复制粘贴,有时候AI会偷懒省略掉部分重复代码。还有,涉及到SQL数据部分,如果你开了 Memcached 缓存,记得清掉。
这里顺便贴一下Valine转Wordpress的Python脚本,AI会根据你的具体需求改进代码。注意,执行任何操作之前,先备份数据,使用这个脚本前需要告诉AI把脚本里的URL匹配模式改为你自己站点的URL结构。(PS:如果你没装python环境,可以先问下AI这段代码都需要装哪些运行环境。连接远程数据库需要开放数据库远程权限和放行3306端口,操作完成后记得关闭。)
点此展开代码块
# 执行代码后,会根据你的数据量等待一段时间,完成后控制台输出迁移完成
import json
import re
import mysql.connector
from datetime import datetime, timezone
from urllib.parse import urlparse, unquote, quote
# ========== 配置(修改为你的信息) ==========
JSONL_FILE = "comment.jsonl"
DB_CONFIG = {
"host": "你的数据库地址",
"user": "数据库用户名",
"password": "数据库密码",
"database": "数据库名",
"charset": "utf8mb4"
}
TABLE_PREFIX = "wp_" # 你的表前缀
# =========================================
conn = mysql.connector.connect(**DB_CONFIG)
cursor = conn.cursor()
# 1. 确保 comment_content 是 LONGTEXT
try:
cursor.execute(f"ALTER TABLE {TABLE_PREFIX}comments MODIFY comment_content LONGTEXT")
print("comment_content 已改为 LONGTEXT")
except Exception as e:
print("修改字段备注:", e)
# 2. 获取所有文章 slug -> ID
cursor.execute(
f"SELECT ID, post_name FROM {TABLE_PREFIX}posts "
f"WHERE post_type IN ('post','page') AND post_status='publish'"
)
rows = cursor.fetchall()
print(f"查询到 {len(rows)} 篇文章")
slug_to_id = {}
for post_id, post_name in rows:
slug_to_id[post_name.lower()] = post_id
# 3. 生成候选 slug 列表的函数
def get_candidate_slugs(url_str):
"""
从 Valine 的 URL 中提取可能的 slug 候选。
1. 先取路径最后一段(原始 slug)
2. 如果原始 slug 包含日期前缀(如 25-09-2019_),去掉前缀生成第二个候选
返回候选 slug 列表,按优先级排序。
"""
path = urlparse(url_str).path.strip("/")
if not path:
return []
raw_slug = path.split("/")[-1] # 最后一段
# 统一解码并转小写(WP 风格)
try:
decoded = unquote(raw_slug)
encoded = quote(decoded, safe='').lower()
except:
encoded = raw_slug.lower()
candidates = [encoded]
# 匹配形如 "DD-MM-YYYY_" 的前缀
match = re.match(r"^\d{2}-\d{2}-\d{4}_(.+)", encoded)
if match:
candidates.append(match.group(1)) # 去掉日期前缀后的部分
return candidates
# 4. 读取 JSONL 并分类
oid_to_new_id = {}
top_level, children = [], []
skipped_slugs = []
with open(JSONL_FILE, "r", encoding="utf-8") as f:
for line in f:
line = line.strip()
if not line:
continue
c = json.loads(line)
candidates = get_candidate_slugs(c.get("url", ""))
post_id = None
for slug in candidates:
post_id = slug_to_id.get(slug)
if post_id:
break
if not post_id:
skipped_slugs.append((c.get("url", ""), candidates))
continue
# ---------- 时间解析(使用 createdAt) ----------
created_str = c.get("createdAt", "")
try:
if created_str.endswith("Z"):
created_str = created_str[:-1] + "+00:00"
dt = datetime.fromisoformat(created_str)
# 统一存为 UTC 的 GMT 时间(WordPress 内部用 GMT)
gmt = dt.strftime('%Y-%m-%d %H:%M:%S')
local = dt.astimezone().strftime('%Y-%m-%d %H:%M:%S') # 本地时间,按服务器时区自动转换
except:
now = datetime.now()
gmt = now.strftime('%Y-%m-%d %H:%M:%S')
local = gmt
# ---------- user_id 判断 ----------
user_id = 1 if c.get("mail", "").lower() == "xty@2broear.com" else 0
comment = {
"post_id": post_id,
"author": c.get("nick", "")[:200],
"email": c.get("mail", "")[:100],
"url": c.get("link", "")[:200],
"content": c.get("comment", "")[:200000],
"date": local,
"date_gmt": gmt,
"approved": 1,
"agent": c.get("ua", "")[:255],
"oid": c.get("objectId"),
"rid": c.get("rid", ""),
"user_id": user_id
}
if not c.get("rid"):
top_level.append(comment)
else:
children.append(comment)
# 5. 打印部分未匹配的样本,便于排查
if skipped_slugs:
print(f"\n未匹配的评论数: {len(skipped_slugs)} 条")
print("前 10 个未匹配示例:")
for url, cands in skipped_slugs[:10]:
print(f" URL: {url}")
print(f" 候选 slug: {cands}")
print()
# 6. 插入数据库(加入 user_id)
insert_sql = (
f"INSERT INTO {TABLE_PREFIX}comments "
"(comment_post_ID, comment_author, comment_author_email, comment_author_url, "
"comment_content, comment_date, comment_date_gmt, comment_approved, comment_agent, "
"comment_parent, user_id) "
"VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, 0, %s)"
)
# 顶级评论
for t in top_level:
data = (
t["post_id"], t["author"], t["email"], t["url"],
t["content"], t["date"], t["date_gmt"], t["approved"], t["agent"],
t["user_id"]
)
cursor.execute(insert_sql, data)
oid_to_new_id[t["oid"]] = cursor.lastrowid
# 子评论
for child in children:
parent_id = oid_to_new_id.get(child["rid"], 0)
data = (
child["post_id"], child["author"], child["email"], child["url"],
child["content"], child["date"], child["date_gmt"], child["approved"], child["agent"],
child["user_id"]
)
cursor.execute(insert_sql, data)
new_id = cursor.lastrowid
oid_to_new_id[child["oid"]] = new_id
if parent_id != 0:
cursor.execute(
f"UPDATE {TABLE_PREFIX}comments SET comment_parent = %s WHERE comment_ID = %s",
(parent_id, new_id)
)
# 7. 更新文章评论数
cursor.execute(
f"UPDATE {TABLE_PREFIX}posts p "
f"SET comment_count = (SELECT COUNT(*) FROM {TABLE_PREFIX}comments c "
f"WHERE c.comment_post_ID = p.ID AND c.comment_approved = 1) "
f"WHERE p.post_type IN ('post','page')"
)
conn.commit()
cursor.close()
conn.close()
print("迁移完成!")
小结
AI辅助开发的故事告一段落,短短时间就完成了两个任务标的。不得不说,这玩意有时候是真好用!