| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692 |
- import math
- import random
- from typing import List, Dict, Optional
- #首页数据
- class indexData:
- def __init__(self):
- # 通栏权重设置
- self.sectors_config = [
- {"name": "headLineSector", "total": 1, "weight": 10 ,"CNname":"网站头条" , "random": False},
- {"name": "bannerSector", "total": 1, "weight": 9 ,"CNname":"焦点图" , "random": False},
- {"name": "linkSector", "total": 1, "weight": 8 ,"CNname":"外链面板" , "random": False},
- {"name": "manyPictureSector", "total": 2, "weight": 7 ,"CNname":"新闻图文组合1" , "random": True},
- {"name": "commentSector", "total": 2, "weight": 7 ,"CNname":"新闻图文组合2" , "random": True},
- {"name": "listSector", "total": 2, "weight": 7 ,"CNname":"新闻图文组合3" , "random": True},
- {"name": "onlyImgSector", "total": 2, "weight": 7 ,"CNname":"带广告新闻组合" , "random": True},
- {"name": "adSector", "total": 4, "weight": 6 ,"CNname":"通栏广告" , "random": False}
- ]
- # 通栏数据
- self.sectors_data = {
- #广告通栏
- "adSector": {
- "sectorName": "adSector",
- "sectorCanvasHeight": 12, #占据画布高度
- "componentList": [
- {
- "component_type": 2,
- "component_style": 1,
- "sort": 1,
- "componentData": {}
- }
- ],
- "ad": {
- "width": 1200,
- "height": 90,
- "name": "",
- "price": 0,
- "introduce":"",
- "website_id": "",
- "thumb": "https://img.bjzxtw.org.cn/pre/image/png/20250530/1748588901281358.png",
- "typeid": 2,
- "ad_tag": ""
- }
- },
- #头条通栏
- "headLineSector": {
- "sectorName": "headLineSector",
- "sectorCanvasHeight": 17,
- "componentList": [
- {
- "component_type": 1,
- "component_style": 1,
- "sort": 1,
- "componentData": {
- "level": 1,
- "imgSize": 0,
- "textSize": 4,
- "child": {
- "id": "",
- "imgSize": "",
- "textSize": ""
- },
- "listType": [
- "id",
- "title",
- "imgurl",
- "author",
- "updated_at",
- "introduce",
- "islink",
- "linkurl",
- "copyfrom",
- "cat_arr_id",
- "catid",
- "pinyin"
- ],
- }
- }
- ]
- },
- #轮播图通栏
- "bannerSector": {
- "sectorName": "bannerSector",
- "sectorCanvasHeight": 44,
- "componentList": [
- {
- "component_type": 1,
- "component_style": 1,
- "sort": 1,
- "componentData": {
- "level": 2,
- "imgSize": 5,
- "textSize": 0,
- "child": {
- "id": "",
- "imgSize": "",
- "textSize": ""
- },
- "listType": [
- "id",
- "title",
- "imgurl",
- "author",
- "updated_at",
- "introduce",
- "islink",
- "linkurl",
- "copyfrom",
- "cat_arr_id",
- "catid",
- "pinyin"
- ],
- }
- },
- {
- "component_type": 1,
- "component_style": 1,
- "sort": 2,
- "componentData": {
- "level": 6,
- "imgSize": 0,
- "textSize": 10,
- "child": {
- "id": "",
- "imgSize": "",
- "textSize": ""
- },
- "listType": [
- "id",
- "title",
- "imgurl",
- "author",
- "updated_at",
- "introduce",
- "islink",
- "linkurl",
- "copyfrom",
- "cat_arr_id",
- "catid",
- "pinyin"
- ],
- }
- }
- ]
- },
- #新闻组合通栏1
- "manyPictureSector": {
- "sectorName": "manyPictureSector",
- "sectorCanvasHeight": 47,
- "componentList": [
- {
- "component_type": 1,
- "component_style": 1,
- "sort": 1,
- "componentData": {
- "category_id":"",
- "category_arr":"",
- "name":"请选择导航..",
- "level":"",
- "imgSize": 3,
- "textSize": 9,
- "child":{
- "id":"",
- "imgSize": "",
- "textSize": ""
- },
- "listType": [
- "id",
- "title",
- "imgurl",
- "author",
- "updated_at",
- "introduce",
- "islink",
- "linkurl",
- "copyfrom",
- "cat_arr_id",
- "catid",
- "pinyin"
- ],
- }
- },
- {
- "component_type": 1,
- "component_style": 1,
- "sort": 2,
- "componentData": {
- "category_id":"",
- "category_arr":"",
- "name":"请选择导航..",
- "level":"",
- "imgSize": 3,
- "textSize": 6,
- "child":{
- "id":"",
- "imgSize": "",
- "textSize": ""
- },
- "listType": [
- "id",
- "title",
- "imgurl",
- "author",
- "updated_at",
- "introduce",
- "islink",
- "linkurl",
- "copyfrom",
- "cat_arr_id",
- "catid",
- "pinyin"
- ],
- }
- }
- ]
- },
- #新闻组合通栏2
- "commentSector": {
- "sectorName": "commentSector",
- "sectorCanvasHeight": 47,
- "componentList": [
- {
- "component_type": 1,
- "component_style": 1,
- "sort": 1,
- "componentData": {
- "category_id":"",
- "category_arr":"",
- "name":"请选择导航..",
- "level":"",
- "imgSize": 2,
- "textSize": 12,
- "child":{
- "id":"",
- "imgSize": "",
- "textSize": ""
- },
- "listType": [
- "id",
- "title",
- "imgurl",
- "author",
- "updated_at",
- "introduce",
- "islink",
- "linkurl",
- "copyfrom",
- "cat_arr_id",
- "catid",
- "pinyin"
- ],
- }
- },
- {
- "component_type": 1,
- "component_style": 1,
- "sort": 2,
- "componentData": {
- "category_id":"",
- "category_arr":"",
- "name":"请选择导航..",
- "level":"",
- "imgSize": 1,
- "textSize": 3,
- "child":{
- "id":"",
- "imgSize": "",
- "textSize": ""
- },
- "listType": [
- "id",
- "title",
- "imgurl",
- "author",
- "updated_at",
- "introduce",
- "islink",
- "linkurl",
- "copyfrom",
- "cat_arr_id",
- "catid",
- "pinyin"
- ],
- }
- }
- ]
- },
- #新闻组合通栏3
- "listSector": {
- "sectorName": "listSector",
- "sectorCanvasHeight": 98,
- "componentList": [
- {
- "component_type": 1,
- "component_style": 1,
- "sort": 1,
- "componentData": {
- "category_id":"",
- "category_arr":"",
- "name":"请选择导航..",
- "level":"",
- "imgSize": 2,
- "textSize": 6,
- "child":{
- "id":"",
- "imgSize": "",
- "textSize": ""
- },
- "listType": [
- "id",
- "title",
- "imgurl",
- "author",
- "updated_at",
- "introduce",
- "islink",
- "linkurl",
- "copyfrom",
- "cat_arr_id",
- "catid",
- "pinyin"
- ],
- }
- },
- {
- "component_type": 1,
- "component_style": 1,
- "sort": 2,
- "componentData": {
- "category_id":"",
- "category_arr":"",
- "name":"请选择导航..",
- "level":"",
- "imgSize": 2,
- "textSize": 14,
- "child":{
- "id":"",
- "imgSize": "",
- "textSize": ""
- },
- "listType": [
- "id",
- "title",
- "imgurl",
- "author",
- "updated_at",
- "introduce",
- "islink",
- "linkurl",
- "copyfrom",
- "cat_arr_id",
- "catid",
- "pinyin"
- ],
- }
- },
- {
- "component_type": 1,
- "component_style": 1,
- "sort": 3,
- "componentData": {
- "category_id":"",
- "category_arr":"",
- "name":"请选择导航..",
- "level":"",
- "imgSize": 7,
- "textSize": 0,
- "child":{
- "id":"",
- "imgSize": "",
- "textSize": ""
- },
- "listType": [
- "id",
- "title",
- "imgurl",
- "author",
- "updated_at",
- "introduce",
- "islink",
- "linkurl",
- "copyfrom",
- "cat_arr_id",
- "catid",
- "pinyin"
- ],
- }
- }
- ]
- },
- #广告新闻混合通栏
- "onlyImgSector": {
- "sectorName": "onlyImgSector",
- "sectorCanvasHeight": 51,
- "componentList": [
- {
- "component_type": 1,
- "component_style": 1,
- "sort": 1,
- "componentData": {
- "category_id":"",
- "category_arr":"",
- "name":"请选择导航..",
- "level":"",
- "imgSize": 3,
- "textSize": 4,
- "child":{
- "id":"",
- "imgSize": "",
- "textSize": ""
- },
- "listType": [
- "id",
- "title",
- "imgurl",
- "author",
- "updated_at",
- "introduce",
- "islink",
- "linkurl",
- "copyfrom",
- "cat_arr_id",
- "catid",
- "pinyin"
- ],
- }
- },
- ],
- "ad": {
- "width": 450,
- "height": 290,
- "name": "",
- "price": 0,
- "introduce":"",
- "website_id": "",
- "thumb": "http://img.bjzxtw.org.cn/pre/image/png/20250609/174945725555092.png",
- "typeid": 2,
- "ad_tag": ""
- }
- },
- #外链通栏
- "linkSector": {
- "sectorName": "linkSector",
- "sectorCanvasHeight": 26,
- "componentList": [
- {
- "component_type": 3,
- "component_style": 1,
- "sort": 1,
- "componentData": {}
- }
- ]
- },
- }
- #模板数据
- 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": []
- }
- }
- #初始化通栏权重
- def reset_sectors_config(self):
- self.sectors_config = [
- {"name": "headLineSector", "total": 1, "weight": 10 ,"CNname":"网站头条"},
- {"name": "bannerSector", "total": 1, "weight": 9 ,"CNname":"焦点图"},
- {"name": "linkSector", "total": 1, "weight": 8 ,"CNname":"外链面板"},
- {"name": "manyPictureSector", "total": 2, "weight": 7 ,"CNname":"新闻图文组合1"},
- {"name": "commentSector", "total": 2, "weight": 7 ,"CNname":"新闻图文组合2"},
- {"name": "listSector", "total": 2, "weight": 7 ,"CNname":"新闻图文组合3"},
- {"name": "onlyImgSector", "total": 2, "weight": 7 ,"CNname":"带广告新闻组合"},
- {"name": "adSector", "total": 4, "weight": 6 ,"CNname":"通栏广告"}
- ]
- #创建一个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
|