Files
ai_mip/data_manager.py
2026-01-13 18:59:26 +08:00

281 lines
8.8 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import json
import random
from datetime import datetime
from typing import List, Dict, Optional
from pathlib import Path
from loguru import logger
from config import Config
class DataManager:
"""数据管理器负责URL和统计数据的存储与管理"""
def __init__(self, data_file: str = None):
self.data_file = data_file or str(Path(Config.DATA_DIR) / 'urls_data.json')
self._ensure_data_file()
self.data = self._load_data()
def _ensure_data_file(self):
"""确保数据文件存在"""
Config.ensure_dirs()
if not Path(self.data_file).exists():
self._save_data({'urls': {}})
def _load_data(self) -> Dict:
"""加载数据"""
try:
with open(self.data_file, 'r', encoding='utf-8') as f:
return json.load(f)
except Exception as e:
logger.error(f"加载数据文件失败: {str(e)}")
return {'urls': {}}
def _save_data(self, data: Dict = None):
"""保存数据"""
try:
save_data = data if data is not None else self.data
with open(self.data_file, 'w', encoding='utf-8') as f:
json.dump(save_data, f, ensure_ascii=False, indent=2)
except Exception as e:
logger.error(f"保存数据文件失败: {str(e)}")
def add_url(self, url: str) -> bool:
"""
添加新URL
Args:
url: MIP页面链接
Returns:
是否添加成功
"""
try:
if url in self.data['urls']:
logger.warning(f"URL已存在: {url}")
return False
# 生成随机目标点击次数
target_clicks = random.randint(Config.MIN_CLICK_COUNT, Config.MAX_CLICK_COUNT)
self.data['urls'][url] = {
'url': url,
'status': 'active', # active, completed, failed
'target_clicks': target_clicks,
'click_count': 0,
'reply_count': 0,
'created_time': datetime.now().isoformat(),
'last_click_time': None,
'click_history': []
}
self._save_data()
logger.info(f"成功添加URL目标点击次数: {target_clicks}")
return True
except Exception as e:
logger.error(f"添加URL失败: {str(e)}")
return False
def record_click(self, url: str, has_reply: bool = False):
"""
记录一次点击
Args:
url: URL
has_reply: 是否获得回复
"""
try:
if url not in self.data['urls']:
logger.error(f"URL不存在: {url}")
return
url_data = self.data['urls'][url]
url_data['click_count'] += 1
url_data['last_click_time'] = datetime.now().isoformat()
if has_reply:
url_data['reply_count'] += 1
# 记录点击历史
url_data['click_history'].append({
'time': datetime.now().isoformat(),
'has_reply': has_reply
})
self._save_data()
logger.info(f"记录点击成功,总点击次数: {url_data['click_count']}/{url_data['target_clicks']}")
except Exception as e:
logger.error(f"记录点击失败: {str(e)}")
def mark_url_completed(self, url: str):
"""
标记URL为已完成
Args:
url: URL
"""
try:
if url not in self.data['urls']:
logger.error(f"URL不存在: {url}")
return
self.data['urls'][url]['status'] = 'completed'
self.data['urls'][url]['completed_time'] = datetime.now().isoformat()
self._save_data()
logger.info(f"URL已完成: {url}")
except Exception as e:
logger.error(f"标记URL完成失败: {str(e)}")
def mark_url_failed(self, url: str, reason: str = ""):
"""
标记URL为失败
Args:
url: URL
reason: 失败原因
"""
try:
if url not in self.data['urls']:
logger.error(f"URL不存在: {url}")
return
self.data['urls'][url]['status'] = 'failed'
self.data['urls'][url]['failed_reason'] = reason
self.data['urls'][url]['failed_time'] = datetime.now().isoformat()
self._save_data()
logger.warning(f"URL标记为失败: {url}, 原因: {reason}")
except Exception as e:
logger.error(f"标记URL失败状态失败: {str(e)}")
def get_active_urls(self) -> List[Dict]:
"""
获取所有活跃的URL
Returns:
活跃URL列表
"""
try:
active_urls = [
data for data in self.data['urls'].values()
if data['status'] == 'active'
]
return active_urls
except Exception as e:
logger.error(f"获取活跃URL失败: {str(e)}")
return []
def get_url_info(self, url: str) -> Optional[Dict]:
"""
获取URL详细信息
Args:
url: URL
Returns:
URL信息
"""
return self.data['urls'].get(url)
def get_all_urls(self) -> List[Dict]:
"""
获取所有URL
Returns:
所有URL列表
"""
return list(self.data['urls'].values())
def get_statistics(self) -> Dict:
"""
获取统计数据
Returns:
统计数据
"""
try:
total_urls = len(self.data['urls'])
active_urls = sum(1 for data in self.data['urls'].values() if data['status'] == 'active')
completed_urls = sum(1 for data in self.data['urls'].values() if data['status'] == 'completed')
failed_urls = sum(1 for data in self.data['urls'].values() if data['status'] == 'failed')
total_clicks = sum(data['click_count'] for data in self.data['urls'].values())
total_replies = sum(data['reply_count'] for data in self.data['urls'].values())
stats = {
'total_urls': total_urls,
'active_urls': active_urls,
'completed_urls': completed_urls,
'failed_urls': failed_urls,
'total_clicks': total_clicks,
'total_replies': total_replies,
'reply_rate': f"{(total_replies / total_clicks * 100) if total_clicks > 0 else 0:.2f}%"
}
return stats
except Exception as e:
logger.error(f"获取统计数据失败: {str(e)}")
return {}
def delete_url(self, url: str) -> bool:
"""
删除URL
Args:
url: URL
Returns:
是否删除成功
"""
try:
if url in self.data['urls']:
del self.data['urls'][url]
self._save_data()
logger.info(f"已删除URL: {url}")
return True
else:
logger.warning(f"URL不存在: {url}")
return False
except Exception as e:
logger.error(f"删除URL失败: {str(e)}")
return False
def reset_url(self, url: str) -> bool:
"""
重置URL状态重新开始点击
Args:
url: URL
Returns:
是否重置成功
"""
try:
if url not in self.data['urls']:
logger.warning(f"URL不存在: {url}")
return False
# 生成新的随机目标点击次数
target_clicks = random.randint(Config.MIN_CLICK_COUNT, Config.MAX_CLICK_COUNT)
self.data['urls'][url]['status'] = 'active'
self.data['urls'][url]['target_clicks'] = target_clicks
self.data['urls'][url]['click_count'] = 0
self.data['urls'][url]['reply_count'] = 0
self.data['urls'][url]['last_click_time'] = None
self.data['urls'][url]['click_history'] = []
self.data['urls'][url]['reset_time'] = datetime.now().isoformat()
self._save_data()
logger.info(f"已重置URL: {url}")
return True
except Exception as e:
logger.error(f"重置URL失败: {str(e)}")
return False