add.html 36 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775
  1. <!DOCTYPE html>
  2. <html lang="zh" xmlns:th="http://www.thymeleaf.org">
  3. <head>
  4. <th:block th:include="include :: header('修改呼入大模型配置')"/>
  5. </head>
  6. <body class="white-bg">
  7. <div class="wrapper wrapper-content animated fadeInRight ibox-content">
  8. <form class="form-horizontal m" id="form-inboundllm-add" th:object="${ccInboundLlmAccount}">
  9. <input name="id" th:field="*{id}" type="hidden">
  10. <!-- 1. 别名 -->
  11. <div class="col-xs-12">
  12. <div class="form-group">
  13. <label class="col-sm-3 control-label is-required" th:text="#{inboundllm.form.inboundAlias}"></label>
  14. <div class="col-sm-8">
  15. <input name="inboundAlias" th:field="*{inboundAlias}" class="form-control" type="text" required>
  16. </div>
  17. </div>
  18. </div>
  19. <!-- 1. 被叫号码 -->
  20. <div class="col-xs-12">
  21. <div class="form-group">
  22. <label class="col-sm-3 control-label is-required" th:text="#{inboundllm.form.callee}"></label>
  23. <div class="col-sm-8">
  24. <input name="callee" th:field="*{callee}" class="form-control" type="text" required>
  25. </div>
  26. </div>
  27. </div>
  28. <!-- 2. 服务类型 -->
  29. <div class="col-xs-12">
  30. <div class="form-group">
  31. <label class="col-sm-3 control-label is-required" th:text="#{inboundllm.form.serviceType}"></label>
  32. <div class="col-sm-8">
  33. <select name="serviceType" th:field="*{serviceType}" class="form-control" id="serviceTypeSelect" required>
  34. <option value="ai" th:text="#{inboundllm.form.serviceTypeAI}"></option>
  35. <option value="acd" th:text="#{inboundllm.form.serviceTypeACD}"></option>
  36. <option value="ivr" th:text="#{inboundllm.form.serviceTypeIVR}"></option>
  37. </select>
  38. </div>
  39. </div>
  40. </div>
  41. <!-- 3. 大模型底座 (仅 AI 可见)-->
  42. <div class="col-xs-12 ai-only">
  43. <div class="form-group">
  44. <label class="col-sm-3 control-label is-required" th:text="#{inboundllm.form.llmAccountId}"></label>
  45. <div class="col-sm-8">
  46. <select name="llmAccountId" id="llmAccountId" th:field="*{llmAccountId}" class="form-control" required>
  47. <option value="" th:text="#{inboundllm.form.llmAccountId.empty}"></option>
  48. </select>
  49. </div>
  50. </div>
  51. </div>
  52. <!-- 4. ASR 提供商(仅 AI 可见) -->
  53. <div class="col-xs-12 ai-only">
  54. <div class="form-group">
  55. <label class="col-sm-3 control-label is-required" th:text="#{inboundllm.form.asrProvider}"></label>
  56. <div class="col-sm-8">
  57. <select name="asrProvider" id="asrProvider" th:field="*{asrProvider}" class="form-control" required>
  58. <option value="" th:text="#{inboundllm.form.asrProvider.empty}"></option>
  59. </select>
  60. </div>
  61. </div>
  62. </div>
  63. <!-- ASR语言选择(仅 AI 可见) -->
  64. <div class="col-xs-12 ai-only" id="asrLanguageCodeDiv" style="display:none;">
  65. <div class="form-group">
  66. <label class="col-sm-3 control-label is-required" th:text="#{inboundllm.form.asrLanguageCode}">ASR语言</label>
  67. <div class="col-sm-8">
  68. <select name="asrLanguageCode" id="asrLanguageCode" th:field="*{asrLanguageCode}" class="form-control" required>
  69. <option value="" th:text="#{inboundllm.form.asrLanguageCode.empty}">请选择ASR语言</option>
  70. </select>
  71. </div>
  72. </div>
  73. </div>
  74. <!-- 新增:ASR模型选择(仅 AI 可见) -->
  75. <div class="col-xs-12 ai-only" id="asrModelsDiv" style="display:none;">
  76. <div class="form-group">
  77. <label class="col-sm-3 control-label is-required" th:text="#{inboundllm.form.asrModels}">ASR模型</label>
  78. <div class="col-sm-8">
  79. <select name="asrModels" id="asrModels" th:field="*{asrModels}" class="form-control" required>
  80. <option value="" th:text="#{inboundllm.form.asrModels.empty}">请选择ASR模型</option>
  81. </select>
  82. </div>
  83. </div>
  84. </div>
  85. <!-- 5. 音色来源(仅 AI 可见,LocalWavFile 时隐藏) -->
  86. <div class="col-xs-12 ai-only voice-config">
  87. <div class="form-group">
  88. <label class="col-sm-3 control-label is-required" th:text="#{inboundllm.form.voiceSource}"></label>
  89. <div class="col-sm-8">
  90. <select name="voiceSource" id="voiceSource" th:field="*{voiceSource}" class="form-control" required>
  91. <option value="" th:text="#{inboundllm.form.voiceSource.empty}"></option>
  92. </select>
  93. </div>
  94. </div>
  95. </div>
  96. <!-- TTS语言选择(仅 AI 可见,LocalWavFile 时隐藏) -->
  97. <div class="col-xs-12 ai-only voice-config" id="ttsLanguageCodeDiv" style="display:none;">
  98. <div class="form-group">
  99. <label class="col-sm-3 control-label is-required" th:text="#{inboundllm.form.ttsLanguageCode}">TTS语言</label>
  100. <div class="col-sm-8">
  101. <select name="ttsLanguageCode" id="ttsLanguageCode" th:field="*{ttsLanguageCode}" class="form-control" required>
  102. <option value="" th:text="#{inboundllm.form.ttsLanguageCode.empty}">请选择TTS语言</option>
  103. </select>
  104. </div>
  105. </div>
  106. </div>
  107. <!-- 新增:TTS模型选择(仅 AI 可见,LocalWavFile 时隐藏) -->
  108. <div class="col-xs-12 ai-only voice-config" id="ttsModelsDiv" style="display:none;">
  109. <div class="form-group">
  110. <label class="col-sm-3 control-label is-required" th:text="#{inboundllm.form.ttsModels}">TTS模型</label>
  111. <div class="col-sm-8">
  112. <select name="ttsModels" id="ttsModels" th:field="*{ttsModels}" class="form-control" required>
  113. <option value="" th:text="#{inboundllm.form.ttsModels.empty}">请选择TTS模型</option>
  114. </select>
  115. </div>
  116. </div>
  117. </div>
  118. <!-- 6. 音色编码(仅 AI 可见,LocalWavFile 时隐藏) -->
  119. <div class="col-xs-12 ai-only voice-config">
  120. <div class="form-group">
  121. <label class="col-sm-3 control-label is-required" th:text="#{inboundllm.form.voiceCode}"></label>
  122. <div class="col-sm-8">
  123. <select name="voiceCode" id="voiceCode" th:field="*{voiceCode}" class="form-control" required>
  124. <option value="" th:text="#{inboundllm.form.voiceCode.empty}"></option>
  125. </select>
  126. </div>
  127. </div>
  128. </div>
  129. <!-- 7. AI 转接类型(仅 AI 可见) -->
  130. <div class="col-xs-12 ai-only" id="aiTransferTypeDiv">
  131. <div class="form-group">
  132. <label class="col-sm-3 control-label is-required" th:text="#{inboundllm.form.aiTransferType}"></label>
  133. <div class="col-sm-8">
  134. <select name="aiTransferType" th:field="*{aiTransferType}" id="aiTransferTypeSelect" class="form-control" required>
  135. <option value="acd" th:text="#{inboundllm.form.aiTransferTypeACD}"></option>
  136. <option value="extension" th:text="#{inboundllm.form.aiTransferTypeExtension}"></option>
  137. <option value="gateway" th:text="#{inboundllm.form.aiTransferTypeGateway}"></option>
  138. </select>
  139. </div>
  140. </div>
  141. </div>
  142. <!-- 8. IVR 下拉(仅 IVR 可见) -->
  143. <div class="col-xs-12 ivr-only">
  144. <div class="form-group">
  145. <label class="col-sm-3 control-label is-required" th:text="#{inboundllm.form.ivrId}"></label>
  146. <div class="col-sm-8">
  147. <select name="ivrId" th:field="*{ivrId}" class="form-control" required>
  148. <option value="" th:text="#{inboundllm.form.ivrId.empty}"></option>
  149. </select>
  150. </div>
  151. </div>
  152. </div>
  153. <!-- 9. 业务组(ACD / AI+ACD 可见) -->
  154. <div class="col-xs-12 transfer-field acd-only acd-transfer">
  155. <div class="form-group">
  156. <label class="col-sm-3 control-label is-required" th:text="#{inboundllm.form.aiTransferGroupId}"></label>
  157. <div class="col-sm-8">
  158. <select name="aiTransferGroupId" th:field="*{aiTransferGroupId}" class="form-control" required>
  159. <option value="" th:text="#{inboundllm.form.aiTransferGroupId.empty}"></option>
  160. </select>
  161. </div>
  162. </div>
  163. </div>
  164. <!-- 10. 网关(AI+Gateway 可见) -->
  165. <div class="col-xs-12 transfer-field gateway-transfer">
  166. <div class="form-group">
  167. <label class="col-sm-3 control-label is-required" th:text="#{inboundllm.form.aiTransferGatewayId}"></label>
  168. <div class="col-sm-8">
  169. <select name="aiTransferGatewayId" th:field="*{aiTransferGatewayId}" class="form-control" required>
  170. <option value="" th:text="#{inboundllm.form.aiTransferGatewayId.empty}"></option>
  171. </select>
  172. </div>
  173. </div>
  174. </div>
  175. <!-- 11. 网关目标号码(AI+Gateway 可见) -->
  176. <div class="col-xs-12 transfer-field gateway-transfer">
  177. <div class="form-group">
  178. <label class="col-sm-3 control-label is-required" th:text="#{inboundllm.form.aiTransferGatewayDestNumber}"></label>
  179. <div class="col-sm-8">
  180. <input name="aiTransferGatewayDestNumber" th:field="*{aiTransferGatewayDestNumber}" class="form-control" type="text" required>
  181. </div>
  182. </div>
  183. </div>
  184. <!-- 12. 分机号(AI+Extension 可见) -->
  185. <div class="col-xs-12 transfer-field extension-transfer">
  186. <div class="form-group">
  187. <label class="col-sm-3 control-label is-required" th:text="#{inboundllm.form.aiTransferExtNumber}"></label>
  188. <div class="col-sm-8">
  189. <input name="aiTransferExtNumber" th:field="*{aiTransferExtNumber}" class="form-control" type="text" required>
  190. </div>
  191. </div>
  192. </div>
  193. <!-- 13. 服务评价 下拉 -->
  194. <div class="col-xs-12">
  195. <div class="form-group">
  196. <label class="col-sm-3 control-label " th:text="#{inboundllm.form.satisfSurveyIvrId}"></label>
  197. <div class="col-sm-8">
  198. <select name="satisfSurveyIvrId" th:field="*{satisfSurveyIvrId}" class="form-control" >
  199. <option value="" th:text="#{inboundllm.form.satisfSurveyIvrId.empty}"></option>
  200. </select>
  201. </div>
  202. </div>
  203. </div>
  204. </form>
  205. </div>
  206. <th:block th:include="include :: footer"/>
  207. <script th:inline="javascript">
  208. var prefix = ctx + "aicall/inboundllm";
  209. // 存储llmAccount数据,用于判断providerClassName
  210. var llmAccountMap = {};
  211. $(function(){
  212. /* ---------- 通用下拉数据加载 ---------- */
  213. // 大模型底座
  214. $.ajax({
  215. url: ctx + "aicall/account/all",
  216. success: function(rsp) {
  217. var llmAccountSelect = $('select[name="llmAccountId"]');
  218. llmAccountSelect.empty();
  219. llmAccountSelect.append('<option value="">' + i18n('inboundllm.form.llmAccountId.empty') + '</option>');
  220. rsp.data.forEach(function(llmAccount) {
  221. llmAccountSelect.append($("<option>")
  222. .attr("value", llmAccount.id)
  223. .attr("data-provider", llmAccount.providerClassName)
  224. .text(llmAccount.name));
  225. llmAccountMap[llmAccount.id] = llmAccount;
  226. });
  227. var llmAccountId = /*[[${ccInboundLlmAccount.llmAccountId}]]*/ '';
  228. if (llmAccountId) {
  229. llmAccountSelect.val(llmAccountId);
  230. checkAndToggleVoiceFields(llmAccountId);
  231. }
  232. }
  233. });
  234. // ASR 提供商
  235. $.ajax({
  236. url: ctx + "aicall/ttsAliyun/asr/provider/all",
  237. success: function(rsp) {
  238. var providerSelect = $('#asrProvider');
  239. providerSelect.empty();
  240. Object.entries(rsp.data).forEach(function([key, value]) {
  241. providerSelect.append($("<option>").attr("value", key).text(value));
  242. });
  243. var savedProvider = /*[[${ccInboundLlmAccount.asrProvider}]]*/ '';
  244. if (savedProvider) {
  245. providerSelect.val(savedProvider);
  246. loadAsrLanguages(savedProvider, function() {
  247. var savedAsrLanguageCode = /*[[${ccInboundLlmAccount.asrLanguageCode}]]*/ '';
  248. if (savedAsrLanguageCode) {
  249. $('#asrLanguageCode').val(savedAsrLanguageCode);
  250. loadAsrModels(savedProvider, savedAsrLanguageCode, function() {
  251. var savedAsrModels = /*[[${ccInboundLlmAccount.asrModels}]]*/ '';
  252. if (savedAsrModels) {
  253. $('#asrModels').val(savedAsrModels);
  254. }
  255. });
  256. }
  257. });
  258. }
  259. }
  260. });
  261. // 音色来源
  262. $.ajax({
  263. url: ctx + "aicall/ttsAliyun/tts/voiceSource/all",
  264. success: function(rsp) {
  265. var voiceSourceSelect = $('#voiceSource');
  266. voiceSourceSelect.empty();
  267. Object.entries(rsp.data).forEach(function([key, value]) {
  268. voiceSourceSelect.append($("<option>").attr("value", key).text(value));
  269. });
  270. var savedVoiceSource = /*[[${ccInboundLlmAccount.voiceSource}]]*/ '';
  271. if (savedVoiceSource) {
  272. voiceSourceSelect.val(savedVoiceSource);
  273. loadTtsLanguages(savedVoiceSource, function() {
  274. var savedTtsLanguageCode = /*[[${ccInboundLlmAccount.ttsLanguageCode}]]*/ '';
  275. if (savedTtsLanguageCode) {
  276. $('#ttsLanguageCode').val(savedTtsLanguageCode);
  277. loadTtsModels(savedVoiceSource, savedTtsLanguageCode, function() {
  278. var savedTtsModels = /*[[${ccInboundLlmAccount.ttsModels}]]*/ '';
  279. if (savedTtsModels) {
  280. $('#ttsModels').val(savedTtsModels);
  281. loadVoicesByVoiceSourceAndLanguage(savedVoiceSource, savedTtsLanguageCode, savedTtsModels);
  282. } else {
  283. loadVoicesByVoiceSourceAndLanguage(savedVoiceSource, savedTtsLanguageCode, '');
  284. }
  285. });
  286. }
  287. });
  288. }
  289. }
  290. });
  291. // 业务组
  292. $.ajax({
  293. url: ctx + "cc/bizgroup/all",
  294. success: function(rsp) {
  295. var groupSelect = $('select[name="aiTransferGroupId"]');
  296. groupSelect.empty();
  297. groupSelect.append('<option value="">' + i18n('inboundllm.form.aiTransferGroupId.empty') + '</option>');
  298. rsp.data.forEach(function(bizGroup) {
  299. groupSelect.append($("<option>").attr("value", bizGroup.groupId).text(bizGroup.bizGroupName));
  300. });
  301. var groupId = /*[[${ccInboundLlmAccount.aiTransferGroupId}]]*/ '';
  302. if (groupId) groupSelect.val(groupId);
  303. }
  304. });
  305. // 出局网关
  306. $.ajax({
  307. url: ctx + "cc/gateways/outbound",
  308. success: function(rsp) {
  309. var gatewaySelect = $('select[name="aiTransferGatewayId"]');
  310. gatewaySelect.empty();
  311. gatewaySelect.append('<option value="">' + i18n('inboundllm.form.aiTransferGatewayId.empty') + '</option>');
  312. rsp.data.forEach(function(gateway) {
  313. gatewaySelect.append($("<option>").attr("value", gateway.id).text(gateway.gwDesc));
  314. });
  315. var aiTransferGatewayId = /*[[${ccInboundLlmAccount.aiTransferGatewayId}]]*/ '';
  316. if (aiTransferGatewayId) gatewaySelect.val(aiTransferGatewayId);
  317. }
  318. });
  319. // IVR 下拉
  320. $.ajax({
  321. url: ctx + "cc/ivr/all",
  322. success: function(rsp) {
  323. var ivrIdSelect = $('select[name="ivrId"]');
  324. ivrIdSelect.empty();
  325. ivrIdSelect.append('<option value="">' + i18n('inboundllm.form.ivrId.empty') + '</option>');
  326. rsp.data.forEach(function(ccIvr) {
  327. ivrIdSelect.append($("<option>").attr("value", ccIvr.id).text(ccIvr.ivrNodeName));
  328. });
  329. var ivrId = /*[[${ccInboundLlmAccount.ivrId}]]*/ '';
  330. if (ivrId) ivrIdSelect.val(ivrId);
  331. }
  332. });
  333. // satisfSurveyIvrId 下拉
  334. $.ajax({
  335. url: ctx + "cc/ivr/all",
  336. success: function(rsp) {
  337. var satisfSurveyIvrIdSelect = $('select[name="satisfSurveyIvrId"]');
  338. satisfSurveyIvrIdSelect.empty();
  339. satisfSurveyIvrIdSelect.append('<option value="">' + i18n('inboundllm.form.satisfSurveyIvrId.empty') + '</option>');
  340. rsp.data.forEach(function(ccIvr) {
  341. satisfSurveyIvrIdSelect.append($("<option>").attr("value", ccIvr.id).text(ccIvr.ivrNodeName));
  342. });
  343. var satisfSurveyIvrId = /*[[${ccInboundLlmAccount.satisfSurveyIvrId}]]*/ '';
  344. if (satisfSurveyIvrId) satisfSurveyIvrIdSelect.val(satisfSurveyIvrId);
  345. }
  346. });
  347. /* ---------- 事件绑定 ---------- */
  348. $(document).on('change', '#voiceSource', function() {
  349. var voiceSource = $(this).val();
  350. // 清空并隐藏模型下拉框
  351. $('#ttsModels').empty().append('<option value="">' + i18n('inboundllm.form.ttsModels.empty') + '</option>');
  352. $('#ttsModelsDiv').hide();
  353. loadTtsLanguages(voiceSource, function() {
  354. var ttsLanguageCode = $('#ttsLanguageCode').val();
  355. if (ttsLanguageCode) {
  356. loadTtsModels(voiceSource, ttsLanguageCode, function() {
  357. var ttsModels = $('#ttsModels').val();
  358. loadVoicesByVoiceSourceAndLanguage(voiceSource, ttsLanguageCode, ttsModels);
  359. });
  360. } else {
  361. $('#voiceCode').empty().append('<option value="">' + i18n('inboundllm.form.voiceCode.empty') + '</option>');
  362. }
  363. });
  364. });
  365. $(document).on('change', '#ttsLanguageCode', function() {
  366. var voiceSource = $('#voiceSource').val();
  367. var ttsLanguageCode = $(this).val();
  368. loadTtsModels(voiceSource, ttsLanguageCode, function() {
  369. var ttsModels = $('#ttsModels').val();
  370. loadVoicesByVoiceSourceAndLanguage(voiceSource, ttsLanguageCode, ttsModels);
  371. });
  372. });
  373. $(document).on('change', '#ttsModels', function() {
  374. var voiceSource = $('#voiceSource').val();
  375. var ttsLanguageCode = $('#ttsLanguageCode').val();
  376. var ttsModels = $(this).val();
  377. loadVoicesByVoiceSourceAndLanguage(voiceSource, ttsLanguageCode, ttsModels);
  378. });
  379. $(document).on('change', '#asrProvider', function() {
  380. var asrProvider = $(this).val();
  381. // 清空并隐藏模型下拉框
  382. $('#asrModels').empty().append('<option value="">' + i18n('inboundllm.form.asrModels.empty') + '</option>');
  383. $('#asrModelsDiv').hide();
  384. loadAsrLanguages(asrProvider, function() {
  385. var asrLanguageCode = $('#asrLanguageCode').val();
  386. if (asrLanguageCode) {
  387. loadAsrModels(asrProvider, asrLanguageCode);
  388. }
  389. });
  390. });
  391. $(document).on('change', '#asrLanguageCode', function() {
  392. var asrProvider = $('#asrProvider').val();
  393. var asrLanguageCode = $(this).val();
  394. loadAsrModels(asrProvider, asrLanguageCode);
  395. });
  396. $(document).on('change', '#serviceTypeSelect', function() {
  397. toggleFields();
  398. // 清空satisfSurveyIvrId
  399. $('select[name="satisfSurveyIvrId"]').val("");
  400. });
  401. $(document).on('change', '#aiTransferTypeSelect', function() {
  402. toggleFields();
  403. });
  404. // 监听大模型底座变更
  405. $(document).on('change', '#llmAccountId', function() {
  406. checkAndToggleVoiceFields($(this).val());
  407. });
  408. /* ---------- 校验 ---------- */
  409. $('input[name="callee"]').rules('add', {
  410. remote: {
  411. url: prefix + '/checkCallee',
  412. type: 'get',
  413. data: {
  414. id: function () { return $('input[name="id"]').val(); },
  415. callee: function () { return $('input[name="callee"]').val(); }
  416. },
  417. dataFilter: function (resp) {
  418. return JSON.parse(resp).data ? 'true' : '"该号码不可用"';
  419. }
  420. },
  421. messages: { remote: '该号码不可用' }
  422. });
  423. /* ---------- 初始化 ---------- */
  424. toggleFields();
  425. });
  426. $("#form-inboundllm-add").validate({ focusCleanup: true });
  427. function submitHandler() {
  428. if ($.validate.form()) {
  429. $.operate.save(prefix + "/add", $('#form-inboundllm-add').serialize());
  430. }
  431. }
  432. /* ========== 工具函数 ========== */
  433. // 根据TTS厂商加载语言列表
  434. function loadTtsLanguages(voiceSource, callback) {
  435. var languageSelect = $('#ttsLanguageCode');
  436. var languageDiv = $('#ttsLanguageCodeDiv');
  437. var modelsSelect = $('#ttsModels');
  438. var modelsDiv = $('#ttsModelsDiv');
  439. if (!voiceSource) {
  440. languageSelect.empty().append('<option value="">' + i18n('inboundllm.form.ttsLanguageCode.empty') + '</option>');
  441. languageDiv.hide();
  442. // 清空并隐藏模型下拉框
  443. modelsSelect.empty().append('<option value="">' + i18n('inboundllm.form.ttsModels.empty') + '</option>');
  444. modelsDiv.hide();
  445. if (callback) callback();
  446. return;
  447. }
  448. $.ajax({
  449. url: ctx + "aicall/ttsAliyun/tts/language",
  450. data: { voiceSource: voiceSource },
  451. success: function(rsp) {
  452. languageSelect.empty();
  453. if (rsp.data && rsp.data.length > 0) {
  454. // 如果只有一个选项,直接选中且不显示下拉框,但仍需调用models接口
  455. if (rsp.data.length === 1) {
  456. var item = rsp.data[0];
  457. var langCode = item.code || item.key || item.value;
  458. languageSelect.append($("<option>").attr("value", langCode).text(item.name || item.label || item.text || item.value));
  459. languageSelect.val(langCode);
  460. languageDiv.hide();
  461. // 单条数据默认选中时也要加载models
  462. loadTtsModels(voiceSource, langCode, callback);
  463. } else {
  464. languageSelect.append('<option value="">' + i18n('inboundllm.form.ttsLanguageCode.empty') + '</option>');
  465. rsp.data.forEach(function(item) {
  466. languageSelect.append($("<option>").attr("value", item.code || item.key || item.value).text(item.name || item.label || item.text || item.value));
  467. });
  468. languageDiv.show();
  469. // 多语言时,先清空并隐藏模型下拉框,等待语言选择后再加载
  470. modelsSelect.empty().append('<option value="">' + i18n('inboundllm.form.ttsModels.empty') + '</option>');
  471. modelsDiv.hide();
  472. if (callback) callback();
  473. }
  474. } else {
  475. languageSelect.append('<option value="">' + i18n('inboundllm.form.ttsLanguageCode.empty') + '</option>');
  476. languageDiv.show();
  477. // 无数据时隐藏模型下拉框
  478. modelsSelect.empty().append('<option value="">' + i18n('inboundllm.form.ttsModels.empty') + '</option>');
  479. modelsDiv.hide();
  480. if (callback) callback();
  481. }
  482. }
  483. });
  484. }
  485. // 根据ASR厂商加载语言列表
  486. function loadAsrLanguages(asrProvider, callback) {
  487. var languageSelect = $('#asrLanguageCode');
  488. var languageDiv = $('#asrLanguageCodeDiv');
  489. var modelsSelect = $('#asrModels');
  490. var modelsDiv = $('#asrModelsDiv');
  491. if (!asrProvider) {
  492. languageSelect.empty().append('<option value="">' + i18n('inboundllm.form.asrLanguageCode.empty') + '</option>');
  493. languageDiv.hide();
  494. // 清空并隐藏模型下拉框
  495. modelsSelect.empty().append('<option value="">' + i18n('inboundllm.form.asrModels.empty') + '</option>');
  496. modelsDiv.hide();
  497. if (callback) callback();
  498. return;
  499. }
  500. $.ajax({
  501. url: ctx + "aicall/ttsAliyun/asr/language",
  502. data: { asrProvider: asrProvider },
  503. success: function(rsp) {
  504. languageSelect.empty();
  505. if (rsp.data && rsp.data.length > 0) {
  506. // 如果只有一个选项,直接选中且不显示下拉框,但仍需调用models接口
  507. if (rsp.data.length === 1) {
  508. var item = rsp.data[0];
  509. var langCode = item.code || item.key || item.value;
  510. languageSelect.append($("<option>").attr("value", langCode).text(item.name || item.label || item.text || item.value));
  511. languageSelect.val(langCode);
  512. languageDiv.hide();
  513. // 单条数据默认选中时也要加载models
  514. loadAsrModels(asrProvider, langCode, callback);
  515. } else {
  516. languageSelect.append('<option value="">' + i18n('inboundllm.form.asrLanguageCode.empty') + '</option>');
  517. rsp.data.forEach(function(item) {
  518. languageSelect.append($("<option>").attr("value", item.code || item.key || item.value).text(item.name || item.label || item.text || item.value));
  519. });
  520. languageDiv.show();
  521. // 多语言时,先清空并隐藏模型下拉框,等待语言选择后再加载
  522. modelsSelect.empty().append('<option value="">' + i18n('inboundllm.form.asrModels.empty') + '</option>');
  523. modelsDiv.hide();
  524. if (callback) callback();
  525. }
  526. } else {
  527. languageSelect.append('<option value="">' + i18n('inboundllm.form.asrLanguageCode.empty') + '</option>');
  528. languageDiv.show();
  529. // 无数据时隐藏模型下拉框
  530. modelsSelect.empty().append('<option value="">' + i18n('inboundllm.form.asrModels.empty') + '</option>');
  531. modelsDiv.hide();
  532. if (callback) callback();
  533. }
  534. }
  535. });
  536. }
  537. // 根据TTS厂商和语言加载模型列表
  538. function loadTtsModels(voiceSource, ttsLanguageCode, callback) {
  539. var modelsSelect = $('#ttsModels');
  540. var modelsDiv = $('#ttsModelsDiv');
  541. if (!voiceSource || !ttsLanguageCode) {
  542. modelsSelect.empty().append('<option value="">' + i18n('inboundllm.form.ttsModels.empty') + '</option>');
  543. modelsDiv.hide();
  544. if (callback) callback();
  545. return;
  546. }
  547. $.ajax({
  548. url: ctx + "aicall/ttsAliyun/tts/models",
  549. data: {
  550. voiceSource: voiceSource,
  551. ttsLanguageCode: ttsLanguageCode
  552. },
  553. success: function(rsp) {
  554. modelsSelect.empty();
  555. if (rsp.data && rsp.data.length > 0) {
  556. // 如果只有一个选项,直接选中且不显示下拉框
  557. if (rsp.data.length === 1) {
  558. var item = rsp.data[0];
  559. var modelValue = item.code || item.key || item.value;
  560. modelsSelect.append($("<option>").attr("value", modelValue).text(item.name || item.label || item.text || item.value));
  561. modelsSelect.val(modelValue);
  562. modelsDiv.hide(); // 单值时隐藏
  563. } else {
  564. modelsSelect.append('<option value="">' + i18n('inboundllm.form.ttsModels.empty') + '</option>');
  565. rsp.data.forEach(function(item) {
  566. modelsSelect.append($("<option>").attr("value", item.code || item.key || item.value).text(item.name || item.label || item.text || item.value));
  567. });
  568. modelsDiv.show(); // 多值时显示
  569. }
  570. } else {
  571. modelsSelect.append('<option value="">' + i18n('inboundllm.form.ttsModels.empty') + '</option>');
  572. modelsDiv.hide(); // 无数据时隐藏
  573. }
  574. if (callback) callback();
  575. }
  576. });
  577. }
  578. // 根据ASR厂商和语言加载模型列表
  579. function loadAsrModels(asrProvider, asrLanguageCode, callback) {
  580. var modelsSelect = $('#asrModels');
  581. var modelsDiv = $('#asrModelsDiv');
  582. if (!asrProvider || !asrLanguageCode) {
  583. modelsSelect.empty().append('<option value="">' + i18n('inboundllm.form.asrModels.empty') + '</option>');
  584. modelsDiv.hide();
  585. if (callback) callback();
  586. return;
  587. }
  588. $.ajax({
  589. url: ctx + "aicall/ttsAliyun/asr/models",
  590. data: {
  591. asrProvider: asrProvider,
  592. asrLanguageCode: asrLanguageCode
  593. },
  594. success: function(rsp) {
  595. modelsSelect.empty();
  596. if (rsp.data && rsp.data.length > 0) {
  597. // 如果只有一个选项,直接选中且不显示下拉框
  598. if (rsp.data.length === 1) {
  599. var item = rsp.data[0];
  600. var modelValue = item.code || item.key || item.value;
  601. modelsSelect.append($("<option>").attr("value", modelValue).text(item.name || item.label || item.text || item.value));
  602. modelsSelect.val(modelValue);
  603. modelsDiv.hide(); // 单值时隐藏
  604. } else {
  605. modelsSelect.append('<option value="">' + i18n('inboundllm.form.asrModels.empty') + '</option>');
  606. rsp.data.forEach(function(item) {
  607. modelsSelect.append($("<option>").attr("value", item.code || item.key || item.value).text(item.name || item.label || item.text || item.value));
  608. });
  609. modelsDiv.show(); // 多值时显示
  610. }
  611. } else {
  612. modelsSelect.append('<option value="">' + i18n('inboundllm.form.asrModels.empty') + '</option>');
  613. modelsDiv.hide(); // 无数据时隐藏
  614. }
  615. if (callback) callback();
  616. }
  617. });
  618. }
  619. // 根据TTS厂商、语言和模型加载音色
  620. function loadVoicesByVoiceSourceAndLanguage(voiceSource, ttsLanguageCode, ttsModels) {
  621. var voiceSelect = $('#voiceCode');
  622. if (!voiceSource || !ttsLanguageCode) {
  623. voiceSelect.empty().append('<option value="">' + i18n('inboundllm.form.voiceCode.empty') + '</option>');
  624. return;
  625. }
  626. $.ajax({
  627. url: ctx + "aicall/ttsAliyun/getByLanguageCode",
  628. data: {
  629. voiceSource: voiceSource,
  630. ttsLanguageCode: ttsLanguageCode,
  631. ttsModels: ttsModels
  632. },
  633. success: function(rsp) {
  634. voiceSelect.empty();
  635. rsp.data.forEach(function(voice) {
  636. voiceSelect.append($("<option>")
  637. .attr("value", voice.voiceCode)
  638. .attr("data-source", voice.voiceSource)
  639. .text(voice.voiceName));
  640. });
  641. var voiceCode = /*[[${ccInboundLlmAccount.voiceCode}]]*/ '';
  642. if (voiceCode) voiceSelect.val(voiceCode);
  643. }
  644. });
  645. }
  646. function toggleFields() {
  647. var serviceType = $('#serviceTypeSelect').val();
  648. var aiTransferType = $('#aiTransferTypeSelect').val();
  649. // 先全部隐藏
  650. $('.ai-only,.acd-only,.ivr-only,.transfer-field').hide();
  651. if (serviceType === 'ai') {
  652. $('.ai-only').show();
  653. // 根据当前值重新判断语言下拉框是否显示
  654. var ttsLanguageCount = $('#ttsLanguageCode option').length;
  655. var asrLanguageCount = $('#asrLanguageCode option').length;
  656. var ttsModelsCount = $('#ttsModels option').length;
  657. var asrModelsCount = $('#asrModels option').length;
  658. if (ttsLanguageCount <= 1) $('#ttsLanguageCodeDiv').hide();
  659. if (asrLanguageCount <= 1) $('#asrLanguageCodeDiv').hide();
  660. if (ttsModelsCount <= 1) $('#ttsModelsDiv').hide();
  661. if (asrModelsCount <= 1) $('#asrModelsDiv').hide();
  662. // 检查是否需要隐藏TTS相关字段
  663. var llmAccountId = $('#llmAccountId').val();
  664. if (llmAccountId) {
  665. checkAndToggleVoiceFields(llmAccountId);
  666. }
  667. if (aiTransferType === 'acd') $('.acd-transfer').show();
  668. if (aiTransferType === 'gateway') $('.gateway-transfer').show();
  669. if (aiTransferType === 'extension')$('.extension-transfer').show();
  670. } else if (serviceType === 'acd') {
  671. $('.acd-only').show();
  672. } else if (serviceType === 'ivr') {
  673. $('.ivr-only').show();
  674. }
  675. }
  676. function checkAndToggleVoiceFields(llmAccountId) {
  677. var llmAccount = llmAccountMap[llmAccountId];
  678. if (llmAccount && llmAccount.providerClassName === 'LocalWavFile') {
  679. // LocalWavFile时隐藏TTS相关字段(voiceSource、ttsLanguageCode、ttsModels、voiceCode),保留ASR
  680. $('.voice-config').hide();
  681. $('.voice-config select').prop('required', false);
  682. // 清空TTS相关值
  683. $('#voiceSource').val('');
  684. $('#ttsLanguageCode').val('');
  685. $('#ttsModels').val('');
  686. $('#voiceCode').val('');
  687. } else {
  688. // 非LocalWavFile时显示TTS相关字段
  689. var serviceType = $('#serviceTypeSelect').val();
  690. if (serviceType === 'ai') {
  691. $('.voice-config').show();
  692. $('.voice-config select').prop('required', true);
  693. // 根据当前值重新判断语言下拉框是否显示
  694. var ttsLanguageCount = $('#ttsLanguageCode option').length;
  695. var ttsModelsCount = $('#ttsModels option').length;
  696. if (ttsLanguageCount <= 1) {
  697. $('#ttsLanguageCodeDiv').hide();
  698. }
  699. if (ttsModelsCount <= 1) {
  700. $('#ttsModelsDiv').hide();
  701. }
  702. }
  703. }
  704. }
  705. </script>
  706. </body>
  707. </html>