fix-lobster-vue-encoding.js 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222
  1. /**
  2. * Rewrite lobster admin vue files with correct UTF-8 Chinese.
  3. * Run: node java/scripts/fix-lobster-vue-encoding.js
  4. */
  5. const fs = require('fs')
  6. const path = require('path')
  7. const root = path.resolve(__dirname, '../..')
  8. const uddDebug = `<template>
  9. <div class="app-container udd-debug-page">
  10. <el-row :gutter="16">
  11. <el-col :span="10">
  12. <el-card shadow="never">
  13. <div slot="header"><i class="el-icon-setting"></i> \u8c03\u8bd5\u53c2\u6570</div>
  14. <el-form label-width="88px" size="small">
  15. <el-form-item label="\u7528\u6237\u6807\u8bc6">
  16. <el-input v-model="form.userKey" placeholder="\u6a21\u62df externalUserId / contactId" />
  17. </el-form-item>
  18. <el-form-item label="\u884c\u4e1a">
  19. <el-select v-model="form.industryType" placeholder="\u9009\u62e9\u884c\u4e1a" filterable clearable style="width:100%">
  20. <el-option v-for="ind in industries" :key="ind.code" :label="ind.labelZh || ind.label" :value="ind.code" />
  21. </el-select>
  22. </el-form-item>
  23. <el-form-item label="\u5ba2\u6237\u6d88\u606f">
  24. <el-input v-model="form.message" type="textarea" :rows="4" placeholder="\u8f93\u5165\u5ba2\u6237\u6d88\u606f\uff0c\u53ef\u591a\u8f6e\u8fde\u7eed\u8c03\u8bd5" />
  25. </el-form-item>
  26. <el-form-item label="\u6301\u4e45\u5316\u72b6\u6001">
  27. <el-switch v-model="form.persistState" />
  28. </el-form-item>
  29. <el-form-item label="\u8df3\u8fc7LLM\u6e32\u67d3">
  30. <el-switch v-model="form.skipLlmRender" />
  31. </el-form-item>
  32. <el-form-item>
  33. <el-button type="primary" :loading="debugLoading" @click="runDebug">\u751f\u6210\u8c03\u8bd5\u56de\u590d</el-button>
  34. <el-button @click="loadState">\u67e5\u770b\u72b6\u6001</el-button>
  35. <el-button type="danger" plain @click="clearState">\u6e05\u7a7a\u72b6\u6001</el-button>
  36. </el-form-item>
  37. </el-form>
  38. </el-card>
  39. <el-card shadow="never" class="mt12">
  40. <div slot="header" class="card-header">
  41. <span><i class="el-icon-document-checked"></i> \u573a\u666f\u81ea\u68c0</span>
  42. <el-button type="text" size="mini" @click="loadScenarioSuite">\u5237\u65b0</el-button>
  43. </div>
  44. <el-table :data="scenarioRows" border size="mini" max-height="320">
  45. <el-table-column label="\u884c\u4e1a" prop="industry" width="80" />
  46. <el-table-column label="\u6d88\u606f" prop="message" min-width="140" show-overflow-tooltip />
  47. <el-table-column label="\u8bc6\u522b\u7c7b\u578b" prop="detectedType" width="90" />
  48. <el-table-column label="\u573a\u666f" prop="resolvedScenario" width="90" />
  49. <el-table-column label="\u8ffd\u95ee" prop="shouldProbe" width="60">
  50. <template slot-scope="scope">{{ scope.row.shouldProbe ? '\u662f' : '\u5426' }}</template>
  51. </el-table-column>
  52. </el-table>
  53. </el-card>
  54. </el-col>
  55. <el-col :span="14">
  56. <el-card shadow="never" class="reply-card">
  57. <div slot="header"><i class="el-icon-chat-dot-round"></i> \u8c03\u8bd5\u7ed3\u679c</div>
  58. <el-alert v-if="debugResult && debugResult.enabled === false" type="warning" show-icon :closable="false" title="UDD \u672a\u542f\u7528\u6216 FAST \u6a21\u5f0f\u5df2\u8df3\u8fc7" />
  59. <div v-if="debugResult && debugResult.reply" class="reply-block">
  60. <div class="section-title">\u56de\u590d</div>
  61. <div class="reply-text">{{ debugResult.reply }}</div>
  62. </div>
  63. <el-collapse v-if="debugResult" class="mt12">
  64. <el-collapse-item title="\u8bed\u4e49\u62c6\u89e3 (decomposition)" name="decomp">
  65. <pre class="json-pre">{{ formatJson(debugResult.decomposition) }}</pre>
  66. </el-collapse-item>
  67. <el-collapse-item title="\u56de\u590d\u8ba1\u5212 (plan)" name="plan">
  68. <pre class="json-pre">{{ formatJson(debugResult.plan) }}</pre>
  69. </el-collapse-item>
  70. <el-collapse-item title="\u586b\u69fd\u72b6\u6001 (state)" name="state">
  71. <pre class="json-pre">{{ formatJson(debugResult.state || stateResult.state) }}</pre>
  72. </el-collapse-item>
  73. <el-collapse-item title="\u753b\u50cf hints" name="hints">
  74. <pre class="json-pre">{{ formatJson(debugResult.profileHints) }}</pre>
  75. </el-collapse-item>
  76. </el-collapse>
  77. <div v-if="!debugResult && !debugLoading" class="empty-tip">\u8f93\u5165\u6d88\u606f\u540e\u70b9\u51fb\u300c\u751f\u6210\u8c03\u8bd5\u56de\u590d\u300d</div>
  78. </el-card>
  79. </el-col>
  80. </el-row>
  81. </div>
  82. </template>
  83. <script>
  84. import {
  85. uddDebugGenerate, uddGetState, uddClearState, uddScenarioSuite,
  86. listIndustryCorpusIndustries
  87. } from '@/api/workflow/lobster'
  88. export default {
  89. name: 'UddDebug',
  90. data() {
  91. return {
  92. industries: [],
  93. debugLoading: false,
  94. debugResult: null,
  95. stateResult: {},
  96. scenarioRows: [],
  97. form: {
  98. userKey: 'udd-debug-user',
  99. industryType: 'general',
  100. message: '',
  101. persistState: true,
  102. skipLlmRender: false
  103. }
  104. }
  105. },
  106. created() {
  107. listIndustryCorpusIndustries().then(res => {
  108. this.industries = res.data || []
  109. })
  110. this.loadScenarioSuite()
  111. },
  112. methods: {
  113. formatJson(obj) {
  114. if (obj == null) return '-'
  115. try {
  116. return JSON.stringify(obj, null, 2)
  117. } catch (e) {
  118. return String(obj)
  119. }
  120. },
  121. runDebug() {
  122. if (!this.form.message || !this.form.message.trim()) {
  123. this.$message.warning('\u8bf7\u8f93\u5165\u5ba2\u6237\u6d88\u606f')
  124. return
  125. }
  126. this.debugLoading = true
  127. uddDebugGenerate({
  128. userKey: this.form.userKey,
  129. industryType: this.form.industryType,
  130. message: this.form.message.trim(),
  131. persistState: this.form.persistState,
  132. skipLlmRender: this.form.skipLlmRender
  133. }).then(res => {
  134. this.debugResult = res.data || {}
  135. }).finally(() => { this.debugLoading = false })
  136. },
  137. loadState() {
  138. uddGetState(this.form.userKey).then(res => {
  139. this.stateResult = res.data || {}
  140. this.$message.success('\u72b6\u6001\u5df2\u5237\u65b0')
  141. })
  142. },
  143. clearState() {
  144. this.$confirm('\u786e\u8ba4\u6e05\u7a7a\u8be5\u7528\u6237\u7684 UDD \u586b\u69fd\u72b6\u6001\uff1f', '\u63d0\u793a', { type: 'warning' }).then(() => {
  145. uddClearState(this.form.userKey).then(() => {
  146. this.stateResult = {}
  147. this.debugResult = null
  148. this.$message.success('\u5df2\u6e05\u7a7a')
  149. })
  150. }).catch(() => {})
  151. },
  152. loadScenarioSuite() {
  153. uddScenarioSuite().then(res => {
  154. this.scenarioRows = res.data || []
  155. })
  156. }
  157. }
  158. }
  159. </script>
  160. <style scoped>
  161. .udd-debug-page .mt12 { margin-top: 12px; }
  162. .udd-debug-page .section-title { font-weight: 600; margin-bottom: 8px; color: #303133; }
  163. .udd-debug-page .reply-text {
  164. padding: 12px;
  165. background: #f5f7fa;
  166. border-radius: 4px;
  167. line-height: 1.6;
  168. white-space: pre-wrap;
  169. }
  170. .udd-debug-page .json-pre {
  171. margin: 0;
  172. padding: 8px;
  173. background: #fafafa;
  174. border-radius: 4px;
  175. font-size: 12px;
  176. max-height: 280px;
  177. overflow: auto;
  178. }
  179. .udd-debug-page .empty-tip { color: #909399; text-align: center; padding: 40px 0; }
  180. .udd-debug-page .card-header { display: flex; justify-content: space-between; align-items: center; }
  181. </style>
  182. `
  183. function write(rel, content) {
  184. const target = path.join(root, rel)
  185. fs.writeFileSync(target, content, { encoding: 'utf8' })
  186. const check = fs.readFileSync(target, 'utf8')
  187. const ok = /[\u4e00-\u9fff]/.test(check) && !check.includes('\ufffd')
  188. console.log(rel, ok ? 'OK' : 'FAIL', check.split('\n')[5].slice(0, 70))
  189. }
  190. write('saas-mgnui/src/views/lobster/udd-debug/index.vue', uddDebug)
  191. // industry-corpus-matrix: read current structure from git blob via exec - use separate minimal fix script part 2
  192. const industryPath = path.join(root, 'saas-mgnui/src/views/lobster/industry-corpus-matrix/index.vue')
  193. let industry = fs.readFileSync(industryPath, 'utf8')
  194. const replacements = [
  195. ['label="\u95ee\u95ee"', 'label="\u573a\u666f"'], // fallback if still broken
  196. ['label="锟斤拷锟斤拷"', 'label="锟斤拷锟斤拷"'],
  197. ['placeholder="全锟斤拷锟斤拷锟斤拷"', 'placeholder="全锟斤拷锟斤拷锟斤拷"'],
  198. ['>锟斤拷锟斤拷<', '>\u641c\u7d22<'],
  199. ['>锟斤拷锟斤拷<', '>\u91cd\u7f6e<'],
  200. ['>锟斤拷始锟斤拷锟斤拷前锟斤拷业<', '>\u521d\u59cb\u5316\u5f53\u524d\u884c\u4e1a<'],
  201. ['>AI+锟斤拷锟斤拷锟斤拷锟斤拷<', '>AI+\u8054\u7f51\u8865\u9f50<'],
  202. ['>锟斤拷锟斤拷锟斤拷锟斤拷锟较碉拷锟斤拷<', '>\u4ece\u9500\u51a0\u8bed\u6599\u5bfc\u5165<'],
  203. ['>锟斤拷锟斤拷锟斤拷目<', '>\u65b0\u589e\u6761\u76ee<'],
  204. ]
  205. // If file is fully corrupted, rebuild from unicode-escaped template in part 2 file
  206. if (!industry.includes('\u573a\u666f') && !industry.includes('锟斤拷锟斤拷')) {
  207. console.log('industry-corpus-matrix needs full rewrite - run part 2')
  208. process.exitCode = 1
  209. } else {
  210. fs.writeFileSync(industryPath, industry, 'utf8')
  211. console.log('industry-corpus-matrix', 'kept existing if readable')
  212. }