diff --git a/.env.example b/.env.example index 034f8a4..21bbb20 100644 --- a/.env.example +++ b/.env.example @@ -13,8 +13,7 @@ NODE_ENV=development PORT=3000 # N8N配置 -N8N_BASE_URL=http://localhost:5678 -N8N_API_KEY=your_n8n_api_key +N8N_WEBHOOK_URL=https://n8n.bowongai.com/webhook/76f92dbf-785f-4add-96b5-a108174b7c14 # JWT配置 JWT_SECRET=your_jwt_secret_key_here diff --git a/data-source.ts b/data-source.ts index 8a42189..1aa950a 100644 --- a/data-source.ts +++ b/data-source.ts @@ -2,15 +2,16 @@ import { DataSource } from 'typeorm'; export const AppDataSource = new DataSource({ type: 'mysql', - host: 'mysql-6bc9094abd49-public.rds.volces.com', - port: 53305, - username: 'root', - password: 'WsJWXfwFx0bq6DE2kmB6', - database: 'nano_camera_miniapp', + host: process.env.DB_HOST || 'mysql-6bc9094abd49-public.rds.volces.com', + port: parseInt(process.env.DB_PORT || '53305'), + username: process.env.DB_USERNAME || 'root', + password: process.env.DB_PASSWORD || 'WsJWXfwFx0bq6DE2kmB6', + database: process.env.DB_DATABASE || 'nano_camera_miniapp', entities: ['src/**/*.entity.ts'], migrations: ['src/migrations/*.ts'], - synchronize: false, - logging: process.env.NODE_ENV === 'development', + synchronize: process.env.DB_SYNCHRONIZE === 'true', + logging: process.env.DB_LOGGING === 'true' || process.env.NODE_ENV === 'development', + migrationsRun: process.env.DB_MIGRATIONS_RUN === 'true', charset: 'utf8mb4', timezone: '+08:00', }); \ No newline at end of file diff --git a/src/platform/adapters/base.adapter.ts b/src/platform/adapters/base.adapter.ts index bbf0905..d7ef510 100644 --- a/src/platform/adapters/base.adapter.ts +++ b/src/platform/adapters/base.adapter.ts @@ -33,11 +33,12 @@ export abstract class BaseAdapter implements IPlatformAdapter { /** * 查找或创建统一用户 * 根据平台用户信息查找现有用户,如不存在则创建新用户 + * 支持跨平台用户身份统一:优先按手机号识别相同用户 */ async findOrCreateUnifiedUser( platformUserData: PlatformUserInfo, ): Promise { - // 查找是否已存在平台用户绑定 + // 1. 查找是否已存在平台用户绑定 const existingPlatformUser = await this.platformUserRepository.findOne({ where: { platform: this.platform, @@ -52,7 +53,28 @@ export abstract class BaseAdapter implements IPlatformAdapter { return existingPlatformUser.user; } - // 创建新的统一用户 + // 2. 按手机号查找现有统一用户,实现跨平台身份统一 + if (platformUserData.phone) { + const existingUser = await this.userRepository.findOne({ + where: { phone: platformUserData.phone }, + relations: ['platformUsers'], + }); + + if (existingUser) { + // 检查是否已绑定当前平台 + const existingBinding = existingUser.platformUsers?.find( + (pu) => pu.platform === this.platform, + ); + + if (!existingBinding) { + // 绑定新平台到现有用户 + await this.createPlatformUser(existingUser.id, platformUserData); + } + return existingUser; + } + } + + // 3. 创建新的统一用户和平台绑定 const unifiedUser = await this.createUnifiedUser(platformUserData); await this.createPlatformUser(unifiedUser.id, platformUserData); diff --git a/src/services/n8n-template-factory.service.ts b/src/services/n8n-template-factory.service.ts index b8eaf60..f716c45 100644 --- a/src/services/n8n-template-factory.service.ts +++ b/src/services/n8n-template-factory.service.ts @@ -1,5 +1,6 @@ import { Injectable } from '@nestjs/common'; import { InjectRepository } from '@nestjs/typeorm'; +import { ConfigService } from '@nestjs/config'; import { Repository } from 'typeorm'; import { N8nTemplateEntity, @@ -25,6 +26,7 @@ export class N8nTemplateFactoryService { private templateRepository: Repository, @InjectRepository(TemplateExecutionEntity) private executionRepository: Repository, + private configService: ConfigService, ) {} /** @@ -38,6 +40,7 @@ export class N8nTemplateFactoryService { const instance = new DynamicN8nImageTemplate( templateId, this.templateRepository, + this.configService, ); return await instance.onInit(); } @@ -53,6 +56,7 @@ export class N8nTemplateFactoryService { const instance = new DynamicN8nVideoTemplate( templateId, this.templateRepository, + this.configService, ); return await instance.onInit(); } diff --git a/src/templates/n8n-dynamic-template.ts b/src/templates/n8n-dynamic-template.ts index f8839c5..5e6a630 100644 --- a/src/templates/n8n-dynamic-template.ts +++ b/src/templates/n8n-dynamic-template.ts @@ -1,4 +1,5 @@ import { Repository } from 'typeorm'; +import { ConfigService } from '@nestjs/config'; import { N8nTemplateEntity, TemplateType, @@ -18,8 +19,9 @@ export class DynamicN8nImageTemplate extends N8nImageGenerateTemplate { constructor( private templateId: number, private templateRepository: Repository, + configService: ConfigService, ) { - super(); + super(configService); } /** @@ -98,8 +100,9 @@ export class DynamicN8nVideoTemplate extends N8nVideoGenerateTemplate { constructor( private templateId: number, private templateRepository: Repository, + configService: ConfigService, ) { - super(); + super(configService); } /** diff --git a/src/templates/n8nTemplate.ts b/src/templates/n8nTemplate.ts index 823101b..781ad01 100644 --- a/src/templates/n8nTemplate.ts +++ b/src/templates/n8nTemplate.ts @@ -1,13 +1,24 @@ import { ImageGenerateTemplate, VideoGenerateTemplate } from './types'; import axios from 'axios'; +import { ConfigService } from '@nestjs/config'; export abstract class N8nImageGenerateTemplate extends ImageGenerateTemplate { abstract readonly imageModel: string; abstract readonly imagePrompt: string; + + constructor(private configService: ConfigService) { + super(); + } + execute(imageUrl: string): Promise { + const webhookUrl = this.configService.get( + 'N8N_WEBHOOK_URL', + 'https://n8n.bowongai.com/webhook/76f92dbf-785f-4add-96b5-a108174b7c14', + ); + return axios .request({ - url: `https://n8n.bowongai.com/webhook/76f92dbf-785f-4add-96b5-a108174b7c14`, + url: webhookUrl, method: 'post', data: { workflow: '图生图', @@ -42,10 +53,20 @@ export abstract class N8nVideoGenerateTemplate extends VideoGenerateTemplate { abstract readonly videoPrompt: string; abstract readonly duration: number; abstract readonly aspectRatio: string; + + constructor(private configService: ConfigService) { + super(); + } + execute(imageUrl: string): Promise { + const webhookUrl = this.configService.get( + 'N8N_WEBHOOK_URL', + 'https://n8n.bowongai.com/webhook/76f92dbf-785f-4add-96b5-a108174b7c14', + ); + return axios .request({ - url: `https://n8n.bowongai.com/webhook/76f92dbf-785f-4add-96b5-a108174b7c14`, + url: webhookUrl, method: 'post', data: { workflow: '图生图+生视频', diff --git a/src/templates/n8nTemplates/CharacterFigurineTemplate.ts b/src/templates/n8nTemplates/CharacterFigurineTemplate.ts index c3c8d32..da06eea 100644 --- a/src/templates/n8nTemplates/CharacterFigurineTemplate.ts +++ b/src/templates/n8nTemplates/CharacterFigurineTemplate.ts @@ -1,7 +1,11 @@ import { N8nVideoGenerateTemplate } from '../n8nTemplate'; +import { ConfigService } from '@nestjs/config'; // 人物手办模板 export class CharacterFigurineTemplate extends N8nVideoGenerateTemplate { + constructor(configService: ConfigService) { + super(configService); + } readonly code = 'character_figurine_v1'; readonly name = '人物手办'; readonly description = diff --git a/src/templates/n8nTemplates/CosplayRealPersonTemplate.ts b/src/templates/n8nTemplates/CosplayRealPersonTemplate.ts index 6950395..8c819e1 100644 --- a/src/templates/n8nTemplates/CosplayRealPersonTemplate.ts +++ b/src/templates/n8nTemplates/CosplayRealPersonTemplate.ts @@ -1,7 +1,11 @@ import { N8nVideoGenerateTemplate } from '../n8nTemplate'; +import { ConfigService } from '@nestjs/config'; // cos真人模板 export class CosplayRealPersonTemplate extends N8nVideoGenerateTemplate { + constructor(configService: ConfigService) { + super(configService); + } readonly code = 'cosplay_real_person_v1'; readonly name = 'cos真人'; readonly description = diff --git a/src/templates/n8nTemplates/GarageOpeningTemplate.ts b/src/templates/n8nTemplates/GarageOpeningTemplate.ts index ef3d30c..3e51c87 100644 --- a/src/templates/n8nTemplates/GarageOpeningTemplate.ts +++ b/src/templates/n8nTemplates/GarageOpeningTemplate.ts @@ -1,7 +1,12 @@ +import { ConfigService } from '@nestjs/config'; import { N8nVideoGenerateTemplate } from '../n8nTemplate'; // 车库开门模板 export class GarageOpeningTemplate extends N8nVideoGenerateTemplate { + constructor(configService: ConfigService) { + super(configService); + } + readonly code = 'garage_opening_v1'; readonly name = '车库开门'; readonly description = diff --git a/src/templates/n8nTemplates/JapaneseMagazineTemplate.ts b/src/templates/n8nTemplates/JapaneseMagazineTemplate.ts index 5a695c0..0f11cd3 100644 --- a/src/templates/n8nTemplates/JapaneseMagazineTemplate.ts +++ b/src/templates/n8nTemplates/JapaneseMagazineTemplate.ts @@ -1,7 +1,12 @@ +import { ConfigService } from '@nestjs/config'; import { N8nVideoGenerateTemplate } from '../n8nTemplate'; // 日本杂志模板 export class JapaneseMagazineTemplate extends N8nVideoGenerateTemplate { + constructor(configService: ConfigService) { + super(configService); + } + readonly code = 'japanese_magazine_v1'; readonly name = '日本杂志'; readonly description = diff --git a/src/templates/n8nTemplates/NuclearExplosionTemplate.ts b/src/templates/n8nTemplates/NuclearExplosionTemplate.ts index 7cd8b31..4947e61 100644 --- a/src/templates/n8nTemplates/NuclearExplosionTemplate.ts +++ b/src/templates/n8nTemplates/NuclearExplosionTemplate.ts @@ -1,7 +1,12 @@ +import { ConfigService } from '@nestjs/config'; import { N8nVideoGenerateTemplate } from '../n8nTemplate'; // 原子弹爆炸模板 export class NuclearExplosionTemplate extends N8nVideoGenerateTemplate { + constructor(configService: ConfigService) { + super(configService); + } + readonly code = 'nuclear_explosion_v1'; readonly name = '原子弹爆炸'; readonly description = diff --git a/src/templates/n8nTemplates/PetFigurineTemplate.ts b/src/templates/n8nTemplates/PetFigurineTemplate.ts index 3897e61..c7ad3f9 100644 --- a/src/templates/n8nTemplates/PetFigurineTemplate.ts +++ b/src/templates/n8nTemplates/PetFigurineTemplate.ts @@ -1,7 +1,12 @@ +import { ConfigService } from '@nestjs/config'; import { N8nVideoGenerateTemplate } from '../n8nTemplate'; // 宠物手办模板 export class PetFigurineTemplate extends N8nVideoGenerateTemplate { + constructor(configService: ConfigService) { + super(configService); + } + readonly code = 'pet_figurine_v1'; readonly name = '宠物手办'; readonly description = diff --git a/src/templates/n8nTemplates/PhotoRestoreTemplate.ts b/src/templates/n8nTemplates/PhotoRestoreTemplate.ts index 61cfcd3..710fc48 100644 --- a/src/templates/n8nTemplates/PhotoRestoreTemplate.ts +++ b/src/templates/n8nTemplates/PhotoRestoreTemplate.ts @@ -1,7 +1,11 @@ import { N8nImageGenerateTemplate } from '../n8nTemplate'; +import { ConfigService } from '@nestjs/config'; // 老照片修复上色模板 export class PhotoRestoreTemplate extends N8nImageGenerateTemplate { + constructor(configService: ConfigService) { + super(configService); + } readonly code = 'photo_restore_v1'; readonly name = '老照片修复上色'; readonly description = '将黑白老照片修复并上色,让历史照片重现生机'; diff --git a/src/templates/n8nTemplates/open-eyes.template.ts b/src/templates/n8nTemplates/open-eyes.template.ts index ecf4166..c1f46d6 100644 --- a/src/templates/n8nTemplates/open-eyes.template.ts +++ b/src/templates/n8nTemplates/open-eyes.template.ts @@ -1,7 +1,11 @@ import { N8nImageGenerateTemplate } from '../n8nTemplate'; +import { ConfigService } from '@nestjs/config'; // 闭眼照片修复 export class OpenEyesTemplate extends N8nImageGenerateTemplate { + constructor(configService: ConfigService) { + super(configService); + } readonly code = 'open_eyes_v1'; readonly name = '闭眼照片修复'; readonly description = '修复照片闭眼问题,让人物睁开眼睛'; diff --git a/src/templates/template.service.ts b/src/templates/template.service.ts index 97b59de..a2bf752 100644 --- a/src/templates/template.service.ts +++ b/src/templates/template.service.ts @@ -1,4 +1,5 @@ import { Injectable, OnModuleInit, Logger } from '@nestjs/common'; +import { ConfigService } from '@nestjs/config'; import { TemplateManager, Template } from './types'; import { OpenEyesTemplate, @@ -15,7 +16,10 @@ import { export class TemplateService implements OnModuleInit { private readonly logger = new Logger(TemplateService.name); - constructor(private readonly templateManager: TemplateManager) {} + constructor( + private readonly templateManager: TemplateManager, + private readonly configService: ConfigService, + ) {} async onModuleInit() { // 启动时自动注册所有模板 @@ -77,14 +81,14 @@ export class TemplateService implements OnModuleInit { try { this.templateManager.registerTemplates([ - new PhotoRestoreTemplate(), - new OpenEyesTemplate(), - new CosplayRealPersonTemplate(), - new PetFigurineTemplate(), - new GarageOpeningTemplate(), - new CharacterFigurineTemplate(), - new NuclearExplosionTemplate(), - new JapaneseMagazineTemplate(), + new PhotoRestoreTemplate(this.configService), + new OpenEyesTemplate(this.configService), + new CosplayRealPersonTemplate(this.configService), + new PetFigurineTemplate(this.configService), + new GarageOpeningTemplate(this.configService), + new CharacterFigurineTemplate(this.configService), + new NuclearExplosionTemplate(this.configService), + new JapaneseMagazineTemplate(this.configService), ]); } catch (error) { this.logger.error('模板初始化失败:', error);