ZhuLinsen/daily_stock_analysis · error · ValueError

图片内容为空

Error message

图片内容为空

What it means

Simple guard in extract_stock_codes_from_image: image_bytes is empty (falsy) after MIME validation passed. The function refuses to base64-encode and call the vision API on an empty payload.

Source

Thrown at src/services/image_stock_extractor.py:370

    优先级:Gemini -> Anthropic -> OpenAI(首个可用)。
    支持多 Key 轮询与重试(最多 3 次,指数退避)。

    Args:
        image_bytes: 原始图片字节
        mime_type: MIME 类型(如 image/jpeg, image/png)

    Returns:
        (items, raw_text) - items 为 [(code, name?, confidence), ...],raw_text 为原始 LLM 响应。

    Raises:
        ValueError: 图片无效、未配置 Vision API 或提取失败时。
    """
    mime_type = (mime_type or "image/jpeg").strip().lower().split(";")[0].strip()
    if mime_type not in ALLOWED_MIME:
        raise ValueError(f"不支持的图片类型: {mime_type}。允许: {list(ALLOWED_MIME)}")

    if not image_bytes:
        raise ValueError("图片内容为空")

    if len(image_bytes) > MAX_SIZE_BYTES:
        raise ValueError(f"Image too large (max {MAX_SIZE_BYTES // (1024 * 1024)}MB)")

    _verify_image_magic_bytes(image_bytes, mime_type)

    image_b64 = base64.b64encode(image_bytes).decode("ascii")
    model = _resolve_vision_model()
    keys = _get_api_keys_for_model(model, get_config())

    last_error: Optional[Exception] = None
    for attempt in range(3):
        try:
            key = random.choice(keys) if keys else None
            raw = _call_litellm_vision(image_b64, mime_type, api_key=key)
            logger.debug("[ImageExtractor] raw LLM response:\n%s", raw)
            items = _parse_items_from_text(raw)
            logger.info(

View on GitHub (pinned to 5159bd72e8)

Solutions

  1. Check the upload path: verify file.size > 0 before submitting
  2. Verify the read: seek(0) before .read() if reusing a file handle
  3. Add client-side validation rejecting empty files

Example fix

# before
with open(p,'rb') as f: data = f.read()  # f at EOF -> b''
items, raw = extract_stock_codes_from_image(data, 'image/png')
# after
with open(p,'rb') as f:
    f.seek(0)
    data = f.read()
assert data, 'empty file'
items, raw = extract_stock_codes_from_image(data, 'image/png')
Defensive patterns

Strategy: validation

Validate before calling

if not image_bytes:
    raise ValueError('上传文件为空,请重新选择文件')
# or: if uploaded.size == 0: reject

Type guard

def has_image_payload(b: bytes | None) -> bool:
    return isinstance(b, (bytes, bytearray)) and len(b) > 0

Prevention

When it happens

Trigger: Calling with b'' or None as image_bytes; upstream file read returning empty bytes (0-byte upload, truncated multipart part).

Common situations: Front-end sending an empty FormData entry; file handle read after position exhausted; race where upload file was deleted before read completed.

Related errors


AI-assisted analysis of ZhuLinsen/daily_stock_analysis@5159bd72e8 (2026-08-15). Data as JSON: /api/errors/480aab3cf8072255. Report an issue: GitHub.