Vedant Jigarbhai Mehta commited on
Commit
0357317
Β·
1 Parent(s): dbab84d

add prompts file

Browse files
Files changed (1) hide show
  1. vedant-prompts.md +177 -0
vedant-prompts.md ADDED
@@ -0,0 +1,177 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # AI-Assisted Development β€” Prompt Log
2
+
3
+ I used Claude (Anthropic) as a coding assistant during this project, primarily for performance optimization, edge case discovery, unfamiliar library APIs, LLM prompt iteration, and debugging deployment issues. Below is the sequential log of every AI-assisted prompt with brief notes describing what stage the project was at when each prompt was made.
4
+
5
+ ---
6
+
7
+ ### Stage 1: Data Pipeline
8
+
9
+ The first work was setting up the data pipeline β€” parsing 8,799 Reddit posts from JSONL into SQLite, generating sentence embeddings, running UMAP dimensionality reduction, and constructing the network graph. Most of this was straightforward, but the network graph required careful handling of three different edge types and the exclusion of meta-authors like `[deleted]`.
10
+
11
+ ## Prompt 1
12
+ **Component**: Network graph β€” shared URL edges (`backend/pipeline/build_graph.py`)
13
+ **Prompt**: "Write the shared URL edge logic for a NetworkX graph: for each external URL posted by 2+ authors, create edges between all author pairs with weight 2.0. Filter out internal Reddit domains."
14
+ **Issue**: Output included `self.*` and `i.redd.it` as "shared URLs" β€” would create thousands of false connections between unrelated authors who just happened to post images.
15
+ **Fix**: Added domain filtering for `self.*`, `reddit.com`, `i.redd.it`, `v.redd.it`. Also excluded `[deleted]` (appears in 9/10 subreddits) to prevent a false super-connector node dominating all centrality metrics.
16
+
17
+ ---
18
+
19
+ After the network graph was generated (320 nodes, 773 edges, 72 components), the next step was the topic clustering pipeline β€” KMeans with TF-IDF labels for each cluster.
20
+
21
+ ## Prompt 2
22
+ **Component**: KMeans cluster labeling (`backend/pipeline/cluster.py`)
23
+ **Prompt**: "Pre-compute KMeans cluster assignments for k = [3, 5, 8, 10, 15, 20, 30, 50]. For each cluster, extract top TF-IDF terms as a label."
24
+ **Issue**: TF-IDF used default settings, so cluster labels included common words like "the", "is", "and" β€” making them uninformative ("the, is, trump, people, and").
25
+ **Fix**: Added `stop_words='english'` and `max_df=0.9` to filter overly common terms. Labels improved to descriptive terms like "trump, tariffs, china, canada, trade".
26
+
27
+ ---
28
+
29
+ ### Stage 2: Backend API
30
+
31
+ With all pre-computed artifacts in place (`posts.db`, `embeddings.npy`, `graph.json`, `umap_coords.npy`), the next phase was building the Flask API layer β€” endpoints for time-series, semantic search, network graph, and clusters. The semantic search endpoint was the most performance-sensitive part.
32
+
33
+ ## Prompt 3
34
+ **Component**: Cosine similarity optimization (`backend/routes/search.py`)
35
+ **Prompt**: "My semantic search loops through 8,799 embeddings computing cosine similarity one-by-one with scipy. Takes ~200ms per query. How can I vectorize this?"
36
+ **Issue**: AI suggested `scipy.spatial.distance.cdist` β€” computes a full pairwise distance matrix, overkill when only one query vs all posts is needed.
37
+ **Fix**: Since embeddings are L2-normalized at pre-computation time, cosine similarity equals the dot product. Replaced with `similarities = embeddings @ query_vec.T` β€” single numpy operation. Search dropped from ~200ms to <10ms.
38
+
39
+ ---
40
+
41
+ The rubric specifically mentions stress-testing search with edge cases: empty queries, very short queries, non-English input. The next prompt was about anticipating what else could break.
42
+
43
+ ## Prompt 4
44
+ **Component**: Search edge case handling (`backend/routes/search.py`)
45
+ **Prompt**: "What edge cases should I handle for semantic search? I handle empty queries already. What else could break during stress testing?"
46
+ **Issue**: AI recommended `polyglot` for language detection β€” requires system-level ICU dependencies that won't install in Docker. Also threw exceptions on single-character inputs.
47
+ **Fix**: Switched to `langdetect` (pure Python). Added: short query handling with suggestions, non-English translation via the LLM before embedding, and a 0.45 similarity threshold below which the system returns "no strong matches" instead of fabricating analysis on irrelevant results.
48
+
49
+ ---
50
+
51
+ The network endpoint needed to support node removal β€” the rubric explicitly says they will test "what does your graph look like with a highly connected node removed?"
52
+
53
+ ## Prompt 5
54
+ **Component**: Network node removal endpoint (`backend/routes/network.py`)
55
+ **Prompt**: "Add GET /api/v1/network/remove-node/:author that removes a node from the graph, recomputes connected components, and returns before/after stats with an impact description."
56
+ **Issue**: Reconstructed the entire NetworkX graph from JSON on every call (~100ms overhead). Crashed with 500 error when the author didn't exist β€” no validation.
57
+ **Fix**: Cache base graph in memory at startup. Use `G.copy()` and remove from the copy (never mutate original). Return 404 with clear message if author not found. Impact description includes specific numbers: "Removing John3262005 fragmented the network: components 72 β†’ 83."
58
+
59
+ ---
60
+
61
+ The rubric also requires a tunable cluster count parameter and explicitly mentions testing extreme values.
62
+
63
+ ## Prompt 6
64
+ **Component**: Clustering API with tunable k (`backend/routes/clusters.py`)
65
+ **Prompt**: "Implement GET /api/v1/clusters?k=N that returns pre-computed cluster assignments for cached k values, or runs KMeans on-the-fly for non-cached values."
66
+ **Issue**: No validation on k parameter β€” passing k=0, k=-5, or k=10000 either crashed KMeans or returned meaningless results.
67
+ **Fix**: Clamp k to [2, 50]. If outside range, return clamped value with a warning message in the response. Pre-computed k values load from SQLite instantly; non-cached values compute in <1s.
68
+
69
+ ---
70
+
71
+ ### Stage 3: LLM Integration
72
+
73
+ With the data endpoints working, the next phase was integrating Google's Gemma 3 27B for dynamic chart summaries (the rubric requires plain-language summaries beneath each time-series plot, generated dynamically from actual data).
74
+
75
+ ## Prompt 7
76
+ **Component**: LLM prompt engineering (`backend/services/llm_service.py`)
77
+ **Prompt**: "My chart summaries are too vague β€” they say 'The chart shows posts over time.' I need them to mention specific subreddit names, dates, and numbers. Here's the data I'm passing: [peak period, top subs, start/end values]. Rewrite the system prompt."
78
+ **Issue**: Model (Gemma 3 27B) hallucinated dates outside the dataset range (e.g., "June 2025" when data ends in February 2025) and returned markdown headers like `## Executive Summary`.
79
+ **Fix**: Added hard constraints: "Dataset covers July 2024 to February 2025 ONLY. Do NOT mention dates outside this range." and "NO markdown, NO headers." Reduced temperature from 0.7 to 0.3. Added backend post-processing to strip remaining markdown.
80
+
81
+ ---
82
+
83
+ After the prompt engineering was working in standalone tests, the LLM started silently failing when called through Flask β€” fallback templates appeared instead of real summaries.
84
+
85
+ ## Prompt 8
86
+ **Component**: LLM API initialization bug (`backend/services/llm_service.py`)
87
+ **Prompt**: "LLM summaries work in standalone test but silently fall back to template summaries when running through Flask. Google AI calls fail with no error. What's happening?"
88
+ **Issue**: The module read `os.environ.get('GEMINI_API_KEY')` at import time, but Flask loads `.env` during `create_app()` β€” after imports. Key was always empty when `genai.configure()` ran.
89
+ **Fix**: Changed to lazy initialization with `_ensure_configured()` that runs on the first LLM call, not at import. Classic Flask app factory pitfall β€” module-level code runs before the app context exists.
90
+
91
+ ---
92
+
93
+ ### Stage 4: Frontend
94
+
95
+ With the backend stable, the next phase was the React frontend β€” six pages (Overview, Time Series, Network, Topics, SearchAI, Embeddings), shared layout, and interactive charts. Most of the React work used standard patterns, but the network graph was the first time using `react-force-graph-2d`.
96
+
97
+ ## Prompt 9
98
+ **Component**: React force-directed graph rendering (`frontend/src/pages/Network.jsx`)
99
+ **Prompt**: "Using react-force-graph-2d with 320 nodes. Default rendering shows all node labels at every zoom level β€” unreadable. How do I use the nodeCanvasObject callback to show labels only when zoomed in past a threshold?"
100
+ **Issue**: Custom rendering worked, but the graph started in one corner instead of centering, and the force simulation ran indefinitely consuming CPU.
101
+ **Fix**: Added `zoomToFit(400, 50)` with setTimeout after layout settles to auto-center. Set `cooldownTicks={200}` to stop simulation after convergence. Labels only appear at `globalScale > 5` for high-degree nodes.
102
+
103
+ ---
104
+
105
+ The time-series page used Recharts, which had its own quirks around missing data points and chart annotations.
106
+
107
+ ## Prompt 10
108
+ **Component**: Recharts time-series configuration (`frontend/src/pages/TimeSeries.jsx`)
109
+ **Prompt**: "Recharts LineChart drops lines to zero when a subreddit has no posts in a given week, creating misleading spikes. How to skip the gap? Also, how to add ReferenceLine annotations for political events?"
110
+ **Issue**: `connectNulls` fixed the gap issue, but ReferenceLine event labels overlapped when multiple events were close together on the x-axis.
111
+ **Fix**: Used `position='top'` with 10px font for labels. Accepted some overlap as unavoidable β€” hover tooltips provide full labels anyway.
112
+
113
+ ---
114
+
115
+ After basic search was working, I added a feature where the search results would also show a time-series chart of how matching posts trended over time. This required deciding between modifying the existing endpoint or creating a new one.
116
+
117
+ ## Prompt 11
118
+ **Component**: Search time-series feature design (`backend/routes/search.py`, `frontend/src/components/common/SearchTrendChart.jsx`)
119
+ **Prompt**: "I need to show a time-series chart of posts matching a semantic search query in the search results. Should I modify the existing /search endpoint to also return time-series data, or create a separate endpoint?"
120
+ **Issue**: AI suggested modifying `/search` to include time-series data β€” would block the entire response on time-series computation, doubling perceived latency.
121
+ **Fix**: Created separate `/search/timeseries` endpoint. Frontend fires both requests with `Promise.allSettled` β€” search results appear as soon as the LLM responds, chart fills in independently. Used a lower similarity threshold (0.30) for time-series to capture more posts.
122
+
123
+ ---
124
+
125
+ The Topics page had a donut chart and cluster cards, but they were initially static. The next step was making them interactive with expandable detail views.
126
+
127
+ ## Prompt 12
128
+ **Component**: Cluster expandable detail panels (`frontend/src/pages/Clusters.jsx`)
129
+ **Prompt**: "I have a donut chart and cluster cards. Want clicking either to expand a detail panel showing subreddit breakdown bars and top 10 posts with Reddit links. How to handle state and auto-scroll?"
130
+ **Issue**: Click handler used the array index from the Recharts payload, but segments were sorted by size β€” index didn't match the cluster ID. The expanded panel also appeared off-screen.
131
+ **Fix**: Changed click handler to use `data.id` directly from the payload. Added `scrollIntoView({ behavior: 'smooth' })` with a 100ms setTimeout for the panel to render first. Non-selected segments dim to 30% opacity for visual focus.
132
+
133
+ ---
134
+
135
+ ### Stage 5: UI Polish
136
+
137
+ With all features functional, the next phase was visual polish β€” switching from a plain sidebar layout to a glassmorphic top navbar with a dark/light mode toggle, adding the gradient background, and refining typography. The dark mode CSS was the trickiest part.
138
+
139
+ ## Prompt 13
140
+ **Component**: Dark mode CSS overrides (`frontend/src/index.css`)
141
+ **Prompt**: "I have a dark/light mode toggle that adds a 'dark-mode' class to a container div. My cards use Tailwind bg-white/70. How do I override these in dark mode without modifying every component?"
142
+ **Issue**: AI suggested Tailwind's `dark:` prefix β€” doesn't work because our dark mode is class-based on a child container, not the `<html>` element.
143
+ **Fix**: Used plain CSS overrides targeting `.dark-mode .bg-white\/70 { background: rgba(20, 20, 25, 0.8) !important; }` with escaped forward slash. Also added overrides for Recharts text, tooltips, and grid lines.
144
+
145
+ ---
146
+
147
+ The Embeddings page needed a Datamapplot HTML file generated from the UMAP coordinates with a custom color palette matching the political spectrum.
148
+
149
+ ## Prompt 14
150
+ **Component**: Datamapplot generation (`backend/pipeline/build_datamapplot.py`)
151
+ **Prompt**: "Generate an interactive Datamapplot HTML from UMAP coordinates with subreddit labels and a custom color palette matching the political spectrum (reds for right-leaning, blues for left-leaning, purples for mixed)."
152
+ **Issue**: Used `point_size` parameter that doesn't exist in the current Datamapplot API β€” function signature had changed between versions.
153
+ **Fix**: Checked the actual function signature with `help(datamapplot.create_interactive_plot)`. Removed unsupported parameters and used `label_color_map` to map subreddit names to political-spectrum colors.
154
+
155
+ ---
156
+
157
+ ### Stage 6: Narrative & Verification
158
+
159
+ The final feature work was adding the narrative content β€” the methodology section, key findings panel, and contextual explanations on each page. Before publishing any statistics on the dashboard, every claim needed to be verified against the actual database.
160
+
161
+ ## Prompt 15
162
+ **Component**: Key findings data verification (`frontend/src/pages/Overview.jsx`)
163
+ **Prompt**: "Write SQL queries to verify these claims against the database before I hardcode them: activity surge % after inauguration, bridge account count, M_i_c_K's posting frequency, and top news domains per subreddit."
164
+ **Issue**: Verification queries were correct, but they revealed the original estimates were wrong β€” "340% surge" (actual: 1,500%) and "M_i_c_K posted 246 times in 7 months" (actual: 26 days = 9.46/day).
165
+ **Fix**: Corrected every claim with verified numbers. Lesson: never display estimated numbers on a dashboard that evaluators will scrutinize. Every statistic shown is now backed by a verified database query.
166
+
167
+ ---
168
+
169
+ ### Stage 7: Deployment
170
+
171
+ With everything stress-tested and working locally, the last step was deploying to a public URL. The first attempt on Render.com failed, leading to a switch to Hugging Face Spaces.
172
+
173
+ ## Prompt 16
174
+ **Component**: Deployment configuration (`Dockerfile`)
175
+ **Prompt**: "Configure a Dockerfile for Hugging Face Spaces β€” Python 3.11, Node.js 22, build the React frontend, run the data pipeline during Docker build, serve with gunicorn on port 7860."
176
+ **Issue**: Initial deployment on Render.com failed with out-of-memory on the 512MB free tier β€” sentence-transformer model (~90MB) plus embeddings (13MB) plus Flask overhead exceeded the limit.
177
+ **Fix**: Switched to Hugging Face Spaces (16GB RAM on Docker free tier). Restructured Dockerfile to run the full pipeline during Docker build so large pre-computed files don't need to be committed (avoiding GitHub fork LFS restrictions).