Add smart ACK provider for WeChat MP replies

Replace fixed ackText with a rule-based AckProvider that picks
response templates by message type and intent (translate, summary,
rewrite, poster, ppt, mindmap, code, search, schedule). Pure sync,
zero I/O, auto-falls back to config.ackText on any error.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
john
2026-06-26 15:19:03 +08:00
parent 9ed4fd48d7
commit 9b4a25799f
162 changed files with 17276 additions and 2054 deletions
+37 -6
View File
@@ -38,6 +38,30 @@ function normalizeSort(value) {
return 'recommend';
}
export function defaultPlazaCoverUrl(publicUrl) {
const value = String(publicUrl ?? '').trim();
if (!value) return '';
const [pathname, suffix = ''] = value.split(/([?#].*)/, 2);
if (!pathname) return '';
const nextPath = pathname.endsWith('/') ? `${pathname}index.thumbnail.png` : `${pathname}.thumbnail.png`;
return `${nextPath}${suffix}`;
}
export function resolvePlazaCoverUrl(inputCoverUrl, publicUrl) {
const value = String(inputCoverUrl ?? '').trim();
if (!value) return defaultPlazaCoverUrl(publicUrl);
if (/^https?:\/\//i.test(value)) return value;
const base = String(publicUrl ?? '').trim();
if (base && /^https?:\/\//i.test(base)) {
try {
return new URL(value, base).toString();
} catch {
return value;
}
}
return value;
}
function formatStats(row) {
return {
view_count: Number(row.view_count ?? 0),
@@ -66,11 +90,12 @@ function promoteFreshPosts(items, now = Date.now()) {
}
function formatPostRow(row, { category, viewerReacted = null, publicationUrl = null } = {}) {
const resolvedPublicationUrl = publicationUrl ?? row.public_url ?? null;
return {
id: row.id,
title: row.title,
summary: row.summary ?? '',
cover_url: row.cover_url ?? '',
cover_url: resolvePlazaCoverUrl(row.cover_url, resolvedPublicationUrl),
category: category ?? {
id: row.category_id,
name: row.category_name ?? '',
@@ -87,7 +112,7 @@ function formatPostRow(row, { category, viewerReacted = null, publicationUrl = n
stats: formatStats(row),
viewer_reacted: viewerReacted,
published_at: new Date(Number(row.published_at)).toISOString(),
...(publicationUrl ? { publication_url: publicationUrl } : {}),
...(resolvedPublicationUrl ? { publication_url: resolvedPublicationUrl } : {}),
...(row.allow_comment != null ? { allow_comment: Boolean(row.allow_comment) } : {}),
...(row.status ? { status: row.status } : {}),
};
@@ -97,6 +122,8 @@ export const plazaInternals = {
normalizeTags,
clampLimit,
normalizeSort,
defaultPlazaCoverUrl,
resolvePlazaCoverUrl,
};
export function createPlazaPostService(
@@ -238,7 +265,7 @@ export function createPlazaPostService(
const categoryId = await resolveCategoryId(input?.category_id, input?.category_slug);
const userSnapshot = await loadUserSnapshot(userId);
const tags = normalizeTags(input?.tags);
const coverUrl = String(input?.cover_url ?? '').trim();
const coverUrl = resolvePlazaCoverUrl(input?.cover_url, publication.public_url);
const allowComment = input?.allow_comment == null ? true : Boolean(input.allow_comment);
const now = Date.now();
const postId = idFactory();
@@ -298,7 +325,10 @@ export function createPlazaPostService(
const updatePost = async (userId, postId, input) => {
const [rows] = await pool.query(
`SELECT * FROM plaza_posts WHERE id = ? AND user_id = ? LIMIT 1`,
`SELECT pp.*, pr.public_url
FROM plaza_posts pp
JOIN h5_publish_records pr ON pr.id = pp.publication_id
WHERE pp.id = ? AND pp.user_id = ? LIMIT 1`,
[postId, userId],
);
const post = rows[0];
@@ -317,7 +347,7 @@ export function createPlazaPostService(
}
if (input?.cover_url != null) {
updates.push('cover_url = ?');
params.push(String(input.cover_url).trim());
params.push(resolvePlazaCoverUrl(input.cover_url, post.public_url));
}
if (input?.allow_comment != null) {
updates.push('allow_comment = ?');
@@ -450,9 +480,10 @@ export function createPlazaPostService(
: 'pp.hot_score DESC, pp.id DESC';
const [rows] = await pool.query(
`SELECT pp.*, c.name AS category_name, c.slug AS category_slug, c.icon AS category_icon
`SELECT pp.*, c.name AS category_name, c.slug AS category_slug, c.icon AS category_icon, pr.public_url
FROM plaza_posts pp
JOIN plaza_categories c ON c.id = pp.category_id
JOIN h5_publish_records pr ON pr.id = pp.publication_id
WHERE pp.status = ?
${categoryFilter}
${cursorClause}