Skip to content

Commit abe64ba

Browse files
Tony QiuTony Qiu
authored andcommitted
add back recommendation filters code
1 parent 8bfbebf commit abe64ba

File tree

3 files changed

+175
-129
lines changed

3 files changed

+175
-129
lines changed

.github/workflows/update-events-data.yml

Lines changed: 10 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -90,28 +90,23 @@ jobs:
9090
backend/scraping/*.csv
9191
retention-days: 30
9292

93-
- name: Generate static events file
93+
- name: Generate static data file
9494
id: generate_static
9595
working-directory: backend/scraping
96-
run: python get_static_events.py
97-
98-
- name: Generate recommended filters
99-
if: github.event_name == 'schedule' || github.event.inputs.run_scraper == 'true'
100-
working-directory: backend/scripts
101-
run: python generate_recommended_filters.py
102-
continue-on-error: true
103-
104-
- name: Send newsletter to subscribers
105-
if: github.event_name == 'schedule' || github.event.inputs.run_scraper == 'true'
106-
working-directory: backend/scripts
107-
run: python send_newsletter.py
108-
continue-on-error: true
96+
run: python generate_static_data.py
97+
10998

11099
- name: Commit and push changes
111100
if: steps.generate_static.outcome == 'success'
112101
run: |
113102
git config --global user.name 'github-actions[bot]'
114103
git config --global user.email 'github-actions[bot]@users.noreply.github.com'
115104
git add frontend/src/data/staticData.ts
116-
git commit -m "chore: update static events and recommended filters from DB" || echo "No changes to commit"
105+
git commit -m "chore: update static data from DB" || echo "No changes to commit"
117106
git push --force
107+
108+
- name: Send newsletter to subscribers
109+
if: github.event_name == 'schedule' || github.event.inputs.run_scraper == 'true'
110+
working-directory: backend/scripts
111+
run: python send_newsletter.py
112+
continue-on-error: true
Lines changed: 165 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,165 @@
1+
import logging
2+
import os
3+
import sys
4+
from datetime import date, datetime, time
5+
from pathlib import Path
6+
7+
import psycopg2
8+
from dotenv import load_dotenv
9+
10+
# Add parent directory to path for imports
11+
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
12+
13+
load_dotenv()
14+
15+
16+
def format_value(value):
17+
"""Format values for TypeScript file"""
18+
if value is None:
19+
return "null"
20+
if isinstance(value, date | time | datetime):
21+
return f'"{value.isoformat()}"'
22+
if isinstance(value, str):
23+
escaped_value = (
24+
value.replace("\\", "\\\\")
25+
.replace('"', '\\"')
26+
.replace("\n", "\\n")
27+
.replace("\r", "\\r")
28+
)
29+
return f'"{escaped_value}"'
30+
if isinstance(value, bool):
31+
return str(value).lower()
32+
return value
33+
34+
35+
def fetch_events_for_static_data():
36+
"""Fetch all upcoming events from the database for static data generation"""
37+
conn_string = os.environ.get("SUPABASE_DB_URL")
38+
logging.info("Connecting to the database...")
39+
40+
with psycopg2.connect(conn_string) as conn, conn.cursor() as cur:
41+
logging.info("Executing query...")
42+
query = """
43+
SELECT
44+
e.id,
45+
e.club_handle,
46+
e.url,
47+
e.name,
48+
e.date,
49+
e.start_time,
50+
CASE
51+
WHEN e.end_time IS NULL THEN e.start_time + interval '1 hour'
52+
ELSE e.end_time
53+
END as end_time,
54+
e.location,
55+
e.price,
56+
e.food,
57+
e.registration,
58+
e.image_url,
59+
e.club_type,
60+
e.added_at,
61+
e.description
62+
FROM
63+
events e
64+
WHERE
65+
e.date >= CURRENT_DATE
66+
ORDER BY e.date ASC, e.start_time ASC;
67+
"""
68+
cur.execute(query)
69+
columns = [desc[0] for desc in cur.description]
70+
events = [dict(zip(columns, row, strict=False)) for row in cur.fetchall()]
71+
logging.info(f"Fetched {len(events)} events.")
72+
return events
73+
74+
75+
def generate_recommended_filters(events_data):
76+
"""Generate recommended filters using OpenAI service"""
77+
try:
78+
from services.openai_service import generate_recommended_filters
79+
logging.info("Generating recommended filters using OpenAI...")
80+
recommended_filters = generate_recommended_filters(events_data)
81+
82+
if not recommended_filters:
83+
logging.warning("Failed to generate recommended filters")
84+
return []
85+
86+
logging.info(f"Generated {len(recommended_filters)} filters: {recommended_filters}")
87+
return recommended_filters
88+
except Exception as e:
89+
logging.error(f"Error generating recommended filters: {e}")
90+
return []
91+
92+
93+
def main():
94+
"""Fetches events, generates filters, and writes to staticData.ts"""
95+
logging.basicConfig(
96+
level=logging.INFO, format="%(asctime)s - %(levelname)s - %(message)s"
97+
)
98+
try:
99+
# Fetch upcoming events
100+
events = fetch_events_for_static_data()
101+
102+
# Generate recommended filters
103+
recommended_filters = generate_recommended_filters(events)
104+
105+
# Write to staticData.ts
106+
output_path = (
107+
Path(__file__).parent.parent.parent
108+
/ "frontend"
109+
/ "src"
110+
/ "data"
111+
/ "staticData.ts"
112+
)
113+
logging.info(f"Writing to {output_path}...")
114+
with output_path.open("w", encoding="utf-8") as f:
115+
# Write the last updated timestamp
116+
current_time = datetime.now().isoformat()
117+
f.write('import { Event } from "@/hooks/useEvents";\n\n')
118+
f.write(f'export const LAST_UPDATED = "{current_time}";\n\n')
119+
120+
# Write static events data
121+
f.write("export const staticEventsData = new Map<string, Event>([\n")
122+
for i, event in enumerate(events):
123+
event_id = str(event["id"])
124+
f.write(f" [{format_value(event_id)}, {{\n")
125+
f.write(f" id: {format_value(event_id)},\n")
126+
f.write(f' club_handle: {format_value(event["club_handle"])},\n')
127+
f.write(f' url: {format_value(event["url"])},\n')
128+
f.write(f' name: {format_value(event["name"])},\n')
129+
f.write(f' date: {format_value(event["date"])},\n')
130+
f.write(f' start_time: {format_value(event["start_time"])},\n')
131+
f.write(f' end_time: {format_value(event["end_time"])},\n')
132+
f.write(f' location: {format_value(event["location"])},\n')
133+
f.write(f' price: {format_value(event["price"])},\n')
134+
f.write(f' food: {format_value(event["food"])},\n')
135+
f.write(f' registration: {format_value(event["registration"])},\n')
136+
f.write(f' image_url: {format_value(event["image_url"])},\n')
137+
f.write(f' club_type: {format_value(event["club_type"])},\n')
138+
f.write(f' added_at: {format_value(event["added_at"])},\n')
139+
f.write(" }]")
140+
if i < len(events) - 1:
141+
f.write(",")
142+
f.write("\n")
143+
f.write("]);\n\n")
144+
145+
# Write recommended filters
146+
if recommended_filters:
147+
f.write("export const RECOMMENDED_FILTERS: string[] = [\n")
148+
for i, filter_keyword in enumerate(recommended_filters):
149+
escaped = filter_keyword.replace('"', '\\"')
150+
f.write(f' "{escaped}"')
151+
if i < len(recommended_filters) - 1:
152+
f.write(",")
153+
f.write("\n")
154+
f.write("];\n")
155+
else:
156+
f.write("export const RECOMMENDED_FILTERS: string[] = [];\n")
157+
158+
logging.info("Successfully updated staticData.ts with events and recommended filters")
159+
except Exception:
160+
logging.exception("An error occurred")
161+
sys.exit(1)
162+
163+
164+
if __name__ == "__main__":
165+
main()

backend/scraping/get_static_events.py

Lines changed: 0 additions & 114 deletions
This file was deleted.

0 commit comments

Comments
 (0)