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("""
""", 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("""
""", 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('⚪ Paste some code first.
', 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'✅ Detected {detected} — matches your selection! (Confidence: {conf})
{reason}
', unsafe_allow_html=True)
else:
st.markdown(f'❌ Detected {detected} but you selected {src_lang} (Confidence: {conf})
{reason}
', 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("CodeShift · GPT-4o · Built with Streamlit", unsafe_allow_html=True)