| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230 |
- import math
- import random
- from typing import List, Dict, Optional
- #首页数据
- class indexData:
- def __init__(self):
- #提交的模板数据
- self.sectors_webSiteData = {
- "base": {
- "websiteId": ""
- },
- "style": {
- "styleId": ""
- },
- "template": {
- "index": [],
- "class": [],
- "list": [],
- "article": [],
- "search": [],
- "aloneList": [],
- "aloneArticle": []
- },
- "ad": {
- "top":{
- "width": 830,
- "height": 110,
- "name": "",
- "price": 0,
- "introduce":"",
- "website_id": "",
- "thumb": "http://img.bjzxtw.org.cn/pre/image/png/20250527/1748332370111555.png",
- "typeid": 2,
- "ad_tag": ""
- },
- "index": [],
- "class": [],
- "list": [],
- "article": [],
- "search": [],
- "aloneList": [],
- "aloneArticle": []
- },
- "isSearch": True
- }
- #提交的画布数据
- self.canvas_data = {
- "topAd":{
- "width": 830,
- "height": 110,
- "name": "",
- "price": "",
- "introduce": "",
- "website_id": "",
- "thumb": "http://192.168.1.234:19000/pre/image/jpeg/20251226/1766715237727691.jpg",
- "typeid": 2,
- "ad_tag": "",
- "ad_url": ""
- },
- "template":{
- "index":[],
- "class": [],
- "list": [],
- "article": [],
- "search": [],
- "aloneList": [],
- "aloneArticle": []
- }
- }
- #创建一个templateData实例
- templateData = indexData()
- # 动态权重计算类
- class Sector:
- def __init__(self, name: str, total: int, weight: int, CNname: str):
- self.name = name # 名称
- self.total = total # 总数
- self.weight = weight # 权重
- self.remaining = total # 剩余数量 后面我们要对比 剩余数据/总数 来计算权重
- self.used_count = 0 # 记录已使用次数
- self.CNname = CNname # 中文名称
- """
- 思路:
- 1.按照权限的高低选择通栏
- 2.如果权限一样,随机选择
- 3.每选择两次新闻通栏后,adSector权重提升
- """
- class SectorScheduler:
- def __init__(self, sectors_config: List[Dict]):
- # 过滤掉total为0的sector(即不存在的sector)
- self.sectors = [
- Sector(sector['name'], sector['total'], sector['weight'], sector['CNname'])
- for sector in sectors_config
- if sector['total'] > 0
- ]
- self.history = [] # 记录选择历史
- self.consecutive_count = 0 # 连续选择相同权重sector的次数
- self.last_weight = None # 上一次选择的权重
-
- # 定义需要随机选择的sector组
- self.random_sector_group = {sector['name'] for sector in sectors_config if sector.get('random', False)}
-
- def calculate_dynamic_weight(self, sector: Sector) -> float:
- """计算动态权重 - 更复杂的权重计算"""
- if sector.remaining <= 0:
- return 0
-
- base_weight = sector.weight
-
- # 1. 基于剩余数量的权重调整
- usage_ratio = sector.remaining / sector.total
- quantity_factor = math.pow(usage_ratio, 0.4) # 剩余数量越多,权重相对越高
-
- # 2. 基于使用频率的权重调整(避免过度使用)
- if sector.used_count > 0:
- usage_frequency = 1.0 / (1 + math.log(1 + sector.used_count))
- else:
- usage_frequency = 1.0
-
- # 3. 对于adSector的特殊处理
- if sector.name == "adSector":
- # 检查是否需要插入adSector(每两个相同权重后)
- if self.consecutive_count >= 2 and self.last_weight == 7:
- ad_boost = 2.0 # 大幅提升adSector权重
- else:
- # 根据历史中adSector的出现频率调整
- recent_ad_count = self.history[-3:].count("adSector") if len(self.history) >= 3 else 0
- if recent_ad_count == 0:
- ad_boost = 1.5 # 一段时间没出现,适当提升
- else:
- ad_boost = 0.8 # 最近出现较多,适当降低
- else:
- ad_boost = 1.0
-
- # 4. 对于高权重sector的保护(确保它们优先被选择)
- if base_weight >= 8:
- priority_boost = 1.5
- else:
- priority_boost = 1.0
-
- dynamic_weight = base_weight * quantity_factor * usage_frequency * ad_boost * priority_boost
-
- return dynamic_weight
-
- def get_random_sector_from_group(self, target_weight: int) -> Optional[Sector]:
- """从随机组中随机选择一个指定权重的sector"""
- available_sectors = [
- sector for sector in self.sectors
- if sector.name in self.random_sector_group
- and sector.weight == target_weight
- and sector.remaining > 0
- ]
-
- if available_sectors:
- return random.choice(available_sectors)
- return None
-
- def select_next(self) -> Optional[str]:
- """选择下一个sector"""
- best_sector = None
- best_weight = -1
-
- current_weight = 7 # 随机选择组的权重
-
- # 首先检查是否需要强制插入adSector
- if (self.consecutive_count >= 2 and self.last_weight == current_weight and
- any(s.name == "adSector" and s.remaining > 0 for s in self.sectors)):
-
- ad_sector = next(s for s in self.sectors if s.name == "adSector" and s.remaining > 0)
- ad_sector.remaining -= 1
- ad_sector.used_count += 1
-
- # 更新历史记录
- self.history.append("adSector")
- self.consecutive_count = 0
- self.last_weight = ad_sector.weight
-
- return "adSector"
-
- # 正常选择逻辑
- for sector in self.sectors:
- if sector.remaining > 0:
- # 对于随机选择组的sector,使用统一的权重计算
- if sector.name in self.random_sector_group and sector.weight == current_weight:
- # 使用组内统一的权重值进行比较
- dynamic_weight = current_weight
- else:
- dynamic_weight = self.calculate_dynamic_weight(sector)
-
- if dynamic_weight > best_weight:
- best_weight = dynamic_weight
- best_sector = sector
-
- if best_sector:
- # 如果最佳sector属于随机选择组,则随机选择该组中的一个
- if best_sector.name in self.random_sector_group and best_sector.weight == current_weight:
- random_sector = self.get_random_sector_from_group(current_weight)
- if random_sector:
- best_sector = random_sector
-
- best_sector.remaining -= 1
- best_sector.used_count += 1
-
- # 更新连续选择计数
- if self.last_weight == best_sector.weight and best_sector.name != "adSector":
- self.consecutive_count += 1
- else:
- self.consecutive_count = 1
-
- self.last_weight = best_sector.weight
- self.history.append(best_sector.name)
-
- return best_sector.name
-
- return None
-
- def generate_sequence(self, count: int) -> List[str]:
- """生成指定长度的序列"""
- result = []
- for i in range(count):
- next_sector = self.select_next()
- if next_sector:
- result.append(next_sector)
- else:
- break # 没有可选的sector了
- return result
|