改了过滤
This commit is contained in:
parent
534c9f6677
commit
efafe4c452
@ -12,6 +12,7 @@ import shutil
|
||||
import dotenv
|
||||
import random
|
||||
import uuid
|
||||
from django.db.models import Q
|
||||
|
||||
dotenv.load_dotenv()
|
||||
|
||||
@ -24,729 +25,6 @@ directory_monitoring = {}
|
||||
monitor_thread = None
|
||||
is_monitoring = False
|
||||
|
||||
# # 在文件开头定义日志目录
|
||||
# BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
||||
# LOG_DIR = os.path.join(BASE_DIR, 'logs', 'process_monitor')
|
||||
|
||||
# 创建保存视频的基本路径
|
||||
# TIKTOK_VIDEOS_PATH = os.path.join(BASE_DIR, 'media', 'tiktok_videos')
|
||||
|
||||
# 确保基本目录存在
|
||||
# os.makedirs(TIKTOK_VIDEOS_PATH, exist_ok=True)
|
||||
|
||||
# 确保基础目录结构存在,添加 'all' 目录
|
||||
# for resource_type in ['cpu', 'memory', 'gpu', 'all']:
|
||||
# os.makedirs(os.path.join(LOG_DIR, resource_type), exist_ok=True)
|
||||
|
||||
# 全局变量来跟踪监控的目录
|
||||
# monitored_directories = set()
|
||||
|
||||
# 在文件顶部添加 API 基础 URL
|
||||
# API_BASE_URL = os.getenv("API_BASE_URL")
|
||||
|
||||
#
|
||||
# @csrf_exempt
|
||||
# @require_http_methods(["POST"])
|
||||
# def fetch_tiktok_videos(request):
|
||||
# """获取TikTok视频"""
|
||||
# try:
|
||||
# # 添加全局变量引用
|
||||
# global all_downloaded_videos
|
||||
#
|
||||
# # 如果变量未初始化,则初始化为空列表
|
||||
# if 'all_downloaded_videos' not in globals():
|
||||
# all_downloaded_videos = []
|
||||
#
|
||||
# data = json.loads(request.body)
|
||||
# unique_id = data.get('unique_id')
|
||||
#
|
||||
# if not unique_id:
|
||||
# return JsonResponse({
|
||||
# 'status': 'error',
|
||||
# 'message': '请提供TikTok用户ID(unique_id)'
|
||||
# }, json_dumps_params={'ensure_ascii': False})
|
||||
#
|
||||
# # 检查数据库中是否已存在该unique_id
|
||||
# if TiktokUserVideos.objects.filter(unique_id=unique_id).exists():
|
||||
# logger.info(f"用户 {unique_id} 已存在于数据库中,跳过处理")
|
||||
# return JsonResponse({
|
||||
# 'status': 'success',
|
||||
# 'message': f'用户 {unique_id} 已存在,跳过处理'
|
||||
# }, json_dumps_params={'ensure_ascii': False})
|
||||
#
|
||||
# # 获取creator_oec_id
|
||||
# creator_oec_id = data.get('creator_oec_id')
|
||||
# logger.info(f"从请求数据中获取到creator_oec_id: {creator_oec_id}")
|
||||
#
|
||||
# # 调用API获取用户资料和secUid
|
||||
# logger.info(f"正在获取用户 {unique_id} 的资料...")
|
||||
# # user_profile = fetch_user_profile(unique_id)
|
||||
# user_profile = None
|
||||
# if not user_profile or 'data' not in user_profile:
|
||||
# # 尝试使用备用方法获取用户资料
|
||||
# logger.info(f"尝试使用备用方法获取用户 {unique_id} 的资料...")
|
||||
#
|
||||
# # 从data中获取creator_oec_id
|
||||
# try:
|
||||
# # 从响应中提取creator_oec_id
|
||||
# creator_oec_id = data.get('creator_oec_id')
|
||||
# logger.info(f"从请求数据中获取到creator_oec_id: {creator_oec_id}")
|
||||
#
|
||||
# # 如果有creator_oec_id,则使用备用方法获取用户资料
|
||||
# if creator_oec_id:
|
||||
# user_profile = fetch_user_profile_1(creator_oec_id)
|
||||
#
|
||||
# if not user_profile or 'data' not in user_profile:
|
||||
# return JsonResponse({
|
||||
# 'status': 'error',
|
||||
# 'message': f'无法获取用户 {unique_id} 的资料(两种方法均失败)'
|
||||
# }, json_dumps_params={'ensure_ascii': False})
|
||||
# else:
|
||||
# return JsonResponse({
|
||||
# 'status': 'error',
|
||||
# 'message': f'无法获取用户 {unique_id} 的资料'
|
||||
# }, json_dumps_params={'ensure_ascii': False})
|
||||
# except Exception as e:
|
||||
# logger.error(f"备用方法获取用户资料失败: {e}")
|
||||
# return JsonResponse({
|
||||
# 'status': 'error',
|
||||
# 'message': f'无法获取用户 {unique_id} 的资料: {str(e)}'
|
||||
# }, json_dumps_params={'ensure_ascii': False})
|
||||
#
|
||||
# # 从API响应中提取secUid和其他用户信息
|
||||
# try:
|
||||
# user_info = user_profile['data']['userInfo']['user']
|
||||
# sec_uid = user_info['secUid']
|
||||
#
|
||||
# # 提取其他用户信息
|
||||
# nickname = user_info.get('nickname', f'用户_{unique_id}')
|
||||
# signature = user_info.get('signature', '')
|
||||
# avatar_url = user_info.get('avatarLarger', '')
|
||||
# user_stats = user_profile['data']['userInfo']['stats']
|
||||
# follower_count = user_stats.get('followerCount', 0)
|
||||
# heart_count = user_stats.get('heartCount', 0)
|
||||
#
|
||||
# logger.info(f"成功获取用户secUid: {sec_uid}")
|
||||
# except (KeyError, TypeError) as e:
|
||||
# logger.error(f"解析用户资料出错: {e}")
|
||||
# return JsonResponse({
|
||||
# 'status': 'error',
|
||||
# 'message': f'解析用户资料出错: {str(e)}'
|
||||
# }, json_dumps_params={'ensure_ascii': False})
|
||||
#
|
||||
# # 确保用户目录存在
|
||||
# user_dir = os.path.join(TIKTOK_VIDEOS_PATH, unique_id)
|
||||
# os.makedirs(user_dir, exist_ok=True)
|
||||
#
|
||||
# # 获取用户视频
|
||||
# downloaded_videos = []
|
||||
# videos_data = fetch_user_videos(sec_uid)
|
||||
# if videos_data and 'data' in videos_data and 'itemList' in videos_data['data']:
|
||||
# videos = videos_data['data']['itemList']
|
||||
# user_dir = os.path.join(TIKTOK_VIDEOS_PATH, unique_id)
|
||||
# os.makedirs(user_dir, exist_ok=True)
|
||||
#
|
||||
# # 获取前10个热门视频
|
||||
# top_videos = sorted(videos, key=lambda x: x.get('stats', {}).get('playCount', 0), reverse=True)[:10]
|
||||
#
|
||||
# # 定义下载任务函数
|
||||
# def download_task(video):
|
||||
# try:
|
||||
# video_id = video.get('id', '')
|
||||
# if not video_id:
|
||||
# return None
|
||||
#
|
||||
# save_path = os.path.join(user_dir, f"{video_id}.mp4")
|
||||
#
|
||||
# stats = video.get('stats', {})
|
||||
# play_count = int(stats.get('playCount', 0))
|
||||
#
|
||||
# # 检查是否已下载过该视频
|
||||
# is_downloaded = os.path.exists(save_path) and os.path.getsize(save_path) > 0
|
||||
#
|
||||
# if is_downloaded and is_valid_video_file(save_path):
|
||||
# logger.info(f"视频已存在且有效,跳过下载: {video_id}")
|
||||
# # 即使跳过下载,也添加到已下载列表中
|
||||
# return {
|
||||
# 'id': video_id,
|
||||
# 'desc': video.get('desc', ''),
|
||||
# 'play_count': play_count,
|
||||
# 'user_unique_id': unique_id,
|
||||
# 'skipped': True
|
||||
# }
|
||||
# elif download_video(video_id, unique_id, save_path):
|
||||
# # download_video函数内部已经检查了文件有效性
|
||||
# return {
|
||||
# 'id': video_id,
|
||||
# 'desc': video.get('desc', ''),
|
||||
# 'play_count': play_count,
|
||||
# 'user_unique_id': unique_id,
|
||||
# 'skipped': False
|
||||
# }
|
||||
# return None
|
||||
# except Exception as e:
|
||||
# logger.error(f"下载视频时出错: {e}")
|
||||
# return None
|
||||
#
|
||||
# # 使用线程池并发下载
|
||||
# with concurrent.futures.ThreadPoolExecutor(max_workers=4) as executor:
|
||||
# # 提交所有下载任务
|
||||
# future_to_video = {executor.submit(download_task, video): video for video in top_videos}
|
||||
#
|
||||
# # 获取结果
|
||||
# for future in concurrent.futures.as_completed(future_to_video):
|
||||
# result = future.result()
|
||||
# if result:
|
||||
# downloaded_videos.append(result)
|
||||
#
|
||||
# all_downloaded_videos.extend(downloaded_videos)
|
||||
#
|
||||
# # 视频下载完成后,先调用API分析视频,然后再保存到数据库
|
||||
# if downloaded_videos: # 只有当有视频下载成功时才处理
|
||||
# video_info_json = json.dumps([{
|
||||
# 'id': v['id'],
|
||||
# 'desc': v['desc'],
|
||||
# 'play_count': v['play_count']
|
||||
# } for v in downloaded_videos], ensure_ascii=False)
|
||||
#
|
||||
# # 先调用视频分析和文档创建API
|
||||
# document_id = analyze_videos_and_create_document(user_dir, nickname, unique_id, sec_uid)
|
||||
#
|
||||
# # 只有在API调用成功后才写入数据库
|
||||
# if document_id:
|
||||
# user_record = TiktokUserVideos.objects.update_or_create(
|
||||
# sec_user_id=sec_uid,
|
||||
# defaults={
|
||||
# 'unique_id': unique_id, # 添加unique_id字段
|
||||
# 'nickname': nickname,
|
||||
# 'signature': signature,
|
||||
# 'follower_count': follower_count,
|
||||
# 'total_favorited': heart_count,
|
||||
# 'avatar_url': avatar_url,
|
||||
# 'videos_folder': user_dir,
|
||||
# 'video_paths': video_info_json,
|
||||
# 'creator_oec_id': creator_oec_id,
|
||||
# 'document_id': document_id
|
||||
# }
|
||||
# )
|
||||
# logger.info(
|
||||
# f"API调用成功,用户 {nickname} 的数据已写入数据库,下载视频数: {len(downloaded_videos)},document_id: {document_id}")
|
||||
# else:
|
||||
# logger.warning(f"API调用失败,跳过用户 {nickname} 的数据库写入")
|
||||
# else:
|
||||
# logger.warning(f"未获取到用户 {unique_id} 的视频数据")
|
||||
# document_id = None
|
||||
#
|
||||
# return JsonResponse({
|
||||
# 'status': 'success',
|
||||
# 'message': '处理完成'
|
||||
# }, json_dumps_params={'ensure_ascii': False})
|
||||
#
|
||||
# except Exception as e:
|
||||
# logger.error(f"处理TikTok视频失败: {e}")
|
||||
# import traceback
|
||||
# logger.error(f"详细错误: {traceback.format_exc()}")
|
||||
# return JsonResponse({
|
||||
# 'status': 'error',
|
||||
# 'message': f'处理TikTok视频失败: {str(e)}'
|
||||
# }, json_dumps_params={'ensure_ascii': False})
|
||||
#
|
||||
#
|
||||
# @require_http_methods(["GET"])
|
||||
# def get_tiktok_user_videos(request):
|
||||
# """获取已下载的TikTok用户视频列表"""
|
||||
# try:
|
||||
# sec_user_id = request.GET.get('sec_user_id')
|
||||
#
|
||||
# if not sec_user_id:
|
||||
# # 如果没有指定用户ID,返回所有用户列表
|
||||
# users = TiktokUserVideos.objects.all().values('sec_user_id', 'unique_id', 'nickname', 'follower_count',
|
||||
# 'videos_folder', 'create_time', 'avatar_url', 'signature',
|
||||
# 'creator_oec_id')
|
||||
# return JsonResponse({
|
||||
# 'status': 'success',
|
||||
# 'users': list(users)
|
||||
# }, json_dumps_params={'ensure_ascii': False})
|
||||
#
|
||||
# # 查询指定用户信息
|
||||
# try:
|
||||
# user = TiktokUserVideos.objects.get(sec_user_id=sec_user_id)
|
||||
# # 解析视频信息JSON
|
||||
# video_info = json.loads(user.video_paths) if user.video_paths else []
|
||||
#
|
||||
# # 获取文件夹中的文件列表
|
||||
# videos_folder = user.videos_folder
|
||||
# video_files = []
|
||||
# if os.path.exists(videos_folder):
|
||||
# video_files = [f for f in os.listdir(videos_folder) if os.path.isfile(os.path.join(videos_folder, f))]
|
||||
#
|
||||
# except TiktokUserVideos.DoesNotExist:
|
||||
# return JsonResponse({
|
||||
# 'status': 'error',
|
||||
# 'message': f'用户 {sec_user_id} 不存在'
|
||||
# }, json_dumps_params={'ensure_ascii': False})
|
||||
#
|
||||
# return JsonResponse({
|
||||
# 'status': 'success',
|
||||
# 'user_info': {
|
||||
# 'sec_user_id': user.sec_user_id,
|
||||
# 'unique_id': user.unique_id,
|
||||
# 'nickname': user.nickname,
|
||||
# 'signature': user.signature,
|
||||
# 'follower_count': user.follower_count,
|
||||
# 'total_favorited': user.total_favorited,
|
||||
# 'avatar_url': user.avatar_url,
|
||||
# 'creator_oec_id': user.creator_oec_id, # 添加creator_oec_id字段
|
||||
# 'create_time': user.create_time.strftime('%Y-%m-%d %H:%M:%S'),
|
||||
# 'update_time': user.update_time.strftime('%Y-%m-%d %H:%M:%S')
|
||||
# },
|
||||
# 'videos_folder': videos_folder,
|
||||
# 'video_files': video_files,
|
||||
# 'video_info': video_info
|
||||
# }, json_dumps_params={'ensure_ascii': False})
|
||||
#
|
||||
# except Exception as e:
|
||||
# logger.error(f"获取TikTok视频列表失败: {str(e)}")
|
||||
# return JsonResponse({
|
||||
# 'status': 'error',
|
||||
# 'message': f'获取TikTok视频列表失败: {str(e)}'
|
||||
# }, json_dumps_params={'ensure_ascii': False})
|
||||
#
|
||||
#
|
||||
# # 辅助函数
|
||||
#
|
||||
# def fetch_user_videos(sec_uid, cursor=0, count=30):
|
||||
# """获取用户视频列表"""
|
||||
# url = f"{API_BASE_URL}/api/tiktok/web/fetch_user_post?secUid={sec_uid}&cursor={cursor}&count={count}"
|
||||
#
|
||||
# try:
|
||||
# response = requests.get(url, timeout=30)
|
||||
#
|
||||
# if response.status_code == 200:
|
||||
# data = response.json()
|
||||
# logger.info(f"成功获取用户视频,共 {len(data['data'].get('itemList', []))} 个视频")
|
||||
# return data
|
||||
# else:
|
||||
# logger.error(f"获取用户视频失败: {response.status_code}")
|
||||
# return None
|
||||
# except Exception as e:
|
||||
# logger.error(f"获取用户视频异常: {e}")
|
||||
# return None
|
||||
#
|
||||
#
|
||||
# def fetch_user_profile(unique_id):
|
||||
# """获取用户基本信息"""
|
||||
# url = f"{API_BASE_URL}/api/tiktok/web/fetch_user_profile?uniqueId={unique_id}"
|
||||
#
|
||||
# try:
|
||||
# logger.info(f"正在请求用户资料: {url}")
|
||||
# response = requests.get(url, timeout=30)
|
||||
#
|
||||
# if response.status_code == 200:
|
||||
# data = response.json()
|
||||
# logger.info(f"成功获取用户资料: {unique_id}")
|
||||
#
|
||||
# # 打印完整响应以便调试
|
||||
# logger.info(f"API原始响应: {data}")
|
||||
#
|
||||
# # 验证数据完整性
|
||||
# if 'data' not in data or not data['data']:
|
||||
# logger.error(f"API响应缺少data字段: {data}")
|
||||
# return None
|
||||
#
|
||||
# if 'userInfo' not in data['data'] or not data['data']['userInfo']:
|
||||
# logger.error(f"API响应缺少userInfo字段: {data['data']}")
|
||||
# return None
|
||||
#
|
||||
# if 'user' not in data['data']['userInfo'] or not data['data']['userInfo']['user']:
|
||||
# logger.error(f"API响应缺少user字段: {data['data']['userInfo']}")
|
||||
# return None
|
||||
#
|
||||
# # 打印用户信息
|
||||
# logger.info(f"用户信息: {data['data']['userInfo']['user']}")
|
||||
#
|
||||
# return data
|
||||
# else:
|
||||
# logger.error(f"获取用户信息失败: HTTP {response.status_code}, 响应: {response.text[:500]}")
|
||||
# return None
|
||||
# except Exception as e:
|
||||
# logger.error(f"获取用户信息异常: {e}")
|
||||
# return None
|
||||
#
|
||||
#
|
||||
# def get_sec_user_id(unique_id):
|
||||
# """
|
||||
# 通过TikTok用户名获取secUid
|
||||
#
|
||||
# Args:
|
||||
# unique_id: TikTok用户名
|
||||
#
|
||||
# Returns:
|
||||
# secUid字符串,如果获取失败则返回None
|
||||
# """
|
||||
# url = f"{API_BASE_URL}/api/tiktok/web/get_sec_user_id?url=https://www.tiktok.com/@{unique_id}"
|
||||
#
|
||||
# try:
|
||||
# logger.info(f"正在请求secUid: {url}")
|
||||
# response = requests.get(url, timeout=30)
|
||||
#
|
||||
# if response.status_code == 200:
|
||||
# data = response.json()
|
||||
# logger.info(f"成功获取secUid: {data}")
|
||||
#
|
||||
# if 'data' in data and data['data']:
|
||||
# sec_uid = data['data']
|
||||
# logger.info(f"获取到secUid: {sec_uid}")
|
||||
# return sec_uid
|
||||
# else:
|
||||
# logger.error(f"API响应缺少data字段或data为空: {data}")
|
||||
# return None
|
||||
# else:
|
||||
# logger.error(f"获取secUid失败: HTTP {response.status_code}, 响应: {response.text[:500]}")
|
||||
# return None
|
||||
# except Exception as e:
|
||||
# logger.error(f"获取secUid异常: {e}")
|
||||
# return None
|
||||
#
|
||||
#
|
||||
# def fetch_user_profile_1(creator_oec_id):
|
||||
# """
|
||||
# 通过creator_oec_id获取用户基本信息
|
||||
#
|
||||
# 当fetch_user_profile无法获取用户信息时,使用此备用方法
|
||||
# 通过POST请求获取用户详细资料
|
||||
#
|
||||
# Args:
|
||||
# creator_oec_id: 创作者OEC ID
|
||||
#
|
||||
# Returns:
|
||||
# 与fetch_user_profile相同格式的用户信息
|
||||
# """
|
||||
# url = "http://100.65.206.105:8899/profile"
|
||||
#
|
||||
# try:
|
||||
# logger.info(f"正在通过creator_oec_id请求用户资料: {creator_oec_id}")
|
||||
#
|
||||
# # 构建请求体
|
||||
# payload = {
|
||||
# "creator_oec_id": creator_oec_id,
|
||||
# "profile_types": [1, 6]
|
||||
# }
|
||||
#
|
||||
# # 发送POST请求
|
||||
# response = requests.post(url, json=payload, timeout=30)
|
||||
#
|
||||
# if response.status_code == 200:
|
||||
# data = response.json()
|
||||
# logger.info(f"成功获取用户资料(方法2): {creator_oec_id}")
|
||||
#
|
||||
# # 验证数据完整性
|
||||
# if 'creator_profile' not in data:
|
||||
# logger.error(f"API响应缺少creator_profile字段: {data}")
|
||||
# return None
|
||||
#
|
||||
# # 转换为与fetch_user_profile相同的格式
|
||||
# creator_profile = data.get('creator_profile', {})
|
||||
#
|
||||
# # 获取uniqueId
|
||||
# unique_id = creator_profile.get('handle', {}).get('value', '')
|
||||
#
|
||||
# # 通过uniqueId获取secUid
|
||||
# sec_uid = None
|
||||
# if unique_id:
|
||||
# sec_uid = get_sec_user_id(unique_id)
|
||||
#
|
||||
# # 如果无法获取secUid,使用一个占位符
|
||||
# if not sec_uid:
|
||||
# logger.warning(f"无法获取用户 {unique_id} 的secUid,使用占位符")
|
||||
# sec_uid = f"placeholder_secuid_{creator_oec_id}"
|
||||
#
|
||||
# # 构建与原API相同格式的响应
|
||||
# formatted_data = {
|
||||
# 'data': {
|
||||
# 'userInfo': {
|
||||
# 'user': {
|
||||
# 'secUid': sec_uid,
|
||||
# 'uniqueId': unique_id,
|
||||
# 'nickname': creator_profile.get('nickname', {}).get('value', ''),
|
||||
# 'signature': creator_profile.get('bio', {}).get('value', ''),
|
||||
# 'avatarLarger': creator_profile.get('avatar', {}).get('value', {}).get('url_list', [''])[0]
|
||||
# },
|
||||
# 'stats': {
|
||||
# 'followerCount': int(creator_profile.get('follower_cnt', {}).get('value', '0')),
|
||||
# 'heartCount': 0, # 没有对应字段,设为0
|
||||
# 'followingCount': 0, # 没有对应字段,设为0
|
||||
# 'videoCount': 0 # 没有对应字段,设为0
|
||||
# }
|
||||
# }
|
||||
# }
|
||||
# }
|
||||
#
|
||||
# return formatted_data
|
||||
# else:
|
||||
# logger.error(f"获取用户信息失败(方法2): HTTP {response.status_code}, 响应: {response.text[:500]}")
|
||||
# return None
|
||||
# except Exception as e:
|
||||
# logger.error(f"获取用户信息异常(方法2): {e}")
|
||||
# import traceback
|
||||
# logger.error(f"详细错误: {traceback.format_exc()}")
|
||||
# return None
|
||||
#
|
||||
#
|
||||
# def is_valid_video_file(file_path):
|
||||
# """
|
||||
# 检查视频文件是否有效
|
||||
#
|
||||
# Args:
|
||||
# file_path: 视频文件路径
|
||||
#
|
||||
# Returns:
|
||||
# bool: 如果文件有效返回True,否则返回False
|
||||
# """
|
||||
# try:
|
||||
# # 检查文件是否存在
|
||||
# if not os.path.exists(file_path):
|
||||
# logger.error(f"视频文件不存在: {file_path}")
|
||||
# return False
|
||||
#
|
||||
# # 检查文件大小是否合理 (大于10KB)
|
||||
# file_size = os.path.getsize(file_path)
|
||||
# if file_size < 10 * 1024: # 小于10KB的文件可能是无效的
|
||||
# logger.warning(f"视频文件过小,可能无效: {file_path},大小: {file_size}字节")
|
||||
# return False
|
||||
#
|
||||
# # 检查文件是否可读
|
||||
# with open(file_path, 'rb') as f:
|
||||
# # 尝试读取前100字节
|
||||
# data = f.read(100)
|
||||
# if not data:
|
||||
# logger.warning(f"视频文件内容为空: {file_path}")
|
||||
# return False
|
||||
#
|
||||
# return True
|
||||
#
|
||||
# except Exception as e:
|
||||
# logger.error(f"验证视频文件时出错: {e}")
|
||||
# return False
|
||||
#
|
||||
#
|
||||
# def download_video(video_id, unique_id, save_path):
|
||||
# """使用API的直接下载接口下载TikTok视频"""
|
||||
# # 确保视频ID是纯数字
|
||||
# if not str(video_id).isdigit():
|
||||
# logger.error(f"无效的视频ID: {video_id},必须是纯数字")
|
||||
# return False
|
||||
#
|
||||
# # 检查文件是否已存在
|
||||
# if os.path.exists(save_path):
|
||||
# file_size = os.path.getsize(save_path)
|
||||
# if file_size > 0: # 确保文件不是空文件
|
||||
# # 进一步验证文件有效性
|
||||
# if is_valid_video_file(save_path):
|
||||
# logger.info(f"视频文件已存在且有效,跳过下载: {save_path},文件大小: {file_size}字节")
|
||||
# return True
|
||||
# else:
|
||||
# logger.warning(f"发现无效视频文件,将重新下载: {save_path}")
|
||||
# # 删除无效文件
|
||||
# os.remove(save_path)
|
||||
# else:
|
||||
# logger.warning(f"发现空视频文件,将重新下载: {save_path}")
|
||||
# # 删除空文件
|
||||
# os.remove(save_path)
|
||||
#
|
||||
# # 构建标准TikTok视频URL
|
||||
# tiktok_url = f"https://www.tiktok.com/@{unique_id}/video/{video_id}"
|
||||
# logger.info(f"构建的TikTok URL: {tiktok_url}")
|
||||
#
|
||||
# # 构建完整的API请求URL
|
||||
# api_url = f"{API_BASE_URL}/api/download"
|
||||
# full_url = f"{api_url}?url={tiktok_url}&prefix=true&with_watermark=false"
|
||||
# logger.info(f"完整的API请求URL: {full_url}")
|
||||
#
|
||||
# try:
|
||||
# # 直接使用完整URL发送请求
|
||||
# response = requests.get(full_url, stream=True, timeout=60)
|
||||
#
|
||||
# # 检查响应状态
|
||||
# if response.status_code != 200:
|
||||
# logger.error(
|
||||
# f"下载视频失败: {response.status_code} - {response.text[:200] if response.text else '无响应内容'}")
|
||||
# return False
|
||||
#
|
||||
# # 获取内容类型
|
||||
# content_type = response.headers.get('Content-Type', '')
|
||||
# logger.info(f"响应内容类型: {content_type}")
|
||||
#
|
||||
# # 保存文件
|
||||
# with open(save_path, 'wb') as f:
|
||||
# for chunk in response.iter_content(chunk_size=8192):
|
||||
# if chunk:
|
||||
# f.write(chunk)
|
||||
#
|
||||
# file_size = os.path.getsize(save_path)
|
||||
# logger.info(f"视频已下载到: {save_path},文件大小: {file_size}字节")
|
||||
#
|
||||
# # 验证下载的文件是否有效
|
||||
# if is_valid_video_file(save_path):
|
||||
# logger.info(f"视频文件验证通过: {save_path}")
|
||||
# return True
|
||||
# else:
|
||||
# logger.error(f"下载的视频文件无效: {save_path}")
|
||||
# # 删除无效文件
|
||||
# if os.path.exists(save_path):
|
||||
# os.remove(save_path)
|
||||
# return False
|
||||
#
|
||||
# except Exception as e:
|
||||
# logger.error(f"下载视频异常: {e}")
|
||||
# import traceback
|
||||
# logger.error(f"详细错误: {traceback.format_exc()}")
|
||||
# return False
|
||||
#
|
||||
#
|
||||
# def analyze_videos_and_create_document(videos_folder, nickname, unique_id, sec_uid):
|
||||
# """
|
||||
# 分析视频目录并创建Yanxi文档
|
||||
#
|
||||
# Args:
|
||||
# videos_folder: 视频所在目录路径
|
||||
# nickname: 用户昵称
|
||||
# unique_id: TikTok用户ID
|
||||
# sec_uid: 用户的安全ID
|
||||
#
|
||||
# Returns:
|
||||
# str: 如果API调用成功返回document_id,否则返回None
|
||||
# """
|
||||
# try:
|
||||
# # 直接调用analyze_directory函数进行视频分析
|
||||
# from app.api.summary.summary import analyze_directory
|
||||
#
|
||||
# logger.info(f"开始分析视频目录: {videos_folder}")
|
||||
# analyze_result = analyze_directory(videos_folder)
|
||||
#
|
||||
# if analyze_result:
|
||||
# logger.info(f"分析成功")
|
||||
#
|
||||
# # 提取分析结果中的用户画像和聚合摘要
|
||||
# user_persona = analyze_result.get('user_persona', '')
|
||||
# content_summary = analyze_result.get('content_summary', '')
|
||||
#
|
||||
# content = f"{user_persona}\n\n{content_summary}"
|
||||
#
|
||||
# # 调用yanxi API创建文档
|
||||
# try:
|
||||
# yanxi_url = "http://localhost:8899/yanxi/api/dataset/231aaa42-fc97-11ef-a8ef-0242ac120006/document"
|
||||
# yanxi_data = {
|
||||
# "name": f"{nickname}@{unique_id}",
|
||||
# "paragraphs": [
|
||||
# {
|
||||
# "content": content,
|
||||
# "title": sec_uid,
|
||||
# "is_active": True
|
||||
# }
|
||||
# ]
|
||||
# }
|
||||
#
|
||||
# logger.info(f"调用Yanxi API: {yanxi_url}")
|
||||
# yanxi_response = requests.post(
|
||||
# yanxi_url,
|
||||
# json=yanxi_data,
|
||||
# headers={"Content-Type": "application/json"},
|
||||
# timeout=60
|
||||
# )
|
||||
#
|
||||
# if yanxi_response.status_code in [200, 201]:
|
||||
# response_data = yanxi_response.json()
|
||||
# document_id = response_data.get('data', {}).get('id')
|
||||
# if document_id:
|
||||
# logger.info(f"文档创建成功,document_id: {document_id}")
|
||||
# return document_id
|
||||
# else:
|
||||
# logger.error("文档创建成功但未获取到document_id")
|
||||
# return None
|
||||
# else:
|
||||
# logger.error(f"文档创建失败: {yanxi_response.status_code}, {yanxi_response.text}")
|
||||
# return None
|
||||
# except Exception as e:
|
||||
# logger.error(f"调用Yanxi API出错: {e}")
|
||||
# return None
|
||||
# else:
|
||||
# logger.error(f"分析失败")
|
||||
# return None
|
||||
# except Exception as e:
|
||||
# logger.error(f"视频分析出错: {e}")
|
||||
# return None
|
||||
#
|
||||
#
|
||||
# @csrf_exempt
|
||||
# @require_http_methods(["DELETE"])
|
||||
# def delete_tiktok_user(request):
|
||||
# """删除TikTok用户及其相关视频和文档"""
|
||||
# try:
|
||||
# data = json.loads(request.body)
|
||||
# sec_uid = data.get('sec_uid')
|
||||
#
|
||||
# if not sec_uid:
|
||||
# return JsonResponse({
|
||||
# 'status': 'error',
|
||||
# 'message': 'invalid params'
|
||||
# }, json_dumps_params={'ensure_ascii': False})
|
||||
#
|
||||
# try:
|
||||
# user = TiktokUserVideos.objects.get(sec_user_id=sec_uid)
|
||||
# except TiktokUserVideos.DoesNotExist:
|
||||
# return JsonResponse({
|
||||
# 'status': 'error',
|
||||
# 'message': f'用户 {sec_uid} 不存在'
|
||||
# }, json_dumps_params={'ensure_ascii': False})
|
||||
#
|
||||
# # 获取必要信息
|
||||
# videos_folder = user.videos_folder
|
||||
# document_id = user.document_id
|
||||
#
|
||||
# # 1. 删除视频文件夹
|
||||
# if videos_folder and os.path.exists(videos_folder):
|
||||
# try:
|
||||
# shutil.rmtree(videos_folder)
|
||||
# logger.info(f"成功删除视频文件夹: {videos_folder}")
|
||||
# except Exception as e:
|
||||
# logger.error(f"删除视频文件夹失败: {e}")
|
||||
#
|
||||
# # 2. 删除文档
|
||||
# if document_id:
|
||||
# try:
|
||||
# delete_url = f"http://localhost:8899/yanxi/api/dataset/231aaa42-fc97-11ef-a8ef-0242ac120006/document/{document_id}"
|
||||
# delete_response = requests.delete(
|
||||
# delete_url,
|
||||
# headers={"Content-Type": "application/json"},
|
||||
# timeout=30
|
||||
# )
|
||||
#
|
||||
# if delete_response.status_code in [200, 204]:
|
||||
# logger.info(f"成功删除文档: {document_id}")
|
||||
# else:
|
||||
# logger.error(f"删除文档失败: {delete_response.status_code}, {delete_response.text}")
|
||||
# except Exception as e:
|
||||
# logger.error(f"调用删除文档API出错: {e}")
|
||||
#
|
||||
# # 3. 删除数据库记录
|
||||
# user.delete()
|
||||
# logger.info(f"成功删除用户数据: {sec_uid}")
|
||||
#
|
||||
# return JsonResponse({
|
||||
# 'status': 'success',
|
||||
# 'message': f'成功删除用户 {sec_uid} 及其相关数据'
|
||||
# }, json_dumps_params={'ensure_ascii': False})
|
||||
#
|
||||
# except Exception as e:
|
||||
# logger.error(f"删除用户异常: {e}")
|
||||
# import traceback
|
||||
# logger.error(f"详细错误: {traceback.format_exc()}")
|
||||
# return JsonResponse({
|
||||
# 'status': 'error',
|
||||
# 'message': f'删除用户时发生错误: {str(e)}'
|
||||
# }, json_dumps_params={'ensure_ascii': False})
|
||||
|
||||
|
||||
@csrf_exempt
|
||||
@require_http_methods(["POST"])
|
||||
@ -765,29 +43,32 @@ def filter_creators(request):
|
||||
# 基础查询
|
||||
query = CreatorProfile.objects.all()
|
||||
|
||||
# Category 单选过滤
|
||||
# Category 多选过滤
|
||||
category = filter_data.get('category')
|
||||
if category and len(category) > 0:
|
||||
query = query.filter(category=category[0])
|
||||
query = query.filter(category__in=category)
|
||||
|
||||
# 电商能力等级过滤 (L1-L7),单选
|
||||
# 电商能力等级过滤 (L1-L7),多选
|
||||
e_commerce_level = filter_data.get('e_commerce_level')
|
||||
if e_commerce_level and len(e_commerce_level) > 0:
|
||||
level_str = e_commerce_level[0]
|
||||
level_nums = []
|
||||
for level_str in e_commerce_level:
|
||||
if level_str.startswith('L'):
|
||||
level_num = int(level_str[1:])
|
||||
query = query.filter(e_commerce_level=level_num)
|
||||
level_nums.append(int(level_str[1:]))
|
||||
if level_nums:
|
||||
query = query.filter(e_commerce_level__in=level_nums)
|
||||
|
||||
# 曝光等级过滤 (KOL-1, KOL-2, KOC-1等),单选
|
||||
# 曝光等级过滤 (KOL-1, KOL-2, KOC-1等),多选
|
||||
exposure_level = filter_data.get('exposure_level')
|
||||
if exposure_level and len(exposure_level) > 0:
|
||||
query = query.filter(exposure_level=exposure_level[0])
|
||||
query = query.filter(exposure_level__in=exposure_level)
|
||||
|
||||
# GMV范围过滤 ($0-$5k, $5k-$25k, $25k-$50k等),单选
|
||||
# GMV范围过滤 ($0-$5k, $5k-$25k, $25k-$50k等),多选
|
||||
gmv_range = filter_data.get('gmv_range')
|
||||
if gmv_range and len(gmv_range) > 0:
|
||||
gmv_q = Q()
|
||||
for gmv_val in gmv_range:
|
||||
gmv_min, gmv_max = 0, float('inf')
|
||||
gmv_val = gmv_range[0]
|
||||
if gmv_val == "$0-$5k":
|
||||
gmv_min, gmv_max = 0, 5
|
||||
elif gmv_val == "$5k-$25k":
|
||||
@ -801,12 +82,16 @@ def filter_creators(request):
|
||||
elif gmv_val == "$400k-$1500k":
|
||||
gmv_min, gmv_max = 400, 1500
|
||||
elif gmv_val == "$1500k+":
|
||||
gmv_min = 1500
|
||||
gmv_min, gmv_max = 1500, float('inf')
|
||||
|
||||
range_q = Q()
|
||||
if gmv_min > 0:
|
||||
query = query.filter(gmv__gte=gmv_min)
|
||||
range_q &= Q(gmv__gte=gmv_min)
|
||||
if gmv_max < float('inf'):
|
||||
query = query.filter(gmv__lte=gmv_max)
|
||||
range_q &= Q(gmv__lte=gmv_max)
|
||||
gmv_q |= range_q
|
||||
|
||||
query = query.filter(gmv_q)
|
||||
|
||||
# 观看量范围过滤,单选
|
||||
views_range = filter_data.get('views_range')
|
||||
|
BIN
requirements.txt
Normal file
BIN
requirements.txt
Normal file
Binary file not shown.
Loading…
Reference in New Issue
Block a user