cplusplus-to-python / frontend /streamlit_app.py
DxCode's picture
Fix
7e6c7e8
Raw
History Blame Contribute Delete
4.85 kB
"""
Streamlit frontend for the C++ to Python translation app.
Run locally with:
streamlit run frontend/streamlit_app.py
"""
import os
import requests
import streamlit as st
try:
from backend.cpp_python_translator import translate_competitive_cpp
except ImportError:
translate_competitive_cpp = None
DEFAULT_BACKEND_URL = "http://127.0.0.1:8000/translate"
BACKEND_URL = os.getenv("TRANSLATE_API_URL", DEFAULT_BACKEND_URL)
REQUEST_TIMEOUT_SECONDS = 120
st.set_page_config(
page_title="C++ to Python Translator",
page_icon="</>",
layout="wide",
)
st.title("C++ to Python Translator")
st.caption("Translate competitive-programming C++ solutions into Python.")
default_cpp_code = """#include <bits/stdc++.h>
using namespace std;
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n;
cin >> n;
vector<int> a(n);
for (int i = 0; i < n; i++) {
cin >> a[i];
}
long long sum = 0;
for (int x : a) {
sum += x;
}
cout << sum << '\\n';
return 0;
}
"""
source_code = st.text_area(
label="C++ source code",
value=default_cpp_code,
height=420,
)
translate_clicked = st.button(
"Translate",
type="primary",
use_container_width=False,
)
def render_translated_code(translated_code: str) -> None:
if not translated_code:
st.error("No translated code was produced.")
return
st.subheader("Translated Python")
st.code(translated_code, language="python")
def translate_locally(source_code_to_translate: str) -> str | None:
if translate_competitive_cpp is None:
return None
return translate_competitive_cpp(source_code_to_translate)
if translate_clicked:
cleaned_source_code = source_code.strip()
if not cleaned_source_code:
st.warning("Please enter C++ code before translating.")
else:
# HTTP request handling:
# - The frontend sends JSON because the FastAPI endpoint expects a
# Pydantic body with the source_code string field.
# - requests.post serializes the dict below to:
# {"source_code": "..."}
# - timeout prevents the UI from hanging forever if the model server is
# cold, overloaded, or unreachable.
payload = {"source_code": cleaned_source_code}
with st.spinner("Translating..."):
try:
response = requests.post(
BACKEND_URL,
json=payload,
timeout=REQUEST_TIMEOUT_SECONDS,
)
# Raise an exception for 4xx/5xx responses so they are handled
# in one place below instead of silently rendering bad output.
response.raise_for_status()
# FastAPI returns JSON shaped like:
# {"translated_code": "print(...)"}
response_json = response.json()
translated_code = response_json.get("translated_code", "")
render_translated_code(translated_code)
except requests.exceptions.ConnectionError:
translated_code = translate_locally(cleaned_source_code)
if translated_code is None:
st.error(
"Could not reach the FastAPI backend and local translation "
"is unavailable in this build."
)
else:
st.warning("FastAPI was unavailable, so local translation was used.")
render_translated_code(translated_code)
except requests.exceptions.Timeout:
translated_code = translate_locally(cleaned_source_code)
if translated_code is None:
st.error(
"The translation request timed out and local translation "
"is unavailable in this build."
)
else:
st.warning("The backend timed out, so local translation was used.")
render_translated_code(translated_code)
except requests.exceptions.HTTPError as exc:
error_message = response.text if "response" in locals() else str(exc)
st.error(f"The backend returned an error: {error_message}")
except ValueError:
st.error("The backend response was not valid JSON.")
except requests.exceptions.RequestException as exc:
translated_code = translate_locally(cleaned_source_code)
if translated_code is None:
st.error(f"Request failed: {exc}")
else:
st.warning("The backend request failed, so local translation was used.")
render_translated_code(translated_code)