'use strict'; /** * NAC AI 资产估值问答界面 - 服务端 * 职责: * 1. 静态文件服务(index.html) * 2. /api/v4/* → 代理到估值引擎 v4.0(:3003) * 3. /api/inference/stream → 代理到推理引擎(:3001),支持 SSE 流式输出 * 4. /api/v4/xtzh-price → XTZH 实时价格(带本地缓存) * 5. /api/inference/ask → 普通问答(非流式) */ const express = require('express'); const http = require('http'); const path = require('path'); const app = express(); const PORT = process.env.PORT || 3005; // ============================================================ // 中间件 // ============================================================ app.use(express.json({ limit: '2mb' })); app.use(express.static(path.join(__dirname, 'public'))); // CORS(内部服务) app.use((req, res, next) => { res.setHeader('Access-Control-Allow-Origin', '*'); res.setHeader('Access-Control-Allow-Methods', 'GET,POST,OPTIONS'); res.setHeader('Access-Control-Allow-Headers', 'Content-Type,Authorization'); if (req.method === 'OPTIONS') return res.sendStatus(204); next(); }); // ============================================================ // 配置 // ============================================================ const VALUATION_ENGINE = { host: '127.0.0.1', port: 3003, timeout: 30000 }; const INFERENCE_ENGINE = { host: '127.0.0.1', port: 3001, timeout: 60000 }; // XTZH 价格缓存(5分钟) let xtzhPriceCache = null; let xtzhPriceCacheTime = 0; const XTZH_CACHE_TTL = 5 * 60 * 1000; // ============================================================ // XTZH 实时价格 // ============================================================ app.get('/api/v4/xtzh-price', async (req, res) => { try { // 检查缓存 if (xtzhPriceCache && Date.now() - xtzhPriceCacheTime < XTZH_CACHE_TTL) { return res.json(xtzhPriceCache); } // 从估值引擎获取 const data = await proxyRequest('GET', VALUATION_ENGINE, '/api/v4/xtzh-price', null, 5000); xtzhPriceCache = data; xtzhPriceCacheTime = Date.now(); return res.json(data); } catch(e) { // 降级:返回静态价格 const fallback = { usd: 4.3944, source: 'NAC_SDR_MODEL_V4_FALLBACK', goldCoverage: 1.25, sdrBasket: { USD: 0.5813, EUR: 0.1886, CNY: 0.1042, JPY: 0.0895, GBP: 0.0864 }, timestamp: new Date().toISOString(), note: '估值引擎离线,使用最后已知价格' }; return res.json(fallback); } }); // ============================================================ // 估值引擎代理 // ============================================================ app.post('/api/v4/valuate', async (req, res) => { try { const data = await proxyRequest('POST', VALUATION_ENGINE, '/api/v4/valuate', req.body, VALUATION_ENGINE.timeout); return res.json(data); } catch(e) { console.error('[ValuationProxy] Error:', e.message); return res.status(502).json({ error: '估值引擎暂时不可用', detail: e.message }); } }); // ============================================================ // 推理引擎 SSE 流式输出 // ============================================================ app.post('/api/inference/stream', (req, res) => { const body = JSON.stringify(req.body); res.setHeader('Content-Type', 'text/event-stream'); res.setHeader('Cache-Control', 'no-cache'); res.setHeader('Connection', 'keep-alive'); res.setHeader('X-Accel-Buffering', 'no'); const options = { hostname: INFERENCE_ENGINE.host, port: INFERENCE_ENGINE.port, path: '/api/inference/stream', method: 'POST', headers: { 'Content-Type': 'application/json', 'Content-Length': Buffer.byteLength(body) }, timeout: INFERENCE_ENGINE.timeout }; const proxyReq = http.request(options, (proxyRes) => { proxyRes.on('data', chunk => { if (!res.writableEnded) res.write(chunk); }); proxyRes.on('end', () => { if (!res.writableEnded) { res.write('data: [DONE]\n\n'); res.end(); } }); proxyRes.on('error', (err) => { if (!res.writableEnded) { res.write(`data: ${JSON.stringify({ type: 'error', message: err.message })}\n\n`); res.end(); } }); }); proxyReq.on('error', (err) => { console.error('[InferenceSSE] Proxy error:', err.message); if (!res.writableEnded) { // 降级:使用本地估值问答 handleLocalValuationQA(req.body, res); } }); proxyReq.on('timeout', () => { proxyReq.destroy(); if (!res.writableEnded) { res.write(`data: ${JSON.stringify({ type: 'error', message: '推理引擎响应超时' })}\n\n`); res.end(); } }); proxyReq.write(body); proxyReq.end(); req.on('close', () => { if (!proxyReq.destroyed) proxyReq.destroy(); }); }); // ============================================================ // 本地估值问答降级处理(推理引擎不可用时) // ============================================================ function handleLocalValuationQA(body, res) { const question = body.question || ''; const jurisdiction = body.jurisdiction || 'HK'; const assetType = body.assetType || 'real_estate'; const mode = body.mode || 'valuation'; const lang = body.language || 'zh'; let answer = ''; if (lang === 'zh') { if (question.includes('XTZH') || question.includes('定价') || question.includes('SDR')) { answer = generateXTZHExplanation(jurisdiction, lang); } else if (question.includes('上链') || question.includes('TOKEN') || question.includes('流程')) { answer = generateOnChainGuide(jurisdiction, lang); } else if (question.includes('方法') || question.includes('市场法') || question.includes('收益法')) { answer = generateMethodologyExplanation(assetType, lang); } else if (question.includes('辖区') || question.includes('对比') || question.includes('比较')) { answer = generateJurisdictionComparison(lang); } else { answer = generateGeneralValuationResponse(question, jurisdiction, assetType, lang); } } else { answer = generateGeneralValuationResponse(question, jurisdiction, assetType, lang); } // 流式输出(按行分块,确保 Markdown 表格行完整传输) const lines = answer.split('\n'); let i = 0; const interval = setInterval(() => { if (i >= lines.length) { clearInterval(interval); res.write('data: [DONE]\n\n'); res.end(); return; } // 每行加上换行符发送 const lineContent = lines[i] + (i < lines.length - 1 ? '\n' : ''); res.write(`data: ${JSON.stringify({ type: 'chunk', content: lineContent })}\n\n`); i++; }, 40); } function generateXTZHExplanation(jurisdiction, lang) { return `## XTZH 统一定价机制 **XTZH(新资产链稳定权益代币)** 采用SDR锚定篮子动态计算,确保全球资产估值的一致性和稳定性。 ### SDR五货币篮子权重 | 货币 | 权重 | 说明 | |------|------|------| | 美元 USD | 58.13% | 全球储备主导货币 | | 欧元 EUR | 18.86% | 欧洲区域货币 | | 人民币 CNY | 10.42% | 新兴市场代表 | | 日元 JPY | 8.95% | 亚太货币 | | 英镑 GBP | 8.64% | 英联邦货币 | ### 当前定价参数 - **XTZH/USD 汇率**:$4.3944 - **黄金覆盖率**:125%(超额储备保障) - **定价模型**:NAC_SDR_MODEL_V4 - **更新频率**:实时(每分钟) ### 80%质押规则 > 资产估值 × 80% = 可发行权益化代币数量 这确保了链上资产的超额抵押,保障代币持有者权益。`; } function generateOnChainGuide(jurisdiction, lang) { return `## 资产上链完整流程 ### 第一步:AI估值 1. 提交资产描述(类型、位置、面积、市值) 2. AI引擎自动识别GNACS分类 3. 多方法融合估值(市场法/收益法/成本法) 4. 输出 **finalXTZH** 和置信度 ### 第二步:合规审批 - 辖区合规验证(${jurisdiction}监管要求) - KYC/AML核查 - 资产所有权证明 - 合规评分 ≥ 80分方可上链 ### 第三步:TOKEN生成 - 智能合约部署(Charter语言,NVM虚拟机) - GNACS编码注册 - ACC-20协议代币铸造 ### 第四步:权证发行 - 资产权证NFT生成 - 链上存证(CBPP共识确认) - 权证与实物资产绑定 ### 第五步:代币流通 - 80%质押规则执行 - 二级市场流通 - 持续合规监控 > **注意**:完整上链流程通常需要3-7个工作日,具体时间取决于辖区审批速度。`; } function generateMethodologyExplanation(assetType, lang) { const methods = { real_estate: `## 不动产估值方法论 ### 市场比较法(权重40%) - 选取3-5个可比交易案例 - 调整因素:位置、面积、楼层、装修 - 适用:住宅、商业地产 ### 收益资本化法(权重35%) - 净营业收入 ÷ 资本化率 - 资本化率参考:HK 3-4%,SG 3.5-4.5%,AE 6-8% - 适用:商业地产、租赁物业 ### 成本法(权重25%) - 土地价值 + 建筑重置成本 - 折旧 - 适用:特殊用途物业、新建物业 ### XTZH换算 > finalUSD ÷ XTZH价格($4.3944) = finalXTZH`, financial: `## 金融资产估值方法论 ### DCF折现现金流法(权重50%) - 预测未来现金流 - 折现率:WACC + 风险溢价 - 适用:股权、债券、基金 ### 市场乘数法(权重30%) - P/E、P/B、EV/EBITDA - 对标可比公司 ### 净资产法(权重20%) - 账面价值调整 - 适用:清算场景` }; return methods[assetType] || methods.real_estate; } function generateJurisdictionComparison(lang) { return `## 主要辖区估值对比 | 辖区 | 资本化率 | 辖区乘数 | 主要法规 | 合规难度 | |------|---------|---------|---------|---------| | 🇭🇰 香港 | 3.0-4.0% | 1.05 | HKMA/SFC | ★★★☆☆ | | 🇸🇬 新加坡 | 3.5-4.5% | 1.03 | MAS | ★★★☆☆ | | 🇦🇪 阿联酋 | 6.0-8.0% | 1.08 | ADGM/DIFC | ★★☆☆☆ | | 🇺🇸 美国 | 4.0-6.0% | 0.95 | SEC/FINRA | ★★★★★ | | 🇬🇧 英国 | 4.5-5.5% | 0.98 | FCA | ★★★★☆ | | 🇯🇵 日本 | 3.0-4.5% | 1.00 | FSA | ★★★★☆ | | 🇨🇳 中国 | 4.0-5.0% | 0.90 | CBIRC | ★★★★★ | > **辖区乘数**:对最终XTZH估值的调整系数,反映各辖区市场流动性和监管环境。`; } function generateGeneralValuationResponse(question, jurisdiction, assetType, lang) { return `## NAC AI 资产估值引擎 感谢您的咨询!我是NAC NewAssetChain的AI资产估值专家。 **当前配置:** - 辖区:${jurisdiction} - 资产类型:${assetType} - XTZH价格:$4.3944 USD(SDR锚定) **我可以帮您:** 1. **资产估值** - 描述您的资产(类型、位置、面积、市值),我将给出XTZH估值 2. **XTZH定价** - 解释SDR锚定机制和当前价格计算 3. **上链流程** - 从估值到TOKEN生成的完整流程 4. **辖区对比** - 不同司法辖区的估值差异 5. **方法论** - 市场法/收益法/成本法详解 请告诉我您想了解的具体问题,或直接描述您的资产信息!`; } // ============================================================ // 工具函数:HTTP代理请求 // ============================================================ function proxyRequest(method, target, path, body, timeout) { return new Promise((resolve, reject) => { const bodyStr = body ? JSON.stringify(body) : null; const options = { hostname: target.host, port: target.port, path: path, method: method, headers: { 'Content-Type': 'application/json', ...(bodyStr ? { 'Content-Length': Buffer.byteLength(bodyStr) } : {}) }, timeout: timeout || 10000 }; const req = http.request(options, (res) => { let data = ''; res.on('data', chunk => data += chunk); res.on('end', () => { try { resolve(JSON.parse(data)); } catch(e) { reject(new Error('无效的JSON响应: ' + data.substring(0, 100))); } }); }); req.on('error', reject); req.on('timeout', () => { req.destroy(); reject(new Error('请求超时')); }); if (bodyStr) req.write(bodyStr); req.end(); }); } // ============================================================ // 静态文件服务(主页) // ============================================================ app.get('/', (req, res) => { res.sendFile(path.join(__dirname, 'public', 'index.html')); }); // 健康检查 app.get('/health', (req, res) => { res.json({ status: 'ok', service: 'nac-valuation-ui', version: '1.0.0', timestamp: new Date().toISOString(), engines: { valuation: `${VALUATION_ENGINE.host}:${VALUATION_ENGINE.port}`, inference: `${INFERENCE_ENGINE.host}:${INFERENCE_ENGINE.port}` } }); }); // ============================================================ // 启动 // ============================================================ app.listen(PORT, '0.0.0.0', () => { console.log(`[NAC Valuation UI] 服务启动 → http://0.0.0.0:${PORT}`); console.log(`[NAC Valuation UI] 估值引擎 → ${VALUATION_ENGINE.host}:${VALUATION_ENGINE.port}`); console.log(`[NAC Valuation UI] 推理引擎 → ${INFERENCE_ENGINE.host}:${INFERENCE_ENGINE.port}`); });