|
11 | 11 | import random |
12 | 12 | from pathlib import Path |
13 | 13 | from datetime import datetime |
14 | | -from typing import List, Union |
| 14 | +from typing import List, Union, Callable |
15 | 15 |
|
16 | 16 | ## Installed package imports |
17 | 17 | import requests |
|
44 | 44 | DEFAULT_FONT = "standard" |
45 | 45 |
|
46 | 46 |
|
| 47 | +def generate_problem_casual(problem_markdown: str) -> str: |
| 48 | + if OPENAI_API_KEY == "": |
| 49 | + print("[*] OpenAI API Key not found. Exiting ...") |
| 50 | + return "" |
| 51 | + |
| 52 | + prompt = f""" |
| 53 | +You are a friendly storyteller and teacher, explaining competitive programming problems in a simple, relaxing way — |
| 54 | +something light enough for a reader to enjoy before bed when their brain is only at 10-20% power. |
| 55 | +
|
| 56 | +Given the following Codeforces problem statement (in markdown format), produce a casual explanation that feels |
| 57 | +like a conversation, not a lecture. Your response should be written in **plain markdown** with a soft, easy-to-read style. |
| 58 | +
|
| 59 | +Please include: |
| 60 | +
|
| 61 | +--- |
| 62 | +
|
| 63 | +## 1. Gentle Storytelling Summary |
| 64 | +- Retell the problem in very simple words, like explaining to a friend. |
| 65 | +- Use small metaphors or analogies if it helps (e.g., “Imagine you’re sorting candies”). |
| 66 | +- Avoid heavy math terms unless absolutely necessary. |
| 67 | +
|
| 68 | +## 2. The Core Idea |
| 69 | +- What is the problem *really* asking for? |
| 70 | +- Describe it in everyday terms, focusing on the main trick or decision. |
| 71 | +
|
| 72 | +## 3. How You Might Think About Solving It |
| 73 | +- Give a casual sketch of how one might approach it, without going too deep into technical jargon. |
| 74 | +- Mention the key observation in plain English. |
| 75 | +- Include one or two “good to know” hints, but keep it lightweight. |
| 76 | +
|
| 77 | +## 4. A Cozy Closing Thought |
| 78 | +- End with a friendly note: encouragement, a fun analogy, or how this problem connects to daily life. |
| 79 | +- The tone should feel relaxing and supportive. |
| 80 | +
|
| 81 | +--- |
| 82 | +
|
| 83 | +### Problem Statement: |
| 84 | +
|
| 85 | +{problem_markdown} |
| 86 | +
|
| 87 | +--- |
| 88 | +
|
| 89 | +Formatting rules: |
| 90 | +- Do not use technical section headers like "algorithms", "system design", etc. |
| 91 | +- Keep it warm, casual, and low-pressure. |
| 92 | +- Avoid overwhelming lists or references. |
| 93 | +- Imagine the reader is tired but curious, and just wants to end the day with a little mental puzzle explained gently. |
| 94 | +""" |
| 95 | + |
| 96 | + response = client.chat.completions.create( |
| 97 | + model="gpt-4o-mini", |
| 98 | + messages=[ |
| 99 | + { |
| 100 | + "role": "system", |
| 101 | + "content": "You are a friendly teacher and storyteller. Always keep things simple, warm, and casual, with a tone that makes the reader feel at ease.", |
| 102 | + }, |
| 103 | + {"role": "user", "content": prompt}, |
| 104 | + ], |
| 105 | + temperature=0.7, |
| 106 | + max_tokens=2000, |
| 107 | + n=1, |
| 108 | + ) |
| 109 | + |
| 110 | + return response.choices[0].message.content.strip() |
| 111 | + |
| 112 | + |
47 | 113 | def generate_problem_analysis(problem_markdown: str) -> str: |
48 | 114 | if OPENAI_API_KEY == "": |
49 | 115 | print("[*] OpenAI API Key not found. Exiting ...") |
50 | 116 | return "" |
51 | 117 |
|
52 | | - print("[*] OpenAI API Key found.") |
53 | 118 | prompt = f""" |
54 | 119 | You are an expert competitive programming instructor and system architect with a talent for clear, insightful explanations. |
55 | 120 |
|
@@ -161,7 +226,10 @@ def example_algorithm(data): |
161 | 226 | response = client.chat.completions.create( |
162 | 227 | model="gpt-4o-mini", |
163 | 228 | messages=[ |
164 | | - {"role": "system", "content": "You are an expert competitive programming instructor and system architect. Provide highly detailed, structured, research-style responses with actionable insights, references, and clear learning roadmaps."}, |
| 229 | + { |
| 230 | + "role": "system", |
| 231 | + "content": "You are an expert competitive programming instructor and system architect. Provide highly detailed, structured, research-style responses with actionable insights, references, and clear learning roadmaps.", |
| 232 | + }, |
165 | 233 | {"role": "user", "content": prompt}, |
166 | 234 | ], |
167 | 235 | temperature=0.2, |
@@ -239,6 +307,29 @@ def requests_get(url: str) -> requests.Response: |
239 | 307 | return requests.get(url, verify=PROXY) |
240 | 308 |
|
241 | 309 |
|
| 310 | +def append_analysis( |
| 311 | + md_text: str, |
| 312 | + generator_fn: Callable[[str], str], |
| 313 | + label: str, |
| 314 | +) -> str: |
| 315 | + """ |
| 316 | + Apply a given analysis generator function (like generate_problem_analysis |
| 317 | + or generate_problem_casual), format the result, and append to md_text. |
| 318 | + """ |
| 319 | + generated = mdformat.text(generator_fn(md_text).strip()).replace("**", "__") |
| 320 | + |
| 321 | + md_text = ( |
| 322 | + f"{md_text}\n" |
| 323 | + "______________________________________________________________________\n\n" |
| 324 | + f"```markdown\n{get_art_formatted_text(label)}```\n\n" |
| 325 | + "______________________________________________________________________\n" |
| 326 | + f"\n{generated}\n" |
| 327 | + ) |
| 328 | + |
| 329 | + # fix strange unicode issues |
| 330 | + return md_text.replace(" ", " ").replace("’", "'").strip() + "\n" |
| 331 | + |
| 332 | + |
242 | 333 | def get_art_formatted_text(text: str) -> str: |
243 | 334 | result, _, _ = art.text2art( |
244 | 335 | text, |
@@ -341,21 +432,18 @@ def fetch_problem_statement( |
341 | 432 | f"{extracted_samples}" |
342 | 433 | ) |
343 | 434 | md_text = mdformat.text(md_text, options={"wrap": 80}) |
344 | | - art_formatted_text_for_title = get_art_formatted_text((title.split(".")[1]).replace(' ', ' ')) |
345 | | - md_text = f"# Problem\n\n```markdown\n{art_formatted_text_for_title}```\n\n" f"{md_text}" |
346 | | - generated_problem_analysis = mdformat.text( |
347 | | - generate_problem_analysis(md_text).strip() |
348 | | - ).replace("**", "__") |
| 435 | + art_formatted_text_for_title = get_art_formatted_text( |
| 436 | + (title.split(".")[1]).replace(" ", " ") |
| 437 | + ) |
349 | 438 | md_text = ( |
350 | | - f"{md_text}\n" |
351 | | - "______________________________________________________________________\n\n" |
352 | | - f"```markdown\n{get_art_formatted_text('OpenAI Analysis')}```\n\n" |
353 | | - "______________________________________________________________________\n" |
354 | | - f"\n{generated_problem_analysis}\n" |
| 439 | + f"# Problem\n\n```markdown\n{art_formatted_text_for_title}```\n\n" f"{md_text}" |
355 | 440 | ) |
356 | 441 |
|
357 | | - # strange unicode character in output -- skipping |
358 | | - md_text = md_text.replace(' ', ' ').replace('’', '\'').strip() + "\n" |
| 442 | + for generator_fn, label in [ |
| 443 | + (generate_problem_analysis, "OpenAI Analysis"), |
| 444 | + (generate_problem_casual, "Casual Analysis"), |
| 445 | + ]: |
| 446 | + md_text = append_analysis(md_text, generator_fn, label) |
359 | 447 |
|
360 | 448 | # Save locally |
361 | 449 | save_problem_markdown(problem_name, index, md_text, problem_rating, contest_id) |
|
0 commit comments