Hma47 commited on
Commit
a0cfa52
·
verified ·
1 Parent(s): 1bb6758

Upload 4 files

Browse files
Apache License.txt ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ Apache License
2
+ Version 2.0, January 2004
3
+ http://www.apache.org/licenses/
4
+
5
+ Copyright 2025 Shift Mind AI Labs
6
+
7
+ Licensed under the Apache License, Version 2.0 (the "License");
8
+ you may not use this file except in compliance with the License.
9
+ You may obtain a copy of the License at
10
+
11
+ http://www.apache.org/licenses/LICENSE-2.0
12
+
13
+ Unless required by applicable law or agreed to in writing, software
14
+ distributed under the License is distributed on an "AS IS" BASIS,
15
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
+ See the License for the specific language governing permissions and
17
+ limitations under the License.
README.md ADDED
@@ -0,0 +1,90 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ title: "🧠 CodeTutor Pro – Intelligent Code Explanation Platform"
3
+ emoji: "💡"
4
+ colorFrom: "blue"
5
+ colorTo: "purple"
6
+ sdk: "static"
7
+ sdk_version: "0.1.0"
8
+ app_file: "index.html"
9
+ pinned: false
10
+ ---
11
+
12
+ # 🧠 CodeTutor Pro – Intelligent Code Explanation Platform
13
+ **Developed by Shift Mind AI Labs**
14
+
15
+ CodeTutor Pro is an open-source, privacy-first platform that transforms code into clear, beginner-friendly, and multi-language explanations—instantly powered by AI. Whether you are a student, teacher, or developer, this tool helps demystify code, deepen understanding, and accelerate your programming learning journey.
16
+
17
+ ---
18
+
19
+ ## 🚀 Features
20
+
21
+ - **Plain-Language Explanations:** Converts complex code into easy, jargon-free text.
22
+ - **Line-by-Line & Conceptual Analysis:** Detailed, sectioned explanations (no code snippets) with stepwise logic and key concepts.
23
+ - **Multi-Level Output:** Choose from “Complete Beginner” to “Advanced” for the right depth.
24
+ - **Supports All Languages:** Works with Python, Java, C++, JS, HTML, SQL, and more.
25
+ - **Full Multilingual UI:** 90+ languages, RTL/LTR support, instant translation (OpenAI API required).
26
+ - **Editable Explanations:** Output is content-editable for class notes, customization, or portfolio building.
27
+ - **Privacy-First:** API key and all data stored locally; never leaves your device.
28
+
29
+ ---
30
+
31
+ ## 🛠 How to Use
32
+
33
+ 1. **Open the tool** in your browser or on Hugging Face Spaces (no install/login).
34
+ 2. **Select your interface language** (auto-translate supported).
35
+ 3. **Enter your OpenAI API key** (kept private in your browser).
36
+ 4. **Paste or type your code** (any language; up to 1 million characters).
37
+ 5. *(Optional)* Select your programming language and explanation level.
38
+ 6. **Click “🧠 Generate Explanation”.**
39
+ 7. **Read, edit, and copy** your customized, sectioned explanation for class, homework, or sharing.
40
+ 8. **Switch languages or clear cache** anytime for updated UI and output.
41
+
42
+ ---
43
+
44
+ ## 👩‍🏫 For Educators: Classroom Applications
45
+
46
+ - **Instant Code Explanation:** Great for assignments, flipped learning, and project walkthroughs.
47
+ - **Student Differentiation:** Match output depth to learner level; use in ELL/multilingual classes.
48
+ - **Editable Output:** Use in LMS, printouts, or digital portfolios.
49
+ - **PD & Training:** Onboard new teachers to unfamiliar codebases or languages.
50
+
51
+ ---
52
+
53
+ ## 👨‍🎓 For Students: Benefits
54
+
55
+ - **Learn Any Code:** Instantly understand code in your preferred language and depth.
56
+ - **Practice Reflection:** Edit and personalize explanations for deeper learning.
57
+ - **Safe Exploration:** No accounts or data sharing—perfect for minors and privacy-sensitive contexts.
58
+
59
+ ---
60
+
61
+ ## 🔐 Data Privacy
62
+
63
+ - Your OpenAI API key, code, and all data are stored only on your device.
64
+ - Nothing is transmitted to Shift Mind AI Labs, Hugging Face, or third parties.
65
+
66
+ ---
67
+
68
+ ## 📄 License
69
+
70
+ Licensed under the [Apache License 2.0](./LICENSE).
71
+
72
+ ---
73
+
74
+ ## 🧠 About Shift Mind AI Labs
75
+
76
+ Shift Mind AI Labs builds open-source, ethical AI tools for global education, digital skills, and lifelong learning.
77
+
78
+ 🌐 https://www.shiftmind.io
79
+ ✉️ info@shiftmind.io
80
+
81
+ ---
82
+
83
+ ## 🙌 Contributing
84
+
85
+ Feedback, pull requests, and pilots welcome!
86
+ For partnerships, research, or school programs: **info@shiftmind.io**
87
+
88
+ ---
89
+
90
+ *Bringing expert code explanations to every learner, everywhere, in every language.*
index.html ADDED
@@ -0,0 +1,2142 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <title>CodeTutor Pro - Intelligent Code Explanation Platform</title>
6
+ <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
7
+ <style>
8
+ :root {
9
+ --primary: #7c3aed;
10
+ --secondary: #8b5cf6;
11
+ --accent: #c4b5fd;
12
+ --background: #f8fafc;
13
+ --surface: #ffffff;
14
+ --text: #1e293b;
15
+ --text-secondary: #64748b;
16
+ --border: #e2e8f0;
17
+ --success: #10b981;
18
+ --warning: #f59e0b;
19
+ --error: #ef4444;
20
+ --shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
21
+ --shadow-lg: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05);
22
+ }
23
+
24
+ * {
25
+ box-sizing: border-box;
26
+ margin: 0;
27
+ padding: 0;
28
+ }
29
+
30
+ body {
31
+ font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
32
+ background: linear-gradient(135deg, #f1f5f9 0%, #e2e8f0 100%);
33
+ color: var(--text);
34
+ line-height: 1.6;
35
+ min-height: 100vh;
36
+ padding: 15px;
37
+ direction: ltr;
38
+ text-align: left;
39
+ }
40
+
41
+ /* RTL Support - Comprehensive */
42
+ body.rtl {
43
+ direction: rtl;
44
+ text-align: right;
45
+ }
46
+
47
+ body.rtl .form-grid {
48
+ direction: rtl;
49
+ }
50
+
51
+ body.rtl .header {
52
+ direction: rtl;
53
+ }
54
+
55
+ body.rtl .features-grid {
56
+ direction: rtl;
57
+ }
58
+
59
+ body.rtl .settings-bar {
60
+ direction: rtl;
61
+ }
62
+
63
+ body.rtl .language-info {
64
+ flex-direction: row-reverse;
65
+ }
66
+
67
+ body.rtl .form-group {
68
+ text-align: right;
69
+ }
70
+
71
+ body.rtl .landing-form {
72
+ text-align: right;
73
+ }
74
+
75
+ body.rtl .landing-form h2 {
76
+ text-align: center;
77
+ }
78
+
79
+ body.rtl .api-key-section {
80
+ right: 15px;
81
+ left: auto;
82
+ }
83
+
84
+ body.rtl .char-counter {
85
+ text-align: left;
86
+ }
87
+
88
+ body.rtl .form-section h3 {
89
+ flex-direction: row-reverse;
90
+ }
91
+
92
+ body.rtl .output-section h2 {
93
+ flex-direction: row-reverse;
94
+ }
95
+
96
+ body.rtl .generate-btn {
97
+ direction: rtl;
98
+ }
99
+
100
+ body.rtl .spinner {
101
+ margin-right: 0;
102
+ margin-left: 8px;
103
+ }
104
+
105
+ body.rtl .feature-card .icon {
106
+ direction: ltr; /* Keep emojis in LTR */
107
+ }
108
+
109
+ body.rtl .edit-notice {
110
+ direction: rtl;
111
+ }
112
+
113
+ body.rtl .footer {
114
+ direction: rtl;
115
+ }
116
+
117
+ /* Ensure code areas remain LTR for readability */
118
+ body.rtl #codeInput,
119
+ body.rtl .output-area,
120
+ body.rtl pre,
121
+ body.rtl code {
122
+ direction: ltr;
123
+ text-align: left;
124
+ }
125
+
126
+ /* API key inputs should remain LTR */
127
+ body.rtl #apiKey,
128
+ body.rtl #landingApiKey {
129
+ direction: ltr;
130
+ text-align: left;
131
+ }
132
+
133
+ /* RTL List Formatting - Fix numbered lists positioning */
134
+ body.rtl ol {
135
+ padding-right: 20px;
136
+ padding-left: 0;
137
+ margin-right: 0;
138
+ margin-left: 0;
139
+ }
140
+
141
+ body.rtl ul {
142
+ padding-right: 20px;
143
+ padding-left: 0;
144
+ margin-right: 0;
145
+ margin-left: 0;
146
+ }
147
+
148
+ body.rtl li {
149
+ text-align: right;
150
+ direction: rtl;
151
+ margin-right: 0;
152
+ margin-left: 0;
153
+ padding-right: 0;
154
+ padding-left: 0;
155
+ }
156
+
157
+ /* Fix numbered list markers positioning in RTL */
158
+ body.rtl ol li {
159
+ list-style-position: inside;
160
+ text-align: right;
161
+ }
162
+
163
+ body.rtl ul li {
164
+ list-style-position: inside;
165
+ text-align: right;
166
+ }
167
+
168
+ /* Ensure proper spacing for RTL lists */
169
+ body.rtl .output-area ol,
170
+ body.rtl .output-area ul {
171
+ margin: 10px 0;
172
+ padding-right: 25px;
173
+ padding-left: 0;
174
+ }
175
+
176
+ body.rtl .output-area li {
177
+ margin-bottom: 5px;
178
+ text-align: right;
179
+ direction: rtl;
180
+ }
181
+
182
+ .container {
183
+ max-width: 1200px;
184
+ margin: 0 auto;
185
+ background: var(--surface);
186
+ border-radius: 16px;
187
+ box-shadow: var(--shadow-lg);
188
+ overflow: hidden;
189
+ position: relative;
190
+ }
191
+
192
+ /* Landing Page Styles */
193
+ .landing-page {
194
+ display: block;
195
+ padding: 40px;
196
+ text-align: center;
197
+ min-height: 80vh;
198
+ display: flex;
199
+ flex-direction: column;
200
+ justify-content: center;
201
+ align-items: center;
202
+ }
203
+
204
+ .landing-page.hidden {
205
+ display: none;
206
+ }
207
+
208
+ .landing-header {
209
+ margin-bottom: 40px;
210
+ }
211
+
212
+ .landing-header h1 {
213
+ font-size: 3rem;
214
+ font-weight: 800;
215
+ background: linear-gradient(135deg, var(--primary) 0%, var(--secondary) 100%);
216
+ -webkit-background-clip: text;
217
+ -webkit-text-fill-color: transparent;
218
+ background-clip: text;
219
+ margin-bottom: 16px;
220
+ }
221
+
222
+ .landing-header .subtitle {
223
+ font-size: 1.3rem;
224
+ color: var(--text-secondary);
225
+ font-weight: 500;
226
+ margin-bottom: 12px;
227
+ }
228
+
229
+ .landing-header .description {
230
+ font-size: 1.1rem;
231
+ color: var(--text-secondary);
232
+ max-width: 600px;
233
+ margin: 0 auto;
234
+ }
235
+
236
+ .landing-form {
237
+ background: var(--surface);
238
+ border: 2px solid var(--border);
239
+ border-radius: 16px;
240
+ padding: 40px;
241
+ max-width: 500px;
242
+ width: 100%;
243
+ box-shadow: var(--shadow-lg);
244
+ }
245
+
246
+ .landing-form h2 {
247
+ color: var(--primary);
248
+ font-size: 1.5rem;
249
+ font-weight: 700;
250
+ margin-bottom: 30px;
251
+ text-align: center;
252
+ }
253
+
254
+ .form-group {
255
+ margin-bottom: 25px;
256
+ text-align: left;
257
+ }
258
+
259
+ .form-group label {
260
+ display: block;
261
+ margin-bottom: 8px;
262
+ font-weight: 600;
263
+ color: var(--text);
264
+ font-size: 1rem;
265
+ }
266
+
267
+ .form-group input,
268
+ .form-group select {
269
+ width: 100%;
270
+ padding: 14px 16px;
271
+ border: 2px solid var(--border);
272
+ border-radius: 8px;
273
+ font-size: 1rem;
274
+ font-family: inherit;
275
+ background: var(--surface);
276
+ transition: all 0.2s ease;
277
+ }
278
+
279
+ .form-group input:focus,
280
+ .form-group select:focus {
281
+ outline: none;
282
+ border-color: var(--primary);
283
+ box-shadow: 0 0 0 3px rgba(124, 58, 237, 0.1);
284
+ }
285
+
286
+ .start-btn {
287
+ background: linear-gradient(135deg, var(--primary) 0%, var(--secondary) 100%);
288
+ color: white;
289
+ padding: 16px 32px;
290
+ border: none;
291
+ border-radius: 12px;
292
+ font-size: 1.2rem;
293
+ font-weight: 700;
294
+ cursor: pointer;
295
+ transition: all 0.3s ease;
296
+ width: 100%;
297
+ margin-top: 10px;
298
+ }
299
+
300
+ .start-btn:hover {
301
+ transform: translateY(-2px);
302
+ box-shadow: 0 12px 24px -8px rgba(124, 58, 237, 0.4);
303
+ }
304
+
305
+ .start-btn:disabled {
306
+ opacity: 0.7;
307
+ cursor: not-allowed;
308
+ transform: none;
309
+ }
310
+
311
+ /* Main App Styles */
312
+ .main-app {
313
+ display: none;
314
+ }
315
+
316
+ .main-app.active {
317
+ display: block;
318
+ }
319
+
320
+ /* Language and Settings Bar */
321
+ .settings-bar {
322
+ background: rgba(124, 58, 237, 0.05);
323
+ border-bottom: 1px solid var(--border);
324
+ padding: 15px 30px;
325
+ display: flex;
326
+ justify-content: space-between;
327
+ align-items: center;
328
+ flex-wrap: wrap;
329
+ gap: 15px;
330
+ }
331
+
332
+ .language-info {
333
+ display: flex;
334
+ align-items: center;
335
+ gap: 15px;
336
+ font-size: 0.9rem;
337
+ color: var(--text-secondary);
338
+ }
339
+
340
+ .change-language-btn,
341
+ .clear-cache-btn {
342
+ background: var(--primary);
343
+ color: white;
344
+ border: none;
345
+ padding: 8px 16px;
346
+ border-radius: 6px;
347
+ font-size: 0.85rem;
348
+ cursor: pointer;
349
+ transition: all 0.2s ease;
350
+ }
351
+
352
+ .change-language-btn:hover,
353
+ .clear-cache-btn:hover {
354
+ background: var(--secondary);
355
+ transform: translateY(-1px);
356
+ }
357
+
358
+ .clear-cache-btn {
359
+ background: var(--warning);
360
+ }
361
+
362
+ .clear-cache-btn:hover {
363
+ background: #d97706;
364
+ }
365
+
366
+ /* API Key Section - Static Position Top Left */
367
+ .api-key-section {
368
+ background: rgba(124, 58, 237, 0.05);
369
+ border: 1px solid rgba(124, 58, 237, 0.1);
370
+ border-radius: 8px;
371
+ padding: 12px;
372
+ margin: 15px;
373
+ max-width: 280px;
374
+ }
375
+
376
+ .api-key-section label {
377
+ font-size: 12px;
378
+ font-weight: 600;
379
+ color: var(--primary);
380
+ margin-bottom: 6px;
381
+ display: block;
382
+ }
383
+
384
+ .api-key-section input {
385
+ width: 100%;
386
+ padding: 8px 12px;
387
+ border: 1px solid var(--border);
388
+ border-radius: 6px;
389
+ font-size: 14px;
390
+ background: var(--surface);
391
+ transition: all 0.2s ease;
392
+ font-family: 'Courier New', monospace;
393
+ }
394
+
395
+ .api-key-section input:focus {
396
+ outline: none;
397
+ border-color: var(--primary);
398
+ box-shadow: 0 0 0 3px rgba(124, 58, 237, 0.1);
399
+ }
400
+
401
+ /* Main Content */
402
+ .main-content {
403
+ padding: 20px 30px 30px;
404
+ }
405
+
406
+ /* Header */
407
+ .header {
408
+ text-align: center;
409
+ margin-bottom: 25px;
410
+ padding-bottom: 20px;
411
+ border-bottom: 2px solid var(--border);
412
+ }
413
+
414
+ .header h1 {
415
+ font-size: 2.5rem;
416
+ font-weight: 800;
417
+ background: linear-gradient(135deg, var(--primary) 0%, var(--secondary) 100%);
418
+ -webkit-background-clip: text;
419
+ -webkit-text-fill-color: transparent;
420
+ background-clip: text;
421
+ margin-bottom: 8px;
422
+ }
423
+
424
+ .header .subtitle {
425
+ font-size: 1.1rem;
426
+ color: var(--text-secondary);
427
+ font-weight: 500;
428
+ }
429
+
430
+ .header .description {
431
+ font-size: 1rem;
432
+ color: var(--text-secondary);
433
+ margin-top: 12px;
434
+ max-width: 700px;
435
+ margin-left: auto;
436
+ margin-right: auto;
437
+ }
438
+
439
+ /* Code Explanation Features Overview */
440
+ .features-overview {
441
+ background: rgba(124, 58, 237, 0.05);
442
+ border: 1px solid rgba(124, 58, 237, 0.1);
443
+ border-radius: 12px;
444
+ padding: 20px;
445
+ margin-bottom: 25px;
446
+ }
447
+
448
+ .features-overview h3 {
449
+ color: var(--primary);
450
+ font-size: 1.2rem;
451
+ font-weight: 700;
452
+ margin-bottom: 15px;
453
+ text-align: center;
454
+ }
455
+
456
+ .features-grid {
457
+ display: grid;
458
+ grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
459
+ gap: 15px;
460
+ }
461
+
462
+ .feature-card {
463
+ background: rgba(124, 58, 237, 0.02);
464
+ border: 1px solid rgba(124, 58, 237, 0.1);
465
+ border-radius: 8px;
466
+ padding: 15px;
467
+ text-align: center;
468
+ transition: all 0.3s ease;
469
+ }
470
+
471
+ .feature-card:hover {
472
+ background: rgba(124, 58, 237, 0.05);
473
+ border-color: var(--primary);
474
+ transform: translateY(-2px);
475
+ }
476
+
477
+ .feature-card .icon {
478
+ font-size: 1.5rem;
479
+ margin-bottom: 8px;
480
+ }
481
+
482
+ .feature-card h4 {
483
+ color: var(--primary);
484
+ font-size: 0.9rem;
485
+ font-weight: 700;
486
+ margin-bottom: 6px;
487
+ }
488
+
489
+ .feature-card p {
490
+ font-size: 0.8rem;
491
+ color: var(--text-secondary);
492
+ line-height: 1.4;
493
+ }
494
+
495
+ /* Progress Bar */
496
+ .progress-container {
497
+ background: var(--border);
498
+ height: 6px;
499
+ border-radius: 3px;
500
+ margin: 15px 0;
501
+ overflow: hidden;
502
+ }
503
+
504
+ .progress-bar {
505
+ width: 0%;
506
+ height: 100%;
507
+ background: linear-gradient(90deg, var(--primary) 0%, var(--secondary) 100%);
508
+ transition: width 0.3s ease;
509
+ border-radius: 3px;
510
+ }
511
+
512
+ /* Form Section */
513
+ .form-section {
514
+ background: var(--surface);
515
+ border: 1px solid var(--border);
516
+ border-radius: 12px;
517
+ padding: 25px;
518
+ margin-bottom: 25px;
519
+ transition: all 0.3s ease;
520
+ box-shadow: var(--shadow);
521
+ }
522
+
523
+ .form-section:hover {
524
+ border-color: var(--primary);
525
+ box-shadow: 0 8px 25px -8px rgba(124, 58, 237, 0.3);
526
+ }
527
+
528
+ .form-section h3 {
529
+ font-size: 1.2rem;
530
+ font-weight: 700;
531
+ color: var(--primary);
532
+ margin-bottom: 15px;
533
+ display: flex;
534
+ align-items: center;
535
+ gap: 8px;
536
+ }
537
+
538
+ /* Form Elements */
539
+ label {
540
+ display: block;
541
+ margin-bottom: 8px;
542
+ font-weight: 600;
543
+ color: var(--text);
544
+ font-size: 0.95rem;
545
+ }
546
+
547
+ input[type="text"],
548
+ textarea,
549
+ select {
550
+ width: 100%;
551
+ padding: 12px 16px;
552
+ border: 2px solid var(--border);
553
+ border-radius: 8px;
554
+ font-size: 1rem;
555
+ font-family: inherit;
556
+ background: var(--surface);
557
+ transition: all 0.2s ease;
558
+ resize: vertical;
559
+ }
560
+
561
+ input[type="text"]:focus,
562
+ textarea:focus,
563
+ select:focus {
564
+ outline: none;
565
+ border-color: var(--primary);
566
+ box-shadow: 0 0 0 3px rgba(124, 58, 237, 0.1);
567
+ }
568
+
569
+ textarea {
570
+ min-height: 200px;
571
+ line-height: 1.6;
572
+ font-family: 'Fira Code', 'Courier New', monospace;
573
+ }
574
+
575
+ .char-counter {
576
+ font-size: 0.8rem;
577
+ color: var(--text-secondary);
578
+ text-align: right;
579
+ margin-top: 4px;
580
+ }
581
+
582
+ .form-grid {
583
+ display: grid;
584
+ grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
585
+ gap: 15px;
586
+ margin-top: 15px;
587
+ }
588
+
589
+ .form-field {
590
+ display: flex;
591
+ flex-direction: column;
592
+ }
593
+
594
+ /* Generate Button */
595
+ .generate-btn {
596
+ background: linear-gradient(135deg, var(--primary) 0%, var(--secondary) 100%);
597
+ color: white;
598
+ padding: 18px 40px;
599
+ border: none;
600
+ border-radius: 12px;
601
+ font-size: 1.2rem;
602
+ font-weight: 700;
603
+ cursor: pointer;
604
+ transition: all 0.3s ease;
605
+ display: block;
606
+ margin: 30px auto;
607
+ min-width: 320px;
608
+ position: relative;
609
+ overflow: hidden;
610
+ }
611
+
612
+ .generate-btn:hover {
613
+ transform: translateY(-2px);
614
+ box-shadow: 0 12px 24px -8px rgba(124, 58, 237, 0.4);
615
+ }
616
+
617
+ .generate-btn:active {
618
+ transform: translateY(0);
619
+ }
620
+
621
+ .generate-btn:disabled {
622
+ opacity: 0.7;
623
+ cursor: not-allowed;
624
+ transform: none;
625
+ }
626
+
627
+ /* Loading Spinner */
628
+ .spinner {
629
+ display: none;
630
+ width: 20px;
631
+ height: 20px;
632
+ border: 2px solid rgba(255, 255, 255, 0.3);
633
+ border-radius: 50%;
634
+ border-top-color: white;
635
+ animation: spin 1s ease-in-out infinite;
636
+ margin-right: 8px;
637
+ }
638
+
639
+ @keyframes spin {
640
+ to { transform: rotate(360deg); }
641
+ }
642
+
643
+ /* Output Section */
644
+ .output-section {
645
+ margin-top: 30px;
646
+ }
647
+
648
+ .output-section h2 {
649
+ font-size: 1.5rem;
650
+ font-weight: 700;
651
+ color: var(--primary);
652
+ margin-bottom: 15px;
653
+ display: flex;
654
+ align-items: center;
655
+ gap: 8px;
656
+ text-align: center;
657
+ justify-content: center;
658
+ }
659
+
660
+ .output-area {
661
+ background: var(--surface);
662
+ border: 2px solid var(--border);
663
+ border-radius: 12px;
664
+ padding: 25px;
665
+ min-height: 300px;
666
+ transition: all 0.3s ease;
667
+ position: relative;
668
+ overflow-x: auto;
669
+ font-family: 'Georgia', serif;
670
+ line-height: 1.8;
671
+ white-space: pre-wrap;
672
+ word-wrap: break-word;
673
+ }
674
+
675
+ .output-area:empty::before {
676
+ content: "Your detailed code explanation will appear here...";
677
+ color: var(--text-secondary);
678
+ font-style: italic;
679
+ font-family: 'Inter', sans-serif;
680
+ }
681
+
682
+ .output-area:focus {
683
+ outline: none;
684
+ border-color: var(--primary);
685
+ box-shadow: 0 0 0 3px rgba(124, 58, 237, 0.1);
686
+ }
687
+
688
+ .output-area h2, .output-area h3 {
689
+ color: var(--primary);
690
+ margin: 25px 0 15px 0;
691
+ font-family: 'Inter', sans-serif;
692
+ }
693
+
694
+ .output-area h2 {
695
+ border-bottom: 2px solid var(--primary);
696
+ padding-bottom: 8px;
697
+ font-size: 1.4rem;
698
+ }
699
+
700
+ .output-area h3 {
701
+ font-size: 1.2rem;
702
+ }
703
+
704
+ /* Section Headers with Decorative Underlines - Matching Example Format */
705
+ .output-area .section-header {
706
+ color: #e67e22; /* Orange color like in the example */
707
+ font-size: 1.3rem;
708
+ font-weight: 700;
709
+ margin: 30px 0 20px 0;
710
+ padding-bottom: 10px;
711
+ border-bottom: 3px solid #e67e22;
712
+ text-align: right; /* RTL alignment */
713
+ direction: rtl;
714
+ font-family: 'Inter', sans-serif;
715
+ }
716
+
717
+ /* For LTR languages */
718
+ body:not(.rtl) .output-area .section-header {
719
+ text-align: left;
720
+ direction: ltr;
721
+ }
722
+
723
+ /* Section content paragraphs */
724
+ .output-area .section-content {
725
+ margin: 15px 0 25px 0;
726
+ line-height: 1.8;
727
+ font-size: 1rem;
728
+ text-align: right;
729
+ direction: rtl;
730
+ }
731
+
732
+ /* For LTR languages */
733
+ body:not(.rtl) .output-area .section-content {
734
+ text-align: left;
735
+ direction: ltr;
736
+ }
737
+
738
+ /* Better paragraph spacing for the new format */
739
+ .output-area .section-content p {
740
+ margin: 12px 0;
741
+ line-height: 1.8;
742
+ }
743
+
744
+ .output-area p {
745
+ margin: 12px 0;
746
+ }
747
+
748
+ .output-area strong {
749
+ color: var(--primary);
750
+ }
751
+
752
+ .output-area ul, .output-area ol {
753
+ margin: 12px 0 12px 20px;
754
+ }
755
+
756
+ .output-area li {
757
+ margin: 6px 0;
758
+ }
759
+
760
+ .output-area code {
761
+ background: rgba(124, 58, 237, 0.1);
762
+ padding: 2px 6px;
763
+ border-radius: 4px;
764
+ font-family: 'Fira Code', 'Courier New', monospace;
765
+ color: var(--primary);
766
+ font-size: 0.9em;
767
+ }
768
+
769
+ .output-area pre {
770
+ background: rgba(124, 58, 237, 0.05);
771
+ border: 1px solid rgba(124, 58, 237, 0.2);
772
+ border-radius: 8px;
773
+ padding: 16px;
774
+ margin: 16px 0;
775
+ overflow-x: auto;
776
+ font-family: 'Fira Code', 'Courier New', monospace;
777
+ font-size: 0.9em;
778
+ line-height: 1.5;
779
+ }
780
+
781
+ .output-area pre code {
782
+ background: none;
783
+ padding: 0;
784
+ border-radius: 0;
785
+ color: var(--text);
786
+ font-size: inherit;
787
+ }
788
+
789
+ /* Edit Notice */
790
+ .edit-notice {
791
+ background: rgba(124, 58, 237, 0.1);
792
+ border: 1px solid rgba(124, 58, 237, 0.2);
793
+ color: var(--primary);
794
+ padding: 8px 12px;
795
+ border-radius: 6px;
796
+ margin-bottom: 10px;
797
+ font-size: 0.85rem;
798
+ text-align: center;
799
+ font-weight: 500;
800
+ }
801
+
802
+ /* Error Messages */
803
+ .error-message {
804
+ background: rgba(239, 68, 68, 0.1);
805
+ border: 1px solid rgba(239, 68, 68, 0.2);
806
+ color: var(--error);
807
+ padding: 12px 16px;
808
+ border-radius: 8px;
809
+ margin: 10px 0;
810
+ font-size: 0.9rem;
811
+ display: none;
812
+ }
813
+
814
+ /* Status Messages */
815
+ .status-message {
816
+ background: rgba(124, 58, 237, 0.1);
817
+ border: 1px solid rgba(124, 58, 237, 0.2);
818
+ color: var(--primary);
819
+ padding: 12px 16px;
820
+ border-radius: 8px;
821
+ margin: 10px 0;
822
+ font-size: 0.9rem;
823
+ text-align: center;
824
+ font-weight: 600;
825
+ }
826
+
827
+ /* Footer */
828
+ .footer {
829
+ text-align: center;
830
+ padding: 20px;
831
+ background: rgba(124, 58, 237, 0.05);
832
+ border-top: 1px solid var(--border);
833
+ color: var(--text-secondary);
834
+ font-size: 0.9rem;
835
+ }
836
+
837
+ /* Responsive Design */
838
+ @media (max-width: 768px) {
839
+ body {
840
+ padding: 10px;
841
+ }
842
+
843
+ .landing-page {
844
+ padding: 20px;
845
+ }
846
+
847
+ .landing-header h1 {
848
+ font-size: 2.2rem;
849
+ }
850
+
851
+ .landing-form {
852
+ padding: 30px 20px;
853
+ }
854
+
855
+ .settings-bar {
856
+ padding: 12px 20px;
857
+ flex-direction: column;
858
+ align-items: stretch;
859
+ }
860
+
861
+ .language-info {
862
+ justify-content: center;
863
+ margin-bottom: 10px;
864
+ }
865
+
866
+ .api-key-section {
867
+ margin: 10px;
868
+ max-width: none;
869
+ }
870
+
871
+ .main-content {
872
+ padding: 15px 20px 20px;
873
+ }
874
+
875
+ .header h1 {
876
+ font-size: 2rem;
877
+ }
878
+
879
+ .form-section {
880
+ padding: 20px 15px;
881
+ }
882
+
883
+ .features-grid {
884
+ grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
885
+ }
886
+
887
+ .form-grid {
888
+ grid-template-columns: 1fr;
889
+ }
890
+
891
+ .generate-btn {
892
+ width: 100%;
893
+ margin: 25px 0;
894
+ padding: 16px 32px;
895
+ font-size: 1.1rem;
896
+ }
897
+
898
+ .output-area {
899
+ padding: 20px;
900
+ }
901
+ }
902
+
903
+ @media (max-width: 480px) {
904
+ .landing-header h1 {
905
+ font-size: 1.8rem;
906
+ }
907
+
908
+ .header h1 {
909
+ font-size: 1.8rem;
910
+ }
911
+
912
+ .features-grid {
913
+ grid-template-columns: 1fr;
914
+ }
915
+
916
+ .feature-card {
917
+ padding: 12px;
918
+ }
919
+ }
920
+
921
+ /* Dark mode support */
922
+ @media (prefers-color-scheme: dark) {
923
+ :root {
924
+ --background: #0f172a;
925
+ --surface: #1e293b;
926
+ --text: #f1f5f9;
927
+ --text-secondary: #94a3b8;
928
+ --border: #334155;
929
+ }
930
+
931
+ body {
932
+ background: linear-gradient(135deg, #0f172a 0%, #1e293b 100%);
933
+ }
934
+ }
935
+
936
+ /* Translation loading indicator */
937
+ .translation-loading {
938
+ opacity: 0.6;
939
+ pointer-events: none;
940
+ }
941
+
942
+ .translation-loading::after {
943
+ content: "🔄";
944
+ position: absolute;
945
+ top: 10px;
946
+ right: 10px;
947
+ animation: spin 1s linear infinite;
948
+ }
949
+ </style>
950
+ </head>
951
+ <body>
952
+ <!-- Landing Page -->
953
+ <div class="landing-page" id="landingPage">
954
+ <div class="landing-header">
955
+ <h1 data-translate="app_title">CodeTutor Pro</h1>
956
+ <p class="subtitle" data-translate="app_subtitle">Intelligent Code Explanation Platform</p>
957
+ <p class="description" data-translate="app_description">Transform complex code into clear, beginner-friendly explanations with AI-powered analysis</p>
958
+ </div>
959
+
960
+ <div class="landing-form">
961
+ <h2 data-translate="setup_title">Get Started</h2>
962
+
963
+ <div class="form-group">
964
+ <label for="languageSelect" data-translate="language_label">Select Language:</label>
965
+ <select id="languageSelect" required>
966
+ <option value="">Choose your language...</option>
967
+ <!-- Languages will be populated by JavaScript -->
968
+ </select>
969
+ </div>
970
+
971
+ <div class="form-group">
972
+ <label for="landingApiKey" data-translate="api_key_label">OpenAI API Key:</label>
973
+ <input type="password" id="landingApiKey" data-translate-placeholder="api_key_placeholder" placeholder="Enter your OpenAI API key" autocomplete="off" required>
974
+ </div>
975
+
976
+ <button class="start-btn" id="startBtn" data-translate="start_button">Start Using CodeTutor Pro</button>
977
+ </div>
978
+ </div>
979
+
980
+ <!-- Main Application -->
981
+ <div class="main-app" id="mainApp">
982
+ <!-- Settings Bar -->
983
+ <div class="settings-bar">
984
+ <div class="language-info">
985
+ <span data-translate="current_language">Language:</span>
986
+ <strong id="currentLanguageName">English</strong>
987
+ <button class="change-language-btn" id="changeLanguageBtn" data-translate="change_language">Change Language</button>
988
+ </div>
989
+ <div>
990
+ <button class="clear-cache-btn" id="clearCacheBtn" data-translate="clear_cache">Clear Translation Cache</button>
991
+ </div>
992
+ </div>
993
+
994
+ <div class="container">
995
+ <!-- API Key Section - Static Position Top Left -->
996
+ <div class="api-key-section">
997
+ <label for="apiKey" data-translate="api_key_short">🔑 API Key</label>
998
+ <input type="password" id="apiKey" data-translate-placeholder="api_key_placeholder" placeholder="Enter your OpenAI API key" autocomplete="off">
999
+ </div>
1000
+
1001
+ <div class="main-content">
1002
+ <!-- Header -->
1003
+ <div class="header">
1004
+ <h1 data-translate="app_title">CodeTutor Pro</h1>
1005
+ <p class="subtitle" data-translate="app_subtitle">Intelligent Code Explanation Platform</p>
1006
+ <p class="description" data-translate="app_description">Transform complex code into clear, beginner-friendly explanations with AI-powered analysis</p>
1007
+ </div>
1008
+
1009
+ <!-- Code Explanation Features Overview -->
1010
+ <div class="features-overview">
1011
+ <h3 data-translate="features_title">💡 Advanced Code Explanation Features</h3>
1012
+ <div class="features-grid">
1013
+ <div class="feature-card">
1014
+ <div class="icon">🎯</div>
1015
+ <h4 data-translate="feature_beginner_title">Beginner-Friendly</h4>
1016
+ <p data-translate="feature_beginner_desc">Plain language explanations without technical jargon</p>
1017
+ </div>
1018
+ <div class="feature-card">
1019
+ <div class="icon">🔍</div>
1020
+ <h4 data-translate="feature_analysis_title">Line-by-Line Analysis</h4>
1021
+ <p data-translate="feature_analysis_desc">Detailed breakdown of each code component</p>
1022
+ </div>
1023
+ <div class="feature-card">
1024
+ <div class="icon">📚</div>
1025
+ <h4 data-translate="feature_concept_title">Concept Explanation</h4>
1026
+ <p data-translate="feature_concept_desc">Clear examples and programming concepts</p>
1027
+ </div>
1028
+ <div class="feature-card">
1029
+ <div class="icon">✏️</div>
1030
+ <h4 data-translate="feature_editable_title">Editable Output</h4>
1031
+ <p data-translate="feature_editable_desc">Customize and refine explanations as needed</p>
1032
+ </div>
1033
+ <div class="feature-card">
1034
+ <div class="icon">🌐</div>
1035
+ <h4 data-translate="feature_multilang_title">Multi-Language Support</h4>
1036
+ <p data-translate="feature_multilang_desc">Works with all major programming languages</p>
1037
+ </div>
1038
+ </div>
1039
+ </div>
1040
+
1041
+ <!-- Progress Bar -->
1042
+ <div class="progress-container">
1043
+ <div class="progress-bar" id="progressBar"></div>
1044
+ </div>
1045
+
1046
+ <!-- Form Section -->
1047
+ <div class="form-section">
1048
+ <h3 data-translate="code_input_title">💻 Code Input & Analysis</h3>
1049
+
1050
+ <label for="codeInput" data-translate="code_input_label">Enter Your Code:</label>
1051
+ <textarea
1052
+ id="codeInput"
1053
+ data-translate-placeholder="code_input_placeholder"
1054
+ placeholder="Paste your code here... (supports all programming languages: Python, JavaScript, Java, C++, HTML, CSS, SQL, etc.)"
1055
+ maxlength="1000000"
1056
+ required
1057
+ ></textarea>
1058
+ <div class="char-counter">
1059
+ <span id="charCount">0</span>/1000000 <span data-translate="characters">characters</span>
1060
+ </div>
1061
+
1062
+ <div class="form-grid">
1063
+ <div class="form-field">
1064
+ <label for="programmingLanguage" data-translate="programming_language_label">Programming Language (Optional):</label>
1065
+ <select id="programmingLanguage">
1066
+ <option value="" data-translate="auto_detect">Auto-detect language</option>
1067
+ <option value="Python">Python</option>
1068
+ <option value="JavaScript">JavaScript</option>
1069
+ <option value="Java">Java</option>
1070
+ <option value="C++">C++</option>
1071
+ <option value="C#">C#</option>
1072
+ <option value="HTML">HTML</option>
1073
+ <option value="CSS">CSS</option>
1074
+ <option value="SQL">SQL</option>
1075
+ <option value="PHP">PHP</option>
1076
+ <option value="Ruby">Ruby</option>
1077
+ <option value="Go">Go</option>
1078
+ <option value="Rust">Rust</option>
1079
+ <option value="Swift">Swift</option>
1080
+ <option value="Kotlin">Kotlin</option>
1081
+ <option value="TypeScript">TypeScript</option>
1082
+ <option value="R">R</option>
1083
+ <option value="MATLAB">MATLAB</option>
1084
+ <option value="Scala">Scala</option>
1085
+ <option value="Perl">Perl</option>
1086
+ <option value="Shell/Bash">Shell/Bash</option>
1087
+ </select>
1088
+ </div>
1089
+
1090
+ <div class="form-field">
1091
+ <label for="explanationLevel" data-translate="explanation_level_label">Explanation Level:</label>
1092
+ <select id="explanationLevel" required>
1093
+ <option value="" data-translate="select_explanation_level">Select explanation level</option>
1094
+ <option value="Complete Beginner" data-translate="level_complete_beginner">Complete Beginner (No programming experience)</option>
1095
+ <option value="Beginner" data-translate="level_beginner">Beginner (Basic programming knowledge)</option>
1096
+ <option value="Intermediate" data-translate="level_intermediate">Intermediate (Some programming experience)</option>
1097
+ <option value="Advanced" data-translate="level_advanced">Advanced (Experienced programmer)</option>
1098
+ </select>
1099
+ </div>
1100
+ </div>
1101
+ </div>
1102
+
1103
+ <!-- Error Message -->
1104
+ <div class="error-message" id="errorMessage"></div>
1105
+
1106
+ <!-- Status Message -->
1107
+ <div class="status-message" id="statusMessage" style="display: none;"></div>
1108
+
1109
+ <!-- Generate Button -->
1110
+ <button class="generate-btn" id="generateBtn">
1111
+ <span class="spinner" id="spinner"></span>
1112
+ <span id="buttonText" data-translate="generate_button">🧠 Generate Explanation</span>
1113
+ </button>
1114
+
1115
+ <!-- Output Section -->
1116
+ <div class="output-section">
1117
+ <h2 data-translate="output_title">📖 Code Explanation</h2>
1118
+ <div class="edit-notice" data-translate="edit_notice">
1119
+ ✏️ This explanation is editable - click anywhere to customize and refine the content
1120
+ </div>
1121
+ <div class="output-area" id="explanationOutput" contenteditable="true"></div>
1122
+ </div>
1123
+ </div>
1124
+
1125
+ <!-- Footer -->
1126
+ <div class="footer" data-translate="footer">
1127
+ Created by Shift Mind AI Labs
1128
+ </div>
1129
+ </div>
1130
+ </div>
1131
+
1132
+ <script>
1133
+ // Global variables
1134
+ let currentLanguage = 'en';
1135
+ let translationCache = {};
1136
+ let isTranslating = false;
1137
+
1138
+ // 92 Languages with their codes and RTL information
1139
+ const languages = [
1140
+ { code: 'en', name: 'English', nativeName: 'English', rtl: false },
1141
+ { code: 'es', name: 'Spanish', nativeName: 'Español', rtl: false },
1142
+ { code: 'fr', name: 'French', nativeName: 'Français', rtl: false },
1143
+ { code: 'de', name: 'German', nativeName: 'Deutsch', rtl: false },
1144
+ { code: 'it', name: 'Italian', nativeName: 'Italiano', rtl: false },
1145
+ { code: 'pt', name: 'Portuguese', nativeName: 'Português', rtl: false },
1146
+ { code: 'ru', name: 'Russian', nativeName: 'Русский', rtl: false },
1147
+ { code: 'ja', name: 'Japanese', nativeName: '日本語', rtl: false },
1148
+ { code: 'ko', name: 'Korean', nativeName: '한국어', rtl: false },
1149
+ { code: 'zh', name: 'Chinese (Simplified)', nativeName: '中文 (简体)', rtl: false },
1150
+ { code: 'zh-TW', name: 'Chinese (Traditional)', nativeName: '中文 (繁體)', rtl: false },
1151
+ { code: 'ar', name: 'Arabic', nativeName: 'العربية', rtl: true },
1152
+ { code: 'he', name: 'Hebrew', nativeName: 'עברית', rtl: true },
1153
+ { code: 'hi', name: 'Hindi', nativeName: 'हिन्दी', rtl: false },
1154
+ { code: 'th', name: 'Thai', nativeName: 'ไทย', rtl: false },
1155
+ { code: 'vi', name: 'Vietnamese', nativeName: 'Tiếng Việt', rtl: false },
1156
+ { code: 'tr', name: 'Turkish', nativeName: 'Türkçe', rtl: false },
1157
+ { code: 'pl', name: 'Polish', nativeName: 'Polski', rtl: false },
1158
+ { code: 'nl', name: 'Dutch', nativeName: 'Nederlands', rtl: false },
1159
+ { code: 'sv', name: 'Swedish', nativeName: 'Svenska', rtl: false },
1160
+ { code: 'da', name: 'Danish', nativeName: 'Dansk', rtl: false },
1161
+ { code: 'no', name: 'Norwegian', nativeName: 'Norsk', rtl: false },
1162
+ { code: 'fi', name: 'Finnish', nativeName: 'Suomi', rtl: false },
1163
+ { code: 'cs', name: 'Czech', nativeName: 'Čeština', rtl: false },
1164
+ { code: 'sk', name: 'Slovak', nativeName: 'Slovenčina', rtl: false },
1165
+ { code: 'hu', name: 'Hungarian', nativeName: 'Magyar', rtl: false },
1166
+ { code: 'ro', name: 'Romanian', nativeName: 'Română', rtl: false },
1167
+ { code: 'bg', name: 'Bulgarian', nativeName: 'Български', rtl: false },
1168
+ { code: 'hr', name: 'Croatian', nativeName: 'Hrvatski', rtl: false },
1169
+ { code: 'sr', name: 'Serbian', nativeName: 'Српски', rtl: false },
1170
+ { code: 'sl', name: 'Slovenian', nativeName: 'Slovenščina', rtl: false },
1171
+ { code: 'et', name: 'Estonian', nativeName: 'Eesti', rtl: false },
1172
+ { code: 'lv', name: 'Latvian', nativeName: 'Latviešu', rtl: false },
1173
+ { code: 'lt', name: 'Lithuanian', nativeName: 'Lietuvių', rtl: false },
1174
+ { code: 'uk', name: 'Ukrainian', nativeName: 'Українська', rtl: false },
1175
+ { code: 'be', name: 'Belarusian', nativeName: 'Беларуская', rtl: false },
1176
+ { code: 'mk', name: 'Macedonian', nativeName: 'Македонски', rtl: false },
1177
+ { code: 'sq', name: 'Albanian', nativeName: 'Shqip', rtl: false },
1178
+ { code: 'el', name: 'Greek', nativeName: 'Ελληνικά', rtl: false },
1179
+ { code: 'mt', name: 'Maltese', nativeName: 'Malti', rtl: false },
1180
+ { code: 'ga', name: 'Irish', nativeName: 'Gaeilge', rtl: false },
1181
+ { code: 'cy', name: 'Welsh', nativeName: 'Cymraeg', rtl: false },
1182
+ { code: 'is', name: 'Icelandic', nativeName: 'Íslenska', rtl: false },
1183
+ { code: 'fo', name: 'Faroese', nativeName: 'Føroyskt', rtl: false },
1184
+ { code: 'eu', name: 'Basque', nativeName: 'Euskera', rtl: false },
1185
+ { code: 'ca', name: 'Catalan', nativeName: 'Català', rtl: false },
1186
+ { code: 'gl', name: 'Galician', nativeName: 'Galego', rtl: false },
1187
+ { code: 'oc', name: 'Occitan', nativeName: 'Occitan', rtl: false },
1188
+ { code: 'br', name: 'Breton', nativeName: 'Brezhoneg', rtl: false },
1189
+ { code: 'co', name: 'Corsican', nativeName: 'Corsu', rtl: false },
1190
+ { code: 'sc', name: 'Sardinian', nativeName: 'Sardu', rtl: false },
1191
+ { code: 'rm', name: 'Romansh', nativeName: 'Rumantsch', rtl: false },
1192
+ { code: 'lb', name: 'Luxembourgish', nativeName: 'Lëtzebuergesch', rtl: false },
1193
+ { code: 'fy', name: 'Frisian', nativeName: 'Frysk', rtl: false },
1194
+ { code: 'af', name: 'Afrikaans', nativeName: 'Afrikaans', rtl: false },
1195
+ { code: 'zu', name: 'Zulu', nativeName: 'isiZulu', rtl: false },
1196
+ { code: 'xh', name: 'Xhosa', nativeName: 'isiXhosa', rtl: false },
1197
+ { code: 'st', name: 'Sesotho', nativeName: 'Sesotho', rtl: false },
1198
+ { code: 'tn', name: 'Setswana', nativeName: 'Setswana', rtl: false },
1199
+ { code: 'ss', name: 'Swati', nativeName: 'siSwati', rtl: false },
1200
+ { code: 've', name: 'Venda', nativeName: 'Tshivenḓa', rtl: false },
1201
+ { code: 'ts', name: 'Tsonga', nativeName: 'Xitsonga', rtl: false },
1202
+ { code: 'nr', name: 'Ndebele', nativeName: 'isiNdebele', rtl: false },
1203
+ { code: 'sw', name: 'Swahili', nativeName: 'Kiswahili', rtl: false },
1204
+ { code: 'am', name: 'Amharic', nativeName: 'አማርኛ', rtl: false },
1205
+ { code: 'ti', name: 'Tigrinya', nativeName: 'ትግርኛ', rtl: false },
1206
+ { code: 'om', name: 'Oromo', nativeName: 'Afaan Oromoo', rtl: false },
1207
+ { code: 'so', name: 'Somali', nativeName: 'Soomaali', rtl: false },
1208
+ { code: 'ha', name: 'Hausa', nativeName: 'Hausa', rtl: false },
1209
+ { code: 'yo', name: 'Yoruba', nativeName: 'Yorùbá', rtl: false },
1210
+ { code: 'ig', name: 'Igbo', nativeName: 'Igbo', rtl: false },
1211
+ { code: 'ff', name: 'Fulah', nativeName: 'Fulfulde', rtl: false },
1212
+ { code: 'wo', name: 'Wolof', nativeName: 'Wolof', rtl: false },
1213
+ { code: 'bm', name: 'Bambara', nativeName: 'Bamanankan', rtl: false },
1214
+ { code: 'rw', name: 'Kinyarwanda', nativeName: 'Ikinyarwanda', rtl: false },
1215
+ { code: 'rn', name: 'Kirundi', nativeName: 'Ikirundi', rtl: false },
1216
+ { code: 'ny', name: 'Chichewa', nativeName: 'Chichewa', rtl: false },
1217
+ { code: 'sn', name: 'Shona', nativeName: 'chiShona', rtl: false },
1218
+ { code: 'mg', name: 'Malagasy', nativeName: 'Malagasy', rtl: false },
1219
+ { code: 'fa', name: 'Persian', nativeName: 'فارسی', rtl: true },
1220
+ { code: 'ur', name: 'Urdu', nativeName: 'اردو', rtl: true },
1221
+ { code: 'ps', name: 'Pashto', nativeName: 'پښتو', rtl: true },
1222
+ { code: 'ku', name: 'Kurdish', nativeName: 'Kurdî', rtl: true },
1223
+ { code: 'ckb', name: 'Sorani Kurdish', nativeName: 'کوردی', rtl: true },
1224
+ { code: 'sd', name: 'Sindhi', nativeName: 'سنڌي', rtl: true },
1225
+ { code: 'ug', name: 'Uyghur', nativeName: 'ئۇيغۇرچە', rtl: true },
1226
+ { code: 'bn', name: 'Bengali', nativeName: 'বাংলা', rtl: false },
1227
+ { code: 'gu', name: 'Gujarati', nativeName: 'ગુજરાતી', rtl: false },
1228
+ { code: 'pa', name: 'Punjabi', nativeName: 'ਪੰਜਾਬੀ', rtl: false },
1229
+ { code: 'ta', name: 'Tamil', nativeName: 'தமிழ்', rtl: false },
1230
+ { code: 'te', name: 'Telugu', nativeName: 'తెలుగు', rtl: false },
1231
+ { code: 'kn', name: 'Kannada', nativeName: 'ಕನ್ನಡ', rtl: false },
1232
+ { code: 'ml', name: 'Malayalam', nativeName: 'മലയാളം', rtl: false },
1233
+ { code: 'si', name: 'Sinhala', nativeName: 'සිංහල', rtl: false },
1234
+ { code: 'my', name: 'Myanmar', nativeName: 'မြန်မာ', rtl: false },
1235
+ { code: 'km', name: 'Khmer', nativeName: 'ខ្មែរ', rtl: false },
1236
+ { code: 'lo', name: 'Lao', nativeName: 'ລາວ', rtl: false },
1237
+ { code: 'ka', name: 'Georgian', nativeName: 'ქართული', rtl: false },
1238
+ { code: 'hy', name: 'Armenian', nativeName: 'Հայերեն', rtl: false },
1239
+ { code: 'az', name: 'Azerbaijani', nativeName: 'Azərbaycan', rtl: false },
1240
+ { code: 'kk', name: 'Kazakh', nativeName: 'Қазақ', rtl: false },
1241
+ { code: 'ky', name: 'Kyrgyz', nativeName: 'Кыргыз', rtl: false },
1242
+ { code: 'uz', name: 'Uzbek', nativeName: 'Oʻzbek', rtl: false },
1243
+ { code: 'tk', name: 'Turkmen', nativeName: 'Türkmen', rtl: false },
1244
+ { code: 'tg', name: 'Tajik', nativeName: 'Тоҷикӣ', rtl: false },
1245
+ { code: 'mn', name: 'Mongolian', nativeName: 'Монгол', rtl: false }
1246
+ ];
1247
+
1248
+ // Default translations for English
1249
+ const defaultTranslations = {
1250
+ app_title: "CodeTutor Pro",
1251
+ app_subtitle: "Intelligent Code Explanation Platform",
1252
+ app_description: "Transform complex code into clear, beginner-friendly explanations with AI-powered analysis",
1253
+ setup_title: "Get Started",
1254
+ language_label: "Select Language:",
1255
+ api_key_label: "OpenAI API Key:",
1256
+ api_key_placeholder: "Enter your OpenAI API key",
1257
+ start_button: "Start Using CodeTutor Pro",
1258
+ current_language: "Language:",
1259
+ change_language: "Change Language",
1260
+ clear_cache: "Clear Translation Cache",
1261
+ api_key_short: "🔑 API Key",
1262
+ features_title: "💡 Advanced Code Explanation Features",
1263
+ feature_beginner_title: "Beginner-Friendly",
1264
+ feature_beginner_desc: "Plain language explanations without technical jargon",
1265
+ feature_analysis_title: "Line-by-Line Analysis",
1266
+ feature_analysis_desc: "Detailed breakdown of each code component",
1267
+ feature_concept_title: "Concept Explanation",
1268
+ feature_concept_desc: "Clear examples and programming concepts",
1269
+ feature_editable_title: "Editable Output",
1270
+ feature_editable_desc: "Customize and refine explanations as needed",
1271
+ feature_multilang_title: "Multi-Language Support",
1272
+ feature_multilang_desc: "Works with all major programming languages",
1273
+ code_input_title: "💻 Code Input & Analysis",
1274
+ code_input_label: "Enter Your Code:",
1275
+ code_input_placeholder: "Paste your code here... (supports all programming languages: Python, JavaScript, Java, C++, HTML, CSS, SQL, etc.)",
1276
+ characters: "characters",
1277
+ programming_language_label: "Programming Language (Optional):",
1278
+ auto_detect: "Auto-detect language",
1279
+ explanation_level_label: "Explanation Level:",
1280
+ select_explanation_level: "Select explanation level",
1281
+ level_complete_beginner: "Complete Beginner (No programming experience)",
1282
+ level_beginner: "Beginner (Basic programming knowledge)",
1283
+ level_intermediate: "Intermediate (Some programming experience)",
1284
+ level_advanced: "Advanced (Experienced programmer)",
1285
+ generate_button: "🧠 Generate Explanation",
1286
+ output_title: "📖 Code Explanation",
1287
+ edit_notice: "✏️ This explanation is editable - click anywhere to customize and refine the content",
1288
+ footer: "Created by Shift Mind AI Labs"
1289
+ };
1290
+
1291
+ // Load cached translations and settings with improved cache handling
1292
+ function loadSettings() {
1293
+ const savedLanguage = localStorage.getItem('codetutor_language');
1294
+ const savedCache = localStorage.getItem('codetutor_translation_cache');
1295
+ const savedApiKey = localStorage.getItem('codetutor_api_key');
1296
+
1297
+ if (savedLanguage) {
1298
+ currentLanguage = savedLanguage;
1299
+ }
1300
+
1301
+ if (savedCache) {
1302
+ try {
1303
+ const parsedCache = JSON.parse(savedCache);
1304
+ // Handle both old and new cache formats
1305
+ translationCache = {};
1306
+ Object.keys(parsedCache).forEach(key => {
1307
+ const value = parsedCache[key];
1308
+ if (typeof value === 'string') {
1309
+ // Old format - convert to new format
1310
+ translationCache[key] = {
1311
+ text: value,
1312
+ timestamp: Date.now() - (7 * 24 * 60 * 60 * 1000) // Mark as 7 days old
1313
+ };
1314
+ } else if (typeof value === 'object' && value.text) {
1315
+ // New format
1316
+ translationCache[key] = value;
1317
+ }
1318
+ });
1319
+ } catch (e) {
1320
+ console.error('Error loading translation cache:', e);
1321
+ translationCache = {};
1322
+ }
1323
+ }
1324
+
1325
+ if (savedApiKey) {
1326
+ document.getElementById('landingApiKey').value = savedApiKey;
1327
+ document.getElementById('apiKey').value = savedApiKey;
1328
+ }
1329
+ }
1330
+
1331
+ // Save settings with cache size management
1332
+ function saveSettings() {
1333
+ localStorage.setItem('codetutor_language', currentLanguage);
1334
+
1335
+ // Limit cache size to prevent localStorage overflow
1336
+ const cacheKeys = Object.keys(translationCache);
1337
+ if (cacheKeys.length > 1000) {
1338
+ // Keep only the 800 most recent entries
1339
+ const sortedEntries = cacheKeys
1340
+ .map(key => ({ key, timestamp: translationCache[key].timestamp || 0 }))
1341
+ .sort((a, b) => b.timestamp - a.timestamp)
1342
+ .slice(0, 800);
1343
+
1344
+ const newCache = {};
1345
+ sortedEntries.forEach(entry => {
1346
+ newCache[entry.key] = translationCache[entry.key];
1347
+ });
1348
+ translationCache = newCache;
1349
+ }
1350
+
1351
+ localStorage.setItem('codetutor_translation_cache', JSON.stringify(translationCache));
1352
+ }
1353
+
1354
+ // Populate language dropdown
1355
+ function populateLanguageDropdown() {
1356
+ const select = document.getElementById('languageSelect');
1357
+ select.innerHTML = '<option value="">Choose your language...</option>';
1358
+
1359
+ languages.forEach(lang => {
1360
+ const option = document.createElement('option');
1361
+ option.value = lang.code;
1362
+ option.textContent = `${lang.nativeName} (${lang.name})`;
1363
+ if (lang.code === currentLanguage) {
1364
+ option.selected = true;
1365
+ }
1366
+ select.appendChild(option);
1367
+ });
1368
+ }
1369
+
1370
+ // Set RTL/LTR direction
1371
+ function setTextDirection(langCode) {
1372
+ const language = languages.find(lang => lang.code === langCode);
1373
+ const body = document.body;
1374
+
1375
+ if (language && language.rtl) {
1376
+ body.classList.add('rtl');
1377
+ body.setAttribute('dir', 'rtl');
1378
+ } else {
1379
+ body.classList.remove('rtl');
1380
+ body.setAttribute('dir', 'ltr');
1381
+ }
1382
+ }
1383
+
1384
+ // Translation function using OpenAI API with improved caching and batch processing
1385
+ async function translateText(text, targetLanguage) {
1386
+ if (targetLanguage === 'en' || !text || text.trim() === '') {
1387
+ return text;
1388
+ }
1389
+
1390
+ const cacheKey = `${text.trim()}_${targetLanguage}`;
1391
+ if (translationCache[cacheKey]) {
1392
+ const cached = translationCache[cacheKey];
1393
+ return typeof cached === 'string' ? cached : cached.text;
1394
+ }
1395
+
1396
+ const apiKey = document.getElementById('landingApiKey').value || document.getElementById('apiKey').value;
1397
+ if (!apiKey) {
1398
+ console.warn('No API key available for translation');
1399
+ return text;
1400
+ }
1401
+
1402
+ try {
1403
+ const language = languages.find(lang => lang.code === targetLanguage);
1404
+ const languageName = language ? language.name : targetLanguage;
1405
+
1406
+ const prompt = `Translate the following text to ${languageName}. Maintain any HTML tags, emojis, and formatting. Only return the translated text, nothing else:\n\n${text}`;
1407
+
1408
+ const response = await fetch("https://api.openai.com/v1/chat/completions", {
1409
+ method: "POST",
1410
+ headers: {
1411
+ "Content-Type": "application/json",
1412
+ "Authorization": `Bearer ${apiKey}`
1413
+ },
1414
+ body: JSON.stringify({
1415
+ model: "gpt-4o-mini",
1416
+ messages: [{ role: "user", content: prompt }],
1417
+ max_tokens: 800,
1418
+ temperature: 0.2
1419
+ })
1420
+ });
1421
+
1422
+ if (!response.ok) {
1423
+ const errorData = await response.json();
1424
+ throw new Error(errorData.error?.message || 'Translation API request failed');
1425
+ }
1426
+
1427
+ const data = await response.json();
1428
+ const translatedText = data.choices[0].message.content.trim();
1429
+
1430
+ // Cache the translation with timestamp
1431
+ translationCache[cacheKey] = {
1432
+ text: translatedText,
1433
+ timestamp: Date.now()
1434
+ };
1435
+ saveSettings();
1436
+
1437
+ return translatedText;
1438
+ } catch (error) {
1439
+ console.error('Translation error:', error);
1440
+ // Try to find a similar cached translation as fallback
1441
+ const similarKey = Object.keys(translationCache).find(key =>
1442
+ key.includes(text.substring(0, 20)) && key.endsWith(`_${targetLanguage}`)
1443
+ );
1444
+ if (similarKey && translationCache[similarKey]) {
1445
+ return translationCache[similarKey].text || translationCache[similarKey];
1446
+ }
1447
+ return text; // Return original text if translation fails
1448
+ }
1449
+ }
1450
+
1451
+ // Batch translation for better performance
1452
+ async function translateBatch(textArray, targetLanguage) {
1453
+ if (targetLanguage === 'en') {
1454
+ return textArray;
1455
+ }
1456
+
1457
+ const results = [];
1458
+ const uncachedTexts = [];
1459
+ const uncachedIndices = [];
1460
+
1461
+ // Check cache first
1462
+ textArray.forEach((text, index) => {
1463
+ const cacheKey = `${text.trim()}_${targetLanguage}`;
1464
+ if (translationCache[cacheKey]) {
1465
+ const cached = translationCache[cacheKey];
1466
+ results[index] = typeof cached === 'string' ? cached : cached.text;
1467
+ } else {
1468
+ uncachedTexts.push(text);
1469
+ uncachedIndices.push(index);
1470
+ }
1471
+ });
1472
+
1473
+ // Translate uncached texts
1474
+ if (uncachedTexts.length > 0) {
1475
+ const apiKey = document.getElementById('landingApiKey').value || document.getElementById('apiKey').value;
1476
+ if (!apiKey) {
1477
+ // Fill remaining with original texts
1478
+ uncachedIndices.forEach((index, i) => {
1479
+ results[index] = uncachedTexts[i];
1480
+ });
1481
+ return results;
1482
+ }
1483
+
1484
+ try {
1485
+ const language = languages.find(lang => lang.code === targetLanguage);
1486
+ const languageName = language ? language.name : targetLanguage;
1487
+
1488
+ const batchText = uncachedTexts.map((text, i) => `${i + 1}. ${text}`).join('\n');
1489
+ const prompt = `Translate the following numbered list to ${languageName}. Maintain the numbering, HTML tags, emojis, and formatting. Return only the translated numbered list:\n\n${batchText}`;
1490
+
1491
+ const response = await fetch("https://api.openai.com/v1/chat/completions", {
1492
+ method: "POST",
1493
+ headers: {
1494
+ "Content-Type": "application/json",
1495
+ "Authorization": `Bearer ${apiKey}`
1496
+ },
1497
+ body: JSON.stringify({
1498
+ model: "gpt-4o-mini",
1499
+ messages: [{ role: "user", content: prompt }],
1500
+ max_tokens: 2000,
1501
+ temperature: 0.2
1502
+ })
1503
+ });
1504
+
1505
+ if (response.ok) {
1506
+ const data = await response.json();
1507
+ const translatedBatch = data.choices[0].message.content.trim();
1508
+ const translatedLines = translatedBatch.split('\n').filter(line => line.trim());
1509
+
1510
+ translatedLines.forEach((line, i) => {
1511
+ if (i < uncachedTexts.length) {
1512
+ const translatedText = line.replace(/^\d+\.\s*/, '').trim();
1513
+ const originalIndex = uncachedIndices[i];
1514
+ results[originalIndex] = translatedText;
1515
+
1516
+ // Cache the translation
1517
+ const cacheKey = `${uncachedTexts[i].trim()}_${targetLanguage}`;
1518
+ translationCache[cacheKey] = {
1519
+ text: translatedText,
1520
+ timestamp: Date.now()
1521
+ };
1522
+ }
1523
+ });
1524
+
1525
+ saveSettings();
1526
+ } else {
1527
+ // Fallback to individual translations
1528
+ for (let i = 0; i < uncachedTexts.length; i++) {
1529
+ const translatedText = await translateText(uncachedTexts[i], targetLanguage);
1530
+ results[uncachedIndices[i]] = translatedText;
1531
+ }
1532
+ }
1533
+ } catch (error) {
1534
+ console.error('Batch translation error:', error);
1535
+ // Fallback to original texts
1536
+ uncachedIndices.forEach((index, i) => {
1537
+ results[index] = uncachedTexts[i];
1538
+ });
1539
+ }
1540
+ }
1541
+
1542
+ return results;
1543
+ }
1544
+
1545
+ // Clean old cache entries (older than 30 days)
1546
+ function cleanOldCache() {
1547
+ const thirtyDaysAgo = Date.now() - (30 * 24 * 60 * 60 * 1000);
1548
+ let cleaned = false;
1549
+
1550
+ Object.keys(translationCache).forEach(key => {
1551
+ const cached = translationCache[key];
1552
+ if (typeof cached === 'object' && cached.timestamp && cached.timestamp < thirtyDaysAgo) {
1553
+ delete translationCache[key];
1554
+ cleaned = true;
1555
+ }
1556
+ });
1557
+
1558
+ if (cleaned) {
1559
+ saveSettings();
1560
+ }
1561
+ }
1562
+
1563
+ // Apply translations to the page with improved batch processing
1564
+ async function applyTranslations(langCode) {
1565
+ if (isTranslating) return;
1566
+ isTranslating = true;
1567
+
1568
+ const elements = document.querySelectorAll('[data-translate]');
1569
+ const placeholderElements = document.querySelectorAll('[data-translate-placeholder]');
1570
+
1571
+ // Add loading indicator
1572
+ document.body.classList.add('translation-loading');
1573
+
1574
+ // Show translation progress
1575
+ const progressElement = document.getElementById('progressBar');
1576
+ if (progressElement) {
1577
+ progressElement.style.width = '10%';
1578
+ }
1579
+
1580
+ try {
1581
+ // Clean old cache entries
1582
+ cleanOldCache();
1583
+
1584
+ if (langCode === 'en') {
1585
+ // Apply English (default) translations
1586
+ elements.forEach(element => {
1587
+ const key = element.getAttribute('data-translate');
1588
+ const originalText = defaultTranslations[key] || element.textContent;
1589
+ element.textContent = originalText;
1590
+ });
1591
+
1592
+ placeholderElements.forEach(element => {
1593
+ const key = element.getAttribute('data-translate-placeholder');
1594
+ if (key === 'api_key_placeholder') {
1595
+ element.setAttribute('placeholder', 'Enter your OpenAI API key');
1596
+ } else if (key === 'code_input_placeholder') {
1597
+ element.setAttribute('placeholder', 'Paste your code here... (supports all programming languages: Python, JavaScript, Java, C++, HTML, CSS, SQL, etc.)');
1598
+ }
1599
+ });
1600
+ } else {
1601
+ // Collect all texts to translate
1602
+ const textsToTranslate = [];
1603
+ const elementMap = [];
1604
+
1605
+ elements.forEach(element => {
1606
+ const key = element.getAttribute('data-translate');
1607
+ const originalText = defaultTranslations[key] || element.textContent;
1608
+ textsToTranslate.push(originalText);
1609
+ elementMap.push({ element, type: 'text' });
1610
+ });
1611
+
1612
+ placeholderElements.forEach(element => {
1613
+ const originalPlaceholder = element.getAttribute('placeholder');
1614
+ if (originalPlaceholder) {
1615
+ textsToTranslate.push(originalPlaceholder);
1616
+ elementMap.push({ element, type: 'placeholder' });
1617
+ }
1618
+ });
1619
+
1620
+ if (progressElement) {
1621
+ progressElement.style.width = '30%';
1622
+ }
1623
+
1624
+ // Batch translate all texts
1625
+ const translatedTexts = await translateBatch(textsToTranslate, langCode);
1626
+
1627
+ if (progressElement) {
1628
+ progressElement.style.width = '70%';
1629
+ }
1630
+
1631
+ // Apply translations
1632
+ translatedTexts.forEach((translatedText, index) => {
1633
+ const mapping = elementMap[index];
1634
+ if (mapping.type === 'text') {
1635
+ mapping.element.textContent = translatedText;
1636
+ } else if (mapping.type === 'placeholder') {
1637
+ mapping.element.setAttribute('placeholder', translatedText);
1638
+ }
1639
+ });
1640
+ }
1641
+
1642
+ if (progressElement) {
1643
+ progressElement.style.width = '90%';
1644
+ }
1645
+
1646
+ // Update current language display
1647
+ const language = languages.find(lang => lang.code === langCode);
1648
+ if (language) {
1649
+ const currentLangElement = document.getElementById('currentLanguageName');
1650
+ if (currentLangElement) {
1651
+ currentLangElement.textContent = language.nativeName;
1652
+ }
1653
+ }
1654
+
1655
+ if (progressElement) {
1656
+ progressElement.style.width = '100%';
1657
+ setTimeout(() => {
1658
+ progressElement.style.width = '0%';
1659
+ }, 1000);
1660
+ }
1661
+
1662
+ } catch (error) {
1663
+ console.error('Error applying translations:', error);
1664
+ // Show error message to user
1665
+ const errorDiv = document.getElementById('errorMessage');
1666
+ if (errorDiv) {
1667
+ errorDiv.textContent = `Translation error: ${error.message}`;
1668
+ errorDiv.style.display = 'block';
1669
+ setTimeout(() => {
1670
+ errorDiv.style.display = 'none';
1671
+ }, 5000);
1672
+ }
1673
+ } finally {
1674
+ document.body.classList.remove('translation-loading');
1675
+ isTranslating = false;
1676
+ }
1677
+ }
1678
+
1679
+ // Initialize the application with improved loading states
1680
+ function initializeApp() {
1681
+ loadSettings();
1682
+ populateLanguageDropdown();
1683
+ setTextDirection(currentLanguage);
1684
+
1685
+ // If language is already selected, show main app
1686
+ if (currentLanguage !== 'en' || localStorage.getItem('codetutor_language')) {
1687
+ showMainApp();
1688
+
1689
+ // Show loading state while translating
1690
+ const statusDiv = document.getElementById('statusMessage');
1691
+ if (statusDiv && currentLanguage !== 'en') {
1692
+ statusDiv.textContent = 'Loading translations...';
1693
+ statusDiv.style.display = 'block';
1694
+ }
1695
+
1696
+ applyTranslations(currentLanguage).then(() => {
1697
+ if (statusDiv) {
1698
+ statusDiv.style.display = 'none';
1699
+ }
1700
+ });
1701
+ }
1702
+ }
1703
+
1704
+ // Show main application with smooth transition
1705
+ function showMainApp() {
1706
+ const landingPage = document.getElementById('landingPage');
1707
+ const mainApp = document.getElementById('mainApp');
1708
+
1709
+ landingPage.classList.add('hidden');
1710
+ mainApp.classList.add('active');
1711
+
1712
+ // Copy API key from landing to main app
1713
+ const landingApiKey = document.getElementById('landingApiKey').value;
1714
+ if (landingApiKey) {
1715
+ document.getElementById('apiKey').value = landingApiKey;
1716
+ localStorage.setItem('codetutor_api_key', landingApiKey);
1717
+ }
1718
+
1719
+ // Focus on code input for better UX
1720
+ setTimeout(() => {
1721
+ const codeInput = document.getElementById('codeInput');
1722
+ if (codeInput) {
1723
+ codeInput.focus();
1724
+ }
1725
+ }, 500);
1726
+ }
1727
+
1728
+ // Show landing page with reset
1729
+ function showLandingPage() {
1730
+ const landingPage = document.getElementById('landingPage');
1731
+ const mainApp = document.getElementById('mainApp');
1732
+
1733
+ landingPage.classList.remove('hidden');
1734
+ mainApp.classList.remove('active');
1735
+
1736
+ // Reset language selection to current language
1737
+ const languageSelect = document.getElementById('languageSelect');
1738
+ if (languageSelect) {
1739
+ languageSelect.value = currentLanguage;
1740
+ }
1741
+ }
1742
+
1743
+ // Event Listeners
1744
+ document.getElementById('startBtn').addEventListener('click', async function() {
1745
+ const selectedLanguage = document.getElementById('languageSelect').value;
1746
+ const apiKey = document.getElementById('landingApiKey').value.trim();
1747
+
1748
+ if (!selectedLanguage) {
1749
+ alert('Please select a language');
1750
+ return;
1751
+ }
1752
+
1753
+ if (!apiKey) {
1754
+ alert('Please enter your OpenAI API key');
1755
+ return;
1756
+ }
1757
+
1758
+ // Save settings
1759
+ currentLanguage = selectedLanguage;
1760
+ localStorage.setItem('codetutor_api_key', apiKey);
1761
+ saveSettings();
1762
+
1763
+ // Set text direction
1764
+ setTextDirection(currentLanguage);
1765
+
1766
+ // Show main app
1767
+ showMainApp();
1768
+
1769
+ // Apply translations
1770
+ await applyTranslations(currentLanguage);
1771
+ });
1772
+
1773
+ document.getElementById('changeLanguageBtn').addEventListener('click', function() {
1774
+ showLandingPage();
1775
+ });
1776
+
1777
+ document.getElementById('clearCacheBtn').addEventListener('click', function() {
1778
+ const cacheSize = Object.keys(translationCache).length;
1779
+ const cacheMemory = JSON.stringify(translationCache).length;
1780
+ const cacheMemoryKB = Math.round(cacheMemory / 1024);
1781
+
1782
+ const confirmMessage = `Clear translation cache?\n\nCurrent cache contains:\n• ${cacheSize} translations\n• ~${cacheMemoryKB} KB of data\n\nThis will remove all cached translations and may require re-translating content.`;
1783
+
1784
+ if (confirm(confirmMessage)) {
1785
+ translationCache = {};
1786
+ localStorage.removeItem('codetutor_translation_cache');
1787
+
1788
+ // Show success message
1789
+ const statusDiv = document.getElementById('statusMessage');
1790
+ if (statusDiv) {
1791
+ statusDiv.textContent = `Translation cache cleared! Removed ${cacheSize} cached translations.`;
1792
+ statusDiv.style.display = 'block';
1793
+ setTimeout(() => {
1794
+ statusDiv.style.display = 'none';
1795
+ }, 3000);
1796
+ } else {
1797
+ alert(`Translation cache cleared successfully! Removed ${cacheSize} cached translations.`);
1798
+ }
1799
+ }
1800
+ });
1801
+
1802
+ // Store API key in localStorage
1803
+ const apiKeyInput = document.getElementById('apiKey');
1804
+ const landingApiKeyInput = document.getElementById('landingApiKey');
1805
+
1806
+ [apiKeyInput, landingApiKeyInput].forEach(input => {
1807
+ input.addEventListener('input', function() {
1808
+ localStorage.setItem('codetutor_api_key', this.value);
1809
+ // Sync both inputs
1810
+ if (this.id === 'apiKey') {
1811
+ landingApiKeyInput.value = this.value;
1812
+ } else {
1813
+ apiKeyInput.value = this.value;
1814
+ }
1815
+ });
1816
+ });
1817
+
1818
+ // Initialize when page loads
1819
+ document.addEventListener('DOMContentLoaded', initializeApp);
1820
+
1821
+ // Character counter
1822
+ const codeInputTextarea = document.getElementById('codeInput');
1823
+ const charCountSpan = document.getElementById('charCount');
1824
+
1825
+ codeInputTextarea.addEventListener('input', function() {
1826
+ const currentLength = this.value.length;
1827
+ charCountSpan.textContent = currentLength;
1828
+
1829
+ if (currentLength > 9000) {
1830
+ charCountSpan.style.color = 'var(--warning)';
1831
+ } else if (currentLength > 9500) {
1832
+ charCountSpan.style.color = 'var(--error)';
1833
+ } else {
1834
+ charCountSpan.style.color = 'var(--text-secondary)';
1835
+ }
1836
+ });
1837
+
1838
+ // Update progress bar
1839
+ function updateProgress(percent) {
1840
+ document.getElementById('progressBar').style.width = percent + '%';
1841
+ }
1842
+
1843
+ // Show status message
1844
+ function showStatus(message) {
1845
+ const statusDiv = document.getElementById('statusMessage');
1846
+ statusDiv.textContent = message;
1847
+ statusDiv.style.display = 'block';
1848
+ }
1849
+
1850
+ // Hide status message
1851
+ function hideStatus() {
1852
+ document.getElementById('statusMessage').style.display = 'none';
1853
+ }
1854
+
1855
+ // Error handling
1856
+ function showError(message) {
1857
+ const errorDiv = document.getElementById('errorMessage');
1858
+ errorDiv.textContent = message;
1859
+ errorDiv.style.display = 'block';
1860
+ setTimeout(() => {
1861
+ errorDiv.style.display = 'none';
1862
+ }, 5000);
1863
+ }
1864
+
1865
+ // Build the comprehensive code explanation prompt
1866
+ function buildCodeExplanationPrompt() {
1867
+ const codeInput = document.getElementById('codeInput').value.trim();
1868
+ const programmingLanguage = document.getElementById('programmingLanguage').value;
1869
+ const explanationLevel = document.getElementById('explanationLevel').value;
1870
+
1871
+ const languageContext = programmingLanguage ? `Programming Language: ${programmingLanguage}` : 'Programming Language: Auto-detect from code';
1872
+
1873
+ // Get the target language for the explanation
1874
+ const language = languages.find(lang => lang.code === currentLanguage);
1875
+ const languageName = language ? language.name : 'English';
1876
+
1877
+ return `You are CodeTutor Pro, an expert programming instructor and code explainer. Your mission is to make complex code understandable for learners at different levels. A user has provided code and wants a comprehensive explanation.
1878
+
1879
+ IMPORTANT: Provide the entire response in ${languageName}. All explanations, headings, and content should be in ${languageName}.
1880
+
1881
+ CRITICAL INSTRUCTION: DO NOT include any code snippets, code blocks, or actual code in your response. Provide ONLY descriptive explanations in natural language. Instead of showing code, describe what the code does in detail using words only.
1882
+
1883
+ USER DETAILS:
1884
+ ${languageContext}
1885
+ Explanation Level: ${explanationLevel}
1886
+ Response Language: ${languageName}
1887
+
1888
+ CODE TO EXPLAIN:
1889
+ <<<BEGIN CODE>>>
1890
+ ${codeInput}
1891
+ <<<END CODE>>>
1892
+
1893
+ Provide a comprehensive, well-structured explanation using section headers with underlines (not numbered lists). Format your response with clear section headers followed by detailed paragraphs. Use this structure:
1894
+
1895
+ **Section Header Format**: Use descriptive section titles that explain what will be discussed, followed by detailed paragraphs.
1896
+
1897
+ Structure your explanation with these types of sections:
1898
+
1899
+ **Code Overview Section**
1900
+ - What this code does in simple terms
1901
+ - The main purpose and functionality
1902
+ - What problem it solves or what task it accomplishes
1903
+
1904
+ **Detailed Analysis Section**
1905
+ - Describe each section and component in detail using natural language
1906
+ - Explain what each part does and why it's needed without showing the actual code
1907
+ - Describe how different parts work together
1908
+
1909
+ **Key Concepts Section**
1910
+ - Important programming concepts demonstrated in this code
1911
+ - Explain any algorithms, data structures, or design patterns used
1912
+ - Define technical terms in simple language
1913
+
1914
+ **Execution Flow Section**
1915
+ - Step-by-step execution flow described in words
1916
+ - What happens when the code runs
1917
+ - Input and output explanation
1918
+
1919
+ **Learning Insights Section**
1920
+ - What beginners can learn from this code
1921
+ - Best practices demonstrated
1922
+ - Common patterns or techniques shown
1923
+
1924
+ **Practical Applications Section**
1925
+ - Where this type of code might be used
1926
+ - Real-world scenarios and examples
1927
+ - How it could be modified or extended
1928
+
1929
+ FORMATTING INSTRUCTIONS:
1930
+ - Use descriptive section headers (not numbered lists like 1., 2., 3.)
1931
+ - Write each section as flowing paragraphs of text
1932
+ - Ensure proper text direction for RTL languages
1933
+ - Integrate English technical terms naturally within the text flow
1934
+ - Use clear, professional formatting with proper spacing
1935
+
1936
+ Tailor your explanation to the ${explanationLevel} level:
1937
+ - **Complete Beginner**: Use very simple language, explain basic concepts, avoid jargon
1938
+ - **Beginner**: Use clear language, explain intermediate concepts, minimal jargon with definitions
1939
+ - **Intermediate**: Use standard programming terminology, focus on logic and structure
1940
+ - **Advanced**: Use technical language, focus on optimization, patterns, and best practices
1941
+
1942
+ Make the explanation engaging, educational, and easy to follow. Use examples and analogies when helpful. Format with clear headings and structure for easy reading.
1943
+
1944
+ REMEMBER: Write everything in ${languageName}. DO NOT include any code snippets or code blocks - provide ONLY descriptive text explanations.`;
1945
+ }
1946
+
1947
+ // API call function
1948
+ async function callAPI(prompt) {
1949
+ const apiKey = document.getElementById('apiKey').value.trim();
1950
+
1951
+ if (!apiKey) {
1952
+ throw new Error('Please enter your OpenAI API key');
1953
+ }
1954
+
1955
+ const payload = {
1956
+ model: "gpt-4o-mini",
1957
+ messages: [{ role: "system", content: prompt }],
1958
+ max_tokens: 16000,
1959
+ temperature: 0.5
1960
+ };
1961
+
1962
+ const response = await fetch("https://api.openai.com/v1/chat/completions", {
1963
+ method: "POST",
1964
+ headers: {
1965
+ "Content-Type": "application/json",
1966
+ "Authorization": `Bearer ${apiKey}`
1967
+ },
1968
+ body: JSON.stringify(payload)
1969
+ });
1970
+
1971
+ if (!response.ok) {
1972
+ const errorData = await response.json();
1973
+ throw new Error(errorData.error?.message || "API request failed");
1974
+ }
1975
+
1976
+ const data = await response.json();
1977
+
1978
+ // Debug: Log the full response to check for truncation
1979
+ console.log('Full API response:', data);
1980
+
1981
+ // Check if the response was truncated
1982
+ if (data.choices[0].finish_reason === 'length') {
1983
+ console.warn('Response was truncated due to max_tokens limit');
1984
+ }
1985
+
1986
+ return data.choices[0].message.content;
1987
+ }
1988
+
1989
+ // Validation function
1990
+ function validateInputs() {
1991
+ const codeInput = document.getElementById('codeInput').value.trim();
1992
+ const explanationLevel = document.getElementById('explanationLevel').value;
1993
+
1994
+ if (!codeInput) {
1995
+ document.getElementById('codeInput').focus();
1996
+ throw new Error('Please enter the code you want explained');
1997
+ }
1998
+
1999
+ if (codeInput.length < 10) {
2000
+ document.getElementById('codeInput').focus();
2001
+ throw new Error('Please provide more code to analyze (at least 10 characters)');
2002
+ }
2003
+
2004
+ if (!explanationLevel) {
2005
+ document.getElementById('explanationLevel').focus();
2006
+ throw new Error('Please select your explanation level');
2007
+ }
2008
+ }
2009
+
2010
+ // Handle form submission
2011
+ document.getElementById('generateBtn').addEventListener('click', async function() {
2012
+ const button = this;
2013
+ const buttonText = document.getElementById('buttonText');
2014
+ const spinner = document.getElementById('spinner');
2015
+ const explanationOutput = document.getElementById('explanationOutput');
2016
+
2017
+ try {
2018
+ // Validate inputs
2019
+ validateInputs();
2020
+
2021
+ // Update button state
2022
+ button.disabled = true;
2023
+ spinner.style.display = 'inline-block';
2024
+ buttonText.textContent = 'Analyzing Code...';
2025
+
2026
+ // Clear previous output
2027
+ explanationOutput.innerHTML = '';
2028
+ hideStatus();
2029
+
2030
+ // Show progress and status
2031
+ updateProgress(20);
2032
+ showStatus("Analyzing code structure and syntax...");
2033
+
2034
+ // Build prompt and call API
2035
+ const prompt = buildCodeExplanationPrompt();
2036
+
2037
+ updateProgress(50);
2038
+ showStatus("Generating comprehensive explanation...");
2039
+
2040
+ const result = await callAPI(prompt);
2041
+
2042
+ updateProgress(100);
2043
+ hideStatus();
2044
+
2045
+ // Display result with section headers and underlines format
2046
+ let formattedResult = result;
2047
+
2048
+ // Debug: Log the raw result to see what we're getting
2049
+ console.log('Raw API result:', result);
2050
+
2051
+ // Remove any code block markers that might accidentally be included
2052
+ formattedResult = formattedResult.replace(/```[\s\S]*?```/g, '');
2053
+ formattedResult = formattedResult.replace(/`([^`\n]+)`/g, '$1');
2054
+
2055
+ // Handle section headers with underlines (convert markdown headers to section headers)
2056
+ formattedResult = formattedResult.replace(/^## (.*?)$/gm, '<div class="section-header">$1</div>');
2057
+ formattedResult = formattedResult.replace(/^### (.*?)$/gm, '<div class="section-header">$1</div>');
2058
+ formattedResult = formattedResult.replace(/^#### (.*?)$/gm, '<div class="section-header">$1</div>');
2059
+
2060
+ // Handle bold text
2061
+ formattedResult = formattedResult.replace(/\*\*(.*?)\*\*/g, '<strong>$1</strong>');
2062
+
2063
+ // Convert line breaks to <br> tags BEFORE processing sections
2064
+ formattedResult = formattedResult.replace(/\n/g, "<br>");
2065
+
2066
+ // Group content after section headers into section-content divs
2067
+ formattedResult = formattedResult.replace(/(<div class="section-header">.*?<\/div>)<br>(.*?)(?=<div class="section-header">|$)/g,
2068
+ '$1<br><div class="section-content">$2</div>');
2069
+
2070
+ // Clean up extra <br> tags around section headers
2071
+ formattedResult = formattedResult.replace(/<br><div class="section-header">/g, '<div class="section-header">');
2072
+ formattedResult = formattedResult.replace(/<\/div><br><div class="section-content">/g, '</div><div class="section-content">');
2073
+
2074
+ // Handle any remaining content that's not in a section (like intro text)
2075
+ if (!formattedResult.includes('<div class="section-header">')) {
2076
+ // If no section headers, wrap everything in section-content
2077
+ formattedResult = `<div class="section-content">${formattedResult}</div>`;
2078
+ } else {
2079
+ // Handle content before the first section header
2080
+ formattedResult = formattedResult.replace(/^(.*?)(<div class="section-header">)/s,
2081
+ '<div class="section-content">$1</div>$2');
2082
+ }
2083
+
2084
+ explanationOutput.innerHTML = formattedResult;
2085
+
2086
+ } catch (error) {
2087
+ console.error('Error:', error);
2088
+ showError(error.message);
2089
+ explanationOutput.innerHTML = '';
2090
+ hideStatus();
2091
+ updateProgress(0);
2092
+ } finally {
2093
+ // Reset button state
2094
+ button.disabled = false;
2095
+ spinner.style.display = 'none';
2096
+ buttonText.textContent = '🧠 Generate Explanation';
2097
+ }
2098
+ });
2099
+
2100
+ // Handle input changes
2101
+ document.getElementById('codeInput').addEventListener('input', function() {
2102
+ updateProgress(0);
2103
+ hideStatus();
2104
+ });
2105
+
2106
+ document.getElementById('programmingLanguage').addEventListener('change', function() {
2107
+ updateProgress(0);
2108
+ hideStatus();
2109
+ });
2110
+
2111
+ document.getElementById('explanationLevel').addEventListener('change', function() {
2112
+ updateProgress(0);
2113
+ hideStatus();
2114
+ });
2115
+
2116
+ // Keyboard shortcut for generation
2117
+ document.addEventListener('keydown', function(e) {
2118
+ if ((e.ctrlKey || e.metaKey) && e.key === 'Enter') {
2119
+ e.preventDefault();
2120
+ if (document.getElementById('mainApp').classList.contains('active')) {
2121
+ document.getElementById('generateBtn').click();
2122
+ }
2123
+ }
2124
+ });
2125
+
2126
+ // Handle contenteditable placeholder
2127
+ const outputArea = document.getElementById('explanationOutput');
2128
+ outputArea.addEventListener('focus', function() {
2129
+ if (this.innerHTML === '') {
2130
+ this.innerHTML = '';
2131
+ }
2132
+ });
2133
+
2134
+ outputArea.addEventListener('blur', function() {
2135
+ if (this.innerHTML.trim() === '') {
2136
+ this.innerHTML = '';
2137
+ }
2138
+ });
2139
+ </script>
2140
+ </body>
2141
+ </html>
2142
+
📘 Educator & Student Guide CodeTut.txt ADDED
@@ -0,0 +1,76 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ 📘 Educator & Student Guide: CodeTutor Pro
2
+ 1. Purpose & Audience
3
+ CodeTutor Pro enables anyone—from total beginners to advanced programmers—to receive natural-language, stepwise code explanations in their preferred language and depth. It’s ideal for schools, self-learners, and multilingual classes.
4
+
5
+ 2. Getting Started
6
+ Access: Open the HTML file or visit the Hugging Face Space.
7
+
8
+ Select Language: Choose from 90+ languages (including Arabic, Chinese, Spanish, and more). UI and outputs are instantly translated.
9
+
10
+ Enter OpenAI API Key: This enables AI-powered code analysis and translation. The key is never shared externally.
11
+
12
+ 3. Using the Tool
13
+ A. Input Your Code
14
+
15
+ Paste code (any language or style) into the main textbox.
16
+
17
+ Select the language and explanation level for tailored feedback.
18
+
19
+ B. Generate Explanation
20
+
21
+ Click “🧠 Generate Explanation”.
22
+
23
+ The tool analyzes code and produces sectioned, beginner-friendly output with no code snippets—just clear, structured text.
24
+
25
+ C. Review & Edit
26
+
27
+ Output is editable. Click anywhere to add notes, highlight key points, or personalize the explanation.
28
+
29
+ D. Switch Languages or Depth
30
+
31
+ Change UI/output language or explanation depth at any time for differentiated learning.
32
+
33
+ 4. Advanced Tips
34
+ Classroom Use:
35
+
36
+ Assign code samples and have students explain, compare, or critique AI outputs.
37
+
38
+ Great for flipped learning, remote/hybrid classrooms, or international groups.
39
+
40
+ Professional/PD Use:
41
+
42
+ Use for onboarding staff, cross-team code sharing, or technical documentation.
43
+
44
+ Support Multilingual Learners:
45
+
46
+ Instantly switch explanation language for ELLs or bilingual programs.
47
+
48
+ Portfolio Building:
49
+
50
+ Students can save, edit, and showcase their understanding of code for projects or interviews.
51
+
52
+ 5. Data Privacy & Security
53
+ All operations are fully local; nothing leaves your browser.
54
+
55
+ No login, registration, or data collection.
56
+
57
+ API keys and code remain on your device only.
58
+
59
+ 6. Troubleshooting & Support
60
+ API Key Errors:
61
+
62
+ Make sure your OpenAI key is valid and has sufficient quota.
63
+
64
+ Translation Issues:
65
+
66
+ Try clearing the translation cache or reloading the app.
67
+
68
+ Output Issues:
69
+
70
+ For very large code or long outputs, break code into sections for better results.
71
+
72
+ Contact:
73
+
74
+ Email info@shiftmind.io or visit www.shiftmind.io.
75
+
76
+ CodeTutor Pro brings high-quality, safe, multilingual code explanations to every learner—everywhere.