Procházet zdrojové kódy

clean install bugfix

anhuiqiang před 5 hodinami
rodič
revize
23432c6788

+ 74 - 0
fix_kb_service.py

@@ -0,0 +1,74 @@
+import os
+
+file_path = r'd:\aura\AuraK\server\src\knowledge-base\knowledge-base.service.ts'
+
+with open(file_path, 'r', encoding='utf-8') as f:
+    lines = f.readlines()
+
+new_lines = []
+changed = False
+for line in lines:
+    # Match the specific pattern: userId, followed by kb.embeddingModelId
+    if 'userId,' in line and 'kb.embeddingModelId' in line:
+        # Check if it's the specific call site with three arguments
+        # Example: [chunk.content], userId, kb.embeddingModelId
+        # Or: batchTexts, userId, kb.embeddingModelId
+        if 'getEmbeddings' not in line: # It's probably a multi-line call
+             pass# Handled below
+        
+        new_line = line.replace('userId,', '').replace('  ', ' ') # Simple fix for potential double spaces
+        # But wait, let's be more precise
+        if 'userId,' in line:
+             new_line = line.replace('userId,', '').strip()
+             # Re-add leading whitespace
+             leading = line[:line.find(line.lstrip())]
+             new_line = leading + new_line + '\n'
+             new_lines.append(new_line)
+             changed = True
+             continue
+
+    new_lines.append(line)
+
+# Let's try a simpler approach if the above is too complex
+with open(file_path, 'r', encoding='utf-8') as f:
+    content = f.read()
+
+# Pattern 1: [chunk.content], userId, kb.embeddingModelId
+target1 = """                    [chunk.content], // Single text
+                    userId,
+                    kb.embeddingModelId,"""
+replacement1 = """                    [chunk.content], // Single text
+                    kb.embeddingModelId,"""
+
+# Pattern 2: chunkTexts, userId, kb.embeddingModelId
+target2 = """                chunkTexts,
+                userId,
+                kb.embeddingModelId,"""
+replacement2 = """                chunkTexts,
+                kb.embeddingModelId,"""
+
+# Pattern 3: batchTexts, userId, kb.embeddingModelId
+target3 = """                batchTexts,
+                userId,
+                kb.embeddingModelId,"""
+replacement3 = """                batchTexts,
+                kb.embeddingModelId,"""
+
+# Pattern 4 (Precise results): texts, userId, embeddingModelId
+target4 = """          texts,
+          userId,
+          embeddingModelId,"""
+replacement4 = """          texts,
+          embeddingModelId,"""
+
+fixed_content = content.replace(target1, replacement1)
+fixed_content = fixed_content.replace(target2, replacement2)
+fixed_content = fixed_content.replace(target3, replacement3)
+fixed_content = fixed_content.replace(target4, replacement4)
+
+if fixed_content != content:
+    with open(file_path, 'w', encoding='utf-8') as f:
+        f.write(fixed_content)
+    print("Successfully replaced patterns.")
+else:
+    print("No patterns found to replace.")

+ 1 - 1
server/Dockerfile

@@ -23,4 +23,4 @@ RUN yarn build
 EXPOSE 3001
 
 # Start application
-CMD ["node", "/app/dist/src/main.js"]
+CMD ["node", "/app/dist/main.js"]

+ 1 - 4
server/src/api/api-v1.controller.ts

@@ -63,10 +63,7 @@ export class ApiV1Controller {
     // Get organization settings and model configuration
     const tenantSettings = await this.tenantService.getSettings(user.tenantId);
     const userSetting = await this.userSettingService.getByUser(user.id);
-    const models = await this.modelConfigService.findAll(
-      user.id,
-      user.tenantId,
-    );
+    const models = await this.modelConfigService.findAll();
     const llmModel =
       models.find((m) => m.id === tenantSettings?.selectedLLMId) ??
       models.find((m) => m.type === 'llm' && m.isDefault);

+ 1 - 4
server/src/api/api.controller.ts

@@ -41,10 +41,7 @@ export class ApiController {
 
     try {
       // ユーザーの LLM モデル設定を取得
-      const models = await this.modelConfigService.findAll(
-        req.user.id,
-        req.user.tenantId,
-      );
+      const models = await this.modelConfigService.findAll();
       const llmModel = models.find((m) => m.type === 'llm');
       if (!llmModel) {
         throw new Error(this.i18nService.getMessage('addLLMConfig'));

+ 2 - 6
server/src/chat/chat.controller.ts

@@ -92,7 +92,7 @@ export class ChatController {
       const tenantId = req.user.tenantId;
 
       // 获取用户的LLM模型配置
-      let models = await this.modelConfigService.findAll(userId, tenantId);
+      let models = await this.modelConfigService.findAll();
 
       if (role !== 'SUPER_ADMIN') {
         const tenantSettings = await this.tenantService.getSettings(tenantId);
@@ -104,11 +104,7 @@ export class ChatController {
       let llmModel;
       if (selectedLLMId) {
         // Find specifically selected model
-        llmModel = await this.modelConfigService.findOne(
-          selectedLLMId,
-          userId,
-          tenantId,
-        );
+        llmModel = await this.modelConfigService.findOne(selectedLLMId);
         console.log('使用选中的LLM模型:', llmModel.name);
       } else {
         // Use organization's default LLM from Index Chat Config (strict)

+ 2 - 6
server/src/chat/chat.service.ts

@@ -133,11 +133,8 @@ export class ChatService {
 
       if (selectedEmbeddingId) {
         // Find specifically selected model
-        embeddingModel = await this.modelConfigService.findOne(
-          selectedEmbeddingId,
-          userId,
-          tenantId || 'default',
-        );
+        embeddingModel =
+          await this.modelConfigService.findOne(selectedEmbeddingId);
       } else {
         // Use organization's default from Index Chat Config (strict)
         embeddingModel = await this.modelConfigService.findDefaultByType(
@@ -486,7 +483,6 @@ ${instruction}`;
       );
       const queryEmbedding = await this.embeddingService.getEmbeddings(
         [combinedQuery],
-        userId,
         embeddingModelId,
       );
       const queryVector = queryEmbedding[0];

+ 8 - 28
server/src/knowledge-base/chunk-config.service.ts

@@ -65,22 +65,14 @@ export class ChunkConfigService {
   /**
    * Get model limit settings (read from database)
    */
-  async getModelLimits(
-    modelId: string,
-    userId: string,
-    tenantId?: string,
-  ): Promise<{
+  async getModelLimits(modelId: string): Promise<{
     maxInputTokens: number;
     maxBatchSize: number;
     expectedDimensions: number;
     providerName: string;
     isVectorModel: boolean;
   }> {
-    const modelConfig = await this.modelConfigService.findOne(
-      modelId,
-      userId,
-      tenantId || '',
-    );
+    const modelConfig = await this.modelConfigService.findOne(modelId);
 
     if (!modelConfig || modelConfig.type !== 'embedding') {
       throw new BadRequestException(
@@ -134,8 +126,6 @@ export class ChunkConfigService {
     chunkSize: number,
     chunkOverlap: number,
     modelId: string,
-    userId: string,
-    tenantId?: string,
   ): Promise<{
     chunkSize: number;
     chunkOverlap: number;
@@ -144,7 +134,7 @@ export class ChunkConfigService {
     effectiveMaxOverlapSize: number;
   }> {
     const warnings: string[] = [];
-    const limits = await this.getModelLimits(modelId, userId, tenantId);
+    const limits = await this.getModelLimits(modelId);
 
     // 1. Calculate final limits (choose smaller of env var and model limit)
     const effectiveMaxChunkSize = Math.min(
@@ -263,11 +253,9 @@ export class ChunkConfigService {
    */
   async getRecommendedBatchSize(
     modelId: string,
-    userId: string,
-    tenantId?: string,
     currentBatchSize: number = 100,
   ): Promise<number> {
-    const limits = await this.getModelLimits(modelId, userId, tenantId);
+    const limits = await this.getModelLimits(modelId);
 
     // Choose smaller of configured value and model limit
     const recommended = Math.min(
@@ -302,11 +290,9 @@ export class ChunkConfigService {
    */
   async validateDimensions(
     modelId: string,
-    userId: string,
     actualDimensions: number,
-    tenantId?: string,
   ): Promise<boolean> {
-    const limits = await this.getModelLimits(modelId, userId, tenantId);
+    const limits = await this.getModelLimits(modelId);
 
     if (actualDimensions !== limits.expectedDimensions) {
       this.logger.warn(
@@ -329,10 +315,8 @@ export class ChunkConfigService {
     chunkSize: number,
     chunkOverlap: number,
     modelId: string,
-    userId: string,
-    tenantId?: string,
   ): Promise<string> {
-    const limits = await this.getModelLimits(modelId, userId, tenantId);
+    const limits = await this.getModelLimits(modelId);
 
     return [
       `Model: ${modelId}`,
@@ -364,7 +348,7 @@ export class ChunkConfigService {
       expectedDimensions: number;
     };
   }> {
-    const limits = await this.getModelLimits(modelId, userId, tenantId);
+    const limits = await this.getModelLimits(modelId);
 
     // Calculate final limits (choose smaller of env var and model limit)
     const maxChunkSize = Math.min(this.envMaxChunkSize, limits.maxInputTokens);
@@ -374,11 +358,7 @@ export class ChunkConfigService {
     );
 
     // Get model config name
-    const modelConfig = await this.modelConfigService.findOne(
-      modelId,
-      userId,
-      tenantId || '',
-    );
+    const modelConfig = await this.modelConfigService.findOne(modelId);
     const modelName = modelConfig?.name || 'Unknown';
 
     // Get defaults from tenant or user settings

+ 1 - 12
server/src/knowledge-base/embedding.service.ts

@@ -35,16 +35,12 @@ export class EmbeddingService {
 
   async getEmbeddings(
     texts: string[],
-    userId: string,
     embeddingModelConfigId: string,
-    tenantId?: string,
   ): Promise<number[][]> {
     this.logger.log(`Generating embeddings for ${texts.length} texts`);
 
     const modelConfig = await this.modelConfigService.findOne(
       embeddingModelConfigId,
-      userId,
-      tenantId || 'default',
     );
     if (!modelConfig || modelConfig.type !== 'embedding') {
       throw new Error(
@@ -60,8 +56,6 @@ export class EmbeddingService {
       );
     }
 
-    // API key is optional - allows local models
-
     if (!modelConfig.baseUrl) {
       throw new Error(
         `Model ${modelConfig.name} does not have baseUrl configured`,
@@ -86,7 +80,6 @@ export class EmbeddingService {
         const batch = texts.slice(i, i + maxBatchSize);
         const batchEmbeddings = await this.getEmbeddingsForBatch(
           batch,
-          userId,
           modelConfig,
           maxBatchSize,
         );
@@ -104,7 +97,6 @@ export class EmbeddingService {
       // Normal processing (within batch size)
       return await this.getEmbeddingsForBatch(
         texts,
-        userId,
         modelConfig,
         maxBatchSize,
       );
@@ -141,7 +133,6 @@ export class EmbeddingService {
    */
   private async getEmbeddingsForBatch(
     texts: string[],
-    userId: string,
     modelConfig: any,
     maxBatchSize: number,
   ): Promise<number[][]> {
@@ -161,7 +152,7 @@ export class EmbeddingService {
         }, 60000); // 60s timeout
 
         this.logger.log(
-          `[Model call] Type: Embedding, Model: ${modelConfig.name} (${modelConfig.modelId}), User: ${userId}, Text count: ${texts.length}`,
+          `[Model call] Type: Embedding, Model: ${modelConfig.name} (${modelConfig.modelId}), Text count: ${texts.length}`,
         );
         this.logger.log(
           `Calling embedding API (attempt ${attempt}/${MAX_RETRIES}): ${apiUrl}`,
@@ -208,13 +199,11 @@ export class EmbeddingService {
 
               const firstResult = await this.getEmbeddingsForBatch(
                 firstHalf,
-                userId,
                 modelConfig,
                 Math.floor(maxBatchSize / 2),
               );
               const secondResult = await this.getEmbeddingsForBatch(
                 secondHalf,
-                userId,
                 modelConfig,
                 Math.floor(maxBatchSize / 2),
               );

+ 8 - 41
server/src/knowledge-base/knowledge-base.service.ts

@@ -515,11 +515,8 @@ export class KnowledgeBaseService {
       );
       const visionModelId = settings?.selectedVisionId;
       if (visionModelId) {
-        const visionModel = await this.modelConfigService.findOne(
-          visionModelId,
-          userId,
-          tenantId,
-        );
+        const visionModel =
+          await this.modelConfigService.findOne(visionModelId);
         if (
           visionModel &&
           visionModel.type === 'vision' &&
@@ -613,11 +610,7 @@ export class KnowledgeBaseService {
       return this.processFastMode(kb, userId, tenantId, config);
     }
 
-    const visionModel = await this.modelConfigService.findOne(
-      visionModelId,
-      userId,
-      tenantId,
-    );
+    const visionModel = await this.modelConfigService.findOne(visionModelId);
     if (
       !visionModel ||
       visionModel.type !== 'vision' ||
@@ -719,8 +712,6 @@ export class KnowledgeBaseService {
     // Check index existence - get actual model dimensions
     const actualDimensions = await this.getActualModelDimensions(
       embeddingModelId,
-      userId,
-      tenantId,
     );
     await this.elasticsearchService.createIndexIfNotExists(actualDimensions);
 
@@ -735,7 +726,6 @@ export class KnowledgeBaseService {
         // Generate vectors
         const embeddings = await this.embeddingService.getEmbeddings(
           texts,
-          userId,
           embeddingModelId,
         );
 
@@ -846,7 +836,6 @@ export class KnowledgeBaseService {
         kb.chunkSize,
         kb.chunkOverlap,
         kb.embeddingModelId,
-        userId,
       );
       this.logger.debug(`File ${kbId}: Chunk config validated.`);
 
@@ -876,7 +865,6 @@ export class KnowledgeBaseService {
         validatedConfig.chunkSize,
         validatedConfig.chunkOverlap,
         kb.embeddingModelId,
-        userId,
       );
       this.logger.log(`Chunk config: ${configSummary}`);
       this.logger.log(
@@ -917,8 +905,6 @@ export class KnowledgeBaseService {
       const recommendedBatchSize =
         await this.chunkConfigService.getRecommendedBatchSize(
           kb.embeddingModelId,
-          userId,
-          tenantId,
           parseInt(process.env.CHUNK_BATCH_SIZE || '100'),
         );
 
@@ -937,8 +923,6 @@ export class KnowledgeBaseService {
       // 6. Get actual model dimensions and check index exists
       const actualDimensions = await this.getActualModelDimensions(
         kb.embeddingModelId,
-        userId,
-        tenantId,
       );
       await this.elasticsearchService.createIndexIfNotExists(actualDimensions);
 
@@ -968,7 +952,6 @@ export class KnowledgeBaseService {
               const chunkTexts = batch.map((chunk) => chunk.content);
               const embeddings = await this.embeddingService.getEmbeddings(
                 chunkTexts,
-                userId,
                 kb.embeddingModelId,
               );
 
@@ -1044,7 +1027,6 @@ export class KnowledgeBaseService {
               try {
                 const embeddings = await this.embeddingService.getEmbeddings(
                   [chunk.content], // Single text
-                  userId,
                   kb.embeddingModelId,
                 );
 
@@ -1111,7 +1093,6 @@ export class KnowledgeBaseService {
               const batchTexts = batch.map((c) => c.content);
               const embeddings = await this.embeddingService.getEmbeddings(
                 batchTexts,
-                userId,
                 kb.embeddingModelId,
               );
 
@@ -1161,7 +1142,6 @@ export class KnowledgeBaseService {
                 try {
                   const embeddings = await this.embeddingService.getEmbeddings(
                     [chunk.content], // Single text
-                    userId,
                     kb.embeddingModelId,
                   );
 
@@ -1222,7 +1202,6 @@ export class KnowledgeBaseService {
           try {
             const embeddings = await this.embeddingService.getEmbeddings(
               chunkTexts,
-              userId,
               kb.embeddingModelId,
             );
 
@@ -1273,7 +1252,6 @@ export class KnowledgeBaseService {
                 try {
                   const embeddings = await this.embeddingService.getEmbeddings(
                     [chunk.content], // Single text
-                    userId,
                     kb.embeddingModelId,
                   );
 
@@ -1712,8 +1690,6 @@ export class KnowledgeBaseService {
    */
   private async getActualModelDimensions(
     embeddingModelId: string,
-    userId: string,
-    tenantId: string,
   ): Promise<number> {
     const defaultDimensions = parseInt(
       process.env.DEFAULT_VECTOR_DIMENSIONS || '2560',
@@ -1721,11 +1697,8 @@ export class KnowledgeBaseService {
 
     try {
       // 1. Prioritize getting from model config
-      const modelConfig = await this.modelConfigService.findOne(
-        embeddingModelId,
-        userId,
-        tenantId,
-      );
+      const modelConfig =
+        await this.modelConfigService.findOne(embeddingModelId);
 
       if (modelConfig && modelConfig.dimensions) {
         this.logger.log(
@@ -1738,7 +1711,6 @@ export class KnowledgeBaseService {
       this.logger.log(`Probing model dimensions: ${embeddingModelId}`);
       const probeEmbeddings = await this.embeddingService.getEmbeddings(
         ['probe'],
-        userId,
         embeddingModelId,
       );
 
@@ -1751,14 +1723,9 @@ export class KnowledgeBaseService {
         // Update model config for next use
         if (modelConfig) {
           try {
-            await this.modelConfigService.update(
-              userId,
-              tenantId,
-              modelConfig.id,
-              {
-                dimensions: actualDimensions,
-              },
-            );
+            await this.modelConfigService.update(modelConfig.id, {
+              dimensions: actualDimensions,
+            });
             this.logger.log(
               `Updated model ${modelConfig.name} dimension config to ${actualDimensions}`,
             );

+ 2 - 3
server/src/model-config/dto/model-config-response.dto.ts

@@ -1,5 +1,5 @@
 // server/src/model-config/dto/model-config-response.dto.ts
-import { Exclude } from 'class-transformer';
+import { Exclude, Expose, Transform } from 'class-transformer';
 import { ModelConfig } from '../model-config.entity';
 
 export class ModelConfigResponseDto {
@@ -9,13 +9,12 @@ export class ModelConfigResponseDto {
   modelId: string;
   baseUrl?: string;
 
-  @Exclude() // Exclude API key from being returned to the client
+  @Transform(({ value }) => (value ? '********' : undefined))
   apiKey?: string;
 
   type: string;
   isEnabled?: boolean;
   isDefault?: boolean;
-  userId: string;
   createdAt: Date;
   updatedAt: Date;
 

+ 10 - 36
server/src/model-config/model-config.controller.ts

@@ -32,49 +32,32 @@ export class ModelConfigController {
   @Post()
   @HttpCode(HttpStatus.CREATED)
   async create(
-    @Req() req,
     @Body() createModelConfigDto: CreateModelConfigDto,
   ): Promise<ModelConfigResponseDto> {
-    const modelConfig = await this.modelConfigService.create(
-      req.user.id,
-      req.user.tenantId,
-      createModelConfigDto,
-    );
+    const modelConfig =
+      await this.modelConfigService.create(createModelConfigDto);
     return plainToClass(ModelConfigResponseDto, modelConfig);
   }
 
   @Get()
-  async findAll(@Req() req): Promise<ModelConfigResponseDto[]> {
-    const modelConfigs = await this.modelConfigService.findAll(
-      req.user.id,
-      req.user.tenantId,
-    );
+  async findAll(): Promise<ModelConfigResponseDto[]> {
+    const modelConfigs = await this.modelConfigService.findAll();
     return modelConfigs.map((mc) => plainToClass(ModelConfigResponseDto, mc));
   }
 
   @Get(':id')
-  async findOne(
-    @Req() req,
-    @Param('id') id: string,
-  ): Promise<ModelConfigResponseDto> {
-    const modelConfig = await this.modelConfigService.findOne(
-      id,
-      req.user.id,
-      req.user.tenantId,
-    );
+  async findOne(@Param('id') id: string): Promise<ModelConfigResponseDto> {
+    const modelConfig = await this.modelConfigService.findOne(id);
     return plainToClass(ModelConfigResponseDto, modelConfig);
   }
 
   @Roles(UserRole.TENANT_ADMIN, UserRole.SUPER_ADMIN)
   @Put(':id')
   async update(
-    @Req() req,
     @Param('id') id: string,
     @Body() updateModelConfigDto: UpdateModelConfigDto,
   ): Promise<ModelConfigResponseDto> {
     const modelConfig = await this.modelConfigService.update(
-      req.user.id,
-      req.user.tenantId,
       id,
       updateModelConfigDto,
     );
@@ -84,23 +67,14 @@ export class ModelConfigController {
   @Roles(UserRole.TENANT_ADMIN, UserRole.SUPER_ADMIN)
   @Delete(':id')
   @HttpCode(HttpStatus.NO_CONTENT)
-  async remove(@Req() req, @Param('id') id: string): Promise<void> {
-    await this.modelConfigService.remove(req.user.id, req.user.tenantId, id);
+  async remove(@Param('id') id: string): Promise<void> {
+    await this.modelConfigService.remove(id);
   }
 
   @Roles(UserRole.TENANT_ADMIN, UserRole.SUPER_ADMIN)
   @Patch(':id/set-default')
-  async setDefault(
-    @Req() req,
-    @Param('id') id: string,
-  ): Promise<ModelConfigResponseDto> {
-    const userId = req.user.id;
-    const tenantId = req.user.tenantId;
-    const modelConfig = await this.modelConfigService.setDefault(
-      userId,
-      tenantId,
-      id,
-    );
+  async setDefault(@Param('id') id: string): Promise<ModelConfigResponseDto> {
+    const modelConfig = await this.modelConfigService.setDefault(id);
     return plainToClass(ModelConfigResponseDto, modelConfig);
   }
 }

+ 0 - 20
server/src/model-config/model-config.entity.ts

@@ -3,12 +3,9 @@ import {
   Column,
   CreateDateColumn,
   Entity,
-  JoinColumn,
-  ManyToOne,
   PrimaryGeneratedColumn,
   UpdateDateColumn,
 } from 'typeorm';
-import { User } from '../user/user.entity';
 
 @Entity('model_configs')
 export class ModelConfig {
@@ -77,23 +74,6 @@ export class ModelConfig {
   @Column({ type: 'text', nullable: true })
   providerName?: string;
 
-  // ==================== Existing Fields ====================
-
-  @Column({ type: 'text', nullable: true })
-  userId: string;
-
-  // null = global/system model (visible to all tenants)
-  // set = private to this tenant
-  @Column({ type: 'text', nullable: true, name: 'tenant_id' })
-  tenantId: string;
-
-  @ManyToOne(() => User, (user) => user.modelConfigs, {
-    onDelete: 'CASCADE',
-    nullable: true,
-  })
-  @JoinColumn({ name: 'userId' })
-  user: User | null;
-
   @CreateDateColumn({ name: 'created_at' })
   createdAt: Date;
 

+ 13 - 85
server/src/model-config/model-config.service.ts

@@ -27,47 +27,22 @@ export class ModelConfigService {
   ) {}
 
   async create(
-    userId: string,
-    tenantId: string,
     createModelConfigDto: CreateModelConfigDto,
   ): Promise<ModelConfig> {
     const modelConfig = this.modelConfigRepository.create({
       ...createModelConfigDto,
-      userId,
-      tenantId,
     });
     return this.modelConfigRepository.save(modelConfig);
   }
 
-  async findAll(userId: string, tenantId: string): Promise<ModelConfig[]> {
-    return this.modelConfigRepository
-      .createQueryBuilder('model')
-      .where(
-        'model.tenantId = :tenantId OR model.tenantId IS NULL OR model.tenantId = :globalTenantId',
-        {
-          tenantId,
-          globalTenantId: GLOBAL_TENANT_ID,
-        },
-      )
-      .getMany();
+  async findAll(): Promise<ModelConfig[]> {
+    return this.modelConfigRepository.find();
   }
 
-  async findOne(
-    id: string,
-    userId: string,
-    tenantId: string,
-  ): Promise<ModelConfig> {
-    const modelConfig = await this.modelConfigRepository
-      .createQueryBuilder('model')
-      .where('model.id = :id', { id })
-      .andWhere(
-        '(model.tenantId = :tenantId OR model.tenantId IS NULL OR model.tenantId = :globalTenantId)',
-        {
-          tenantId,
-          globalTenantId: GLOBAL_TENANT_ID,
-        },
-      )
-      .getOne();
+  async findOne(id: string): Promise<ModelConfig> {
+    const modelConfig = await this.modelConfigRepository.findOne({
+      where: { id },
+    });
 
     if (!modelConfig) {
       throw new NotFoundException(
@@ -77,44 +52,15 @@ export class ModelConfigService {
     return modelConfig;
   }
 
-  async findByType(
-    userId: string,
-    tenantId: string,
-    type: string,
-  ): Promise<ModelConfig[]> {
-    return this.modelConfigRepository
-      .createQueryBuilder('model')
-      .where('model.type = :type', { type })
-      .andWhere(
-        '(model.tenantId = :tenantId OR model.tenantId IS NULL OR model.tenantId = :globalTenantId)',
-        {
-          tenantId,
-          globalTenantId: GLOBAL_TENANT_ID,
-        },
-      )
-      .getMany();
+  async findByType(type: string): Promise<ModelConfig[]> {
+    return this.modelConfigRepository.find({ where: { type } });
   }
 
   async update(
-    userId: string,
-    tenantId: string,
     id: string,
     updateModelConfigDto: UpdateModelConfigDto,
   ): Promise<ModelConfig> {
-    const modelConfig = await this.findOne(id, userId, tenantId);
-
-    if (!modelConfig) {
-      throw new NotFoundException(
-        this.i18nService.formatMessage('modelConfigNotFound', { id }),
-      );
-    }
-
-    // Only allow updating if it belongs to the tenant, or if it's a global admin (not fully implemented, so we check tenantId)
-    if (modelConfig.tenantId && modelConfig.tenantId !== tenantId) {
-      throw new ForbiddenException(
-        this.i18nService.getMessage('cannotUpdateOtherTenantModel'),
-      );
-    }
+    const modelConfig = await this.findOne(id);
 
     // Update the model
     const updated = this.modelConfigRepository.merge(
@@ -124,14 +70,7 @@ export class ModelConfigService {
     return this.modelConfigRepository.save(updated);
   }
 
-  async remove(userId: string, tenantId: string, id: string): Promise<void> {
-    // Only allow removing if it exists and accessible in current tenant context
-    const model = await this.findOne(id, userId, tenantId);
-    if (model.tenantId && model.tenantId !== tenantId) {
-      throw new ForbiddenException(
-        this.i18nService.getMessage('cannotDeleteOtherTenantModel'),
-      );
-    }
+  async remove(id: string): Promise<void> {
     const result = await this.modelConfigRepository.delete({ id });
     if (result.affected === 0) {
       throw new NotFoundException(
@@ -143,26 +82,15 @@ export class ModelConfigService {
   /**
    * Set the specified model as default
    */
-  async setDefault(
-    userId: string,
-    tenantId: string,
-    id: string,
-  ): Promise<ModelConfig> {
-    const modelConfig = await this.findOne(id, userId, tenantId);
+  async setDefault(id: string): Promise<ModelConfig> {
+    const modelConfig = await this.findOne(id);
 
-    // Clear default flag for other models of the same type (within current tenant or global)
+    // Clear default flag for other models of the same type
     await this.modelConfigRepository
       .createQueryBuilder()
       .update(ModelConfig)
       .set({ isDefault: false })
       .where('type = :type', { type: modelConfig.type })
-      .andWhere(
-        '(tenantId = :tenantId OR tenantId IS NULL OR tenantId = :globalTenantId)',
-        {
-          tenantId,
-          globalTenantId: GLOBAL_TENANT_ID,
-        },
-      )
       .execute();
 
     modelConfig.isDefault = true;

+ 0 - 2
server/src/rag/rag.service.ts

@@ -59,9 +59,7 @@ export class RagService {
       try {
         const vectors = await this.embeddingService.getEmbeddings(
           [query],
-          userId,
           embeddingModelId,
-          tenantId,
         );
         queryVector = vectors[0];
       } catch (error) {

+ 1 - 5
server/src/rag/rerank.service.ts

@@ -42,11 +42,7 @@ export class RerankService {
     let modelConfig;
     try {
       // 1. Get model config
-      modelConfig = await this.modelConfigService.findOne(
-        rerankModelId,
-        userId,
-        tenantId || 'default',
-      );
+      modelConfig = await this.modelConfigService.findOne(rerankModelId);
 
       if (!modelConfig || modelConfig.type !== ModelType.RERANK) {
         this.logger.warn(`Invalid rerank model config: ${rerankModelId}`);

+ 0 - 3
server/src/user/user.entity.ts

@@ -66,9 +66,6 @@ export class User {
   @UpdateDateColumn({ name: 'updated_at' })
   updatedAt: Date;
 
-  @OneToMany(() => ModelConfig, (modelConfig) => modelConfig.user)
-  modelConfigs: ModelConfig[];
-
   @OneToOne(() => UserSetting, (setting) => setting.user)
   userSetting: UserSetting;
 

+ 2 - 1
server/src/user/user.service.ts

@@ -177,7 +177,7 @@ export class UserService implements OnModuleInit {
     const user = await this.usersRepository.save({
       username,
       password: hashedPassword,
-      displayName,
+      displayName: displayName || username,
       isAdmin,
       tenantId: tenantId ?? undefined,
     } as any);
@@ -398,6 +398,7 @@ export class UserService implements OnModuleInit {
       await this.usersRepository.save({
         username: 'admin',
         password: hashedPassword,
+        displayName: 'Admin',
         isAdmin: true,
         role: UserRole.SUPER_ADMIN,
       });

+ 1 - 5
server/src/vision-pipeline/vision-pipeline-cost-aware.service.ts

@@ -219,11 +219,7 @@ export class VisionPipelineCostAwareService {
     modelId: string,
     tenantId?: string,
   ): Promise<VisionModelConfig> {
-    const config = await this.modelConfigService.findOne(
-      modelId,
-      userId,
-      tenantId || 'default',
-    );
+    const config = await this.modelConfigService.findOne(modelId);
 
     if (!config) {
       throw new Error(`Model config not found: ${modelId}`);

+ 0 - 6
server/src/vision-pipeline/vision-pipeline.service.ts

@@ -104,9 +104,7 @@ export class VisionPipelineService {
       // Step 3: Get Vision model configuration
       this.logger.log('🤖 Step 3/4: Preparation of Vision model');
       const modelConfig = await this.getVisionModelConfig(
-        options.userId,
         options.modelId,
-        options.tenantId,
       );
       this.logger.log(
         `✅ Vision model configuration completed: ${modelConfig.modelId}`,
@@ -225,14 +223,10 @@ export class VisionPipelineService {
    * Get Vision model configuration
    */
   private async getVisionModelConfig(
-    userId: string,
     modelId: string,
-    tenantId?: string,
   ): Promise<VisionModelConfig> {
     const config = await this.modelConfigService.findOne(
       modelId,
-      userId,
-      tenantId || 'default',
     );
 
     if (!config) {

+ 7 - 4
web/components/ChatInterface.tsx

@@ -32,6 +32,7 @@ interface ChatInterfaceProps {
   onPreviewSource?: (source: ChatSource) => void;
   onOpenFile?: (source: ChatSource) => void;
   onHistoryIdCreated?: (historyId: string) => void;
+  authToken?: string; // Add optional auth token prop
 }
 
 const ChatInterface: React.FC<ChatInterfaceProps> = ({
@@ -50,7 +51,8 @@ const ChatInterface: React.FC<ChatInterfaceProps> = ({
   onHistoryMessagesLoaded,
   onPreviewSource,
   onOpenFile,
-  onHistoryIdCreated
+  onHistoryIdCreated,
+  authToken
 }) => {
   const { t, language } = useLanguage();
   const [messages, setMessages] = useState<Message[]>([]);
@@ -167,8 +169,9 @@ const ChatInterface: React.FC<ChatInterfaceProps> = ({
     setIsLoading(true);
     setMessages((prev) => [...prev, newMessage]);
 
-    const authToken = localStorage.getItem('authToken');
-    if (!authToken) {
+    const effectiveToken = authToken || localStorage.getItem('kb_api_key') || localStorage.getItem('authToken');
+    
+    if (!effectiveToken) {
       const errorMsg: Message = {
         id: generateUUID(),
         role: Role.MODEL,
@@ -204,7 +207,7 @@ const ChatInterface: React.FC<ChatInterfaceProps> = ({
       const stream = chatService.streamChat(
         userText,
         history,
-        authToken,
+        effectiveToken,
         language,
         settings.selectedEmbeddingId,
         settings.selectedLLMId, // Pass selected LLM ID

+ 1 - 0
web/components/views/ChatView.tsx

@@ -368,6 +368,7 @@ export const ChatView: React.FC<ChatViewProps> = ({
                         onHistoryMessagesLoaded={() => setHistoryMessages(null)}
                         onHistoryIdCreated={setCurrentHistoryId}
                         onPreviewSource={setPreviewSource}
+                        authToken={authToken}
                         onOpenFile={(source) => {
                             if (source.fileId) {
                                 if (isFormatSupportedForPreview(source.fileName)) {

+ 6 - 10
web/services/apiClient.ts

@@ -135,17 +135,13 @@ class ApiClient {
   
   // Legacy compatibility method — returns raw Response for streaming and other special cases
   async request(path: string, options: RequestInit = {}): Promise<Response> {
-    const apiKey = localStorage.getItem('kb_api_key');
-    const activeTenantId = localStorage.getItem('kb_active_tenant_id');
-    const token = localStorage.getItem('authToken');
+    const authHeaders = this.getAuthHeaders();
     const headers = new Headers(options.headers);
-
-    if (apiKey) headers.set('x-api-key', apiKey);
-    if (activeTenantId) headers.set('x-tenant-id', activeTenantId);
-    if (token) headers.set('Authorization', `Bearer ${token}`);
-
-    const language = localStorage.getItem('userLanguage') || 'zh';
-    headers.set('x-user-language', language);
+    
+    // Merge auth headers into request headers
+    Object.entries(authHeaders).forEach(([key, value]) => {
+      headers.set(key, value);
+    });
 
     let url = path;
     if (!path.startsWith('http')) {