agens-studio 0.1.4 → 0.1.6
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/cli.js +77 -48
- package/package.json +1 -1
- package/src/services/agensClient.js +15 -3
package/cli.js
CHANGED
|
@@ -861,59 +861,88 @@ async function menuAssets() {
|
|
|
861
861
|
else if (c === '4') search = await ask('搜索关键词');
|
|
862
862
|
else if (c !== '1') { console.log(`${C.red}无效选择${C.reset}`); continue; }
|
|
863
863
|
|
|
864
|
-
const
|
|
864
|
+
const pageSize = 20;
|
|
865
|
+
let page = 1;
|
|
865
866
|
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
867
|
+
while (true) {
|
|
868
|
+
const { items, total } = await assetStore.listAssets({ type, search, page, pageSize });
|
|
869
|
+
const totalPages = Math.max(1, Math.ceil(total / pageSize));
|
|
870
|
+
const startIdx = (page - 1) * pageSize;
|
|
870
871
|
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
const note = a.note ? ` | ${a.note}` : '';
|
|
876
|
-
console.log(` ${C.cyan}${String(i + 1).padStart(2)}.${C.reset} ${icon} ${a.filename}`);
|
|
877
|
-
console.log(` ${C.gray}${prompt}${note}${C.reset}`);
|
|
878
|
-
console.log(` ${formatSize(a.size)} | ${fmtDate(a.createdAt)} | ${a.kept ? C.green + '保留' + C.reset : C.gray + '未保留' + C.reset}`);
|
|
879
|
-
});
|
|
872
|
+
if (items.length === 0) {
|
|
873
|
+
console.log(`\n${C.gray}暂无素材${total > 0 ? `(共 ${total} 条,当前页为空)` : ''}${C.reset}`);
|
|
874
|
+
break;
|
|
875
|
+
}
|
|
880
876
|
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
877
|
+
console.log(`\n${C.bold}共 ${total} 条素材(第 ${page}/${totalPages} 页):${C.reset}\n`);
|
|
878
|
+
items.forEach((a, i) => {
|
|
879
|
+
const globalIdx = startIdx + i + 1;
|
|
880
|
+
const icon = a.type === 'video' ? '🎬' : '🖼';
|
|
881
|
+
const prompt = (a.prompt || '').slice(0, 50);
|
|
882
|
+
const note = a.note ? ` | ${a.note}` : '';
|
|
883
|
+
console.log(` ${C.cyan}${String(globalIdx).padStart(3)}.${C.reset} ${icon} ${a.filename}`);
|
|
884
|
+
console.log(` ${C.gray}${prompt}${note}${C.reset}`);
|
|
885
|
+
console.log(` ${formatSize(a.size)} | ${fmtDate(a.createdAt)} | ${a.kept ? C.green + '保留' + C.reset : C.gray + '未保留' + C.reset}`);
|
|
886
|
+
});
|
|
887
887
|
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
await assetStore.
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
} else if (action === 3) {
|
|
913
|
-
if (await confirm(`确认删除 ${asset.filename}`)) {
|
|
914
|
-
await assetStore.deleteAsset(asset.id);
|
|
915
|
-
console.log(`${C.green}已删除${C.reset}`);
|
|
888
|
+
const navHints = [];
|
|
889
|
+
if (page < totalPages) navHints.push('n=下一页');
|
|
890
|
+
if (page > 1) navHints.push('p=上一页');
|
|
891
|
+
const navStr = navHints.length ? `(${navHints.join(',')})` : '';
|
|
892
|
+
|
|
893
|
+
console.log('');
|
|
894
|
+
const op = await ask(`输入序号查看详情${navStr},或回车返回`);
|
|
895
|
+
if (!op) break;
|
|
896
|
+
|
|
897
|
+
if (op.toLowerCase() === 'n' && page < totalPages) { page++; continue; }
|
|
898
|
+
if (op.toLowerCase() === 'p' && page > 1) { page--; continue; }
|
|
899
|
+
|
|
900
|
+
const num = parseInt(op, 10);
|
|
901
|
+
if (isNaN(num) || num < 1 || num > total) { console.log(`${C.red}无效序号(范围 1-${total})${C.reset}`); continue; }
|
|
902
|
+
|
|
903
|
+
const targetPage = Math.ceil(num / pageSize);
|
|
904
|
+
const localIdx = num - (targetPage - 1) * pageSize - 1;
|
|
905
|
+
let asset;
|
|
906
|
+
if (targetPage === page) {
|
|
907
|
+
asset = items[localIdx];
|
|
908
|
+
} else {
|
|
909
|
+
const nextPageData = await assetStore.listAssets({ type, search, page: targetPage, pageSize });
|
|
910
|
+
asset = nextPageData.items[localIdx];
|
|
911
|
+
page = targetPage;
|
|
916
912
|
}
|
|
913
|
+
if (asset) await showAssetDetail(asset);
|
|
914
|
+
}
|
|
915
|
+
}
|
|
916
|
+
}
|
|
917
|
+
|
|
918
|
+
async function showAssetDetail(asset) {
|
|
919
|
+
const absPath = path.join(config.dirs.root, asset.path);
|
|
920
|
+
console.log(`\n${C.bold}素材详情:${C.reset}`);
|
|
921
|
+
console.log(` ID:${asset.id}`);
|
|
922
|
+
console.log(` 文件:${absPath}`);
|
|
923
|
+
console.log(` 提示词:${asset.prompt || '(无)'}`);
|
|
924
|
+
console.log(` 模式:${asset.mode || '(无)'}`);
|
|
925
|
+
console.log(` 大小:${formatSize(asset.size)}`);
|
|
926
|
+
console.log(` 创建:${fmtDate(asset.createdAt)}`);
|
|
927
|
+
console.log(` 保留:${asset.kept ? '是' : '否'}`);
|
|
928
|
+
if (asset.note) console.log(` 备注:${asset.note}`);
|
|
929
|
+
|
|
930
|
+
const action = await choose('操作', ['打开文件', '切换保留状态', '添加备注', '删除']);
|
|
931
|
+
if (action === 0) {
|
|
932
|
+
openFile(absPath);
|
|
933
|
+
} else if (action === 1) {
|
|
934
|
+
await assetStore.updateAsset(asset.id, { kept: !asset.kept });
|
|
935
|
+
console.log(`${C.green}已${asset.kept ? '取消保留' : '标记保留'}${C.reset}`);
|
|
936
|
+
} else if (action === 2) {
|
|
937
|
+
const note = await ask('输入备注');
|
|
938
|
+
if (note) {
|
|
939
|
+
await assetStore.updateAsset(asset.id, { note });
|
|
940
|
+
console.log(`${C.green}备注已保存${C.reset}`);
|
|
941
|
+
}
|
|
942
|
+
} else if (action === 3) {
|
|
943
|
+
if (await confirm(`确认删除 ${asset.filename}`)) {
|
|
944
|
+
await assetStore.deleteAsset(asset.id);
|
|
945
|
+
console.log(`${C.green}已删除${C.reset}`);
|
|
917
946
|
}
|
|
918
947
|
}
|
|
919
948
|
}
|
package/package.json
CHANGED
|
@@ -76,7 +76,7 @@ async function localImageToString(localPath, asDataUri) {
|
|
|
76
76
|
|
|
77
77
|
async function agnesFetch(url, opts, options) {
|
|
78
78
|
const opts2 = options || {};
|
|
79
|
-
const retries = opts2.retries != null ? opts2.retries :
|
|
79
|
+
const retries = opts2.retries != null ? opts2.retries : 5;
|
|
80
80
|
const timeoutMs = opts2.timeoutMs != null ? opts2.timeoutMs : 120000;
|
|
81
81
|
let lastErr;
|
|
82
82
|
for (let attempt = 0; attempt <= retries; attempt++) {
|
|
@@ -87,8 +87,20 @@ async function agnesFetch(url, opts, options) {
|
|
|
87
87
|
clearTimeout(timer);
|
|
88
88
|
if ((res.status === 429 || res.status === 503) && attempt < retries) {
|
|
89
89
|
const t = await res.text().catch(function () { return ''; });
|
|
90
|
-
|
|
91
|
-
|
|
90
|
+
// 429 = 限频(1次/分钟),等 65 秒;503 = 服务忙,等 15 秒
|
|
91
|
+
const waitSec = res.status === 429 ? 65 : 15;
|
|
92
|
+
const reason = res.status === 429 ? '限频' : '服务忙';
|
|
93
|
+
console.log('[agnes] ' + res.status + ' ' + reason + ',' + waitSec + '秒后重试 (' + (attempt + 1) + '/' + retries + ')');
|
|
94
|
+
// 倒计时显示(仅 429 长等待时显示)
|
|
95
|
+
if (waitSec >= 30) {
|
|
96
|
+
for (let s = waitSec; s > 0; s--) {
|
|
97
|
+
process.stdout.write('\r 等待中... ' + s + '秒 ');
|
|
98
|
+
await new Promise(function (r) { setTimeout(r, 1000); });
|
|
99
|
+
}
|
|
100
|
+
process.stdout.write('\r' + ' '.repeat(40) + '\r');
|
|
101
|
+
} else {
|
|
102
|
+
await new Promise(function (r) { setTimeout(r, waitSec * 1000); });
|
|
103
|
+
}
|
|
92
104
|
continue;
|
|
93
105
|
}
|
|
94
106
|
return res;
|