Success in calling for me. Bypass OpenAI-provided library code, but in this case, AI code bloat (and then ChatGPT->5.1 told what not to do) since Iām away from a bunch of my own code examples.
import os
import asyncio
import json
import unicodedata
import httpx
def _sanitize_text(value: str | bytes) -> str:
"""
Coerce input to a clean Unicode string safe for JSON and UTF-8 transmission.
- Accepts str or bytes (even though the public signature uses str).
- If bytes: try UTF-8, then cp1252 with replacement on failure.
- Normalizes to NFC.
- Removes control characters except for whitespace controls (\n, \r, \t).
- Round-trips through UTF-8 with replacement to ensure valid code points only.
"""
# Coerce bytes ā str
if isinstance(value, bytes):
try:
text = value.decode("utf-8")
except UnicodeDecodeError:
# Fallback for legacy 8-bit code pages like cp1252
text = value.decode("cp1252", errors="replace")
else:
text = value
if not isinstance(text, str):
text = str(text)
# Unicode normalization
text = unicodedata.normalize("NFC", text)
# Remove control characters except \n, \r, \t
def _keep_char(ch: str) -> bool:
if ch in ("\n", "\r", "\t"):
return True
cat = unicodedata.category(ch)
# Categories starting with "C" are control, format, surrogate, private-use, unassigned
return not cat.startswith("C")
text = "".join(ch for ch in text if _keep_char(ch))
# Force UTF-8 validity; replace any remaining invalid sequences
text = text.encode("utf-8", errors="replace").decode("utf-8")
return text
async def get_product_name(description: str) -> str:
# First, sanitize the raw description (even if it happens to be bytes at runtime).
sanitized_description = _sanitize_text(description)
# Original prompt template, but interpolating the sanitized description.
prompt = (
f"Create a product name given the description. *Important:* your response must be one to three words long."
f" <BEGIN DESCRIPTION>\n{sanitized_description}\n<END DESCRIPTION>\n\n"
f"**Your response must be a one to three words long description of the product above.**"
)
# Run a second sanitizer pass over the full prompt to guard against any
# unintended characters introduced around the description.
prompt = _sanitize_text(prompt)
api_key = os.environ["OPENAI_API_KEY"] # guaranteed to exist per your setup
headers = {
"Authorization": f"Bearer {api_key}",
"Content-Type": "application/json",
}
payload = {
"model": "gpt-4.1-nano",
"input": prompt,
"max_output_tokens": 2025,
}
async with httpx.AsyncClient(timeout=30.0) as client:
try:
response = await client.post(
"https://api.openai.com/v1/responses",
headers=headers,
json=payload,
)
response.raise_for_status()
except httpx.HTTPStatusError as exc:
# Print raw body for debugging any 4xx/5xx issues
print("OpenAI API error body:")
try:
print(exc.response.text)
except Exception:
print("<unable to read error body>")
raise
data = response.json()
# Parse the Responses API "output" array:
# Keep only elements of type "message" or "refusal".
# From each, collect "output_text" entries from "content".
output = data.get("output") or []
collected: list[str] = []
for item in output:
item_type = item.get("type")
if item_type not in {"message", "refusal"}:
continue
contents = item.get("content") or []
for block in contents:
if block.get("type") == "output_text":
text = block.get("text") or ""
if text:
collected.append(text)
result = "".join(collected).strip()
if not result:
# Defensive fallback: show some context for debugging
raise RuntimeError(
f"No output_text segments found in response: {json.dumps(data, ensure_ascii=False)[:2000]}"
)
return result
if __name__ == "__main__":
async def _demo() -> None:
doc = "A compact, wireless, noise-cancelling pair of travel headphones."
name = await get_product_name(doc)
print("Suggested product name:", name)
asyncio.run(_demo())
Output by the demo string passed:
Suggested product name: TravelSilence
or
Suggested product name: TravelSphere
My first thought was that the API would be adding a bad field to the shape, that you never see echoed because of status 500. Or that there was glitchy input āthereā but unseen. But the two parameters and prompt input run fine when casting to UTF-8 is ensured and OpenAIās SDK library code-of-the-day is not used.