# LLM service using OpenAI Responses API (gpt-5)
#
# https://platform.openai.com/docs/guides/text-generation
# https://developers.openai.com/cookbook/examples/gpt-5/gpt-5_prompting_guide
# https://developers.openai.com/cookbook/examples/gpt-5/gpt-5_new_params_and_tools
#
# Endpoints: GET /run?task=..., POST /run
#
# Supported request parameters:
#   task                 - required, the user prompt / instruction
#   max_tokens           - max output tokens (also accepted as max_output_tokens
#                          or max_new_tokens), default: 500
#   reasoning_effort     - reasoning depth: "minimal" | "medium", default: "medium"
#   verbosity            - answer length: "low" | "medium" | "high", optional
#   previous_response_id - optional, reuse prior reasoning context (stateful)
#
# Not supported by gpt-5 Responses API (removed):
#   temperature, top_p, n, num_beams, early_stopping, max_time, min_tokens
#
# Configuration via environment variables:
#   OPENAI_API_KEY           - required, your OpenAI API key
#   OPENAI_MODEL             - optional, default: gpt-5
#   OPENAI_BASE_URL          - optional, default: https://api.openai.com/v1
#   OPENAI_SYSTEM_PROMPT     - optional, overrides the default system prompt
#   OPENAI_REASONING_EFFORT  - optional, default: medium
#   OPENAI_VERBOSITY         - optional, default: not set
#
import os
import json
import logging

from openai import OpenAI
from flask import Flask, abort, jsonify, request

logging.basicConfig(
    format="%(asctime)s - %(levelname)s - %(name)s -   %(message)s", datefmt="%m/%d/%Y %H:%M:%S", level=logging.INFO,
)
logger = logging.getLogger(__name__)

OPENAI_API_KEY          = os.environ.get("OPENAI_API_KEY", "")
OPENAI_MODEL            = os.environ.get("OPENAI_MODEL", "gpt-5")
OPENAI_BASE_URL         = os.environ.get("OPENAI_BASE_URL", "https://api.openai.com/v1")
OPENAI_REASONING_EFFORT = os.environ.get("OPENAI_REASONING_EFFORT", "medium")
OPENAI_VERBOSITY        = os.environ.get("OPENAI_VERBOSITY", "")

DEFAULT_SYSTEM_PROMPT = (
    "You are a precise search assistant. "
    "Follow the instruction exactly. "
    "Return only the requested output — no explanations, no extra text, no markdown."
)
OPENAI_SYSTEM_PROMPT = os.environ.get("OPENAI_SYSTEM_PROMPT", DEFAULT_SYSTEM_PROMPT)

if not OPENAI_API_KEY:
    logger.warning("OPENAI_API_KEY is not set — all requests will fail!")

client = OpenAI(api_key=OPENAI_API_KEY, base_url=OPENAI_BASE_URL)

logger.info("OpenAI LLM service started")
logger.info("Model            : " + OPENAI_MODEL)
logger.info("Base URL         : " + OPENAI_BASE_URL)
logger.info("Reasoning effort : " + OPENAI_REASONING_EFFORT)


def run(data):
    if not data.get('task'):
        abort(500)

    task = data['task']

    # Accept all common max-tokens field names
    if 'max_output_tokens' in data:
        max_output_tokens = int(data['max_output_tokens'])
    elif 'max_tokens' in data:
        max_output_tokens = int(data['max_tokens'])
    elif 'max_new_tokens' in data:
        max_output_tokens = int(data['max_new_tokens'])
    else:
        max_output_tokens = 500

    reasoning_effort = data.get('reasoning_effort', OPENAI_REASONING_EFFORT)
    verbosity        = data.get('verbosity', OPENAI_VERBOSITY) or None

    text_params = {'max_output_tokens': max_output_tokens}
    if verbosity:
        text_params['verbosity'] = verbosity

    params = {
        'model':     OPENAI_MODEL,
        'input':     [
            {"role": "system", "content": OPENAI_SYSTEM_PROMPT},
            {"role": "user",   "content": task},
        ],
        'reasoning': {'effort': reasoning_effort},
#        'text':      text_params,
    }

    if 'previous_response_id' in data:
        params['previous_response_id'] = data['previous_response_id']

    response = client.responses.create(**params)

    result = response.output_text.strip()
    logger.info(f"Generated: {result!r}")
    return result


#====================================
#http://localhost:8087/run?task=Who+are+you%3F

app = Flask(__name__)

@app.route("/run", methods=['GET'])
def run_get():
    task = request.args.get('task', '')
    if not task:
        abort(500)
    logger.info('Task: ' + task)
    result = run({"task": task})
    return jsonify({'result': result})

@app.route("/run", methods=['POST'])
def run_post():
    data = json.loads(request.data)
    result = run(data)
    return jsonify({'result': result})

if __name__ == '__main__':
    app.run(host="0.0.0.0")
#    app.run(host="0.0.0.0", port=80, debug=False)
