diff --git a/src/main/java/com/guwan/backend/config/HadoopConfig.java b/src/main/java/com/guwan/backend/config/HadoopConfig.java deleted file mode 100644 index c1cd653..0000000 --- a/src/main/java/com/guwan/backend/config/HadoopConfig.java +++ /dev/null @@ -1,28 +0,0 @@ -package com.guwan.backend.config; - -import org.apache.hadoop.fs.FileSystem; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; - -@Configuration -public class HadoopConfig { - - @Value("${hadoop.fs.defaultFS}") - private String fsDefaultFS; - - @Value("${hadoop.username}") - private String username; - - @Bean - public FileSystem fileSystem() throws Exception { - org.apache.hadoop.conf.Configuration conf = new org.apache.hadoop.conf.Configuration(); - conf.set("fs.defaultFS", fsDefaultFS); - // 设置副本数 - conf.set("dfs.replication", "3"); - // 设置块大小,适合大文件存储 - conf.set("dfs.blocksize", "128m"); - - return FileSystem.get(conf); - } -} \ No newline at end of file diff --git a/src/main/java/com/guwan/backend/constant/SecurityConstants.java b/src/main/java/com/guwan/backend/constant/SecurityConstants.java index a3fb8b0..37791bf 100644 --- a/src/main/java/com/guwan/backend/constant/SecurityConstants.java +++ b/src/main/java/com/guwan/backend/constant/SecurityConstants.java @@ -26,6 +26,7 @@ public class SecurityConstants { public static final List STATIC_RESOURCES = List.of( "/static/**", // 静态资源目录 "/public/**", // 公共资源目录 - "/error" // 错误页面 + "/error", // 错误页面 + "/swagger-ui.html" ); } \ No newline at end of file diff --git a/src/main/java/com/guwan/backend/controller/VideoController.java b/src/main/java/com/guwan/backend/controller/VideoController.java index e4b5596..93e22b9 100644 --- a/src/main/java/com/guwan/backend/controller/VideoController.java +++ b/src/main/java/com/guwan/backend/controller/VideoController.java @@ -1,22 +1,17 @@ package com.guwan.backend.controller; import com.baomidou.mybatisplus.core.metadata.IPage; -import com.guwan.backend.annotation.OperationLog; import com.guwan.backend.common.Result; import com.guwan.backend.dto.video.VideoDTO; import com.guwan.backend.service.VideoService; -import com.guwan.backend.service.VideoRecommendService; -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; -import org.springframework.web.bind.annotation.*; -import org.springframework.web.multipart.MultipartFile; - -import java.util.List; - import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.security.SecurityRequirement; import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; @Slf4j @Tag(name = "视频管理", description = "视频相关接口") @@ -26,7 +21,7 @@ import io.swagger.v3.oas.annotations.tags.Tag; public class VideoController { private final VideoService videoService; - private final VideoRecommendService recommendService; + @Operation(summary = "上传视频", description = "上传视频文件并返回视频信息") @SecurityRequirement(name = "bearer-jwt") @@ -131,30 +126,7 @@ public class VideoController { } } - @Operation(summary = "获取推荐视频") - @SecurityRequirement(name = "bearer-jwt") - @GetMapping("/recommend") - public Result> getRecommendVideos( - @Parameter(description = "返回数量") @RequestParam(defaultValue = "10") Integer limit) { - try { - Long userId = securityUtil.getCurrentUserId(); - return Result.success(recommendService.getRecommendVideos(userId, limit)); - } catch (Exception e) { - log.error("获取推荐视频失败", e); - return Result.error(e.getMessage()); - } - } - @Operation(summary = "获取相似视频") - @GetMapping("/{id}/similar") - public Result> getSimilarVideos( - @Parameter(description = "视频ID") @PathVariable Long id, - @Parameter(description = "返回数量") @RequestParam(defaultValue = "10") Integer limit) { - try { - return Result.success(recommendService.getSimilarVideos(id, limit)); - } catch (Exception e) { - log.error("获取相似视频失败", e); - return Result.error(e.getMessage()); - } - } + + } \ No newline at end of file diff --git a/src/main/java/com/guwan/backend/controller/VideoStreamController.java b/src/main/java/com/guwan/backend/controller/VideoStreamController.java deleted file mode 100644 index 66a4833..0000000 --- a/src/main/java/com/guwan/backend/controller/VideoStreamController.java +++ /dev/null @@ -1,66 +0,0 @@ -package com.guwan.backend.controller; - -import com.guwan.backend.entity.Video; -import com.guwan.backend.service.HdfsStorageService; -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; -import org.springframework.core.io.InputStreamResource; -import org.springframework.core.io.ResourceRegion; -import org.springframework.http.*; -import org.springframework.web.bind.annotation.*; - -import java.io.IOException; -import java.io.InputStream; - -@Slf4j -@RestController -@RequestMapping("/api/stream") -@RequiredArgsConstructor -public class VideoStreamController { - - private final HdfsStorageService hdfsStorageService; - private static final long CHUNK_SIZE = 1024 * 1024; // 1MB chunks - - @GetMapping("/video/{id}") - public ResponseEntity streamVideo( - @PathVariable Long id, - @RequestHeader(value = "Range", required = false) String rangeHeader) { - try { - // 获取视频路径 - Video video = videoMapper.selectById(id); - if (video == null) { - return ResponseEntity.notFound().build(); - } - - // 获取视频流 - InputStream videoStream = hdfsStorageService.getVideoStream(video.getUrl()); - InputStreamResource resource = new InputStreamResource(videoStream); - - // 获取视频元数据 - VideoMetadata metadata = hdfsStorageService.getVideoMetadata(video.getUrl()); - long contentLength = metadata.getSize(); - - // 处理Range请求 - HttpRange range = rangeHeader == null ? null : HttpRange.parseRanges(rangeHeader).get(0); - ResourceRegion region; - - if (range != null) { - long start = range.getRangeStart(contentLength); - long end = range.getRangeEnd(contentLength); - long rangeLength = Math.min(CHUNK_SIZE, end - start + 1); - region = new ResourceRegion(resource, start, rangeLength); - } else { - long rangeLength = Math.min(CHUNK_SIZE, contentLength); - region = new ResourceRegion(resource, 0, rangeLength); - } - - return ResponseEntity.status(HttpStatus.PARTIAL_CONTENT) - .contentType(MediaTypeFactory.getMediaType(resource).orElse(MediaType.APPLICATION_OCTET_STREAM)) - .body(region); - - } catch (IOException e) { - log.error("视频流处理失败", e); - return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build(); - } - } -} \ No newline at end of file diff --git a/src/main/java/com/guwan/backend/entity/SmsLog.java b/src/main/java/com/guwan/backend/entity/SmsLog.java deleted file mode 100644 index 7280c24..0000000 --- a/src/main/java/com/guwan/backend/entity/SmsLog.java +++ /dev/null @@ -1,30 +0,0 @@ -package com.guwan.backend.entity; - -import com.baomidou.mybatisplus.annotation.IdType; -import com.baomidou.mybatisplus.annotation.TableField; -import com.baomidou.mybatisplus.annotation.TableId; -import com.baomidou.mybatisplus.annotation.TableName; -import lombok.Data; - -import java.time.LocalDateTime; - -@Data -@TableName("sms_log") -public class SmsLog { - @TableId(type = IdType.AUTO) - private Long id; - - private String phone; - - private String type; - - private String content; - - private Integer status; - - @TableField("error_msg") - private String errorMsg; - - @TableField("created_time") - private LocalDateTime createdTime; -} \ No newline at end of file diff --git a/src/main/java/com/guwan/backend/service/DeepRecommendService.java b/src/main/java/com/guwan/backend/service/DeepRecommendService.java deleted file mode 100644 index 8a97324..0000000 --- a/src/main/java/com/guwan/backend/service/DeepRecommendService.java +++ /dev/null @@ -1,114 +0,0 @@ -package com.guwan.backend.service; - -import ai.djl.ndarray.NDArray; -import ai.djl.ndarray.NDList; -import ai.djl.ndarray.NDManager; -import ai.djl.training.util.ProgressBar; -import lombok.extern.slf4j.Slf4j; -import org.springframework.stereotype.Service; - -@Slf4j -@Service -public class DeepRecommendService { - - private static final int EMBEDDING_SIZE = 128; - private static final String MODEL_PATH = "models/recommend_model.pt"; - - private final NDManager manager; - private final Model model; - - public DeepRecommendService() { - // 初始化DJL环境 - this.manager = NDManager.newBaseManager(); - this.model = Model.newInstance("recommend"); - loadModel(); - } - - /** - * 获取视频的嵌入向量 - */ - public float[] getVideoEmbedding(Video video) { - try { - // 准备输入特征 - NDArray features = prepareVideoFeatures(video); - - // 获取模型输出 - NDArray embedding = model.forward(new NDList(features)).singletonOrThrow(); - - // 转换为Java数组 - return embedding.toFloatArray(); - } catch (Exception e) { - log.error("获取视频嵌入向量失败", e); - return new float[EMBEDDING_SIZE]; - } - } - - /** - * 获取用户的嵌入向量 - */ - public float[] getUserEmbedding(List behaviors) { - try { - // 准备输入特征 - NDArray features = prepareUserFeatures(behaviors); - - // 获取模型输出 - NDArray embedding = model.forward(new NDList(features)).singletonOrThrow(); - - // 转换为Java数组 - return embedding.toFloatArray(); - } catch (Exception e) { - log.error("获取用户嵌入向量失败", e); - return new float[EMBEDDING_SIZE]; - } - } - - /** - * 计算相似度分数 - */ - public double calculateSimilarityScore(float[] embedding1, float[] embedding2) { - double dotProduct = 0.0; - double norm1 = 0.0; - double norm2 = 0.0; - - for (int i = 0; i < embedding1.length; i++) { - dotProduct += embedding1[i] * embedding2[i]; - norm1 += embedding1[i] * embedding1[i]; - norm2 += embedding2[i] * embedding2[i]; - } - - return dotProduct / (Math.sqrt(norm1) * Math.sqrt(norm2)); - } - - private void loadModel() { - try { - // 加载预训练模型 - Path modelPath = Paths.get(MODEL_PATH); - model.load(modelPath); - } catch (Exception e) { - log.error("加载推荐模型失败", e); - } - } - - private NDArray prepareVideoFeatures(Video video) { - // 将视频特征转换为模型输入格式 - float[] features = new float[]{ - video.getDuration(), - video.getViewCount(), - video.getLikeCount(), - // ... 其他特征 - }; - return manager.create(features); - } - - private NDArray prepareUserFeatures(List behaviors) { - // 将用户行为特征转换为模型输入格式 - float[] features = new float[]{ - // 统计特征 - behaviors.size(), - calculateAverageWatchDuration(behaviors), - calculateLikeRatio(behaviors), - // ... 其他特征 - }; - return manager.create(features); - } -} \ No newline at end of file diff --git a/src/main/java/com/guwan/backend/service/FileService.java b/src/main/java/com/guwan/backend/service/FileService.java deleted file mode 100644 index b09321a..0000000 --- a/src/main/java/com/guwan/backend/service/FileService.java +++ /dev/null @@ -1,5 +0,0 @@ -package com.guwan.backend.service; - -public interface FileService { - String uploadBase64Image(String base64Image, String folder); -} \ No newline at end of file diff --git a/src/main/java/com/guwan/backend/service/HdfsStorageService.java b/src/main/java/com/guwan/backend/service/HdfsStorageService.java deleted file mode 100644 index bb75b92..0000000 --- a/src/main/java/com/guwan/backend/service/HdfsStorageService.java +++ /dev/null @@ -1,82 +0,0 @@ -package com.guwan.backend.service; - -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; -import org.apache.hadoop.fs.FSDataInputStream; -import org.apache.hadoop.fs.FSDataOutputStream; -import org.apache.hadoop.fs.FileSystem; -import org.apache.hadoop.fs.Path; -import org.springframework.stereotype.Service; -import org.springframework.web.multipart.MultipartFile; - -import java.io.BufferedInputStream; -import java.io.IOException; -import java.io.InputStream; - -@Slf4j -@Service -@RequiredArgsConstructor -public class HdfsStorageService { - - private final FileSystem fileSystem; - private static final String VIDEO_PATH = "/videos"; - private static final int BUFFER_SIZE = 4096; - - /** - * 上传视频到HDFS - */ - public String uploadVideo(MultipartFile file, String fileName) throws IOException { - String hdfsPath = VIDEO_PATH + "/" + fileName; - Path path = new Path(hdfsPath); - - try (FSDataOutputStream out = fileSystem.create(path); - BufferedInputStream in = new BufferedInputStream(file.getInputStream())) { - - byte[] buffer = new byte[BUFFER_SIZE]; - int length; - while ((length = in.read(buffer)) > 0) { - out.write(buffer, 0, length); - } - - return hdfsPath; - } - } - - /** - * 从HDFS读取视频流 - */ - public InputStream getVideoStream(String path) throws IOException { - Path hdfsPath = new Path(path); - if (!fileSystem.exists(hdfsPath)) { - throw new IOException("Video not found: " + path); - } - return fileSystem.open(hdfsPath); - } - - /** - * 删除HDFS中的视频 - */ - public void deleteVideo(String path) throws IOException { - Path hdfsPath = new Path(path); - if (fileSystem.exists(hdfsPath)) { - fileSystem.delete(hdfsPath, false); - } - } - - /** - * 获取视频元数据 - */ - public VideoMetadata getVideoMetadata(String path) throws IOException { - Path hdfsPath = new Path(path); - if (!fileSystem.exists(hdfsPath)) { - throw new IOException("Video not found: " + path); - } - - return VideoMetadata.builder() - .size(fileSystem.getFileStatus(hdfsPath).getLen()) - .blockSize(fileSystem.getFileStatus(hdfsPath).getBlockSize()) - .replication(fileSystem.getFileStatus(hdfsPath).getReplication()) - .modificationTime(fileSystem.getFileStatus(hdfsPath).getModificationTime()) - .build(); - } -} \ No newline at end of file diff --git a/src/main/java/com/guwan/backend/service/VerificationService.java b/src/main/java/com/guwan/backend/service/VerificationService.java deleted file mode 100644 index 03b70e5..0000000 --- a/src/main/java/com/guwan/backend/service/VerificationService.java +++ /dev/null @@ -1,8 +0,0 @@ -package com.guwan.backend.service; - -public interface VerificationService { - void sendEmailCode(String email); - void sendSmsCode(String phone); - boolean verifyEmailCode(String email, String code); - boolean verifySmsCode(String phone, String code); -} \ No newline at end of file diff --git a/src/main/java/com/guwan/backend/service/VideoRecommendService.java b/src/main/java/com/guwan/backend/service/VideoRecommendService.java deleted file mode 100644 index 70af961..0000000 --- a/src/main/java/com/guwan/backend/service/VideoRecommendService.java +++ /dev/null @@ -1,21 +0,0 @@ -package com.guwan.backend.service; - -import com.guwan.backend.dto.video.VideoDTO; -import java.util.List; - -public interface VideoRecommendService { - // 获取推荐视频列表 - List getRecommendVideos(Long userId, int limit); - - // 记录用户行为 - void recordUserBehavior(Long userId, Long videoId, String behaviorType, Integer watchDuration, Float watchProgress); - - // 更新用户兴趣 - void updateUserInterests(Long userId); - - // 计算视频相似度 - double calculateVideoSimilarity(Long videoId1, Long videoId2); - - // 获取相似视频 - List getSimilarVideos(Long videoId, int limit); -} \ No newline at end of file diff --git a/src/main/java/com/guwan/backend/service/impl/DummyFileServiceImpl.java b/src/main/java/com/guwan/backend/service/impl/DummyFileServiceImpl.java deleted file mode 100644 index 26fcf40..0000000 --- a/src/main/java/com/guwan/backend/service/impl/DummyFileServiceImpl.java +++ /dev/null @@ -1,18 +0,0 @@ -package com.guwan.backend.service.impl; - -import com.guwan.backend.service.FileService; -import lombok.extern.slf4j.Slf4j; -import org.springframework.context.annotation.Primary; -import org.springframework.stereotype.Service; - -@Slf4j -@Service -@Primary -public class DummyFileServiceImpl implements FileService { - - @Override - public String uploadBase64Image(String base64Image, String folder) { - log.info("模拟上传图片到文件夹: {}", folder); - return "dummy/image/path.jpg"; - } -} \ No newline at end of file diff --git a/src/main/java/com/guwan/backend/service/impl/FileServiceImpl.java b/src/main/java/com/guwan/backend/service/impl/FileServiceImpl.java deleted file mode 100644 index 4ca1e64..0000000 --- a/src/main/java/com/guwan/backend/service/impl/FileServiceImpl.java +++ /dev/null @@ -1,46 +0,0 @@ -package com.guwan.backend.service.impl; - -import com.guwan.backend.service.FileService; -import lombok.extern.slf4j.Slf4j; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.stereotype.Service; - -import java.io.File; -import java.io.FileOutputStream; -import java.util.Base64; -import java.util.UUID; - -@Slf4j -//@Service // 注释掉这个注解 -public class FileServiceImpl implements FileService { - - @Value("${file.upload.path}") - private String uploadPath; - - @Override - public String uploadBase64Image(String base64Image, String folder) { - try { - // 解码Base64图片 - String[] parts = base64Image.split(","); - byte[] imageBytes = Base64.getDecoder().decode(parts[1]); - - // 生成文件名 - String fileName = UUID.randomUUID().toString() + ".jpg"; - String folderPath = uploadPath + "/" + folder; - String filePath = folderPath + "/" + fileName; - - // 创建目录 - new File(folderPath).mkdirs(); - - // 写入文件 - try (FileOutputStream fos = new FileOutputStream(filePath)) { - fos.write(imageBytes); - } - - return folder + "/" + fileName; - } catch (Exception e) { - log.error("上传图片失败", e); - throw new RuntimeException("上传图片失败", e); - } - } -} \ No newline at end of file diff --git a/src/main/java/com/guwan/backend/service/impl/VideoRecommendServiceImpl.java b/src/main/java/com/guwan/backend/service/impl/VideoRecommendServiceImpl.java deleted file mode 100644 index 609084f..0000000 --- a/src/main/java/com/guwan/backend/service/impl/VideoRecommendServiceImpl.java +++ /dev/null @@ -1,143 +0,0 @@ -package com.guwan.backend.service.impl; - -import com.guwan.backend.service.VideoRecommendService; -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; -import java.util.*; -import java.util.stream.Collectors; - -@Slf4j -@Service -@RequiredArgsConstructor -public class VideoRecommendServiceImpl implements VideoRecommendService { - - private final UserBehaviorMapper behaviorMapper; - private final VideoTagWeightMapper tagWeightMapper; - private final UserInterestMapper interestMapper; - private final VideoMapper videoMapper; - private final DeepRecommendService deepRecommendService; - - @Override - public List getRecommendVideos(Long userId, int limit) { - // 1. 获取用户行为数据 - List behaviors = getRecentBehaviors(userId); - - // 2. 获取用户嵌入向量 - float[] userEmbedding = deepRecommendService.getUserEmbedding(behaviors); - - // 3. 获取候选视频 - List