Revert "feat: 完整集成JWLLL搜索推荐系统到Merge项目"

This reverts commit b2ef519aa46c958768dba291676a9a4590d2b9ff.

Reason for revert: <错误的接口修改>

Change-Id: Ie3e7748c5331c509f45757792af5fe9e17172953
diff --git a/Merge/back_jwlll/README.md b/Merge/back_jwlll/README.md
deleted file mode 100644
index 9f19db8..0000000
--- a/Merge/back_jwlll/README.md
+++ /dev/null
@@ -1,64 +0,0 @@
-# JWLLL 搜索推荐算法服务
-
-这个模块包含了 JWLLL 的搜索推荐算法服务,提供以下功能:
-
-## 主要功能
-
-1. **智能搜索**
-   - 支持中文分词
-   - 拼音搜索
-   - 语义关联搜索
-   - TF-IDF 向量相似度
-   - Word2Vec 语义扩展
-
-2. **推荐算法**
-   - 基于标签的内容推荐
-   - 协同过滤推荐
-   - 个性化推荐
-
-3. **帖子管理**
-   - 帖子详情查看
-   - 点赞/取消点赞
-   - 评论功能
-   - 帖子上传
-
-## API 接口
-
-- `POST /search` - 搜索内容
-- `GET /user_tags` - 获取用户标签
-- `POST /recommend_tags` - 标签推荐
-- `POST /user_based_recommend` - 协同过滤推荐
-- `GET /post/<id>` - 获取帖子详情
-- `POST /like` - 点赞帖子
-- `POST /unlike` - 取消点赞
-- `POST /comment` - 添加评论
-- `GET /comments/<post_id>` - 获取评论
-- `POST /upload` - 上传帖子
-
-## 部署说明
-
-1. 确保安装了所有依赖:
-   ```bash
-   pip install -r requirements.txt
-   ```
-
-2. 配置数据库连接:
-   - 修改 `config.py` 中的数据库配置
-
-3. 启动服务:
-   ```bash
-   python app.py
-   ```
-
-4. 服务将在 http://127.0.0.1:5000 启动
-
-## 配置文件
-
-- `semantic_config.json` - 语义映射配置
-- `models/chinese_word2vec.bin` - Word2Vec 模型文件(可选)
-
-## 注意事项
-
-- Word2Vec 模型文件较大,如果没有可以禁用该功能
-- 确保数据库中有测试数据
-- 默认用户ID为 '3',请确保数据库中存在该用户
diff --git a/Merge/back_jwlll/app.py b/Merge/back_jwlll/app.py
deleted file mode 100644
index 940c564..0000000
--- a/Merge/back_jwlll/app.py
+++ /dev/null
@@ -1,1076 +0,0 @@
-# main_online.py
-# 搜索推荐算法服务的主入口
-
-import json
-import numpy as np
-import difflib
-from flask import Flask, request, jsonify, Response
-import pymysql
-import jieba
-from sklearn.feature_extraction.text import TfidfVectorizer
-from sklearn.metrics.pairwise import cosine_similarity
-import pypinyin
-from flask_cors import CORS
-import re
-import Levenshtein
-import os
-import logging
-
-# 设置日志
-logging.basicConfig(
-    level=logging.INFO,
-    format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
-)
-logger = logging.getLogger("allpt-search")
-
-# 导入Word2Vec辅助模块
-try:
-    from word2vec_helper import get_word2vec_helper, expand_query, get_similar_words
-    WORD2VEC_ENABLED = True
-    logger.info("Word2Vec模块已加载")
-except ImportError as e:
-    logger.warning(f"Word2Vec模块加载失败: {e},将使用传统搜索")
-    WORD2VEC_ENABLED = False
-
-# 数据库配置
-DB_CONFIG = {
-    "host": "10.126.59.25",
-    "port": 3306,
-    "user": "root",
-    "password": "123456",
-    "database": "redbook",
-    "charset": "utf8mb4"
-}
-
-def get_db_conn():
-    return pymysql.connect(**DB_CONFIG)
-
-def get_pinyin(text):
-    # 返回字符串的全拼音(不带声调,全部小写),支持英文直接返回
-    if not text:
-        return ""
-    import re
-    # 如果全是英文,直接返回小写
-    if re.fullmatch(r'[a-zA-Z]+', text):
-        return text.lower()
-    return ''.join([p[0] for p in pypinyin.pinyin(text, style=pypinyin.NORMAL)])
-
-def get_pinyin_initials(text):
-    # 返回字符串的首字母拼音(全部小写),支持英文直接返回
-    if not text:
-        return ""
-    import re
-    if re.fullmatch(r'[a-zA-Z]+', text):
-        return text.lower()
-    return ''.join([p[0][0] for p in pypinyin.pinyin(text, style=pypinyin.NORMAL)])
-
-# 新增词语相似度计算函数
-def word_similarity(word1, word2):
-    """计算两个词的相似度,支持拼音匹配"""
-    # 直接匹配
-    if word1 == word2:
-        return 1.0
-    
-    # 拼音匹配
-    if get_pinyin(word1) == get_pinyin(word2):
-        return 0.9
-    
-    # 拼音首字母匹配
-    if get_pinyin_initials(word1) == get_pinyin_initials(word2):
-        return 0.7
-    
-    # 字符串相似度
-    return difflib.SequenceMatcher(None, word1, word2).ratio()
-
-def semantic_title_similarity(query, title):
-    """计算查询词与标题的语义相似度"""
-    # 分词
-    query_words = list(jieba.cut(query))
-    title_words = list(jieba.cut(title))
-    
-    if not query_words or not title_words:
-        return 0.0
-    
-    # 计算每个查询词与标题词的最大相似度
-    max_similarities = []
-    key_matches = 0  # 关键词精确匹配数量
-    
-    for q_word in query_words:
-        if len(q_word.strip()) <= 1:  # 忽略单字,减少噪音
-            continue
-            
-        word_sims = [word_similarity(q_word, t_word) for t_word in title_words]
-        if word_sims:
-            max_sim = max(word_sims)
-            max_similarities.append(max_sim)
-            if max_sim > 0.85:  # 认为是关键词匹配
-                key_matches += 1
-    
-    if not max_similarities:
-        return 0.0
-    
-    # 计算平均相似度
-    avg_sim = sum(max_similarities) / len(max_similarities)
-    
-    # 权重计算: 平均相似度占70%,关键词匹配率占30%
-    key_match_ratio = key_matches / len(query_words) if query_words else 0
-    
-    # 标题中包含完整查询短语时给予额外加分
-    exact_bonus = 0.3 if query in title else 0
-    
-    return 0.7 * avg_sim + 0.3 * key_match_ratio + exact_bonus
-
-# 添加语义关联词典,用于增强搜索能力
-def load_semantic_mappings():
-    """
-    加载语义关联映射表,用于增强搜索语义理解
-    返回包含语义映射关系的字典
-    """
-    # 初始化空字典,所有映射将从配置文件加载
-    mappings = {}
-    
-    # 从配置文件加载映射
-    try:
-        config_path = os.path.join(os.path.dirname(__file__), "semantic_config.json")
-        if os.path.exists(config_path):
-            with open(config_path, 'r', encoding='utf-8') as f:
-                mappings = json.load(f)
-            logger.info(f"已从配置文件加载 {len(mappings)} 个语义映射")
-        else:
-            logger.warning(f"语义配置文件不存在: {config_path}")
-    except Exception as e:
-        logger.error(f"加载语义配置文件失败: {e}")
-    
-    return mappings
-
-# 初始化语义映射
-SEMANTIC_MAPPINGS = load_semantic_mappings()
-
-def expand_search_keywords(keyword):
-    """
-    扩展搜索关键词,增加语义关联词
-    """
-    expanded = [keyword]
-    
-    # 分词处理
-    words = list(jieba.cut(keyword))
-    logger.info(f"关键词 '{keyword}' 分词结果: {words}")  # 记录分词结果
-    
-    # 分别对每个分词进行语义扩展
-    for word in words:
-        if word in SEMANTIC_MAPPINGS:
-            # 添加语义关联词
-            mapped_words = SEMANTIC_MAPPINGS[word]
-            expanded.extend(mapped_words)
-            logger.info(f"语义映射: '{word}' -> {mapped_words}")
-            
-            # 移除所有特殊处理部分
-            # 不再对任何特定关键词如"越狱"进行特殊处理
-    
-    # Word2Vec扩展 - 如果可用,对分词结果进行Word2Vec扩展
-    if WORD2VEC_ENABLED:
-        try:
-            # 使用单独的变量记录原始扩展结果,方便记录日志
-            original_expanded = set(expanded)
-            
-            # 首先尝试对整个关键词进行扩展
-            w2v_expanded = set()
-            similar_words = get_similar_words(keyword, topn=3, min_similarity=0.6)
-            w2v_expanded.update(similar_words)
-            
-            # 然后对较长的分词进行扩展
-            for word in words:
-                if len(word) > 1:  # 忽略单字
-                    similar_words = get_similar_words(word, topn=2, min_similarity=0.65)
-                    w2v_expanded.update(similar_words)
-            
-            # 合并结果
-            expanded.extend(w2v_expanded)
-            
-            # 记录日志
-            if w2v_expanded:
-                logger.info(f"Word2Vec扩展: {keyword} -> {list(w2v_expanded)}")
-        except Exception as e:
-            # 出错时记录但不中断搜索流程
-            logger.error(f"Word2Vec扩展失败: {e}")
-            logger.info("将仅使用配置文件中的语义映射")
-    
-    # 去重
-    return list(set(expanded))
-
-# 替换原有的calculate_keyword_relevance函数,采用更通用的相关性算法
-def calculate_keyword_relevance(keyword, item):
-    """计算搜索关键词与条目的相关性得分"""
-    title = item.get('title', '')
-    description = item.get('description', '') or ''
-    tags = item.get('tags', '') or ''
-    category = item.get('category', '') or ''  # 添加category字段
-    
-    # 初始化得分
-    score = 0
-    
-    # 1. 精确匹配(最高优先级)
-    if keyword.lower() == title.lower():
-        return 15.0  # 完全匹配给予最高分
-    
-    # 2. 标题中精确词匹配
-    title_words = re.findall(r'\b\w+\b', title.lower())
-    if keyword.lower() in title_words:
-        score += 10.0  # 作为独立词完全匹配
-    
-    # 3. 标题包含关键词(部分匹配)
-    elif keyword.lower() in title.lower():
-        # 计算关键词所占标题比例
-        match_ratio = len(keyword) / len(title)
-        if match_ratio > 0.5:  # 关键词占标题很大比例
-            score += 8.0
-        else:
-            score += 5.0
-    
-    # 4. 标题分词匹配
-    keyword_words = list(jieba.cut(keyword))
-    title_jieba_words = list(jieba.cut(title))
-    
-    matched_words = 0
-    for k_word in keyword_words:
-        if len(k_word) > 1:  # 忽略单字
-            if k_word in title_jieba_words:
-                matched_words += 1
-            else:
-                # 拼音匹配
-                k_pinyin = get_pinyin(k_word)
-                for t_word in title_jieba_words:
-                    if get_pinyin(t_word) == k_pinyin:
-                        matched_words += 0.8
-                        break
-    
-    if len(keyword_words) > 0:
-        word_match_ratio = matched_words / len(keyword_words)
-        score += 3.0 * word_match_ratio
-    
-    # 5. 拼音相似度
-    keyword_pinyin = get_pinyin(keyword)
-    title_pinyin = get_pinyin(title)
-    
-    if keyword_pinyin == title_pinyin:
-        score += 3.5
-    elif keyword_pinyin in title_pinyin:
-        # 计算拼音在标题中的位置影响
-        pos = title_pinyin.find(keyword_pinyin)
-        if pos == 0:  # 出现在开头
-            score += 3.0
-        else:
-            score += 2.0
-    
-    # 6. 编辑距离相似度
-    try:
-        edit_distance = Levenshtein.distance(keyword.lower(), title.lower())
-        max_len = max(len(keyword), len(title))
-        if max_len > 0:
-            similarity = 1 - (edit_distance / max_len)
-            if similarity > 0.7:
-                score += 1.5 * similarity
-    except:
-        similarity = difflib.SequenceMatcher(None, keyword.lower(), title.lower()).ratio()
-        if similarity > 0.7:
-            score += 1.5 * similarity
-    
-    # 7. 中文字符重叠检测 - 修改为仅当重叠2个以上汉字或占比超过40%时才计分
-    if re.search(r'[\u4e00-\u9fff]', keyword) and re.search(r'[\u4e00-\u9fff]', title):
-        cn_chars_keyword = set(re.findall(r'[\u4e00-\u9fff]', keyword))
-        cn_chars_title = set(re.findall(r'[\u4e00-\u9fff]', title))
-        
-        # 计算重叠的汉字集合
-        overlapped_chars = cn_chars_keyword & cn_chars_title
-        
-        # 仅当重叠汉字数量大于1且占比超过阈值时才计分
-        if len(overlapped_chars) > 1 and len(cn_chars_keyword) > 0:
-            overlap_ratio = len(overlapped_chars) / len(cn_chars_keyword)
-            # 增加重叠比例的阈值要求,防止单个汉字导致的误匹配
-            if overlap_ratio >= 0.4 or len(overlapped_chars) >= 3:
-                score += 2.0 * overlap_ratio
-            # 对于非常低的重叠度,不加分,避免无关内容干扰
-        
-        # 记录日志,帮助调试特定案例
-        if keyword == "明日方舟" and "白日梦想家" in title:
-            logger.info(f"'明日方舟'与'{title}'的汉字重叠: {overlapped_chars}, 重叠比例: {len(overlapped_chars)/len(cn_chars_keyword) if cn_chars_keyword else 0}")
-    
-    # 8. 序列资源检测(如"功夫熊猫2"是"功夫熊猫"的系列)
-    base_title_match = re.match(r'(.*?)([0-9]+|[一二三四五六七八九十]|:|\:|\s+[0-9]+)', title)
-    if base_title_match:
-        base_title = base_title_match.group(1).strip()
-        if keyword.lower() == base_title.lower():
-            score += 2.0
-    
-    # 9. 标签和描述匹配(增加权重)
-    if tags:
-        tags_list = tags.split(',')
-        if keyword in tags_list:
-            score += 1.5  # 提高标签匹配的权重
-        elif any(keyword.lower() in tag.lower() for tag in tags_list):
-            score += 1.0  # 提高部分匹配的权重
-    
-    # 描述匹配增强
-    if keyword.lower() in description.lower():
-        score += 1.5  # 提高描述匹配的权重
-        
-        # 检查关键词在描述中的位置和上下文
-        pos = description.lower().find(keyword.lower())
-        if pos >= 0 and pos < len(description) / 3:
-            # 关键词出现在描述前1/3部分,可能更重要
-            score += 0.5
-    
-    # 考虑分词匹配描述
-    keyword_words = list(jieba.cut(keyword))
-    description_words = list(jieba.cut(description))
-    matched_desc_words = 0
-    for k_word in keyword_words:
-        if len(k_word) > 1 and k_word in description_words:
-            matched_desc_words += 1
-    
-    if len(keyword_words) > 0:
-        desc_match_ratio = matched_desc_words / len(keyword_words)
-        score += 1.0 * desc_match_ratio
-    
-    # 分类匹配
-    if keyword.lower() in category.lower():
-        score += 1.0
-    
-    # 添加语义关联匹配得分
-    # 扩展关键词进行匹配
-    expanded_keywords = expand_search_keywords(keyword)
-    # 检测标题是否包含语义相关词
-    for exp_keyword in expanded_keywords:
-        if exp_keyword != keyword and exp_keyword in title:  # 避免重复计算原关键词
-            score += 1.5  # 一般语义关联
-    
-    return score
-
-# 创建Flask应用
-app = Flask(__name__)
-CORS(app)  # 允许所有跨域请求
-
-# 添加init_word2vec函数
-def init_word2vec():
-    """初始化Word2Vec模型"""
-    try:
-        helper = get_word2vec_helper()
-        if helper.initialized:
-            logger.info(f"Word2Vec模型已成功加载,词汇量: {len(helper.model.index_to_key)}, 向量维度: {helper.model.vector_size}")
-        else:
-            if helper.load_model():
-                logger.info(f"Word2Vec模型加载成功,词汇量: {len(helper.model.index_to_key)}, 向量维度: {helper.model.vector_size}")
-            else:
-                logger.error("Word2Vec模型加载失败")
-    except Exception as e:
-        logger.error(f"初始化Word2Vec出错: {e}")
-
-# 新的初始化方式:
-def initialize_app():
-    """应用初始化函数,替代before_first_request装饰器"""
-    # 修正:使用正确的函数名
-    # 原代码: init_semantic_mapping()
-    # 修正为使用已定义的函数名
-    global SEMANTIC_MAPPINGS
-    SEMANTIC_MAPPINGS = load_semantic_mappings()  # 更新全局语义映射变量
-    
-    if WORD2VEC_ENABLED:
-        init_word2vec()  # 现在这个函数已经定义了
-
-# 在启动应用之前调用初始化函数
-initialize_app()
-
-# 测试路由
-@app.route('/test', methods=['GET'])
-def test():
-    import datetime
-    return jsonify({"message": "服务器正常运行", "timestamp": str(datetime.datetime.now())})
-
-# 获取单个帖子详情的API
-@app.route('/post/<int:post_id>', methods=['GET'])
-def get_post_detail(post_id):
-    """
-    获取单个帖子详情
-    """
-    logger.info(f"接收到获取帖子详情请求,post_id: {post_id}")
-    conn = get_db_conn()
-    try:
-        with conn.cursor(pymysql.cursors.DictCursor) as cursor:
-            # 联表查询帖子详情,获取分类名和type
-            query = """
-            SELECT 
-                p.id,
-                p.title,
-                p.content,
-                p.heat,
-                p.created_at as create_time,
-                p.updated_at as last_active,
-                p.status,
-                p.type,
-                tp.name as category
-            FROM posts p 
-            LEFT JOIN topics tp ON p.topic_id = tp.id
-            WHERE p.id = %s
-            """
-            logger.info(f"执行查询: {query} with post_id: {post_id}")
-            cursor.execute(query, (post_id,))
-            post = cursor.fetchone()
-            
-            logger.info(f"查询结果: {post}")
-            
-            if not post:
-                logger.warning(f"帖子不存在,post_id: {post_id}")
-                return jsonify({"error": "帖子不存在"}), 404
-            
-            # 设置默认值
-            post['tags'] = []
-            post['author'] = '匿名用户'
-            if not post.get('category'):
-                post['category'] = '未分类'
-            if not post.get('type'):
-                post['type'] = 'text'
-            # 格式化时间
-            if post['create_time']:
-                post['create_time'] = post['create_time'].strftime('%Y-%m-%d %H:%M:%S')
-            if post['last_active']:
-                post['last_active'] = post['last_active'].strftime('%Y-%m-%d %H:%M:%S')
-            
-            logger.info(f"返回帖子详情: {post}")
-            return Response(json.dumps(post, ensure_ascii=False), mimetype='application/json; charset=utf-8')
-    except Exception as e:
-        logger.error(f"获取帖子详情失败: {e}")
-        import traceback
-        traceback.print_exc()
-        return jsonify({"error": "服务器内部错误"}), 500
-    finally:
-        conn.close()
-
-# 搜索功能的API
-@app.route('/search', methods=['POST'])
-def search():
-    """
-    搜索功能API
-    请求格式:{
-        "keyword": "关键词",
-        "sort_by": "downloads" | "downloads_asc" | "newest" | "oldest" | "similarity" | "title_asc" | "title_desc",
-        "category": "可选,分类名",
-        "search_mode": "title" | "title_desc" | "tags" | "all"  # 可选,默认"title",
-        "tags": ["标签1", "标签2"]  # 可选,支持传递多个标签
-    }
-    """
-    if request.content_type != 'application/json':
-        return jsonify({"error": "Content-Type must be application/json"}), 415
-
-    data = request.get_json()
-    keyword = data.get("keyword", "").strip()
-    sort_by = data.get("sort_by", "similarity")  # 默认按相似度排序
-    category = data.get("category", None)
-    search_mode = data.get("search_mode", "title")
-    tags = data.get("tags", None)  # 支持传递多个标签
-
-    # 校验参数 - 不管什么模式都要求关键词
-    if not (1 <= len(keyword) <= 20):
-        return jsonify({"error": "请输入1-20个字符"}), 400
-
-    # 第一阶段:数据库查询获取候选集
-    results = []
-    conn = get_db_conn()
-    try:
-        with conn.cursor(pymysql.cursors.DictCursor) as cursor:
-            # 首先尝试查询完全匹配的结果
-            exact_query = f"""
-                SELECT id, title, topic_id, heat, created_at, content
-                FROM posts
-                WHERE title = %s
-            """
-            cursor.execute(exact_query, (keyword,))
-            exact_matches = cursor.fetchall() or []  # 确保返回列表而非元组
-            
-            # 扩展关键词,增加语义关联词
-            expanded_keywords = expand_search_keywords(keyword)
-            logger.info(f"扩展后的关键词: {expanded_keywords}")  # 调试信息
-            
-            # 构建查询条件
-            conditions = []
-            params = []
-            
-            # 标题匹配 - 所有搜索模式都匹配title
-            conditions.append("title LIKE %s")
-            params.append(f"%{keyword}%")
-            
-            # 为扩展关键词添加标题匹配条件
-            for exp_keyword in expanded_keywords:
-                if exp_keyword != keyword:  # 避免重复原关键词
-                    conditions.append("title LIKE %s")
-                    params.append(f"%{exp_keyword}%")
-            
-            # 描述匹配
-            if search_mode in ["title_desc", "all"]:
-                # 原始关键词匹配描述
-                conditions.append("content LIKE %s")
-                params.append(f"%{keyword}%")
-                
-                # 扩展关键词匹配描述
-                for exp_keyword in expanded_keywords:
-                    if exp_keyword != keyword:
-                        conditions.append("content LIKE %s")
-                        params.append(f"%{exp_keyword}%")
-            
-            # 标签匹配
-            # 暂不处理,后续join实现
-            
-            # 分类匹配 - 仅在all模式下
-            if search_mode == "all":
-                # 原始关键词匹配分类
-                conditions.append("topic_id LIKE %s")
-                params.append(f"%{keyword}%")
-                
-                # 扩展关键词匹配分类
-                for exp_keyword in expanded_keywords:
-                    if exp_keyword != keyword:
-                        conditions.append("topic_id LIKE %s")
-                        params.append(f"%{exp_keyword}%")
-            
-            # 构建SQL查询
-            if conditions:
-                where_clause = " OR ".join(conditions)
-                logger.info(f"搜索条件: {where_clause}")
-                logger.info(f"参数列表: {params}")
-                
-                if category:
-                    where_clause = f"({where_clause}) AND topic_id=%s"
-                    params.append(category)
-                
-                sql = f"""
-                    SELECT p.id, p.title, tp.name as category, p.heat, p.created_at, p.content,
-                        GROUP_CONCAT(t.name) as tags
-                    FROM posts p
-                    LEFT JOIN post_tags pt ON p.id = pt.post_id
-                    LEFT JOIN tags t ON pt.tag_id = t.id
-                    LEFT JOIN topics tp ON p.topic_id = tp.id
-                    WHERE {where_clause}
-                    GROUP BY p.id
-                    LIMIT 500
-                """
-                
-                cursor.execute(sql, params)
-                expanded_results = cursor.fetchall()
-                logger.info(f"数据库返回记录数: {len(expanded_results) if expanded_results else 0}")
-            else:
-                expanded_results = []
-
-            # 如果扩展查询和精确匹配都没有结果,获取全部记录进行相关性计算
-            if not expanded_results and not exact_matches:
-                sql = "SELECT p.id, p.title, tp.name as category, p.heat, p.created_at, p.content, GROUP_CONCAT(t.name) as tags FROM posts p LEFT JOIN post_tags pt ON p.id = pt.post_id LEFT JOIN tags t ON pt.tag_id = t.id LEFT JOIN topics tp ON p.topic_id = tp.id"
-                if category:
-                    sql += " WHERE p.topic_id=%s"
-                    category_params = [category]
-                    cursor.execute(sql + " GROUP BY p.id", category_params)
-                else:
-                    cursor.execute(sql + " GROUP BY p.id")
-                
-                all_results = cursor.fetchall() or []  # 确保返回列表
-            else:
-                if isinstance(exact_matches, tuple):
-                    exact_matches = list(exact_matches)
-                if isinstance(expanded_results, tuple):
-                    expanded_results = list(expanded_results)
-                all_results = expanded_results + exact_matches
-            
-            # 对所有结果使用相关性计算规则
-            scored_results = []
-            for item in all_results:
-                # 计算相关性得分
-                relevance_score = calculate_keyword_relevance(keyword, item)
-                
-                # 降低相关性阈值,确保更多结果被保留 (从0.5改为0.1)
-                if relevance_score > 0.1:
-                    item['relevance_score'] = relevance_score
-                    scored_results.append(item)
-                    logger.info(f"匹配项: {item['title']}, 相关性得分: {relevance_score}")
-            
-            # 按相关性得分排序
-            scored_results.sort(key=lambda x: x.get('relevance_score', 0), reverse=True)
-            
-            # 确保精确匹配的结果置顶
-            if exact_matches:
-                for exact_match in exact_matches:
-                    exact_match['relevance_score'] = 20.0  # 超高分确保置顶
-                
-                # 移除scored_results中已经存在于exact_matches的项
-                exact_ids = {item['id'] for item in exact_matches}
-                scored_results = [item for item in scored_results if item['id'] not in exact_ids]
-                
-                # 合并两个结果集
-                results = exact_matches + scored_results
-            else:
-                results = scored_results
-            
-            # 限制返回结果数量
-            results = results[:50]
-            
-    except Exception as e:
-        logger.error(f"搜索出错: {e}")
-        import traceback
-        traceback.print_exc()
-        return jsonify({"error": "搜索系统异常,请稍后再试"}), 500
-    finally:
-        conn.close()
-    
-    # 第二阶段:根据指定方式排序
-    if results:
-        if sort_by == "similarity" or not sort_by:
-            # 保持按相关性得分排序,已经排好了
-            pass
-        elif sort_by == "downloads":
-            results.sort(key=lambda x: x.get("download_count", 0), reverse=True)
-        elif sort_by == "downloads_asc":
-            results.sort(key=lambda x: x.get("download_count", 0))
-        elif sort_by == "newest":
-            results.sort(key=lambda x: x.get("create_time", ""), reverse=True)
-        elif sort_by == "oldest":
-            results.sort(key=lambda x: x.get("create_time", ""))
-        elif sort_by == "title_asc":
-            results.sort(key=lambda x: x.get("title", ""))
-        elif sort_by == "title_desc":
-            results.sort(key=lambda x: x.get("title", ""), reverse=True)
-    
-    # 最终处理:清理不需要返回的字段,并将 datetime 转为字符串
-    for item in results:
-        item.pop("description", None)
-        item.pop("tags", None)
-        item.pop("relevance_score", None)
-        for k, v in item.items():
-            if hasattr(v, 'isoformat'):
-                item[k] = v.isoformat(sep=' ', timespec='seconds')
-
-    return Response(json.dumps({"results": results}, ensure_ascii=False), mimetype='application/json; charset=utf-8')
-
-# 推荐功能的API
-@app.route('/recommend_tags', methods=['POST'])
-def recommend_tags():
-    """
-    推荐功能API
-    请求格式:{
-        "user_id": "user1",
-        "tags": ["标签1", "标签2"]  # 可为空
-    }
-    """
-    if request.content_type != 'application/json':
-        return jsonify({"error": "Content-Type must be application/json"}), 415
-
-    data = request.get_json()
-    user_id = data.get("user_id")
-    tags = set(data.get("tags", []))
-
-    # 查询用户已保存的兴趣标签
-    user_tags = set()
-    if user_id:
-        conn = get_db_conn()
-        try:
-            with conn.cursor() as cursor:
-                cursor.execute("SELECT t.name FROM user_tags ut JOIN tags t ON ut.tag_id = t.id WHERE ut.user_id=%s", (user_id,))
-                user_tags = set(row[0] for row in cursor.fetchall())
-        finally:
-            conn.close()
-
-    # 合并前端传递的tags和用户兴趣标签
-    all_tags = list(tags | user_tags)
-
-    if not all_tags:
-        return Response(json.dumps({"error": "暂无推荐结果"}, ensure_ascii=False), mimetype='application/json; charset=utf-8'), 200
-
-    conn = get_db_conn()
-    try:
-        with conn.cursor(pymysql.cursors.DictCursor) as cursor:
-            # 优先用tags字段匹配
-            # 先查找所有tag_id
-            tag_ids = []
-            for tag in all_tags:
-                cursor.execute("SELECT id FROM tags WHERE name=%s", (tag,))
-                row = cursor.fetchone()
-                if row:
-                    tag_ids.append(row['id'])
-            if not tag_ids:
-                return Response(json.dumps({"error": "暂无推荐结果"}, ensure_ascii=False), mimetype='application/json; charset=utf-8'), 200
-            tag_placeholders = ','.join(['%s'] * len(tag_ids))
-            sql = f"""
-                SELECT p.id, p.title, tp.name as category, p.heat,
-                       GROUP_CONCAT(tg.name) as tags
-                FROM posts p
-                LEFT JOIN post_tags pt ON p.id = pt.post_id
-                LEFT JOIN tags tg ON pt.tag_id = tg.id
-                LEFT JOIN topics tp ON p.topic_id = tp.id
-                WHERE pt.tag_id IN ({tag_placeholders})
-                GROUP BY p.id
-                LIMIT 50
-            """
-            cursor.execute(sql, tuple(tag_ids))
-            results = cursor.fetchall()
-            # 若无结果,回退title/content模糊匹配
-            if not results:
-                or_conditions = []
-                params = []
-                for tag in all_tags:
-                    or_conditions.append("p.title LIKE %s OR p.content LIKE %s")
-                    params.extend(['%' + tag + '%', '%' + tag + '%'])
-                where_clause = ' OR '.join(or_conditions)
-                sql = f"""
-                    SELECT p.id, p.title, tp.name as category, p.heat,
-                           GROUP_CONCAT(tg.name) as tags
-                    FROM posts p
-                    LEFT JOIN post_tags pt ON p.id = pt.post_id
-                    LEFT JOIN tags tg ON pt.tag_id = tg.id
-                    LEFT JOIN topics tp ON p.topic_id = tp.id
-                    WHERE {where_clause}
-                    GROUP BY p.id
-                    LIMIT 50
-                """
-                cursor.execute(sql, tuple(params))
-                results = cursor.fetchall()
-    finally:
-        conn.close()
-
-    if not results:
-        return Response(json.dumps({"error": "暂无推荐结果"}, ensure_ascii=False), mimetype='application/json; charset=utf-8'), 200
-
-    return Response(json.dumps({"recommendations": results}, ensure_ascii=False), mimetype='application/json; charset=utf-8')
-
-# 用户兴趣标签管理API(可选)
-@app.route('/tags', methods=['POST', 'GET', 'DELETE'])
-def user_tags():
-    """
-    POST: 添加用户兴趣标签
-    GET: 查询用户兴趣标签
-    DELETE: 删除用户兴趣标签
-    """
-    if request.method == 'POST':
-        if request.content_type != 'application/json':
-            return jsonify({"error": "Content-Type must be application/json"}), 415
-        data = request.get_json()
-        user_id = data.get("user_id")
-        tags = data.get("tags", [])
-        
-        if not user_id:
-            return jsonify({"error": "用户ID不能为空"}), 400
-        
-        # 确保标签列表格式正确
-        if isinstance(tags, str):
-            tags = [tag.strip() for tag in tags.split(',') if tag.strip()]
-        
-        if not tags:
-            return jsonify({"error": "标签不能为空"}), 400
-        
-        conn = get_db_conn()
-        try:
-            with conn.cursor() as cursor:
-                # 添加用户标签
-                for tag in tags:
-                    # 先查找tag_id
-                    cursor.execute("SELECT id FROM tags WHERE name=%s", (tag,))
-                    tag_row = cursor.fetchone()
-                    if tag_row:
-                        tag_id = tag_row[0]
-                        cursor.execute("REPLACE INTO user_tags (user_id, tag_id) VALUES (%s, %s)", (user_id, tag_id))
-                conn.commit()
-                # 返回更新后的标签列表
-                cursor.execute("SELECT t.name FROM user_tags ut JOIN tags t ON ut.tag_id = t.id WHERE ut.user_id=%s", (user_id,))
-                updated_tags = [row[0] for row in cursor.fetchall()]
-        finally:
-            conn.close()
-        return Response(json.dumps({"msg": "添加成功", "tags": updated_tags}, ensure_ascii=False), mimetype='application/json; charset=utf-8')
-    elif request.method == 'DELETE':
-        if request.content_type != 'application/json':
-            return jsonify({"error": "Content-Type must be application/json"}), 415
-        data = request.get_json()
-        user_id = data.get("user_id")
-        tags = data.get("tags", [])
-        if not user_id:
-            return jsonify({"error": "用户ID不能为空"}), 400
-        if not tags:
-            return jsonify({"error": "标签不能为空"}), 400
-        
-        conn = get_db_conn()
-        try:
-            with conn.cursor() as cursor:
-                for tag in tags:
-                    cursor.execute("SELECT id FROM tags WHERE name=%s", (tag,))
-                    tag_row = cursor.fetchone()
-                    if tag_row:
-                        tag_id = tag_row[0]
-                        cursor.execute("DELETE FROM user_tags WHERE user_id=%s AND tag_id=%s", (user_id, tag_id))
-                conn.commit()
-                cursor.execute("SELECT t.name FROM user_tags ut JOIN tags t ON ut.tag_id = t.id WHERE ut.user_id=%s", (user_id,))
-                remaining_tags = [row[0] for row in cursor.fetchall()]
-        finally:
-            conn.close()
-        return Response(json.dumps({"msg": "删除成功", "tags": remaining_tags}, ensure_ascii=False), mimetype='application/json; charset=utf-8')
-    else:  # GET 请求
-        user_id = request.args.get("user_id")
-        if not user_id:
-            return jsonify({"error": "用户ID不能为空"}), 400
-        conn = get_db_conn()
-        try:
-            with conn.cursor() as cursor:
-                cursor.execute("SELECT t.name FROM user_tags ut JOIN tags t ON ut.tag_id = t.id WHERE ut.user_id=%s", (user_id,))
-                tags = [row[0] for row in cursor.fetchall()]
-        finally:
-            conn.close()
-        return Response(json.dumps({"tags": tags}, ensure_ascii=False), mimetype='application/json; charset=utf-8')
-
-# 添加/user_tags路由作为/tags的别名
-@app.route('/user_tags', methods=['POST', 'GET', 'DELETE'])
-def user_tags_alias():
-    """
-    /user_tags路由 - 作为/tags路由的别名
-    POST: 添加用户兴趣标签
-    GET: 查询用户兴趣标签
-    DELETE: 删除用户兴趣标签
-    """
-    return user_tags()
-
-# 基于用户的协同过滤推荐API
-@app.route('/user_based_recommend', methods=['POST'])
-def user_based_recommend():
-    """
-    基于用户的协同过滤推荐API
-    请求格式:{
-        "user_id": "user1",
-        "top_n": 5
-    }
-    """
-    if request.content_type != 'application/json':
-        return jsonify({"error": "Content-Type must be application/json"}), 415
-
-    data = request.get_json()
-    user_id = data.get("user_id")
-    top_n = int(data.get("top_n", 5))
-
-    if not user_id:
-        return jsonify({"error": "用户ID不能为空"}), 400
-    
-    conn = get_db_conn()
-    try:
-        with conn.cursor(pymysql.cursors.DictCursor) as cursor:
-            # 1. 检查用户是否存在下载记录(收藏或浏览)
-            cursor.execute("""
-                SELECT COUNT(*) as count
-                FROM behaviors
-                WHERE user_id = %s AND type IN ('favorite', 'view')
-            """, (user_id,))
-            result = cursor.fetchone()
-            user_download_count = result['count'] if result else 0
-            
-            logger.info(f"用户 {user_id} 下载记录数: {user_download_count}")
-            
-            # 如果用户没有足够的行为数据,返回基于热度的推荐
-            if user_download_count < 3:
-                logger.info(f"用户 {user_id} 下载记录不足,返回热门推荐")
-                cursor.execute("""
-                    SELECT p.id, p.title, tp.name as category, p.heat
-                    FROM posts p
-                    LEFT JOIN topics tp ON p.topic_id = tp.id
-                    ORDER BY p.heat DESC
-                    LIMIT %s
-                """, (top_n,))
-                popular_seeds = cursor.fetchall()
-                return Response(json.dumps({"recommendations": popular_seeds, "type": "popular"}, ensure_ascii=False), mimetype='application/json; charset=utf-8')
-            
-            # 2. 获取用户已下载(收藏/浏览)的帖子
-            cursor.execute("""
-                SELECT post_id
-                FROM behaviors
-                WHERE user_id = %s AND type IN ('favorite', 'view')
-            """, (user_id,))
-            user_seeds = set(row['post_id'] for row in cursor.fetchall())
-            logger.info(f"用户 {user_id} 已下载种子: {user_seeds}")
-            
-            # 3. 获取所有用户-帖子下载(收藏/浏览)矩阵
-            cursor.execute("""
-                SELECT user_id, post_id
-                FROM behaviors
-                WHERE created_at > DATE_SUB(NOW(), INTERVAL 3 MONTH)
-                AND user_id <> %s AND type IN ('favorite', 'view')
-            """, (user_id,))
-            download_records = cursor.fetchall()
-            
-            if not download_records:
-                logger.info(f"没有其他用户的下载记录,返回热门推荐")
-                cursor.execute("""
-                    SELECT p.id, p.title, tp.name as category, p.heat
-                    FROM posts p
-                    LEFT JOIN topics tp ON p.topic_id = tp.id
-                    ORDER BY p.heat DESC
-                    LIMIT %s
-                """, (top_n,))
-                popular_seeds = cursor.fetchall()
-                return Response(json.dumps({"recommendations": popular_seeds, "type": "popular"}, ensure_ascii=False), mimetype='application/json; charset=utf-8')
-            
-            # 构建用户-物品矩阵
-            user_item_matrix = {}
-            for record in download_records:
-                uid = record['user_id']
-                sid = record['post_id']
-                if uid not in user_item_matrix:
-                    user_item_matrix[uid] = set()
-                user_item_matrix[uid].add(sid)
-            
-            # 4. 计算用户相似度
-            similar_users = []
-            for other_id, other_seeds in user_item_matrix.items():
-                if other_id == user_id:
-                    continue
-                intersection = len(user_seeds.intersection(other_seeds))
-                union = len(user_seeds.union(other_seeds))
-                if union > 0 and intersection > 0:
-                    similarity = intersection / union
-                    similar_users.append((other_id, similarity, other_seeds))
-            logger.info(f"找到 {len(similar_users)} 个相似用户")
-            similar_users.sort(key=lambda x: x[1], reverse=True)
-            similar_users = similar_users[:5]
-            # 5. 基于相似用户推荐帖子
-            candidate_seeds = {}
-            for similar_user, similarity, seeds in similar_users:
-                logger.info(f"相似用户 {similar_user}, 相似度 {similarity}")
-                for post_id in seeds:
-                    if post_id not in user_seeds:
-                        if post_id not in candidate_seeds:
-                            candidate_seeds[post_id] = 0
-                        candidate_seeds[post_id] += similarity
-            if not candidate_seeds:
-                logger.info(f"没有找到候选种子,返回热门推荐")
-                cursor.execute("""
-                    SELECT p.id, p.title, tp.name as category, p.heat
-                    FROM posts p
-                    LEFT JOIN topics tp ON p.topic_id = tp.id
-                    ORDER BY p.heat DESC
-                    LIMIT %s
-                """, (top_n,))
-                popular_seeds = cursor.fetchall()
-                return Response(json.dumps({"recommendations": popular_seeds, "type": "popular"}, ensure_ascii=False), mimetype='application/json; charset=utf-8')
-            # 6. 获取推荐帖子的详细信息
-            recommended_seeds = sorted(candidate_seeds.items(), key=lambda x: x[1], reverse=True)[:top_n]
-            post_ids = [post_id for post_id, _ in recommended_seeds]
-            format_strings = ','.join(['%s'] * len(post_ids))
-            cursor.execute(f"""
-                SELECT p.id, p.title, tp.name as category, p.heat
-                FROM posts p
-                LEFT JOIN topics tp ON p.topic_id = tp.id
-                WHERE p.id IN ({format_strings})
-            """, tuple(post_ids))
-            result_seeds = cursor.fetchall()
-            seed_score_map = {post_id: score for post_id, score in recommended_seeds}
-            result_seeds.sort(key=lambda x: seed_score_map.get(x['id'], 0), reverse=True)
-            logger.info(f"返回 {len(result_seeds)} 个基于协同过滤的推荐")
-            return Response(json.dumps({"recommendations": result_seeds, "type": "collaborative"}, ensure_ascii=False), mimetype='application/json; charset=utf-8')
-    except Exception as e:
-        logger.error(f"推荐系统错误: {e}")
-        import traceback
-        traceback.print_exc()
-        return Response(json.dumps({"error": "推荐系统异常,请稍后再试", "details": str(e)}, ensure_ascii=False), mimetype='application/json; charset=utf-8')
-    finally:
-        conn.close()
-@app.route('/word2vec_status', methods=['GET'])
-def word2vec_status():
-    """
-    检查Word2Vec模型状态
-    返回模型是否加载、词汇量等信息
-    """
-    if not WORD2VEC_ENABLED:
-        return Response(json.dumps({
-            "enabled": False,
-            "message": "Word2Vec功能未启用"
-        }, ensure_ascii=False), mimetype='application/json; charset=utf-8')
-    try:
-        helper = get_word2vec_helper()
-        status = {
-            "enabled": WORD2VEC_ENABLED,
-            "initialized": helper.initialized,
-            "vocab_size": len(helper.model.index_to_key) if helper.model else 0,
-            "vector_size": helper.model.vector_size if helper.model else 0
-        }
-        
-        # 测试几个常用词的相似词,展示模型效果
-        test_results = {}
-        test_words = ["电影", "动作", "科幻", "动漫", "游戏"]
-        for word in test_words:
-            similar_words = helper.get_similar_words(word, topn=5)
-            test_results[word] = similar_words
-        
-        status["test_results"] = test_results
-        return Response(json.dumps(status, ensure_ascii=False), mimetype='application/json; charset=utf-8')
-    except Exception as e:
-        return Response(json.dumps({
-            "enabled": WORD2VEC_ENABLED,
-            "initialized": False,
-            "error": str(e)
-        }, ensure_ascii=False), mimetype='application/json; charset=utf-8')
-
-# 添加一个临时诊断端点
-@app.route('/debug_search', methods=['POST'])
-def debug_search():
-    """临时的调试端点,用于检查数据库中的记录"""
-    if request.content_type != 'application/json':
-        return jsonify({"error": "Content-Type must be application/json"}), 415
-
-    data = request.get_json()
-    keyword = data.get("keyword", "").strip()
-    
-    conn = get_db_conn()
-    try:
-        with conn.cursor(pymysql.cursors.DictCursor) as cursor:
-            # 尝试查询包含特定词的所有记录
-            queries = [
-                ("标题中包含关键词", f"SELECT seed_id, title, description, tags FROM pt_seed WHERE title LIKE '%{keyword}%' LIMIT 10"),
-                ("描述中包含关键词", f"SELECT seed_id, title, description, tags FROM pt_seed WHERE description LIKE '%{keyword}%' LIMIT 10"),
-                ("标签中包含关键词", f"SELECT seed_id, title, description, tags FROM pt_seed WHERE FIND_IN_SET('{keyword}', tags) LIMIT 10"),
-                ("肖申克的救赎", "SELECT seed_id, title, description, tags FROM pt_seed WHERE title = '肖申克的救赎'")
-            ]
-            
-            results = {}
-            for query_name, query in queries:
-                cursor.execute(query)
-                results[query_name] = cursor.fetchall()
-                
-            return Response(json.dumps(results, ensure_ascii=False), mimetype='application/json; charset=utf-8')
-    finally:
-        conn.close()
-
-"""
-接口本地测试方法(可直接运行main_online.py后用curl或Postman测试):
-
-1. 搜索接口
-curl -X POST http://127.0.0.1:5000/search -H "Content-Type: application/json" -d '{"keyword":"电影","sort_by":"downloads"}'
-
-2. 标签推荐接口
-curl -X POST http://127.0.0.1:5000/recommend_tags -H "Content-Type: application/json" -d '{"user_id":"1","tags":["动作","科幻"]}'
-
-3. 用户兴趣标签管理(添加标签)
-curl -X POST http://127.0.0.1:5000/user_tags -H "Content-Type: application/json" -d '{"user_id":"1","tags":["动作","科幻"]}'
-
-4. 用户兴趣标签管理(查询标签)
-curl "http://127.0.0.1:5000/user_tags?user_id=1"
-
-5. 用户兴趣标签管理(删除标签)
-curl -X DELETE http://127.0.0.1:5000/user_tags -H "Content-Type: application/json" -d '{"user_id":"1","tags":["动作","科幻"]}'
-
-6. 协同过滤推荐
-curl -X POST http://127.0.0.1:5000/user_based_recommend -H "Content-Type: application/json" -d '{"user_id":"user1","top_n":3}'
-
-7. Word2Vec状态检查
-curl "http://127.0.0.1:5000/word2vec_status"
-
-8. 调试接口(临时)
-curl -X POST http://127.0.0.1:5000/debug_search -H "Content-Type: application/json" -d '{"keyword":"电影"}'
-
-所有接口均可用Postman按上述参数测试。
-"""
-
-if __name__ == "__main__":
-    try:
-        logger.info("搜索推荐服务启动中...")
-        app.run(host="0.0.0.0", port=5000)
-    except Exception as e:
-        logger.error(f"启动异常: {e}")
-        import traceback
-        traceback.print_exc()
diff --git a/Merge/back_jwlll/config.py b/Merge/back_jwlll/config.py
deleted file mode 100644
index 77cb8dc..0000000
--- a/Merge/back_jwlll/config.py
+++ /dev/null
@@ -1,38 +0,0 @@
-# JWLLL 搜索推荐服务配置
-
-# 数据库配置
-DB_CONFIG = {
-    "host": "10.126.59.25",
-    "port": 3306,
-    "user": "root",
-    "password": "123456",
-    "database": "redbook",
-    "charset": "utf8mb4"
-}
-
-# 服务器配置
-SERVER_CONFIG = {
-    "host": "127.0.0.1",
-    "port": 5000,
-    "debug": True
-}
-
-# Word2Vec 模型配置
-WORD2VEC_CONFIG = {
-    "model_path": "models/chinese_word2vec.bin",
-    "enabled": True  # 如果没有模型文件,设置为 False
-}
-
-# 搜索推荐配置
-SEARCH_CONFIG = {
-    "default_user_id": "3",
-    "default_tags": ["美食", "影视", "穿搭"],
-    "max_results": 50,
-    "similarity_threshold": 0.1
-}
-
-# 日志配置
-LOGGING_CONFIG = {
-    "level": "INFO",
-    "format": "%(asctime)s - %(name)s - %(levelname)s - %(message)s"
-}
diff --git a/Merge/back_jwlll/requirements.txt b/Merge/back_jwlll/requirements.txt
deleted file mode 100644
index 6e7bd22..0000000
--- a/Merge/back_jwlll/requirements.txt
+++ /dev/null
@@ -1,9 +0,0 @@
-Flask==2.3.3
-pymysql==1.1.0
-scikit-learn==1.3.2
-jieba==0.42.1
-pypinyin==0.49.0
-flask-cors==4.0.0
-numpy==1.24.4
-Levenshtein==0.23.0
-gensim==4.3.2
diff --git a/Merge/back_jwlll/semantic_config.json b/Merge/back_jwlll/semantic_config.json
deleted file mode 100644
index f5e34d3..0000000
--- a/Merge/back_jwlll/semantic_config.json
+++ /dev/null
@@ -1,77 +0,0 @@
-{
-  "国宝": ["熊猫", "大熊猫", "功夫熊猫", "四川", "成都", "保护动物"],
-  "熊猫": ["国宝", "大熊猫", "功夫熊猫", "竹子", "四川", "黑白"],
-  "功夫": ["武术", "格斗", "武打", "功夫熊猫", "李小龙", "成龙", "太极", "截拳道", "中国功夫"],
-  
-  "梦": ["梦想", "梦境", "白日梦", "白日梦想家", "潜意识", "睡眠", "做梦"],
-  "白日梦": ["梦想", "幻想", "白日梦想家", "想象", "憧憬"],
-  
-  "魔戒": ["指环王", "魔戒再现", "中土世界", "霍比特人", "精灵", "魔法", "奇幻"],
-  "指环": ["魔戒", "指环王", "戒指", "魔戒再现", "首饰"],
-  "中土世界": ["魔戒", "指环王", "霍比特人", "精灵", "矮人", "奇幻"],
-  
-  "漫威": ["复仇者", "钢铁侠", "蜘蛛侠", "美国队长", "雷神", "绿巨人", "黑寡妇", "惊奇队长", "超级英雄", "漫画"],
-  "钢铁侠": ["托尼斯塔克", "钢铁战衣", "贾维斯", "复仇者", "漫威", "超级英雄"],
-  "蜘蛛侠": ["彼得帕克", "蜘蛛", "纽约", "漫威", "超级英雄", "蜘蛛感应"],
-  
-  "DC": ["蝙蝠侠", "超人", "神奇女侠", "正义联盟", "闪电侠", "水行侠", "超级英雄", "漫画"],
-  "蝙蝠侠": ["布鲁斯韦恩", "高谭市", "小丑", "罗宾", "DC", "超级英雄"],
-  "超人": ["克拉克肯特", "氪星", "莱克斯卢瑟", "超能力", "DC", "超级英雄"],
-  
-  "星球大战": ["星战", "原力", "天行者", "达斯维达", "尤达", "绝地武士", "光剑", "帝国", "科幻"],
-  "原力": ["绝地武士", "星球大战", "天行者", "尤达", "光剑", "西斯", "科幻"],
-  
-  "哈利波特": ["魔法", "霍格沃茨", "魔杖", "魔法石", "伏地魔", "巫师", "奇幻", "魔幻"],
-  "魔法": ["巫师", "法术", "咒语", "哈利波特", "霍格沃茨", "魔杖", "奇幻", "魔幻"],
-  
-  "科幻": ["未来", "太空", "星际", "外星人", "人工智能", "机器人", "时空", "星球大战", "星际穿越"],
-  "太空": ["宇宙", "星球", "卫星", "宇航员", "航天", "科幻", "星际", "外太空"],
-  "人工智能": ["AI", "机器学习", "深度学习", "神经网络", "机器人", "算法", "科技", "科幻"],
-  
-  "动作": ["武打", "格斗", "功夫", "特技", "追逐", "冒险", "刺激", "爆破"],
-  "冒险": ["探险", "奇遇", "探索", "未知", "旅程", "冒险家", "刺激", "危险"],
-  "奇幻": ["魔法", "魔幻", "神话", "异世界", "精灵", "龙", "魔戒", "哈利波特"],
-  
-  "悬疑": ["推理", "谜题", "侦探", "神秘", "悬念", "惊悚", "犯罪", "悬疑片"],
-  "推理": ["侦探", "线索", "谜题", "破案", "悬疑", "逻辑", "智力", "悬疑片"],
-  
-  "恐怖": ["惊悚", "鬼怪", "恶魔", "惊吓", "血腥", "恐怖片", "心理恐惧", "超自然"],
-  "鬼怪": ["幽灵", "鬼魂", "妖怪", "超自然", "恐怖", "惊悚", "诡异", "恐怖片"],
-  
-  "喜剧": ["搞笑", "幽默", "欢乐", "笑声", "喜剧片", "滑稽", "逗乐", "喜剧演员"],
-  "搞笑": ["幽默", "笑话", "喜剧", "逗乐", "滑稽", "欢乐", "喜剧片", "喜剧演员"],
-  
-  "战争": ["军事", "战场", "士兵", "军队", "战役", "武器", "战争片", "历史战争"],
-  "军事": ["军队", "武器", "战争", "军人", "战略", "战术", "国防", "军事片"],
-  
-  "剧情": ["情节", "故事", "叙事", "人物", "感人", "真实", "戏剧性", "剧情片"],
-  "历史": ["古代", "历史事件", "历史人物", "朝代", "文明", "历史片", "传记", "纪实"],
-  
-  "纪录片": ["真实记录", "纪实", "历史", "自然", "科学", "社会", "文化", "探索"],
-  "动画": ["卡通", "动漫", "动画片", "动画电影", "CG", "3D动画", "手绘", "二次元"],
-  
-  "音乐": ["歌曲", "旋律", "节奏", "乐器", "演唱", "音乐家", "音乐剧", "音乐会"],
-  "歌曲": ["歌词", "唱歌", "歌手", "流行歌曲", "音乐", "专辑", "单曲", "MV"],
-  
-  "爱情": ["恋爱", "浪漫", "情侣", "爱情故事", "爱情片", "感情", "爱意", "约会"],
-  "浪漫": ["爱情", "情感", "温馨", "甜蜜", "爱意", "爱情片", "情侣", "表白"],
-  
-  "Netflix": ["网飞", "流媒体", "自制剧", "电视剧", "纸牌屋", "怪奇物语", "王冠", "订阅"],
-  "迪士尼": ["米老鼠", "唐老鸭", "公主", "动画", "迪士尼乐园", "皮克斯", "童话", "漫威"],
-  
-  "游戏": ["电子游戏", "游戏机", "主机游戏", "PC游戏", "手游", "网游", "单机", "多人游戏"],
-  "动漫": ["日本动画", "漫画", "二次元", "动画", "动画片", "ACGN", "宅文化", "御宅族"],
-  
-  "日本": ["东京", "京都", "大阪", "日本文化", "日本料理", "樱花", "动漫", "武士道"],
-  "美国": ["纽约", "洛杉矶", "华盛顿", "美国文化", "好莱坞", "自由女神像", "美式"],
-  
-  "教育": ["学习", "知识", "课程", "教学", "学校", "教科书", "老师", "学生"],
-  "技术": ["科技", "工程", "编程", "软件", "硬件", "开发", "技术革新", "IT"],
-  
-  "监狱": ["越狱", "囚犯", "牢房", "服刑", "狱警"],
-  "越狱": ["监狱", "囚犯", "逃狱", "越狱计划", "监狱逃脱"],
-  
-  "肥皂": ["手工皂", "皂"],
-  "手工皂": ["肥皂", "皂"],
-  "皂": ["肥皂", "手工皂"]
-}
diff --git a/Merge/back_jwlll/word2vec_helper.py b/Merge/back_jwlll/word2vec_helper.py
deleted file mode 100644
index ecd1a72..0000000
--- a/Merge/back_jwlll/word2vec_helper.py
+++ /dev/null
@@ -1,279 +0,0 @@
-# word2vec_helper.py
-# Word2Vec模型加载与使用的辅助模块
-
-import os
-import numpy as np
-from gensim.models import KeyedVectors, Word2Vec
-import jieba
-import logging
-import time
-
-# 设置日志
-logging.basicConfig(format='%(asctime)s : %(levelname)s : %(message)s', level=logging.INFO)
-
-class Word2VecHelper:
-    def __init__(self, model_path=None):
-        """
-        初始化Word2Vec辅助类
-        
-        参数:
-            model_path: 预训练模型路径,支持word2vec格式和二进制格式
-                        如果为None,将使用默认路径或尝试下载小型模型
-        """
-        self.model = None
-        
-        # 更改默认模型路径和备用选项
-        if model_path:
-            self.model_path = model_path
-        else:
-            # 首选路径 - 大型腾讯模型
-            primary_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), 
-                                      "models", "chinese_word2vec.bin")
-            
-            # 备用路径 - 小型模型
-            backup_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), 
-                                     "models", "chinese_word2vec_small.bin")
-            
-            if os.path.exists(primary_path):
-                self.model_path = primary_path
-            elif os.path.exists(backup_path):
-                self.model_path = backup_path
-            else:
-                # 如果都不存在,可以尝试自动下载小模型
-                self.model_path = primary_path
-                self._try_download_small_model()
-        
-        self.initialized = False
-        # 缓存查询结果,提高性能
-        self.similarity_cache = {}
-        self.similar_words_cache = {}
-    
-    def _try_download_small_model(self):
-        """尝试下载小型词向量模型作为备用选项"""
-        try:
-            import gensim.downloader as api
-            logging.info("尝试下载小型中文词向量模型...")
-            
-            # 创建模型目录
-            os.makedirs(os.path.dirname(self.model_path), exist_ok=True)
-            
-            # 尝试下载fastText的小型中文模型
-            small_model = api.load("fasttext-wiki-news-subwords-300")
-            small_model.save(self.model_path.replace(".bin", "_small.bin"))
-            logging.info(f"小型模型已下载并保存到 {self.model_path}")
-        except Exception as e:
-            logging.error(f"无法下载备用模型: {e}")
-
-    def load_model(self):
-        """加载Word2Vec模型"""
-        try:
-            start_time = time.time()
-            logging.info(f"开始加载Word2Vec模型: {self.model_path}")
-            
-            # 判断文件扩展名,选择合适的加载方式
-            if self.model_path.endswith('.bin'):
-                # 加载二进制格式的模型
-                self.model = KeyedVectors.load_word2vec_format(self.model_path, binary=True)
-            else:
-                # 加载文本格式的模型或gensim模型
-                self.model = Word2Vec.load(self.model_path).wv
-                
-            self.initialized = True
-            logging.info(f"Word2Vec模型加载完成,耗时 {time.time() - start_time:.2f} 秒")
-            logging.info(f"词向量维度: {self.model.vector_size}")
-            logging.info(f"词汇表大小: {len(self.model.index_to_key)}")
-            return True
-        except Exception as e:
-            logging.error(f"加载Word2Vec模型失败: {e}")
-            self.initialized = False
-            return False
-    
-    def ensure_initialized(self):
-        """确保模型已初始化"""
-        if not self.initialized:
-            return self.load_model()
-        return True
-    
-    def get_similar_words(self, word, topn=10, min_similarity=0.5):
-        """
-        获取与给定词语最相似的词语列表
-        
-        参数:
-            word: 输入词语
-            topn: 返回相似词的数量
-            min_similarity: 最小相似度阈值
-        返回:
-            相似词列表,如果词不存在或模型未加载则返回空列表
-        """
-        if not self.ensure_initialized():
-            return []
-            
-        # 检查缓存
-        cache_key = f"{word}_{topn}_{min_similarity}"
-        if cache_key in self.similar_words_cache:
-            return self.similar_words_cache[cache_key]
-        
-        try:
-            # 如果词不在词汇表中,进行分词处理
-            if word not in self.model.key_to_index:
-                # 对中文词进行分词,然后查找每个子词的相似词
-                word_parts = list(jieba.cut(word))
-                
-                if not word_parts:
-                    return []
-                
-                # 如果存在多个子词,找到存在于模型中的子词
-                valid_parts = [w for w in word_parts if w in self.model.key_to_index]
-                
-                if not valid_parts:
-                    return []
-                
-                # 使用最长的有效子词或第一个有效子词
-                valid_parts.sort(key=len, reverse=True)
-                word = valid_parts[0]
-                
-                # 如果替换后的词仍不在词汇表中,返回空列表
-                if word not in self.model.key_to_index:
-                    return []
-            
-            # 获取相似词
-            similar_words = self.model.most_similar(word, topn=topn*2)  # 多获取一些,后续过滤
-            
-            # 过滤低于阈值的结果,并只返回词语(不返回相似度)
-            filtered_words = [w for w, sim in similar_words if sim >= min_similarity][:topn]
-            
-            # 缓存结果
-            self.similar_words_cache[cache_key] = filtered_words
-            return filtered_words
-            
-        except Exception as e:
-            logging.error(f"获取相似词失败: {e}, 词语: {word}")
-            return []
-    
-    def calculate_similarity(self, word1, word2):
-        """
-        计算两个词的相似度
-        
-        参数:
-            word1, word2: 输入词语
-        返回:
-            相似度分数(0-1),如果任意词不存在则返回0
-        """
-        if not self.ensure_initialized():
-            return 0
-            
-        # 检查缓存
-        cache_key = f"{word1}_{word2}"
-        reverse_key = f"{word2}_{word1}"
-        
-        if cache_key in self.similarity_cache:
-            return self.similarity_cache[cache_key]
-        if reverse_key in self.similarity_cache:
-            return self.similarity_cache[reverse_key]
-        
-        try:
-            # 检查词是否在词汇表中
-            if word1 not in self.model.key_to_index or word2 not in self.model.key_to_index:
-                return 0
-            
-            similarity = self.model.similarity(word1, word2)
-            
-            # 缓存结果
-            self.similarity_cache[cache_key] = similarity
-            return similarity
-            
-        except Exception as e:
-            logging.error(f"计算相似度失败: {e}, 词语: {word1}, {word2}")
-            return 0
-    
-    def expand_query(self, query, topn=5, min_similarity=0.6):
-        """
-        扩展查询词,返回相关词汇
-        
-        参数:
-            query: 查询词
-            topn: 每个词扩展的相似词数量
-            min_similarity: 最小相似度阈值
-        返回:
-            扩展后的词语列表
-        """
-        if not self.ensure_initialized():
-            return [query]
-            
-        expanded_terms = [query]
-        
-        # 对查询进行分词
-        words = list(jieba.cut(query))
-        
-        # 为每个词找相似词
-        for word in words:
-            if len(word) <= 1:  # 忽略单字,减少噪音
-                continue
-                
-            similar_words = self.get_similar_words(word, topn=topn, min_similarity=min_similarity)
-            expanded_terms.extend(similar_words)
-        
-        # 确保唯一性
-        return list(set(expanded_terms))
-
-# 单例模式,全局使用一个模型实例
-_word2vec_helper = None
-
-def get_word2vec_helper(model_path=None):
-    """获取Word2Vec辅助类的全局单例"""
-    global _word2vec_helper
-    if _word2vec_helper is None:
-        _word2vec_helper = Word2VecHelper(model_path)
-        _word2vec_helper.ensure_initialized()
-    return _word2vec_helper
-
-# 便捷函数,方便直接调用
-def get_similar_words(word, topn=10, min_similarity=0.5):
-    """获取相似词的便捷函数"""
-    helper = get_word2vec_helper()
-    return helper.get_similar_words(word, topn, min_similarity)
-
-def calculate_similarity(word1, word2):
-    """计算相似度的便捷函数"""
-    helper = get_word2vec_helper()
-    return helper.calculate_similarity(word1, word2)
-
-def expand_query(query, topn=5, min_similarity=0.6):
-    """扩展查询的便捷函数"""
-    helper = get_word2vec_helper()
-    return helper.expand_query(query, topn, min_similarity)
-
-# 使用示例
-if __name__ == "__main__":
-    # 测试模型加载和词语相似度
-    helper = get_word2vec_helper()
-    
-    # 测试词
-    test_words = ["电影", "功夫", "熊猫", "科幻", "漫威"]
-    
-    for word in test_words:
-        print(f"\n{word} 的相似词:")
-        similar = helper.get_similar_words(word, topn=5)
-        for sim_word in similar:
-            print(f"  - {sim_word}")
-    
-    # 测试相似度计算
-    word_pairs = [
-        ("电影", "电视"),
-        ("功夫", "武术"),
-        ("科幻", "未来"),
-        ("漫威", "超级英雄")
-    ]
-    
-    print("\n词语相似度:")
-    for w1, w2 in word_pairs:
-        sim = helper.calculate_similarity(w1, w2)
-        print(f"  {w1} <-> {w2}: {sim:.4f}")
-    
-    # 测试查询扩展
-    test_queries = ["功夫熊猫", "科幻电影", "漫威英雄"]
-    
-    print("\n查询扩展:")
-    for query in test_queries:
-        expanded = helper.expand_query(query)
-        print(f"  {query} -> {expanded}")
diff --git a/Merge/back_rhj/__pycache__/config.cpython-312.pyc b/Merge/back_rhj/__pycache__/config.cpython-312.pyc
index 52dc95c..00c0bdd 100644
--- a/Merge/back_rhj/__pycache__/config.cpython-312.pyc
+++ b/Merge/back_rhj/__pycache__/config.cpython-312.pyc
Binary files differ
diff --git a/Merge/back_rhj/app/__pycache__/__init__.cpython-312.pyc b/Merge/back_rhj/app/__pycache__/__init__.cpython-312.pyc
index 59d6618..770df5b 100644
--- a/Merge/back_rhj/app/__pycache__/__init__.cpython-312.pyc
+++ b/Merge/back_rhj/app/__pycache__/__init__.cpython-312.pyc
Binary files differ
diff --git a/Merge/back_rhj/app/__pycache__/routes.cpython-312.pyc b/Merge/back_rhj/app/__pycache__/routes.cpython-312.pyc
index 696eaf4..f2ad12b 100644
--- a/Merge/back_rhj/app/__pycache__/routes.cpython-312.pyc
+++ b/Merge/back_rhj/app/__pycache__/routes.cpython-312.pyc
Binary files differ
diff --git a/Merge/back_rhj/app/blueprints/__pycache__/recommend.cpython-312.pyc b/Merge/back_rhj/app/blueprints/__pycache__/recommend.cpython-312.pyc
index fc734ad..75ccdab 100644
--- a/Merge/back_rhj/app/blueprints/__pycache__/recommend.cpython-312.pyc
+++ b/Merge/back_rhj/app/blueprints/__pycache__/recommend.cpython-312.pyc
Binary files differ
diff --git a/Merge/back_rhj/app/blueprints/__pycache__/scheduler.cpython-312.pyc b/Merge/back_rhj/app/blueprints/__pycache__/scheduler.cpython-312.pyc
index 57040f1..ae84b70 100644
--- a/Merge/back_rhj/app/blueprints/__pycache__/scheduler.cpython-312.pyc
+++ b/Merge/back_rhj/app/blueprints/__pycache__/scheduler.cpython-312.pyc
Binary files differ
diff --git a/Merge/back_rhj/app/functions/__pycache__/FAuth.cpython-312.pyc b/Merge/back_rhj/app/functions/__pycache__/FAuth.cpython-312.pyc
index a806a51..6c0297b 100644
--- a/Merge/back_rhj/app/functions/__pycache__/FAuth.cpython-312.pyc
+++ b/Merge/back_rhj/app/functions/__pycache__/FAuth.cpython-312.pyc
Binary files differ
diff --git a/Merge/back_rhj/app/models/__pycache__/__init__.cpython-312.pyc b/Merge/back_rhj/app/models/__pycache__/__init__.cpython-312.pyc
index 13b00b1..8eec580 100644
--- a/Merge/back_rhj/app/models/__pycache__/__init__.cpython-312.pyc
+++ b/Merge/back_rhj/app/models/__pycache__/__init__.cpython-312.pyc
Binary files differ
diff --git a/Merge/back_rhj/app/models/__pycache__/email_verification.cpython-312.pyc b/Merge/back_rhj/app/models/__pycache__/email_verification.cpython-312.pyc
index 7a02a9f..c9ad75d 100644
--- a/Merge/back_rhj/app/models/__pycache__/email_verification.cpython-312.pyc
+++ b/Merge/back_rhj/app/models/__pycache__/email_verification.cpython-312.pyc
Binary files differ
diff --git a/Merge/back_rhj/app/models/__pycache__/users.cpython-312.pyc b/Merge/back_rhj/app/models/__pycache__/users.cpython-312.pyc
index 1cd3627..1af05fe 100644
--- a/Merge/back_rhj/app/models/__pycache__/users.cpython-312.pyc
+++ b/Merge/back_rhj/app/models/__pycache__/users.cpython-312.pyc
Binary files differ
diff --git a/Merge/back_rhj/app/models/recall/__pycache__/__init__.cpython-312.pyc b/Merge/back_rhj/app/models/recall/__pycache__/__init__.cpython-312.pyc
index ec1bb4b..88c8123 100644
--- a/Merge/back_rhj/app/models/recall/__pycache__/__init__.cpython-312.pyc
+++ b/Merge/back_rhj/app/models/recall/__pycache__/__init__.cpython-312.pyc
Binary files differ
diff --git a/Merge/back_rhj/app/models/recall/__pycache__/ad_recall.cpython-312.pyc b/Merge/back_rhj/app/models/recall/__pycache__/ad_recall.cpython-312.pyc
index 372104d..7d0748e 100644
--- a/Merge/back_rhj/app/models/recall/__pycache__/ad_recall.cpython-312.pyc
+++ b/Merge/back_rhj/app/models/recall/__pycache__/ad_recall.cpython-312.pyc
Binary files differ
diff --git a/Merge/back_rhj/app/models/recall/__pycache__/hot_recall.cpython-312.pyc b/Merge/back_rhj/app/models/recall/__pycache__/hot_recall.cpython-312.pyc
index de7e3f9..3cfdd43 100644
--- a/Merge/back_rhj/app/models/recall/__pycache__/hot_recall.cpython-312.pyc
+++ b/Merge/back_rhj/app/models/recall/__pycache__/hot_recall.cpython-312.pyc
Binary files differ
diff --git a/Merge/back_rhj/app/models/recall/__pycache__/multi_recall_manager.cpython-312.pyc b/Merge/back_rhj/app/models/recall/__pycache__/multi_recall_manager.cpython-312.pyc
index 0b05f7e..9e1d7c8 100644
--- a/Merge/back_rhj/app/models/recall/__pycache__/multi_recall_manager.cpython-312.pyc
+++ b/Merge/back_rhj/app/models/recall/__pycache__/multi_recall_manager.cpython-312.pyc
Binary files differ
diff --git a/Merge/back_rhj/app/models/recall/__pycache__/swing_recall.cpython-312.pyc b/Merge/back_rhj/app/models/recall/__pycache__/swing_recall.cpython-312.pyc
index 87bc373..24c3ddb 100644
--- a/Merge/back_rhj/app/models/recall/__pycache__/swing_recall.cpython-312.pyc
+++ b/Merge/back_rhj/app/models/recall/__pycache__/swing_recall.cpython-312.pyc
Binary files differ
diff --git a/Merge/back_rhj/app/models/recall/__pycache__/usercf_recall.cpython-312.pyc b/Merge/back_rhj/app/models/recall/__pycache__/usercf_recall.cpython-312.pyc
index e5dc324..e212bf5 100644
--- a/Merge/back_rhj/app/models/recall/__pycache__/usercf_recall.cpython-312.pyc
+++ b/Merge/back_rhj/app/models/recall/__pycache__/usercf_recall.cpython-312.pyc
Binary files differ
diff --git a/Merge/back_rhj/app/models/recommend/__pycache__/LightGCN.cpython-312.pyc b/Merge/back_rhj/app/models/recommend/__pycache__/LightGCN.cpython-312.pyc
index 48bb03f..f7079b8 100644
--- a/Merge/back_rhj/app/models/recommend/__pycache__/LightGCN.cpython-312.pyc
+++ b/Merge/back_rhj/app/models/recommend/__pycache__/LightGCN.cpython-312.pyc
Binary files differ
diff --git a/Merge/back_rhj/app/models/recommend/__pycache__/base_model.cpython-312.pyc b/Merge/back_rhj/app/models/recommend/__pycache__/base_model.cpython-312.pyc
index 204d2a7..19bf281 100644
--- a/Merge/back_rhj/app/models/recommend/__pycache__/base_model.cpython-312.pyc
+++ b/Merge/back_rhj/app/models/recommend/__pycache__/base_model.cpython-312.pyc
Binary files differ
diff --git a/Merge/back_rhj/app/models/recommend/__pycache__/operators.cpython-312.pyc b/Merge/back_rhj/app/models/recommend/__pycache__/operators.cpython-312.pyc
index 4e24e5b..28de5cd 100644
--- a/Merge/back_rhj/app/models/recommend/__pycache__/operators.cpython-312.pyc
+++ b/Merge/back_rhj/app/models/recommend/__pycache__/operators.cpython-312.pyc
Binary files differ
diff --git a/Merge/back_rhj/app/services/__pycache__/lightgcn_scorer.cpython-312.pyc b/Merge/back_rhj/app/services/__pycache__/lightgcn_scorer.cpython-312.pyc
index bd899a9..a8d871a 100644
--- a/Merge/back_rhj/app/services/__pycache__/lightgcn_scorer.cpython-312.pyc
+++ b/Merge/back_rhj/app/services/__pycache__/lightgcn_scorer.cpython-312.pyc
Binary files differ
diff --git a/Merge/back_rhj/app/services/__pycache__/recommendation_service.cpython-312.pyc b/Merge/back_rhj/app/services/__pycache__/recommendation_service.cpython-312.pyc
index 0446ed2..fd70a42 100644
--- a/Merge/back_rhj/app/services/__pycache__/recommendation_service.cpython-312.pyc
+++ b/Merge/back_rhj/app/services/__pycache__/recommendation_service.cpython-312.pyc
Binary files differ
diff --git a/Merge/back_rhj/app/utils/__pycache__/data_loader.cpython-312.pyc b/Merge/back_rhj/app/utils/__pycache__/data_loader.cpython-312.pyc
index 70405e3..8157bf8 100644
--- a/Merge/back_rhj/app/utils/__pycache__/data_loader.cpython-312.pyc
+++ b/Merge/back_rhj/app/utils/__pycache__/data_loader.cpython-312.pyc
Binary files differ
diff --git a/Merge/back_rhj/app/utils/__pycache__/graph_build.cpython-312.pyc b/Merge/back_rhj/app/utils/__pycache__/graph_build.cpython-312.pyc
index 6fa5bc6..e1676da 100644
--- a/Merge/back_rhj/app/utils/__pycache__/graph_build.cpython-312.pyc
+++ b/Merge/back_rhj/app/utils/__pycache__/graph_build.cpython-312.pyc
Binary files differ
diff --git a/Merge/back_rhj/app/utils/__pycache__/parse_args.cpython-312.pyc b/Merge/back_rhj/app/utils/__pycache__/parse_args.cpython-312.pyc
index 9295682..ba17fcf 100644
--- a/Merge/back_rhj/app/utils/__pycache__/parse_args.cpython-312.pyc
+++ b/Merge/back_rhj/app/utils/__pycache__/parse_args.cpython-312.pyc
Binary files differ
diff --git a/Merge/back_rhj/app/utils/__pycache__/scheduler_manager.cpython-312.pyc b/Merge/back_rhj/app/utils/__pycache__/scheduler_manager.cpython-312.pyc
index 89f68ad..6ed8964 100644
--- a/Merge/back_rhj/app/utils/__pycache__/scheduler_manager.cpython-312.pyc
+++ b/Merge/back_rhj/app/utils/__pycache__/scheduler_manager.cpython-312.pyc
Binary files differ
diff --git a/Merge/back_rhj/requirements.txt b/Merge/back_rhj/requirements.txt
deleted file mode 100644
index 9886994..0000000
--- a/Merge/back_rhj/requirements.txt
+++ /dev/null
@@ -1,10 +0,0 @@
-Flask==2.3.3
-Flask-CORS==4.0.0
-python-dotenv==1.0.0
-SQLAlchemy==2.0.23
-PyMySQL==1.1.0
-torch==2.1.0
-numpy==1.24.3
-PyJWT==2.8.0
-Flask-Mail==0.9.1
-APScheduler==3.10.4
diff --git a/Merge/back_wzy/__pycache__/config.cpython-312.pyc b/Merge/back_wzy/__pycache__/config.cpython-312.pyc
index d25ef2e..4e1a3be 100644
--- a/Merge/back_wzy/__pycache__/config.cpython-312.pyc
+++ b/Merge/back_wzy/__pycache__/config.cpython-312.pyc
Binary files differ
diff --git a/Merge/back_wzy/__pycache__/extensions.cpython-312.pyc b/Merge/back_wzy/__pycache__/extensions.cpython-312.pyc
index cda341f..27ba8c2 100644
--- a/Merge/back_wzy/__pycache__/extensions.cpython-312.pyc
+++ b/Merge/back_wzy/__pycache__/extensions.cpython-312.pyc
Binary files differ
diff --git a/Merge/back_wzy/models/__pycache__/__init__.cpython-312.pyc b/Merge/back_wzy/models/__pycache__/__init__.cpython-312.pyc
index b97c14e..fe53b2a 100644
--- a/Merge/back_wzy/models/__pycache__/__init__.cpython-312.pyc
+++ b/Merge/back_wzy/models/__pycache__/__init__.cpython-312.pyc
Binary files differ
diff --git a/Merge/back_wzy/models/__pycache__/behavior.cpython-312.pyc b/Merge/back_wzy/models/__pycache__/behavior.cpython-312.pyc
index 3fed625..71f3757 100644
--- a/Merge/back_wzy/models/__pycache__/behavior.cpython-312.pyc
+++ b/Merge/back_wzy/models/__pycache__/behavior.cpython-312.pyc
Binary files differ
diff --git a/Merge/back_wzy/models/__pycache__/comment.cpython-312.pyc b/Merge/back_wzy/models/__pycache__/comment.cpython-312.pyc
index cc7439e..393c6d3 100644
--- a/Merge/back_wzy/models/__pycache__/comment.cpython-312.pyc
+++ b/Merge/back_wzy/models/__pycache__/comment.cpython-312.pyc
Binary files differ
diff --git a/Merge/back_wzy/models/__pycache__/post.cpython-312.pyc b/Merge/back_wzy/models/__pycache__/post.cpython-312.pyc
index c121706..1d64737 100644
--- a/Merge/back_wzy/models/__pycache__/post.cpython-312.pyc
+++ b/Merge/back_wzy/models/__pycache__/post.cpython-312.pyc
Binary files differ
diff --git a/Merge/back_wzy/models/__pycache__/tag.cpython-312.pyc b/Merge/back_wzy/models/__pycache__/tag.cpython-312.pyc
index cc339ff..d76c0e0 100644
--- a/Merge/back_wzy/models/__pycache__/tag.cpython-312.pyc
+++ b/Merge/back_wzy/models/__pycache__/tag.cpython-312.pyc
Binary files differ
diff --git a/Merge/back_wzy/models/__pycache__/topic.cpython-312.pyc b/Merge/back_wzy/models/__pycache__/topic.cpython-312.pyc
index 0cd3f35..a779595 100644
--- a/Merge/back_wzy/models/__pycache__/topic.cpython-312.pyc
+++ b/Merge/back_wzy/models/__pycache__/topic.cpython-312.pyc
Binary files differ
diff --git a/Merge/back_wzy/models/__pycache__/user.cpython-312.pyc b/Merge/back_wzy/models/__pycache__/user.cpython-312.pyc
index 18cbff6..e3841c7 100644
--- a/Merge/back_wzy/models/__pycache__/user.cpython-312.pyc
+++ b/Merge/back_wzy/models/__pycache__/user.cpython-312.pyc
Binary files differ
diff --git a/Merge/back_wzy/routes/__pycache__/__init__.cpython-312.pyc b/Merge/back_wzy/routes/__pycache__/__init__.cpython-312.pyc
index 3c51245..acde7ed 100644
--- a/Merge/back_wzy/routes/__pycache__/__init__.cpython-312.pyc
+++ b/Merge/back_wzy/routes/__pycache__/__init__.cpython-312.pyc
Binary files differ
diff --git a/Merge/back_wzy/routes/__pycache__/comments.cpython-312.pyc b/Merge/back_wzy/routes/__pycache__/comments.cpython-312.pyc
index d8d9a10..4bd83ee 100644
--- a/Merge/back_wzy/routes/__pycache__/comments.cpython-312.pyc
+++ b/Merge/back_wzy/routes/__pycache__/comments.cpython-312.pyc
Binary files differ
diff --git a/Merge/back_wzy/routes/__pycache__/posts.cpython-312.pyc b/Merge/back_wzy/routes/__pycache__/posts.cpython-312.pyc
index 1787ef1..a957747 100644
--- a/Merge/back_wzy/routes/__pycache__/posts.cpython-312.pyc
+++ b/Merge/back_wzy/routes/__pycache__/posts.cpython-312.pyc
Binary files differ
diff --git a/Merge/front/src/api/search_jwlll.js b/Merge/front/src/api/search_jwlll.js
deleted file mode 100644
index 5ab7eb1..0000000
--- a/Merge/front/src/api/search_jwlll.js
+++ /dev/null
@@ -1,97 +0,0 @@
-// 搜索推荐算法相关的API接口
-// 对应 JWLLL 后端服务
-
-const BASE_URL = 'http://127.0.0.1:5000'
-
-// 通用请求函数
-const request = async (url, options = {}) => {
-  try {
-    const response = await fetch(url, {
-      headers: {
-        'Content-Type': 'application/json',
-        ...options.headers
-      },
-      ...options
-    })
-    return await response.json()
-  } catch (error) {
-    console.error('API请求错误:', error)
-    throw error
-  }
-}
-
-// 搜索API
-export const searchAPI = {
-  // 搜索内容
-  search: async (keyword, category = undefined) => {
-    return await request(`${BASE_URL}/search`, {
-      method: 'POST',
-      body: JSON.stringify({ keyword, category })
-    })
-  },
-
-  // 获取用户标签
-  getUserTags: async (userId) => {
-    return await request(`${BASE_URL}/user_tags?user_id=${userId}`)
-  },
-
-  // 标签推荐
-  recommendByTags: async (userId, tags) => {
-    return await request(`${BASE_URL}/recommend_tags`, {
-      method: 'POST',
-      body: JSON.stringify({ user_id: userId, tags })
-    })
-  },
-
-  // 协同过滤推荐
-  userBasedRecommend: async (userId, topN = 20) => {
-    return await request(`${BASE_URL}/user_based_recommend`, {
-      method: 'POST',
-      body: JSON.stringify({ user_id: userId, top_n: topN })
-    })
-  },
-
-  // 获取帖子详情
-  getPostDetail: async (postId) => {
-    return await request(`${BASE_URL}/post/${postId}`)
-  },
-
-  // 点赞帖子
-  likePost: async (postId, userId) => {
-    return await request(`${BASE_URL}/like`, {
-      method: 'POST',
-      body: JSON.stringify({ post_id: postId, user_id: userId })
-    })
-  },
-
-  // 取消点赞
-  unlikePost: async (postId, userId) => {
-    return await request(`${BASE_URL}/unlike`, {
-      method: 'POST',
-      body: JSON.stringify({ post_id: postId, user_id: userId })
-    })
-  },
-
-  // 添加评论
-  addComment: async (postId, userId, content) => {
-    return await request(`${BASE_URL}/comment`, {
-      method: 'POST',
-      body: JSON.stringify({ post_id: postId, user_id: userId, content })
-    })
-  },
-
-  // 获取评论
-  getComments: async (postId) => {
-    return await request(`${BASE_URL}/comments/${postId}`)
-  },
-
-  // 上传帖子
-  uploadPost: async (postData) => {
-    return await request(`${BASE_URL}/upload`, {
-      method: 'POST',
-      body: JSON.stringify(postData)
-    })
-  }
-}
-
-export default searchAPI
diff --git a/Merge/front/src/components/CreatePost.jsx b/Merge/front/src/components/CreatePost.jsx
index c11e247..1d2f306 100644
--- a/Merge/front/src/components/CreatePost.jsx
+++ b/Merge/front/src/components/CreatePost.jsx
@@ -13,8 +13,10 @@
   const navigate = useNavigate()
   const { postId } = useParams()
   const isEdit = Boolean(postId)
+
   // 步骤:新帖先上传,编辑则直接到 detail
   const [step, setStep] = useState(isEdit ? 'detail' : 'upload')
+  const [files, setFiles] = useState([])
   const [mediaUrls, setMediaUrls] = useState([])
 
   // 表单字段
@@ -51,8 +53,10 @@
       .catch(err => setError(err.message))
       .finally(() => setLoading(false))
   }, [isEdit, postId])
+
   // 上传回调
   const handleUploadComplete = async uploadedFiles => {
+    setFiles(uploadedFiles)
     // TODO: 真正上传到服务器后替换为服务端 URL
     const urls = await Promise.all(
       uploadedFiles.map(f => URL.createObjectURL(f))
diff --git a/Merge/front/src/components/HomeFeed.jsx b/Merge/front/src/components/HomeFeed.jsx
index e32a2eb..c681858 100644
--- a/Merge/front/src/components/HomeFeed.jsx
+++ b/Merge/front/src/components/HomeFeed.jsx
@@ -1,10 +1,9 @@
 // src/components/HomeFeed.jsx
 
-import React, { useState, useEffect, useCallback } from 'react'
+import React, { useState, useEffect } from 'react'
 import { useNavigate } from 'react-router-dom'
 import { ThumbsUp } from 'lucide-react'
 import { fetchPosts, fetchPost } from '../api/posts_wzy'
-import { searchAPI } from '../api/search_jwlll'
 import '../style/HomeFeed.css'
 
 const categories = [
@@ -12,120 +11,15 @@
   '职场','情感','家居','游戏','旅行','健身'
 ]
 
-const recommendModes = [
-  { label: '标签推荐', value: 'tag' },
-  { label: '协同过滤推荐', value: 'cf' }
-]
-
-const DEFAULT_USER_ID = '3' // 确保数据库有此用户
-const DEFAULT_TAGS = ['美食','影视','穿搭'] // 可根据实际数据库调整
-
 export default function HomeFeed() {
   const navigate = useNavigate()
   const [activeCat, setActiveCat] = useState('推荐')
   const [items, setItems]         = useState([])
   const [loading, setLoading]     = useState(true)
   const [error, setError]         = useState(null)
-    // JWLLL 搜索推荐相关状态
-  const [search, setSearch] = useState('')
-  const [recMode, setRecMode] = useState('tag')
-  const [recCFNum, setRecCFNum] = useState(20)
-  const [useSearchRecommend, setUseSearchRecommend] = useState(false) // 是否使用搜索推荐模式  // JWLLL 搜索推荐功能函数
-  
-  // JWLLL搜索推荐内容
-  const fetchSearchContent = useCallback(async (keyword = '') => {
-    setLoading(true)
-    setError(null)
-    try {
-      const data = await searchAPI.search(keyword || activeCat, activeCat === '推荐' ? undefined : activeCat)
-      const formattedItems = (data.results || []).map(item => ({
-        id: item.id,
-        title: item.title,
-        author: item.author || '佚名',
-        avatar: `https://i.pravatar.cc/40?img=${item.id}`,
-        img: item.img || '', 
-        likes: item.heat || 0,
-        content: item.content
-      }))
-      setItems(formattedItems)
-    } catch (e) {
-      console.error('搜索失败:', e)
-      setError('搜索失败')
-      setItems([])
-    }
-    setLoading(false)
-  }, [activeCat])
-
-  // 标签推荐
-  const fetchTagRecommend = useCallback(async (tags) => {
-    setLoading(true)
-    setError(null)
-    try {
-      const data = await searchAPI.recommendByTags(DEFAULT_USER_ID, tags)
-      const formattedItems = (data.recommendations || []).map(item => ({
-        id: item.id,
-        title: item.title,
-        author: item.author || '佚名',
-        avatar: `https://i.pravatar.cc/40?img=${item.id}`,
-        img: item.img || '', 
-        likes: item.heat || 0,
-        content: item.content
-      }))
-      setItems(formattedItems)
-    } catch (e) {
-      console.error('标签推荐失败:', e)
-      setError('标签推荐失败')
-      setItems([])
-    }
-    setLoading(false)
-  }, [])
-
-  // 协同过滤推荐
-  const fetchCFRecommend = useCallback(async (topN = recCFNum) => {
-    setLoading(true)
-    setError(null)
-    try {
-      const data = await searchAPI.userBasedRecommend(DEFAULT_USER_ID, topN)
-      const formattedItems = (data.recommendations || []).map(item => ({
-        id: item.id,
-        title: item.title,
-        author: item.author || '佚名',
-        avatar: `https://i.pravatar.cc/40?img=${item.id}`,
-        img: item.img || '', 
-        likes: item.heat || 0,
-        content: item.content
-      }))
-      setItems(formattedItems)
-    } catch (e) {
-      console.error('协同过滤推荐失败:', e)
-      setError('协同过滤推荐失败')
-      setItems([])
-    }
-    setLoading(false)
-  }, [recCFNum])
-
-  // 获取用户兴趣标签后再推荐
-  const fetchUserTagsAndRecommend = useCallback(async () => {
-    setLoading(true)
-    setError(null)
-    let tags = []
-    try {
-      const data = await searchAPI.getUserTags(DEFAULT_USER_ID)
-      tags = Array.isArray(data.tags) && data.tags.length > 0 ? data.tags : DEFAULT_TAGS
-    } catch {
-      tags = DEFAULT_TAGS
-    }
-    if (recMode === 'tag') {
-      await fetchTagRecommend(tags)
-    } else {
-      await fetchCFRecommend()
-    }
-    setLoading(false)
-  }, [recMode, fetchTagRecommend, fetchCFRecommend])
 
   useEffect(() => {
-    // 原始数据加载函数
-    const loadPosts = async () => {
+    async function loadPosts() {
       try {
         const list = await fetchPosts()  // [{id, title, heat, created_at}, …]
         // 为了拿到 media_urls 和 user_id,这里再拉详情
@@ -149,149 +43,25 @@
         setLoading(false)
       }
     }
+    loadPosts()
+  }, [])
 
-    // 根据模式选择加载方式
-    if (activeCat === '推荐' && useSearchRecommend) {
-      fetchUserTagsAndRecommend()
-    } else {
-      loadPosts()
-    }
-  }, [activeCat, useSearchRecommend, fetchUserTagsAndRecommend])
-  // 切换推荐模式时的额外处理
-  useEffect(() => {
-    if (activeCat === '推荐' && useSearchRecommend) {
-      fetchUserTagsAndRecommend()
-    }
-    // eslint-disable-next-line
-  }, [recMode, fetchUserTagsAndRecommend])
-
-  // 根据模式选择不同的加载方式
-  const handleSearch = e => {
-    e.preventDefault()
-    if (useSearchRecommend) {
-      fetchSearchContent(search)
-    } else {
-      // 切换到搜索推荐模式
-      setUseSearchRecommend(true)
-      fetchSearchContent(search)
-    }
-  }
-
-  const handlePostClick = (postId) => {
-    navigate(`/post/${postId}`)
-  }
   return (
     <div className="home-feed">
-      {/* 数据源切换 */}
-      <div style={{marginBottom:12, display:'flex', alignItems:'center', gap:16}}>
-        <span>数据源:</span>
-        <div style={{display:'flex', gap:8}}>
-          <button
-            className={!useSearchRecommend ? 'rec-btn styled active' : 'rec-btn styled'}
-            onClick={() => {setUseSearchRecommend(false); setActiveCat('推荐')}}
-            type="button"
-            style={{
-              borderRadius: 20,
-              padding: '4px 18px',
-              border: !useSearchRecommend ? '2px solid #e84c4a' : '1px solid #ccc',
-              background: !useSearchRecommend ? '#fff0f0' : '#fff',
-              color: !useSearchRecommend ? '#e84c4a' : '#333',
-              fontWeight: !useSearchRecommend ? 600 : 400,
-              cursor: 'pointer',
-              transition: 'all 0.2s',
-              outline: 'none',
-            }}
-          >原始数据</button>
-          <button
-            className={useSearchRecommend ? 'rec-btn styled active' : 'rec-btn styled'}
-            onClick={() => {setUseSearchRecommend(true); setActiveCat('推荐')}}
-            type="button"
-            style={{
-              borderRadius: 20,
-              padding: '4px 18px',
-              border: useSearchRecommend ? '2px solid #e84c4a' : '1px solid #ccc',
-              background: useSearchRecommend ? '#fff0f0' : '#fff',
-              color: useSearchRecommend ? '#e84c4a' : '#333',
-              fontWeight: useSearchRecommend ? 600 : 400,
-              cursor: 'pointer',
-              transition: 'all 0.2s',
-              outline: 'none',
-            }}
-          >智能推荐</button>
-        </div>
-      </div>
-
-      {/* 推荐模式切换,仅在推荐页显示且使用搜索推荐时 */}
-      {activeCat === '推荐' && useSearchRecommend && (
-        <div style={{marginBottom:12, display:'flex', alignItems:'center', gap:16}}>
-          <span style={{marginRight:8}}>推荐模式:</span>
-          <div style={{display:'flex', gap:8}}>
-            {recommendModes.map(m => (
-              <button
-                key={m.value}
-                className={recMode===m.value? 'rec-btn styled active':'rec-btn styled'}
-                onClick={() => setRecMode(m.value)}
-                type="button"
-                style={{
-                  borderRadius: 20,
-                  padding: '4px 18px',
-                  border: recMode===m.value ? '2px solid #e84c4a' : '1px solid #ccc',
-                  background: recMode===m.value ? '#fff0f0' : '#fff',
-                  color: recMode===m.value ? '#e84c4a' : '#333',
-                  fontWeight: recMode===m.value ? 600 : 400,
-                  cursor: 'pointer',
-                  transition: 'all 0.2s',
-                  outline: 'none',
-                }}
-              >{m.label}</button>
-            ))}
-          </div>
-          {/* 协同过滤推荐数量选择 */}
-          {recMode === 'cf' && (
-            <div style={{display:'flex',alignItems:'center',gap:4}}>
-              <span>推荐数量:</span>
-              <select value={recCFNum} onChange={e => { setRecCFNum(Number(e.target.value)); fetchCFRecommend(Number(e.target.value)) }} style={{padding:'2px 8px',borderRadius:6,border:'1px solid #ccc'}}>
-                {[10, 20, 30, 50].map(n => <option key={n} value={n}>{n}</option>)}
-              </select>
-            </div>
-          )}
-        </div>
-      )}
-
-      {/* 搜索栏 */}
-      <form className="feed-search" onSubmit={handleSearch} style={{marginBottom:16, display:'flex', gap:8, alignItems:'center'}}>
-        <input
-          type="text"
-          className="search-input"
-          placeholder="搜索内容/标题/标签"
-          value={search}
-          onChange={e => setSearch(e.target.value)}
-        />
-        <button type="submit" className="search-btn">搜索</button>
-      </form>
-
       {/* 顶部分类 */}
       <nav className="feed-tabs">
         {categories.map(cat => (
           <button
             key={cat}
             className={cat === activeCat ? 'tab active' : 'tab'}
-            onClick={() => { 
-              setActiveCat(cat); 
-              setSearch('');
-              if (useSearchRecommend) {
-                if (cat === '推荐') {
-                  fetchUserTagsAndRecommend()
-                } else {
-                  fetchSearchContent()
-                }
-              }
-            }}
+            onClick={() => setActiveCat(cat)}
           >
             {cat}
           </button>
         ))}
-      </nav>      {/* 状态提示 */}
+      </nav>
+
+      {/* 状态提示 */}
       {loading ? (
         <div className="loading">加载中…</div>
       ) : error ? (
@@ -299,27 +69,22 @@
       ) : (
         /* 瀑布流卡片区 */
         <div className="feed-grid">
-          {items.length === 0 ? (
-            <div style={{padding:32, color:'#aaa'}}>暂无内容</div>
-          ) : (
-            items.map(item => (
-              <div key={item.id} className="feed-card" onClick={() => handlePostClick(item.id)}>
-                {item.img && <img className="card-img" src={item.img} alt={item.title} />}
-                <h3 className="card-title">{item.title}</h3>
-                {item.content && <div className="card-content">{item.content.slice(0, 60) || ''}</div>}
-                <div className="card-footer">
-                  <div className="card-author">
-                    <img className="avatar" src={item.avatar} alt={item.author} />
-                    <span className="username">{item.author}</span>
-                  </div>
-                  <div className="card-likes">
-                    <ThumbsUp size={16} />
-                    <span className="likes-count">{item.likes}</span>
-                  </div>
+          {items.map(item => (
+            <div key={item.id} className="feed-card">
+              <img className="card-img" src={item.img} alt={item.title} />
+              <h3 className="card-title">{item.title}</h3>
+              <div className="card-footer">
+                <div className="card-author">
+                  <img className="avatar" src={item.avatar} alt={item.author} />
+                  <span className="username">{item.author}</span>
+                </div>
+                <div className="card-likes">
+                  <ThumbsUp size={16} />
+                  <span className="likes-count">{item.likes}</span>
                 </div>
               </div>
-            ))
-          )}
+            </div>
+          ))}
         </div>
       )}
     </div>
diff --git a/Merge/front/src/components/LogsDashboard.js b/Merge/front/src/components/LogsDashboard.js
index 6ab4746..22047e2 100644
--- a/Merge/front/src/components/LogsDashboard.js
+++ b/Merge/front/src/components/LogsDashboard.js
@@ -3,9 +3,7 @@
 import '../style/Admin.css';
 
 function LogsDashboard() {
-  // eslint-disable-next-line no-unused-vars
   const [logs, setLogs] = useState([]);
-  // eslint-disable-next-line no-unused-vars
   const [stats, setStats] = useState({});
 
   useEffect(() => {
diff --git a/Merge/front/src/components/PostDetailJWLLL.jsx b/Merge/front/src/components/PostDetailJWLLL.jsx
deleted file mode 100644
index 0dc7289..0000000
--- a/Merge/front/src/components/PostDetailJWLLL.jsx
+++ /dev/null
@@ -1,322 +0,0 @@
-import React, { useState, useEffect } from 'react'
-import { useParams, useNavigate } from 'react-router-dom'
-import { ArrowLeft, ThumbsUp, MessageCircle, Share2, BookmarkPlus, Heart, Eye } from 'lucide-react'
-import { searchAPI } from '../api/search_jwlll'
-import '../style/PostDetail.css'
-
-export default function PostDetail() {
-  const { id } = useParams()
-  const navigate = useNavigate()
-  const [post, setPost] = useState(null)
-  const [loading, setLoading] = useState(true)
-  const [error, setError] = useState(null)
-  const [liked, setLiked] = useState(false)
-  const [bookmarked, setBookmarked] = useState(false)
-  const [likeCount, setLikeCount] = useState(0)
-  const [comments, setComments] = useState([])
-  const [newComment, setNewComment] = useState('')
-  const [showComments, setShowComments] = useState(false)
-
-  const DEFAULT_USER_ID = '3' // 默认用户ID
-
-  useEffect(() => {
-    fetchPostDetail()
-    fetchComments()
-  }, [id])
-
-  const fetchPostDetail = async () => {
-    setLoading(true)
-    setError(null)
-    try {
-      const data = await searchAPI.getPostDetail(id)
-      setPost(data)
-      setLikeCount(data.heat || 0)
-    } catch (error) {
-      console.error('获取帖子详情失败:', error)
-      setError('帖子不存在或已被删除')
-    } finally {
-      setLoading(false)
-    }
-  }
-
-  const fetchComments = async () => {
-    try {
-      const data = await searchAPI.getComments(id)
-      setComments(data.comments || [])
-    } catch (error) {
-      console.error('获取评论失败:', error)
-    }
-  }
-
-  const handleBack = () => {
-    navigate(-1)
-  }
-
-  const handleLike = async () => {
-    try {
-      const newLiked = !liked
-      if (newLiked) {
-        await searchAPI.likePost(id, DEFAULT_USER_ID)
-      } else {
-        await searchAPI.unlikePost(id, DEFAULT_USER_ID)
-      }
-      setLiked(newLiked)
-      setLikeCount(prev => newLiked ? prev + 1 : prev - 1)
-    } catch (error) {
-      console.error('点赞失败:', error)
-      // 回滚状态
-      setLiked(!liked)
-      setLikeCount(prev => liked ? prev + 1 : prev - 1)
-    }
-  }
-
-  const handleBookmark = () => {
-    setBookmarked(!bookmarked)
-    // 实际项目中这里应该调用后端API保存收藏状态
-  }
-
-  const handleShare = () => {
-    // 分享功能
-    if (navigator.share) {
-      navigator.share({
-        title: post?.title,
-        text: post?.content,
-        url: window.location.href,
-      })
-    } else {
-      // 复制链接到剪贴板
-      navigator.clipboard.writeText(window.location.href)
-      alert('链接已复制到剪贴板')
-    }
-  }
-
-  const handleAddComment = async (e) => {
-    e.preventDefault()
-    if (!newComment.trim()) return
-
-    try {
-      await searchAPI.addComment(id, DEFAULT_USER_ID, newComment)
-      setNewComment('')
-      fetchComments() // 刷新评论列表
-    } catch (error) {
-      console.error('添加评论失败:', error)
-      alert('评论失败,请重试')
-    }
-  }
-
-  if (loading) {
-    return (
-      <div className="post-detail">
-        <div className="loading-container">
-          <div className="loading-spinner"></div>
-          <p>加载中...</p>
-        </div>
-      </div>
-    )
-  }
-
-  if (error) {
-    return (
-      <div className="post-detail">
-        <div className="error-container">
-          <h2>😔 出错了</h2>
-          <p>{error}</p>
-          <button onClick={handleBack} className="back-btn">
-            <ArrowLeft size={20} />
-            返回
-          </button>
-        </div>
-      </div>
-    )
-  }
-
-  if (!post) {
-    return (
-      <div className="post-detail">
-        <div className="error-container">
-          <h2>😔 帖子不存在</h2>
-          <p>该帖子可能已被删除或不存在</p>
-          <button onClick={handleBack} className="back-btn">
-            <ArrowLeft size={20} />
-            返回
-          </button>
-        </div>
-      </div>
-    )
-  }
-
-  return (
-    <div className="post-detail">
-      {/* 顶部导航栏 */}
-      <header className="post-header">
-        <button onClick={handleBack} className="back-btn">
-          <ArrowLeft size={20} />
-          返回
-        </button>
-        <div className="header-actions">
-          <button onClick={handleShare} className="action-btn">
-            <Share2 size={20} />
-          </button>
-          <button 
-            onClick={handleBookmark} 
-            className={`action-btn ${bookmarked ? 'active' : ''}`}
-          >
-            <BookmarkPlus size={20} />
-          </button>
-        </div>
-      </header>
-
-      {/* 主要内容区 */}
-      <main className="post-content">
-        {/* 帖子标题 */}
-        <h1 className="post-title">{post.title}</h1>
-
-        {/* 作者信息和元数据 */}
-        <div className="post-meta">
-          <div className="author-info">
-            <div className="avatar">
-              {post.author ? post.author.charAt(0).toUpperCase() : 'U'}
-            </div>
-            <div className="author-details">
-              <span className="author-name">{post.author || '匿名用户'}</span>
-              <span className="post-date">
-                {post.create_time ? new Date(post.create_time).toLocaleDateString('zh-CN') : '未知时间'}
-              </span>
-            </div>
-          </div>
-          <div className="post-stats">
-            <span className="stat-item">
-              <Eye size={16} />
-              {post.views || 0}
-            </span>
-            <span className="stat-item">
-              <Heart size={16} />
-              {likeCount}
-            </span>
-          </div>
-        </div>
-
-        {/* 标签 */}
-        {post.tags && post.tags.length > 0 && (
-          <div className="post-tags">
-            {post.tags.map((tag, index) => (
-              <span key={index} className="tag">{tag}</span>
-            ))}
-          </div>
-        )}
-
-        {/* 帖子正文 */}
-        <div className="post-body">
-          <p>{post.content}</p>
-        </div>
-
-        {/* 类别信息 */}
-        {(post.category || post.type) && (
-          <div className="post-category">
-            {post.category && (
-              <>
-                <span className="category-label">分类:</span>
-                <span className="category-name">{post.category}</span>
-              </>
-            )}
-            {post.type && (
-              <>
-                <span className="category-label" style={{marginLeft: '1em'}}>类型:</span>
-                <span className="category-name">{post.type}</span>
-              </>
-            )}
-          </div>
-        )}
-
-        {/* 评论区 */}
-        <div className="comments-section">
-          <div className="comments-header">
-            <button 
-              onClick={() => setShowComments(!showComments)}
-              className="comments-toggle"
-            >
-              <MessageCircle size={20} />
-              评论 ({comments.length})
-            </button>
-          </div>
-
-          {showComments && (
-            <div className="comments-content">
-              {/* 添加评论 */}
-              <form onSubmit={handleAddComment} className="comment-form">
-                <textarea
-                  value={newComment}
-                  onChange={(e) => setNewComment(e.target.value)}
-                  placeholder="写下你的评论..."
-                  className="comment-input"
-                  rows={3}
-                />
-                <button type="submit" className="comment-submit">
-                  发布评论
-                </button>
-              </form>
-
-              {/* 评论列表 */}
-              <div className="comments-list">
-                {comments.length === 0 ? (
-                  <p className="no-comments">暂无评论</p>
-                ) : (
-                  comments.map((comment, index) => (
-                    <div key={index} className="comment-item">
-                      <div className="comment-author">
-                        <div className="comment-avatar">
-                          {comment.user_name ? comment.user_name.charAt(0).toUpperCase() : 'U'}
-                        </div>
-                        <span className="comment-name">{comment.user_name || '匿名用户'}</span>
-                        <span className="comment-time">
-                          {comment.create_time ? new Date(comment.create_time).toLocaleString('zh-CN') : ''}
-                        </span>
-                      </div>
-                      <div className="comment-content">
-                        {comment.content}
-                      </div>
-                    </div>
-                  ))
-                )}
-              </div>
-            </div>
-          )}
-        </div>
-      </main>
-
-      {/* 底部操作栏 */}
-      <footer className="post-footer">
-        <div className="action-bar">
-          <button 
-            onClick={handleLike} 
-            className={`action-button ${liked ? 'liked' : ''}`}
-          >
-            <ThumbsUp size={20} />
-            <span>{likeCount}</span>
-          </button>
-          
-          <button 
-            onClick={() => setShowComments(!showComments)}
-            className="action-button"
-          >
-            <MessageCircle size={20} />
-            <span>评论</span>
-          </button>
-          
-          <button onClick={handleShare} className="action-button">
-            <Share2 size={20} />
-            <span>分享</span>
-          </button>
-          
-          <button 
-            onClick={handleBookmark} 
-            className={`action-button ${bookmarked ? 'bookmarked' : ''}`}
-          >
-            <BookmarkPlus size={20} />
-            <span>收藏</span>
-          </button>
-        </div>
-      </footer>
-    </div>
-  )
-}
diff --git a/Merge/front/src/components/Sidebar.jsx b/Merge/front/src/components/Sidebar.jsx
index e35db63..92bc8f1 100644
--- a/Merge/front/src/components/Sidebar.jsx
+++ b/Merge/front/src/components/Sidebar.jsx
@@ -7,8 +7,6 @@
   Activity,
   Users,
   ChevronDown,
-  Search,
-  Upload,
 } from 'lucide-react'
 import '../App.css'
 
@@ -26,7 +24,6 @@
       { id: 'fans',     label: '粉丝数据', path: '/dashboard/fans'     },
     ]
   },
-  { id: 'upload-jwlll', label: '智能发布', icon: Upload, path: '/upload-jwlll' },
   // { id: 'activity', label: '活动中心', icon: Activity, path: '/activity' },
   // { id: 'notes',    label: '笔记灵感', icon: BookOpen, path: '/notes'    },
   // { id: 'creator',  label: '创作学院', icon: Users,    path: '/creator'  },
diff --git a/Merge/front/src/components/UploadPageJWLLL.jsx b/Merge/front/src/components/UploadPageJWLLL.jsx
deleted file mode 100644
index 2d9ee7d..0000000
--- a/Merge/front/src/components/UploadPageJWLLL.jsx
+++ /dev/null
@@ -1,328 +0,0 @@
-import React, { useState } from 'react'
-import { Image, Video, Send } from 'lucide-react'
-import { searchAPI } from '../api/search_jwlll'
-import '../style/UploadPage.css'
-
-const categories = [
-  '穿搭','美食','彩妆','影视',
-  '职场','情感','家居','游戏','旅行','健身'
-]
-
-export default function UploadPageJWLLL({ onComplete }) {
-  const [activeTab, setActiveTab] = useState('image')
-  const [isDragOver, setIsDragOver] = useState(false)
-  const [isUploading, setIsUploading] = useState(false)
-  const [uploadedFiles, setUploadedFiles] = useState([])
-  const [uploadProgress, setUploadProgress] = useState(0)
-  
-  // 新增表单字段
-  const [title, setTitle] = useState('')
-  const [content, setContent] = useState('')
-  const [tags, setTags] = useState('')
-  const [category, setCategory] = useState(categories[0])
-  const [isPublishing, setIsPublishing] = useState(false)
-
-  const DEFAULT_USER_ID = '3' // 默认用户ID
-
-  const validateFiles = files => {
-    const imgTypes = ['image/jpeg','image/jpg','image/png','image/webp']
-    const vidTypes = ['video/mp4','video/mov','video/avi']
-    const types = activeTab==='video'? vidTypes : imgTypes
-    const max   = activeTab==='video'? 2*1024*1024*1024 : 32*1024*1024
-
-    const invalid = files.filter(f => !types.includes(f.type) || f.size > max)
-    if (invalid.length) {
-      alert(`发现 ${invalid.length} 个无效文件,请检查文件格式和大小`)
-      return false
-    }
-    return true
-  }
-
-  const simulateUpload = files => {
-    setIsUploading(true)
-    setUploadProgress(0)
-    setUploadedFiles(files)
-    const iv = setInterval(() => {
-      setUploadProgress(p => {
-        if (p >= 100) {
-          clearInterval(iv)
-          setIsUploading(false)
-          if (typeof onComplete === 'function') {
-            onComplete(files)
-          }
-          return 100
-        }
-        return p + 10
-      })
-    }, 200)
-  }
-
-  const handleFileUpload = () => {
-    if (isUploading) return
-    const input = document.createElement('input')
-    input.type = 'file'
-    input.accept = activeTab==='video'? 'video/*' : 'image/*'
-    input.multiple = activeTab==='image'
-    input.onchange = e => {
-      const files = Array.from(e.target.files)
-      if (files.length > 0 && validateFiles(files)) simulateUpload(files)
-    }
-    input.click()
-  }
-
-  const handleDragOver  = e => { e.preventDefault(); e.stopPropagation(); setIsDragOver(true) }
-  const handleDragLeave = e => { e.preventDefault(); e.stopPropagation(); setIsDragOver(false) }
-  const handleDrop      = e => {
-    e.preventDefault(); e.stopPropagation(); setIsDragOver(false)
-    if (isUploading) return
-    const files = Array.from(e.dataTransfer.files)
-    if (files.length > 0 && validateFiles(files)) simulateUpload(files)
-  }
-
-  const clearFiles = () => setUploadedFiles([])
-  const removeFile = idx => setUploadedFiles(f => f.filter((_,i) => i!==idx))
-
-  // 发布帖子
-  const handlePublish = async () => {
-    if (!title.trim()) {
-      alert('请输入标题')
-      return
-    }
-    if (!content.trim()) {
-      alert('请输入内容')
-      return
-    }
-
-    setIsPublishing(true)
-    try {
-      const postData = {
-        user_id: DEFAULT_USER_ID,
-        title: title.trim(),
-        content: content.trim(),
-        tags: tags.split(',').map(t => t.trim()).filter(t => t),
-        category: category,
-        type: activeTab === 'video' ? 'video' : 'image',
-        media_files: uploadedFiles.map(f => f.name) // 实际项目中应该是上传后的URL
-      }
-
-      await searchAPI.uploadPost(postData)
-      alert('发布成功!')
-      
-      // 清空表单
-      setTitle('')
-      setContent('')
-      setTags('')
-      setUploadedFiles([])
-      setActiveTab('image')
-      
-    } catch (error) {
-      console.error('发布失败:', error)
-      alert('发布失败,请重试')
-    } finally {
-      setIsPublishing(false)
-    }
-  }
-
-  return (
-    <div className="upload-page-jwlll">
-      <div className="upload-tabs">
-        <button
-          className={`upload-tab${activeTab==='video'?' active':''}`}
-          onClick={() => setActiveTab('video')}
-        >上传视频</button>
-        <button
-          className={`upload-tab${activeTab==='image'?' active':''}`}
-          onClick={() => setActiveTab('image')}
-        >上传图文</button>
-      </div>
-
-      {/* 内容表单 */}
-      <div className="content-form">
-        <div className="form-group">
-          <label htmlFor="title">标题</label>
-          <input
-            id="title"
-            type="text"
-            value={title}
-            onChange={(e) => setTitle(e.target.value)}
-            placeholder="请输入标题..."
-            className="form-input"
-            maxLength={100}
-          />
-        </div>
-
-        <div className="form-group">
-          <label htmlFor="content">内容</label>
-          <textarea
-            id="content"
-            value={content}
-            onChange={(e) => setContent(e.target.value)}
-            placeholder="请输入内容..."
-            className="form-textarea"
-            rows={4}
-            maxLength={1000}
-          />
-        </div>
-
-        <div className="form-row">
-          <div className="form-group">
-            <label htmlFor="category">分类</label>
-            <select
-              id="category"
-              value={category}
-              onChange={(e) => setCategory(e.target.value)}
-              className="form-select"
-            >
-              {categories.map(cat => (
-                <option key={cat} value={cat}>{cat}</option>
-              ))}
-            </select>
-          </div>
-
-          <div className="form-group">
-            <label htmlFor="tags">标签</label>
-            <input
-              id="tags"
-              type="text"
-              value={tags}
-              onChange={(e) => setTags(e.target.value)}
-              placeholder="用逗号分隔多个标签..."
-              className="form-input"
-            />
-          </div>
-        </div>
-      </div>
-
-      {/* 文件上传区域 */}
-      <div
-        className={`upload-area${isDragOver?' drag-over':''}`}
-        onDragOver={handleDragOver}
-        onDragLeave={handleDragLeave}
-        onDrop={handleDrop}
-      >
-        <div className="upload-icon">
-          {activeTab==='video'? <Video/> : <Image/>}
-        </div>
-        <h2 className="upload-title">
-          {activeTab==='video'
-            ? '拖拽视频到此处或点击上传'
-            : '拖拽图片到此处或点击上传'
-          }
-        </h2>
-        <p className="upload-subtitle">(需支持上传格式)</p>
-        <button
-          className={`upload-btn${isUploading?' uploading':''}`}
-          onClick={handleFileUpload}
-          disabled={isUploading}
-        >
-          {isUploading
-            ? `上传中... ${uploadProgress}%`
-            : activeTab==='video'
-              ? '上传视频'
-              : '上传图片'
-          }
-        </button>
-
-        {isUploading && (
-          <div className="progress-container">
-            <div className="progress-bar">
-              <div
-                className="progress-fill"
-                style={{ width: `${uploadProgress}%` }}
-              />
-            </div>
-            <div className="progress-text">{uploadProgress}%</div>
-          </div>
-        )}
-      </div>
-
-      {uploadedFiles.length > 0 && (
-        <div className="file-preview-area">
-          <div className="preview-header">
-            <h3 className="preview-title">已上传文件 ({uploadedFiles.length})</h3>
-            <button className="clear-files-btn" onClick={clearFiles}>
-              清除所有
-            </button>
-          </div>
-          <div className="file-grid">
-            {uploadedFiles.map((file, i) => (
-              <div key={i} className="file-item">
-                <button
-                  className="remove-file-btn"
-                  onClick={() => removeFile(i)}
-                  title="删除文件"
-                >×</button>
-                {file.type.startsWith('image/') ? (
-                  <div className="file-thumbnail">
-                    <img src={URL.createObjectURL(file)} alt={file.name} />
-                  </div>
-                ) : (
-                  <div className="file-thumbnail video-thumbnail">
-                    <Video size={24} />
-                  </div>
-                )}
-                <div className="file-info">
-                  <div className="file-name" title={file.name}>
-                    {file.name.length > 20
-                      ? file.name.slice(0,17) + '...'
-                      : file.name
-                    }
-                  </div>
-                  <div className="file-size">
-                    {(file.size/1024/1024).toFixed(2)} MB
-                  </div>
-                </div>
-              </div>
-            ))}
-          </div>
-        </div>
-      )}
-
-      {/* 发布按钮 */}
-      <div className="publish-section">
-        <button
-          className={`publish-btn${isPublishing?' publishing':''}`}
-          onClick={handlePublish}
-          disabled={isPublishing || !title.trim() || !content.trim()}
-        >
-          <Send size={20} />
-          {isPublishing ? '发布中...' : '发布'}
-        </button>
-      </div>
-
-      <div className="upload-info fade-in">
-        {activeTab==='image' ? (
-          <>
-            <div className="info-item">
-              <h3 className="info-title">图片大小</h3>
-              <p className="info-desc">最大32MB</p>
-            </div>
-            <div className="info-item">
-              <h3 className="info-title">图片格式</h3>
-              <p className="info-desc">png/jpg/jpeg/webp</p>
-            </div>
-            <div className="info-item">
-              <h3 className="info-title">分辨率</h3>
-              <p className="info-desc">建议720×960及以上</p>
-            </div>
-          </>
-        ) : (
-          <>
-            <div className="info-item">
-              <h3 className="info-title">视频大小</h3>
-              <p className="info-desc">最大2GB,时长≤5分钟</p>
-            </div>
-            <div className="info-item">
-              <h3 className="info-title">视频格式</h3>
-              <p className="info-desc">mp4/mov</p>
-            </div>
-            <div className="info-item">
-              <h3 className="info-title">分辨率</h3>
-              <p className="info-desc">建议720P及以上</p>
-            </div>
-          </>
-        )}
-      </div>
-    </div>
-  )
-}
diff --git a/Merge/front/src/router/App.js b/Merge/front/src/router/App.js
index efc4067..d7f5f09 100644
--- a/Merge/front/src/router/App.js
+++ b/Merge/front/src/router/App.js
@@ -12,8 +12,6 @@
 import NotebookPage       from '../components/NotebookPage'
 import PlaceholderPage    from '../components/PlaceholderPage'
 import UserProfile        from '../components/UserProfile'
-import PostDetailJWLLL    from '../components/PostDetailJWLLL'
-import UploadPageJWLLL    from '../components/UploadPageJWLLL'
 
 import AdminPage          from '../components/Admin'
 import SuperAdmin         from '../components/SuperAdmin'
@@ -43,13 +41,13 @@
         {/* 2.1 任何登录用户都能看自己的主页 */}
         <Route element={<RequireOwnProfile />}>
           <Route path="/user/:userId" element={<UserProfile />} />
-        </Route>        {/* 2.2 普通用户 */}
+        </Route>
+
+        {/* 2.2 普通用户 */}
         <Route element={<RequireRole allowedRoles={['user']} />}>
           <Route path="/home"               element={<HomeFeed />} />
-          <Route path="/post/:id"           element={<PostDetailJWLLL />} />
           <Route path="/posts/new"          element={<CreatePost />} />
           <Route path="/posts/edit/:postId" element={<CreatePost />} />
-          <Route path="/upload-jwlll"       element={<UploadPageJWLLL />} />
           <Route path="/notebooks"          element={<NotebookPage />} />
           <Route path="/dashboard/*"        element={<PlaceholderPage />} />
           <Route path="/activity"           element={<PlaceholderPage pageId="activity" />} />
diff --git a/Merge/front/src/style/HomeFeed.css b/Merge/front/src/style/HomeFeed.css
index 394c84b..f1bf75d 100644
--- a/Merge/front/src/style/HomeFeed.css
+++ b/Merge/front/src/style/HomeFeed.css
@@ -113,95 +113,4 @@
 .card-likes .likes-count {
   font-size: 13px;
   color: #666;
-}
-
-/* --------- JWLLL 搜索推荐功能样式 --------- */
-
-/* 搜索框美化 */
-.feed-search {
-  display: flex;
-  gap: 8px;
-  align-items: center;
-}
-
-.search-input {
-  flex: 1;
-  padding: 8px 14px;
-  border: 1.5px solid #e0e0e0;
-  border-radius: 20px;
-  font-size: 15px;
-  outline: none;
-  transition: border 0.2s;
-  background: #fafbfc;
-}
-
-.search-input:focus {
-  border: 1.5px solid #e84c4a;
-  background: #fff;
-}
-
-.search-btn {
-  padding: 8px 22px;
-  border: none;
-  border-radius: 20px;
-  background: linear-gradient(90deg,#ff6a6a,#ff4757);
-  color: #fff;
-  font-weight: 600;
-  font-size: 15px;
-  cursor: pointer;
-  box-shadow: 0 2px 8px rgba(255,71,87,0.08);
-  transition: background 0.2s, box-shadow 0.2s;
-}
-
-.search-btn:hover {
-  background: linear-gradient(90deg,#ff4757,#e84c4a);
-  box-shadow: 0 4px 16px rgba(255,71,87,0.15);
-}
-
-/* 推荐模式切换按钮 */
-.rec-btn {
-  background: #f8f9fa;
-  border: 1px solid #dee2e6;
-  color: #495057;
-  padding: 6px 12px;
-  border-radius: 20px;
-  cursor: pointer;
-  transition: all 0.2s;
-  font-size: 14px;
-  outline: none;
-}
-
-.rec-btn:hover {
-  background: #e9ecef;
-}
-
-.rec-btn.active {
-  background: #fff0f0;
-  border: 2px solid #e84c4a;
-  color: #e84c4a;
-  font-weight: 600;
-}
-
-/* 卡片内容显示区域 */
-.card-content {
-  padding: 0 12px 8px;
-  font-size: 13px;
-  color: #666;
-  line-height: 1.4;
-  overflow: hidden;
-  text-overflow: ellipsis;
-  display: -webkit-box;
-  -webkit-line-clamp: 2;
-  -webkit-box-orient: vertical;
-}
-
-/* 点击效果 */
-.feed-card {
-  cursor: pointer;
-  transition: transform 0.2s, box-shadow 0.2s;
-}
-
-.feed-card:hover {
-  transform: translateY(-2px);
-  box-shadow: 0 4px 12px rgba(0,0,0,0.15);
 }
\ No newline at end of file
diff --git a/Merge/front/src/style/PostDetail.css b/Merge/front/src/style/PostDetail.css
deleted file mode 100644
index 1be7126..0000000
--- a/Merge/front/src/style/PostDetail.css
+++ /dev/null
@@ -1,436 +0,0 @@
-/* 帖子详情页面容器 */
-.post-detail {
-  max-width: 800px;
-  margin: 0 auto;
-  background: #fff;
-  min-height: 100vh;
-  display: flex;
-  flex-direction: column;
-}
-
-/* 加载状态 */
-.loading-container {
-  display: flex;
-  flex-direction: column;
-  align-items: center;
-  justify-content: center;
-  padding: 60px 20px;
-  color: #666;
-}
-
-.loading-spinner {
-  width: 40px;
-  height: 40px;
-  border: 3px solid #f3f3f3;
-  border-top: 3px solid #ff4757;
-  border-radius: 50%;
-  animation: spin 1s linear infinite;
-  margin-bottom: 20px;
-}
-
-@keyframes spin {
-  0% { transform: rotate(0deg); }
-  100% { transform: rotate(360deg); }
-}
-
-/* 错误状态 */
-.error-container {
-  text-align: center;
-  padding: 60px 20px;
-  color: #666;
-}
-
-.error-container h2 {
-  margin-bottom: 16px;
-  color: #333;
-}
-
-/* 顶部导航栏 */
-.post-header {
-  display: flex;
-  justify-content: space-between;
-  align-items: center;
-  padding: 16px 20px;
-  border-bottom: 1px solid #eee;
-  background: #fff;
-  position: sticky;
-  top: 0;
-  z-index: 100;
-}
-
-.back-btn {
-  display: flex;
-  align-items: center;
-  gap: 8px;
-  padding: 8px 16px;
-  border: none;
-  background: #f8f9fa;
-  border-radius: 20px;
-  cursor: pointer;
-  transition: background-color 0.2s;
-  font-size: 14px;
-  color: #333;
-}
-
-.back-btn:hover {
-  background: #e9ecef;
-}
-
-.header-actions {
-  display: flex;
-  gap: 8px;
-}
-
-.action-btn {
-  display: flex;
-  align-items: center;
-  justify-content: center;
-  width: 40px;
-  height: 40px;
-  border: none;
-  background: #f8f9fa;
-  border-radius: 50%;
-  cursor: pointer;
-  transition: background-color 0.2s;
-  color: #666;
-}
-
-.action-btn:hover {
-  background: #e9ecef;
-}
-
-.action-btn.active {
-  background: #ff4757;
-  color: white;
-}
-
-/* 主要内容区 */
-.post-content {
-  flex: 1;
-  padding: 20px;
-}
-
-.post-title {
-  font-size: 24px;
-  font-weight: 700;
-  line-height: 1.4;
-  margin-bottom: 20px;
-  color: #333;
-}
-
-/* 帖子元信息 */
-.post-meta {
-  display: flex;
-  justify-content: space-between;
-  align-items: center;
-  margin-bottom: 20px;
-  padding-bottom: 16px;
-  border-bottom: 1px solid #f0f0f0;
-}
-
-.author-info {
-  display: flex;
-  align-items: center;
-  gap: 12px;
-}
-
-.avatar {
-  width: 40px;
-  height: 40px;
-  border-radius: 50%;
-  background: #ff4757;
-  color: white;
-  display: flex;
-  align-items: center;
-  justify-content: center;
-  font-weight: 600;
-  font-size: 16px;
-}
-
-.author-details {
-  display: flex;
-  flex-direction: column;
-  gap: 2px;
-}
-
-.author-name {
-  font-weight: 600;
-  color: #333;
-  font-size: 14px;
-}
-
-.post-date {
-  font-size: 12px;
-  color: #666;
-}
-
-.post-stats {
-  display: flex;
-  gap: 16px;
-}
-
-.stat-item {
-  display: flex;
-  align-items: center;
-  gap: 4px;
-  font-size: 14px;
-  color: #666;
-}
-
-/* 标签 */
-.post-tags {
-  display: flex;
-  flex-wrap: wrap;
-  gap: 8px;
-  margin-bottom: 20px;
-}
-
-.tag {
-  padding: 4px 12px;
-  background: #f8f9fa;
-  border-radius: 16px;
-  font-size: 12px;
-  color: #666;
-  border: 1px solid #e9ecef;
-}
-
-/* 帖子正文 */
-.post-body {
-  margin-bottom: 24px;
-  line-height: 1.6;
-  color: #333;
-  font-size: 16px;
-}
-
-.post-body p {
-  margin-bottom: 16px;
-}
-
-/* 类别信息 */
-.post-category {
-  margin-bottom: 20px;
-  padding: 12px;
-  background: #f8f9fa;
-  border-radius: 8px;
-  font-size: 14px;
-}
-
-.category-label {
-  color: #666;
-  font-weight: 500;
-}
-
-.category-name {
-  color: #333;
-  font-weight: 600;
-}
-
-/* 评论区 */
-.comments-section {
-  margin-top: 32px;
-  padding-top: 24px;
-  border-top: 1px solid #eee;
-}
-
-.comments-header {
-  margin-bottom: 20px;
-}
-
-.comments-toggle {
-  display: flex;
-  align-items: center;
-  gap: 8px;
-  padding: 10px 16px;
-  border: 1px solid #e9ecef;
-  background: #f8f9fa;
-  border-radius: 8px;
-  cursor: pointer;
-  transition: background-color 0.2s;
-  font-size: 14px;
-  color: #333;
-}
-
-.comments-toggle:hover {
-  background: #e9ecef;
-}
-
-.comments-content {
-  margin-top: 16px;
-}
-
-/* 评论表单 */
-.comment-form {
-  margin-bottom: 24px;
-  padding: 16px;
-  background: #f8f9fa;
-  border-radius: 8px;
-}
-
-.comment-input {
-  width: 100%;
-  padding: 12px;
-  border: 1px solid #dee2e6;
-  border-radius: 6px;
-  resize: vertical;
-  font-family: inherit;
-  font-size: 14px;
-  margin-bottom: 12px;
-  outline: none;
-  transition: border-color 0.2s;
-}
-
-.comment-input:focus {
-  border-color: #ff4757;
-}
-
-.comment-submit {
-  padding: 8px 16px;
-  background: #ff4757;
-  color: white;
-  border: none;
-  border-radius: 6px;
-  cursor: pointer;
-  font-size: 14px;
-  transition: background-color 0.2s;
-}
-
-.comment-submit:hover {
-  background: #e84c4a;
-}
-
-/* 评论列表 */
-.comments-list {
-  display: flex;
-  flex-direction: column;
-  gap: 16px;
-}
-
-.no-comments {
-  text-align: center;
-  color: #666;
-  font-style: italic;
-  padding: 32px 0;
-}
-
-.comment-item {
-  padding: 16px;
-  background: #fff;
-  border: 1px solid #e9ecef;
-  border-radius: 8px;
-}
-
-.comment-author {
-  display: flex;
-  align-items: center;
-  gap: 8px;
-  margin-bottom: 8px;
-}
-
-.comment-avatar {
-  width: 32px;
-  height: 32px;
-  border-radius: 50%;
-  background: #6c757d;
-  color: white;
-  display: flex;
-  align-items: center;
-  justify-content: center;
-  font-weight: 600;
-  font-size: 14px;
-}
-
-.comment-name {
-  font-weight: 600;
-  color: #333;
-  font-size: 14px;
-}
-
-.comment-time {
-  font-size: 12px;
-  color: #666;
-  margin-left: auto;
-}
-
-.comment-content {
-  font-size: 14px;
-  line-height: 1.5;
-  color: #333;
-  margin-left: 40px;
-}
-
-/* 底部操作栏 */
-.post-footer {
-  padding: 16px 20px;
-  border-top: 1px solid #eee;
-  background: #fff;
-  position: sticky;
-  bottom: 0;
-}
-
-.action-bar {
-  display: flex;
-  justify-content: space-around;
-  align-items: center;
-  max-width: 400px;
-  margin: 0 auto;
-}
-
-.action-button {
-  display: flex;
-  flex-direction: column;
-  align-items: center;
-  gap: 4px;
-  padding: 8px 12px;
-  border: none;
-  background: transparent;
-  cursor: pointer;
-  transition: color 0.2s;
-  color: #666;
-  font-size: 12px;
-}
-
-.action-button:hover {
-  color: #333;
-}
-
-.action-button.liked {
-  color: #ff4757;
-}
-
-.action-button.bookmarked {
-  color: #ffa502;
-}
-
-/* 响应式设计 */
-@media (max-width: 768px) {
-  .post-detail {
-    margin: 0;
-  }
-  
-  .post-content {
-    padding: 16px;
-  }
-  
-  .post-title {
-    font-size: 20px;
-  }
-  
-  .post-meta {
-    flex-direction: column;
-    align-items: flex-start;
-    gap: 12px;
-  }
-  
-  .post-stats {
-    align-self: flex-end;
-  }
-  
-  .action-bar {
-    max-width: none;
-  }
-  
-  .comment-content {
-    margin-left: 0;
-    margin-top: 8px;
-  }
-}