Upload image-proxy.js
Browse files- image-proxy.js +83 -29
image-proxy.js
CHANGED
|
@@ -662,56 +662,58 @@ function proxyWebSocket(clientReq, clientSocket, clientHead) {
|
|
| 662 |
function serveHistory(req, res, query) {
|
| 663 |
const days = parseInt(query.days) || 10;
|
| 664 |
const cutoff = Date.now() - (days * 24 * 60 * 60 * 1000);
|
| 665 |
-
|
| 666 |
fs.readdir(SESSIONS_DIR, { withFileTypes: true }, (err, entries) => {
|
| 667 |
if (err) {
|
| 668 |
res.writeHead(500, { 'Content-Type': 'text/html; charset=utf-8' });
|
| 669 |
res.end('<h1>错误</h1><p>无法读取会话目录</p>');
|
| 670 |
return;
|
| 671 |
}
|
| 672 |
-
|
| 673 |
const sessions = [];
|
| 674 |
let pending = 0;
|
| 675 |
-
|
| 676 |
entries.forEach(entry => {
|
| 677 |
if (!entry.isFile() || !entry.name.endsWith('.json')) return;
|
| 678 |
-
|
| 679 |
pending++;
|
| 680 |
const filePath = path.join(SESSIONS_DIR, entry.name);
|
| 681 |
-
|
| 682 |
fs.readFile(filePath, 'utf8', (err, data) => {
|
| 683 |
if (!err) {
|
| 684 |
try {
|
| 685 |
const session = JSON.parse(data);
|
| 686 |
const mtime = fs.statSync(filePath).mtimeMs;
|
| 687 |
-
|
| 688 |
-
|
| 689 |
-
|
|
|
|
| 690 |
sessions.push({
|
| 691 |
-
|
|
|
|
| 692 |
name: session.name || session.title || '未命名对话',
|
| 693 |
model: session.model || session.original_model || '未知模型',
|
| 694 |
platform: session.platform || session.channel || 'webchat',
|
| 695 |
-
messages:
|
| 696 |
updated: new Date(mtime).toLocaleString('zh-CN'),
|
| 697 |
mtime: mtime
|
| 698 |
});
|
| 699 |
}
|
| 700 |
} catch (e) {}
|
| 701 |
}
|
| 702 |
-
|
| 703 |
pending--;
|
| 704 |
if (pending === 0) {
|
| 705 |
// 按时间倒序
|
| 706 |
sessions.sort((a, b) => b.mtime - a.mtime);
|
| 707 |
-
|
| 708 |
const html = buildHistoryHtml(sessions, days);
|
| 709 |
res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });
|
| 710 |
res.end(html);
|
| 711 |
}
|
| 712 |
});
|
| 713 |
});
|
| 714 |
-
|
| 715 |
if (pending === 0) {
|
| 716 |
const html = buildHistoryHtml([], days);
|
| 717 |
res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });
|
|
@@ -721,24 +723,76 @@ function serveHistory(req, res, query) {
|
|
| 721 |
}
|
| 722 |
|
| 723 |
function serveHistoryDetail(req, res, sessionId) {
|
| 724 |
-
|
| 725 |
-
|
| 726 |
-
|
| 727 |
-
|
| 728 |
-
|
| 729 |
-
|
| 730 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 731 |
}
|
| 732 |
|
| 733 |
-
|
| 734 |
-
|
| 735 |
-
|
| 736 |
-
|
| 737 |
-
|
| 738 |
-
|
| 739 |
-
|
| 740 |
-
|
| 741 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 742 |
});
|
| 743 |
}
|
| 744 |
|
|
|
|
| 662 |
function serveHistory(req, res, query) {
|
| 663 |
const days = parseInt(query.days) || 10;
|
| 664 |
const cutoff = Date.now() - (days * 24 * 60 * 60 * 1000);
|
| 665 |
+
|
| 666 |
fs.readdir(SESSIONS_DIR, { withFileTypes: true }, (err, entries) => {
|
| 667 |
if (err) {
|
| 668 |
res.writeHead(500, { 'Content-Type': 'text/html; charset=utf-8' });
|
| 669 |
res.end('<h1>错误</h1><p>无法读取会话目录</p>');
|
| 670 |
return;
|
| 671 |
}
|
| 672 |
+
|
| 673 |
const sessions = [];
|
| 674 |
let pending = 0;
|
| 675 |
+
|
| 676 |
entries.forEach(entry => {
|
| 677 |
if (!entry.isFile() || !entry.name.endsWith('.json')) return;
|
| 678 |
+
|
| 679 |
pending++;
|
| 680 |
const filePath = path.join(SESSIONS_DIR, entry.name);
|
| 681 |
+
|
| 682 |
fs.readFile(filePath, 'utf8', (err, data) => {
|
| 683 |
if (!err) {
|
| 684 |
try {
|
| 685 |
const session = JSON.parse(data);
|
| 686 |
const mtime = fs.statSync(filePath).mtimeMs;
|
| 687 |
+
const msgCount = Array.isArray(session.messages) ? session.messages.length : 0;
|
| 688 |
+
|
| 689 |
+
// 过滤:只显示有真实消息的会话,且在规定时间内
|
| 690 |
+
if (mtime >= cutoff && msgCount > 0) {
|
| 691 |
sessions.push({
|
| 692 |
+
// 使用文件名(不含扩展名)作为 ID,确保与磁盘文件一一对应
|
| 693 |
+
id: entry.name.replace('.json', ''),
|
| 694 |
name: session.name || session.title || '未命名对话',
|
| 695 |
model: session.model || session.original_model || '未知模型',
|
| 696 |
platform: session.platform || session.channel || 'webchat',
|
| 697 |
+
messages: msgCount,
|
| 698 |
updated: new Date(mtime).toLocaleString('zh-CN'),
|
| 699 |
mtime: mtime
|
| 700 |
});
|
| 701 |
}
|
| 702 |
} catch (e) {}
|
| 703 |
}
|
| 704 |
+
|
| 705 |
pending--;
|
| 706 |
if (pending === 0) {
|
| 707 |
// 按时间倒序
|
| 708 |
sessions.sort((a, b) => b.mtime - a.mtime);
|
| 709 |
+
|
| 710 |
const html = buildHistoryHtml(sessions, days);
|
| 711 |
res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });
|
| 712 |
res.end(html);
|
| 713 |
}
|
| 714 |
});
|
| 715 |
});
|
| 716 |
+
|
| 717 |
if (pending === 0) {
|
| 718 |
const html = buildHistoryHtml([], days);
|
| 719 |
res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });
|
|
|
|
| 723 |
}
|
| 724 |
|
| 725 |
function serveHistoryDetail(req, res, sessionId) {
|
| 726 |
+
// 首先尝试直接匹配文件名
|
| 727 |
+
const directPath = path.join(SESSIONS_DIR, `${sessionId}.json`);
|
| 728 |
+
|
| 729 |
+
fs.readFile(directPath, 'utf8', (err, data) => {
|
| 730 |
+
if (!err) {
|
| 731 |
+
try {
|
| 732 |
+
const session = JSON.parse(data);
|
| 733 |
+
const html = buildHistoryDetailHtml(session, sessionId);
|
| 734 |
+
res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });
|
| 735 |
+
res.end(html);
|
| 736 |
+
return;
|
| 737 |
+
} catch (e) {
|
| 738 |
+
res.writeHead(500, { 'Content-Type': 'text/html; charset=utf-8' });
|
| 739 |
+
res.end('<h1>错误</h1><p>无法解析会话数据</p>');
|
| 740 |
+
return;
|
| 741 |
+
}
|
| 742 |
}
|
| 743 |
|
| 744 |
+
// 直接匹配失败:扫描目录,查找包含该 session_id / id 的文件
|
| 745 |
+
fs.readdir(SESSIONS_DIR, { withFileTypes: true }, (readErr, entries) => {
|
| 746 |
+
if (readErr) {
|
| 747 |
+
res.writeHead(500, { 'Content-Type': 'text/html; charset=utf-8' });
|
| 748 |
+
res.end('<h1>错误</h1><p>无法读取会话目录</p>');
|
| 749 |
+
return;
|
| 750 |
+
}
|
| 751 |
+
|
| 752 |
+
const jsonFiles = entries
|
| 753 |
+
.filter(e => e.isFile() && e.name.endsWith('.json'))
|
| 754 |
+
.map(e => e.name);
|
| 755 |
+
|
| 756 |
+
let checked = 0;
|
| 757 |
+
let found = false;
|
| 758 |
+
|
| 759 |
+
if (jsonFiles.length === 0) {
|
| 760 |
+
res.writeHead(404, { 'Content-Type': 'text/html; charset=utf-8' });
|
| 761 |
+
res.end('<h1>404</h1><p>会话不存在</p>');
|
| 762 |
+
return;
|
| 763 |
+
}
|
| 764 |
+
|
| 765 |
+
jsonFiles.forEach(fileName => {
|
| 766 |
+
const fp = path.join(SESSIONS_DIR, fileName);
|
| 767 |
+
fs.readFile(fp, 'utf8', (readFileErr, fileData) => {
|
| 768 |
+
if (found) return; // 已找到,忽略后续结果
|
| 769 |
+
|
| 770 |
+
checked++;
|
| 771 |
+
|
| 772 |
+
if (!readFileErr) {
|
| 773 |
+
try {
|
| 774 |
+
const session = JSON.parse(fileData);
|
| 775 |
+
if (
|
| 776 |
+
session.session_id === sessionId ||
|
| 777 |
+
session.id === sessionId ||
|
| 778 |
+
fileName.replace('.json', '') === sessionId
|
| 779 |
+
) {
|
| 780 |
+
found = true;
|
| 781 |
+
const html = buildHistoryDetailHtml(session, sessionId);
|
| 782 |
+
res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });
|
| 783 |
+
res.end(html);
|
| 784 |
+
return;
|
| 785 |
+
}
|
| 786 |
+
} catch (e) {}
|
| 787 |
+
}
|
| 788 |
+
|
| 789 |
+
if (checked === jsonFiles.length && !found) {
|
| 790 |
+
res.writeHead(404, { 'Content-Type': 'text/html; charset=utf-8' });
|
| 791 |
+
res.end('<h1>404</h1><p>会话不存在</p>');
|
| 792 |
+
}
|
| 793 |
+
});
|
| 794 |
+
});
|
| 795 |
+
});
|
| 796 |
});
|
| 797 |
}
|
| 798 |
|