tiahchia commited on
Commit
41159b4
·
verified ·
1 Parent(s): a17207c

Update utils.py

Browse files
Files changed (1) hide show
  1. utils.py +50 -113
utils.py CHANGED
@@ -1,113 +1,50 @@
1
- import gradio as gr
2
- from utils import generate_challenge, generate_image
3
- import json
4
-
5
- TOPICS = [
6
- "recursion", "Fibonacci sequence", "loops", "dictionary usage",
7
- "list comprehensions", "sorting algorithms", "basic OOP"
8
- ]
9
-
10
- TYPING_GAME_HTML = f"""
11
- <div id="typingGame" style="width:100%; height:400px; position:relative; overflow:hidden; border:1px solid #ccc; margin-bottom:20px;"></div>
12
- <div style="text-align:center;">
13
- <button id="startGameBtn" style="padding:10px 20px; font-size:16px;">Start Typing Game</button>
14
- <p>Score: <span id="score">0</span></p>
15
- </div>
16
- <script>
17
- let gameArea = document.getElementById("typingGame");
18
- let startBtn = document.getElementById("startGameBtn");
19
- let scoreDisplay = document.getElementById("score");
20
- let letters = [];
21
- let animationFrame;
22
- let score = 0;
23
- let gameStarted = false;
24
-
25
- const TOPICS = {json.dumps(TOPICS)};
26
-
27
- function randomLetter() {{
28
- const topic = TOPICS[Math.floor(Math.random() * TOPICS.length)];
29
- const char = topic[Math.floor(Math.random() * topic.length)];
30
- return char;
31
- }}
32
-
33
- function spawnLetter() {{
34
- const char = randomLetter();
35
- const span = document.createElement("span");
36
- span.textContent = char;
37
- span.style.position = "absolute";
38
- span.style.top = "0px";
39
- span.style.left = Math.random() * (gameArea.offsetWidth - 20) + "px";
40
- span.style.fontSize = "32px";
41
- span.style.fontFamily = "Consolas, monospace";
42
- span.style.color = "#fa29bc";
43
- letters.push({{elem: span, y: 0}});
44
- gameArea.appendChild(span);
45
- }}
46
-
47
- function update() {{
48
- for (let i = letters.length - 1; i >= 0; i--) {{
49
- let letter = letters[i];
50
- letter.y += 2; // speed
51
- letter.elem.style.top = letter.y + "px";
52
- if (letter.y > gameArea.offsetHeight) {{
53
- gameArea.removeChild(letter.elem);
54
- letters.splice(i,1);
55
- }}
56
- }}
57
- animationFrame = requestAnimationFrame(update);
58
- }}
59
-
60
- document.addEventListener("keydown", e => {{
61
- if (!gameStarted) return;
62
- for (let i = letters.length - 1; i >=0; i--) {{
63
- let letter = letters[i];
64
- if (letter.elem.textContent.toLowerCase() === e.key.toLowerCase()) {{
65
- score++;
66
- scoreDisplay.textContent = score;
67
- // pop animation
68
- letter.elem.style.transition = "transform 0.2s, opacity 0.2s";
69
- letter.elem.style.transform = "scale(2)";
70
- letter.elem.style.opacity = "0";
71
- setTimeout(()=>{{gameArea.removeChild(letter.elem)}},200);
72
- letters.splice(i,1);
73
- break;
74
- }}
75
- }}
76
- }});
77
-
78
- startBtn.onclick = () => {{
79
- if (gameStarted) return;
80
- gameStarted = true;
81
- spawnInterval = setInterval(spawnLetter, 600); // spawn every 0.6s
82
- update();
83
- }};
84
- </script>
85
- """
86
-
87
-
88
- # ---------- Gradio Interface ----------
89
- with gr.Blocks(css="""
90
- body { background:#111; color:#fa29bc; font-family:Consolas, monospace; }
91
- .gr-button { background:#fa29bc; color:white; border:none; }
92
- .gr-download { background:#fa29bc; color:white; border:none; }
93
- footer { display:none; }
94
- """) as demo:
95
- gr.Markdown("## 🚀 Python Challenge Generator")
96
- gr.HTML(TYPING_GAME_HTML)
97
-
98
- with gr.Row():
99
- download_btn = gr.File(label="Download Challenge")
100
- image_output = gr.Image(label="Code Snippet")
101
-
102
- generate_btn = gr.Button("Generate Challenge")
103
-
104
- def generate():
105
- text, file_path = generate_challenge()
106
- topic = text.split("\n")[0] # first line as topic
107
- image = generate_image(topic)
108
- return file_path, image
109
-
110
- generate_btn.click(fn=generate, outputs=[download_btn, image_output])
111
-
112
- if __name__ == "__main__":
113
- demo.launch()
 
1
+ import os
2
+ import openai
3
+ from PIL import Image
4
+ from io import BytesIO
5
+ import base64
6
+
7
+ # ---------- Load OpenAI API Key ----------
8
+ OPENAI_API_KEY = os.environ.get("OPENAI_API_KEY")
9
+ openai.api_key = OPENAI_API_KEY
10
+
11
+ # ---------- Generate Coding Challenge ----------
12
+ def generate_challenge(topic="Python Challenge"):
13
+ """
14
+ Generates a step-by-step Python tutorial with a small challenge.
15
+ Returns a tuple: (path to text file, text content)
16
+ """
17
+ prompt = f"""
18
+ Create a fun, step-by-step Python tutorial for beginners on the topic: "{topic}".
19
+ Include explanations, Python code snippets, and end with a small practice challenge.
20
+ """
21
+ response = openai.chat.completions.create(
22
+ model="gpt-4",
23
+ messages=[{"role": "user", "content": prompt}]
24
+ )
25
+ text = response.choices[0].message.content
26
+
27
+ # Save to text file
28
+ file_path = "/tmp/challenge.txt"
29
+ with open(file_path, "w", encoding="utf-8") as f:
30
+ f.write(text)
31
+
32
+ return file_path, text
33
+
34
+ # ---------- Generate Terminal-Style Code Image ----------
35
+ def generate_image(code_snippet, size="1024x1024"):
36
+ """
37
+ Generates an image of a code snippet in a dark terminal / VSCode style using OpenAI.
38
+ Returns a PIL image object.
39
+ """
40
+ prompt = f"A screenshot of a terminal window showing this Python code:\n\n{code_snippet}\n" \
41
+ "Terminal has dark background, monospace font, minimal UI"
42
+ response = openai.images.generate(
43
+ model="gpt-image-1",
44
+ prompt=prompt,
45
+ size=size
46
+ )
47
+ image_base64 = response.data[0].b64_json
48
+ image = Image.open(BytesIO(base64.b64decode(image_base64)))
49
+ display_image = image.resize((image.width // 2, image.height // 2))
50
+ return display_image