File size: 4,849 Bytes
868eab0
 
 
 
 
 
 
 
 
 
 
 
7e6c7e8
 
 
 
868eab0
7e6c7e8
 
868eab0
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
7e6c7e8
 
 
 
 
 
 
 
 
 
 
 
 
 
 
868eab0
 
 
 
 
 
 
 
 
 
 
 
 
 
 
f0a80b9
868eab0
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
7e6c7e8
868eab0
 
7e6c7e8
 
 
 
 
 
 
 
 
868eab0
7e6c7e8
 
 
 
 
 
 
 
 
868eab0
 
 
 
 
 
7e6c7e8
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
"""
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)