|
@@ -17,6 +17,8 @@ import { ModelType } from '../types';
|
|
|
import { FeishuWsManager } from './feishu-ws.manager';
|
|
import { FeishuWsManager } from './feishu-ws.manager';
|
|
|
import { ConnectionStatus } from './dto/ws-status.dto';
|
|
import { ConnectionStatus } from './dto/ws-status.dto';
|
|
|
import { FeishuAssessmentService } from './services/feishu-assessment.service';
|
|
import { FeishuAssessmentService } from './services/feishu-assessment.service';
|
|
|
|
|
+import { tenantStore } from '../tenant/tenant.store';
|
|
|
|
|
+import { i18nStore } from '../i18n/i18n.store';
|
|
|
|
|
|
|
|
@Injectable()
|
|
@Injectable()
|
|
|
export class FeishuService implements OnModuleInit {
|
|
export class FeishuService implements OnModuleInit {
|
|
@@ -42,11 +44,13 @@ export class FeishuService implements OnModuleInit {
|
|
|
this.wsManager.setFeishuService(this);
|
|
this.wsManager.setFeishuService(this);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- // ─── Bot CRUD ────────────────────────────────────────────────────────────────
|
|
|
|
|
-
|
|
|
|
|
- async createBot(userId: string, dto: CreateFeishuBotDto): Promise<FeishuBot> {
|
|
|
|
|
|
|
+ async createBot(
|
|
|
|
|
+ userId: string,
|
|
|
|
|
+ tenantId: string,
|
|
|
|
|
+ dto: CreateFeishuBotDto,
|
|
|
|
|
+ ): Promise<FeishuBot> {
|
|
|
const existing = await this.botRepository.findOne({
|
|
const existing = await this.botRepository.findOne({
|
|
|
- where: { userId, appId: dto.appId },
|
|
|
|
|
|
|
+ where: { userId, appId: dto.appId, tenantId },
|
|
|
});
|
|
});
|
|
|
|
|
|
|
|
if (existing) {
|
|
if (existing) {
|
|
@@ -54,13 +58,13 @@ export class FeishuService implements OnModuleInit {
|
|
|
return this.botRepository.save(existing);
|
|
return this.botRepository.save(existing);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- const bot = this.botRepository.create({ userId, ...dto });
|
|
|
|
|
|
|
+ const bot = this.botRepository.create({ userId, tenantId, ...dto });
|
|
|
return this.botRepository.save(bot);
|
|
return this.botRepository.save(bot);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- async getUserBots(userId: string): Promise<FeishuBot[]> {
|
|
|
|
|
|
|
+ async getUserBots(userId: string, tenantId: string): Promise<FeishuBot[]> {
|
|
|
return this.botRepository.find({
|
|
return this.botRepository.find({
|
|
|
- where: { userId },
|
|
|
|
|
|
|
+ where: { userId, tenantId },
|
|
|
relations: ['user'],
|
|
relations: ['user'],
|
|
|
});
|
|
});
|
|
|
}
|
|
}
|
|
@@ -301,18 +305,41 @@ export class FeishuService implements OnModuleInit {
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ // Get bot owner context
|
|
|
|
|
+ const userId = bot.userId;
|
|
|
|
|
+ const tenantId = bot.tenantId || 'default';
|
|
|
|
|
+
|
|
|
|
|
+ // We still fetch the user for language preference, but tenant/user IDs are from bot
|
|
|
|
|
+ const user = await this.userService.findOneById(userId);
|
|
|
|
|
+ const language = user?.userSetting?.language || 'zh';
|
|
|
|
|
+
|
|
|
try {
|
|
try {
|
|
|
- // Check if message is an assessment command
|
|
|
|
|
- if (this.isAssessmentCommand(userText)) {
|
|
|
|
|
- this.logger.log(
|
|
|
|
|
- `Routing assessment command [${messageId}] for bot ${bot.appId}`,
|
|
|
|
|
- );
|
|
|
|
|
- // Delegate to assessment service
|
|
|
|
|
- await this.feishuAssessmentService.handleCommand(bot, openId, userText);
|
|
|
|
|
- } else {
|
|
|
|
|
- // Delegate to standard RAG pipeline
|
|
|
|
|
- await this.processChatMessage(bot, openId, messageId, userText, true);
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ // Establish context for all downstream services and TypeORM subscribers
|
|
|
|
|
+ await tenantStore.run({ tenantId, userId }, async () => {
|
|
|
|
|
+ await i18nStore.run({ language }, async () => {
|
|
|
|
|
+ // Check if message is an assessment command
|
|
|
|
|
+ if (this.isAssessmentCommand(userText)) {
|
|
|
|
|
+ this.logger.log(
|
|
|
|
|
+ `Routing assessment command [${messageId}] for bot ${bot.appId}`,
|
|
|
|
|
+ );
|
|
|
|
|
+ // Delegate to assessment service (will run in the same context)
|
|
|
|
|
+ await this.feishuAssessmentService.handleCommand(
|
|
|
|
|
+ bot,
|
|
|
|
|
+ openId,
|
|
|
|
|
+ userText,
|
|
|
|
|
+ );
|
|
|
|
|
+ } else {
|
|
|
|
|
+ // Delegate to standard RAG pipeline (will run in the same context)
|
|
|
|
|
+ await this.processChatMessage(
|
|
|
|
|
+ bot,
|
|
|
|
|
+ openId,
|
|
|
|
|
+ messageId,
|
|
|
|
|
+ userText,
|
|
|
|
|
+ true,
|
|
|
|
|
+ );
|
|
|
|
|
+ }
|
|
|
|
|
+ });
|
|
|
|
|
+ });
|
|
|
} catch (error) {
|
|
} catch (error) {
|
|
|
this.logger.error(
|
|
this.logger.error(
|
|
|
`Message routing failed [${messageId}]: ${error.message}`,
|
|
`Message routing failed [${messageId}]: ${error.message}`,
|
|
@@ -366,10 +393,12 @@ export class FeishuService implements OnModuleInit {
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- // Get user from bot owner
|
|
|
|
|
|
|
+ // Get bot owner context
|
|
|
const userId = bot.userId;
|
|
const userId = bot.userId;
|
|
|
|
|
+ const tenantId = bot.tenantId || 'default';
|
|
|
|
|
+
|
|
|
|
|
+ // Fetch user for language preference
|
|
|
const user = await this.userService.findOneById(userId);
|
|
const user = await this.userService.findOneById(userId);
|
|
|
- const tenantId = user?.tenantId || 'default';
|
|
|
|
|
const language = user?.userSetting?.language || 'zh';
|
|
const language = user?.userSetting?.language || 'zh';
|
|
|
|
|
|
|
|
// Get the user's default LLM model
|
|
// Get the user's default LLM model
|