recommendation.controller.ts 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168
  1. import { Controller, Get, Logger, Param, Query } from '@nestjs/common';
  2. import {
  3. ApiOperation,
  4. ApiResponse,
  5. ApiTags,
  6. ApiParam,
  7. ApiQuery,
  8. } from '@nestjs/swagger';
  9. import { RecommendationService } from './recommendation.service';
  10. import {
  11. GetSimilarVideosResponseDto,
  12. VideoRecommendationDto,
  13. } from './dto/video-recommendation.dto';
  14. import {
  15. AdRecommendationDto,
  16. GetSimilarAdsResponseDto,
  17. } from './dto/ad-recommendation.dto';
  18. @ApiTags('推荐系统')
  19. @Controller('api/v1/recommendation')
  20. export class RecommendationController {
  21. private readonly logger = new Logger(RecommendationController.name);
  22. constructor(private readonly recommendationService: RecommendationService) {}
  23. @Get('videos/:videoId/similar')
  24. @ApiOperation({
  25. summary: '获取相似视频推荐',
  26. description:
  27. '基于视频标签和Redis分数推荐相似视频。优先从标签相关视频中推荐,不足时从全局热门视频补充。',
  28. })
  29. @ApiParam({
  30. name: 'videoId',
  31. description: '当前视频ID',
  32. example: '6756abc123def',
  33. })
  34. @ApiQuery({
  35. name: 'limit',
  36. required: false,
  37. description: '返回推荐数量(默认10)',
  38. example: 10,
  39. })
  40. @ApiResponse({
  41. status: 200,
  42. description: '成功返回推荐列表',
  43. type: GetSimilarVideosResponseDto,
  44. })
  45. async getSimilarVideos(
  46. @Param('videoId') videoId: string,
  47. @Query('limit') limit?: string,
  48. ): Promise<GetSimilarVideosResponseDto> {
  49. const limitNum = limit ? parseInt(limit, 10) : 10;
  50. this.logger.debug(
  51. `GET /api/v1/recommendation/videos/${videoId}/similar?limit=${limitNum}`,
  52. );
  53. const recommendations = await this.recommendationService.getSimilarVideos(
  54. videoId,
  55. limitNum,
  56. );
  57. return {
  58. currentVideoId: videoId,
  59. recommendations,
  60. count: recommendations.length,
  61. };
  62. }
  63. @Get('ads/:adId/similar')
  64. @ApiOperation({
  65. summary: '获取相似广告推荐(带过滤条件)',
  66. description:
  67. '基于渠道、广告模块和时间有效性过滤,返回相似广告推荐。仅返回同渠道、同模块、状态启用且在有效期内的广告。',
  68. })
  69. @ApiParam({
  70. name: 'adId',
  71. description: '当前广告ID',
  72. example: '6756def456ghi',
  73. })
  74. // @ApiQuery({
  75. // name: 'channelId',
  76. // required: true,
  77. // description: '渠道ID(必须匹配)',
  78. // example: '6756channel123',
  79. // })
  80. @ApiQuery({
  81. name: 'adsModuleId',
  82. required: true,
  83. description: '广告模块ID(场景/槽位)',
  84. example: '6756module456',
  85. })
  86. @ApiQuery({
  87. name: 'limit',
  88. required: false,
  89. description: '返回推荐数量(默认5)',
  90. example: 5,
  91. })
  92. @ApiResponse({
  93. status: 200,
  94. description: '成功返回推荐列表',
  95. type: GetSimilarAdsResponseDto,
  96. })
  97. async getSimilarAds(
  98. @Param('adId') adId: string,
  99. @Query('adsModuleId') adsModuleId: string,
  100. @Query('limit') limit?: string,
  101. ): Promise<GetSimilarAdsResponseDto> {
  102. const limitNum = limit ? parseInt(limit, 10) : 5;
  103. this.logger.debug(
  104. `GET /api/v1/recommendation/ads/${adId}/similar?adsModuleId=${adsModuleId}&limit=${limitNum}`,
  105. );
  106. const recommendations = await this.recommendationService.getSimilarAds(
  107. adId,
  108. {
  109. adsModuleId,
  110. limit: limitNum,
  111. },
  112. );
  113. return {
  114. currentAdId: adId,
  115. recommendations,
  116. count: recommendations.length,
  117. context: {
  118. adsModuleId,
  119. limit: limitNum,
  120. },
  121. };
  122. }
  123. @Get('ads/:adId/similar-simple')
  124. @ApiOperation({
  125. summary: '获取相似广告推荐(简单版)',
  126. description:
  127. '基于Redis全局分数推荐相似广告,不进行渠道和模块过滤。仅用于测试或特殊场景。',
  128. })
  129. @ApiParam({
  130. name: 'adId',
  131. description: '当前广告ID',
  132. example: '6756def456ghi',
  133. })
  134. @ApiQuery({
  135. name: 'limit',
  136. required: false,
  137. description: '返回推荐数量(默认10)',
  138. example: 5,
  139. })
  140. @ApiResponse({
  141. status: 200,
  142. description: '成功返回推荐列表',
  143. type: [VideoRecommendationDto],
  144. })
  145. async getSimilarAdsSimple(
  146. @Param('adId') adId: string,
  147. @Query('limit') limit?: string,
  148. ): Promise<VideoRecommendationDto[]> {
  149. const limitNum = limit ? parseInt(limit, 10) : 10;
  150. this.logger.debug(
  151. `GET /api/v1/recommendation/ads/${adId}/similar-simple?limit=${limitNum}`,
  152. );
  153. return this.recommendationService.getSimilarAdsSimple(adId, limitNum);
  154. }
  155. }