|
@@ -71,7 +71,7 @@
|
|
|
<span>📡 API 端点列表 ({{ apiEndpoints.length }})</span>
|
|
<span>📡 API 端点列表 ({{ apiEndpoints.length }})</span>
|
|
|
<el-input v-model="apiFilter" placeholder="筛选端点..." size="mini" prefix-icon="el-icon-search" style="width:200px" clearable />
|
|
<el-input v-model="apiFilter" placeholder="筛选端点..." size="mini" prefix-icon="el-icon-search" style="width:200px" clearable />
|
|
|
</div>
|
|
</div>
|
|
|
- <el-table :data="filteredApiEndpoints" border stripe size="small" max-height="400">
|
|
|
|
|
|
|
+ <el-table :data="filteredApiEndpoints" border stripe size="small" max-height="500">
|
|
|
<el-table-column prop="method" label="方法" width="80">
|
|
<el-table-column prop="method" label="方法" width="80">
|
|
|
<template slot-scope="{ row }">
|
|
<template slot-scope="{ row }">
|
|
|
<el-tag :type="row.method === 'GET' ? 'info' : 'primary'" size="mini">{{ row.method }}</el-tag>
|
|
<el-tag :type="row.method === 'GET' ? 'info' : 'primary'" size="mini">{{ row.method }}</el-tag>
|
|
@@ -90,7 +90,7 @@
|
|
|
<!-- 快速测试面板 -->
|
|
<!-- 快速测试面板 -->
|
|
|
<el-card class="test-card" shadow="never">
|
|
<el-card class="test-card" shadow="never">
|
|
|
<div slot="header" class="card-header">
|
|
<div slot="header" class="card-header">
|
|
|
- <span>🧪 快速功能测试</span>
|
|
|
|
|
|
|
+ <span>🧪 功能测试</span>
|
|
|
<el-button size="mini" type="success" @click="runQuickTests" :loading="quickTesting">一键测试</el-button>
|
|
<el-button size="mini" type="success" @click="runQuickTests" :loading="quickTesting">一键测试</el-button>
|
|
|
</div>
|
|
</div>
|
|
|
<el-row :gutter="12">
|
|
<el-row :gutter="12">
|
|
@@ -176,7 +176,7 @@
|
|
|
<el-button size="mini" type="danger" @click="clearLogs">清空</el-button>
|
|
<el-button size="mini" type="danger" @click="clearLogs">清空</el-button>
|
|
|
</div>
|
|
</div>
|
|
|
</div>
|
|
</div>
|
|
|
- <div class="log-container">
|
|
|
|
|
|
|
+ <div class="log-container" ref="logContainer">
|
|
|
<div v-for="(log, i) in logList" :key="i" class="log-line" :class="'log-' + getLogLevel(log)">
|
|
<div v-for="(log, i) in logList" :key="i" class="log-line" :class="'log-' + getLogLevel(log)">
|
|
|
<span class="log-time">{{ log.time }}</span>
|
|
<span class="log-time">{{ log.time }}</span>
|
|
|
<span class="log-level">{{ log.level }}</span>
|
|
<span class="log-level">{{ log.level }}</span>
|
|
@@ -189,16 +189,33 @@
|
|
|
</template>
|
|
</template>
|
|
|
|
|
|
|
|
<script>
|
|
<script>
|
|
|
-import {
|
|
|
|
|
- getLangGraphHealth,
|
|
|
|
|
- getLangGraphSpec,
|
|
|
|
|
- getLangGraphDetailedHealth,
|
|
|
|
|
- testFoodRecognize,
|
|
|
|
|
- testMenuGenerate,
|
|
|
|
|
- testChat,
|
|
|
|
|
- testRecommend,
|
|
|
|
|
- testQuestionnaireGenerate
|
|
|
|
|
-} from '@/api/langgraph'
|
|
|
|
|
|
|
+const BASE = 'https://ai.etotem.com.cn'
|
|
|
|
|
+
|
|
|
|
|
+function fetchJSON(url, options = {}) {
|
|
|
|
|
+ return fetch(url, {
|
|
|
|
|
+ ...options,
|
|
|
|
|
+ headers: {
|
|
|
|
|
+ 'Content-Type': 'application/json',
|
|
|
|
|
+ ...options.headers
|
|
|
|
|
+ }
|
|
|
|
|
+ }).then(function(res) {
|
|
|
|
|
+ if (!res.ok) throw new Error('HTTP ' + res.status)
|
|
|
|
|
+ return res.json()
|
|
|
|
|
+ })
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+function fetchText(url, options = {}) {
|
|
|
|
|
+ return fetch(url, {
|
|
|
|
|
+ ...options,
|
|
|
|
|
+ headers: {
|
|
|
|
|
+ 'Content-Type': 'application/json',
|
|
|
|
|
+ ...options.headers
|
|
|
|
|
+ }
|
|
|
|
|
+ }).then(function(res) {
|
|
|
|
|
+ if (!res.ok) throw new Error('HTTP ' + res.status)
|
|
|
|
|
+ return res.text()
|
|
|
|
|
+ })
|
|
|
|
|
+}
|
|
|
|
|
|
|
|
export default {
|
|
export default {
|
|
|
name: 'LangGraphAdmin',
|
|
name: 'LangGraphAdmin',
|
|
@@ -216,43 +233,47 @@ export default {
|
|
|
componentList: [],
|
|
componentList: [],
|
|
|
refreshing: false,
|
|
refreshing: false,
|
|
|
quickTesting: false,
|
|
quickTesting: false,
|
|
|
- config: {},
|
|
|
|
|
- // 测试对话框
|
|
|
|
|
|
|
+ config: {
|
|
|
|
|
+ LLM_MODEL: 'deepseek',
|
|
|
|
|
+ LLM_BASE_URL: 'http://axonhub.iwintrue.com/v1',
|
|
|
|
|
+ EMBEDDING_MODEL: 'BAAI/bge-large-zh-v1.5',
|
|
|
|
|
+ EMBEDDING_BASE_URL: 'https://api.siliconflow.cn/v1',
|
|
|
|
|
+ JAVA_BASE_URL: 'http://111.227.6.214:9082',
|
|
|
|
|
+ CHROMA_DB_PATH: '/data/chroma_db',
|
|
|
|
|
+ LANGCHAIN_TRACING_V2: 'true',
|
|
|
|
|
+ LOG_LEVEL: 'info'
|
|
|
|
|
+ },
|
|
|
testDialogVisible: false,
|
|
testDialogVisible: false,
|
|
|
testingEndpoint: {},
|
|
testingEndpoint: {},
|
|
|
testParams: '{}',
|
|
testParams: '{}',
|
|
|
testing: false,
|
|
testing: false,
|
|
|
testResponse: '',
|
|
testResponse: '',
|
|
|
- // 日志
|
|
|
|
|
logList: [],
|
|
logList: [],
|
|
|
- logLoading: false
|
|
|
|
|
|
|
+ logLoading: false,
|
|
|
|
|
+ _interval: null
|
|
|
}
|
|
}
|
|
|
},
|
|
},
|
|
|
- computed: (function() {
|
|
|
|
|
- return {
|
|
|
|
|
- filteredApiEndpoints: function() {
|
|
|
|
|
- var self = this
|
|
|
|
|
- if (!self.apiFilter) return self.apiEndpoints
|
|
|
|
|
- var kw = self.apiFilter.toLowerCase()
|
|
|
|
|
- return self.apiEndpoints.filter(function(e) {
|
|
|
|
|
- return e.path.toLowerCase().indexOf(kw) >= 0 || (e.summary && e.summary.toLowerCase().indexOf(kw) >= 0)
|
|
|
|
|
- })
|
|
|
|
|
- },
|
|
|
|
|
- quickTests: function() {
|
|
|
|
|
- return [
|
|
|
|
|
- { key: 'food', name: '食材识别', desc: 'POST /api/v1/food/recognize', result: 'pending', time: 0, errorMsg: '' },
|
|
|
|
|
- { key: 'menu', name: '菜单生成', desc: 'POST /api/v1/menu/generate', result: 'pending', time: 0, errorMsg: '' },
|
|
|
|
|
- { key: 'chat', name: 'AI 对话', desc: 'POST /api/v1/chat', result: 'pending', time: 0, errorMsg: '' },
|
|
|
|
|
- { key: 'questionnaire', name: '问卷生成', desc: 'POST /api/v1/questionnaire/generate', result: 'pending', time: 0, errorMsg: '' }
|
|
|
|
|
- ]
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ computed: {
|
|
|
|
|
+ filteredApiEndpoints: function() {
|
|
|
|
|
+ var self = this
|
|
|
|
|
+ if (!self.apiFilter) return self.apiEndpoints
|
|
|
|
|
+ var kw = self.apiFilter.toLowerCase()
|
|
|
|
|
+ return self.apiEndpoints.filter(function(e) {
|
|
|
|
|
+ return e.path.toLowerCase().indexOf(kw) >= 0 || (e.summary && e.summary.toLowerCase().indexOf(kw) >= 0)
|
|
|
|
|
+ })
|
|
|
|
|
+ },
|
|
|
|
|
+ quickTests: function() {
|
|
|
|
|
+ return [
|
|
|
|
|
+ { key: 'food', name: '食材识别', desc: 'POST /api/v1/food/recognize', result: 'pending', time: 0, errorMsg: '' },
|
|
|
|
|
+ { key: 'menu', name: '菜单生成', desc: 'POST /api/v1/menu/generate', result: 'pending', time: 0, errorMsg: '' },
|
|
|
|
|
+ { key: 'chat', name: 'AI 对话', desc: 'POST /api/v1/chat', result: 'pending', time: 0, errorMsg: '' },
|
|
|
|
|
+ { key: 'questionnaire', name: '问卷生成', desc: 'POST /api/v1/questionnaire/generate', result: 'pending', time: 0, errorMsg: '' }
|
|
|
|
|
+ ]
|
|
|
}
|
|
}
|
|
|
- })(),
|
|
|
|
|
|
|
+ },
|
|
|
created: function() {
|
|
created: function() {
|
|
|
this.refreshAll()
|
|
this.refreshAll()
|
|
|
- this.fetchConfig()
|
|
|
|
|
this.fetchLogs()
|
|
this.fetchLogs()
|
|
|
- // 每 30 秒自动刷新状态
|
|
|
|
|
this._interval = setInterval(this.refreshAll, 30000)
|
|
this._interval = setInterval(this.refreshAll, 30000)
|
|
|
},
|
|
},
|
|
|
beforeDestroy: function() {
|
|
beforeDestroy: function() {
|
|
@@ -269,8 +290,13 @@ export default {
|
|
|
},
|
|
},
|
|
|
async fetchHealth() {
|
|
async fetchHealth() {
|
|
|
try {
|
|
try {
|
|
|
- var res = await getLangGraphHealth()
|
|
|
|
|
- if (res.status === 'healthy') {
|
|
|
|
|
|
|
+ var img = new Image()
|
|
|
|
|
+ var healthy = await new Promise(function(resolve) {
|
|
|
|
|
+ img.onload = function() { resolve(true) }
|
|
|
|
|
+ img.onerror = function() { resolve(false) }
|
|
|
|
|
+ img.src = BASE + '/health?t=' + Date.now()
|
|
|
|
|
+ })
|
|
|
|
|
+ if (healthy) {
|
|
|
this.statusText = '运行中'
|
|
this.statusText = '运行中'
|
|
|
this.statusClass = 'status-healthy'
|
|
this.statusClass = 'status-healthy'
|
|
|
this.statusIcon = '✅'
|
|
this.statusIcon = '✅'
|
|
@@ -288,8 +314,8 @@ export default {
|
|
|
},
|
|
},
|
|
|
async fetchSpec() {
|
|
async fetchSpec() {
|
|
|
try {
|
|
try {
|
|
|
- var res = await getLangGraphSpec()
|
|
|
|
|
- var paths = res.data.paths || {}
|
|
|
|
|
|
|
+ var res = await fetchJSON(BASE + '/openapi.json')
|
|
|
|
|
+ var paths = res.paths || {}
|
|
|
var endpoints = []
|
|
var endpoints = []
|
|
|
var self = this
|
|
var self = this
|
|
|
Object.keys(paths).forEach(function(path) {
|
|
Object.keys(paths).forEach(function(path) {
|
|
@@ -316,21 +342,20 @@ export default {
|
|
|
},
|
|
},
|
|
|
async fetchDetailedHealth() {
|
|
async fetchDetailedHealth() {
|
|
|
try {
|
|
try {
|
|
|
- var res = await getLangGraphDetailedHealth()
|
|
|
|
|
- var data = res.data || {}
|
|
|
|
|
|
|
+ var res = await fetchJSON(BASE + '/api/v1/health')
|
|
|
|
|
+ var data = res || {}
|
|
|
var comps = []
|
|
var comps = []
|
|
|
var c = data.components || {}
|
|
var c = data.components || {}
|
|
|
if (c.chromadb) {
|
|
if (c.chromadb) {
|
|
|
comps.push({ name: 'ChromaDB', status: c.chromadb.status || 'unknown', detail: c.chromadb.path || '' })
|
|
comps.push({ name: 'ChromaDB', status: c.chromadb.status || 'unknown', detail: c.chromadb.path || '' })
|
|
|
}
|
|
}
|
|
|
if (c.llm) {
|
|
if (c.llm) {
|
|
|
- comps.push({ name: 'LLM', status: c.llm.status || 'unknown', detail: '' })
|
|
|
|
|
|
|
+ comps.push({ name: 'LLM', status: c.llm.status || 'unknown', detail: c.llm.message || '' })
|
|
|
}
|
|
}
|
|
|
if (c.java_backend) {
|
|
if (c.java_backend) {
|
|
|
comps.push({ name: 'Java 后端', status: c.java_backend.status || 'unknown', detail: c.java_backend.code ? 'HTTP ' + c.java_backend.code : '' })
|
|
comps.push({ name: 'Java 后端', status: c.java_backend.status || 'unknown', detail: c.java_backend.code ? 'HTTP ' + c.java_backend.code : '' })
|
|
|
}
|
|
}
|
|
|
this.componentList = comps
|
|
this.componentList = comps
|
|
|
- // 更新总状态
|
|
|
|
|
var allOk = comps.every(function(x) { return x.status === 'ok' })
|
|
var allOk = comps.every(function(x) { return x.status === 'ok' })
|
|
|
var hasError = comps.some(function(x) { return x.status === 'error' })
|
|
var hasError = comps.some(function(x) { return x.status === 'error' })
|
|
|
if (allOk) {
|
|
if (allOk) {
|
|
@@ -351,23 +376,16 @@ export default {
|
|
|
this.componentList = [{ name: '健康检查', status: 'error', detail: e.message }]
|
|
this.componentList = [{ name: '健康检查', status: 'error', detail: e.message }]
|
|
|
}
|
|
}
|
|
|
},
|
|
},
|
|
|
- async fetchConfig() {
|
|
|
|
|
- try {
|
|
|
|
|
- var res = await getLangGraphSpec()
|
|
|
|
|
- // 从 openapi 无法直接获取配置,尝试从 /api/v1/health 获取
|
|
|
|
|
- var h = await getLangGraphDetailedHealth()
|
|
|
|
|
- this.config = {
|
|
|
|
|
- LLM_MODEL: 'deepseek',
|
|
|
|
|
- LLM_BASE_URL: 'http://axonhub.iwintrue.com/v1',
|
|
|
|
|
- EMBEDDING_MODEL: 'BAAI/bge-large-zh-v1.5',
|
|
|
|
|
- EMBEDDING_BASE_URL: 'https://api.siliconflow.cn/v1',
|
|
|
|
|
- JAVA_BASE_URL: 'http://111.227.6.214:9082',
|
|
|
|
|
- CHROMA_DB_PATH: '/data/chroma_db',
|
|
|
|
|
- LANGCHAIN_TRACING_V2: 'true',
|
|
|
|
|
- LOG_LEVEL: 'info'
|
|
|
|
|
- }
|
|
|
|
|
- } catch (e) {
|
|
|
|
|
- console.error('获取配置失败', e)
|
|
|
|
|
|
|
+ fetchConfig: function() {
|
|
|
|
|
+ this.config = {
|
|
|
|
|
+ LLM_MODEL: 'deepseek',
|
|
|
|
|
+ LLM_BASE_URL: 'http://axonhub.iwintrue.com/v1',
|
|
|
|
|
+ EMBEDDING_MODEL: 'BAAI/bge-large-zh-v1.5',
|
|
|
|
|
+ EMBEDDING_BASE_URL: 'https://api.siliconflow.cn/v1',
|
|
|
|
|
+ JAVA_BASE_URL: 'http://111.227.6.214:9082',
|
|
|
|
|
+ CHROMA_DB_PATH: '/data/chroma_db',
|
|
|
|
|
+ LANGCHAIN_TRACING_V2: 'true',
|
|
|
|
|
+ LOG_LEVEL: 'info'
|
|
|
}
|
|
}
|
|
|
},
|
|
},
|
|
|
openTestDialog: function(endpoint) {
|
|
openTestDialog: function(endpoint) {
|
|
@@ -377,8 +395,7 @@ export default {
|
|
|
'/api/v1/menu/generate': JSON.stringify({ selected_foods: '[{"name":"鸡肉"}]', participants: '[]', date: '2026-08-08' }, null, 2),
|
|
'/api/v1/menu/generate': JSON.stringify({ selected_foods: '[{"name":"鸡肉"}]', participants: '[]', date: '2026-08-08' }, null, 2),
|
|
|
'/api/v1/chat': JSON.stringify({ query: '你好', user_id: 1 }, null, 2),
|
|
'/api/v1/chat': JSON.stringify({ query: '你好', user_id: 1 }, null, 2),
|
|
|
'/api/v1/recommend': JSON.stringify({ user_id: 1, query: '推荐早餐', limit: 5 }, null, 2),
|
|
'/api/v1/recommend': JSON.stringify({ user_id: 1, query: '推荐早餐', limit: 5 }, null, 2),
|
|
|
- '/api/v1/questionnaire/generate': JSON.stringify({ member_name: '小明', relationship_type: 'parent' }, null, 2),
|
|
|
|
|
- '/api/v1/tongue/diagnose': '请上传舌苔图片 (MIME 类型表单)'
|
|
|
|
|
|
|
+ '/api/v1/questionnaire/generate': JSON.stringify({ member_name: '小明', relationship_type: 'parent' }, null, 2)
|
|
|
}
|
|
}
|
|
|
this.testParams = defaults[endpoint.path] || '{}'
|
|
this.testParams = defaults[endpoint.path] || '{}'
|
|
|
this.testResponse = ''
|
|
this.testResponse = ''
|
|
@@ -393,70 +410,87 @@ export default {
|
|
|
if (self.testParams && self.testParams !== '请上传舌苔图片 (MIME 类型表单)') {
|
|
if (self.testParams && self.testParams !== '请上传舌苔图片 (MIME 类型表单)') {
|
|
|
payload = JSON.parse(self.testParams)
|
|
payload = JSON.parse(self.testParams)
|
|
|
}
|
|
}
|
|
|
- var res = await this._callApi(self.testingEndpoint.path, payload)
|
|
|
|
|
- self.testResponse = JSON.stringify(res.data, null, 2)
|
|
|
|
|
|
|
+ var path = self.testingEndpoint.path
|
|
|
|
|
+ var res = await fetch(BASE + path, {
|
|
|
|
|
+ method: 'POST',
|
|
|
|
|
+ headers: { 'Content-Type': 'application/json' },
|
|
|
|
|
+ body: JSON.stringify(payload),
|
|
|
|
|
+ signal: AbortSignal.timeout(60000)
|
|
|
|
|
+ })
|
|
|
|
|
+ var data = await res.json()
|
|
|
|
|
+ self.testResponse = JSON.stringify(data, null, 2)
|
|
|
} catch (e) {
|
|
} catch (e) {
|
|
|
- self.testResponse = '错误: ' + (e.response ? JSON.stringify(e.response.data) : e.message)
|
|
|
|
|
|
|
+ self.testResponse = '错误: ' + e.message
|
|
|
} finally {
|
|
} finally {
|
|
|
self.testing = false
|
|
self.testing = false
|
|
|
}
|
|
}
|
|
|
},
|
|
},
|
|
|
- _callApi: function(path, data) {
|
|
|
|
|
- var base = 'https://ai.etotem.com.cn'
|
|
|
|
|
- var axios = require('axios')
|
|
|
|
|
- return axios.post(base + path, data, { timeout: 60000 })
|
|
|
|
|
- },
|
|
|
|
|
async runQuickTests() {
|
|
async runQuickTests() {
|
|
|
var self = this
|
|
var self = this
|
|
|
self.quickTesting = true
|
|
self.quickTesting = true
|
|
|
- var tests = self.quickTests
|
|
|
|
|
|
|
+ var tests = self.quickTests.slice()
|
|
|
var results = { food: tests[0], menu: tests[1], chat: tests[2], questionnaire: tests[3] }
|
|
var results = { food: tests[0], menu: tests[1], chat: tests[2], questionnaire: tests[3] }
|
|
|
|
|
|
|
|
- // 食材识别
|
|
|
|
|
var t0 = Date.now()
|
|
var t0 = Date.now()
|
|
|
try {
|
|
try {
|
|
|
- var r1 = await testFoodRecognize({ image_url: 'https://example.com/food.jpg' })
|
|
|
|
|
|
|
+ var r1 = await fetch(BASE + '/api/v1/food/recognize', {
|
|
|
|
|
+ method: 'POST',
|
|
|
|
|
+ headers: { 'Content-Type': 'application/json' },
|
|
|
|
|
+ body: JSON.stringify({ image_url: 'https://example.com/food.jpg' })
|
|
|
|
|
+ })
|
|
|
|
|
+ await r1.json()
|
|
|
results.food.result = 'success'
|
|
results.food.result = 'success'
|
|
|
results.food.time = Date.now() - t0
|
|
results.food.time = Date.now() - t0
|
|
|
} catch (e) {
|
|
} catch (e) {
|
|
|
results.food.result = 'error'
|
|
results.food.result = 'error'
|
|
|
- results.food.errorMsg = (e.response && e.response.data && e.response.data.detail) || e.message
|
|
|
|
|
|
|
+ results.food.errorMsg = e.message
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- // 菜单生成
|
|
|
|
|
t0 = Date.now()
|
|
t0 = Date.now()
|
|
|
try {
|
|
try {
|
|
|
- var r2 = await testMenuGenerate({ selected_foods: '[{"name":"鸡肉"}]', participants: '[]', date: '2026-08-08' })
|
|
|
|
|
|
|
+ var r2 = await fetch(BASE + '/api/v1/menu/generate', {
|
|
|
|
|
+ method: 'POST',
|
|
|
|
|
+ headers: { 'Content-Type': 'application/json' },
|
|
|
|
|
+ body: JSON.stringify({ selected_foods: '[{"name":"鸡肉"}]', participants: '[]', date: '2026-08-08' })
|
|
|
|
|
+ })
|
|
|
|
|
+ await r2.json()
|
|
|
results.menu.result = 'success'
|
|
results.menu.result = 'success'
|
|
|
results.menu.time = Date.now() - t0
|
|
results.menu.time = Date.now() - t0
|
|
|
} catch (e) {
|
|
} catch (e) {
|
|
|
results.menu.result = 'error'
|
|
results.menu.result = 'error'
|
|
|
- results.menu.errorMsg = (e.response && e.response.data && e.response.data.detail) || e.message
|
|
|
|
|
|
|
+ results.menu.errorMsg = e.message
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- // 对话
|
|
|
|
|
t0 = Date.now()
|
|
t0 = Date.now()
|
|
|
try {
|
|
try {
|
|
|
- var r3 = await testChat({ query: '你好', user_id: 1 })
|
|
|
|
|
|
|
+ var r3 = await fetch(BASE + '/api/v1/chat', {
|
|
|
|
|
+ method: 'POST',
|
|
|
|
|
+ headers: { 'Content-Type': 'application/json' },
|
|
|
|
|
+ body: JSON.stringify({ query: '你好', user_id: 1 })
|
|
|
|
|
+ })
|
|
|
|
|
+ await r3.json()
|
|
|
results.chat.result = 'success'
|
|
results.chat.result = 'success'
|
|
|
results.chat.time = Date.now() - t0
|
|
results.chat.time = Date.now() - t0
|
|
|
} catch (e) {
|
|
} catch (e) {
|
|
|
results.chat.result = 'error'
|
|
results.chat.result = 'error'
|
|
|
- results.chat.errorMsg = (e.response && e.response.data && e.response.data.detail) || e.message
|
|
|
|
|
|
|
+ results.chat.errorMsg = e.message
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- // 问卷
|
|
|
|
|
t0 = Date.now()
|
|
t0 = Date.now()
|
|
|
try {
|
|
try {
|
|
|
- var r4 = await testQuestionnaireGenerate({ member_name: '小明', relationship_type: 'parent' })
|
|
|
|
|
|
|
+ var r4 = await fetch(BASE + '/api/v1/questionnaire/generate', {
|
|
|
|
|
+ method: 'POST',
|
|
|
|
|
+ headers: { 'Content-Type': 'application/json' },
|
|
|
|
|
+ body: JSON.stringify({ member_name: '小明', relationship_type: 'parent' })
|
|
|
|
|
+ })
|
|
|
|
|
+ await r4.json()
|
|
|
results.questionnaire.result = 'success'
|
|
results.questionnaire.result = 'success'
|
|
|
results.questionnaire.time = Date.now() - t0
|
|
results.questionnaire.time = Date.now() - t0
|
|
|
} catch (e) {
|
|
} catch (e) {
|
|
|
results.questionnaire.result = 'error'
|
|
results.questionnaire.result = 'error'
|
|
|
- results.questionnaire.errorMsg = (e.response && e.response.data && e.response.data.detail) || e.message
|
|
|
|
|
|
|
+ results.questionnaire.errorMsg = e.message
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- // 更新显示
|
|
|
|
|
tests[0] = results.food
|
|
tests[0] = results.food
|
|
|
tests[1] = results.menu
|
|
tests[1] = results.menu
|
|
|
tests[2] = results.chat
|
|
tests[2] = results.chat
|
|
@@ -466,11 +500,19 @@ export default {
|
|
|
async fetchLogs() {
|
|
async fetchLogs() {
|
|
|
this.logLoading = true
|
|
this.logLoading = true
|
|
|
try {
|
|
try {
|
|
|
- // 从后端获取日志
|
|
|
|
|
- var res = await this.$axios.get('https://ai.etotem.com.cn/openapi.json', { timeout: 5000 })
|
|
|
|
|
- this.logList = [{ time: new Date().toLocaleTimeString(), level: 'INFO', msg: '服务连接正常,API 端点数: ' + (res.data.paths ? Object.keys(res.data.paths).length : 0) }]
|
|
|
|
|
|
|
+ var res = await fetch(BASE + '/openapi.json')
|
|
|
|
|
+ var data = await res.json()
|
|
|
|
|
+ this.logList = [{
|
|
|
|
|
+ time: new Date().toLocaleTimeString(),
|
|
|
|
|
+ level: 'INFO',
|
|
|
|
|
+ msg: '服务连接正常,API 端点数: ' + Object.keys(data.paths || {}).length
|
|
|
|
|
+ }]
|
|
|
} catch (e) {
|
|
} catch (e) {
|
|
|
- this.logList = [{ time: new Date().toLocaleTimeString(), level: 'ERROR', msg: '无法连接到 LangGraph 服务: ' + e.message }]
|
|
|
|
|
|
|
+ this.logList = [{
|
|
|
|
|
+ time: new Date().toLocaleTimeString(),
|
|
|
|
|
+ level: 'ERROR',
|
|
|
|
|
+ msg: '无法连接到 LangGraph 服务: ' + e.message
|
|
|
|
|
+ }]
|
|
|
} finally {
|
|
} finally {
|
|
|
this.logLoading = false
|
|
this.logLoading = false
|
|
|
}
|
|
}
|
|
@@ -583,7 +625,7 @@ export default {
|
|
|
word-break: break-all;
|
|
word-break: break-all;
|
|
|
}
|
|
}
|
|
|
.log-container {
|
|
.log-container {
|
|
|
- max-height: 300px;
|
|
|
|
|
|
|
+ max-height: 250px;
|
|
|
overflow-y: auto;
|
|
overflow-y: auto;
|
|
|
background: #1e1e1e;
|
|
background: #1e1e1e;
|
|
|
border-radius: 4px;
|
|
border-radius: 4px;
|