Update app.py
Browse files
app.py
CHANGED
@@ -23,7 +23,7 @@ load_dotenv()
|
|
23 |
API_BASE_URL = os.environ.get("API_BASE_URL", "")
|
24 |
MODERATION_ENDPOINT = f"{API_BASE_URL}/v3/moderations"
|
25 |
|
26 |
-
# ---
|
27 |
# Mapping user-friendly names to ISO 639-1 codes
|
28 |
WHISPER_LANGUAGES = {
|
29 |
"English": "en", "Chinese": "zh", "German": "de", "Spanish": "es", "Russian": "ru",
|
@@ -80,7 +80,6 @@ def moderate_content(text_input, image_input, video_input, audio_input, language
|
|
80 |
if text_input:
|
81 |
payload["input"] = text_input
|
82 |
|
83 |
-
# Gradio provides file paths; we need to convert them to base64
|
84 |
image_b64 = file_to_base64(image_input)
|
85 |
if image_b64:
|
86 |
payload["image"] = image_b64
|
@@ -92,22 +91,19 @@ def moderate_content(text_input, image_input, video_input, audio_input, language
|
|
92 |
audio_b64 = file_to_base64(audio_input)
|
93 |
if audio_b64:
|
94 |
payload["voice"] = audio_b64
|
95 |
-
|
96 |
-
language_code = SORTED_LANGUAGES.get(language_full_name, "en") # Default to 'en' if not found
|
97 |
payload["language"] = language_code
|
98 |
logging.info(f"Audio detected. Using language: {language_full_name} ({language_code})")
|
99 |
|
100 |
-
|
101 |
logging.info(f"Sending request to {MODERATION_ENDPOINT} with inputs: {list(payload.keys())}")
|
102 |
|
103 |
summary_output = "An error occurred. Please check the logs."
|
104 |
full_response_output = {}
|
105 |
|
106 |
try:
|
107 |
-
# Using a synchronous client is simpler for this Gradio function
|
108 |
with httpx.Client(timeout=180.0) as client:
|
109 |
response = client.post(MODERATION_ENDPOINT, json=payload)
|
110 |
-
response.raise_for_status() # Raises
|
111 |
|
112 |
data = response.json()
|
113 |
full_response_output = data
|
@@ -116,15 +112,11 @@ def moderate_content(text_input, image_input, video_input, audio_input, language
|
|
116 |
summary_output = "API returned an empty result. This might happen if media processing fails (e.g., a video with no frames)."
|
117 |
return summary_output, full_response_output
|
118 |
|
119 |
-
# The v3 endpoint returns a single aggregated result
|
120 |
result = data["results"][0]
|
121 |
|
122 |
-
# Format a nice, human-readable summary
|
123 |
status = "π¨ FLAGGED π¨" if result["flagged"] else "β
SAFE β
"
|
124 |
reason = result.get("reason") or "N/A"
|
125 |
transcribed = result.get("transcribed_text") or "N/A"
|
126 |
-
|
127 |
-
# Create a clean list of flagged categories
|
128 |
flagged_categories = [cat for cat, flagged in result.get("categories", {}).items() if flagged]
|
129 |
categories_str = ", ".join(flagged_categories) if flagged_categories else "None"
|
130 |
|
@@ -140,16 +132,55 @@ def moderate_content(text_input, image_input, video_input, audio_input, language
|
|
140 |
"""
|
141 |
logging.info("Successfully received and parsed moderation response.")
|
142 |
|
|
|
143 |
except httpx.HTTPStatusError as e:
|
144 |
-
|
145 |
-
|
146 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
147 |
except httpx.RequestError as e:
|
148 |
-
|
149 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
150 |
except Exception as e:
|
151 |
-
|
152 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
153 |
|
154 |
return summary_output, full_response_output
|
155 |
|
@@ -171,7 +202,6 @@ with gr.Blocks(theme=gr.themes.Soft(), css="footer {display: none !important}")
|
|
171 |
video_input = gr.Video(label="Video Input")
|
172 |
audio_input = gr.Audio(label="Voice/Audio Input", type="filepath")
|
173 |
|
174 |
-
# --- NEW: Language selection dropdown ---
|
175 |
language_input = gr.Dropdown(
|
176 |
label="Audio Language (if providing audio)",
|
177 |
choices=list(SORTED_LANGUAGES.keys()),
|
@@ -188,7 +218,6 @@ with gr.Blocks(theme=gr.themes.Soft(), css="footer {display: none !important}")
|
|
188 |
|
189 |
submit_button.click(
|
190 |
fn=moderate_content,
|
191 |
-
# --- UPDATED: Add language_input to the list ---
|
192 |
inputs=[text_input, image_input, video_input, audio_input, language_input],
|
193 |
outputs=[result_output, full_response_output]
|
194 |
)
|
@@ -198,13 +227,11 @@ with gr.Blocks(theme=gr.themes.Soft(), css="footer {display: none !important}")
|
|
198 |
["This is a test of the system with safe text.", None, None, None, "English"],
|
199 |
["I am going to kill the process on my computer.", None, None, None, "English"],
|
200 |
],
|
201 |
-
# --- UPDATED: Add language_input to the list ---
|
202 |
inputs=[text_input, image_input, video_input, audio_input, language_input],
|
203 |
outputs=[result_output, full_response_output],
|
204 |
fn=moderate_content
|
205 |
)
|
206 |
|
207 |
-
|
208 |
if __name__ == "__main__":
|
209 |
logging.info(f"Connecting to API server at: {API_BASE_URL}")
|
210 |
if API_BASE_URL == "http://127.0.0.1:8000":
|
|
|
23 |
API_BASE_URL = os.environ.get("API_BASE_URL", "")
|
24 |
MODERATION_ENDPOINT = f"{API_BASE_URL}/v3/moderations"
|
25 |
|
26 |
+
# --- Full list of Whisper V3 supported languages ---
|
27 |
# Mapping user-friendly names to ISO 639-1 codes
|
28 |
WHISPER_LANGUAGES = {
|
29 |
"English": "en", "Chinese": "zh", "German": "de", "Spanish": "es", "Russian": "ru",
|
|
|
80 |
if text_input:
|
81 |
payload["input"] = text_input
|
82 |
|
|
|
83 |
image_b64 = file_to_base64(image_input)
|
84 |
if image_b64:
|
85 |
payload["image"] = image_b64
|
|
|
91 |
audio_b64 = file_to_base64(audio_input)
|
92 |
if audio_b64:
|
93 |
payload["voice"] = audio_b64
|
94 |
+
language_code = SORTED_LANGUAGES.get(language_full_name, "en") # Default to 'en'
|
|
|
95 |
payload["language"] = language_code
|
96 |
logging.info(f"Audio detected. Using language: {language_full_name} ({language_code})")
|
97 |
|
|
|
98 |
logging.info(f"Sending request to {MODERATION_ENDPOINT} with inputs: {list(payload.keys())}")
|
99 |
|
100 |
summary_output = "An error occurred. Please check the logs."
|
101 |
full_response_output = {}
|
102 |
|
103 |
try:
|
|
|
104 |
with httpx.Client(timeout=180.0) as client:
|
105 |
response = client.post(MODERATION_ENDPOINT, json=payload)
|
106 |
+
response.raise_for_status() # Raises HTTPStatusError for 4xx/5xx responses
|
107 |
|
108 |
data = response.json()
|
109 |
full_response_output = data
|
|
|
112 |
summary_output = "API returned an empty result. This might happen if media processing fails (e.g., a video with no frames)."
|
113 |
return summary_output, full_response_output
|
114 |
|
|
|
115 |
result = data["results"][0]
|
116 |
|
|
|
117 |
status = "π¨ FLAGGED π¨" if result["flagged"] else "β
SAFE β
"
|
118 |
reason = result.get("reason") or "N/A"
|
119 |
transcribed = result.get("transcribed_text") or "N/A"
|
|
|
|
|
120 |
flagged_categories = [cat for cat, flagged in result.get("categories", {}).items() if flagged]
|
121 |
categories_str = ", ".join(flagged_categories) if flagged_categories else "None"
|
122 |
|
|
|
132 |
"""
|
133 |
logging.info("Successfully received and parsed moderation response.")
|
134 |
|
135 |
+
# --- MODIFIED: Enhanced Error Handling ---
|
136 |
except httpx.HTTPStatusError as e:
|
137 |
+
# Catches errors returned by the backend API (e.g., 422, 500)
|
138 |
+
user_message = "The moderation service returned an error."
|
139 |
+
error_details = ""
|
140 |
+
try:
|
141 |
+
# Try to parse the JSON error response from the server
|
142 |
+
error_json = e.response.json()
|
143 |
+
detail = error_json.get("detail", "No specific error detail provided.")
|
144 |
+
error_details = f"**Reason:** {detail}"
|
145 |
+
full_response_output = {"error": "Backend API Error", "status_code": e.response.status_code, "details": error_json}
|
146 |
+
except (json.JSONDecodeError, AttributeError):
|
147 |
+
# Fallback for non-JSON or unexpected error formats
|
148 |
+
error_details = f"**Raw Server Response:**\n```\n{e.response.text}\n```"
|
149 |
+
full_response_output = {"error": "Backend API Error", "status_code": e.response.status_code, "details": e.response.text}
|
150 |
+
|
151 |
+
summary_output = f"""
|
152 |
+
**π« Error from Moderation Service (HTTP {e.response.status_code})**
|
153 |
+
---
|
154 |
+
{user_message}
|
155 |
+
|
156 |
+
{error_details}
|
157 |
+
"""
|
158 |
+
logging.error(f"HTTP Status Error: {e.response.status_code} - Response: {e.response.text}")
|
159 |
+
|
160 |
except httpx.RequestError as e:
|
161 |
+
# Catches network errors (e.g., server is down, DNS issues)
|
162 |
+
summary_output = f"""
|
163 |
+
**π Connection Error**
|
164 |
+
---
|
165 |
+
Could not connect to the API server at `{API_BASE_URL}`.
|
166 |
+
|
167 |
+
Please ensure the backend server is running and the URL is configured correctly in your `.env` file.
|
168 |
+
"""
|
169 |
+
full_response_output = {"error": "Connection Error", "url": API_BASE_URL, "details": str(e)}
|
170 |
+
logging.error(f"Request Error: Could not connect to {API_BASE_URL}. Details: {e}")
|
171 |
+
|
172 |
except Exception as e:
|
173 |
+
# A catch-all for any other unexpected errors in this Gradio script
|
174 |
+
summary_output = f"""
|
175 |
+
**π₯ An Unexpected Application Error Occurred**
|
176 |
+
---
|
177 |
+
An error happened within the Gradio application itself.
|
178 |
+
Please check the application logs for more details.
|
179 |
+
|
180 |
+
**Error Type:** `{type(e).__name__}`
|
181 |
+
"""
|
182 |
+
full_response_output = {"error": "Gradio App Internal Error", "type": type(e).__name__, "details": str(e)}
|
183 |
+
logging.error(f"Unexpected Error in Gradio App: {e}", exc_info=True)
|
184 |
|
185 |
return summary_output, full_response_output
|
186 |
|
|
|
202 |
video_input = gr.Video(label="Video Input")
|
203 |
audio_input = gr.Audio(label="Voice/Audio Input", type="filepath")
|
204 |
|
|
|
205 |
language_input = gr.Dropdown(
|
206 |
label="Audio Language (if providing audio)",
|
207 |
choices=list(SORTED_LANGUAGES.keys()),
|
|
|
218 |
|
219 |
submit_button.click(
|
220 |
fn=moderate_content,
|
|
|
221 |
inputs=[text_input, image_input, video_input, audio_input, language_input],
|
222 |
outputs=[result_output, full_response_output]
|
223 |
)
|
|
|
227 |
["This is a test of the system with safe text.", None, None, None, "English"],
|
228 |
["I am going to kill the process on my computer.", None, None, None, "English"],
|
229 |
],
|
|
|
230 |
inputs=[text_input, image_input, video_input, audio_input, language_input],
|
231 |
outputs=[result_output, full_response_output],
|
232 |
fn=moderate_content
|
233 |
)
|
234 |
|
|
|
235 |
if __name__ == "__main__":
|
236 |
logging.info(f"Connecting to API server at: {API_BASE_URL}")
|
237 |
if API_BASE_URL == "http://127.0.0.1:8000":
|