Add image-designer skill, align billing to DeepSeek ×1, and enrich Plaza demo.
Introduce AI image generation with chat shortcut and agent API, improve MindSpace chat-to-page save resolution, and seed Plaza covers with production deploy scripts. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
+63
-11
@@ -21,7 +21,7 @@ import {
|
||||
userSessionCookie,
|
||||
} from './user-auth.mjs';
|
||||
import { createWikiAuth } from './wiki-auth.mjs';
|
||||
import { PUBLISH_ROOT_DIR, PUBLISH_KEY_UUID, PUBLIC_ZONE_DIR, resolvePublishDir } from './user-publish.mjs';
|
||||
import { PUBLISH_ROOT_DIR, PUBLISH_KEY_UUID, PUBLIC_ZONE_DIR, resolvePublicBaseUrl, resolvePublishDir } from './user-publish.mjs';
|
||||
import { ensureWorkspaceHtmlThumbnail, startWorkspaceThumbnailWatcher, workspaceThumbnailRelativePath } from './mindspace-workspace-thumbnails.mjs';
|
||||
import { startWorkspaceAssetSyncWatcher } from './mindspace-workspace-sync.mjs';
|
||||
import { attachRequestId, sendData, sendError } from './api-response.mjs';
|
||||
@@ -31,6 +31,7 @@ import { createMindSpaceService } from './mindspace.mjs';
|
||||
import { createAssetService } from './mindspace-assets.mjs';
|
||||
import { createPageService, pageInternals } from './mindspace-pages.mjs';
|
||||
import { createPageLiveEditService } from './mindspace-page-live-edit.mjs';
|
||||
import { createImageGenerationService } from './image-generation.mjs';
|
||||
import { createPageEditSessionService } from './mindspace-page-edit-session.mjs';
|
||||
import { suggestCoverMetaWithAi } from './mindspace-cover-ai.mjs';
|
||||
import { createPublicationService } from './mindspace-publications.mjs';
|
||||
@@ -54,7 +55,6 @@ import { createCleanupService } from './mindspace-cleanup.mjs';
|
||||
import { createAgentJobService } from './mindspace-agent-jobs.mjs';
|
||||
import { createMindSpaceAgentRunner } from './mindspace-agent-runner.mjs';
|
||||
import {
|
||||
analyzeChatMessageForSave,
|
||||
buildChatSavePreviewFrameUrl,
|
||||
buildChatSaveThumbnailUrl,
|
||||
buildWorkspaceAssetUrl,
|
||||
@@ -62,7 +62,6 @@ import {
|
||||
buildWorkspaceThumbnailUrl,
|
||||
injectHtmlBaseHref,
|
||||
resolveChatSaveAnalysis,
|
||||
resolveStaticHtmlContent,
|
||||
} from './mindspace-chat-save.mjs';
|
||||
import { generateHtmlThumbnail } from './mindspace-thumbnails.mjs';
|
||||
import { scanContent } from './mindspace-content-scan.mjs';
|
||||
@@ -101,6 +100,7 @@ const API_SECRET = process.env.TKMIND_SERVER__SECRET_KEY ?? 'local-dev-secret';
|
||||
const INTERNAL_AGENT_SECRET = process.env.MINDSPACE_INTERNAL_AGENT_SECRET ?? API_SECRET;
|
||||
const ACCESS_PASSWORD = process.env.H5_ACCESS_PASSWORD;
|
||||
const USERS_ROOT = process.env.H5_USERS_ROOT ?? path.join(__dirname, 'users');
|
||||
const PUBLIC_BASE_URL = resolvePublicBaseUrl(process.env);
|
||||
|
||||
const app = express();
|
||||
app.set('trust proxy', 1);
|
||||
@@ -176,6 +176,7 @@ let mindSpaceAssets = null;
|
||||
let mindSpaceAudit = null;
|
||||
let mindSpacePages = null;
|
||||
let mindSpacePageLiveEdit = null;
|
||||
let imageGeneration = null;
|
||||
let mindSpacePageEditSession = null;
|
||||
let mindSpacePublications = null;
|
||||
let plazaPosts = null;
|
||||
@@ -225,6 +226,18 @@ async function bootstrapUserAuth() {
|
||||
return rows[0]?.user_id ?? null;
|
||||
},
|
||||
});
|
||||
imageGeneration = createImageGenerationService({
|
||||
pool,
|
||||
h5Root: __dirname,
|
||||
publicBaseUrl: PUBLIC_BASE_URL,
|
||||
resolveUserIdForAgentSession: async (sessionId) => {
|
||||
const [rows] = await pool.query(
|
||||
`SELECT user_id FROM h5_user_sessions WHERE agent_session_id = ? LIMIT 1`,
|
||||
[sessionId],
|
||||
);
|
||||
return rows[0]?.user_id ?? null;
|
||||
},
|
||||
});
|
||||
mindSpacePublications = createPublicationService(pool, {
|
||||
storageRoot:
|
||||
process.env.MINDSPACE_STORAGE_ROOT ?? path.join(__dirname, 'data', 'mindspace'),
|
||||
@@ -436,7 +449,16 @@ app.post('/auth/login', jsonBody, async (req, res) => {
|
||||
return res.status(401).json({ message: result.message });
|
||||
}
|
||||
setUserLoginCookies(res, req, result.token);
|
||||
return res.json({ authenticated: true, user: result.user, mode: 'user' });
|
||||
const row = await userAuth.getUserById(result.user.id);
|
||||
const capabilityState = row ? await userAuth.resolveUserCapabilities(row) : null;
|
||||
return res.json({
|
||||
authenticated: true,
|
||||
user: result.user,
|
||||
mode: 'user',
|
||||
capabilities: capabilityState?.capabilities,
|
||||
grantedSkills: capabilityState?.grantedSkills ?? [],
|
||||
unrestricted: capabilityState?.unrestricted,
|
||||
});
|
||||
}
|
||||
|
||||
if (!legacyAuth) {
|
||||
@@ -1289,6 +1311,7 @@ api.use(async (req, res, next) => {
|
||||
if (req.path === '/status') return next();
|
||||
if (req.path.startsWith('/internal/agent/')) return next();
|
||||
if (req.path === '/agent/mindspace_page_patch') return next();
|
||||
if (req.path === '/agent/generate_image') return next();
|
||||
|
||||
const plazaPublic = isPlazaPublicRead(req.path, req.method);
|
||||
|
||||
@@ -2068,6 +2091,7 @@ async function resolveChatSaveBundle(user, h5Root, input = {}) {
|
||||
username: user.username,
|
||||
h5Root,
|
||||
selectedLinkIndex,
|
||||
publicBaseUrl: PUBLIC_BASE_URL,
|
||||
});
|
||||
return {
|
||||
source,
|
||||
@@ -2224,12 +2248,13 @@ api.post('/mindspace/v1/pages/save-from-chat', async (req, res) => {
|
||||
req.body?.session_id,
|
||||
req.body?.message_id,
|
||||
);
|
||||
const analysis = analyzeChatMessageForSave({
|
||||
const { analysis, resolvedHtml } = await resolveChatSaveAnalysis({
|
||||
content: source.content,
|
||||
userId: req.currentUser.id,
|
||||
username: req.currentUser.username,
|
||||
h5Root: __dirname,
|
||||
selectedLinkIndex: Number(req.body?.selected_link_index ?? 0),
|
||||
publicBaseUrl: PUBLIC_BASE_URL,
|
||||
});
|
||||
const snapshot = {
|
||||
session_name: source.session.name,
|
||||
@@ -2237,13 +2262,9 @@ api.post('/mindspace/v1/pages/save-from-chat', async (req, res) => {
|
||||
role: source.message.role,
|
||||
content_mode: analysis.contentMode,
|
||||
public_url: analysis.previewUrl,
|
||||
relative_path: analysis.relativePath,
|
||||
relative_path: resolvedHtml?.relativePath ?? analysis.relativePath,
|
||||
};
|
||||
|
||||
let resolvedHtml = null;
|
||||
if (analysis.contentMode === 'static_html') {
|
||||
resolvedHtml = await resolveStaticHtmlContent(analysis).catch(() => null);
|
||||
}
|
||||
const privacyScan = scanContent(resolvedHtml?.content ?? source.content);
|
||||
assertPrivateSaveAllowed(categoryCode, privacyScan, req.body?.acknowledged_finding_ids);
|
||||
|
||||
@@ -2309,7 +2330,7 @@ api.post('/mindspace/v1/pages/save-from-chat', async (req, res) => {
|
||||
|
||||
if (analysis.contentMode === 'static_html' && resolvedHtml?.content && analysis.relativePath) {
|
||||
const publishDir = resolvePublishDir(__dirname, req.currentUser);
|
||||
await ensureWorkspaceHtmlThumbnail(publishDir, analysis.relativePath, resolvedHtml.content, {
|
||||
void ensureWorkspaceHtmlThumbnail(publishDir, analysis.relativePath, resolvedHtml.content, {
|
||||
title: pageInput.title,
|
||||
subtitle: pageInput.summary,
|
||||
}).catch(() => {});
|
||||
@@ -2557,6 +2578,37 @@ api.post('/agent/mindspace_page_patch', async (req, res) => {
|
||||
}
|
||||
});
|
||||
|
||||
api.post('/agent/generate_image', async (req, res) => {
|
||||
if (!imageGeneration) {
|
||||
return res.status(503).json({ message: '图片生成未启用' });
|
||||
}
|
||||
try {
|
||||
const result = await imageGeneration.generateForAgentSession(req.body ?? {});
|
||||
return sendData(res, req, {
|
||||
relative_path: result.relativePath,
|
||||
public_url: result.publicUrl,
|
||||
mime_type: result.mimeType,
|
||||
size: result.size,
|
||||
style: result.style,
|
||||
quality: result.quality,
|
||||
revised_prompt: result.revisedPrompt,
|
||||
prompt: result.prompt,
|
||||
});
|
||||
} catch (error) {
|
||||
const code = error?.code ?? 'internal_error';
|
||||
const statusByCode = {
|
||||
image_gen_unavailable: 503,
|
||||
image_gen_not_configured: 503,
|
||||
invalid_request: 400,
|
||||
invalid_output_path: 400,
|
||||
forbidden: 403,
|
||||
image_gen_failed: 502,
|
||||
};
|
||||
const status = statusByCode[code] ?? 500;
|
||||
return sendError(res, req, status, code, error?.message || '图片生成失败', error?.details);
|
||||
}
|
||||
});
|
||||
|
||||
api.get('/mindspace/v1/pages/:pageId/thumbnail', async (req, res) => {
|
||||
if (!mindSpacePages) return res.status(503).json({ message: 'MindSpace 未启用' });
|
||||
try {
|
||||
|
||||
Reference in New Issue
Block a user