File size: 7,231 Bytes
7d11191
 
 
e7dbf80
7d11191
 
e7dbf80
7d11191
 
 
 
4f1311e
e7dbf80
 
 
 
 
7d11191
4f1311e
 
 
 
 
7d11191
4f1311e
 
7d11191
e7dbf80
 
 
 
 
 
 
 
4f1311e
 
 
 
 
cf5b48d
4f1311e
cf5b48d
 
 
4f1311e
 
7d11191
4f1311e
 
 
 
 
 
 
cf5b48d
 
 
4f1311e
 
cf5b48d
 
 
4f1311e
 
 
cf5b48d
4f1311e
7d11191
4f1311e
 
7d11191
cf5b48d
 
 
 
 
4f1311e
 
7d11191
cf5b48d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4f1311e
 
 
7d11191
4f1311e
 
 
 
 
 
e7dbf80
 
 
 
 
 
1aa73ec
 
 
 
 
 
 
 
 
 
 
f5aeb1a
 
 
 
 
 
 
 
 
 
 
 
 
4f1311e
 
 
 
f5aeb1a
 
 
 
 
 
 
e7dbf80
 
 
 
 
4f1311e
 
 
 
1aa73ec
 
 
 
4f1311e
 
 
 
 
cf5b48d
4f1311e
1aa73ec
 
 
 
 
 
4f1311e
cf5b48d
 
4f1311e
e7dbf80
4f1311e
 
 
cf5b48d
 
 
4f1311e
cf5b48d
 
 
4f1311e
7d11191
4f1311e
 
 
7d11191
4f1311e
cf5b48d
 
 
 
 
e7dbf80
 
 
 
 
7d11191
 
f5aeb1a
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
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
import gradio as gr
import pandas as pd
import os
from translator_utils import process_rows, revert_rows, download_dataset, LOCAL_FILENAME, ENV_HF_TOKEN, read_csv_robust

def load_data():
    """Load the dataset safely using robust reader."""
    if not os.path.exists(LOCAL_FILENAME):
        try:
            download_dataset()
        except:
            return pd.DataFrame()
            
    df = read_csv_robust(LOCAL_FILENAME)
    if df.empty:
        return df
        
    try:
        if 'Judul_Inggris' not in df.columns:
            df['Judul_Inggris'] = ""
        if 'Isi_Inggris' not in df.columns:
            df['Isi_Inggris'] = ""
        df = df.fillna("")
        return df
    except:
        return pd.DataFrame()

def force_refresh_data():
    """Forces a re-download and reload of the data."""
    try:
        download_dataset(force=True)
        return load_data(), "Data refreshed successfully."
    except Exception as e:
        return pd.DataFrame(), f"Failed to refresh data: {e}"

def get_pending_data(full_df):
    """Filter for rows that are NOT fully translated."""
    if full_df.empty:
        return full_df
    mask = (full_df['Judul_Inggris'].str.strip() == "") | (full_df['Isi_Inggris'].str.strip() == "")
    
    df_view = full_df[mask].copy()
    df_view.reset_index(inplace=True) 
    df_view.rename(columns={'index': 'ID'}, inplace=True)
    
    df_view.insert(0, "Select", False)
    return df_view

def get_history_data(full_df, date_filter=""):
    """Filter for rows that ARE fully translated."""
    if full_df.empty:
        return full_df
    mask = (full_df['Judul_Inggris'].str.strip() != "") & (full_df['Isi_Inggris'].str.strip() != "")
    df_view = full_df[mask].copy()
    
    df_view.reset_index(inplace=True)
    df_view.rename(columns={'index': 'ID'}, inplace=True)
    
    if date_filter:
        df_view = df_view[df_view['Tanggal'].str.contains(date_filter, case=False, na=False)]
    
    # Add 'Select' column for Revert functionality
    df_view.insert(0, "Select", False)
    return df_view

def on_translate_selected(df_data, token, progress=gr.Progress()):
    """Callback when user clicks 'Translate Selected'."""
    selected_rows = df_data[df_data["Select"] == True]
    
    if selected_rows.empty:
        return gr.DataFrame(), gr.DataFrame(), "No rows selected!"
    
    try:
        indices = selected_rows['ID'].tolist()
        indices = [int(i) for i in indices]
    except KeyError:
        return gr.DataFrame(), gr.DataFrame(), "Error: ID column missing."
    
    updated_df, msg = process_rows(indices, token=token, progress=progress)
    
    pending = get_pending_data(updated_df)
    history = get_history_data(updated_df)
    
    return pending, history, msg

def on_revert_selected(df_data, token, progress=gr.Progress()):
    """Callback when user clicks 'Revert Selected'."""
    selected_rows = df_data[df_data["Select"] == True]
    
    if selected_rows.empty:
        return gr.DataFrame(), gr.DataFrame(), "No rows selected!"
    
    try:
        indices = selected_rows['ID'].tolist()
        indices = [int(i) for i in indices]
    except KeyError:
        return gr.DataFrame(), gr.DataFrame(), "Error: ID column missing."
    
    # Call revert
    updated_df, msg = revert_rows(indices, token=token, progress=progress)
    
    # Refresh views
    pending = get_pending_data(updated_df)
    history = get_history_data(updated_df)
    
    return pending, history, msg

def filter_history(date_input):
    df = load_data()
    return get_history_data(df, date_input)

def refresh_views():
    df, msg = force_refresh_data()
    pending = get_pending_data(df)
    history = get_history_data(df)
    return pending, history, msg

def auto_select_pending(df_view):
    """Automatically selects the first 10 rows in the pending view."""
    if df_view.empty:
        return df_view, "No rows to select."
    
    # Set 'Select' to True for the first 10 rows
    limit = min(10, len(df_view))
    df_view.loc[:limit-1, "Select"] = True
    
    return df_view, f"Auto-selected top {limit} rows."

# CSS to ensure columns are readable
custom_css = """
/* Fix minimum width for content columns */
table td:nth-child(5), table td:nth-child(6), table td:nth-child(7), table td:nth-child(8) {
    min-width: 300px !important;
    white-space: pre-wrap !important;
}
/* Ensure row ID is small */
table td:nth-child(2) {
    width: 50px !important;
}
"""

with gr.Blocks(title="Auto AI News Translator") as app:
    gr.Markdown("# Auto AI News Translator")
    gr.Markdown("Translate news from Indonesian to English (with Chunking). Select rows to translate.")
    
    # Inject default value from Env Var
    hf_token = gr.Textbox(
        label="HF Token (Optional for Persistence)", 
        placeholder="hf_... (Leave empty if set in ENV)", 
        type="password",
        value=ENV_HF_TOKEN
    )
    
    with gr.Row():
        status_output = gr.Textbox(label="Status", value="Ready", interactive=False, scale=4)
        refresh_btn = gr.Button("🔄 Refresh Data (Force Redownload)", scale=1)
        
    
    with gr.Tabs():
        with gr.TabItem("Translate Pending"):
            gr.Markdown("Select rows to translate and click Submit.")
            with gr.Row():
                auto_select_btn = gr.Button("Auto-Select Next 10", size="sm")
                translate_btn = gr.Button("Translate Selected Rows", variant="primary")
            
            pending_df_comp = gr.DataFrame(
                value=get_pending_data(load_data()),
                label="Pending Translations",
                interactive=True,
                wrap=True,
                datatype=["bool", "number"] + ["str"] * 6 
            )

            auto_select_btn.click(
                fn=auto_select_pending,
                inputs=[pending_df_comp],
                outputs=[pending_df_comp, status_output]
            )
            
        with gr.TabItem("History (Revert Supported)"):
            gr.Markdown("Select rows to delete translation and move back to Pending.")
            date_filter = gr.Textbox(label="Filter by Date (YYYY-MM-DD)")
            # History now has checkbox
            history_df_comp = gr.DataFrame(
                value=get_history_data(load_data()),
                label="Translation History",
                interactive=True,
                wrap=True,
                datatype=["bool", "number"] + ["str"] * 6
            )
            with gr.Row():
                date_filter.change(fn=filter_history, inputs=[date_filter], outputs=[history_df_comp])
                revert_btn = gr.Button("Revert Selected (Delete & Move to Pending)", variant="stop")

    translate_btn.click(
        fn=on_translate_selected,
        inputs=[pending_df_comp, hf_token],
        outputs=[pending_df_comp, history_df_comp, status_output]
    )
    
    revert_btn.click(
        fn=on_revert_selected,
        inputs=[history_df_comp, hf_token],
        outputs=[pending_df_comp, history_df_comp, status_output]
    )
    
    refresh_btn.click(
        fn=refresh_views,
        outputs=[pending_df_comp, history_df_comp, status_output]
    )

if __name__ == "__main__":
    app.launch(css=custom_css)