mirror of
https://github.com/hellodigua/ChatLab.git
synced 2026-10-26 02:04:37 +08:00
Add self-hosted Umami reporting alongside existing telemetry across Desktop and CLI Web. Track normalized startup, import, feature, and AI usage with a stable anonymous ID and strict privacy allowlists. Keep incremental usage platform-independent and preserve accurate failure classifications and platform metadata across import paths.
134 lines
3.8 KiB
TypeScript
134 lines
3.8 KiB
TypeScript
import { defineStore } from 'pinia'
|
|
import { ref } from 'vue'
|
|
import dayjs from 'dayjs'
|
|
import 'dayjs/locale/zh-cn'
|
|
import 'dayjs/locale/zh-tw'
|
|
import 'dayjs/locale/en'
|
|
import 'dayjs/locale/ja'
|
|
import { type LocaleType, setLocale as setI18nLocale, getLocale, getDayjsLocale } from '@/i18n'
|
|
import type { PreprocessConfig } from '@electron/preload/index'
|
|
import type { AIPreprocessConfig } from '@openchatlab/shared-types'
|
|
import { useAIService, usePlatformService } from '@/services'
|
|
import { PLATFORM_CAPABILITIES } from '@/utils/platform-capabilities'
|
|
|
|
const DESENSITIZE_RULES_SCHEMA_VERSION = 2
|
|
|
|
function serializeAiPreprocessConfig(config: PreprocessConfig): AIPreprocessConfig {
|
|
return {
|
|
...config,
|
|
desensitizeRulesSchemaVersion: DESENSITIZE_RULES_SCHEMA_VERSION,
|
|
desensitizeBuiltinRuleOverrides: { ...(config.desensitizeBuiltinRuleOverrides ?? {}) },
|
|
mergeWindowSeconds: config.mergeWindowSeconds ?? 180,
|
|
desensitizeRules: config.desensitizeRules
|
|
.filter((rule) => !rule.builtin)
|
|
.map((rule) => ({
|
|
...rule,
|
|
locales: [...rule.locales],
|
|
})),
|
|
}
|
|
}
|
|
|
|
export const useSettingsStore = defineStore(
|
|
'settings',
|
|
() => {
|
|
const locale = ref<LocaleType>(getLocale())
|
|
|
|
const defaultSessionTab = ref<'insights' | 'ai-chat'>('insights')
|
|
|
|
const debugMode = ref(false)
|
|
|
|
function setDebugMode(enabled: boolean) {
|
|
debugMode.value = enabled
|
|
window.electron?.ipcRenderer.send('app:setDebugMode', enabled)
|
|
}
|
|
|
|
const aiPreprocessConfig = ref<PreprocessConfig>({
|
|
dataCleaning: true,
|
|
mergeConsecutive: true,
|
|
mergeWindowSeconds: 180,
|
|
blacklistKeywords: [],
|
|
denoise: true,
|
|
desensitize: true,
|
|
desensitizeRulesSchemaVersion: DESENSITIZE_RULES_SCHEMA_VERSION,
|
|
desensitizeBuiltinRuleOverrides: {},
|
|
desensitizeRules: [],
|
|
anonymizeNames: false,
|
|
})
|
|
|
|
/**
|
|
* 确保脱敏规则已初始化(首次使用或升级时通过 IPC 从主进程获取)
|
|
*/
|
|
async function ensureDesensitizeRules() {
|
|
const plainRules = JSON.parse(JSON.stringify(aiPreprocessConfig.value.desensitizeRules))
|
|
aiPreprocessConfig.value.desensitizeRules = await useAIService().mergeDesensitizeRules(
|
|
plainRules,
|
|
locale.value,
|
|
aiPreprocessConfig.value.desensitizeBuiltinRuleOverrides ?? {}
|
|
)
|
|
}
|
|
|
|
/**
|
|
* 切换语言
|
|
*/
|
|
async function setLocale(newLocale: LocaleType) {
|
|
locale.value = newLocale
|
|
|
|
setI18nLocale(newLocale)
|
|
|
|
dayjs.locale(getDayjsLocale(newLocale))
|
|
|
|
window.electron?.ipcRenderer.send('locale:change', newLocale)
|
|
|
|
if (PLATFORM_CAPABILITIES.initializesLlm) await ensureDesensitizeRules()
|
|
|
|
try {
|
|
void usePlatformService()
|
|
.trackDailyActive(newLocale)
|
|
.catch(() => {})
|
|
} catch {
|
|
// Analytics is best-effort and can be unavailable during early startup or in tests.
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 初始化语言设置
|
|
* 应在应用启动时调用
|
|
*/
|
|
async function initLocale() {
|
|
const i18nLocale = getLocale()
|
|
if (locale.value !== i18nLocale) {
|
|
setI18nLocale(locale.value)
|
|
}
|
|
|
|
dayjs.locale(getDayjsLocale(locale.value))
|
|
|
|
if (PLATFORM_CAPABILITIES.initializesLlm) await ensureDesensitizeRules()
|
|
|
|
window.electron?.ipcRenderer.send('app:setDebugMode', debugMode.value)
|
|
}
|
|
|
|
return {
|
|
locale,
|
|
setLocale,
|
|
initLocale,
|
|
defaultSessionTab,
|
|
debugMode,
|
|
setDebugMode,
|
|
aiPreprocessConfig,
|
|
ensureDesensitizeRules,
|
|
}
|
|
},
|
|
{
|
|
persist: {
|
|
pick: ['debugMode'],
|
|
storage: localStorage,
|
|
},
|
|
backendPersist: {
|
|
pick: ['aiPreprocessConfig'],
|
|
serialize: (state) => ({
|
|
aiPreprocessConfig: serializeAiPreprocessConfig(state.aiPreprocessConfig as PreprocessConfig),
|
|
}),
|
|
},
|
|
}
|
|
)
|