diff --git a/pkg/dash/app_html.py b/pkg/dash/app_html.py
index df8f2b6..b3c5dcc 100644
--- a/pkg/dash/app_html.py
+++ b/pkg/dash/app_html.py
@@ -160,7 +160,15 @@ def layout_config(app):
dcc.Tab(label='Heatmap(1-day)', value='one_day_heatmap'),
]),
html.Div(id='tabs-content'),
+ dcc.Input(
+ id='target-input',
+ type='number',
+ placeholder='输入 Target 值',
+ value=None,
+ style={'marginTop': '10px', 'width': '50%'}
+ ),
], style={'marginLeft': '50px'}),
+
dcc.Interval(id='clock-interval', interval=1000, n_intervals=0)
])
return app
diff --git a/pkg/dash/func/info.py b/pkg/dash/func/info.py
index 7694004..b07f5d9 100644
--- a/pkg/dash/func/info.py
+++ b/pkg/dash/func/info.py
@@ -1,5 +1,5 @@
import pytz
-from pkg.tool import get_tweets_since_last_friday, format_time_str, get_time_since_last_tweet
+from pkg.tool import get_tweets_since_last_friday, format_time_str, get_time_since_last_tweet, get_hourly_weighted_array
from pkg.dash.app_init import app
from dash.dependencies import Input, Output
from datetime import timedelta
@@ -9,19 +9,25 @@ from dash import html
@app.callback(
[Output('info-tooltip', 'children')],
- [Input('clock-interval', 'n_intervals')]
+ [Input('clock-interval', 'n_intervals'),
+ Input('target-input', 'value')]
)
-def update_info(n):
- # 获取所有指标
+def update_info(n, target_value):
pace = calculate_tweet_pace()
decline_rates = calculate_pace_decline_rate()
pace_increases = calculate_pace_increase_in_hour()
- _, days_to_next_friday = get_pace_params()
+ tweet_count, days_to_next_friday = get_pace_params()
+ remain_hours = days_to_next_friday * 24
+ now = tweet_count
table_style_border = {'textAlign': 'center', 'border': '1px solid white'}
table_style_c = {'textAlign': 'center'}
table_style_l = {'textAlign': 'left'}
- # First table for Pace
+ target = int(target_value) if target_value is not None else None
+ avg_tweets_per_day = calculate_avg_tweets_per_day(target, now, remain_hours) if target is not None else "未计算"
+ days_passed = 7 - days_to_next_friday
+ avg_tweets = round(tweet_count / days_passed, 2) if days_passed > 0 else 0
+
pace_table_rows = [
html.Tr([
html.Th('Pace', style=table_style_border),
@@ -66,6 +72,22 @@ def update_info(n):
html.Td("1.Check Reply",
colSpan=7,
style=table_style_l)
+ ]),
+ html.Tr([
+ html.Td(f"Target: {target if target else '[未设置]'}",
+ colSpan=4,
+ style=table_style_c),
+ html.Td(f"Need's Avg Tweets Per Day: {avg_tweets_per_day}",
+ colSpan=4,
+ style=table_style_l)
+ ]),
+ html.Tr([
+ html.Td(f"Avg Tweets: {avg_tweets}",
+ colSpan=4,
+ style=table_style_c),
+ html.Td("", # 右侧留空,与上一行对齐
+ colSpan=4,
+ style=table_style_l)
])
]
pace_table = html.Table(pace_table_rows, style={
@@ -114,6 +136,42 @@ def calculate_pace_increase_in_hour():
new_tweet_count = tweet_count + increment
new_pace = (new_tweet_count / (7 - future_days)) * future_days + new_tweet_count
pace_increase = new_pace - current_pace
- # Add current pace to the increase value
pace_increases[f'increase_{increment}'] = round(current_pace + pace_increase, 2)
return pace_increases
+
+
+def calculate_avg_tweets_per_day(target, now, remain):
+ Xi = get_hourly_weighted_array()
+ if remain <= 0:
+ return "剩余时间不足,无法计算"
+ if target <= now:
+ return "目标已达成,无需额外发帖"
+
+ fx = max(remain - 12, 0)
+
+ if remain > 12:
+ fy = sum(Xi[0:12]) * 24
+ else:
+ full_hours = int(remain)
+ fractional_hour = remain - full_hours
+ if full_hours >= 24:
+ print(f"Debug: full_hours={full_hours} exceeds 24, capping at 23")
+ full_hours = 23
+ fractional_hour = 0 # 如果超过24小时,小数部分忽略
+
+ if full_hours < 0:
+ print(f"Debug: full_hours={full_hours} is negative, setting to 0")
+ full_hours = 0
+
+ if full_hours > 0:
+ fy = sum(Xi[0:full_hours]) + Xi[full_hours] * fractional_hour
+ else:
+ fy = Xi[0] * fractional_hour
+ fy *= 24
+
+ if fx + fy == 0:
+ return "计算无效,请检查剩余时间"
+
+ result = (target - now) / ((fx + fy) / 24)
+ print(f"Debug: fx={fx}, fy={fy}, result={result}")
+ return round(result, 2)
\ No newline at end of file
diff --git a/pkg/dash/func/render.py b/pkg/dash/func/render.py
index 5b831e9..2cdc5f8 100644
--- a/pkg/dash/func/render.py
+++ b/pkg/dash/func/render.py
@@ -112,13 +112,18 @@ def render_tab_content(tab, selected_dates, interval, time_zones, days_to_displa
x_labels = [f"{i * interval:02d}" for i in range(intervals_per_hour)]
+ rate_values = [[z_values[h][i] / tweet_count_total if tweet_count_total > 0 else 0
+ for i in range(intervals_per_hour)]
+ for h in range(24)]
+
fig = go.Figure(data=go.Heatmap(
z=z_values,
x=x_labels,
y=[f"{h:02d}" for h in hours],
colorscale='Viridis',
hoverongaps=False,
- hovertemplate='%{y}:%{x} EST
Tweets: %{z}'
+ customdata=rate_values,
+ hovertemplate='%{y}:%{x} EST
Tweets: %{z}
Rate: %{customdata:.2%}'
))
if tab in ['line', 'one_day_heatmap']:
diff --git a/pkg/tool.py b/pkg/tool.py
index bcc8eb7..a7c92d6 100644
--- a/pkg/tool.py
+++ b/pkg/tool.py
@@ -94,4 +94,34 @@ def format_time_str(days_to_next_friday):
minutes = int((total_seconds % (60 * 60)) // 60)
seconds = int(total_seconds % 60)
total_hours = round(days_to_next_friday * 24, 2)
- return f"{days}d {hours:02d}h {minutes:02d}m {seconds:02d}s ({total_hours}h)"
\ No newline at end of file
+ return f"{days}d {hours:02d}h {minutes:02d}m {seconds:02d}s ({total_hours}h)"
+
+
+def get_hourly_weighted_array():
+ est = pytz.timezone('US/Eastern')
+ now = datetime.now(est).date()
+ last_7_days = [now - timedelta(days=i) for i in range(7)]
+
+ multi_data_agg = render_data.global_agg_df[
+ render_data.global_agg_df['date'].isin(last_7_days)].copy()
+
+ if multi_data_agg.empty:
+ return [1 / 24] * 24
+
+ agg_data = aggregate_data(multi_data_agg, 60)
+ one_day_data = agg_data.groupby('interval_group')['tweet_count'].sum().reset_index()
+ tweet_count_total = one_day_data['tweet_count'].sum()
+
+ hourly_rates = [0] * 24
+ for _, row in one_day_data.iterrows():
+ minute = row['interval_group']
+ hour = int(minute // 60)
+ if hour < 24:
+ hourly_rates[hour] = row['tweet_count'] / tweet_count_total if tweet_count_total > 0 else 0
+
+ total_rate = sum(hourly_rates)
+ if total_rate > 0:
+ hourly_rates = [rate / total_rate for rate in hourly_rates]
+ else:
+ hourly_rates = [1 / 24] * 24
+ return hourly_rates
\ No newline at end of file
diff --git a/plan.md b/plan.md
index f700518..d01c7ae 100644
--- a/plan.md
+++ b/plan.md
@@ -1,5 +1,7 @@
#### 后续
1. 考虑通过 tweets 数预测市场曲线的模型(人工智能)
2. 考虑elon jets的效果
+3. 推算出达到某个市场要求,这七天内的发帖情况应该是什么样的。
+4. peak点预期:人工智能预测peak时间段,并列举出peak情况对应市场期望。