from flask import Flask, render_template, request, jsonify from gradio_client import Client, handle_file import os import json import random # For demo data variation app = Flask(__name__) app.config['UPLOAD_FOLDER'] = 'uploads' app.config['MAX_CONTENT_LENGTH'] = 16 * 1024 * 1024 # 16 MB max upload size os.makedirs(app.config['UPLOAD_FOLDER'], exist_ok=True) API_TOKEN_HF = os.environ['API_TOKEN_HF'] # --- Demo Data --- # This will be used for initial page load and if the API call fails or is mocked BASE_AROMA_NAMES_ORDER = [ # Keep this order consistent with frontend "Rose", "Ocean Breeze", "Fresh Cut Grass", "Lemon Zest", "Lavender", "Sweet Orange", "Cool Mint", "Vanilla Bean", "Wild Berry", "Spring Rain" ] client = Client("doevent/gemini_others", hf_token=API_TOKEN_HF, download_files="uploads") def get_demo_perfume_data(): perfume_name = random.choice(["Demo Garden", "Demo Whisper", "Demo Flare", "Demo Dream"]) slogan = random.choice([ "Awaken your senses.", "Dare to dream.", "The essence of you.", "An unforgettable journey." ]) # Create a random set of aromas and doses num_active_aromas = random.randint(2, 10) active_aromas_sample = random.sample(BASE_AROMA_NAMES_ORDER, num_active_aromas) aromas_data = [] total_dose_for_demo = 0 # To simulate filling the flask for i, name in enumerate(BASE_AROMA_NAMES_ORDER): if name in active_aromas_sample and total_dose_for_demo < 0.8: # Limit total demo dose dose = round(random.uniform(0.1, 0.3), 2) aromas_data.append({"name": name, "dose": dose}) total_dose_for_demo += dose # else: # We can include all aromas with 0 dose if needed by frontend for table population # aromas_data.append({"name": name, "dose": 0.0}) return { "perfume_name": perfume_name, "slogan": slogan, "aromas": aromas_data # This list might only contain active aromas } @app.route('/') def index(): initial_data = get_demo_perfume_data() return render_template('index.html', initial_data=initial_data, base_aromas_ordered=BASE_AROMA_NAMES_ORDER) @app.route('/analyze_image', methods=['POST']) def analyze_image_route(): if 'imageFile' not in request.files: return jsonify({"error": "No image file provided"}), 400 file = request.files['imageFile'] if file.filename == '': return jsonify({"error": "No image selected"}), 400 if file: try: filename = "uploaded_image_" + file.filename # Add some uniqueness if needed image_path = os.path.join(app.config['UPLOAD_FOLDER'], filename) file.save(image_path) custom_prompt_for_perfume = ( "Based on the visual elements, mood, and potential theme of this image, " "invent a unique perfume. I need the following information structured as a JSON object:\n" "1. 'perfume_name': A creative and fitting name for the perfume.\n" "2. 'slogan': A short, catchy slogan for this perfume.\n" "3. 'aromas': A list of 2 to 10 base aroma notes. For each note, provide its 'name' " f"(chosen from this list: {', '.join(BASE_AROMA_NAMES_ORDER)}, or a very similar common scent if appropriate) " "and its 'dose' as a decimal proportion (e.g., 0.3 for 30%). " "Ideally, the total dose should be equal to a full bottle of 10.0 for 100%" "\nExample of 'aromas' list: [{'name': 'Rose', 'dose': 0.4}, {'name': 'Lavender', 'dose': 0.2}]" ) api_result_raw = client.predict( files_list=[handle_file(image_path)], message=custom_prompt_for_perfume, model_name="gemini-2.0-flash", temperature=0.7, max_output_tokens=1024, system_prompt_load= "", type_mime_name="application/json", output_schema=None, google_search_opt=False, other_options_json=None, thinking_mode=False, thinking_budget=None, api_name="/predict" ) os.remove(image_path) # Clean up uploaded file # print("Raw API Result:", api_result_raw) api_result_raw = api_result_raw[0]["candidates"][0]["content"]["parts"][0]['text'] print("Raw API Result:", api_result_raw) return api_result_raw except Exception as e: print(f"Error during API call or processing: {e}") # In case of any error, return demo data for now for frontend testing # os.remove(image_path) # Ensure cleanup even on error error_data = get_demo_perfume_data() error_data["api_error"] = f"An error occurred: {str(e)}. Displaying demo data." return jsonify(error_data), 500 # Send 500 to indicate server-side error return jsonify({"error": "Invalid file"}), 400 if __name__ == '__main__': app.run(host="0.0.0.0", port=7860, debug=True) # Use a different port if 5000 is common