@changw98ic/dashboard 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +674 -0
- package/README.md +40 -0
- package/dist/index.d.ts +23 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +104 -0
- package/dist/index.js.map +1 -0
- package/dist/routes/chapter.d.ts +10 -0
- package/dist/routes/chapter.d.ts.map +1 -0
- package/dist/routes/chapter.js +81 -0
- package/dist/routes/chapter.js.map +1 -0
- package/dist/routes/entity.d.ts +10 -0
- package/dist/routes/entity.d.ts.map +1 -0
- package/dist/routes/entity.js +117 -0
- package/dist/routes/entity.js.map +1 -0
- package/dist/routes/project.d.ts +10 -0
- package/dist/routes/project.d.ts.map +1 -0
- package/dist/routes/project.js +75 -0
- package/dist/routes/project.js.map +1 -0
- package/dist/routes/stats.d.ts +10 -0
- package/dist/routes/stats.d.ts.map +1 -0
- package/dist/routes/stats.js +141 -0
- package/dist/routes/stats.js.map +1 -0
- package/package.json +60 -0
package/README.md
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# @changw98ic/dashboard
|
|
2
|
+
|
|
3
|
+
可视化面板 - Fastify 后端。
|
|
4
|
+
|
|
5
|
+
## 安装
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @changw98ic/dashboard
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## 使用
|
|
12
|
+
|
|
13
|
+
```typescript
|
|
14
|
+
import { createDashboard } from '@changw98ic/dashboard';
|
|
15
|
+
|
|
16
|
+
const dashboard = createDashboard({
|
|
17
|
+
port: 3000,
|
|
18
|
+
projectRoot: '/path/to/novel'
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
await dashboard.start();
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## 命令行
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
npx webnovel dashboard
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## 文档
|
|
31
|
+
|
|
32
|
+
详见 [项目主页](https://github.com/changw98ic/webnovel-writer-skill#readme)
|
|
33
|
+
|
|
34
|
+
## 致谢
|
|
35
|
+
|
|
36
|
+
本项目基于 [lingfengQAQ/webnovel-writer-skill](https://github.com/lingfengQAQ/webnovel-writer-skill) 开发。
|
|
37
|
+
|
|
38
|
+
## License
|
|
39
|
+
|
|
40
|
+
MIT
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @changw98ic/dashboard
|
|
3
|
+
*
|
|
4
|
+
* 可视化面板 - Fastify 后端
|
|
5
|
+
*/
|
|
6
|
+
import Fastify from 'fastify';
|
|
7
|
+
export interface DashboardOptions {
|
|
8
|
+
port?: number;
|
|
9
|
+
host?: string;
|
|
10
|
+
projectRoot: string;
|
|
11
|
+
staticDir?: string;
|
|
12
|
+
}
|
|
13
|
+
export declare function createDashboard(options: DashboardOptions): Promise<{
|
|
14
|
+
fastify: Fastify.FastifyInstance<import("http").Server<typeof import("http").IncomingMessage, typeof import("http").ServerResponse>, import("http").IncomingMessage, import("http").ServerResponse<import("http").IncomingMessage>, Fastify.FastifyBaseLogger, Fastify.FastifyTypeProviderDefault> & PromiseLike<Fastify.FastifyInstance<import("http").Server<typeof import("http").IncomingMessage, typeof import("http").ServerResponse>, import("http").IncomingMessage, import("http").ServerResponse<import("http").IncomingMessage>, Fastify.FastifyBaseLogger, Fastify.FastifyTypeProviderDefault>>;
|
|
15
|
+
start: () => Promise<Fastify.FastifyInstance<import("http").Server<typeof import("http").IncomingMessage, typeof import("http").ServerResponse>, import("http").IncomingMessage, import("http").ServerResponse<import("http").IncomingMessage>, Fastify.FastifyBaseLogger, Fastify.FastifyTypeProviderDefault>>;
|
|
16
|
+
stop: () => Promise<void>;
|
|
17
|
+
}>;
|
|
18
|
+
export { projectRoutes } from './routes/project.js';
|
|
19
|
+
export { chapterRoutes } from './routes/chapter.js';
|
|
20
|
+
export { entityRoutes } from './routes/entity.js';
|
|
21
|
+
export { statsRoutes } from './routes/stats.js';
|
|
22
|
+
export default createDashboard;
|
|
23
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,OAAO,MAAM,SAAS,CAAC;AA8B9B,MAAM,WAAW,gBAAgB;IAC/B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,wBAAsB,eAAe,CAAC,OAAO,EAAE,gBAAgB;;;;GA0E9D;AAED,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAEhD,eAAe,eAAe,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @changw98ic/dashboard
|
|
3
|
+
*
|
|
4
|
+
* 可视化面板 - Fastify 后端
|
|
5
|
+
*/
|
|
6
|
+
import Fastify from 'fastify';
|
|
7
|
+
import cors from '@fastify/cors';
|
|
8
|
+
import staticPlugin from '@fastify/static';
|
|
9
|
+
import { existsSync } from 'fs';
|
|
10
|
+
import { join, dirname } from 'path';
|
|
11
|
+
import { fileURLToPath } from 'url';
|
|
12
|
+
import { projectRoutes } from './routes/project.js';
|
|
13
|
+
import { chapterRoutes } from './routes/chapter.js';
|
|
14
|
+
import { entityRoutes } from './routes/entity.js';
|
|
15
|
+
import { statsRoutes } from './routes/stats.js';
|
|
16
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
17
|
+
function resolveStaticDir(staticDir) {
|
|
18
|
+
const candidates = [
|
|
19
|
+
staticDir,
|
|
20
|
+
join(__dirname, '../frontend/dist'),
|
|
21
|
+
join(__dirname, '../../../webnovel-writer/dashboard/frontend/dist'),
|
|
22
|
+
];
|
|
23
|
+
for (const candidate of candidates) {
|
|
24
|
+
if (candidate && existsSync(candidate)) {
|
|
25
|
+
return candidate;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
return null;
|
|
29
|
+
}
|
|
30
|
+
export async function createDashboard(options) {
|
|
31
|
+
const { port = 3000, host = 'localhost', projectRoot, staticDir } = options;
|
|
32
|
+
const resolvedStaticDir = resolveStaticDir(staticDir);
|
|
33
|
+
const fastify = Fastify({
|
|
34
|
+
logger: {
|
|
35
|
+
level: 'info',
|
|
36
|
+
},
|
|
37
|
+
});
|
|
38
|
+
// 注册 CORS
|
|
39
|
+
await fastify.register(cors, {
|
|
40
|
+
origin: true,
|
|
41
|
+
});
|
|
42
|
+
// 注册静态文件服务
|
|
43
|
+
if (resolvedStaticDir) {
|
|
44
|
+
await fastify.register(staticPlugin, {
|
|
45
|
+
root: resolvedStaticDir,
|
|
46
|
+
prefix: '/assets/',
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
// 注册路由
|
|
50
|
+
await fastify.register(projectRoutes, { prefix: '/api/project', projectRoot });
|
|
51
|
+
await fastify.register(chapterRoutes, { prefix: '/api/chapters', projectRoot });
|
|
52
|
+
await fastify.register(entityRoutes, { prefix: '/api/entities', projectRoot });
|
|
53
|
+
await fastify.register(statsRoutes, { prefix: '/api/stats', projectRoot });
|
|
54
|
+
// 健康检查
|
|
55
|
+
fastify.get('/api/health', async () => ({ status: 'ok', timestamp: new Date().toISOString() }));
|
|
56
|
+
// SPA fallback
|
|
57
|
+
fastify.setNotFoundHandler((request, reply) => {
|
|
58
|
+
if (request.url.startsWith('/api/')) {
|
|
59
|
+
reply.code(404).send({ error: 'Not found' });
|
|
60
|
+
}
|
|
61
|
+
else {
|
|
62
|
+
if (resolvedStaticDir) {
|
|
63
|
+
reply.sendFile('index.html');
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
reply.type('text/html').send(`
|
|
67
|
+
<!doctype html>
|
|
68
|
+
<html lang="zh-CN">
|
|
69
|
+
<head>
|
|
70
|
+
<meta charset="utf-8" />
|
|
71
|
+
<title>Webnovel Dashboard</title>
|
|
72
|
+
</head>
|
|
73
|
+
<body>
|
|
74
|
+
<h1>Webnovel Dashboard API 已启动</h1>
|
|
75
|
+
<p>未找到前端静态资源目录,请先构建或提供 staticDir。</p>
|
|
76
|
+
</body>
|
|
77
|
+
</html>
|
|
78
|
+
`);
|
|
79
|
+
}
|
|
80
|
+
});
|
|
81
|
+
return {
|
|
82
|
+
fastify,
|
|
83
|
+
start: async () => {
|
|
84
|
+
await fastify.listen({ port, host });
|
|
85
|
+
console.log(`Dashboard running at http://${host}:${port}`);
|
|
86
|
+
if (resolvedStaticDir) {
|
|
87
|
+
console.log(`Dashboard static assets: ${resolvedStaticDir}`);
|
|
88
|
+
}
|
|
89
|
+
else {
|
|
90
|
+
console.warn('Dashboard static assets not found; API-only mode enabled.');
|
|
91
|
+
}
|
|
92
|
+
return fastify;
|
|
93
|
+
},
|
|
94
|
+
stop: async () => {
|
|
95
|
+
await fastify.close();
|
|
96
|
+
},
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
export { projectRoutes } from './routes/project.js';
|
|
100
|
+
export { chapterRoutes } from './routes/chapter.js';
|
|
101
|
+
export { entityRoutes } from './routes/entity.js';
|
|
102
|
+
export { statsRoutes } from './routes/stats.js';
|
|
103
|
+
export default createDashboard;
|
|
104
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Chapter Routes - 章节管理 API
|
|
3
|
+
*/
|
|
4
|
+
import type { FastifyPluginAsync } from 'fastify';
|
|
5
|
+
interface ChapterRoutesOptions {
|
|
6
|
+
projectRoot: string;
|
|
7
|
+
}
|
|
8
|
+
export declare const chapterRoutes: FastifyPluginAsync<ChapterRoutesOptions>;
|
|
9
|
+
export {};
|
|
10
|
+
//# sourceMappingURL=chapter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chapter.d.ts","sourceRoot":"","sources":["../../src/routes/chapter.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,OAAO,KAAK,EAAE,kBAAkB,EAAgB,MAAM,SAAS,CAAC;AAKhE,UAAU,oBAAoB;IAC5B,WAAW,EAAE,MAAM,CAAC;CACrB;AASD,eAAO,MAAM,aAAa,EAAE,kBAAkB,CAAC,oBAAoB,CA6FlE,CAAC"}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { StateManager, IndexManager } from '@changw98ic/data';
|
|
2
|
+
import { readFile } from 'fs/promises';
|
|
3
|
+
import { join } from 'path';
|
|
4
|
+
export const chapterRoutes = async (fastify, options) => {
|
|
5
|
+
const { projectRoot } = options;
|
|
6
|
+
// 获取章节列表
|
|
7
|
+
fastify.get('/', async (_request, reply) => {
|
|
8
|
+
const stateManager = new StateManager({ projectRoot });
|
|
9
|
+
if (!stateManager.exists()) {
|
|
10
|
+
return reply.code(404).send({ error: 'Project not initialized' });
|
|
11
|
+
}
|
|
12
|
+
const state = await stateManager.loadState();
|
|
13
|
+
const chapterMetas = Object.entries(state.chapter_meta || {}).map(([num, meta]) => {
|
|
14
|
+
const m = meta;
|
|
15
|
+
return {
|
|
16
|
+
chapter: parseInt(num),
|
|
17
|
+
title: m.title,
|
|
18
|
+
word_count: m.word_count,
|
|
19
|
+
location: m.location,
|
|
20
|
+
summary: m.summary,
|
|
21
|
+
};
|
|
22
|
+
});
|
|
23
|
+
return {
|
|
24
|
+
chapters: chapterMetas.sort((a, b) => a.chapter - b.chapter),
|
|
25
|
+
total: chapterMetas.length,
|
|
26
|
+
};
|
|
27
|
+
});
|
|
28
|
+
// 获取单个章节详情
|
|
29
|
+
fastify.get('/:chapter', async (request, reply) => {
|
|
30
|
+
const { chapter } = request.params;
|
|
31
|
+
const chapterNum = parseInt(chapter);
|
|
32
|
+
const stateManager = new StateManager({ projectRoot });
|
|
33
|
+
const indexManager = new IndexManager({ projectRoot });
|
|
34
|
+
if (!stateManager.exists()) {
|
|
35
|
+
return reply.code(404).send({ error: 'Project not initialized' });
|
|
36
|
+
}
|
|
37
|
+
const state = await stateManager.loadState();
|
|
38
|
+
const meta = state.chapter_meta?.[chapterNum.toString()];
|
|
39
|
+
if (!meta) {
|
|
40
|
+
return reply.code(404).send({ error: 'Chapter not found' });
|
|
41
|
+
}
|
|
42
|
+
// 获取章节的场景
|
|
43
|
+
const scenes = indexManager.getScenes(chapterNum);
|
|
44
|
+
return {
|
|
45
|
+
chapter: chapterNum,
|
|
46
|
+
title: meta.title,
|
|
47
|
+
word_count: meta.word_count,
|
|
48
|
+
location: meta.location,
|
|
49
|
+
summary: meta.summary,
|
|
50
|
+
scenes,
|
|
51
|
+
};
|
|
52
|
+
});
|
|
53
|
+
// 获取章节正文
|
|
54
|
+
fastify.get('/:chapter/content', async (request, reply) => {
|
|
55
|
+
const { chapter } = request.params;
|
|
56
|
+
const chapterNum = parseInt(chapter);
|
|
57
|
+
const stateManager = new StateManager({ projectRoot });
|
|
58
|
+
if (!stateManager.exists()) {
|
|
59
|
+
return reply.code(404).send({ error: 'Project not initialized' });
|
|
60
|
+
}
|
|
61
|
+
const state = await stateManager.loadState();
|
|
62
|
+
const meta = state.chapter_meta?.[chapterNum.toString()];
|
|
63
|
+
if (!meta || !meta.location) {
|
|
64
|
+
return reply.code(404).send({ error: 'Chapter content not found' });
|
|
65
|
+
}
|
|
66
|
+
try {
|
|
67
|
+
const contentPath = join(projectRoot, meta.location);
|
|
68
|
+
const content = await readFile(contentPath, 'utf-8');
|
|
69
|
+
return {
|
|
70
|
+
chapter: chapterNum,
|
|
71
|
+
title: meta.title,
|
|
72
|
+
content,
|
|
73
|
+
word_count: content.length,
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
catch {
|
|
77
|
+
return reply.code(404).send({ error: 'Chapter file not found' });
|
|
78
|
+
}
|
|
79
|
+
});
|
|
80
|
+
};
|
|
81
|
+
//# sourceMappingURL=chapter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chapter.js","sourceRoot":"","sources":["../../src/routes/chapter.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Entity Routes - 实体管理 API
|
|
3
|
+
*/
|
|
4
|
+
import type { FastifyPluginAsync } from 'fastify';
|
|
5
|
+
interface EntityRoutesOptions {
|
|
6
|
+
projectRoot: string;
|
|
7
|
+
}
|
|
8
|
+
export declare const entityRoutes: FastifyPluginAsync<EntityRoutesOptions>;
|
|
9
|
+
export {};
|
|
10
|
+
//# sourceMappingURL=entity.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"entity.d.ts","sourceRoot":"","sources":["../../src/routes/entity.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,SAAS,CAAC;AAGlD,UAAU,mBAAmB;IAC3B,WAAW,EAAE,MAAM,CAAC;CACrB;AASD,eAAO,MAAM,YAAY,EAAE,kBAAkB,CAAC,mBAAmB,CA0IhE,CAAC"}
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import { IndexManager } from '@changw98ic/data';
|
|
2
|
+
export const entityRoutes = async (fastify, options) => {
|
|
3
|
+
const { projectRoot } = options;
|
|
4
|
+
// 获取实体列表
|
|
5
|
+
fastify.get('/', async (request, _reply) => {
|
|
6
|
+
const query = request.query;
|
|
7
|
+
const indexManager = new IndexManager({ projectRoot });
|
|
8
|
+
const entities = indexManager.getEntities({
|
|
9
|
+
type: query.type,
|
|
10
|
+
tier: query.tier,
|
|
11
|
+
limit: query.limit || 50,
|
|
12
|
+
});
|
|
13
|
+
return {
|
|
14
|
+
entities: entities.map(e => ({
|
|
15
|
+
id: e.id,
|
|
16
|
+
name: e.canonical_name,
|
|
17
|
+
type: e.type,
|
|
18
|
+
tier: e.tier,
|
|
19
|
+
first_appearance: e.first_appearance,
|
|
20
|
+
last_appearance: e.last_appearance,
|
|
21
|
+
is_protagonist: e.is_protagonist,
|
|
22
|
+
})),
|
|
23
|
+
total: entities.length,
|
|
24
|
+
};
|
|
25
|
+
});
|
|
26
|
+
// 获取核心实体
|
|
27
|
+
fastify.get('/core', async (_request, _reply) => {
|
|
28
|
+
const indexManager = new IndexManager({ projectRoot });
|
|
29
|
+
const entities = indexManager.getCoreEntities();
|
|
30
|
+
return {
|
|
31
|
+
entities: entities.map(e => ({
|
|
32
|
+
id: e.id,
|
|
33
|
+
name: e.canonical_name,
|
|
34
|
+
type: e.type,
|
|
35
|
+
tier: e.tier,
|
|
36
|
+
current: e.current,
|
|
37
|
+
last_appearance: e.last_appearance,
|
|
38
|
+
})),
|
|
39
|
+
total: entities.length,
|
|
40
|
+
};
|
|
41
|
+
});
|
|
42
|
+
// 搜索实体
|
|
43
|
+
fastify.get('/search', async (request, reply) => {
|
|
44
|
+
const query = request.query;
|
|
45
|
+
if (!query.q) {
|
|
46
|
+
return reply.code(400).send({ error: 'Missing search query' });
|
|
47
|
+
}
|
|
48
|
+
const indexManager = new IndexManager({ projectRoot });
|
|
49
|
+
const entities = indexManager.searchEntities(query.q, query.limit || 20);
|
|
50
|
+
return {
|
|
51
|
+
query: query.q,
|
|
52
|
+
entities: entities.map(e => ({
|
|
53
|
+
id: e.id,
|
|
54
|
+
name: e.canonical_name,
|
|
55
|
+
type: e.type,
|
|
56
|
+
tier: e.tier,
|
|
57
|
+
last_appearance: e.last_appearance,
|
|
58
|
+
})),
|
|
59
|
+
total: entities.length,
|
|
60
|
+
};
|
|
61
|
+
});
|
|
62
|
+
// 获取单个实体详情
|
|
63
|
+
fastify.get('/:id', async (request, reply) => {
|
|
64
|
+
const { id } = request.params;
|
|
65
|
+
const indexManager = new IndexManager({ projectRoot });
|
|
66
|
+
const entity = indexManager.getEntityById(id);
|
|
67
|
+
if (!entity) {
|
|
68
|
+
return reply.code(404).send({ error: 'Entity not found' });
|
|
69
|
+
}
|
|
70
|
+
// 获取别名
|
|
71
|
+
const aliases = indexManager.getAliasesForEntity(id);
|
|
72
|
+
// 获取状态变化历史
|
|
73
|
+
const stateChanges = indexManager.getStateChanges(id, 20);
|
|
74
|
+
// 获取关系
|
|
75
|
+
const relationships = indexManager.getRelationships(id, 20);
|
|
76
|
+
return {
|
|
77
|
+
...entity,
|
|
78
|
+
aliases,
|
|
79
|
+
state_changes: stateChanges,
|
|
80
|
+
relationships,
|
|
81
|
+
};
|
|
82
|
+
});
|
|
83
|
+
// 获取实体关系图谱
|
|
84
|
+
fastify.get('/graph', async (_request, _reply) => {
|
|
85
|
+
const indexManager = new IndexManager({ projectRoot });
|
|
86
|
+
const entities = indexManager.getEntities({ limit: 100 });
|
|
87
|
+
const nodes = entities.map(e => ({
|
|
88
|
+
id: e.id,
|
|
89
|
+
label: e.canonical_name,
|
|
90
|
+
type: e.type,
|
|
91
|
+
tier: e.tier,
|
|
92
|
+
}));
|
|
93
|
+
// 获取所有关系
|
|
94
|
+
const edges = [];
|
|
95
|
+
for (const entity of entities.slice(0, 50)) {
|
|
96
|
+
const rels = indexManager.getRelationships(entity.id, 10);
|
|
97
|
+
for (const rel of rels) {
|
|
98
|
+
edges.push({
|
|
99
|
+
source: rel.from_entity,
|
|
100
|
+
target: rel.to_entity,
|
|
101
|
+
type: rel.type,
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
return { nodes, edges };
|
|
106
|
+
});
|
|
107
|
+
// 获取最近出场记录
|
|
108
|
+
fastify.get('/recent', async (request, _reply) => {
|
|
109
|
+
const query = request.query;
|
|
110
|
+
const indexManager = new IndexManager({ projectRoot });
|
|
111
|
+
const recent = indexManager.getRecentAppearances(query.limit || 20);
|
|
112
|
+
return {
|
|
113
|
+
entities: recent,
|
|
114
|
+
};
|
|
115
|
+
});
|
|
116
|
+
};
|
|
117
|
+
//# sourceMappingURL=entity.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"entity.js","sourceRoot":"","sources":["../../src/routes/entity.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Project Routes - 项目信息 API
|
|
3
|
+
*/
|
|
4
|
+
import type { FastifyPluginAsync } from 'fastify';
|
|
5
|
+
interface ProjectRoutesOptions {
|
|
6
|
+
projectRoot: string;
|
|
7
|
+
}
|
|
8
|
+
export declare const projectRoutes: FastifyPluginAsync<ProjectRoutesOptions>;
|
|
9
|
+
export {};
|
|
10
|
+
//# sourceMappingURL=project.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"project.d.ts","sourceRoot":"","sources":["../../src/routes/project.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,SAAS,CAAC;AAGlD,UAAU,oBAAoB;IAC5B,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,eAAO,MAAM,aAAa,EAAE,kBAAkB,CAAC,oBAAoB,CA4FlE,CAAC"}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { StateManager } from '@changw98ic/data';
|
|
2
|
+
export const projectRoutes = async (fastify, options) => {
|
|
3
|
+
const { projectRoot } = options;
|
|
4
|
+
// 获取项目信息
|
|
5
|
+
fastify.get('/info', async (_request, reply) => {
|
|
6
|
+
const stateManager = new StateManager({ projectRoot });
|
|
7
|
+
if (!stateManager.exists()) {
|
|
8
|
+
return reply.code(404).send({ error: 'Project not initialized' });
|
|
9
|
+
}
|
|
10
|
+
const state = await stateManager.loadState();
|
|
11
|
+
return {
|
|
12
|
+
title: state.project_info.title,
|
|
13
|
+
genre: state.project_info.genre,
|
|
14
|
+
target_words: state.project_info.target_words,
|
|
15
|
+
target_chapters: state.project_info.target_chapters,
|
|
16
|
+
current_chapter: state.progress.current_chapter,
|
|
17
|
+
total_words: state.progress.total_words,
|
|
18
|
+
created_at: state.project_info.created_at,
|
|
19
|
+
};
|
|
20
|
+
});
|
|
21
|
+
// 获取进度信息
|
|
22
|
+
fastify.get('/progress', async (_request, reply) => {
|
|
23
|
+
const stateManager = new StateManager({ projectRoot });
|
|
24
|
+
if (!stateManager.exists()) {
|
|
25
|
+
return reply.code(404).send({ error: 'Project not initialized' });
|
|
26
|
+
}
|
|
27
|
+
const state = await stateManager.loadState();
|
|
28
|
+
return {
|
|
29
|
+
current_chapter: state.progress.current_chapter,
|
|
30
|
+
total_words: state.progress.total_words,
|
|
31
|
+
completed_chapters: state.progress.completed_chapters || 0,
|
|
32
|
+
progress_percent: state.project_info.target_chapters
|
|
33
|
+
? Math.round((state.progress.current_chapter / state.project_info.target_chapters) * 100)
|
|
34
|
+
: 0,
|
|
35
|
+
};
|
|
36
|
+
});
|
|
37
|
+
// 获取主角状态
|
|
38
|
+
fastify.get('/protagonist', async (_request, reply) => {
|
|
39
|
+
const stateManager = new StateManager({ projectRoot });
|
|
40
|
+
if (!stateManager.exists()) {
|
|
41
|
+
return reply.code(404).send({ error: 'Project not initialized' });
|
|
42
|
+
}
|
|
43
|
+
const state = await stateManager.loadState();
|
|
44
|
+
return state.protagonist_state || {};
|
|
45
|
+
});
|
|
46
|
+
// 获取伏笔
|
|
47
|
+
fastify.get('/foreshadowing', async (_request, reply) => {
|
|
48
|
+
const stateManager = new StateManager({ projectRoot });
|
|
49
|
+
if (!stateManager.exists()) {
|
|
50
|
+
return reply.code(404).send({ error: 'Project not initialized' });
|
|
51
|
+
}
|
|
52
|
+
const state = await stateManager.loadState();
|
|
53
|
+
const foreshadowing = state.plot_threads?.foreshadowing || [];
|
|
54
|
+
return {
|
|
55
|
+
active: foreshadowing.filter((f) => f.status === 'active'),
|
|
56
|
+
resolved: foreshadowing.filter((f) => f.status === 'resolved'),
|
|
57
|
+
total: foreshadowing.length,
|
|
58
|
+
};
|
|
59
|
+
});
|
|
60
|
+
// 获取 Strand Tracker
|
|
61
|
+
fastify.get('/strands', async (_request, reply) => {
|
|
62
|
+
const stateManager = new StateManager({ projectRoot });
|
|
63
|
+
if (!stateManager.exists()) {
|
|
64
|
+
return reply.code(404).send({ error: 'Project not initialized' });
|
|
65
|
+
}
|
|
66
|
+
const state = await stateManager.loadState();
|
|
67
|
+
return {
|
|
68
|
+
entries: state.strand_tracker?.entries || [],
|
|
69
|
+
quest_consecutive: state.strand_tracker?.quest_consecutive || 0,
|
|
70
|
+
fire_gap: state.strand_tracker?.fire_gap || 0,
|
|
71
|
+
constellation_gap: state.strand_tracker?.constellation_gap || 0,
|
|
72
|
+
};
|
|
73
|
+
});
|
|
74
|
+
};
|
|
75
|
+
//# sourceMappingURL=project.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"project.js","sourceRoot":"","sources":["../../src/routes/project.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Stats Routes - 统计信息 API
|
|
3
|
+
*/
|
|
4
|
+
import type { FastifyPluginAsync } from 'fastify';
|
|
5
|
+
interface StatsRoutesOptions {
|
|
6
|
+
projectRoot: string;
|
|
7
|
+
}
|
|
8
|
+
export declare const statsRoutes: FastifyPluginAsync<StatsRoutesOptions>;
|
|
9
|
+
export {};
|
|
10
|
+
//# sourceMappingURL=stats.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stats.d.ts","sourceRoot":"","sources":["../../src/routes/stats.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,OAAO,KAAK,EAAE,kBAAkB,EAAgB,MAAM,SAAS,CAAC;AAGhE,UAAU,kBAAkB;IAC1B,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,eAAO,MAAM,WAAW,EAAE,kBAAkB,CAAC,kBAAkB,CAgK9D,CAAC"}
|