Merge branch 'dev'
This commit is contained in:
commit
ee7ff023df
@ -4,7 +4,6 @@ class WeatherArt < ApplicationRecord
|
||||
|
||||
belongs_to :city
|
||||
has_one_attached :image
|
||||
has_one_attached :image_with_watermark
|
||||
|
||||
has_many :visits, class_name: "Ahoy::Visit", foreign_key: :weather_art_id
|
||||
has_many :events, class_name: "Ahoy::Event", foreign_key: :weather_art_id
|
||||
@ -59,4 +58,145 @@ class WeatherArt < ApplicationRecord
|
||||
def image_url
|
||||
image.attached? ? image.blob : nil
|
||||
end
|
||||
|
||||
def webp_image
|
||||
return nil unless image.attached?
|
||||
|
||||
image.variant(
|
||||
format: "webp",
|
||||
saver: {
|
||||
quality: 100,
|
||||
strip: true, # 移除元数据以减小文件大小
|
||||
interlace: "plane" # 渐进式加载
|
||||
}
|
||||
)
|
||||
end
|
||||
|
||||
# 添加图片变体处理
|
||||
PREVIEW_DIMENSIONS = {
|
||||
big: [ 1792, 1024 ],
|
||||
medium: [ 896, 512 ],
|
||||
small: [ 448, 256 ]
|
||||
}.freeze
|
||||
def preview_image(size = :medium)
|
||||
return nil unless image.attached?
|
||||
|
||||
width, height = PREVIEW_DIMENSIONS[size] || PREVIEW_DIMENSIONS[:medium]
|
||||
|
||||
image.variant(
|
||||
resize_to_limit: [ width, height ],
|
||||
format: "webp",
|
||||
saver: {
|
||||
quality: 75,
|
||||
strip: true, # 移除元数据以减小文件大小
|
||||
interlace: "plane" # 渐进式加载
|
||||
}
|
||||
)
|
||||
end
|
||||
|
||||
def watermarked_image
|
||||
return nil unless image.attached?
|
||||
|
||||
overlay_text = create_overlay_text
|
||||
|
||||
image.variant(
|
||||
composite: [ {
|
||||
input: overlay_text,
|
||||
gravity: "southeast"
|
||||
} ]
|
||||
)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def create_overlay_text
|
||||
{
|
||||
create: {
|
||||
width: 400,
|
||||
height: 100,
|
||||
background: [ 0, 0, 0, 0.5 ] # 半透明黑色背景
|
||||
},
|
||||
"svg-overlay": %(
|
||||
<svg width="400" height="100">
|
||||
<text x="20" y="40"
|
||||
style="fill: white; font-family: Arial; font-size: 20px;">
|
||||
#{city.name} - #{weather_date.strftime('%Y-%m-%d')}
|
||||
</text>
|
||||
<text x="20" y="70"
|
||||
style="fill: white; font-family: Arial; font-size: 20px;">
|
||||
© todayaiweather.com
|
||||
</text>
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
end
|
||||
|
||||
def create_text_layer(font_size)
|
||||
text = [
|
||||
weather_date.strftime("%Y-%m-%d"),
|
||||
"#{temperature}°C, #{description}",
|
||||
"#{city.name}, #{city.country.name}, #{city.country.region.name}",
|
||||
"© todayaiweather.com"
|
||||
].join("\n")
|
||||
|
||||
{
|
||||
create: {
|
||||
width: 600,
|
||||
height: 200,
|
||||
background: [ 0, 0, 0, 0 ]
|
||||
},
|
||||
"svg-overlay": %(
|
||||
<svg width="600" height="200">
|
||||
<style>
|
||||
.text {
|
||||
font-family: Arial, sans-serif;
|
||||
font-size: #{font_size}px;
|
||||
}
|
||||
.shadow {
|
||||
fill: white;
|
||||
stroke: black;
|
||||
stroke-width: 2px;
|
||||
paint-order: stroke fill;
|
||||
}
|
||||
</style>
|
||||
<text x="20" y="#{font_size + 10}" class="text shadow">#{weather_date.strftime('%Y-%m-%d')}</text>
|
||||
<text x="20" y="#{font_size * 2 + 20}" class="text shadow">#{temperature}°C, #{description}</text>
|
||||
<text x="20" y="#{font_size * 3 + 30}" class="text shadow">#{city.name}, #{city.country.name}</text>
|
||||
<text x="20" y="#{font_size * 4 + 40}" class="text shadow">© todayaiweather.com</text>
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
end
|
||||
|
||||
def watermark_command(font_size:, stroke_width:, spacing:)
|
||||
date_str = weather_date.strftime("%Y-%m-%d")
|
||||
weather_info = "#{temperature}°C, #{description}"
|
||||
location_info = "#{city.name}, #{city.country.name}, #{city.country.region.name}"
|
||||
copyright = "© todayaiweather.com"
|
||||
|
||||
"gravity southeast " \
|
||||
"fill white " \
|
||||
"font Arial " \
|
||||
"pointsize #{font_size} " \
|
||||
"stroke black " \
|
||||
"strokewidth #{stroke_width} " \
|
||||
"text 30,#{spacing * 12} '#{copyright}' " \
|
||||
"text 30,#{spacing * 8} '#{location_info}' " \
|
||||
"text 30,#{spacing * 4} '#{weather_info}' " \
|
||||
"text 30,#{spacing} '#{date_str}'"
|
||||
end
|
||||
|
||||
def watermark_text
|
||||
date_str = weather_date.strftime("%Y-%m-%d")
|
||||
weather_info = "#{temperature}°C, #{description}"
|
||||
location_info = "#{city.name}, #{city.country.name}, #{city.country.region.name}"
|
||||
copyright = "© todayaiweather.com"
|
||||
|
||||
[
|
||||
"text 30,120 '#{copyright}'",
|
||||
"text 30,80 '#{location_info}'",
|
||||
"text 30,40 '#{weather_info}'",
|
||||
"text 30,0 '#{date_str}'"
|
||||
].join(" ")
|
||||
end
|
||||
end
|
||||
|
@ -3,6 +3,7 @@ class AiService
|
||||
@client = OpenAI::Client.new(
|
||||
access_token: Rails.application.credentials.openai.token,
|
||||
uri_base: Rails.application.credentials.openai.uri,
|
||||
log_errors: Rails.env.development?, # 只在开发环境下启用
|
||||
request_timeout: 240
|
||||
)
|
||||
end
|
||||
@ -47,8 +48,8 @@ class AiService
|
||||
def ask_ai(system_message, user_message)
|
||||
response = @client.chat(
|
||||
parameters: {
|
||||
model: "gpt-4",
|
||||
message:
|
||||
model: "gpt-4o",
|
||||
messages:
|
||||
[ {
|
||||
role: "System",
|
||||
content: system_message
|
||||
|
@ -31,8 +31,8 @@ class WeatherService
|
||||
pressure: data["pressure"].to_f,
|
||||
visibility: data["vis"].to_f,
|
||||
cloud: data["cloud"].to_f,
|
||||
description: data["text"],
|
||||
time: response["updateTime"]
|
||||
description: data["text"]
|
||||
# time: response["updateTime"]
|
||||
}
|
||||
end
|
||||
end
|
||||
|
@ -6,7 +6,7 @@
|
||||
<!-- 背景图像 -->
|
||||
<% if featured_art&.image&.attached? %>
|
||||
<div class="absolute inset-0 h-[40vh] overflow-hidden">
|
||||
<%= image_tag featured_art.image,
|
||||
<%= image_tag featured_art.webp_image.processed,
|
||||
class: "w-full h-full object-cover" %>
|
||||
<div class="absolute inset-0 bg-gradient-to-b from-base-100/30 via-base-100/60 to-base-100"></div>
|
||||
</div>
|
||||
@ -107,7 +107,7 @@
|
||||
<div class="card bg-base-100 shadow-xl hover:shadow-2xl transition-all duration-300 group overflow-hidden">
|
||||
<figure class="relative aspect-square overflow-hidden">
|
||||
<% if art.image.attached? %>
|
||||
<%= image_tag art.image,
|
||||
<%= image_tag art.preview_image.processed,
|
||||
class: "w-full h-full object-cover transform group-hover:scale-105 transition-transform duration-500" %>
|
||||
|
||||
<div class="absolute inset-0 bg-gradient-to-t from-black via-black/50 to-transparent opacity-0 group-hover:opacity-100 transition-opacity duration-300"></div>
|
||||
|
@ -5,7 +5,7 @@
|
||||
<div class="relative">
|
||||
<!-- 图片 -->
|
||||
<figure class="aspect-[16/9] overflow-hidden">
|
||||
<%= image_tag city.latest_weather_art.image,
|
||||
<%= image_tag city.latest_weather_art.preview_image.processed,
|
||||
class: "w-full h-full object-cover transform group-hover:scale-105 transition-transform duration-500" %>
|
||||
</figure>
|
||||
|
||||
|
@ -6,7 +6,7 @@
|
||||
<!-- 背景图像和渐变 -->
|
||||
<% if featured_art&.image&.attached? %>
|
||||
<div class="absolute inset-0 h-[60vh] overflow-hidden">
|
||||
<%= image_tag featured_art.image,
|
||||
<%= image_tag featured_art.webp_image.processed,
|
||||
class: "w-full h-full object-cover object-center" %>
|
||||
<div class="absolute inset-0 bg-gradient-to-b from-base-100/40 via-base-100/80 to-base-100"></div>
|
||||
</div>
|
||||
|
@ -2,7 +2,7 @@
|
||||
<!-- 背景效果 -->
|
||||
<% if @city.latest_weather_art&.image&.attached? %>
|
||||
<div class="fixed inset-0 -z-10">
|
||||
<%= image_tag @city.latest_weather_art.image,
|
||||
<%= image_tag @city.latest_weather_art.webp_image.processed,
|
||||
class: "absolute w-full h-full object-cover scale-110 filter blur-2xl opacity-25" %>
|
||||
<div class="absolute inset-0 bg-gradient-to-b from-base-200/90 to-base-200/70 backdrop-blur-md"></div>
|
||||
</div>
|
||||
@ -103,7 +103,7 @@
|
||||
<div class="card bg-base-100/80 backdrop-blur-sm shadow-xl hover:shadow-2xl transition-all duration-300 hover:-translate-y-1">
|
||||
<figure class="relative aspect-video overflow-hidden">
|
||||
<% if art.image.attached? %>
|
||||
<%= image_tag art.image,
|
||||
<%= image_tag art.preview_image.processed,
|
||||
class: "w-full h-full object-cover transform hover:scale-105 transition-transform duration-500" %>
|
||||
<div class="absolute bottom-0 left-0 right-0 p-4 bg-gradient-to-t from-black/70 to-transparent">
|
||||
<div class="flex items-center justify-between text-white">
|
||||
|
@ -27,15 +27,15 @@
|
||||
<figure class="relative lg:h-[30rem] h-auto overflow-hidden rounded-lg"> <!-- 添加圆角 -->
|
||||
<div class="gallery" data-controller="photo-swipe-lightbox">
|
||||
<div data-photo-swipe-lightbox-target="gallery" class="h-full">
|
||||
<% blob = @weather_art.image_blob %>
|
||||
<%= link_to rails_blob_path(blob),
|
||||
<% watermarked = @weather_art.webp_image.processed %>
|
||||
<%= link_to rails_blob_path(watermarked),
|
||||
data: {
|
||||
pswp_src: rails_blob_url(blob),
|
||||
pswp_src: rails_blob_url(watermarked),
|
||||
pswp_caption: 'Weather Art',
|
||||
pswp_width: 1792,
|
||||
pswp_height: 1024
|
||||
} do %>
|
||||
<%= image_tag @weather_art.image, class: "object-cover w-full h-full transition-transform transform hover:scale-105 ease-in-out" %>
|
||||
<%= image_tag @weather_art.preview_image(:big).processed, class: "object-cover w-full h-full transition-transform transform hover:scale-105 ease-in-out" %>
|
||||
<%#= image_tag @weather_art.watermarked_variant.processed , class: "object-cover w-full h-full transition-transform transform hover:scale-105 ease-in-out" %>
|
||||
<% end %>
|
||||
</div>
|
||||
|
@ -1,38 +1,85 @@
|
||||
class BatchGenerateWeatherArtsWorker
|
||||
include Sidekiq::Worker
|
||||
|
||||
GENERATION_INTERVAL = 36.hours
|
||||
MAX_DURATION = 50.minutes
|
||||
SLEEP_DURATION = 120.seconds
|
||||
BATCH_SIZE = 20
|
||||
|
||||
module ProcessType
|
||||
DO_NOTHING = 0
|
||||
GET_WEATHER_WITH_GENERATE_AI_ART = 1
|
||||
GET_WEATHER_ONLY = 2
|
||||
end
|
||||
DAILY_GENERATION_LIMIT = 50 # 每日生成图片上限
|
||||
|
||||
def perform(*args)
|
||||
start_time = Time.current
|
||||
cities_to_process = get_eligible_cities.shuffle.take(BATCH_SIZE)
|
||||
cities_to_process.each do |city|
|
||||
remaining_slots = calculate_remaining_slots
|
||||
return if remaining_slots <= 0
|
||||
|
||||
# 获取符合条件的城市并处理
|
||||
cities_to_process = select_cities(remaining_slots)&.shuffle
|
||||
print_cities_list(cities_to_process, start_time)
|
||||
process_cities(cities_to_process, start_time)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def calculate_remaining_slots
|
||||
today_generations = WeatherArt
|
||||
.where("DATE(created_at) = ?", Date.today)
|
||||
.where.not(image_attachment: nil)
|
||||
.count
|
||||
|
||||
[ DAILY_GENERATION_LIMIT - today_generations, 0 ].max
|
||||
end
|
||||
|
||||
def print_cities_list(cities, start_time)
|
||||
Rails.logger.info "Generate city task start at: #{start_time}"
|
||||
Rails.logger.info "Generate city list: "
|
||||
Rails.logger.info "======================================"
|
||||
Rails.logger.info "ID\tRegion\tCountry\tState\tName"
|
||||
cities.each do |city|
|
||||
Rails.logger.info "#{city.id}\t#{city&.country&.region&.name}\t#{city&.country&.name}\t#{city&.state&.name}\t#{city&.name}"
|
||||
end
|
||||
end
|
||||
|
||||
def select_cities(limit)
|
||||
cutoff_time = Time.current - GENERATION_INTERVAL
|
||||
|
||||
# 基础查询:排除最近生成过的城市
|
||||
base_query = City
|
||||
.joins("LEFT JOIN (
|
||||
SELECT city_id, MAX(created_at) as last_generation_time
|
||||
FROM weather_arts
|
||||
GROUP BY city_id
|
||||
) latest_arts ON cities.id = latest_arts.city_id")
|
||||
.where("latest_arts.last_generation_time IS NULL OR latest_arts.last_generation_time < ?", cutoff_time)
|
||||
|
||||
# 优先选择活跃城市
|
||||
active_cities = base_query
|
||||
.where(active: true)
|
||||
.order(:priority)
|
||||
.limit(limit)
|
||||
.to_a
|
||||
|
||||
remaining_slots = limit - active_cities.size
|
||||
|
||||
if remaining_slots > 0
|
||||
# 如果还有剩余名额,从其他城市中随机选择
|
||||
other_cities = base_query
|
||||
.where.not(id: active_cities.map(&:id))
|
||||
.order("RANDOM()")
|
||||
.limit(remaining_slots)
|
||||
.to_a
|
||||
|
||||
active_cities + other_cities
|
||||
else
|
||||
active_cities
|
||||
end
|
||||
end
|
||||
|
||||
def process_cities(cities, start_time)
|
||||
cities.each do |city|
|
||||
break if Time.current - start_time > MAX_DURATION
|
||||
|
||||
Rails.logger.info "Generating weather art for #{city.name}"
|
||||
GenerateWeatherArtWorker.perform_async(city.id)
|
||||
sleep SLEEP_DURATION
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def get_eligible_cities
|
||||
cutoff_time = Time.current - GENERATION_INTERVAL
|
||||
City.active
|
||||
.joins("LEFT JOIN (
|
||||
SELECT city_id, MAX(created_at) as last_generation_time
|
||||
FROM weather_arts
|
||||
GROUP BY city_id
|
||||
) latest_arts ON cities.id = latest_arts.city_id")
|
||||
.where("latest_arts.last_generation_time IS NULL OR latest_arts.last_generation_time < ?", cutoff_time)
|
||||
.order(:priority)
|
||||
end
|
||||
end
|
||||
|
@ -14,6 +14,7 @@ class GenerateWeatherArtWorker
|
||||
return unless image_url
|
||||
|
||||
create_weather_art(weather_data, prompt, image_url)
|
||||
Rails.logger.info "Successful Generate Weather Art In #{city.name}"
|
||||
rescue StandardError => e
|
||||
Rails.logger.error "Error generating weather art for city #{city_id}: #{e.message}"
|
||||
Rails.logger.error e.backtrace.join("\n")
|
||||
|
@ -1 +1 @@
|
||||
WIRCFJoA1YUpdSuljSkBqEJvBpftvTRGA73T9Oy9vXNnOIHcnZDHtlhh2VuF4Xtq41d0aPJ2qPI4kUeGzM34I6FITsSY6i1y5ZEW4vUa8F/BRTO0/viXBPiSAS+BkWVEWYrFkNWJAIitVLG0hq8vCBEEs/KctxY8w9h0LwgyRV2udPzn6A7wyoJhR/V5nRamU6USFiHh6cpTlFQdSIZ0sC6v21IIS+G/ZPJXNNTw2+gVaDfL1yuX1nrLsxeMsb30iugksDj/gCVi42kF/hPVOGIZCM1ftM5j4Q+BcTDyEVqIMeXRdtegLKWM5sI0yB070m7gMRK1Oewa3z+NuPLGp1Stuuo977LGuATmP3/GnAMEZe8tgMfeKYeQv2+TerpLmO07KayOzN3j0qSs/OqrcSUP+SByxRBmpmeXNEQ6q+f1ZDreo/Q1Cm+aZe1UWXYpcgd6MVGHjYUna4SgTQqUKHKdzvf7Yx8fOjrzHRqZ6Y8LWq53Vzr8oNJ9IoNAh9TSJMF4tR3M+OQ7+SARgwQLoVsehgK1Z658GMvhVoeLrPTwvdID54+TSFMepMnownDJPZGKZoZK1+NlUyzz3rJ2iH9AxZnvwPMCcmlHH/Fh/FANmtQxd3DIPpjHHyZjxFLsR9tNuIapXPK8SiRhWbtYo+4i0/dgUvD8SfECSOklfx2tVIhvxTjg4AM+WtI9gieDISq+AZe9fjqyv8vLOJuDX8Nk1k69DKIqB2u+OFJW2/PPYFz2Ry283ep+VRKwS2qlsFEkTRkzPJ5y9dVrCXIYl0R7vgC+GDrUkK1IffZmTaJ+rqmzzwLF1OwPdtN/QuJm0aZZQmN9pQgUjt1PEgthQVW9dt/ElDZKgVjIcds3F1kX0+ZWJQRvBldilC9W5lRSea/9x253dw3wj1ERF6sZsIJCwcxTJigTM4rEfcjrMnEIfiW1HWc1LTJ5DUIh5GISBv7NDF52voP2TBamAq2Zg2vVg2v+bU9ydkkIVOm4oLYZWDQyDBeQC4KJscFCSo1ZxvRuqIRtnI3h2KoXJeK63cxGcVxbHcyYO5xTPXmPkk18pFPYoXe46an6xTEzxYXQMfWuIUvM9oOjgZXFvdgPwDWzL/pSZb6qW5MiDqvlt38ddivUtsZLMMtpgZjXOAyKQyIQNSOHyrrYoj6r8PdFiCZMWjn1B0HmXgIl47jrb9o1nrif9rb5DSUY2Pvl0+TeRnUB8r7Wa+t+UdHjrq6PEaXVOQbej78Rzo5xmZ5XknlbKv02Vjpcm8EIkc00nKvMo29f0mr1Wv48CL+tuDxiW3v2yX8NcTnMEoQkTTaw5wJmSb3dmPdVZwjcCdbqs1CbRpc/ngX7nJP9kF2P57BWqqYq6V4fWk3vEgLpTUsTCbJvTlCx7McLKy2/smtz2HQl6Vs5jofpSIXgNC35TBkPP22XLFiBTah0E2IUeF2TyuLphswQsMDzKzADMxkKpzEVNLCzzKfygDfsfsJqZjKBGHJz3RHDbGoqmgP/4u7FEBV9gUXFt5i5k71HxSnafbpcFkLk3AdfNLso2qUNZSj/8EzY33WFjQIEAFJeTqB8WML/LcVvNqQqvjUyUMgvA+rZq+BwS8svqJEvcRFmZhjeqQbsYs+C+jOlwjrohoak/CgfiHofuXWvnNyi0+PT6bPO5CsjbpJLwFxbPi19tWmnMR7ZOqIE3vN4bf8Rjg4T5zhKKbgIU7wEP+i0u9p0zPFEa6EZMxp8/5q50EjXdlY/cHa/Sp05x2h8jhi1Trxgg8yFOdu2P+dStAwW3Sv4x2o=--aZKHys4Q3dCV2P+L--yEOdlrHAYleGIYmdKAB4FQ==
|
||||
mNiwLK27M1vAWefYLzYIiQO0jBJqqZ1Yo0T1YOcldA3YrQo+AVm1vImv7Nbc96N3OK4f782Q3lNp4mTPl0zUFjiWy2QN/VdBMN9B2uxcUXJIASCJMwDlrc+e2evD6dqUb/hTj0q2Hi/uMVuRBI1O/bDvxxBQma/4MyPgwm6uwnP2g1yLfiBkgveU72yc4tHHmzXwEoxtJa3VkVKus+QWwCyWe/ZKvoDF2RplQm7RYVXgsbNhSdTVfoGvH9ExKRZvKjzrXutLtXe4YpHiiLSisCQBLYqF/XptG86U/uFldtCcbcB6XX2psyrQxHmhdxHnucMSx35rvh4XrjPMNKDpCiYuvJepjaJzgPDRkxjf4txIUHnIs3p6lVto+b92vq2OGKAq/nUwTpAB46WVz4CNCI0Z+QHkbSZ05a6cHAkzBY1Z4uiwu7gM6AFN/jYOdDo6GzxrP6h/Msp3wmOgKiM8Ts1kysXNdJ6E8X8GHPNKfHLnyVnoVrJbY1GGv6oXu4WkIxAK5v6Mi10J0Sd6QQJuZYv2SKNCjXUtxrm4NFWd9DY3BMvF3TSDRU17riruPyJHCYKSqCQHobblC7Sr1lwcN3+CfOJqGXR66D0OH6DNiHwobxsyVSHzSePl5bVi9a44V+GtzDJ0fZQYOpVnzWOsMj++K89dz2qtruB7BSOQe9YAXGk+dk//XqUebz4fqYUiW79aj4M1DyFquapbcn+WpzmXFGuVORM2ZuQjUr0Glev8JMq95R4JIZkMDwm5/q7YUbqEb25yMdhs5c48vmCIy3itliieWN9kYZO6pqIsP73KXms2Xi5nJ+FcaFQ9T24zs/S9JcA1a2KUl6n8kYBcVYBdNBvE+9ab+eJ3RUp3YMOErmMHAtTsUXQCZLmXpRheaaOkupS/XB+M+jYgYLI6+sv86ISZsYz472iT9UMCn5F/X8lNIwDClPoJP2kafLDq6hMlo76Oa/aVj+miy7tJIWFgVvMJ3VwPf526MMZgNShF6tZ+Z7PA0pr+9WuoZSyQ0Ai9lql/Tk+r2ZUPT6Z28qjGr9ln2jbb509ETwhSxnHjINskNyLmfFWUcELy+BEmOSn9GQgay0PoFkUrYpidpXD9Tw2IpEpklyIGhr4HFHv4bQ5uBWjPrIGm3R8fjATA0xB+Wg9SDPSHd+QclAzcL6Po8UlLIZfROjReg7ZJn5+8x0rf7UidNXTfy+JM0GmUR9aUh110RKE0u1WjdhhzdVDiQH2m58CZf3TsP3z4o8SLWfXAftqU8p3sBXPOV+L5RyWrUMzvWmDFzL0RmP854fOILsq76QoI4PULPHD7AIGaCHxuM+qmNQvYhFBMDCaHEeLP4ARX2NmUxMCT40T7bWEFbrAJ14Kd8L/EAjYVsGrBTWGZSvB3aZcZnP3cy4kC9XWvfAksstm9dPSqbxH7d8POb5KJBhSnfm5UWczc24s/6TC9UON921Shz3e9tk7bbBSBNIA/pHWmoZ8vFS3Cegihnt9TnALlWDBrGm7arYr3oQJHqkQ4KPEh36EwZDw/+YDaXLhN2yR8hL7nGPsewcwKdYEU4bGjTpI6xtjs0hBgwuMwTNWUsEm+bijt2feTxzJgUyT9ywW7aSsDfZi88J06LMJfpeAUIjhTjB9Coohk33lrpmsrD5Hb3RaObELlrpG6RkCHlmTxMTjTonS9ni+7dXUYJFYYvtLuyFmhSxEEk7bCrCMVkOWN5tTs0y0J22bxT/FrGLn/GKKlK/FVAeoGN8ZvEOCmIizEQ8k6wgAbuLDaTxV1irLLOeaY3JtjwVxBQHfNuCgxKXxd0zcUqv7D/sgMC0zafcqshG8VaXfGvFexWVEnZjPiZ6aHzeNMhdTPsf9D0p8R3PFgcvC2rSLYNbj2MXnvGqkrtQCre0CiNVxflVvOHbJjugdp5LqAjf6bssCsrZKifaRTPeg=--B6BEVJN27qT5bDUL--B4LzjOJ7SlzEKibq4VSVmg==
|
@ -1,7 +1,7 @@
|
||||
batch_generate_weather:
|
||||
cron: '0 8,18 * * *'
|
||||
class: BatchGenerateWeatherArtsWorker
|
||||
description: "Generate weather arts every 2 hours"
|
||||
description: "Batch Generate weather arts"
|
||||
enabled: true
|
||||
|
||||
refresh_sitemap:
|
||||
|
Loading…
Reference in New Issue
Block a user