"""A local image-question form. Run with python vision_app.py."""
import base64
from io import BytesIO
import os
from flask import Flask, request, render_template_string
from PIL import Image, ImageOps, UnidentifiedImageError
from werkzeug.exceptions import RequestEntityTooLarge
from common import request_json

app = Flask(__name__)
app.config['MAX_CONTENT_LENGTH'] = 5 * 1024 * 1024
HTML = '''<!doctype html><html lang="en"><meta charset="utf-8"><meta name="viewport" content="width=device-width"><title>Ask about an image</title>
<style>body{font:18px/1.6 system-ui;max-width:650px;margin:40px auto;padding:16px}label{display:block;margin-top:16px}input,button{font:inherit;max-width:100%}input[type=text]{width:100%}button{margin-top:20px}pre{white-space:pre-wrap}</style>
<h1>Ask about an image</h1><p>Choose a PNG or JPEG and ask a specific question.</p>
<form method="post" enctype="multipart/form-data"><label>Image<input type="file" name="image" accept="image/png,image/jpeg" required></label><label>Question<input type="text" name="question" value="{{ question }}" required maxlength="1000"></label><button>Ask the model</button></form>
{% if error %}<p role="alert">{{ error }}</p>{% endif %}{% if answer %}<h2>Answer</h2><pre>{{ answer }}</pre><p>Check this against the image. The model can misread text or infer details that are not visible.</p>{% endif %}</html>'''


def image_payload(file):
    with Image.open(file) as image:
        if image.format not in {'PNG', 'JPEG'}:
            raise ValueError('Choose a PNG or JPEG image.')
        if image.width * image.height > 20_000_000:
            raise ValueError('Choose an image smaller than 20 megapixels.')
        image = ImageOps.exif_transpose(image).convert('RGB')
        image.thumbnail((1280, 1280))
        buffer = BytesIO()
        image.save(buffer, format='JPEG', quality=90)
    return base64.b64encode(buffer.getvalue()).decode('ascii')


@app.route('/', methods=['GET', 'POST'])
def index():
    answer = error = ''
    question = 'What price is printed on the label?'
    if request.method == 'POST':
        question = request.form.get('question', '').strip()
        try:
            if not question or len(question) > 1000:
                raise ValueError('Write a question between 1 and 1000 characters.')
            upload = request.files.get('image')
            if upload is None:
                raise ValueError('Choose an image first.')
            encoded = image_payload(upload.stream)
            result = request_json('chat', {
                'model': os.getenv('BLOG_VISION_MODEL', 'qwen3-vl:2b'),
                'stream': False, 'think': False,
                'messages': [{'role': 'user', 'content': question + ' Use only visible information; say when you cannot tell.', 'images': [encoded]}],
                'options': {'temperature': 0, 'num_ctx': 4096, 'num_predict': 300},
            })
            answer = result['message']['content']
        except Image.DecompressionBombError:
            error = 'Choose an image smaller than 20 megapixels.'
        except (ValueError, UnidentifiedImageError, OSError, KeyError) as exc:
            error = str(exc)
    return render_template_string(HTML, answer=answer, error=error, question=question)


@app.errorhandler(RequestEntityTooLarge)
def upload_too_large(_):
    error = 'Choose an image smaller than 5 MB.'
    return render_template_string(HTML, answer='', error=error, question=''), 413


if __name__ == '__main__':
    app.run(host='127.0.0.1', port=5001, debug=False)
