import { defineComponent, ref, reactive, computed, unref, useSSRContext } from 'vue'; import { ssrRenderAttrs, ssrIncludeBooleanAttr, ssrLooseContain, ssrLooseEqual, ssrRenderList, ssrRenderAttr, ssrInterpolate, ssrRenderClass } from 'vue/server-renderer'; import { u as useApi } from './useApi-B-E5eLsI.mjs'; import { u as useToast } from './useToast-CS21XT61.mjs'; import { L as LANG_OPTIONS } from './useLangOptions-DMhiAuTa.mjs'; import { _ as _export_sfc } from './server.mjs'; import './useLoading-D4zrSa2m.mjs'; import '../nitro/nitro.mjs'; import 'node:http'; import 'node:https'; import 'node:events'; import 'node:buffer'; import 'node:fs'; import 'node:path'; import 'node:crypto'; import 'node:url'; import '../routes/renderer.mjs'; import 'vue-bundle-renderer/runtime'; import 'unhead/server'; import 'devalue'; import 'unhead/utils'; import 'pinia'; import 'perfect-debounce'; const _sfc_main = /* @__PURE__ */ defineComponent({ __name: "meetingsvc", __ssrInlineRender: true, setup(__props) { useApi(); useToast(); const REGIONS = [ { value: 1, label: "中国" }, { value: 2, label: "美国" }, { value: 3, label: "东亚" }, { value: 4, label: "东南亚" }, { value: 5, label: "南亚" }, { value: 6, label: "中东" }, { value: 7, label: "欧洲" }, { value: 8, label: "俄罗斯" }, { value: 9, label: "非洲" }, { value: 10, label: "南美" }, { value: 11, label: "北美" }, { value: 12, label: "大洋洲" }, { value: 13, label: "巴西" }, { value: 14, label: "印度" } ]; function regionLabel(v) { return REGIONS.find((r) => r.value === v)?.label ?? "区域" + v; } const apps = ref([]); const scopeApp = ref(""); const scopeRegion = ref(0); const items = ref([]); const available = ref([]); const kindCats = ref({ "1": [8], "2": [3], "3": [5, 9] }); const llmClientChoice = ref(false); const isOverride = ref(false); const loading = ref(false); const saving = ref(false); const busy = ref(false); const probeLang = ref("zh-CN"); ref(null); ref(null); const addKind = ref(1); const addForm = reactive({ svc_id: "", cost_hint: 0, is_default: false, client_visible: false }); const costEdit = reactive({ row_id: 0, name: "", kind: 1, cost_hint: 0 }); function kindLabel(k) { return k === 1 ? "识别" : k === 2 ? "翻译" : "总结"; } function costUnit(k) { return k === 1 ? "元/小时" : k === 2 ? "元/百万字符" : "元/百万token"; } function langName(code) { return LANG_OPTIONS.find((o) => o.code === code)?.name ?? code; } function catsHas(cats, v) { return (cats || "").split(",").map((x) => Number(x.trim())).includes(v); } const svcMap = computed(() => { const m = /* @__PURE__ */ new Map(); for (const s of available.value) m.set(s.id, s); return m; }); function svcName(id) { return svcMap.value.get(id)?.name ?? id; } function svcProvider(id) { return svcMap.value.get(id)?.provider ?? "?"; } function svcLangs(id) { return svcMap.value.get(id)?.languages ?? ""; } function isVision(id) { return catsHas(svcMap.value.get(id)?.categories ?? "", 9); } function ofKind(k) { return items.value.filter((o) => o.kind === k).sort((a, b) => a.priority - b.priority); } function addable(k) { const cats = kindCats.value[String(k)] ?? []; const used = new Set(items.value.filter((o) => o.kind === k).map((o) => o.svc_id)); return available.value.filter((s) => !used.has(s.id) && s.categories.split(",").some((c) => cats.includes(Number(c.trim())))); } function svcSupportsLang(id, lang) { const ls = svcLangs(id); if (!ls) return true; return ls.split(",").map((x) => x.trim()).includes(lang); } const asrHit = computed(() => ofKind(1).find((o) => o.enabled && svcSupportsLang(o.svc_id, probeLang.value)) ?? null); const mtHit = computed(() => ofKind(2).find((o) => o.enabled) ?? null); function asrSkipped(o) { return asrHit.value?.row_id !== o.row_id && (!o.enabled || !svcSupportsLang(o.svc_id, probeLang.value)); } function asrWhyClass(o) { if (asrHit.value?.row_id === o.row_id) return "ok"; if (!o.enabled || !svcSupportsLang(o.svc_id, probeLang.value)) return "no"; return ""; } function asrWhy(o) { if (asrHit.value?.row_id === o.row_id) { return svcLangs(o.svc_id) ? `✓ 当前源语言(${langName(probeLang.value)})由它承接` : `✓ 未限定语言,先落到它(实际支持由引擎判断)`; } if (!o.enabled) return "已停用,跳过"; if (!svcSupportsLang(o.svc_id, probeLang.value)) return `不支持 ${langName(probeLang.value)}(${probeLang.value}),跳过 → 顺延下一个`; return "备用:前面都跳过时接手"; } const langSum = computed(() => { const missing = []; const groups = []; let unlimitedKinds = 0; for (const k of [1, 2, 3]) { const list = ofKind(k).filter((o) => o.enabled); if (!list.length) { missing.push(k); continue; } const union = /* @__PURE__ */ new Set(); let unlimited = false; for (const o of list) { const ls = svcLangs(o.svc_id).split(",").map((x) => x.trim()).filter(Boolean); if (!ls.length) { unlimited = true; break; } ls.forEach((l) => union.add(l)); } if (unlimited) unlimitedKinds++; else groups.push({ kind: k, langs: [...union] }); } if (!groups.length) return { missing, unlimited: true, langs: [], groups, unlimitedKinds }; const langs = groups.reduce((acc, g) => acc.filter((l) => g.langs.includes(l)), [...groups[0].langs]).sort((a, b) => langOrder(a) - langOrder(b)); return { missing, unlimited: false, langs, groups, unlimitedKinds }; }); function langOrder(code) { const i = LANG_OPTIONS.findIndex((o) => o.code === code); return i < 0 ? Number.MAX_SAFE_INTEGER : i; } const langSumFormula = computed(() => { const parts = []; for (const k of [1, 2, 3]) { if (langSum.value.missing.includes(k)) { parts.push(`${kindLabel(k)} 未配置`); continue; } const g = langSum.value.groups.find((x) => x.kind === k); parts.push(`${kindLabel(k)} ${g ? g.langs.length + " 种" : "全语种"}`); } return parts.join(" ∩ "); }); const llmDefault = computed(() => ofKind(3).find((o) => o.is_default) ?? null); const pickable = computed(() => ofKind(3).filter((o) => o.enabled && o.client_visible)); return (_ctx, _push, _parent, _attrs) => { _push(`

会议记录服务

识别 / 翻译 / 总结三段,从第三方服务配置里选已配好的服务来编排(不再单独填凭据)。 先配「全局默认」作兜底,再按应用 / 区域覆盖——没配覆盖的应用自动继承全局默认。

作用域
${ssrInterpolate(scopeApp.value ? `正在编辑「${scopeApp.value}」` : "正在编辑全局默认")}${ssrInterpolate(scopeRegion.value ? ` · ${regionLabel(scopeRegion.value)}` : " · 全区域")} `); if (isOverride.value) { _push(`(覆盖全局默认)`); } else { _push(``); } _push(`
`); if (loading.value) { _push(`
`); } else { _push(`
当前配置支持的语言`); if (langSum.value.unlimited) { _push(`未限定(各引擎自行判断)`); } else { _push(`${ssrInterpolate(langSum.value.langs.length)} 种`); if (langSum.value.missing.length) { _push(`(链路未配全,尚不可用)`); } else { _push(``); } _push(``); } _push(`${ssrInterpolate(langSumFormula.value)}
`); if (langSum.value.missing.length) { _push(`
⚠ ${ssrInterpolate(langSum.value.missing.map(kindLabel).join("、"))}段没有启用中的服务,整条链路走不通——先把这些段配上。
`); } else if (!langSum.value.unlimited && !langSum.value.langs.length) { _push(`
⚠ 各段语言无交集,任何语种都走不完整条链路。放宽某一段的支持语言,或补一个覆盖面更广的服务。
`); } else { _push(``); } if (langSum.value.langs.length) { _push(`
`); ssrRenderList(langSum.value.langs, (l) => { _push(`${ssrInterpolate(l)}`); }); _push(`
`); } else if (langSum.value.unlimited && !langSum.value.missing.length) { _push(`
各段都没限定支持语言(服务未填 languages 字段),实际能否处理由引擎判断。
`); } else { _push(``); } _push(`
`); if (!available.value.length) { _push(`
该作用域没有可选服务。先去第三方服务配置添加「录音文件识别 / 机器翻译 / 文本或多媒体大模型」类的服务 (全局默认或该应用作用域),这里才能选。
`); } else { _push(``); } _push(`
识别(录音文件转写)
按顺序找第一个「已启用 + 支持源语言」的服务,不支持则跳到下一个。把便宜的排前面即"优先用性价比高的"。
选路预览`); if (asrHit.value) { _push(`命中 ${ssrInterpolate(svcName(asrHit.value.svc_id))}`); if (asrHit.value.cost_hint) { _push(` · ¥${ssrInterpolate(asrHit.value.cost_hint)}/时`); } else { _push(``); } _push(``); } else { _push(`无可用服务 —— ${ssrInterpolate(langName(probeLang.value))} 会转写失败`); } _push(`
`); if (!ofKind(1).length) { _push(`
暂无识别服务,点右上「+ 添加识别服务」
`); } else { _push(``); } _push(``); ssrRenderList(ofKind(1), (o, i) => { _push(`
${ssrInterpolate(i + 1)}
${ssrInterpolate(svcName(o.svc_id))}
${ssrInterpolate(svcProvider(o.svc_id))} · ${ssrInterpolate(o.svc_id)}
`); if (svcLangs(o.svc_id)) { _push(``); ssrRenderList(svcLangs(o.svc_id).split(",").slice(0, 5), (l) => { _push(`${ssrInterpolate(l)}`); }); _push(``); if (svcLangs(o.svc_id).split(",").length > 5) { _push(`+${ssrInterpolate(svcLangs(o.svc_id).split(",").length - 5)}`); } else { _push(``); } _push(``); } else { _push(`未限定`); } _push(`
`); if (o.cost_hint) { _push(`¥${ssrInterpolate(o.cost_hint)} /时`); } else { _push(`—`); } _push(`
${ssrInterpolate(asrWhy(o))}
`); }); _push(`
翻译
按顺序取第一个已启用的服务;调用失败自动回退下一个。
`); if (!ofKind(2).length) { _push(`
暂无翻译服务
`); } else { _push(``); } _push(``); ssrRenderList(ofKind(2), (o, i) => { _push(`
${ssrInterpolate(i + 1)}
${ssrInterpolate(svcName(o.svc_id))}
${ssrInterpolate(svcProvider(o.svc_id))} · ${ssrInterpolate(o.svc_id)}
`); if (o.cost_hint) { _push(`¥${ssrInterpolate(o.cost_hint)} /百万字符`); } else { _push(`—`); } _push(`
`); if (!o.enabled) { _push(`已停用,跳过`); } else if (mtHit.value && mtHit.value.row_id === o.row_id) { _push(`✓ 默认由它承接,失败顺延`); } else { _push(`备用:前面失败时接手`); } _push(`
`); }); _push(`
总结(大模型)
后台指定默认模型,客户端可在允许范围内自选。带 🖼 的是多媒体大模型,能识别会议里的图片。

`); if (llmClientChoice.value) { _push(` 前端能选 ${ssrInterpolate(pickable.value.length)} 个模型`); if (pickable.value.length) { _push(`:${ssrInterpolate(pickable.value.map((x) => svcName(x.svc_id)).join("、"))}`); } else { _push(`(一个都没勾「前端可见」,等同强制默认)`); } _push(`。不传则用默认 ${ssrInterpolate(llmDefault.value ? svcName(llmDefault.value.svc_id) : "—")}。 `); } else { _push(` 前端不下发模型列表,一律走默认模型 ${ssrInterpolate(llmDefault.value ? svcName(llmDefault.value.svc_id) : "—")};客户端传了也忽略。 `); } _push(`

`); if (!ofKind(3).length) { _push(`
暂无模型
`); } else { _push(``); } _push(``); ssrRenderList(ofKind(3), (o) => { _push(`
${ssrInterpolate(svcName(o.svc_id))} `); if (isVision(o.svc_id)) { _push(`🖼`); } else { _push(``); } if (o.is_default) { _push(`默认`); } else { _push(``); } _push(`
${ssrInterpolate(svcProvider(o.svc_id))} · ${ssrInterpolate(o.svc_id)}
`); if (o.cost_hint) { _push(`¥${ssrInterpolate(o.cost_hint)} /百万token`); } else { _push(`—`); } _push(`
`); }); _push(`
参考单价
前端可见
启用
`); } _push(``); }; } }); const _sfc_setup = _sfc_main.setup; _sfc_main.setup = (props, ctx) => { const ssrContext = useSSRContext(); (ssrContext.modules || (ssrContext.modules = /* @__PURE__ */ new Set())).add("pages/meetingsvc.vue"); return _sfc_setup ? _sfc_setup(props, ctx) : void 0; }; const meetingsvc = /* @__PURE__ */ _export_sfc(_sfc_main, [["__scopeId", "data-v-512b8191"]]); export { meetingsvc as default }; //# sourceMappingURL=meetingsvc-BKMj3MwH.mjs.map