079project 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.
Files changed (67) hide show
  1. package/GroupStarter.cjs +647 -0
  2. package/LICENSE +165 -0
  3. package/PropagateSignalUseJsWorker.js +92 -0
  4. package/README.md +102 -0
  5. package/Redis-8.0.3-Windows-x64-cygwin-with-Service/README.md +52 -0
  6. package/Redis-8.0.3-Windows-x64-cygwin-with-Service/README.zh_CN.md +59 -0
  7. package/Redis-8.0.3-Windows-x64-cygwin-with-Service/RedisService.exe +0 -0
  8. package/Redis-8.0.3-Windows-x64-cygwin-with-Service/cygcrypto-3.dll +0 -0
  9. package/Redis-8.0.3-Windows-x64-cygwin-with-Service/cyggcc_s-seh-1.dll +0 -0
  10. package/Redis-8.0.3-Windows-x64-cygwin-with-Service/cygssl-3.dll +0 -0
  11. package/Redis-8.0.3-Windows-x64-cygwin-with-Service/cygstdc++-6.dll +0 -0
  12. package/Redis-8.0.3-Windows-x64-cygwin-with-Service/cygwin1.dll +0 -0
  13. package/Redis-8.0.3-Windows-x64-cygwin-with-Service/cygz.dll +0 -0
  14. package/Redis-8.0.3-Windows-x64-cygwin-with-Service/dump.rdb +0 -0
  15. package/Redis-8.0.3-Windows-x64-cygwin-with-Service/install_redis_service.bat +100 -0
  16. package/Redis-8.0.3-Windows-x64-cygwin-with-Service/redis-benchmark.exe +0 -0
  17. package/Redis-8.0.3-Windows-x64-cygwin-with-Service/redis-check-aof.exe +0 -0
  18. package/Redis-8.0.3-Windows-x64-cygwin-with-Service/redis-check-rdb.exe +0 -0
  19. package/Redis-8.0.3-Windows-x64-cygwin-with-Service/redis-cli.exe +0 -0
  20. package/Redis-8.0.3-Windows-x64-cygwin-with-Service/redis-full.conf +376 -0
  21. package/Redis-8.0.3-Windows-x64-cygwin-with-Service/redis-sentinel.exe +0 -0
  22. package/Redis-8.0.3-Windows-x64-cygwin-with-Service/redis-server.exe +0 -0
  23. package/Redis-8.0.3-Windows-x64-cygwin-with-Service/redis.conf +2348 -0
  24. package/Redis-8.0.3-Windows-x64-cygwin-with-Service/sentinel.conf +361 -0
  25. package/Redis-8.0.3-Windows-x64-cygwin-with-Service/start.bat +4 -0
  26. package/Redis-8.0.3-Windows-x64-cygwin-with-Service/uninstall_redis_service.bat +30 -0
  27. package/boot.py +51 -0
  28. package/chat_Client.js +29 -0
  29. package/controller.cjs +118 -0
  30. package/enhancedForwarder.js +378 -0
  31. package/forwarder.js +1456 -0
  32. package/groupmanager.cjs +143 -0
  33. package/howToStart.txt +8 -0
  34. package/lemma.csv +210 -0
  35. package/load.py +35 -0
  36. package/mainManager.cjs +81 -0
  37. package/mainStarter.cjs +535 -0
  38. package/main_Serve.cjs +2745 -0
  39. package/main_Study.cjs +3230 -0
  40. package/memeMergeWorker.cjs +55 -0
  41. package/model_RNN.py +117 -0
  42. package/note.txt +5 -0
  43. package/notebook.txt +8 -0
  44. package/npminstall-debug.log +206 -0
  45. package/package.json +48 -0
  46. package/public/chat_straight.html +90 -0
  47. package/public/index.html +247 -0
  48. package/public/indexmain.html +136 -0
  49. package/public/monitor.html +194 -0
  50. package/robots/wikitext-something.txt +25 -0
  51. package/runtime.proto +24 -0
  52. package/runtime_data.json +766294 -0
  53. package/serializer_seq2seq.h5 +0 -0
  54. package/start.js +46 -0
  55. package/tests/test_FIrststep1.txt +1224 -0
  56. package/tests/test_FIrststep2.txt +2956 -0
  57. package/tests/test_FIrststep3.txt +1224 -0
  58. package/tests/test_FIrststep4.txt +1396 -0
  59. package/tests/test_FIrststep5.txt +2852 -0
  60. package/tests/test_FIrststep6.txt +1516 -0
  61. package/tests/test_FirstStep7.txt +1748 -0
  62. package/tests/test_Firstsetp8.txt +2672 -0
  63. package/tokenizer.json +1 -0
  64. package/vocabularySplitter.js +253 -0
  65. package/wikitext/.gitattributes +27 -0
  66. package/wikitext/README.md +344 -0
  67. package/wikitext/describtion.txt +1 -0
@@ -0,0 +1,247 @@
1
+ <!doctype html>
2
+ <html lang="zh-CN">
3
+ <head>
4
+ <meta charset="utf-8" />
5
+ <title>Phoenix079 前端 Transformer(客户端序列化,后端提供词表)</title>
6
+ <meta name="viewport" content="width=device-width,initial-scale=1" />
7
+ <style>
8
+ body { font-family: system-ui, -apple-system, Segoe UI, Roboto, Arial; max-width: 980px; margin: 20px auto; padding: 0 12px; color:#222; }
9
+ textarea, input { width: 100%; box-sizing: border-box; padding: 8px; margin: 6px 0; }
10
+ button { padding: 8px 12px; margin: 4px 8px 4px 0; cursor: pointer; }
11
+ .row { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; }
12
+ .card { border: 1px solid #ddd; padding: 12px; border-radius: 6px; margin-top: 12px; background: #fafafa; }
13
+ pre { white-space: pre-wrap; word-wrap: break-word; }
14
+ .mono { font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", monospace; }
15
+ .muted { color:#666; }
16
+ </style>
17
+ <!-- 首选CDN(会再在脚本中做多CDN回退与按需动态加载) -->
18
+ <script src="https://cdn.jsdelivr.net/npm/@xenova/transformers@2.14.0/dist/transformers.min.js"></script>
19
+ </head>
20
+ <body>
21
+ <h2>Phoenix079 — 浏览器端 Transformer 串联(后端提供词表)</h2>
22
+ <p class="muted">流程:输入提示词 → 发送到后端 /api/chat → 获取词表 → 在本地 Transformer 串成句子(不回传)。下方仍保留 /api/corpus 语料拉取用于词表/观察。</p>
23
+
24
+ <div class="card">
25
+ <div class="row">
26
+ <label>语料抓取(/api/corpus):</label>
27
+ <label>max</label><input id="maxLines" type="number" min="10" step="100" value="1000" />
28
+ <label>groupStart</label><input id="gStart" type="number" min="0" step="1" value="0" />
29
+ <label>groupEnd</label><input id="gEnd" type="number" min="0" step="1" value="10" />
30
+ <button id="fetchCorpusBtn">拉取语料</button>
31
+ </div>
32
+ <pre id="corpusInfo" class="mono">(未加载)</pre>
33
+ <textarea id="corpusSample" rows="6" placeholder="拉取后显示部分样本(最多50行预览)"></textarea>
34
+ </div>
35
+
36
+ <div class="card">
37
+ <label>提示词输入(每行或空格分隔):</label>
38
+ <textarea id="promptInput" rows="6" placeholder="apple banana orange&#10;fast lightweight transformer"></textarea>
39
+ <div class="row">
40
+ <button id="loadModelBtn">加载模型(DistilGPT2)</button>
41
+ <span>模型状态:<span id="modelStatus" class="mono">未加载</span></span>
42
+ </div>
43
+
44
+ <div class="row">
45
+ <button id="requestBackendBtn">发送提示词到后端,获取词表(/api/chat)</button>
46
+ <button id="composeBtn">用前端 Transformer 将词表串成句子</button>
47
+ <button id="clearBtn">清空</button>
48
+ </div>
49
+
50
+ <div class="card">
51
+ <strong>后端返回的词表(若后端未直接提供,则由前端从返回文本中提取)</strong>
52
+ <textarea id="vocabBox" rows="6" placeholder="词表每行一个,可手动编辑"></textarea>
53
+ <div class="muted">说明:优先使用后端返回的字段 words / vocab;若没有,则从 responses 中提取高频词(客户端去停用词、规范化)。</div>
54
+ </div>
55
+
56
+ <div class="card">
57
+ <strong>客户端生成结果(不回传)</strong>
58
+ <pre id="clientOut" class="mono">(未生成)</pre>
59
+ </div>
60
+
61
+ <div class="card">
62
+ <strong>后端原始响应(调试)</strong>
63
+ <pre id="backendRaw" class="mono">(未请求)</pre>
64
+ </div>
65
+ </div>
66
+
67
+ <script>
68
+ // ——— 保障:按需加载 transformers(多CDN回退) ———
69
+ async function ensureTransformersLoaded() {
70
+ if (window.transformers) return window.transformers;
71
+ const cdns = [
72
+ 'https://cdn.jsdelivr.net/npm/@xenova/transformers@2.14.0/dist/transformers.min.js',
73
+ 'https://unpkg.com/@xenova/transformers@2.14.0/dist/transformers.min.js',
74
+ 'https://cdn.jsdelivr.net/npm/@xenova/transformers/dist/transformers.min.js'
75
+ ];
76
+ for (const url of cdns) {
77
+ try {
78
+ await new Promise((resolve, reject) => {
79
+ const s = document.createElement('script');
80
+ s.src = url; s.async = true;
81
+ s.onload = () => resolve();
82
+ s.onerror = () => reject(new Error('load failed: ' + url));
83
+ document.head.appendChild(s);
84
+ });
85
+ if (window.transformers) return window.transformers;
86
+ } catch (_) {}
87
+ }
88
+ throw new Error('无法加载 transformers.js,请检查网络/CDN。');
89
+ }
90
+
91
+ // ——— 小工具:文本→词,简单停用词过滤 ———
92
+ const STOP = new Set(('a,an,the,of,for,to,in,on,at,by,from,with,as,about,above,after,against,all,' +
93
+ 'am,are,is,was,were,be,been,being,do,does,did,doing,have,has,had,having,not,no,nor,only,or,' +
94
+ 'and,any,then,than,that,this,these,those,there,here,very,once,over,into,down,up,out,off,own,' +
95
+ 'so,too,can,could,should,would,will,shall,must,may,might,you,your,yours,me,my,mine,we,our,' +
96
+ 'they,their,them,he,she,it,its,his,her,who,whom,which,what,when,where,why,how').split(','));
97
+ function tokenize(s) {
98
+ return (s || '')
99
+ .toLowerCase()
100
+ .replace(/[^a-z0-9_\-\u4e00-\u9fa5\s]/g, ' ')
101
+ .split(/\s+/)
102
+ .filter(w => w && !STOP.has(w));
103
+ }
104
+ function topKWords(texts, k = 32) {
105
+ const freq = new Map();
106
+ for (const t of texts) {
107
+ for (const w of tokenize(t)) freq.set(w, (freq.get(w) || 0) + 1);
108
+ }
109
+ return [...freq.entries()].sort((a,b)=>b[1]-a[1]).slice(0,k).map(([w])=>w);
110
+ }
111
+ function normalizeListBox(text) {
112
+ return text.split(/\r?\n/).map(s => s.trim()).filter(Boolean);
113
+ }
114
+
115
+ // ——— 模型加载与生成 ———
116
+ let pipelineInstance = null;
117
+ async function loadModel() {
118
+ const lib = await ensureTransformersLoaded();
119
+ const { pipeline, env } = lib;
120
+ // 加速配置
121
+ try {
122
+ env.useBrowserCache = true;
123
+ if ('gpu' in navigator) env.useWebGPU = true;
124
+ // WebAssembly 线程数可按需设置(由 transformers 内部选择执行后端)
125
+ } catch(_) {}
126
+ const status = document.getElementById('modelStatus');
127
+ status.textContent = '加载中...(首次较慢)';
128
+ pipelineInstance = await pipeline('text-generation', 'Xenova/distilgpt2'); // 可改为 T5-small:text2text-generation
129
+ status.textContent = '已加载 DistilGPT2';
130
+ }
131
+
132
+ async function composeSentenceFromVocab(vocab) {
133
+ if (!pipelineInstance) throw new Error('模型未加载');
134
+ if (!vocab || vocab.length === 0) return '';
135
+ // 用词表构造提示,引导生成自然句
136
+ const prompt = 'Compose one fluent sentence using as many of these words as possible: ' + vocab.join(', ') + '. Sentence: ';
137
+ const out = await pipelineInstance(prompt, {
138
+ max_new_tokens: 48,
139
+ temperature: 0.8,
140
+ top_k: 50,
141
+ top_p: 0.95,
142
+ do_sample: true
143
+ });
144
+ const text = (Array.isArray(out) && out[0]?.generated_text) ? out[0].generated_text : String(out);
145
+ const idx = text.indexOf('Sentence: ');
146
+ return idx >= 0 ? text.slice(idx + 'Sentence: '.length).trim() : text.trim();
147
+ }
148
+
149
+ // ——— /api/corpus 拉取(保留) ———
150
+ document.getElementById('fetchCorpusBtn').addEventListener('click', async () => {
151
+ const maxLines = parseInt(document.getElementById('maxLines').value, 10) || 1000;
152
+ const gStart = parseInt(document.getElementById('gStart').value, 10) || 0;
153
+ const gEnd = parseInt(document.getElementById('gEnd').value, 10) || 10;
154
+ const url = `/api/corpus?max=${maxLines}&groupStart=${gStart}&groupEnd=${gEnd}&format=ndjson`;
155
+
156
+ try {
157
+ const res = await fetch(url);
158
+ if (!res.ok) throw new Error('HTTP ' + res.status);
159
+ const reader = res.body.getReader();
160
+ const decoder = new TextDecoder();
161
+ let received = 0, groups = new Set();
162
+ const firstLines = [];
163
+ while (true) {
164
+ const { value, done } = await reader.read();
165
+ if (done) break;
166
+ const txt = decoder.decode(value, { stream: true });
167
+ const lines = txt.split('\n').filter(Boolean);
168
+ for (const l of lines) {
169
+ try {
170
+ const obj = JSON.parse(l);
171
+ groups.add(obj.g);
172
+ received++;
173
+ if (firstLines.length < 50) firstLines.push(obj.t);
174
+ } catch {}
175
+ }
176
+ }
177
+ document.getElementById('corpusInfo').textContent = `收到行数: ${received}, 覆盖组: ${groups.size}`;
178
+ document.getElementById('corpusSample').value = firstLines.join('\n');
179
+ } catch (e) {
180
+ document.getElementById('corpusInfo').textContent = '拉取失败: ' + e.message;
181
+ }
182
+ });
183
+
184
+ // ——— 模型加载按钮 ———
185
+ document.getElementById('loadModelBtn').addEventListener('click', async () => {
186
+ try { await loadModel(); } catch (e) {
187
+ document.getElementById('modelStatus').textContent = '加载失败: ' + e.message;
188
+ }
189
+ });
190
+
191
+ // ——— 请求后端词表:发送提示词到 /api/chat ———
192
+ document.getElementById('requestBackendBtn').addEventListener('click', async () => {
193
+ const promptText = document.getElementById('promptInput').value.trim();
194
+ if (!promptText) {
195
+ alert('请先输入提示词');
196
+ return;
197
+ }
198
+ try {
199
+ const resp = await fetch('/api/chat', {
200
+ method: 'POST',
201
+ headers: { 'Content-Type': 'application/json' },
202
+ body: JSON.stringify({ message: promptText })
203
+ });
204
+ const data = await resp.json();
205
+ document.getElementById('backendRaw').textContent = JSON.stringify(data, null, 2);
206
+
207
+ // 优先使用后端直接提供的词表字段(若存在)
208
+ let vocab = [];
209
+ if (Array.isArray(data.words)) {
210
+ vocab = data.words.map(String);
211
+ } else if (Array.isArray(data.vocab)) {
212
+ vocab = data.vocab.map(String);
213
+ } else {
214
+ // 后端未直接给词表:从 responses 中提取高频词
215
+ const texts =
216
+ Array.isArray(data.responses)
217
+ ? data.responses.map(x => typeof x === 'string' ? x : (x && x.response) || '').filter(Boolean)
218
+ : (data.top ? [data.top] : []);
219
+ vocab = topKWords(texts, 32);
220
+ }
221
+ document.getElementById('vocabBox').value = vocab.join('\n');
222
+ } catch (e) {
223
+ document.getElementById('backendRaw').textContent = '请求失败: ' + e.message;
224
+ }
225
+ });
226
+
227
+ // ——— 用前端 Transformer 将词表串为句子(不回传) ———
228
+ document.getElementById('composeBtn').addEventListener('click', async () => {
229
+ const vocab = normalizeListBox(document.getElementById('vocabBox').value);
230
+ try {
231
+ const sentence = await composeSentenceFromVocab(vocab);
232
+ document.getElementById('clientOut').textContent = sentence || '(空)';
233
+ } catch (e) {
234
+ document.getElementById('clientOut').textContent = '失败: ' + e.message;
235
+ }
236
+ });
237
+
238
+ // ——— 清空 ———
239
+ document.getElementById('clearBtn').addEventListener('click', () => {
240
+ document.getElementById('promptInput').value = '';
241
+ document.getElementById('vocabBox').value = '';
242
+ document.getElementById('clientOut').textContent = '(未生成)';
243
+ document.getElementById('backendRaw').textContent = '(未请求)';
244
+ });
245
+ </script>
246
+ </body>
247
+ </html>
@@ -0,0 +1,136 @@
1
+ <!DOCTYPE html>
2
+ <html lang="zh-CN">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
+ <title>AGI 多模态编排入口</title>
7
+ <style>
8
+ body{font-family:system-ui,-apple-system,Segoe UI,Roboto,Helvetica,Arial;line-height:1.5;margin:0;background:#0b1220;color:#e6edf3}
9
+ header{padding:16px 20px;border-bottom:1px solid #23304a}
10
+ main{padding:20px;max-width:980px;margin:0 auto}
11
+ .card{background:#111a2e;border:1px solid #23304a;border-radius:10px;padding:16px;margin-bottom:16px}
12
+ label{display:block;font-size:13px;opacity:.85;margin:6px 0}
13
+ input,select,textarea{width:100%;box-sizing:border-box;padding:10px;border-radius:8px;border:1px solid #32415f;background:#0e1728;color:#e6edf3}
14
+ textarea{min-height:90px}
15
+ .row{display:flex;gap:12px;flex-wrap:wrap}
16
+ .col{flex:1 1 300px}
17
+ button{background:#347dff;border:none;color:white;padding:10px 14px;border-radius:8px;cursor:pointer}
18
+ button:hover{background:#1960ff}
19
+ pre{white-space:pre-wrap;background:#0a0f1c;border:1px solid #23304a;padding:12px;border-radius:8px}
20
+ .hint{font-size:12px;opacity:.8}
21
+ .api-url{font-family:ui-monospace,Consolas,"SF Mono",Menlo,monospace}
22
+ </style>
23
+ </head>
24
+ <body>
25
+ <header>
26
+ <h2>AGI 多模态编排入口</h2>
27
+ <div class="hint">目标:支持文本/图片URL/音频URL混合输入,并可指定输出类型(text/image/audio)。</div>
28
+ </header>
29
+ <main>
30
+ <div class="card">
31
+ <div class="row">
32
+ <div class="col">
33
+ <label>文本输入</label>
34
+ <textarea id="text" placeholder="在此输入文本(可选)"></textarea>
35
+ </div>
36
+ <div class="col">
37
+ <label>图片 URL</label>
38
+ <input id="imageUrl" placeholder="https://...(可选)" />
39
+ <label>音频 URL</label>
40
+ <input id="audioUrl" placeholder="https://...(可选)" />
41
+ </div>
42
+ </div>
43
+ <div class="row">
44
+ <div class="col">
45
+ <label>目标输出类型</label>
46
+ <select id="target">
47
+ <option value="text">text</option>
48
+ <option value="image">image</option>
49
+ <option value="audio">audio</option>
50
+ </select>
51
+ </div>
52
+ <div class="col">
53
+ <label>&nbsp;</label>
54
+ <button id="go">转换 / Convert</button>
55
+ </div>
56
+ </div>
57
+ <div class="row">
58
+ <div class="col">
59
+ <div class="hint">API:<span class="api-url" id="api">/api/agi/convert</span></div>
60
+ </div>
61
+ </div>
62
+ </div>
63
+
64
+ <div class="card">
65
+ <h3>结果</h3>
66
+ <pre id="out">尚无结果</pre>
67
+ </div>
68
+
69
+ <div class="card">
70
+ <h3>快速直连(9 个 API)</h3>
71
+ <div class="hint">用于排错或独立测试,字段含义请参阅服务端日志</div>
72
+ <div class="row">
73
+ <div class="col">
74
+ <button data-endpoint="/api/agi/chat-text">chat-text</button>
75
+ <button data-endpoint="/api/agi/chat-image">chat-image</button>
76
+ <button data-endpoint="/api/agi/chat-audio">chat-audio</button>
77
+ </div>
78
+ <div class="col">
79
+ <button data-endpoint="/api/agi/text-to-image">text-to-image</button>
80
+ <button data-endpoint="/api/agi/image-to-text">image-to-text</button>
81
+ <button data-endpoint="/api/agi/text-to-audio">text-to-audio</button>
82
+ <button data-endpoint="/api/agi/audio-to-text">audio-to-text</button>
83
+ <button data-endpoint="/api/agi/image-to-audio">image-to-audio</button>
84
+ <button data-endpoint="/api/agi/audio-to-image">audio-to-image</button>
85
+ </div>
86
+ </div>
87
+ </div>
88
+ </main>
89
+ <script>
90
+ const out = document.getElementById('out');
91
+ const api = document.getElementById('api');
92
+ const text = document.getElementById('text');
93
+ const imageUrl = document.getElementById('imageUrl');
94
+ const audioUrl = document.getElementById('audioUrl');
95
+ const target = document.getElementById('target');
96
+
97
+ function show(obj){ out.textContent = JSON.stringify(obj, null, 2); }
98
+
99
+ async function post(endpoint, body){
100
+ const r = await fetch(endpoint, { method:'POST', headers:{'Content-Type':'application/json'}, body: JSON.stringify(body) });
101
+ const j = await r.json();
102
+ return j;
103
+ }
104
+
105
+ document.getElementById('go').addEventListener('click', async ()=>{
106
+ api.textContent = '/api/agi/convert';
107
+ try{
108
+ const body = { text: text.value.trim() || undefined, imageUrl: imageUrl.value.trim() || undefined, audioUrl: audioUrl.value.trim() || undefined, target: target.value };
109
+ const j = await post('/api/agi/convert', body);
110
+ show(j);
111
+ }catch(e){ show({ ok:false, error: String(e) }); }
112
+ });
113
+
114
+ document.querySelectorAll('button[data-endpoint]').forEach(btn=>{
115
+ btn.addEventListener('click', async ()=>{
116
+ const ep = btn.getAttribute('data-endpoint');
117
+ api.textContent = ep;
118
+ let body = {};
119
+ const t = text.value.trim(); const iu = imageUrl.value.trim(); const au = audioUrl.value.trim();
120
+ switch(ep){
121
+ case '/api/agi/chat-text': body = { message: t || 'hello' }; break;
122
+ case '/api/agi/chat-image': body = { imageUrl: iu || undefined, message: t || '' }; break;
123
+ case '/api/agi/chat-audio': body = { audioUrl: au || undefined, message: t || '' }; break;
124
+ case '/api/agi/text-to-image': body = { text: t || 'a cat' }; break;
125
+ case '/api/agi/image-to-text': body = { imageUrl: iu || 'https://example.com/img.jpg', imageHint: t || '' }; break;
126
+ case '/api/agi/text-to-audio': body = { text: t || 'hello world' }; break;
127
+ case '/api/agi/audio-to-text': body = { audioUrl: au || 'https://example.com/a.wav', hint: t || '' }; break;
128
+ case '/api/agi/image-to-audio': body = { imageUrl: iu || 'https://example.com/img.jpg', imageHint: t || '' }; break;
129
+ case '/api/agi/audio-to-image': body = { audioUrl: au || 'https://example.com/a.wav', hint: t || '' }; break;
130
+ }
131
+ try{ const j = await post(ep, body); show(j); } catch(e){ show({ ok:false, error:String(e) }); }
132
+ })
133
+ });
134
+ </script>
135
+ </body>
136
+ </html>
@@ -0,0 +1,194 @@
1
+ <!doctype html>
2
+ <html lang="zh-CN">
3
+ <head>
4
+ <meta charset="utf-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
6
+ <title>资源监控 - 时序曲线</title>
7
+ <style>
8
+ body { font-family: system-ui, -apple-system, Segoe UI, Roboto, Arial, "Noto Sans", sans-serif; margin: 0; color: #222; }
9
+ header { display:flex; align-items:center; justify-content: space-between; padding: 12px 16px; border-bottom: 1px solid #eee; position: sticky; top: 0; background: #fff; z-index: 1; }
10
+ .controls { display:flex; gap: 12px; flex-wrap: wrap; }
11
+ .control { display:flex; align-items:center; gap: 6px; }
12
+ .container { padding: 12px 16px; }
13
+ .cards { display:grid; grid-template-columns: repeat(auto-fill, minmax(360px, 1fr)); gap: 16px; }
14
+ .card { border: 1px solid #eee; border-radius: 10px; padding: 12px; box-shadow: 0 1px 2px rgba(0,0,0,.04); }
15
+ .hint { color:#666; font-size: 12px; }
16
+ canvas { width: 100%; height: 280px; }
17
+ footer { padding: 16px; color:#777; font-size:12px; text-align:center; }
18
+ .badge { padding: 2px 6px; border-radius: 999px; background:#f3f4f6; font-size:12px; }
19
+ </style>
20
+ </head>
21
+ <body>
22
+ <header>
23
+ <div>
24
+ <strong>资源监控</strong>
25
+ <span class="badge" id="swap-badge" title="内存应急模式">swap: off</span>
26
+ </div>
27
+ <div class="controls">
28
+ <label class="control">
29
+ 指标
30
+ <select id="series-select" multiple size="3">
31
+ <option value="cpu" selected>CPU</option>
32
+ <option value="mem" selected>内存</option>
33
+ <option value="gpu">GPU利用率</option>
34
+ </select>
35
+ </label>
36
+ <label class="control">
37
+ 刷新(ms)
38
+ <input id="refresh" type="number" min="250" step="250" value="1000" />
39
+ </label>
40
+ <label class="control">
41
+ 窗口(点数)
42
+ <input id="window" type="number" min="30" step="10" value="300" />
43
+ </label>
44
+ <label class="control" title="指数滑动平均,0=无平滑,0.8更平滑">
45
+ 平滑α
46
+ <input id="smoothing" type="number" min="0" max="0.95" step="0.05" value="0.2" />
47
+ </label>
48
+ <button id="pause">暂停</button>
49
+ </div>
50
+ </header>
51
+ <div class="container">
52
+ <div class="cards">
53
+ <div class="card">
54
+ <div class="hint">CPU/内存/GPU 时序曲线</div>
55
+ <canvas id="chart"></canvas>
56
+ </div>
57
+ <div class="card">
58
+ <div class="hint">磁盘/显卡 详情</div>
59
+ <pre id="meta" style="white-space: pre-wrap; font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; font-size:12px; line-height:1.4; max-height: 320px; overflow:auto;">—</pre>
60
+ </div>
61
+ </div>
62
+ </div>
63
+ <footer>提供 /api/metrics 时序数据 · 可配置刷新/窗口/平滑 · 绿色=CPU 蓝色=内存 橙色=GPU</footer>
64
+
65
+ <script src="https://cdn.jsdelivr.net/npm/chart.js@4.4.3/dist/chart.umd.min.js"></script>
66
+ <script>
67
+ const el = (id) => document.getElementById(id);
68
+ let timer = null;
69
+ let paused = false;
70
+ const state = {
71
+ alpha: 0.2, // EMA smoothing
72
+ window: 300,
73
+ series: new Set(['cpu','mem']),
74
+ };
75
+
76
+ function ema(prev, cur, alpha) {
77
+ if (prev == null) return cur;
78
+ return alpha * cur + (1 - alpha) * prev;
79
+ }
80
+
81
+ function fmtPct(x) { return (x * 100).toFixed(1) + '%'; }
82
+
83
+ const ctx = el('chart').getContext('2d');
84
+ const chart = new Chart(ctx, {
85
+ type: 'line',
86
+ data: {
87
+ labels: [],
88
+ datasets: [
89
+ { label: 'CPU', data: [], borderColor: '#16a34a', backgroundColor: 'rgba(22,163,74,.15)', tension: .2 },
90
+ { label: '内存', data: [], borderColor: '#2563eb', backgroundColor: 'rgba(37,99,235,.15)', tension: .2 },
91
+ { label: 'GPU', data: [], borderColor: '#f59e0b', backgroundColor: 'rgba(245,158,11,.15)', tension: .2 },
92
+ ],
93
+ },
94
+ options: {
95
+ responsive: true,
96
+ animation: false,
97
+ interaction: { mode: 'index', intersect: false },
98
+ stacked: false,
99
+ scales: {
100
+ y: { min: 0, max: 1, ticks: { callback: (v) => (v*100|0)+'%' } },
101
+ x: { ticks: { maxRotation: 0 } }
102
+ },
103
+ plugins: { legend: { display: true } },
104
+ },
105
+ });
106
+
107
+ async function pull() {
108
+ try {
109
+ const r = await fetch('/api/metrics');
110
+ if (!r.ok) return;
111
+ const m = await r.json();
112
+ const { ts, cpu, mem, gpu, disk, swapActive } = m;
113
+ el('swap-badge').textContent = 'swap: ' + (swapActive ? 'on' : 'off');
114
+ el('swap-badge').style.background = swapActive ? '#fee2e2' : '#f3f4f6';
115
+
116
+ const labels = ts.map(t => new Date(t).toLocaleTimeString());
117
+ const clamp = (arr) => arr.slice(-state.window);
118
+ const smooth = (arr) => {
119
+ if (state.alpha <= 0) return arr;
120
+ const out = [];
121
+ let prev = null;
122
+ for (const v of arr) { prev = ema(prev, v, state.alpha); out.push(prev); }
123
+ return out;
124
+ }
125
+
126
+ chart.data.labels = clamp(labels);
127
+
128
+ // CPU
129
+ chart.data.datasets[0].hidden = !state.series.has('cpu');
130
+ chart.data.datasets[0].data = smooth(clamp(cpu || []));
131
+
132
+ // MEM
133
+ chart.data.datasets[1].hidden = !state.series.has('mem');
134
+ chart.data.datasets[1].data = smooth(clamp(mem || []));
135
+
136
+ // GPU: 取第一个GPU的util
137
+ const gpuSeries = (gpu && gpu.length) ? new Array((ts||[]).length).fill(0).map((_, i) => {
138
+ const g = gpu[gpu.length-1] || { util: 0 };
139
+ return g.util || 0;
140
+ }) : [];
141
+ chart.data.datasets[2].hidden = !state.series.has('gpu');
142
+ chart.data.datasets[2].data = smooth(clamp(gpuSeries));
143
+
144
+ chart.update();
145
+
146
+ // meta
147
+ const meta = [];
148
+ meta.push(`CPU: ${cpu && cpu.length ? fmtPct(cpu.at(-1)) : '—'} 内存: ${mem && mem.length ? fmtPct(mem.at(-1)) : '—'} GPU: ${gpu && gpu.length ? fmtPct((gpu.at(-1).util||0)) : '—'}`);
149
+ if (disk && Array.isArray(disk) && disk.length) {
150
+ meta.push('\n磁盘:');
151
+ for (const d of disk) {
152
+ meta.push(`- ${d.drive}: ${(d.free/1024/1024/1024).toFixed(1)} GiB free / ${(d.total/1024/1024/1024).toFixed(1)} GiB`);
153
+ }
154
+ }
155
+ if (gpu && Array.isArray(gpu) && gpu.length) {
156
+ meta.push('\n显卡:');
157
+ for (let i=0;i<gpu.length;i++) {
158
+ const g = gpu[i];
159
+ meta.push(`- GPU${i}: util=${fmtPct(g.util||0)} mem=${(g.memUsed/1024/1024|0)}MB / ${(g.memTotal/1024/1024|0)}MB`);
160
+ }
161
+ }
162
+ el('meta').textContent = meta.join('\n');
163
+ } catch (e) {
164
+ // ignore
165
+ }
166
+ }
167
+
168
+ function restartTimer() {
169
+ if (timer) clearInterval(timer);
170
+ const ms = Math.max(250, parseInt(el('refresh').value || '1000', 10));
171
+ timer = setInterval(() => { if (!paused) pull(); }, ms);
172
+ }
173
+
174
+ el('smoothing').addEventListener('change', () => {
175
+ const v = Math.max(0, Math.min(0.95, Number(el('smoothing').value)));
176
+ state.alpha = v;
177
+ });
178
+ el('window').addEventListener('change', () => {
179
+ const v = Math.max(30, Number(el('window').value));
180
+ state.window = v;
181
+ });
182
+ el('refresh').addEventListener('change', () => restartTimer());
183
+ el('pause').addEventListener('click', () => { paused = !paused; el('pause').textContent = paused ? '继续' : '暂停'; });
184
+ el('series-select').addEventListener('change', () => {
185
+ const sel = el('series-select');
186
+ state.series = new Set([...sel.options].filter(o => o.selected).map(o => o.value));
187
+ });
188
+
189
+ // 初始
190
+ pull();
191
+ restartTimer();
192
+ </script>
193
+ </body>
194
+ </html>
@@ -0,0 +1,25 @@
1
+
2
+ As with previous Valkyira Chronicles games , Valkyria Chronicles III is a tactical role @-@ playing game where players take control of a military unit and take part in missions against enemy forces . Stories are told through comic book @-@ like panels with animated character portraits , with characters speaking partially through voiced speech bubbles and partially through unvoiced text . The player progresses through a series of linear missions , gradually unlocked as maps that can be freely scanned through and replayed as they are unlocked . The route to each story location on the map varies depending on an individual player 's approach : when one option is selected , the other is sealed off to the player . Outside missions , the player characters rest in a camp , where units can be customized and character growth occurs . Alongside the main story missions are character @-@ specific sub missions relating to different squad members . After the game 's completion , additional episodes are unlocked , some of them having a higher difficulty than those found in the rest of the game . There are also love simulation elements related to the game 's two main heroines , although they take a very minor role .
3
+
4
+ The game 's battle system , the BliTZ system , is carried over directly from Valkyira Chronicles . During missions , players select each unit using a top @-@ down perspective of the battlefield map : once a character is selected , the player moves the character around the battlefield in third @-@ person . A character can only act once per @-@ turn , but characters can be granted multiple turns at the expense of other characters ' turns . Each character has a field and distance of movement limited by their Action Gauge . Up to nine characters can be assigned to a single mission . During gameplay , characters will call out if something happens to them , such as their health points ( HP ) getting low or being knocked out by enemy attacks . Each character has specific " Potentials " , skills unique to each character . They are divided into " Personal Potential " , which are innate skills that remain unaltered unless otherwise dictated by the story and can either help or impede a character , and " Battle Potentials " , which are grown throughout the game and always grant boons to a character . To learn Battle Potentials , each character has a unique " Masters Table " , a grid @-@ based skill table that can be used to acquire and link different skills . Characters also have Special Abilities that grant them temporary boosts on the battlefield : Kurt can activate " Direct Command " and move around the battlefield without depleting his Action Point gauge , the character Reila can shift into her " Valkyria Form " and become invincible , while Imca can target multiple enemy units with her heavy weapon .
5
+
6
+ Troops are divided into five classes : Scouts , Shocktroopers , Engineers , Lancers and Armored Soldier . Troopers can switch classes by changing their assigned weapon . Changing class does not greatly affect the stats gained while in a previous class . With victory in battle , experience points are awarded to the squad , which are distributed into five different attributes shared by the entire squad , a feature differing from early games ' method of distributing to different unit types .
7
+
8
+ = = Plot = =
9
+
10
+ The game takes place during the Second Europan War . Gallian Army Squad 422 , also known as " The Nameless " , are a penal military unit composed of criminals , foreign deserters , and military offenders whose real names are erased from the records and thereon officially referred to by numbers . Ordered by the Gallian military to perform the most dangerous missions that the Regular Army and Militia will not do , they are nevertheless up to the task , exemplified by their motto , Altaha Abilia , meaning " Always Ready . " The three main characters are No.7 Kurt Irving , an army officer falsely accused of treason who wishes to redeem himself ; Ace No.1 Imca , a female Darcsen heavy weapons specialist who seeks revenge against the Valkyria who destroyed her home ; and No.13 Riela Marcellis , a seemingly jinxed young woman who is unknowingly a descendant of the Valkyria . Together with their fellow squad members , these three are tasked to fight against a mysterious Imperial unit known as Calamity Raven , consisting of mostly Darcsen soldiers .
11
+
12
+ As the Nameless officially do not exist , the upper echelons of the Gallian Army exploit the concept of plausible deniability in order to send them on missions that would otherwise make Gallia lose face in the war . While at times this works to their advantage , such as a successful incursion into Imperial territory , other orders cause certain members of the 422nd great distress . One such member , Gusurg , becomes so enraged that he abandons his post and defects into the ranks of Calamity Raven , attached to the ideal of Darcsen independence proposed by their leader , Dahau . At the same time , elements within Gallian Army Command move to erase the Nameless in order to protect their own interests . Hounded by both allies and enemies , and combined with the presence of a traitor within their ranks , the 422nd desperately move to keep themselves alive while at the same time fight to help the Gallian war effort . This continues until the Nameless 's commanding officer , Ramsey Crowe , who had been kept under house arrest , is escorted to the capital city of Randgriz in order to present evidence exonerating the weary soldiers and expose the real traitor , the Gallian General that had accused Kurt of Treason .
13
+
14
+ Partly due to these events , and partly due to the major losses in manpower Gallia suffers towards the end of the war with the Empire , the Nameless are offered a formal position as a squad in the Gallian Army rather than serve as an anonymous shadow force . This is short @-@ lived , however , as following Maximilian 's defeat , Dahau and Calamity Raven move to activate an ancient Valkyrian super weapon within the Empire , kept secret by their benefactor . Without the support of Maximilian or the chance to prove themselves in the war with Gallia , it is Dahau 's last trump card in creating a new Darcsen nation . As an armed Gallian force invading the Empire just following the two nations ' cease @-@ fire would certainly wreck their newfound peace , Kurt decides to once again make his squad the Nameless , asking Crowe to list himself and all under his command as killed @-@ in @-@ action . Now owing allegiance to none other than themselves , the 422nd confronts Dahau and destroys the Valkyrian weapon . Each member then goes their separate ways in order to begin their lives anew .
15
+
16
+ = = Development = =
17
+
18
+ Concept work for Valkyria Chronicles III began after development finished on Valkyria Chronicles II in early 2010 , with full development beginning shortly after this . The director of Valkyria Chronicles II , Takeshi Ozawa , returned to that role for Valkyria Chronicles III . Development work took approximately one year . After the release of Valkyria Chronicles II , the staff took a look at both the popular response for the game and what they wanted to do next for the series . Like its predecessor , Valkyria Chronicles III was developed for PlayStation Portable : this was due to the team wanting to refine the mechanics created for Valkyria Chronicles II , and they had not come up with the " revolutionary " idea that would warrant a new entry for the PlayStation 3 . Speaking in an interview , it was stated that the development team considered Valkyria Chronicles III to be the series ' first true sequel : while Valkyria Chronicles II had required a large amount of trial and error during development due to the platform move , the third game gave them a chance to improve upon the best parts of Valkyria Chronicles II due to being on the same platform . In addition to Sega staff from the previous games , development work was also handled by Media.Vision. The original scenario was written Kazuki Yamanobe , while the script was written by Hiroyuki Fujii , Koichi Majima , Kishiko Miyagi , Seiki Nagakawa and Takayuki Shouji . Its story was darker and more somber than that of its predecessor .
19
+
20
+ The majority of material created for previous games , such as the BLiTZ system and the design of maps , was carried over . Alongside this , improvements were made to the game 's graphics and some elements were expanded , such as map layouts , mission structure , and the number of playable units per mission . A part of this upgrade involved creating unique polygon models for each character 's body . In order to achieve this , the cooperative elements incorporated into the second game were removed , as they took up a large portion of memory space needed for the improvements . They also adjusted the difficulty settings and ease of play so they could appeal to new players while retaining the essential components of the series ' gameplay . The newer systems were decided upon early in development . The character designs were done by Raita Honjou , who had worked on the previous Valkyria Chronicles games . When creating the Nameless Squad , Honjou was faced with the same problem he had had during the first game : the military uniforms essentially destroyed character individuality , despite him needing to create unique characters the player could identify while maintaining a sense of reality within the Valkyria Chronicles world . The main color of the Nameless was black . As with the previous Valkyria games , Valkyria Chronicles III used the CANVAS graphics engine . The anime opening was produced by Production I.G.
21
+
22
+ = = = Music = = =
23
+
24
+ The music was composed by Hitoshi Sakimoto , who had also worked on the previous Valkyria Chronicles games . When he originally heard about the project , he thought it would be a light tone similar to other Valkyria Chronicles games , but found the themes much darker than expected . An early theme he designed around his original vision of the project was rejected . He redid the main theme about seven times through the music production due to this need to reassess the game . The main theme was initially recorded using orchestra , then Sakimoto removed elements such as the guitar and bass , then adjusted the theme using a synthesizer before redoing segments such as the guitar piece on their own before incorporating them into the theme . The rejected main theme was used as a hopeful tune that played during the game 's ending . The battle themes were designed around the concept of a " modern battle " divorced from a fantasy scenario by using modern musical instruments , constructed to create a sense of atonality . While Sakimoto was most used to working with synthesized music , he felt that he needed to incorporate live instruments such as orchestra and guitar . The guitar was played by Mitsuhiro Ohta , who also arranged several of the later tracks . The game 's opening theme song , " If You Wish for ... " ( もしも君が願うのなら , Moshimo Kimi ga Negauno Nara ) , was sung by Japanese singer May 'n . Its theme was the reason soldiers fought , in particular their wish to protect what was precious to them rather than a sense of responsibility or duty . Its lyrics were written by Seiko Fujibayashi , who had worked on May 'n on previous singles .
25
+
package/runtime.proto ADDED
@@ -0,0 +1,24 @@
1
+ syntax = "proto3";
2
+ message Runtime {
3
+ repeated Meme memes = 1;
4
+ repeated WordGraphPoint wordGraph = 2;
5
+ repeated KVMEntry kvm = 3;
6
+ repeated string vocab = 4;
7
+ }
8
+ message Meme {
9
+ string pointID = 1;
10
+ repeated Connect connect = 2;
11
+ }
12
+ message Connect {
13
+ float weight = 1;
14
+ string pointID = 2;
15
+ int32 direction = 3;
16
+ }
17
+ message WordGraphPoint {
18
+ string pointID = 1;
19
+ repeated Connect connect = 2;
20
+ }
21
+ message KVMEntry {
22
+ string key = 1;
23
+ repeated string value = 2;
24
+ }