dwishank commited on
Commit
8f6fc40
Β·
verified Β·
1 Parent(s): 7817507

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +216 -0
app.py ADDED
@@ -0,0 +1,216 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import streamlit as st
2
+ import openai
3
+ import os
4
+ import re
5
+ import json
6
+
7
+ # ── Page config ────────────────────────────────────────────────────────────────
8
+ st.set_page_config(
9
+ page_title="CodeShift Β· AI Code Converter",
10
+ page_icon="⚑",
11
+ layout="wide",
12
+ )
13
+
14
+ # ── Styling ────────────────────────────────────────────────────────────────────
15
+ st.markdown("""
16
+ <style>
17
+ @import url('https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;600&family=Syne:wght@700;800&display=swap');
18
+
19
+ html, body, [class*="css"] { font-family: 'Syne', sans-serif; }
20
+
21
+ .header {
22
+ background: linear-gradient(135deg, #1a1040, #0d1a2a);
23
+ padding: 24px 32px;
24
+ border-radius: 12px;
25
+ margin-bottom: 24px;
26
+ }
27
+ .header h1 {
28
+ font-size: 2rem; font-weight: 800; margin: 0;
29
+ background: linear-gradient(90deg, #7c6af7, #3ecfcf);
30
+ -webkit-background-clip: text; -webkit-text-fill-color: transparent;
31
+ }
32
+ .header p { color: #7a7f94; margin: 4px 0 0; font-size: 0.9rem; }
33
+
34
+ .status-box { padding: 10px 16px; border-radius: 8px; font-size: 0.88rem; margin-top: 8px; }
35
+ .status-ok { background: #0d2b1f; border-left: 3px solid #3ecf8e; color: #3ecf8e; }
36
+ .status-err { background: #2b0d0d; border-left: 3px solid #f76464; color: #f76464; }
37
+ .status-info { background: #1a1a2e; border-left: 3px solid #7c6af7; color: #a99ff7; }
38
+
39
+ textarea { font-family: 'JetBrains Mono', monospace !important; font-size: 0.82rem !important; }
40
+ </style>
41
+ """, unsafe_allow_html=True)
42
+
43
+ # ── OpenAI client ──────────────────────────────────────────────────────────────
44
+ client = openai.OpenAI(api_key=os.environ.get("OPENAI_API_KEY"))
45
+
46
+ LANGUAGES = [
47
+ "Python", "JavaScript", "TypeScript", "Java", "C", "C++", "C#",
48
+ "Go", "Rust", "Ruby", "PHP", "Swift", "Kotlin", "Bash/Shell", "SQL",
49
+ ]
50
+
51
+ # ── AI helpers ─────────────────────────────────────────────────────────────────
52
+
53
+ def validate_language(code: str, selected: str):
54
+ resp = client.chat.completions.create(
55
+ model="gpt-4o", temperature=0,
56
+ messages=[
57
+ {"role": "system", "content": 'Detect the programming language. Reply ONLY with JSON: {"language":"X","confidence":"high/medium/low","reason":"..."}'},
58
+ {"role": "user", "content": code[:3000]},
59
+ ],
60
+ )
61
+ raw = re.sub(r"```[a-z]*\n?|```", "", resp.choices[0].message.content).strip()
62
+ data = json.loads(raw)
63
+ detected = data.get("language", "Unknown")
64
+ match = detected.lower() == selected.lower()
65
+ return detected, data.get("confidence", "?"), data.get("reason", ""), match
66
+
67
+
68
+ def convert_code(code: str, src: str, tgt: str, notes: str):
69
+ prompt = (
70
+ f"Convert the {src} code to idiomatic {tgt}. "
71
+ f"Preserve all logic. Add comments for non-obvious parts. "
72
+ f"Return ONLY raw code β€” no markdown fences, no preamble."
73
+ + (f" Style notes: {notes}" if notes.strip() else "")
74
+ )
75
+ resp = client.chat.completions.create(
76
+ model="gpt-4o", temperature=0.2,
77
+ messages=[
78
+ {"role": "system", "content": prompt},
79
+ {"role": "user", "content": code},
80
+ ],
81
+ )
82
+ return re.sub(r"```[a-z]*\n?|```", "", resp.choices[0].message.content).strip()
83
+
84
+
85
+ def explain_code(code: str, lang: str):
86
+ resp = client.chat.completions.create(
87
+ model="gpt-4o", temperature=0.3,
88
+ messages=[
89
+ {"role": "system", "content": "Explain this code clearly in plain English using bullet points. Be concise."},
90
+ {"role": "user", "content": f"{lang} code:\n\n{code[:4000]}"},
91
+ ],
92
+ )
93
+ return resp.choices[0].message.content.strip()
94
+
95
+ # ── Header ─────────────────────────────────────────────────────────────────────
96
+ st.markdown("""
97
+ <div class="header">
98
+ <h1>⚑ CodeShift</h1>
99
+ <p>AI-powered code converter &amp; analyser Β· GPT-4o</p>
100
+ </div>
101
+ """, unsafe_allow_html=True)
102
+
103
+ # ── Tabs ───────────────────────────────────────────────────────────────────────
104
+ tab1, tab2, tab3 = st.tabs(["πŸ”„ Convert", "πŸ’‘ Explain", "πŸ”Ž Detect"])
105
+
106
+ # ════════════════════════
107
+ # TAB 1 β€” CONVERT
108
+ # ════════════════════════
109
+ with tab1:
110
+ col_l, col_r = st.columns(2, gap="medium")
111
+
112
+ with col_l:
113
+ st.markdown("### Source Code")
114
+ src_lang = st.selectbox("Source Language", LANGUAGES, index=0, key="src_lang")
115
+ src_code = st.text_area("", height=380, placeholder="# Paste your source code here…", key="src_code")
116
+ style_notes = st.text_input("Style notes (optional)", placeholder="e.g. 'use async/await', 'add type hints'…")
117
+
118
+ c1, c2, c3 = st.columns(3)
119
+ validate_btn = c1.button("πŸ” Validate", use_container_width=True)
120
+ convert_btn = c2.button("⚑ Convert", use_container_width=True, type="primary")
121
+ clear_btn = c3.button("πŸ—‘ Clear", use_container_width=True)
122
+
123
+ if validate_btn:
124
+ if not src_code.strip():
125
+ st.markdown('<div class="status-box status-info">βšͺ Paste some code first.</div>', unsafe_allow_html=True)
126
+ else:
127
+ with st.spinner("Detecting language…"):
128
+ detected, conf, reason, match = validate_language(src_code, src_lang)
129
+ if match:
130
+ st.markdown(f'<div class="status-box status-ok">βœ… Detected <b>{detected}</b> β€” matches your selection! (Confidence: {conf})<br><small>{reason}</small></div>', unsafe_allow_html=True)
131
+ else:
132
+ st.markdown(f'<div class="status-box status-err">❌ Detected <b>{detected}</b> but you selected <b>{src_lang}</b> (Confidence: {conf})<br><small>{reason}</small></div>', unsafe_allow_html=True)
133
+
134
+ if clear_btn:
135
+ st.session_state["src_code"] = ""
136
+ st.session_state["converted"] = ""
137
+ st.rerun()
138
+
139
+ with col_r:
140
+ st.markdown("### Converted Code")
141
+ tgt_lang = st.selectbox("Target Language", LANGUAGES, index=1, key="tgt_lang")
142
+
143
+ if convert_btn:
144
+ if not src_code.strip():
145
+ st.warning("Paste some source code first.")
146
+ elif src_lang == tgt_lang:
147
+ st.info("Source and target languages are the same.")
148
+ else:
149
+ with st.spinner(f"Converting {src_lang} β†’ {tgt_lang}…"):
150
+ result = convert_code(src_code, src_lang, tgt_lang, style_notes)
151
+ st.session_state["converted"] = result
152
+ st.session_state["conv_langs"] = (src_lang, tgt_lang)
153
+
154
+ converted = st.session_state.get("converted", "")
155
+ langs = st.session_state.get("conv_langs", ("", ""))
156
+
157
+ if converted:
158
+ st.success(f"βœ… Converted {langs[0]} β†’ {langs[1]}")
159
+
160
+ st.text_area("", value=converted, height=380,
161
+ placeholder="# Converted code appears here…",
162
+ key="tgt_code")
163
+
164
+ # ════════════════════════
165
+ # TAB 2 β€” EXPLAIN
166
+ # ════════════════════════
167
+ with tab2:
168
+ col_l, col_r = st.columns(2, gap="medium")
169
+
170
+ with col_l:
171
+ st.markdown("### Paste Code to Explain")
172
+ exp_lang = st.selectbox("Language", LANGUAGES, key="exp_lang")
173
+ exp_code = st.text_area("", height=380, placeholder="# Paste code here…", key="exp_code")
174
+ exp_btn = st.button("πŸ’‘ Explain", type="primary", use_container_width=True)
175
+
176
+ with col_r:
177
+ st.markdown("### AI Explanation")
178
+ if exp_btn:
179
+ if not exp_code.strip():
180
+ st.warning("Paste some code first.")
181
+ else:
182
+ with st.spinner("Explaining…"):
183
+ st.session_state["explanation"] = explain_code(exp_code, exp_lang)
184
+
185
+ if st.session_state.get("explanation"):
186
+ st.markdown(st.session_state["explanation"])
187
+ else:
188
+ st.caption("Explanation will appear here after you click Explain.")
189
+
190
+ # ════════════════════════
191
+ # TAB 3 β€” DETECT
192
+ # ════════════════════════
193
+ with tab3:
194
+ col_l, col_r = st.columns(2, gap="medium")
195
+
196
+ with col_l:
197
+ st.markdown("### Mystery Code")
198
+ det_code = st.text_area("", height=380, placeholder="# Paste any code here…", key="det_code")
199
+ det_btn = st.button("πŸ”Ž Detect Language", type="primary", use_container_width=True)
200
+
201
+ with col_r:
202
+ st.markdown("### Detection Result")
203
+ if det_btn:
204
+ if not det_code.strip():
205
+ st.warning("Paste some code first.")
206
+ else:
207
+ with st.spinner("Analysing…"):
208
+ detected, conf, reason, _ = validate_language(det_code, "")
209
+ st.metric("Detected Language", detected)
210
+ st.metric("Confidence", conf.capitalize())
211
+ st.info(reason)
212
+ else:
213
+ st.caption("Results will appear here after detection.")
214
+
215
+ st.markdown("---")
216
+ st.markdown("<center style='color:#4a5068;font-size:0.78rem'>CodeShift Β· GPT-4o Β· Built with Streamlit</center>", unsafe_allow_html=True)