chore: 提交所有工作进度 — SaaS 后端增强、Admin UI、桌面端集成
包含大量 SaaS 平台改进、Admin 管理后台更新、桌面端集成完善、 文档同步、测试文件重构等内容。为 QA 测试准备干净工作树。
This commit is contained in:
@@ -6,6 +6,7 @@
|
||||
*/
|
||||
|
||||
import { invoke } from '@tauri-apps/api/core';
|
||||
import { secureStorage } from './secure-storage';
|
||||
|
||||
export interface EmbeddingConfig {
|
||||
provider: string;
|
||||
@@ -32,12 +33,18 @@ export interface EmbeddingProvider {
|
||||
}
|
||||
|
||||
const EMBEDDING_STORAGE_KEY = 'zclaw-embedding-config';
|
||||
const EMBEDDING_KEY_SECURE = 'zclaw-secure-embedding-apikey';
|
||||
|
||||
/**
|
||||
* Load embedding config from localStorage. apiKey is NOT included;
|
||||
* use loadEmbeddingApiKey() to retrieve it from secure storage.
|
||||
*/
|
||||
export function loadEmbeddingConfig(): EmbeddingConfig {
|
||||
try {
|
||||
const stored = localStorage.getItem(EMBEDDING_STORAGE_KEY);
|
||||
if (stored) {
|
||||
return JSON.parse(stored);
|
||||
const parsed = JSON.parse(stored);
|
||||
return { ...parsed, apiKey: '' };
|
||||
}
|
||||
} catch {
|
||||
// ignore
|
||||
@@ -51,14 +58,37 @@ export function loadEmbeddingConfig(): EmbeddingConfig {
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Save embedding config to localStorage. API key is NOT saved here;
|
||||
* use saveEmbeddingApiKey() separately.
|
||||
*/
|
||||
export function saveEmbeddingConfig(config: EmbeddingConfig): void {
|
||||
try {
|
||||
localStorage.setItem(EMBEDDING_STORAGE_KEY, JSON.stringify(config));
|
||||
const { apiKey: _, ...rest } = config;
|
||||
localStorage.setItem(EMBEDDING_STORAGE_KEY, JSON.stringify(rest));
|
||||
} catch {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Load embedding API key from secure storage.
|
||||
*/
|
||||
export async function loadEmbeddingApiKey(): Promise<string | null> {
|
||||
return secureStorage.get(EMBEDDING_KEY_SECURE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Save embedding API key to secure storage.
|
||||
*/
|
||||
export async function saveEmbeddingApiKey(apiKey: string): Promise<void> {
|
||||
if (!apiKey.trim()) {
|
||||
await secureStorage.delete(EMBEDDING_KEY_SECURE);
|
||||
return;
|
||||
}
|
||||
await secureStorage.set(EMBEDDING_KEY_SECURE, apiKey.trim());
|
||||
}
|
||||
|
||||
export async function getEmbeddingProviders(): Promise<EmbeddingProvider[]> {
|
||||
const result = await invoke<[string, string, string, number][]>('embedding_providers');
|
||||
return result.map(([id, name, defaultModel, dimensions]) => ({
|
||||
@@ -75,7 +105,9 @@ export async function createEmbedding(
|
||||
): Promise<EmbeddingResponse> {
|
||||
const savedConfig = loadEmbeddingConfig();
|
||||
const provider = config?.provider ?? savedConfig.provider;
|
||||
const apiKey = config?.apiKey ?? savedConfig.apiKey;
|
||||
// Resolve apiKey: use explicit config value, then secure storage, then empty
|
||||
const explicitKey = config?.apiKey?.trim();
|
||||
const apiKey = explicitKey || await loadEmbeddingApiKey() || '';
|
||||
const model = config?.model ?? savedConfig.model;
|
||||
const endpoint = config?.endpoint ?? savedConfig.endpoint;
|
||||
|
||||
@@ -136,6 +168,8 @@ export class EmbeddingClient {
|
||||
|
||||
constructor(config?: EmbeddingConfig) {
|
||||
this.config = config ?? loadEmbeddingConfig();
|
||||
// If no explicit apiKey was provided and config was loaded from localStorage,
|
||||
// the apiKey will be empty. It will be resolved from secure storage lazily.
|
||||
}
|
||||
|
||||
get isApiMode(): boolean {
|
||||
@@ -143,7 +177,11 @@ export class EmbeddingClient {
|
||||
}
|
||||
|
||||
async embed(text: string): Promise<number[]> {
|
||||
const response = await createEmbedding(text, this.config);
|
||||
// Resolve apiKey from secure storage if not in config
|
||||
const effectiveConfig = this.config.apiKey
|
||||
? this.config
|
||||
: { ...this.config, apiKey: await loadEmbeddingApiKey() ?? '' };
|
||||
const response = await createEmbedding(text, effectiveConfig);
|
||||
return response.embedding;
|
||||
}
|
||||
|
||||
@@ -161,7 +199,12 @@ export class EmbeddingClient {
|
||||
if (config.provider !== undefined || config.apiKey !== undefined) {
|
||||
this.config.enabled = this.config.provider !== 'local' && !!this.config.apiKey;
|
||||
}
|
||||
// Save non-key fields to localStorage
|
||||
saveEmbeddingConfig(this.config);
|
||||
// Save apiKey to secure storage (fire-and-forget)
|
||||
if (config.apiKey !== undefined) {
|
||||
saveEmbeddingApiKey(config.apiKey).catch(() => {});
|
||||
}
|
||||
}
|
||||
|
||||
getConfig(): EmbeddingConfig {
|
||||
|
||||
Reference in New Issue
Block a user