1.▶️🔄

2.修改项目结构
This commit is contained in:
NY 2025-03-05 10:24:46 +08:00
parent 31b3a35c18
commit 2bf5cf28b7
22 changed files with 780 additions and 20846 deletions

View File

@ -1,28 +0,0 @@
# get-tweets
Get a user's tweets without an API key or doing any web scraping. This script uses web requests to get a user's tweets as if you were an unauthenticated user.
Data you get:
* Tweets (including retweets & replies)
* id
* text
* created_at
* retweet_count
* favorite_count
* reply_count
* quote_count
* retweeted
* is_quote_status
* possibly_sensitive
Requirements are:
* requests - To make the http requests to get the tweet data
# Usage
1. clone the repo
2. pip install -r requirements.txt
3. python get-tweets username --output name_of_file.csv

View File

@ -1,415 +0,0 @@
import dash
from dash import dcc, html
from dash.dependencies import Input, Output, State
import plotly.graph_objs as go
import pandas as pd
import pytz
from datetime import datetime, timedelta
from sqlalchemy import create_engine
from dash import clientside_callback
# Database connection configuration (unchanged)
DB_CONFIG = {
'host': '8.155.23.172',
'port': 3306,
'user': 'root2',
'password': 'tG0f6PVYh18le41BCb',
'database': 'elonX'
}
TABLE_NAME = 'elon_tweets'
db_uri = f"mysql+pymysql://{DB_CONFIG['user']}:{DB_CONFIG['password']}@{DB_CONFIG['host']}:{DB_CONFIG['port']}/{DB_CONFIG['database']}"
engine = create_engine(db_uri)
# Load data (unchanged)
df = pd.read_sql(f'SELECT timestamp FROM {TABLE_NAME}', con=engine)
eastern = pytz.timezone('America/New_York')
pacific = pytz.timezone('America/Los_Angeles')
central = pytz.timezone('America/Chicago')
df['datetime'] = pd.to_datetime(df['timestamp'], unit='s')
df['datetime_est'] = df['datetime'].dt.tz_localize('UTC').dt.tz_convert(eastern)
df['date'] = df['datetime_est'].dt.date
df['minute_of_day'] = df['datetime_est'].dt.hour * 60 + df['datetime_est'].dt.minute
agg_df = df.groupby(['date', 'minute_of_day']).size().reset_index(name='tweet_count')
all_dates = sorted(agg_df['date'].unique(), reverse=True)
default_date = [str(all_dates[0])]
# Initialize Dash app (unchanged)
external_stylesheets = ['/assets/bWLwgP.css']
app = dash.Dash(__name__, external_stylesheets=external_stylesheets)
# Time interval and days options (Modified: removed 1 day, added 120 and 240 days)
interval_options = [
{'label': '1 minute', 'value': 1},
{'label': '5 minutes', 'value': 5},
{'label': '10 minutes', 'value': 10},
{'label': '30 minutes', 'value': 30},
{'label': '60 minutes', 'value': 60}
]
days_options = [
{'label': '7 days', 'value': 7},
{'label': '30 days', 'value': 30},
{'label': '90 days', 'value': 90},
{'label': '120 days', 'value': 120},
{'label': '240 days', 'value': 240}
]
# Dash app layout (unchanged except default days value)
app.layout = html.Div([
# Left sidebar with clock button and tooltip (unchanged)
html.Div(
id='clock-container',
children=[
html.Div(
id='clock-button',
children='🕒',
style={
'fontSize': '24px',
'cursor': 'pointer',
'padding': '5px',
}
),
html.Div(
id='clock-tooltip',
children=[
html.Div(id='pst-clock'),
html.Div(id='cst-clock'),
html.Div(id='est-clock')
],
style={
'position': 'absolute',
'left': '35px',
'top': '0px',
'backgroundColor': 'rgba(0, 0, 0, 0.8)',
'color': 'white',
'padding': '10px',
'borderRadius': '5px',
'fontSize': '14px',
'display': 'none',
'whiteSpace': 'nowrap'
}
),
html.Div(
id='play-button',
children='▶️',
n_clicks=0,
style={
'fontSize': '24px',
'cursor': 'pointer',
'padding': '5px',
'marginTop': '10px'
}
)
],
style={
'position': 'fixed',
'left': '10px',
'top': '50%',
'transform': 'translateY(-50%)',
'zIndex': 1000
}
),
# Main content
html.Div([
html.H1("Elon Musk Tweet Time Analysis (EST)"),
html.Div(id='date-picker-container', children=[
dcc.Dropdown(
id='multi-date-picker',
options=[{'label': str(date), 'value': str(date)} for date in all_dates],
value=default_date,
multi=True,
searchable=True,
placeholder="Search and select dates (YYYY-MM-DD)",
style={'width': '100%'}
)
]),
dcc.Dropdown(
id='multi-interval-picker',
options=interval_options,
value=10,
style={'width': '50%', 'marginTop': '10px'}
),
html.Div(id='days-display-container', style={'display': 'none'}, children=[
dcc.Dropdown(
id='days-display-picker',
options=days_options,
value=30, # Default changed to 30 since 1 is removed
style={'width': '50%', 'marginTop': '10px'}
)
]),
html.Div(id='multi-day-warning', style={'color': 'red', 'margin': '10px'}),
dcc.Checklist(
id='time-zone-checklist',
options=[
{'label': 'California Time (PST)', 'value': 'PST'},
{'label': 'Texas Time (CST)', 'value': 'CST'}
],
value=['PST'],
style={'margin': '10px'}
),
html.Div(id='multi-tweet-summary', style={'fontSize': '20px', 'margin': '10px'}),
dcc.Tabs(id='tabs', value='line', children=[
dcc.Tab(label='Line Chart', value='line'),
dcc.Tab(label='Heatmap', value='heatmap'),
dcc.Tab(label='Scatter Plot', value='scatter'),
]),
html.Div(id='tabs-content'),
], style={'marginLeft': '50px'}),
dcc.Interval(id='clock-interval', interval=1000, n_intervals=0)
])
clientside_callback(
"""
function(n_intervals) {
const button = document.getElementById('clock-button');
const tooltip = document.getElementById('clock-tooltip');
if (button && tooltip) {
button.addEventListener('mouseover', () => {
tooltip.style.display = 'block';
});
button.addEventListener('mouseout', () => {
tooltip.style.display = 'none';
});
}
return window.dash_clientside.no_update;
}
""",
Output('clock-container', 'id'),
Input('clock-interval', 'n_intervals'),
prevent_initial_call=False
)
clientside_callback(
"""
function(n_clicks, existing_children) {
const button = document.getElementById('play-button');
if (!button) return '▶️';
if (n_clicks > 0) {
button.style.cursor = 'wait';
button.innerHTML = '🔄'; // 立即显示加载状态
setTimeout(() => {
button.innerHTML = ''; // 1秒后显示完成状态
button.style.cursor = 'pointer';
setTimeout(() => {
button.innerHTML = '▶️'; // 2秒后恢复初始状态
}, 2000);
}, 1000);
return '🔄'; // 返回当前状态
}
return '▶️'; // 默认状态
}
""",
Output('play-button', 'children'),
Input('play-button', 'n_clicks'),
State('play-button', 'children')
)
# Auxiliary functions (unchanged)
def aggregate_data(data, interval):
all_minutes = pd.DataFrame({'interval_group': range(0, 1440, interval)})
result = []
for date in data['date'].unique():
day_data = data[data['date'] == date].copy()
day_data['interval_group'] = (day_data['minute_of_day'] // interval) * interval
agg = day_data.groupby('interval_group').size().reset_index(name='tweet_count')
complete_data = all_minutes.merge(agg, on='interval_group', how='left').fillna({'tweet_count': 0})
complete_data['date'] = date
result.append(complete_data)
return pd.concat(result, ignore_index=True)
def generate_xticks(interval):
if interval <= 5:
tick_step = 60
elif interval <= 10:
tick_step = 60
elif interval <= 30:
tick_step = 120
else:
tick_step = 240
ticks = list(range(0, 1440, tick_step))
tick_labels = [f"{m // 60:02d}:{m % 60:02d}" for m in ticks]
return ticks, tick_labels
def minutes_to_time(minutes):
hours = minutes // 60
mins = minutes % 60
return f"{hours:02d}:{mins:02d}"
# Callback for updating clocks (unchanged)
@app.callback(
[Output('pst-clock', 'children'),
Output('cst-clock', 'children'),
Output('est-clock', 'children')],
[Input('clock-interval', 'n_intervals')]
)
def update_clocks(n):
now_utc = datetime.now(pytz.UTC)
pst_time = now_utc.astimezone(pacific).strftime('%Y-%m-%d %H:%M:%S PST')
cst_time = now_utc.astimezone(central).strftime('%Y-%m-%d %H:%M:%S CST')
est_time = now_utc.astimezone(eastern).strftime('%Y-%m-%d %H:%M:%S EST')
return f"𝕏: {pst_time}", f"🚀: {cst_time}", f"🏛️/🌴: {est_time}"
# Callback for toggling controls visibility (unchanged)
@app.callback(
[Output('date-picker-container', 'style'),
Output('days-display-container', 'style')],
[Input('tabs', 'value')]
)
def toggle_controls_visibility(tab):
if tab == 'heatmap':
return {'display': 'none'}, {'display': 'block'}
return {'display': 'block'}, {'display': 'none'}
# Callback for updating tabs content (Modified to add Thursday-Friday lines)
@app.callback(
[Output('tabs-content', 'children'),
Output('multi-day-warning', 'children'),
Output('multi-tweet-summary', 'children')],
[Input('tabs', 'value'),
Input('multi-date-picker', 'value'),
Input('multi-interval-picker', 'value'),
Input('time-zone-checklist', 'value'),
Input('days-display-picker', 'value')]
)
def render_tab_content(tab, selected_dates, interval, time_zones, days_to_display):
warning = ""
if tab != 'heatmap':
if len(selected_dates) > 10:
selected_dates = selected_dates[:10]
warning = "Maximum of 10 days can be selected. Showing first 10 selected days."
selected_dates = [datetime.strptime(date, '%Y-%m-%d').date() for date in selected_dates]
else:
selected_dates = sorted(all_dates, reverse=True)[:days_to_display]
multi_data_agg = agg_df[agg_df['date'].isin(selected_dates)].copy()
if multi_data_agg.empty:
multi_data_agg = pd.DataFrame({'date': selected_dates, 'minute_of_day': [0] * len(selected_dates)})
tweet_count_total = 0
else:
tweet_count_total = multi_data_agg['tweet_count'].sum()
multi_data_raw = df[df['date'].isin(selected_dates)].copy()
if multi_data_raw.empty:
tweet_count_total = 0
agg_data = aggregate_data(multi_data_agg, interval)
xticks, xtick_labels = generate_xticks(interval)
if tab == 'line':
fig = go.Figure()
for date in selected_dates:
day_data = agg_data[agg_data['date'] == date]
hover_times = [f"{date} {minutes_to_time(minute)} EST" for minute in day_data['interval_group']]
fig.add_trace(go.Scatter(
x=day_data['interval_group'],
y=day_data['tweet_count'],
mode='lines',
name=str(date),
customdata=hover_times,
hovertemplate='%{customdata}<br>Tweets: %{y}<extra></extra>'
))
elif tab == 'heatmap':
pivot_data = agg_data.pivot(index='date', columns='interval_group', values='tweet_count').fillna(0)
pivot_data.index = pivot_data.index.astype(str)
fig = go.Figure(data=go.Heatmap(
z=pivot_data.values,
x=[minutes_to_time(m) for m in pivot_data.columns],
y=pivot_data.index,
colorscale='Viridis',
hoverongaps=False,
hovertemplate='%{y} %{x} EST<br>Tweets: %{z}<extra></extra>'
))
for i, date_str in enumerate(pivot_data.index):
date = datetime.strptime(date_str, '%Y-%m-%d').date()
if date.weekday() == 4: # Friday
prev_date = date - timedelta(days=1)
if str(prev_date) in pivot_data.index:
y_position = i / len(pivot_data.index)
fig.add_hline(
y=1-y_position,
line_dash="dash",
line_color="white",
xref="x",
yref="paper"
)
fig.update_layout(
title = f'Tweet Heatmap (Interval: {interval} minutes, EST, {len(selected_dates)} days)',
xaxis_title = 'Time of Day (HH:MM EST)',
yaxis_title = 'Date',
height = max(400, len(selected_dates) * 20),
yaxis = dict(autorange='reversed')
)
elif tab == 'scatter':
fig = go.Figure()
for date in selected_dates:
day_data = multi_data_raw[multi_data_raw['date'] == date]
if not day_data.empty:
hover_times = [t.strftime('%Y-%m-%d %H:%M:%S EST') for t in day_data['datetime_est']]
fig.add_trace(go.Scatter(
x=day_data['minute_of_day'],
y=[str(date)] * len(day_data),
mode='markers',
name=str(date),
customdata=hover_times,
hovertemplate='%{customdata}<extra></extra>',
marker=dict(size=8)
))
if tab in ['line', 'scatter']:
if 'PST' in time_zones:
pacific_2am_est = (2 + 3) * 60
pacific_7am_est = (7 + 3) * 60
fig.add_vline(x=pacific_2am_est, line_dash="dash", line_color="blue", annotation_text="CA 2AM PST")
fig.add_vline(x=pacific_7am_est, line_dash="dash", line_color="blue", annotation_text="CA 7AM PST")
if 'CST' in time_zones:
central_2am_est = (2 + 1) * 60
central_7am_est = (7 + 1) * 60
fig.add_vline(x=central_2am_est, line_dash="dash", line_color="green", annotation_text="TX 2AM CST")
fig.add_vline(x=central_7am_est, line_dash="dash", line_color="green", annotation_text="TX 7AM CST")
if tab in ['line', 'scatter']:
fig.update_layout(
title=f'{"Line" if tab == "line" else "Scatter"} Tweet Frequency (Interval: {interval} minutes, EST)',
xaxis_title='Eastern Time (HH:MM)',
yaxis_title='Tweet Count' if tab == 'line' else 'Date',
xaxis=dict(range=[0, 1440], tickvals=xticks, ticktext=xtick_labels, tickangle=45),
height=600,
showlegend=True,
yaxis=dict(autorange='reversed') if tab == 'scatter' else None
)
summary = f"Total tweets for selected dates: {int(tweet_count_total)}"
return dcc.Graph(figure=fig), warning, summary
@app.callback(
Output('play-button', 'n_clicks'),
Input('play-button', 'n_clicks'),
prevent_initial_call=True
)
def execute_function(n_clicks):
if n_clicks > 0:
# Add your function to execute here
# For example:
print("Function executed!")
# Simulate some work
import time
time.sleep(1)
# Reset n_clicks to 0 to allow repeated clicks
return 0
# Run the app
if __name__ == '__main__':
app.run_server(debug=True)

View File

@ -9869,8 +9869,8 @@ rank_id,id,text,created_at
9868,1886471738273247567,"Another description for these types of payments is “money laundering” https://t.co/I2o6IZz98e","Feb 3, 12:48:06 PM EST"
9869,1886482300206244336,"🇺🇸🇺🇸 https://t.co/rim3JWWQOm","Feb 3, 1:30:04 PM EST"
9870,1886492712700141634,"The corrupt politicians “protesting” outside the USAID building are the ones getting money from USAID. Thats why theyre there they want your stolen tax dollars! https://t.co/5yVDqg0mjw","Feb 3, 2:11:26 PM EST"
9871,1886493949109657616,"RT @KanekoaTheGreat: @alrwashdeh_abed Shut it down","Feb 3, 2:16:21 PM EST"
9872,1886493947415195870,"RT @alrwashdeh_abed: @KanekoaTheGreat Thats my own opinion—&gt; maybe Im wrong🧐USAID should be shut down. Its the largest source of insta…","Feb 3, 2:16:21 PM EST"
9871,1886493947415195870,"RT @alrwashdeh_abed: @KanekoaTheGreat Thats my own opinion—&gt; maybe Im wrong🧐USAID should be shut down. Its the largest source of insta…","Feb 3, 2:16:21 PM EST"
9872,1886493949109657616,"RT @KanekoaTheGreat: @alrwashdeh_abed Shut it down","Feb 3, 2:16:21 PM EST"
9873,1886494235328962718,"RT @benhabib6: The @GreatBritishPAC is going to assist our politicians in delivering a proud independent sovereign and prosperous United Ki…","Feb 3, 2:17:29 PM EST"
9874,1886497226962403469,"💯 https://t.co/16w8MUYomb","Feb 3, 2:29:22 PM EST"
9875,1886497326862057858,"RT @HSajwanization: Please get verified on 𝕏 😡","Feb 3, 2:29:46 PM EST"
@ -12747,3 +12747,180 @@ rank_id,id,text,created_at
12746,1896442688779723184,"RT @SecRubio: Being a peacemaker is not a bad thing. We should be applauding and supporting @POTUS's efforts to bring about peace. https://…","Mar 3, 1:09:05 AM EST"
12747,1896442743871959218,"RT @SpaceX: Falcon 9 delivers 21 @Starlink satellites to the constellation from Florida https://t.co/6PMELtitXj","Mar 3, 1:09:18 AM EST"
12748,1896443306739110004,"Deservedly so https://t.co/T1KCXRMO22","Mar 3, 1:11:33 AM EST"
12749,1896454626855260658,"RT @cb_doge: All 7 Starship Launches https://t.co/psGsPgzwWG","Mar 3, 1:56:32 AM EST"
12750,1896455473496490300,"RT @FloydMayweather: 💪🏾 https://t.co/ARyfTVBCxW","Mar 3, 1:59:53 AM EST"
12751,1896456388781732113,"Wow https://t.co/nsmKkGkX5B","Mar 3, 2:03:32 AM EST"
12752,1896456775114838305,"RT @GadSaad: 100-fold greater.","Mar 3, 2:05:04 AM EST"
12753,1896457559755923750,"💯 https://t.co/o4lcaG30MX","Mar 3, 2:08:11 AM EST"
12754,1896458441386058093,"RT @chamath: @WarClandestine https://t.co/FKqre8kpHA","Mar 3, 2:11:41 AM EST"
12755,1896461656265556463,"RT @TheChiefNerd: MEGYN KELLY: “Last month on [CNNs] YouTube feed, they had 155M views and we were 147M … Just me and my six producers ver…","Mar 3, 2:24:28 AM EST"
12756,1896462253987389624,"RT @MarioNawfal: 🇺🇸 MEDIA TRUST HITS ALL-TIME LOW: ONLY 31% OF AMERICANS STILL BELIEVETrust in mass media has cratered to its lowest poin…","Mar 3, 2:26:50 AM EST"
12757,1896462663779291491,"RT @MarioNawfal: ELON: IM JUST TRYING TO KEEP CIVILIZATION GOINGJoe Rogan: “What kind of responsibility do you feel, knowing that if y…","Mar 3, 2:28:28 AM EST"
12758,1896462966549340213,"RT @thecoercednurse: 🤯 I wanted to see how @grok would analyze some of my medical imaging. I pulled a couple screen shots and asked, no med…","Mar 3, 2:29:40 AM EST"
12759,1896462993216647299,"RT @TheChiefNerd: I tested uploading multiple sets of bloodwork to @grok tonight and just WOW!! It not only explained the results but also…","Mar 3, 2:29:46 AM EST"
12760,1896463753908310216,"Yes https://t.co/dEI1igWlO8","Mar 3, 2:32:48 AM EST"
12761,1896464789242802259,"RT @Sadie_NC: The guy has time during a war to shoot a Vogue cover. This should tell you all you need to know about what is really going on…","Mar 3, 2:36:55 AM EST"
12762,1896465825424683239,"RT @RapidResponse47: .@SecRubio: ""The sooner everyone grows up around here and figures out that this is a bad war that's heading in a bad d…","Mar 3, 2:41:02 AM EST"
12763,1896466546610049210,"RT @cb_doge: “Each Raptor rocket engine produces twice as much thrust as all 4 engines on a 747. There are 33 Raptor engines powering the S…","Mar 3, 2:43:54 AM EST"
12764,1896468346155225554,"RT @FoxNews: 'Reagan' screenwriter claims Oscars' DEI requirements excluded film from Best Picture consideration https://t.co/SICeIS2nw2","Mar 3, 2:51:03 AM EST"
12765,1896470003387670554,"RT @davepl1968: #Grok3 just blew my mind. I'm attempting to set up (partition and format) an old SCSI drive on a 1980s PDP-11/73 connect…","Mar 3, 2:57:38 AM EST"
12766,1896474520124547370,"🎯 https://t.co/b2y1CgbAhx","Mar 3, 3:15:35 AM EST"
12767,1896522887127085085,"RT @CodeByPoonam: Grok 3 Voice Mode just dropped and it's INSANEEveryone on X is going crazy over its capabilities.Here are 7 wild exam…","Mar 3, 6:27:46 AM EST"
12768,1896609674587472297,"Starship is the first rocket/spaceship capable of making life multiplanetary, which requires it to be both far more powerful and far more advanced than anything that came before. https://t.co/8E6UPRwb8V","Mar 3, 12:12:38 PM EST"
12769,1896619960899948862,"A senior exec at Tesla sent me some funny pics from days in the factory where I was trying to show the construction team day shift what equipment wasnt working and needed to be removed.So, I spray-painted stick figures on them 😂 https://t.co/ZWoE2yvVs","Mar 3, 12:53:30 PM EST"
12770,1896620487046041778,"Zelensky wants a forever war, a never-ending graft meat grinder. This is evil. https://t.co/FVaEkIm7Gq","Mar 3, 12:55:36 PM EST"
12771,1896622963098865855,"🤨 https://t.co/RPQBtQE6j4","Mar 3, 1:05:26 PM EST"
12772,1896624661959709023,"🔥😂 https://t.co/WEUd8kUkTF","Mar 3, 1:12:11 PM EST"
12773,1896624753743733091,"RT @cb_doge: BREAKING: In just 6 weeks, DOGE has saved American taxpayers ~$105 billion! https://t.co/9j7p4hqvZe","Mar 3, 1:12:33 PM EST"
12774,1896624802968023441,"RT @PressSec: Remember when Joe Biden and Democrats said they needed a border bill to secure the border?President Trump did this in four…","Mar 3, 1:12:45 PM EST"
12775,1896625472957796612,"Imagine if that were to happen … oh it already has https://t.co/bFUfKZ2mCa","Mar 3, 1:15:25 PM EST"
12776,1896629486994821514,"RT @DonaldJTrumpJr: Instant classic.","Mar 3, 1:31:22 PM EST"
12777,1896630661118874001,"Still very few people know about this https://t.co/15DoFSmsRe","Mar 3, 1:36:01 PM EST"
12778,1896630890484338761,"The Tesla team did a great job clearing out the broken conveyor system within 48 hours!","Mar 3, 1:36:56 PM EST"
12779,1896633484686643516,"RT @TheRabbitHole84: Im hoping Trump mentions DOGE and cost cutting efforts for streamlining the government. Given that the United States…","Mar 3, 1:47:15 PM EST"
12780,1896633761720389905,"Improved efficiency https://t.co/EbygKLQ41y","Mar 3, 1:48:21 PM EST"
12781,1896639458478551297,"RT @charliekirk11: The Democrat exodus didnt stop in November. @MichaelPruser has been giving updates on voter registration at the state l…","Mar 3, 2:10:59 PM EST"
12782,1896639735696953753,"RT @DefiyantlyFree: Nancy Mace slams the left for being upset that DOGE and Elon Musk are finding 4 billion dollars a day in waste, fraud,…","Mar 3, 2:12:05 PM EST"
12783,1896639830198743123,"RT @BasedMikeLee: Judges arent presidents If they want to be they can run for that officeIts fine to be a judge Or a president Bu…","Mar 3, 2:12:28 PM EST"
12784,1896640340498772370,"RT @libsoftiktok: AOC lies claiming that the American people ""vehemently opposed"" to Elon cutting waste, fraud, and abuse from the federal…","Mar 3, 2:14:29 PM EST"
12785,1896640842250776740,"RT @DC_Draino: DOGE may have uncovered over $1 Trillion in Social Security fraud?!Over 73% of Americans approve of what DOGE is doing b/c…","Mar 3, 2:16:29 PM EST"
12786,1896641200796610863,"RT @WallStreetMav: DOGE has become one of the most popular aspects of the Trump Presidency.In order to make the changes long term, it nee…","Mar 3, 2:17:54 PM EST"
12787,1896643553964814449,"Shady https://t.co/EqPUqu4Jgf","Mar 3, 2:27:15 PM EST"
12788,1896643623040733528,"RT @WallStreetMav: 🎯 https://t.co/R4RzsNP3q9","Mar 3, 2:27:32 PM EST"
12789,1896644021306654823,"Grok successfully predicted all Oscar winners!Download the @Grok app and try voice mode! https://t.co/Dq0OLtMHrO","Mar 3, 2:29:07 PM EST"
12790,1896644332784058786,"RT @RapidResponse47: US Manufacturing Expands For Second Month Under Trump, Driven by Stronger Demand and Policy Shifts https://t.co/R7YtjE…","Mar 3, 2:30:21 PM EST"
12791,1896644396692672814,"RT @teslaeurope: Model 3 comes with lots of the same improvements that you love about New Model YAnd starts at ~40,000 EUR in many countr…","Mar 3, 2:30:36 PM EST"
12792,1896645680757866956,"RT @SERobinsonJr: Cybertruck via Cybertunnel https://t.co/rYI4GkgI1e","Mar 3, 2:35:42 PM EST"
12793,1896646083042021496,"Download the @Grok app https://t.co/ZUsM3kfnI9","Mar 3, 2:37:18 PM EST"
12794,1896653889296093313,"RT @MarshaBlackburn: For far too long federal bureaucrats abused the taxpayer and spent money like a drunken sailor.Those days have come…","Mar 3, 3:08:19 PM EST"
12795,1896659139704877259,"RT @RapidResponse47: .@POTUS: ""President Zelenskyy supposedly made a statement today -- He said he thinks the war is going to go on for a l…","Mar 3, 3:29:11 PM EST"
12796,1896660984762352079,"RT @fentasyl: Over $450,000,000 of HHS FY24 grant-funded projects contain terms used by the far-left to express their hatred -- Health Scie…","Mar 3, 3:36:31 PM EST"
12797,1896667792923099434,"True https://t.co/TE4OcZ66pc","Mar 3, 4:03:34 PM EST"
12798,1896668653833310573,"Interesting https://t.co/9hbztcM9wV","Mar 3, 4:07:00 PM EST"
12799,1896669877236273331,"Even JFK and Clinton! https://t.co/MmOanHopxY","Mar 3, 4:11:51 PM EST"
12800,1896671278494630128,"Interesting https://t.co/oBXMSlljCr","Mar 3, 4:17:25 PM EST"
12801,1896671341345906923,"RT @cb_doge: BREAKING: President Trump is more popular than ever as per the new approval tracker by the Daily Mail and JL Partners. 🇺🇸 http…","Mar 3, 4:17:40 PM EST"
12802,1896671937876877512,"RT @spacesudoer: Starship flight 8 mission profile. https://t.co/i1bkN8AFNx","Mar 3, 4:20:03 PM EST"
12803,1896692431955112344,"We had an ace up our sleeve @xAI. Turns out to be just enough to hold first place!Upgrades are in work to address presentation quality/style vs competition. That will shift ELO meaningfully higher. https://t.co/qr0HiUqv7R","Mar 3, 5:41:29 PM EST"
12804,1896692760926961928,"The NGOs are trying to destroy democracy! https://t.co/Kla23rPXHS","Mar 3, 5:42:47 PM EST"
12805,1896693369948311986,"True. As distasteful as it is, Zelensky should be offered some kind of amnesty in a neutral country in exchange for a peaceful transition back to democracy in Ukraine. https://t.co/ZpF6nLIDtw","Mar 3, 5:45:12 PM EST"
12806,1896694257865642411,"Major conflict of interest! https://t.co/ySLc2hl8Lt","Mar 3, 5:48:44 PM EST"
12807,1896694292875513910,"RT @SpaceX: The Starship team is go for prop load. Targeting 5:45pm CT for liftoff of Starships eighth flight test.The launch webcast wi…","Mar 3, 5:48:52 PM EST"
12808,1896694826462290180,"If you havent tried unhinged voice mode on the @Grok app, youre missing out 🤣🤣","Mar 3, 5:51:00 PM EST"
12809,1896695608720933024,"RT @Rothmus: 💯 https://t.co/cnfQ0fKGOd","Mar 3, 5:54:06 PM EST"
12810,1896696427046445109,"RT @RapidResponse47: 🚨 President Donald J. Trump announces a new $100 billion investment by TSMC in U.S. chips manufacturing https://t.co/2…","Mar 3, 5:57:21 PM EST"
12811,1896696896552583394,"RT @WhiteHouse: President Trumps Address to Congress Theme Reveal!THE RENEWAL OF THE AMERICAN DREAM 🇺🇸Tomorrow night, 9 PM ET! https:/…","Mar 3, 5:59:13 PM EST"
12812,1896697201109426293,"RT @MarioNawfal: 🚨GROK-3 CLAIMS TOP SPOT—xAI BEATS THE COMPETITIONGrok-3 just tied for #1 on the Arena AI leaderboard, proving its a pow…","Mar 3, 6:00:26 PM EST"
12813,1896697802002149867,"About 42 minutes until Starship Test Flight 8! https://t.co/ehwWcap7Uh","Mar 3, 6:02:49 PM EST"
12814,1896697983439347881,"RT @techdevnotes: Grok 3 is back on TOP!","Mar 3, 6:03:32 PM EST"
12815,1896699910550147242,"This would be cool https://t.co/OB05J4xi8c","Mar 3, 6:11:12 PM EST"
12816,1896703213434462640,"Raptor 3 has almost twice the thrust and much higher reliability than Raptor 1, despite costing about four times less! https://t.co/KfqMafJVKi","Mar 3, 6:24:19 PM EST"
12817,1896704523609190587,"RT @SpaceX: Starships flight trajectory for todays test https://t.co/UeshY3RHQf","Mar 3, 6:29:32 PM EST"
12818,1896705733028360315,"RT @SpaceX: In addition to continued infrastructure development at Starbase, Texas, where SpaceX is headquartered, SpaceX is expanding its…","Mar 3, 6:34:20 PM EST"
12819,1896718180695101800,"Too many question marks about this flight and then we were 20 bar low on ground spin start pressure. Best to destack, inspect both stages and try again in a day or two. https://t.co/TekpJ0uz5y","Mar 3, 7:23:48 PM EST"
12820,1896721195845955757,"$80M in ridiculous spending eliminated! https://t.co/CHnMwzp4vY","Mar 3, 7:35:47 PM EST"
12821,1896723100198445393,"Wow https://t.co/xWqI4gV4oQ","Mar 3, 7:43:21 PM EST"
12822,1896723180720660693,"RT @nicksortor: 🚨 #BREAKING: Democrats just BLOCKED the bill meant to protect women and girls in sportsWhen Democrats say theyre fightin…","Mar 3, 7:43:40 PM EST"
12823,1896723854518800497,"RT @RapidResponse47: The Protection of Women and Girls in Sports Act was just blocked in the Senate.Why do they want boys to play in your…","Mar 3, 7:46:20 PM EST"
12824,1896729318585508170,"RT @WhiteHouse: MEN DO NOT BELONG IN WOMENS SPORTS. https://t.co/iskbT6H3YU","Mar 3, 8:08:03 PM EST"
12825,1896729710635487570,"💯 https://t.co/rrrSKnNrEj","Mar 3, 8:09:37 PM EST"
12826,1896730225704411173,"Congratulations! 🇺🇸🇺🇸 https://t.co/hYEGFplkum","Mar 3, 8:11:40 PM EST"
12827,1896730644685992014,"RT @MarioNawfal: 🚨STEPHEN MILLER: TRUMP'S PRESIDENCY IS THE MOST SUCCESSFUL START IN HISTORY""President Trump is the greatest orator we've…","Mar 3, 8:13:19 PM EST"
12828,1896740517800817082,"RT @MarioNawfal: 🇺🇸🇺🇦DAVID SACKS: WE NEED TO AUDIT UKRAINE""There's definitely been Ukrainian officials who've been caught leaving the cou…","Mar 3, 8:52:33 PM EST"
12829,1896740708935193066,"RT @MarioNawfal: 🇺🇸🇺🇦DAVID SACKS: I DON'T THINK ZELENSKY WANTS PEACE""He says that the war needs to keep going on.If the war is over, he…","Mar 3, 8:53:19 PM EST"
12830,1896741246825295948,"https://t.co/OgrrcTyUVi","Mar 3, 8:55:27 PM EST"
12831,1896741410587738169,"Wow https://t.co/bZzShuUvTK","Mar 3, 8:56:06 PM EST"
12832,1896744422114832571,"RT @KanekoaTheGreat: NEW: David Sacks says Democrats now support endless war, Zelensky wants the war to never end, and Joe Biden could have…","Mar 3, 9:08:04 PM EST"
12833,1896757504459313663,"RT @JDVance: Hope is not a strategy to bring peace to Ukraine.The only person in town who seems to have a strategy is President Donald J.…","Mar 3, 10:00:03 PM EST"
12834,1896757802330444198,"RT @DOGE: The Office of Personnel Management (~2500 employees) budgeted $370M for IT spending in FY2025. They believe this value can be re…","Mar 3, 10:01:14 PM EST"
12835,1896763022238216246,"RT @SpaceX: To meet the growing global demand for high-speed internet, @Starlink is expanding its factory in Bastrop, Texas https://t.co/dx…","Mar 3, 10:21:59 PM EST"
12836,1896763362098417801,"🎯😂 https://t.co/KEpQCoCkhv","Mar 3, 10:23:20 PM EST"
12837,1896763814198317363,"RT @MarioNawfal: 🚨🇺🇸 SHELLENBERGER: DEMOCRATS ARE NOW THE PARTY OF 'NO, YOU CAN'T'""I dont think people believe Elon is doing this for mo…","Mar 3, 10:25:08 PM EST"
12838,1896764761343475832,"💯 https://t.co/6JbcywJEmU","Mar 3, 10:28:53 PM EST"
12839,1896776799461535825,"“Big Balls” lmaooo https://t.co/v0qmeibHDe","Mar 3, 11:16:44 PM EST"
12840,1896779474425032926,"So Senator Richard Blumenthal, aka “Dick”, really wants to meet “Big Balls”!!This is too good 🤣🤣 https://t.co/v0qmeibHDe","Mar 3, 11:27:21 PM EST"
12841,1896779767674028269,"🤦‍♂️ Taxpayer-funded propaganda! https://t.co/XZLdMzXCuc","Mar 3, 11:28:31 PM EST"
12842,1896780346567647347,"Unhinged @Grok is next-level 🤣🤣 https://t.co/yNzAVWROFu","Mar 3, 11:30:49 PM EST"
12843,1896781364017704978,"🇺🇸🇺🇸 https://t.co/hQT4TUhqui","Mar 3, 11:34:52 PM EST"
12844,1896782152668488122,"RT @MarioNawfal: 🚨🇺🇸 SCOTT JENNINGS: TRUMP IS MORE POPULAR THAN ANY DEMOCRAT—AND REPUBLICANS LOVE WHAT HES DOING""You guys keep trying to…","Mar 3, 11:38:00 PM EST"
12845,1896783829278589120,"RT @ablenessy: Give Grok Android Beta a try, let me know what you think.https://t.co/lMiIh1AR9F","Mar 3, 11:44:40 PM EST"
12846,1896784373799874931,"Maybe they should meet for tea …","Mar 3, 11:46:49 PM EST"
12847,1896788581068538340,"RT @cb_doge: You are the media now. https://t.co/nq4PHeM4vl","Mar 4, 12:03:33 AM EST"
12848,1896789742051787192,"RT @KristenWaggoner: The votes are in. Heres the difference between the American public &amp; U.S. Senate on who supports protecting womens s…","Mar 4, 12:08:09 AM EST"
12849,1896792179420570033,"RT @Truthful_ast: Oh man the two towers look sick https://t.co/KDez3z95cS","Mar 4, 12:17:50 AM EST"
12850,1896793979842421011,"RT @DOGE: Updated data on DEI related contract cancellations (separate from grants) by agency: https://t.co/mq7RkMCFEE","Mar 4, 12:25:00 AM EST"
12851,1896807731870527848,"Yeshttps://t.co/LNbqvhF5EK https://t.co/QZKrKnK1II","Mar 4, 1:19:38 AM EST"
12852,1896808067997807092,"RT @MarioNawfal: 🚨🇺🇸HUMAN SMUGGLING RING BUSTED IN LOS ANGELESThis wasnt just any smuggling ring—it was one of the biggest in U.S. histo…","Mar 4, 1:20:59 AM EST"
12853,1896809849360695411,"RT @TheGigaCast: Every Tesla EV sold in America was made in America 🇺🇸 https://t.co/ahwhsyQtLi","Mar 4, 1:28:03 AM EST"
12854,1896810342359126458,"Well, at least your federal tax dollars arent paying for it, just New York tax dollars pay for it now https://t.co/8MNQ3VllR8","Mar 4, 1:30:01 AM EST"
12855,1896810495581245772,"RT @libsoftiktok: Giant male in a MA school injured 3 girls during a girls basketball match. They ended the game early before he can hurt m…","Mar 4, 1:30:37 AM EST"
12856,1896813119999209477,"My post below was almost 2 years ago. Stop sending men to die for nothing. ENOUGH!! https://t.co/jpzqAbixtc","Mar 4, 1:41:03 AM EST"
12857,1896813706975351137,"This was asked of children. Stop this madness. https://t.co/u8Ha2QtAlY","Mar 4, 1:43:23 AM EST"
12858,1896816271569854684,"Yet another scam stealing your tax dollars has been stopped https://t.co/eyYfg7xemJ","Mar 4, 1:53:34 AM EST"
12859,1896816749288579522,"Fixed now. Just basic block and tackle stuff. https://t.co/4Jb23a9l3H","Mar 4, 1:55:28 AM EST"
12860,1896817607950655762,"RT @Regulawyer: A friend borrowed my Tesla with FSD for a week. Heres how it went: (Note: She has never been a Tesla enthusiast. Shes a…","Mar 4, 1:58:53 AM EST"
12861,1896822126516302132,"🚀 💫 https://t.co/03AXyhwBir","Mar 4, 2:16:50 AM EST"
12862,1896835926221037845,"RT @sdamico: This is ~ahead of the modal Chinese consumer electronics factory. Crazy that in the US only SpaceX and Tesla can do it.","Mar 4, 3:11:40 AM EST"
12863,1896842563098993114,"RT @libsoftiktok: DOGE canceled a $215 million contract for a Texas nonprofit which operated a housing facility for migrants.The housing…","Mar 4, 3:38:03 AM EST"
12864,1896842853839769839,"RT @MarioNawfal: 🚨🇷🇴EXCLUSIVE: ROMANIAN MEP - WE ARE NO LONGER A TRUE DEMOCRACYGeorgiana Teodorescu:""We had a huge protest in Romania t…","Mar 4, 3:39:12 AM EST"
12865,1896843688325869853,"RT @KingBobIIV: Remember in Orwells 1984 when, in the middle of Hate Week, Oceania suddenly switches its enemy? One minute, everyone is ra…","Mar 4, 3:42:31 AM EST"
12866,1896845309093020052,"RT @MarioNawfal: 🚨69 𝕏 MINUTES RAW. UNCENSORED. UNSTOPPABLE.Welcome to Episode 2 of 69 𝕏 Minutes—where no ones pulling the strings, no…","Mar 4, 3:48:58 AM EST"
12867,1896928784764596555,"RT @MarioNawfal: 🚨12 HOUR NEWS RECAP1. Trump paused all military aid to Ukraine, escalating tensions days after his heated Oval Office me…","Mar 4, 9:20:40 AM EST"
12868,1896929847798268162,"They are all actors reading a script https://t.co/wemW9tE9PR","Mar 4, 9:24:53 AM EST"
12869,1896930796310806835,"USAID was interfering in governments throughout the world and pushing radical left politics https://t.co/2qO9d3znnP","Mar 4, 9:28:39 AM EST"
12870,1896931790226612720,"Who is writing the words that the puppets speak? Thats the real question. https://t.co/N8kaTj8vPU","Mar 4, 9:32:36 AM EST"
12871,1896932070074823068,"RT @BasedMikeLee: Its almost like someones telling Democrats what to say","Mar 4, 9:33:43 AM EST"
12872,1896933830256398823,"Cant someone be bothered to write three speeches? This is just lazy 😂 https://t.co/Ih43iMPV9Z","Mar 4, 9:40:43 AM EST"
12873,1896939412522713221,"Exactly https://t.co/sdkuQLq258","Mar 4, 10:02:54 AM EST"
12874,1896939718081925259,"Its a valid point. The rules are asymmetric. https://t.co/XvKPmUQy6I","Mar 4, 10:04:06 AM EST"
12875,1896942909196472598,"RT @LisaSu: Huge step forward for advanced chip manufacturing in the U.S. We have seen great results as a lead customer @TSMC in Arizona a…","Mar 4, 10:16:47 AM EST"
12876,1896943837337235547,"True https://t.co/fM61ATI1GI","Mar 4, 10:20:28 AM EST"
12877,1896944271879721169,"💯 https://t.co/miRfUYCnkz","Mar 4, 10:22:12 AM EST"
12878,1896949130251084003,"RT @charliekirk11: Vice President @JDVance introduces Elbridge Colby to the Senate Armed Services Committee to become the 3rd highest ranki…","Mar 4, 10:41:30 AM EST"
12879,1896953284906393754,"Ok, so who is sending the social media interns of the politicians what to post? https://t.co/FdMBEn3Kh1","Mar 4, 10:58:01 AM EST"
12880,1896959643261493394,"Confirm @ElbridgeColby! https://t.co/u9HmvXNlkA","Mar 4, 11:23:17 AM EST"
12881,1896959729819365541,"RT @Grummz: Blackrock drops DEI under Trumps new guidelines!This is monumental. Blackrock was the biggest pusher of DEI in 2020 and 2021,…","Mar 4, 11:23:38 AM EST"
12882,1896959865815445887,"Worst puppet show ever 🤡🤣 https://t.co/4Fhh330ZtG","Mar 4, 11:24:10 AM EST"
12883,1896960472211247361,"And who told them ALL to hold the microphone like theyre a teenager doing TikTok videos 🤣🤣 https://t.co/EKfr7VJhu9","Mar 4, 11:26:35 AM EST"
12884,1896962300604805314,"17 politicians all saying the exact same thing at the same time!!Such lazy propagandists they are 🤨 https://t.co/AuGaeUiFtn","Mar 4, 11:33:50 AM EST"
12885,1896964635418583498,"Did Adam Schiff commit treason? Sounds like he did. https://t.co/3XAzP6oSVe","Mar 4, 11:43:07 AM EST"
12886,1896965855361294376,"Now were up to 22 Dem senators all doing the same cringe video simultaneously!I will buy a Cybertruck for anyone can provide proof of who wrote this particular piece of propaganda. First person to post proof in the replies to this post gets the truck","Mar 4, 11:47:58 AM EST"
12887,1896965989797126213,"RT @nicksortor: 🚨 UPDATE: An ASTOUNDING **22** Democrat Senators have uploaded videos of themselves reading off an identical cringey script…","Mar 4, 11:48:30 AM EST"
12888,1896966739189199025,"Actions, not words, are what matter. Lets see what actions take place. https://t.co/mqmlXAjTGX","Mar 4, 11:51:29 AM EST"
12889,1896969640141844625,"RT @jasondebolt: I wish more people understood this.If what David is saying here was more widely understood, there would be a lot less po…","Mar 4, 12:03:00 PM EST"
12890,1896975038181728449,"💯 https://t.co/aRWF3iIgJU","Mar 4, 12:24:27 PM EST"
12891,1896975177264848999,"😂 https://t.co/7UiVpQlfm4","Mar 4, 12:25:01 PM EST"
12892,1896975871904505884,"Something to think about https://t.co/KbZQEMpFXP","Mar 4, 12:27:46 PM EST"
12893,1896981952240214436,"The public now knows that theyre all just puppets with no mind of their own 🤡🤡 https://t.co/ZP7LP7OCjc","Mar 4, 12:51:56 PM EST"
12894,1896982086139117581,"RT @karmaycholera: To everyone hating on @elonmusk:History is the ultimate judge. People have always been condemned by some and defended…","Mar 4, 12:52:28 PM EST"
12895,1896982352305549738,"How many of the puppets below also have a picture with Soros?High correlation, I bet. https://t.co/HEfSsZbrJa","Mar 4, 12:53:31 PM EST"
12896,1896982719093203269,"23 Dem senators too lazy even to reach for the thesaurus 🤣🤣 https://t.co/eAD1VYE9XT","Mar 4, 12:54:59 PM EST"
12897,1896989474040766786,"Unlike the 23 Dem senators too lazy even to pick up a thesaurus, President @realDonaldTrump is his own person https://t.co/yCZd6ESlP8","Mar 4, 1:21:49 PM EST"
12898,1896989859509846464,"Such lazy puppets smh https://t.co/kdtYetllAI","Mar 4, 1:23:21 PM EST"
12899,1896990302512275665,"RT @TheRabbitHole84: 🛻 Honk 🛻 https://t.co/3rh0EeBNP6","Mar 4, 1:25:07 PM EST"
12900,1896990708806115827,"🎯 https://t.co/shVpiti8Fz","Mar 4, 1:26:44 PM EST"
12901,1896990879438791120,"A lot of people need to move from low to negative productivity roles in government (and some in industry) to high productivity roles in the commercial sector. That is temporarily disruptive, but ultimately for the best.","Mar 4, 1:27:24 PM EST"
12902,1896994374195798037,"Strong men make good times https://t.co/h4ok05TzYz","Mar 4, 1:41:17 PM EST"
12903,1896994479045009702,"RT @thatsKAIZEN: For Gods sake - Trump is literally stopping WW3 with Russia, stopping fentanyl coming across our borders with tariffs, ex…","Mar 4, 1:41:42 PM EST"
12904,1896994698289668503,"They need to return the money https://t.co/OoT5SvQrtd","Mar 4, 1:42:35 PM EST"
12905,1896994904133525813,"Yes https://t.co/a6XoJKYOYq","Mar 4, 1:43:24 PM EST"
12906,1896995745280266333,"Making govt waste an offer it cant refuse https://t.co/PGTdkXstvu","Mar 4, 1:46:44 PM EST"
12907,1896997266084520053,"FAFO","Mar 4, 1:52:47 PM EST"
12908,1896997721418162549,"Stole a million dollars of taxpayer money? 🤔 https://t.co/QIHkbynl8Y","Mar 4, 1:54:35 PM EST"
12909,1896999314825863216,"I love that trick. Works every time 😂 https://t.co/92rtP1Ee1C","Mar 4, 2:00:55 PM EST"
12910,1896999599837241468,"🎯 https://t.co/uJAa4eW9dz","Mar 4, 2:02:03 PM EST"
12911,1897000036871102918,"Unhinged @Grok voice is next-level 🤣🤣 https://t.co/nQTq5JSvw7","Mar 4, 2:03:48 PM EST"
12912,1897000224062890406,"Sorry 🤗 🤷‍♂️ 😂 https://t.co/XEmshEEmUC","Mar 4, 2:04:32 PM EST"
12913,1897003882779382207,"Be careful what you wish for https://t.co/4dIHWamjsk","Mar 4, 2:19:04 PM EST"
12914,1897009712903983165,"RT @DC_Draino: CitiBank has a lot of explaining to doTheyre caught up in a huge money laundering scam where they hold $20 Billion in tax…","Mar 4, 2:42:14 PM EST"
12915,1897010842534834229,"RT @Fidias0: How to Legally Force the EU to Listen to You https://t.co/JeOHNu9oaA","Mar 4, 2:46:44 PM EST"
12916,1897011191136051248,"It works https://t.co/bB19vfKusy","Mar 4, 2:48:07 PM EST"
12917,1897013165843710049,"RT @cb_doge: Starship, Booster and Planet Earth 💫 https://t.co/hY547yUvVl","Mar 4, 2:55:58 PM EST"
12918,1897013217727316448,"https://t.co/KRByjNe9iq","Mar 4, 2:56:10 PM EST"
12919,1897017974978224169,"Important to note that the date of publication of the half trillion dollar annual fraud estimate from @USGAO is last year during the BIDEN administration https://t.co/tkRTk10LWC","Mar 4, 3:15:04 PM EST"
12920,1897019044152402244,"RT @SawyerMerritt: DOGE now estimates they have saved a total of $105 billion to date, which equates to approximately $652 per taxpayer. ht…","Mar 4, 3:19:19 PM EST"
12921,1897027549701791968,"So recent https://t.co/W7IzhzKIaf","Mar 4, 3:53:07 PM EST"
12922,1897028911768461346,"Wow, some impressive use of @Grok here! https://t.co/LTNOBgvo5j","Mar 4, 3:58:32 PM EST"
12923,1897030053680308288,"Should note that I grew up as English South African, not Afrikaans, and consider myself to be simply an American. No hyphen. That said, whats happening in South Africa is deeply wrong. Not what Mandela intended at all. https://t.co/6Tqb8NS9vl","Mar 4, 4:03:04 PM EST"
12924,1897062023005134910,"The oldest living American is Naomi Whitehead, who is 114 years old https://t.co/XHplAAv8zf","Mar 4, 6:10:06 PM EST"
12925,1897067051145138592,"RT @naval: Anything the red Feds do, blue can undo, and vice versa.But *transfer* power and money from the Feds to the states - both red…","Mar 4, 6:30:05 PM EST"
Can't render this file because it is too large.

20279
elonmusk.csv

File diff suppressed because it is too large Load Diff

5
main.py Normal file
View File

@ -0,0 +1,5 @@
from pkg.dash.app_init import app
# Run the app
if __name__ == '__main__':
app.run_server(debug=True)

View File

@ -184,15 +184,15 @@ def update_input_scrollbar():
def save_history_to_file():
"""Save run history to a text file"""
with open("run_history.txt", "w") as f:
with open("cache/run_history.txt", "w") as f:
json.dump(run_history, f, indent=4)
def load_history_from_file():
"""Load run history from a text file"""
global run_history
if os.path.exists("run_history.txt"):
with open("run_history.txt", "r") as f:
if os.path.exists("cache/run_history.txt"):
with open("cache/run_history.txt", "r") as f:
run_history = json.load(f)
else:
run_history = []

62
pkg/config.py Normal file
View File

@ -0,0 +1,62 @@
from sqlalchemy import create_engine
import pandas as pd
import pytz
# Database connection configuration
DB_CONFIG = {
'host': '8.155.23.172',
'port': 3306,
'user': 'root2',
'password': 'tG0f6PVYh18le41BCb',
'database': 'elonX'
}
TABLE_NAME = 'elon_tweets'
db_uri = f"mysql+pymysql://{DB_CONFIG['user']}:{DB_CONFIG['password']}@{DB_CONFIG['host']}:{DB_CONFIG['port']}/{DB_CONFIG['database']}"
engine = create_engine(db_uri)
# Time zone
eastern = pytz.timezone('America/New_York')
pacific = pytz.timezone('America/Los_Angeles')
central = pytz.timezone('America/Chicago')
# CSV update file path
INPUT_FILE = 'cache/elonmusk.csv'
OUTPUT_FILE = 'cache/fixed.csv'
# Time interval and days options
interval_options = [
{'label': '1 minute', 'value': 1},
{'label': '5 minutes', 'value': 5},
{'label': '10 minutes', 'value': 10},
{'label': '30 minutes', 'value': 30},
{'label': '60 minutes', 'value': 60}
]
days_options = [
{'label': '7 days', 'value': 7},
{'label': '30 days', 'value': 30},
{'label': '90 days', 'value': 90},
{'label': '120 days', 'value': 120},
{'label': '240 days', 'value': 240}
]
# Global render data
class RenderData:
def __init__(self):
self.global_df = None
self.global_agg_df = None
self.all_dates = []
self.default_date = []
self.load_data()
def load_data(self):
df = pd.read_sql(f'SELECT timestamp FROM {TABLE_NAME}', con=engine)
df['datetime'] = pd.to_datetime(df['timestamp'], unit='s')
df['datetime_est'] = df['datetime'].dt.tz_localize('UTC').dt.tz_convert(eastern)
df['date'] = df['datetime_est'].dt.date
df['minute_of_day'] = df['datetime_est'].dt.hour * 60 + df['datetime_est'].dt.minute
agg_df = df.groupby(['date', 'minute_of_day']).size().reset_index(name='tweet_count')
self.global_df = df.copy()
self.global_agg_df = agg_df.copy()
self.all_dates = sorted(self.global_agg_df['date'].unique(), reverse=True)
self.default_date = [str(self.all_dates[0])]
render_data = RenderData()

0
pkg/dash/__init__.py Normal file
View File

0
pkg/dash/api/__init__.py Normal file
View File

View File

@ -0,0 +1,14 @@
from pkg.dash.app_init import app
from pkg.get_tweets import process_tweets
from flask import jsonify
from pkg.config import render_data
# Simulated backend endpoint for processing tweets
@app.server.route('/api/process_tweets', methods=['GET'])
def api_process_tweets():
success, message = process_tweets()
if success:
render_data.load_data()
return jsonify({'message': message, 'default_date': render_data.default_date}), 200
else:
return jsonify({'error': message}), 500

124
pkg/dash/app_html.py Normal file
View File

@ -0,0 +1,124 @@
from dash import dcc, html
from pkg.config import interval_options,days_options,render_data
def layout_config(app):
# Dash app layout (unchanged except default days value)
app.layout = html.Div([
# Left sidebar with clock button and tooltip (unchanged)
html.Div(
id='clock-container',
children=[
html.Div(
id='clock-button',
children='🕒',
style={
'fontSize': '24px',
'cursor': 'pointer',
'padding': '5px',
}
),
html.Div(
id='clock-tooltip',
children=[
html.Div(id='pst-clock'),
html.Div(id='cst-clock'),
html.Div(id='est-clock')
],
style={
'position': 'absolute',
'left': '35px',
'top': '0px',
'backgroundColor': 'rgba(0, 0, 0, 0.8)',
'color': 'white',
'padding': '10px',
'borderRadius': '5px',
'fontSize': '14px',
'display': 'none',
'whiteSpace': 'nowrap'
}
),
html.Div(
id='play-button',
children='▶️',
n_clicks=0,
style={
'fontSize': '24px',
'cursor': 'pointer',
'padding': '5px',
'marginTop': '10px'
}
),
html.Div(
id='play-tooltip',
children=[],
style={
'position': 'absolute',
'left': '35px',
'top': '40px',
'backgroundColor': 'rgba(0, 0, 0, 0.8)',
'color': 'white',
'padding': '10px',
'borderRadius': '5px',
'fontSize': '14px',
'display': 'none',
'whiteSpace': 'nowrap'
}
)
],
style={
'position': 'fixed',
'left': '10px',
'top': '50%',
'transform': 'translateY(-50%)',
'zIndex': 1000
}
),
# Main content
html.Div([
html.H1("Elon Musk Tweet Time Analysis (EST)"),
html.Div(id='date-picker-container', children=[
dcc.Dropdown(
id='multi-date-picker',
options=[{'label': str(date), 'value': str(date)} for date in render_data.all_dates],
value=render_data.default_date,
multi=True,
searchable=True,
placeholder="Search and select dates (YYYY-MM-DD)",
style={'width': '100%'}
)
]),
dcc.Dropdown(
id='multi-interval-picker',
options=interval_options,
value=10,
style={'width': '50%', 'marginTop': '10px'}
),
html.Div(id='days-display-container', style={'display': 'none'}, children=[
dcc.Dropdown(
id='days-display-picker',
options=days_options,
value=30, # Default changed to 30 since 1 is removed
style={'width': '50%', 'marginTop': '10px'}
)
]),
html.Div(id='multi-day-warning', style={'color': 'red', 'margin': '10px'}),
dcc.Checklist(
id='time-zone-checklist',
options=[
{'label': 'California Time (PST)', 'value': 'PST'},
{'label': 'Texas Time (CST)', 'value': 'CST'}
],
value=['PST'],
style={'margin': '10px'}
),
html.Div(id='multi-tweet-summary', style={'fontSize': '20px', 'margin': '10px'}),
dcc.Tabs(id='tabs', value='line', children=[
dcc.Tab(label='Line Chart', value='line'),
dcc.Tab(label='Heatmap', value='heatmap'),
dcc.Tab(label='Scatter Plot', value='scatter'),
]),
html.Div(id='tabs-content'),
], style={'marginLeft': '50px'}),
dcc.Interval(id='clock-interval', interval=1000, n_intervals=0)
])
return app

25
pkg/dash/app_init.py Normal file
View File

@ -0,0 +1,25 @@
import dash
from .app_html import layout_config
from .javascript import setting_callback
import os
import importlib
# Initialize Dash app (unchanged)
external_stylesheets = ['assets/bWLwgP.css']
app = dash.Dash(__name__, external_stylesheets=external_stylesheets)
app = layout_config(app)
setting_callback()
base_dir = os.path.dirname(__file__)
sub_dirs = ['func', 'api']
for sub_dir in sub_dirs:
dir_path = os.path.join(base_dir, sub_dir)
if os.path.exists(dir_path):
for filename in os.listdir(dir_path):
if filename.endswith('.py') and filename != '__init__.py':
module_name = filename[:-3]
importlib.import_module(f'.{sub_dir}.{module_name}', package='pkg.dash')

View File

19
pkg/dash/func/clock.py Normal file
View File

@ -0,0 +1,19 @@
import pytz
from pkg.dash.app_init import app
from dash.dependencies import Input, Output
from pkg.config import pacific,central,eastern
from datetime import datetime
# Callback for updating clocks (unchanged)
@app.callback(
[Output('pst-clock', 'children'),
Output('cst-clock', 'children'),
Output('est-clock', 'children')],
[Input('clock-interval', 'n_intervals')]
)
def update_clocks(n):
now_utc = datetime.now(pytz.UTC)
pst_time = now_utc.astimezone(pacific).strftime('%Y-%m-%d %H:%M:%S PST')
cst_time = now_utc.astimezone(central).strftime('%Y-%m-%d %H:%M:%S CST')
est_time = now_utc.astimezone(eastern).strftime('%Y-%m-%d %H:%M:%S EST')
return f"𝕏: {pst_time}", f"🚀: {cst_time}", f"🏛️/🌴: {est_time}"

132
pkg/dash/func/render.py Normal file
View File

@ -0,0 +1,132 @@
from datetime import datetime, timedelta
from dash.dependencies import Input, Output
from pkg.dash.app_init import app
from pkg.config import render_data
from pkg.tool import aggregate_data,generate_xticks,minutes_to_time
from dash import dcc
import plotly.graph_objs as go
import pandas as pd
# Callback for updating tabs content (Modified to add Thursday-Friday lines)
@app.callback(
[Output('tabs-content', 'children'),
Output('multi-day-warning', 'children'),
Output('multi-tweet-summary', 'children')],
[Input('tabs', 'value'),
Input('multi-date-picker', 'value'),
Input('multi-interval-picker', 'value'),
Input('time-zone-checklist', 'value'),
Input('days-display-picker', 'value')]
)
def render_tab_content(tab, selected_dates, interval, time_zones, days_to_display):
warning = ""
if tab != 'heatmap':
if len(selected_dates) > 10:
selected_dates = selected_dates[:10]
warning = "Maximum of 10 days can be selected. Showing first 10 selected days."
selected_dates = [datetime.strptime(date, '%Y-%m-%d').date() for date in selected_dates]
else:
selected_dates = sorted(render_data.global_agg_df['date'].unique(), reverse=True)[:days_to_display]
multi_data_agg = render_data.global_agg_df[render_data.global_agg_df['date'].isin(selected_dates)].copy()
if multi_data_agg.empty:
multi_data_agg = pd.DataFrame({'date': selected_dates, 'minute_of_day': [0] * len(selected_dates)})
tweet_count_total = 0
else:
tweet_count_total = multi_data_agg['tweet_count'].sum()
multi_data_raw = render_data.global_df[render_data.global_df['date'].isin(selected_dates)].copy()
if multi_data_raw.empty:
tweet_count_total = 0
agg_data = aggregate_data(multi_data_agg, interval)
xticks, xtick_labels = generate_xticks(interval)
if tab == 'line':
fig = go.Figure()
for date in selected_dates:
day_data = agg_data[agg_data['date'] == date]
hover_times = [f"{date} {minutes_to_time(minute)} EST" for minute in day_data['interval_group']]
fig.add_trace(go.Scatter(
x=day_data['interval_group'],
y=day_data['tweet_count'],
mode='lines',
name=str(date),
customdata=hover_times,
hovertemplate='%{customdata}<br>Tweets: %{y}<extra></extra>'
))
elif tab == 'heatmap':
pivot_data = agg_data.pivot(index='date', columns='interval_group', values='tweet_count').fillna(0)
pivot_data.index = pivot_data.index.astype(str)
fig = go.Figure(data=go.Heatmap(
z=pivot_data.values,
x=[minutes_to_time(m) for m in pivot_data.columns],
y=pivot_data.index,
colorscale='Viridis',
hoverongaps=False,
hovertemplate='%{y} %{x} EST<br>Tweets: %{z}<extra></extra>'
))
for i, date_str in enumerate(pivot_data.index):
date = datetime.strptime(date_str, '%Y-%m-%d').date()
if date.weekday() == 4: # Friday
prev_date = date - timedelta(days=1)
if str(prev_date) in pivot_data.index:
y_position = i / len(pivot_data.index)
fig.add_hline(
y=1 - y_position,
line_dash="dash",
line_color="white",
xref="x",
yref="paper"
)
fig.update_layout(
title=f'Tweet Heatmap (Interval: {interval} minutes, EST, {len(selected_dates)} days)',
xaxis_title='Time of Day (HH:MM EST)',
yaxis_title='Date',
height=max(400, len(selected_dates) * 20),
yaxis=dict(autorange='reversed')
)
elif tab == 'scatter':
fig = go.Figure()
for date in selected_dates:
day_data = multi_data_raw[multi_data_raw['date'] == date]
if not day_data.empty:
hover_times = [t.strftime('%Y-%m-%d %H:%M:%S EST') for t in day_data['datetime_est']]
fig.add_trace(go.Scatter(
x=day_data['minute_of_day'],
y=[str(date)] * len(day_data),
mode='markers',
name=str(date),
customdata=hover_times,
hovertemplate='%{customdata}<extra></extra>',
marker=dict(size=8)
))
if tab in ['line', 'scatter']:
if 'PST' in time_zones:
pacific_2am_est = (2 + 3) * 60
pacific_7am_est = (7 + 3) * 60
fig.add_vline(x=pacific_2am_est, line_dash="dash", line_color="blue", annotation_text="CA 2AM PST")
fig.add_vline(x=pacific_7am_est, line_dash="dash", line_color="blue", annotation_text="CA 7AM PST")
if 'CST' in time_zones:
central_2am_est = (2 + 1) * 60
central_7am_est = (7 + 1) * 60
fig.add_vline(x=central_2am_est, line_dash="dash", line_color="green", annotation_text="TX 2AM CST")
fig.add_vline(x=central_7am_est, line_dash="dash", line_color="green", annotation_text="TX 7AM CST")
if tab in ['line', 'scatter']:
fig.update_layout(
title=f'{"Line" if tab == "line" else "Scatter"} Tweet Frequency (Interval: {interval} minutes, EST)',
xaxis_title='Eastern Time (HH:MM)',
yaxis_title='Tweet Count' if tab == 'line' else 'Date',
xaxis=dict(range=[0, 1440], tickvals=xticks, ticktext=xtick_labels, tickangle=45),
height=600,
showlegend=True,
yaxis=dict(autorange='reversed') if tab == 'scatter' else None
)
summary = f"Total tweets for selected dates: {int(tweet_count_total)}"
return dcc.Graph(figure=fig), warning, summary

12
pkg/dash/func/ui.py Normal file
View File

@ -0,0 +1,12 @@
from pkg.dash.app_init import app
from dash.dependencies import Input, Output
@app.callback(
[Output('date-picker-container', 'style'),
Output('days-display-container', 'style')],
[Input('tabs', 'value')]
)
def toggle_controls_visibility(tab):
if tab == 'heatmap':
return {'display': 'none'}, {'display': 'block'}
return {'display': 'block'}, {'display': 'none'}

77
pkg/dash/javascript.py Normal file
View File

@ -0,0 +1,77 @@
from dash.dependencies import Input, Output, State
from dash import clientside_callback
def setting_callback():
clientside_callback(
"""
function(n_intervals) {
const button = document.getElementById('clock-button');
const tooltip = document.getElementById('clock-tooltip');
if (button && tooltip) {
button.addEventListener('mouseover', () => {
tooltip.style.display = 'block';
});
button.addEventListener('mouseout', () => {
tooltip.style.display = 'none';
});
}
return window.dash_clientside.no_update;
}
""",
Output('clock-container', 'id'),
Input('clock-interval', 'n_intervals'),
prevent_initial_call=False
)
# Clientside callback for play button with API request
clientside_callback(
"""
async function(n_clicks, existing_children) {
const button = document.getElementById('play-button');
const tooltip = document.getElementById('play-tooltip');
if (!button || !tooltip) return ['▶️', ''];
if (n_clicks > 0) {
button.style.cursor = 'wait';
button.innerHTML = '🔄';
tooltip.style.display = 'none';
try {
const response = await fetch('/api/process_tweets', {
method: 'GET',
headers: {'Content-Type': 'application/json'}
});
const data = await response.json();
if (response.ok) {
button.innerHTML = '';
tooltip.innerHTML = `Success: ${data.message}`;
tooltip.style.display = 'block';
} else {
button.innerHTML = '🆘';
tooltip.innerHTML = `Error: ${data.error}`;
tooltip.style.display = 'block';
}
} catch (error) {
button.innerHTML = '🆘';
tooltip.innerHTML = `Error: Network failure - ${error.message}`;
tooltip.style.display = 'block';
}
setTimeout(() => {
button.innerHTML = '▶️';
button.style.cursor = 'pointer';
tooltip.style.display = 'none';
tooltip.innerHTML = '';
}, 3000);
return [button.innerHTML, tooltip.innerHTML];
}
return ['▶️', ''];
}
""",
[Output('play-button', 'children'), Output('play-tooltip', 'children')],
Input('play-button', 'n_clicks'),
State('play-button', 'children'),
prevent_initial_call=True
)

View File

@ -1,59 +1,33 @@
import csv
import re
import mysql.connector
from datetime import datetime
import requests
# 文件路径
INPUT_FILE = '../elonmusk.csv'
OUTPUT_FILE = '../fixed.csv'
# 数据库连接配置
DB_CONFIG = {
'host': '8.155.23.172',
'port': 3306,
'user': 'root2',
'password': 'tG0f6PVYh18le41BCb',
'database': 'elonX'
}
TABLE_NAME = 'elon_tweets'
from datetime import datetime
from pkg.config import TABLE_NAME,DB_CONFIG,INPUT_FILE,OUTPUT_FILE
def download_file(file_path):
url = 'https://www.xtracker.io/api/download'
headers = {
'Accept': '*/*',
'Accept-Language': 'zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6,zh-TW;q=0.5',
'Cache-Control': 'no-cache',
'Connection': 'keep-alive',
'Content-Type': 'application/json',
'Origin': 'https://www.xtracker.io',
'Pragma': 'no-cache',
'Referer': 'https://www.xtracker.io/',
'Sec-Fetch-Dest': 'empty',
'Sec-Fetch-Mode': 'cors',
'Sec-Fetch-Site': 'same-origin',
'Accept': '*/*', 'Accept-Language': 'zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6,zh-TW;q=0.5',
'Cache-Control': 'no-cache', 'Connection': 'keep-alive', 'Content-Type': 'application/json',
'Origin': 'https://www.xtracker.io', 'Pragma': 'no-cache', 'Referer': 'https://www.xtracker.io/',
'Sec-Fetch-Dest': 'empty', 'Sec-Fetch-Mode': 'cors', 'Sec-Fetch-Site': 'same-origin',
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/133.0.0.0 Safari/537.36 Edg/133.0.0.0',
'sec-ch-ua': '"Not(A:Brand";v="99", "Microsoft Edge";v="133", "Chromium";v="133"',
'sec-ch-ua-mobile': '?0',
'sec-ch-ua': '"Not(A:Brand";v="99", "Microsoft Edge";v="133", "Chromium";v="133"', 'sec-ch-ua-mobile': '?0',
'sec-ch-ua-platform': '"Windows"'
}
data = '{"handle":"elonmusk","platform":"X"}'
try:
response = requests.post(url, headers=headers, data=data)
if response.status_code == 200:
# 直接保存原始字节数据,不进行解码
with open(file_path, 'wb') as f:
f.write(response.content)
print(f"文件已成功下载到 {file_path}(原始字节数据)")
return True, "File downloaded successfully"
else:
print(f"下载失败,状态码:{response.status_code}")
print(f"响应内容:{response.text}")
return False, f"Download failed with status code {response.status_code}: {response.text}"
except Exception as e:
print(f"下载文件时出错:{e}")
return False, f"Error downloading file: {str(e)}"
# 第一步:修复 CSV 文件并添加 rank_id
def fix_line(lines, line_number, rank_id):
full_line = ''.join(lines)
match = re.search(r'^([^,]+),"(.+?)","([A-Z][a-z]{2} \d{1,2}, \d{1,2}:\d{2}:\d{2} (AM|PM) E[SD]T)"$', full_line,
@ -69,7 +43,6 @@ def fix_line(lines, line_number, rank_id):
print(f"Line {line_number} format error: {repr(full_line)}")
return f'{rank_id},{full_line}'
def process_file(input_file, output_file):
with open(input_file, 'r', encoding='utf-8') as f_in, open(output_file, 'w', encoding='utf-8') as f_out:
f_out.write("rank_id,id,text,created_at\n")
@ -90,104 +63,94 @@ def process_file(input_file, output_file):
if buffer:
fixed_line = fix_line(buffer, line_number, rank_id)
f_out.write(fixed_line + '\n')
print(f"CSV 文件已修复并添加 rank_id保存为 {output_file}")
return True, f"CSV 文件已修复并添加 rank_id保存为 {output_file}"
# 第二步:数据库操作
def get_max_rank_id(cursor):
try:
cursor.execute(f"SELECT MAX(rank_id) FROM {TABLE_NAME}")
result = cursor.fetchone()[0]
return result if result is not None else 0
return result if result is not None else 0, True, ""
except mysql.connector.Error as e:
print(f"获取最大 rank_id 出错: {e}")
return 0
return 0, False, f"Error getting max rank_id: {str(e)}"
def import_to_database(input_file):
def import_to_database(input_file: str) -> tuple[bool, str]:
try:
conn = mysql.connector.connect(**DB_CONFIG)
cursor = conn.cursor()
print("成功连接到数据库")
# Use context managers to ensure resources are closed properly
with mysql.connector.connect(**DB_CONFIG) as conn, conn.cursor() as cursor:
current_year = str(datetime.now().year)
max_rank_id, success, error = get_max_rank_id(cursor)
if not success:
return False, error
# 获取当前年份
current_year = str(datetime.now().year)
with open(input_file, 'r', encoding='utf-8') as f:
reader = csv.reader(f)
try:
next(reader) # Skip header
except StopIteration:
return False, "File is empty or has no valid header"
# 获取数据库中最大 rank_id
max_rank_id = get_max_rank_id(cursor)
print(f"数据库中最大 rank_id: {max_rank_id}")
total_rows, inserted = 0, 0
for row in reader:
if len(row) != 4:
continue
try:
rank_id = int(row[0])
tweet_id = float(row[1])
text, created_at = row[2], row[3]
except (ValueError, IndexError) as e:
return False, f"Invalid data format in row: {str(e)}"
with open(input_file, 'r', encoding='utf-8') as f:
reader = csv.reader(f)
next(reader) # 跳过表头
total_rows = 0
inserted = 0
if rank_id <= max_rank_id:
continue
for row in reader:
if len(row) != 4:
print(f"跳过无效行: {row}")
continue
rank_id, id_, text, created_at = row
rank_id = int(rank_id)
tweet_id = float(id_)
total_rows += 1
insert_query = f"""
INSERT INTO {TABLE_NAME} (rank_id, id, text, year, created_at, timestamp)
VALUES (%s, %s, %s, %s, %s, %s)
"""
cursor.execute(insert_query, (rank_id, tweet_id, text, current_year, created_at, 0))
inserted += 1
# 只导入 rank_id 大于 max_rank_id 的记录
if rank_id <= max_rank_id:
continue
total_rows += 1
insert_query = f"""
INSERT INTO {TABLE_NAME} (rank_id, id, text, year, created_at, timestamp)
VALUES (%s, %s, %s, %s, %s, %s)
conn.commit()
update_query = f"""
UPDATE {TABLE_NAME}
SET timestamp = UNIX_TIMESTAMP(
CONVERT_TZ(
STR_TO_DATE(
CONCAT(year, ' ', SUBSTRING_INDEX(created_at, ' ', 4)),
'%Y %b %d, %l:%i:%s %p'
),
CASE
WHEN RIGHT(created_at, 3) = 'EDT' THEN 'America/New_York'
WHEN RIGHT(created_at, 3) = 'EST' THEN 'America/New_York'
ELSE 'UTC'
END,
'UTC'
)
) + 8*60*60
WHERE rank_id > {max_rank_id}
"""
cursor.execute(insert_query, (rank_id, tweet_id, text, current_year, created_at, 0))
inserted += 1
print(f"文本: 【{text}】,这是第 {inserted}")
conn.commit()
print(f"数据库导入完成:总计处理 {total_rows} 行,插入 {inserted}")
# 更新新插入记录的 timestamp使用参数化查询
update_query = f"""
UPDATE {TABLE_NAME}
SET timestamp = UNIX_TIMESTAMP(
CONVERT_TZ(
STR_TO_DATE(
CONCAT(year, ' ', SUBSTRING_INDEX(created_at, ' ', 4)),
'%Y %b %d, %l:%i:%s %p'
),
CASE
WHEN RIGHT(created_at, 3) = 'EDT' THEN 'America/New_York'
WHEN RIGHT(created_at, 3) = 'EST' THEN 'America/New_York'
ELSE 'UTC'
END,
'UTC'
)
) + 8*60*60
WHERE rank_id > {max_rank_id}
"""
cursor.execute(update_query)
conn.commit()
print(f"已更新 rank_id > {max_rank_id} 的记录的时间戳")
cursor.execute(update_query)
conn.commit()
return True, f"Database import completed: {inserted} rows inserted"
except mysql.connector.Error as e:
print(f"数据库错误: {e}")
return False, f"Database error: {str(e)}"
except FileNotFoundError as e:
return False, f"File not found: {str(e)}"
except csv.Error as e:
return False, f"CSV parsing error: {str(e)}"
except Exception as e:
print(f"其他错误: {e}")
finally:
if 'cursor' in locals():
cursor.close()
if 'conn' in locals() and conn.is_connected():
conn.close()
print("数据库连接已关闭")
return False, f"Unexpected error: {str(e)}"
# 主流程
def main():
download_file(INPUT_FILE) # 先下载文件
process_file(INPUT_FILE, OUTPUT_FILE)
import_to_database(OUTPUT_FILE)
if __name__ == "__main__":
main()
def process_tweets():
success, msg = download_file(INPUT_FILE)
if not success:
return False, msg
success, msg = process_file(INPUT_FILE, OUTPUT_FILE)
if not success:
return False, msg
success, msg = import_to_database(OUTPUT_FILE)
return success, msg

34
pkg/tool.py Normal file
View File

@ -0,0 +1,34 @@
import pandas as pd
# Auxiliary functions (unchanged)
def aggregate_data(data, interval):
all_minutes = pd.DataFrame({'interval_group': range(0, 1440, interval)})
result = []
for date in data['date'].unique():
day_data = data[data['date'] == date].copy()
day_data['interval_group'] = (day_data['minute_of_day'] // interval) * interval
agg = day_data.groupby('interval_group').size().reset_index(name='tweet_count')
complete_data = all_minutes.merge(agg, on='interval_group', how='left').fillna({'tweet_count': 0})
complete_data['date'] = date
result.append(complete_data)
return pd.concat(result, ignore_index=True)
def generate_xticks(interval):
if interval <= 5:
tick_step = 60
elif interval <= 10:
tick_step = 60
elif interval <= 30:
tick_step = 120
else:
tick_step = 240
ticks = list(range(0, 1440, tick_step))
tick_labels = [f"{m // 60:02d}:{m % 60:02d}" for m in ticks]
return ticks, tick_labels
def minutes_to_time(minutes):
hours = minutes // 60
mins = minutes % 60
return f"{hours:02d}:{mins:02d}"

11
plan.md Normal file
View File

@ -0,0 +1,11 @@
#### 2025.3.4
1. 完善main.py的 ▶️🔄✅
* 使用api的方式前端请求后端api返回结果
2. 实时时间显示对齐
3. 添加一天内发帖热图
#### 后续
1. 考虑通过 tweets 数预测市场曲线的模型(人工智能)
2. 考虑elon jets的效果

View File

@ -9,4 +9,5 @@ SQLAlchemy~=2.0.38
matplotlib~=3.10.1
numpy~=2.2.3
scipy~=1.15.2
ipython~=8.32.0
ipython~=8.32.0
Flask~=3.0.3