feat: 新增 AI 估值问答界面 (valuation.newassetchain.io)

- 前端:SSE 流式输出 + Markdown 渲染(表格/标题/列表)
- 服务端:Node.js 代理层,连接估值引擎(:3003)和推理引擎(:3001)
- 支持多辖区(9个)、多资产类型(6类)、多语言(5种)
- XTZH 实时价格显示(SDR锚定,5分钟缓存)
- 部署:AI服务器 43.224.155.27:3005,Nginx 反代 valuation.newassetchain.io
This commit is contained in:
NAC Admin 2026-03-05 18:13:53 +08:00
parent 3d79710b88
commit ded3439322
4 changed files with 1860 additions and 0 deletions

View File

@ -0,0 +1,36 @@
# NAC AI 估值问答界面
**部署地址**https://valuation.newassetchain.io
## 功能说明
本模块是 `nac-ai-valuation` 的前端问答界面,运行在 AI 服务器43.224.155.27)的 `:3005` 端口。
### 核心功能
- **AI 估值问答**:支持多轮对话,集中于资产估值相关问答
- **SSE 流式输出**:实时流式显示 AI 回答
- **XTZH 实时价格**:顶部显示当前 XTZH/USD 价格SDR 锚定)
- **多辖区支持**:香港、新加坡、阿联酋、美国、英国、日本、中国、澳洲、德国
- **多资产类型**:不动产、金融资产、艺术品、大宗商品、知识产权、股权
- **Markdown 渲染**:支持表格、标题、列表、引用块等格式
- **多语言**中文、English、العربية、日本語、한국어
### 架构
```
前端 (index.html) → Node.js 代理 (server.js:3005) → 估值引擎 (nac-ai-valuation:3003)
→ 推理引擎 (nac-ai-inference:3001)
```
### 部署
```bash
cd /opt/nac-valuation-ui
npm install --production
PORT=3005 pm2 start server.js --name nac-valuation-ui
```
### 版本历史
- v1.0.0 (2026-03-05)初始版本SSE 流式输出 + Markdown 渲染修复

View File

@ -0,0 +1,16 @@
{
"name": "nac-valuation-ui",
"version": "1.0.0",
"description": "NAC AI 资产估值问答界面 - valuation.newassetchain.io",
"main": "server.js",
"scripts": {
"start": "node server.js",
"dev": "node server.js"
},
"dependencies": {
"express": "^4.18.2"
},
"engines": {
"node": ">=16.0.0"
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,409 @@
'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/EP/BEV/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 USDSDR锚定
**我可以帮您**
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}`);
});