A browser extension that enhances any Codeforces problem page by injecting:
- Hint 1–5 (incremental hints from vague to nearly complete guidance)
- Observations (key insights needed to solve the problem)
- Full Editorial Logic (summarized editorial reasoning)
All generated content is produced via Google Gemini (Gemini 1.5 Flash) using the official problem statement and editorial. This README explains the idea, project structure, setup, and usage in detail.
Codeforces problems often come with official editorials, but navigating back and forth between problem statements and editorial pages can interrupt coding flow. The editorial pages in Codeforces also do not follow a standard template , leading to some editorials being rich in hints while the others may just provide the solution without necessary insights.
The Codeforces Hints Generator aims to solve this by automatically fetching the editorial, using Google Gemini to generate a structured set of hints and observations, and embedding them directly under the problem statement. Users can click “Hint 1” through “Hint 5,” “Observations,” or “Full Editorial” to reveal progressively more detailed guidance without leaving the page.
This extension works on any Codeforces problem—whether from a contest or the problemset—by hooking into the page’s DOM, fetching the editorial (either from /contest/<id>/tutorial or from a linked blog post), and sending both the statement and editorial to Gemini. The resulting JSON payload is parsed and rendered as interactive buttons and content blocks.
-
Content Script Injection A content script (
content_script.js) runs on Codeforces problem URLs and manipulates the DOM to insert UI elements. -
Editorial Retrieval
- Attempts to fetch
/contest/<contestId>/tutorialfirst. - If not available, finds a “Tutorial” link in the sidebar, follows it to the blog post, and extracts the editorial section.
- Attempts to fetch
-
Google Gemini API
- Uses Gemini 1.5 Flash (
generateContentendpoint) to produce a JSON containing: • An array of 5 hints • A block of observations • A block of full editorial logic - The prompt template ensures hints go from vague to nearly complete, observations capture bullet‐style insights, and the editorial summarizes the reasoning.
- Uses Gemini 1.5 Flash (
-
UI Injection
- Once the JSON is parsed, the extension creates a container under the problem statement with: • Five buttons labeled “Hint 1”…“Hint 5” • A button “Observations” • A button “Full Editorial”
- Clicking each button toggles the corresponding content’s visibility.
-
Separation of Secrets via Build Process
- The Gemini API key is kept out of Git by storing it in
api_key.txt(ignored by Git). - A simple Node.js build script (
build-key.js) replaces a placeholder__GEMINI_API_KEY__incontent_script.template.jswith the actual key, generatingcontent_script.jswhich is not committed.
- The Gemini API key is kept out of Git by storing it in
-
Styling
- All CSS lives in
styles.css.
- All CSS lives in
/codeforces-hints-generator
├── .gitignore
├── api_key.txt ← (Gemini key)
├── build-key.js ← Build script: generates content_script.js
├── content_script.template.js ← Template JS
├── content_script.js ← Generated JS
├── styles.css ← All UI styling
├── icon48.png ← 48×48 toolbar icon
├── icon128.png ← 128×128 store icon
├── manifest.json ← Chrome extension manifest (MV3)
└── README.md ← Detailed instructions & documentation
-
api_key.txtContains only your Gemini API key on a single line. -
build-key.jsNode.js script that readsapi_key.txt, replaces the__GEMINI_API_KEY__placeholder incontent_script.template.js, and writes outcontent_script.js. -
content_script.template.jsThe core logic without real key. Contains the placeholderconst GEMINI_API_KEY = "__GEMINI_API_KEY__";thatbuild-key.jsreplaces. -
content_script.jsThe actual content file, generated by runningnode build-key.js. Contains your real key inlined. -
styles.cssAll CSS rules for#cf-hints-container,.cf-hint-button,.cf-hint-content,.cf-warning, etc. -
icon48.pngandicon128.pngRequired for a polished extension icon in the toolbar and store. -
manifest.jsonConfigures permissions, host patterns, and which scripts/css to inject.
- Node.js (v14 or newer) installed on your system.
- A valid Gemini API key with access to Gemini 1.5 Flash (
gemini-1.5-flash). - A modern Chromium‐based browser (Chrome, Edge, Brave, etc.)
git clone https://github.com/aayush-tripathi/codeforces-hints-generator.git
cd codeforces-hints-generator-
In the project root, create a file named
api_key.txt. -
Paste your Gemini API key into that file (no extra spaces or newlines).
echo "YOUR_REAL_GEMINI_KEY_HERE" > api_key.txt
Run:
node build-key.js-
You should see:
✅ content_script.js generated (Gemini key inlined).
-
Open your browser’s Extensions page:
- Chrome/Edge: navigate to
chrome://extensionsoredge://extensions.
- Chrome/Edge: navigate to
-
Enable Developer mode (Chrome/Edge) or Enable add-on debugging (Firefox).
-
Click “Load unpacked” (Chrome/Edge) or “Load Temporary Add-on” (Firefox).
-
Select this folder’s root (the directory containing
manifest.json). -
The extension should now appear in your toolbar and be active on Codeforces pages.
-
permissions:activeTab&scripting: allow dynamic injection on the active Codeforces tab.
-
host_permissions: restricts content script to Codeforces URLs only. -
content_scripts:matches: the URL patterns where the script runs.js: the generatedcontent_script.js(needs to exist afterbuild-key.js).css: injectsstyles.cssto style the generated UI.
-
icons:48×48for toolbar.128×128for the store or high‐res contexts.
The core of this extension is content_script.template.js (transformed at build time). Here’s what happens at runtime:
-
Problem Detection
- The script reads
window.location.pathnameand uses a regex to detect if the URL matches/contest/<id>/problem/<index>or/problemset/problem/<id>/<index>.
- The script reads
-
Editorial Fetching
-
Try direct tutorial URL:
https://codeforces.com/contest/<contestId>/tutorial.- If the request is OK, parse HTML with
DOMParser. - Look for
#problem-<Index> .tutorialand extract its inner text.
- If the request is OK, parse HTML with
-
Fallback to blog post:
- Find any
<a>on the page whose text starts with “Tutorial” (e.g. “Tutorial #1”). - Fetch that blog URL, parse HTML, and locate the
<a href="/contest/<contestId>/problem/<problemIndex>">. - Once found, gather sibling nodes until the next problem‐heading link, concatenating their
.innerText. - If that fails, as a final fallback, grab the entire
.ttypographyblock.
- Find any
- If
editorialTextis still empty, exit.
-
-
Gemini Prompting
-
Build a markdown‐style prompt that includes:
- Instruction to generate 5 hints, observations, and full editorial logic.
- The problem statement (from
.problem-statement). - The fetched editorial text.
-
Use the
fetchAPI to POST to:https://generativelanguage.googleapis.com/v1beta/models/gemini-1.5-flash:generateContent?key=<API_KEY> -
If Gemini returns an error (non‐2xx), insert a red‐background warning and exit.
-
-
Cleaning and Parsing the Gemini Response
- Extract
rawText = geminiData.candidates[0].content.parts[0].text(fallback to empty string). - Trim and remove any triple‐backtick fences (
json …). - If the cleaned text doesn’t start with
{, find the first{and last}and slice the substring. - Attempt
JSON.parse(cleaned). If parsing fails, insert a warning and exit.
- Extract
-
UI Injection
-
Call
injectUI(jsonResponse)with the parsed object: -
The CSS rules in
styles.cssdefine the visual appearance for all IDs/classes used above.
-
All style rules are centralized in styles.css. The content script references these IDs and class names
-
No UI appears:
- Confirm you ran
node build-key.jssuccessfully and thatcontent_script.jsis present (in the same folder asmanifest.json). - Check DevTools → Console for any
CF-Hints:logs or errors. - Ensure you’re on a matching URL pattern (contest or problemset problem).
- Verify that
styles.cssandcontent_script.jsare both referenced correctly inmanifest.json.
- Confirm you ran
-
Gemini API errors:
- If
api_key.txtis missing or blank, you’ll see a.cf-warningunder the problem statement prompting you to update the key. - If the key is invalid or expired, Gemini will return an error. That error text is logged to console and a warning banner (styled by
.cf-warning) appears.
- If
-
Parsing failures:
- If Gemini returns non‐JSON (e.g., with unexpected formatting), the script attempts to strip backticks and extract
{…}. If parsing still fails, a warning appears. - Check DevTools → Console to view the raw response.
- If Gemini returns non‐JSON (e.g., with unexpected formatting), the script attempts to strip backticks and extract
-
Permission issues:
-
Ensure
manifest.jsonincludes:"permissions": ["activeTab", "scripting"], "host_permissions": ["https://codeforces.com/*"]
-
Without those, the content script cannot run or fetch external resources.
-
-
Modify Hint Content
- Edit
content_script.template.jsto tweak the Gemini prompt (e.g., change hint granularity or phrasing). - Run
node build-key.jsand reload the extension.
- Edit
-
Change Styling
- Update
styles.cssfor new colors, fonts, or layout changes. - Save and reload the extension—no need to rebuild JS unless you change class or ID names.
- Update
-
Enable Caching
-
Add the
storagepermission tomanifest.json:"permissions": ["activeTab", "scripting", "storage"]
-
Modify
content_script.template.jsto store fetched editorials/hints inchrome.storage.localto avoid repeated Gemini calls on the same problem.
-
-
Support Additional Sites
- Change the
matchespatterns inmanifest.jsonto include other competitive programming domains (e.g., AtCoder, CodeChef). - Add site‐specific editorial‐scraping logic in
content_script.template.js.
- Change the
This project is licensed under the MIT License. Feel free to fork, modify, and redistribute under the same license.
Thanks and Happy Problem Solving!
