ellagranger commited on
Commit
34b69bb
·
1 Parent(s): 15240fd
Files changed (4) hide show
  1. .gitignore +2 -0
  2. README.md +24 -7
  3. app.py +219 -0
  4. requirements.txt +1 -0
.gitignore ADDED
@@ -0,0 +1,2 @@
 
 
 
1
+ *.pyc
2
+ __pycache__/
README.md CHANGED
@@ -1,14 +1,31 @@
1
  ---
2
  title: Error Tester
3
- emoji: 🏆
4
- colorFrom: gray
5
- colorTo: red
6
  sdk: gradio
7
- sdk_version: 6.26.0
8
- python_version: '3.12'
9
  app_file: app.py
10
  pinned: false
11
- short_description: Error handling code branch testing
12
  ---
13
 
14
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  ---
2
  title: Error Tester
3
+ emoji: 🧪
4
+ colorFrom: red
5
+ colorTo: gray
6
  sdk: gradio
7
+ sdk_version: 5.28.0
 
8
  app_file: app.py
9
  pinned: false
10
+ license: mit
11
  ---
12
 
13
+ A PyHARP example Space for exercising HARP's error handling paths.
14
+
15
+ Use the dropdown controls to select the failure shape, then click Process.
16
+ The app intentionally raises runtime errors, quota-looking Gradio errors,
17
+ Space-status errors, or malformed output payloads so HARP can display the
18
+ corresponding user-facing error.
19
+
20
+ Primary mappings:
21
+
22
+ - `Gradio runtime error` raises `gr.Error`, which should surface as a
23
+ `GradioError::RuntimeError`.
24
+ - `Python runtime error` raises `RuntimeError`, which should surface as a
25
+ `GradioError::RuntimeError` when the Space is launched with `show_error=True`.
26
+ - `ZeroGPU quota error` raises a quota-looking `gr.Error`, which should surface
27
+ as `GradioError::QuotaExceeded`.
28
+ - `Space status error` raises a message matching Hugging Face Space failure
29
+ text, which HARP maps to an HTTP 503-style status failure.
30
+ - `Output payload error` returns invalid or unusable output data for checking
31
+ HARP's downstream output parsing and file-download handling.
app.py ADDED
@@ -0,0 +1,219 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Error Tester: a PyHARP app for exercising HARP's Gradio error handling.
3
+
4
+ The app performs no model inference. Its process endpoint deliberately raises
5
+ or returns selected failure shapes so HARP can be checked against the user-facing
6
+ messages in src/utils/Errors.h.
7
+ """
8
+
9
+ from pyharp import *
10
+
11
+ from typing import Optional, Tuple
12
+ import gradio as gr
13
+
14
+ import os
15
+ import tempfile
16
+ import time
17
+ import wave
18
+
19
+
20
+ model_card = ModelCard(
21
+ name="Error Tester",
22
+ description=(
23
+ "Raises controlled Gradio errors, runtime errors, quota messages, "
24
+ "Space-status messages, and malformed output payloads for testing "
25
+ "HARP's error handling."
26
+ ),
27
+ author="TEAMuP",
28
+ tags=["example", "test", "error handling", "v3"],
29
+ )
30
+
31
+
32
+ ERROR_FAMILIES = [
33
+ "Success",
34
+ "Gradio runtime error",
35
+ "Python runtime error",
36
+ "ZeroGPU quota error",
37
+ "Space status error",
38
+ "Output payload error",
39
+ ]
40
+
41
+ ERROR_VARIANTS = [
42
+ "Default message",
43
+ "Empty detail",
44
+ "Long detail",
45
+ "Custom detail",
46
+ ]
47
+
48
+ OUTPUT_PAYLOADS = [
49
+ "Valid empty labels",
50
+ "Malformed label JSON",
51
+ "Missing audio file",
52
+ "Unsupported audio extension",
53
+ ]
54
+
55
+ DEFAULT_DETAIL = (
56
+ "Synthetic failure from the PyHARP Error Tester. This is expected and is "
57
+ "intended to test HARP's error popup."
58
+ )
59
+
60
+
61
+ def write_silent_wav(duration_seconds: float = 0.25, sample_rate: int = 44100) -> str:
62
+ """Create a small WAV file using only the Python standard library."""
63
+
64
+ fd, path = tempfile.mkstemp(prefix="harp_error_tester_", suffix=".wav")
65
+ os.close(fd)
66
+
67
+ frame_count = int(duration_seconds * sample_rate)
68
+
69
+ with wave.open(path, "wb") as wav:
70
+ wav.setnchannels(1)
71
+ wav.setsampwidth(2)
72
+ wav.setframerate(sample_rate)
73
+ wav.writeframes(b"\x00\x00" * frame_count)
74
+
75
+ return path
76
+
77
+
78
+ def build_detail(variant: str, custom_detail: str) -> str:
79
+ if variant == "Empty detail":
80
+ return ""
81
+
82
+ if variant == "Long detail":
83
+ return (
84
+ DEFAULT_DETAIL
85
+ + " "
86
+ + "This deliberately long diagnostic text should be shortened in "
87
+ + "HARP's transient status area while remaining available in the "
88
+ + "final error dialog. "
89
+ + "x" * 260
90
+ )
91
+
92
+ if variant == "Custom detail" and custom_detail.strip():
93
+ return custom_detail.strip()
94
+
95
+ return DEFAULT_DETAIL
96
+
97
+
98
+ def build_labels(message: str) -> LabelList:
99
+ labels = LabelList()
100
+ labels.labels.append(
101
+ AudioLabel(
102
+ t=0.0,
103
+ label="success",
104
+ duration=0.25,
105
+ description=message,
106
+ color=OutputLabel.rgb_color_to_int(20, 120, 80),
107
+ amplitude=0.5,
108
+ )
109
+ )
110
+ return labels
111
+
112
+
113
+ def process_fn(
114
+ input_audio_path: Optional[str],
115
+ error_family: str,
116
+ error_variant: str,
117
+ output_payload: str,
118
+ delay_seconds: float,
119
+ custom_detail: str,
120
+ ) -> Tuple[str, LabelList]:
121
+ if delay_seconds > 0:
122
+ time.sleep(float(delay_seconds))
123
+
124
+ detail = build_detail(error_variant, custom_detail)
125
+
126
+ if error_family == "Gradio runtime error":
127
+ raise gr.Error(detail or "The Gradio server reported a runtime error.")
128
+
129
+ if error_family == "Python runtime error":
130
+ raise RuntimeError(detail or "Python RuntimeError without additional detail.")
131
+
132
+ if error_family == "ZeroGPU quota error":
133
+ quota_detail = detail or "GPU quota has been exceeded for this Space."
134
+ raise gr.Error(f"ZeroGPU quota exceeded: {quota_detail}")
135
+
136
+ if error_family == "Space status error":
137
+ status_detail = detail or "Check its status on HF."
138
+ raise gr.Error(f"Your Space is in error. {status_detail}")
139
+
140
+ if error_family == "Output payload error":
141
+ audio_path = write_silent_wav()
142
+
143
+ if output_payload == "Malformed label JSON":
144
+ return audio_path, {"labels": "this should be a list"}
145
+
146
+ if output_payload == "Missing audio file":
147
+ return "/tmp/harp_error_tester_missing_output.wav", LabelList()
148
+
149
+ if output_payload == "Unsupported audio extension":
150
+ fd, path = tempfile.mkstemp(prefix="harp_error_tester_", suffix=".txt")
151
+ with os.fdopen(fd, "w") as f:
152
+ f.write("This is not an audio file.\n")
153
+ return path, LabelList()
154
+
155
+ audio_path = input_audio_path or write_silent_wav()
156
+ labels = build_labels(f"Selected family: {error_family}. No error was raised.")
157
+
158
+ return audio_path, labels
159
+
160
+
161
+ with gr.Blocks() as demo:
162
+ input_components = [
163
+ gr.Audio(
164
+ type="filepath",
165
+ label="Optional Input Audio",
166
+ )
167
+ .harp_required(False)
168
+ .set_info("Passed through on success. A silent WAV is generated if empty."),
169
+ gr.Dropdown(
170
+ choices=ERROR_FAMILIES,
171
+ value="Gradio runtime error",
172
+ label="Error Family",
173
+ info="The broad error path to exercise."
174
+ ),
175
+ gr.Dropdown(
176
+ choices=ERROR_VARIANTS,
177
+ value="Default message",
178
+ label="Error Detail",
179
+ info="Controls the detail text carried by raised errors."
180
+ ),
181
+ gr.Dropdown(
182
+ choices=OUTPUT_PAYLOADS,
183
+ value="Valid empty labels",
184
+ label="Output Payload",
185
+ info="Used only when Error Family is Output payload error."
186
+ ),
187
+ gr.Slider(
188
+ minimum=0,
189
+ maximum=30,
190
+ step=1,
191
+ value=0,
192
+ label="Delay (s)",
193
+ info="Stalls before producing the selected response."
194
+ ),
195
+ gr.Textbox(
196
+ value="",
197
+ label="Custom Detail",
198
+ info="Used when Error Detail is Custom detail."
199
+ ),
200
+ ]
201
+
202
+ output_components = [
203
+ gr.Audio(
204
+ type="filepath",
205
+ label="Output Audio",
206
+ ).set_info("Silent or pass-through audio for successful responses."),
207
+ gr.JSON(
208
+ label="Output Labels",
209
+ ).set_info("Labels returned on successful responses."),
210
+ ]
211
+
212
+ app = build_endpoint(
213
+ model_card=model_card,
214
+ input_components=input_components,
215
+ output_components=output_components,
216
+ process_fn=process_fn,
217
+ )
218
+
219
+ demo.queue().launch(share=True, show_error=True, pwa=True)
requirements.txt ADDED
@@ -0,0 +1 @@
 
 
1
+ git+https://github.com/TEAMuP-dev/pyharp.git@94745a9a599f5a538b56a1487b7a465fc359ef31#egg=pyharp