Initial 智念AIGC platform

This commit is contained in:
inman
2026-05-29 10:26:02 +08:00
commit f9c3393f84
86 changed files with 14741 additions and 0 deletions

26
scripts/health-check.mjs Normal file
View File

@@ -0,0 +1,26 @@
const port = process.env.PORT || process.env.NIANXX_PLAY_PORT || '3000';
const hostname = process.env.HOSTNAME || '127.0.0.1';
const baseUrl = process.env.NIANXXPLAY_PUBLIC_BASE_URL || `http://${hostname}:${port}`;
const healthUrl = new URL('/api/health', baseUrl).toString();
const controller = new AbortController();
const timeout = setTimeout(() => controller.abort(), 3000);
try {
const response = await fetch(healthUrl, { signal: controller.signal });
const text = await response.text();
if (!response.ok) {
console.error(`[health] ${response.status} ${response.statusText}: ${text}`);
process.exit(1);
}
const payload = JSON.parse(text);
console.log(JSON.stringify(payload, null, 2));
if (payload?.appId !== 'zhinian-web-studio' || !payload?.ok) {
process.exit(1);
}
} catch (error) {
console.error(`[health] Failed to reach ${healthUrl}: ${error instanceof Error ? error.message : String(error)}`);
process.exit(1);
} finally {
clearTimeout(timeout);
}

View File

@@ -0,0 +1,40 @@
import { readFileSync } from 'node:fs';
import { join, resolve } from 'node:path';
import { dirname } from 'node:path';
import { fileURLToPath } from 'node:url';
const rootDir = resolve(dirname(fileURLToPath(import.meta.url)), '..');
const pkg = JSON.parse(readFileSync(join(rootDir, 'package.json'), 'utf8'));
console.log(JSON.stringify({
project: '智念AIGC平台',
appId: 'zhinian-web-studio',
packageName: pkg.name,
version: pkg.version,
runtime: 'Next.js Web',
webOnly: true,
primaryRoutes: [
'/',
'/create',
'/assets',
'/image-edit',
'/settings'
],
imageCapabilities: [
'image.generate',
'image.inpaint',
'image.upscale'
],
videoCapabilities: [
'video.generate'
],
promptFlow: [
'unified image/video create studio',
'single prompt box',
'single compact upload entry',
'@图片/@视频/@音频 references',
'material thumbnails in chips and @ suggestions',
'shared prompt assembly for image and video'
],
legacyRuntime: 'runtime/nianxx-play is kept as a reference artifact only'
}, null, 2));

View File

@@ -0,0 +1,57 @@
import { readFileSync } from 'node:fs';
import { join, resolve } from 'node:path';
import { dirname } from 'node:path';
import { fileURLToPath } from 'node:url';
const rootDir = resolve(dirname(fileURLToPath(import.meta.url)), '..');
const runtimeDir = join(rootDir, 'runtime', 'nianxx-play');
function readJson(relativePath) {
return JSON.parse(readFileSync(join(runtimeDir, relativePath), 'utf8'));
}
const manifest = readJson('bundle-manifest.json');
const pkg = readJson('package.json');
const paths = readJson('.next/server/app-paths-manifest.json');
const modes = readJson('content/seedance-starter/creation-modes.json');
const catalog = readJson('content/seedance-starter/catalog.json');
const planningCases = readJson('content/planning-cases.json');
const modeCounts = {};
for (const item of catalog.cases || []) {
modeCounts[item.mode] = (modeCounts[item.mode] || 0) + 1;
}
console.log(JSON.stringify({
project: 'Zhinian Creation Assistant',
packageName: 'zhinian-creation-assistant',
runtime: {
appId: manifest.appId,
name: manifest.name,
version: manifest.version,
bundledAt: manifest.bundledAt,
entry: manifest.entry,
sizeBytes: manifest.sizeBytes,
},
package: {
name: pkg.name,
version: pkg.version,
dependencies: pkg.dependencies,
},
routes: Object.keys(paths).sort(),
creationModes: modes.map((mode) => ({
id: mode.id,
name: mode.name,
editorType: mode.editorType,
assetSlots: mode.assetSlots,
})),
catalog: {
totalCases: (catalog.cases || []).length,
modeCounts,
},
planningCases: planningCases.map((item) => ({
id: item.id,
title: item.title,
orientation: item.orientation,
})),
}, null, 2));

107
scripts/start-runtime.mjs Normal file
View File

@@ -0,0 +1,107 @@
import { spawn } from 'node:child_process';
import { existsSync, mkdirSync, readFileSync } from 'node:fs';
import { dirname, join, resolve } from 'node:path';
import { fileURLToPath } from 'node:url';
const rootDir = resolve(dirname(fileURLToPath(import.meta.url)), '..');
const runtimeDir = join(rootDir, 'runtime', 'nianxx-play');
const serverPath = join(runtimeDir, 'server.js');
function parseEnvValue(raw) {
const value = raw.trim();
if (
(value.startsWith('"') && value.endsWith('"')) ||
(value.startsWith("'") && value.endsWith("'"))
) {
try {
return JSON.parse(value);
} catch {
return value.slice(1, -1);
}
}
return value;
}
function parseEnvFile(filePath) {
if (!existsSync(filePath)) return {};
const env = {};
const raw = readFileSync(filePath, 'utf8');
for (const line of raw.split(/\r?\n/)) {
const trimmed = line.trim();
if (!trimmed || trimmed.startsWith('#')) continue;
const match = trimmed.match(/^(?:export\s+)?([A-Za-z_][A-Za-z0-9_]*)=(.*)$/);
if (!match) continue;
env[match[1]] = parseEnvValue(match[2]);
}
return env;
}
function loadEnv() {
const envFiles = [
join(rootDir, '.env'),
join(rootDir, '.env.local'),
];
if (process.env.NIANXXPLAY_LOAD_BUNDLED_ENV === '1') {
envFiles.push(join(runtimeDir, '.env.runtime'));
}
const fileEnv = {};
for (const file of envFiles) {
Object.assign(fileEnv, parseEnvFile(file));
}
return { ...fileEnv, ...process.env };
}
if (!existsSync(serverPath)) {
console.error(`Zhinian Creation Assistant runtime entry not found: ${serverPath}`);
process.exit(1);
}
const baseEnv = loadEnv();
const port = baseEnv.PORT || baseEnv.NIANXX_PLAY_PORT || '3000';
const hostname = baseEnv.HOSTNAME || '127.0.0.1';
const runtimeRoot = baseEnv.NIANXXPLAY_RUNTIME_DIR || join(rootDir, '.runtime');
const dataDir = baseEnv.NIANXXPLAY_DATA_DIR || join(runtimeRoot, 'data');
const uploadDir = baseEnv.NIANXXPLAY_UPLOAD_DIR || join(runtimeRoot, 'uploads');
const resultDir = baseEnv.NIANXXPLAY_RESULT_DIR || join(runtimeRoot, 'generated-results');
mkdirSync(dataDir, { recursive: true });
mkdirSync(uploadDir, { recursive: true });
mkdirSync(resultDir, { recursive: true });
const env = {
...baseEnv,
PORT: String(port),
HOSTNAME: hostname,
NODE_ENV: 'production',
NEXT_TELEMETRY_DISABLED: '1',
NIANXXPLAY_RUNTIME_DIR: runtimeRoot,
NIANXXPLAY_DATA_DIR: dataDir,
NIANXXPLAY_UPLOAD_DIR: uploadDir,
NIANXXPLAY_RESULT_DIR: resultDir,
NIANXXPLAY_PUBLIC_BASE_URL: baseEnv.NIANXXPLAY_PUBLIC_BASE_URL || `http://${hostname}:${port}`,
NIANXXPLAY_DESKTOP_MANAGED: '1',
};
console.log(`[Zhinian Creation Assistant] Starting on http://${hostname}:${port}`);
console.log(`[Zhinian Creation Assistant] Runtime data: ${runtimeRoot}`);
const child = spawn(process.execPath, [serverPath], {
cwd: runtimeDir,
env,
stdio: 'inherit',
});
function stop(signal) {
if (!child.killed) child.kill(signal);
}
process.on('SIGINT', () => stop('SIGINT'));
process.on('SIGTERM', () => stop('SIGTERM'));
child.on('exit', (code, signal) => {
if (signal) {
process.exit(0);
}
process.exit(code ?? 0);
});