CodeConvertorAI / app.py
dwishank's picture
Create app.py
8f6fc40 verified
import streamlit as st
import openai
import os
import re
import json
# ── Page config ────────────────────────────────────────────────────────────────
st.set_page_config(
page_title="CodeShift Β· AI Code Converter",
page_icon="⚑",
layout="wide",
)
# ── Styling ────────────────────────────────────────────────────────────────────
st.markdown("""
<style>
@import url('https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;600&family=Syne:wght@700;800&display=swap');
html, body, [class*="css"] { font-family: 'Syne', sans-serif; }
.header {
background: linear-gradient(135deg, #1a1040, #0d1a2a);
padding: 24px 32px;
border-radius: 12px;
margin-bottom: 24px;
}
.header h1 {
font-size: 2rem; font-weight: 800; margin: 0;
background: linear-gradient(90deg, #7c6af7, #3ecfcf);
-webkit-background-clip: text; -webkit-text-fill-color: transparent;
}
.header p { color: #7a7f94; margin: 4px 0 0; font-size: 0.9rem; }
.status-box { padding: 10px 16px; border-radius: 8px; font-size: 0.88rem; margin-top: 8px; }
.status-ok { background: #0d2b1f; border-left: 3px solid #3ecf8e; color: #3ecf8e; }
.status-err { background: #2b0d0d; border-left: 3px solid #f76464; color: #f76464; }
.status-info { background: #1a1a2e; border-left: 3px solid #7c6af7; color: #a99ff7; }
textarea { font-family: 'JetBrains Mono', monospace !important; font-size: 0.82rem !important; }
</style>
""", unsafe_allow_html=True)
# ── OpenAI client ──────────────────────────────────────────────────────────────
client = openai.OpenAI(api_key=os.environ.get("OPENAI_API_KEY"))
LANGUAGES = [
"Python", "JavaScript", "TypeScript", "Java", "C", "C++", "C#",
"Go", "Rust", "Ruby", "PHP", "Swift", "Kotlin", "Bash/Shell", "SQL",
]
# ── AI helpers ─────────────────────────────────────────────────────────────────
def validate_language(code: str, selected: str):
resp = client.chat.completions.create(
model="gpt-4o", temperature=0,
messages=[
{"role": "system", "content": 'Detect the programming language. Reply ONLY with JSON: {"language":"X","confidence":"high/medium/low","reason":"..."}'},
{"role": "user", "content": code[:3000]},
],
)
raw = re.sub(r"```[a-z]*\n?|```", "", resp.choices[0].message.content).strip()
data = json.loads(raw)
detected = data.get("language", "Unknown")
match = detected.lower() == selected.lower()
return detected, data.get("confidence", "?"), data.get("reason", ""), match
def convert_code(code: str, src: str, tgt: str, notes: str):
prompt = (
f"Convert the {src} code to idiomatic {tgt}. "
f"Preserve all logic. Add comments for non-obvious parts. "
f"Return ONLY raw code β€” no markdown fences, no preamble."
+ (f" Style notes: {notes}" if notes.strip() else "")
)
resp = client.chat.completions.create(
model="gpt-4o", temperature=0.2,
messages=[
{"role": "system", "content": prompt},
{"role": "user", "content": code},
],
)
return re.sub(r"```[a-z]*\n?|```", "", resp.choices[0].message.content).strip()
def explain_code(code: str, lang: str):
resp = client.chat.completions.create(
model="gpt-4o", temperature=0.3,
messages=[
{"role": "system", "content": "Explain this code clearly in plain English using bullet points. Be concise."},
{"role": "user", "content": f"{lang} code:\n\n{code[:4000]}"},
],
)
return resp.choices[0].message.content.strip()
# ── Header ─────────────────────────────────────────────────────────────────────
st.markdown("""
<div class="header">
<h1>⚑ CodeShift</h1>
<p>AI-powered code converter &amp; analyser Β· GPT-4o</p>
</div>
""", unsafe_allow_html=True)
# ── Tabs ───────────────────────────────────────────────────────────────────────
tab1, tab2, tab3 = st.tabs(["πŸ”„ Convert", "πŸ’‘ Explain", "πŸ”Ž Detect"])
# ════════════════════════
# TAB 1 β€” CONVERT
# ════════════════════════
with tab1:
col_l, col_r = st.columns(2, gap="medium")
with col_l:
st.markdown("### Source Code")
src_lang = st.selectbox("Source Language", LANGUAGES, index=0, key="src_lang")
src_code = st.text_area("", height=380, placeholder="# Paste your source code here…", key="src_code")
style_notes = st.text_input("Style notes (optional)", placeholder="e.g. 'use async/await', 'add type hints'…")
c1, c2, c3 = st.columns(3)
validate_btn = c1.button("πŸ” Validate", use_container_width=True)
convert_btn = c2.button("⚑ Convert", use_container_width=True, type="primary")
clear_btn = c3.button("πŸ—‘ Clear", use_container_width=True)
if validate_btn:
if not src_code.strip():
st.markdown('<div class="status-box status-info">βšͺ Paste some code first.</div>', unsafe_allow_html=True)
else:
with st.spinner("Detecting language…"):
detected, conf, reason, match = validate_language(src_code, src_lang)
if match:
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)
else:
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)
if clear_btn:
st.session_state["src_code"] = ""
st.session_state["converted"] = ""
st.rerun()
with col_r:
st.markdown("### Converted Code")
tgt_lang = st.selectbox("Target Language", LANGUAGES, index=1, key="tgt_lang")
if convert_btn:
if not src_code.strip():
st.warning("Paste some source code first.")
elif src_lang == tgt_lang:
st.info("Source and target languages are the same.")
else:
with st.spinner(f"Converting {src_lang} β†’ {tgt_lang}…"):
result = convert_code(src_code, src_lang, tgt_lang, style_notes)
st.session_state["converted"] = result
st.session_state["conv_langs"] = (src_lang, tgt_lang)
converted = st.session_state.get("converted", "")
langs = st.session_state.get("conv_langs", ("", ""))
if converted:
st.success(f"βœ… Converted {langs[0]} β†’ {langs[1]}")
st.text_area("", value=converted, height=380,
placeholder="# Converted code appears here…",
key="tgt_code")
# ════════════════════════
# TAB 2 β€” EXPLAIN
# ════════════════════════
with tab2:
col_l, col_r = st.columns(2, gap="medium")
with col_l:
st.markdown("### Paste Code to Explain")
exp_lang = st.selectbox("Language", LANGUAGES, key="exp_lang")
exp_code = st.text_area("", height=380, placeholder="# Paste code here…", key="exp_code")
exp_btn = st.button("πŸ’‘ Explain", type="primary", use_container_width=True)
with col_r:
st.markdown("### AI Explanation")
if exp_btn:
if not exp_code.strip():
st.warning("Paste some code first.")
else:
with st.spinner("Explaining…"):
st.session_state["explanation"] = explain_code(exp_code, exp_lang)
if st.session_state.get("explanation"):
st.markdown(st.session_state["explanation"])
else:
st.caption("Explanation will appear here after you click Explain.")
# ════════════════════════
# TAB 3 β€” DETECT
# ════════════════════════
with tab3:
col_l, col_r = st.columns(2, gap="medium")
with col_l:
st.markdown("### Mystery Code")
det_code = st.text_area("", height=380, placeholder="# Paste any code here…", key="det_code")
det_btn = st.button("πŸ”Ž Detect Language", type="primary", use_container_width=True)
with col_r:
st.markdown("### Detection Result")
if det_btn:
if not det_code.strip():
st.warning("Paste some code first.")
else:
with st.spinner("Analysing…"):
detected, conf, reason, _ = validate_language(det_code, "")
st.metric("Detected Language", detected)
st.metric("Confidence", conf.capitalize())
st.info(reason)
else:
st.caption("Results will appear here after detection.")
st.markdown("---")
st.markdown("<center style='color:#4a5068;font-size:0.78rem'>CodeShift Β· GPT-4o Β· Built with Streamlit</center>", unsafe_allow_html=True)