class AiService MODELS = { dalle: "dall-e-3", flux: "black-forest-labs/FLUX.1-schnell" }.freeze def initialize @client = OpenAI::Client.new( access_token: Rails.application.credentials.openai.token, uri_base: Rails.application.credentials.openai.uri, log_errors: Rails.env.development?, # 只在开发环境下启用 request_timeout: 240 ) # 这里假设你已经在credentials中添加了siliconflow相关配置 @flux_token = Rails.application.credentials.siliconflow.token @flux_api_url = Rails.application.credentials.siliconflow.url end def generate_prompt(city, weather_data) # city_desc = generate_location_desc(city) city_desc = city.get_description('en') system_message = "You are a professional artist creating prompts for image generation. Create realistic, artistic weather scenes featuring iconic landmarks." user_message = generate_image_prompt_request(city, weather_data, city_desc) ask_ai(system_message, user_message) end # def generate_location_desc(city) # region = city.country.region&.name || "" # country = city.country.name || "" # state = city.state&.name || "" # system_message = # "You are a global geography master, you understand the culture, geography, architecture, customs and other information of all cities around the world. Describe this city based on the city I gave you. Include details about its culture, climate, landmarks, and any unique features that make this place special. Condense the keyword into a description of about 50 words" # user_message = # "Describe the characteristics of the city of #{city.name}, located in the #{state}, #{country}, #{region}" # ask_ai(system_message, user_message) # end def generate_image(prompt, model_type = :flux) case model_type when :flux generate_image_flux(prompt) when :dalle generate_image_dalle(prompt) else generate_image_flux(prompt) # 默认使用FLUX end end def generate_image_dalle(prompt) response = @client.images.generate( parameters: { model: MODELS[:dalle], prompt: prompt, size: "1792x1024", quality: "hd", n: 1 } ) response.dig("data", 0, "url") end def generate_image_flux(prompt) uri = URI(@flux_api_url) http = Net::HTTP.new(uri.host, uri.port) http.use_ssl = true request = Net::HTTP::Post.new(uri) request["Authorization"] = "Bearer #{@flux_token}" request["Content-Type"] = "application/json" # 生成随机种子 seed = rand(10000000000) request.body = { model: MODELS[:flux], prompt: prompt, # image_size: "1024x576", image_size: "1792x1024", seed: seed, prompt_enhancement: false }.to_json response = http.request(request) if response.is_a?(Net::HTTPSuccess) result = JSON.parse(response.body) result.dig("data", 0, "url") else Rails.logger.error("FLUX API error: #{response.code} - #{response.body}") # 异常时回退到DALL-E # generate_image_dalle(prompt) end rescue => e Rails.logger.error("Error generating image with FLUX: #{e.message}") # 异常时回退到DALL-E # generate_image_dalle(prompt) end def ask_ai(system_message, user_message) response = @client.chat( parameters: { model: "gpt-4o-mini", messages: [ { role: "system", content: system_message }, { role: "user", content: user_message } ], temperature: 0.7, max_tokens: 300 } ) response.dig("choices", 0, "message", "content") end private def generate_image_prompt_request(city, weather_data, city_desc) region = city.country.region&.name || "" country = city.country.name || "" state = city.state&.name || "" <<~PROMPT Generate a highly detailed and photorealistic image prompt capturing a specific weather moment in #{city.name}, #{state}, #{country}, #{region}. **Scene Inspiration:** #{city_desc} (Use this description to inform the specific elements and mood of the scene). **Weather Conditions to Depict:** - Temperature Feel: Convey the atmosphere associated with #{weather_data[:temperature]}°C. - Visible Weather: #{weather_data[:description]}. Show its effects on the environment (e.g., rain slicking streets, sun casting sharp shadows, fog softening distant objects). - Sky & Light: Sky is #{weather_data[:cloud]}% cloud covered. Render the lighting accurately for the time: #{weather_data[:time]} (e.g., warm morning light, bright midday sun, soft afternoon light, dramatic sunset colors, twilight ambiance, or night scene lighting like streetlights). **Mandatory Requirements for Realism and Aesthetics:** - **Style:** Photorealistic photograph, hyperrealistic, cinematic quality. Capture fine details, textures (e.g., wet pavement, brickwork, foliage), and accurate lighting. - **Composition:** Atmospheric and artistic composition (e.g., rule of thirds, leading lines), creating depth and visual interest. Consider a natural eye-level perspective or a slightly elevated viewpoint for landscape/cityscape. - **Landmarks/Architecture:** Feature iconic landmarks or characteristic architecture from #{city.name} as naturally integrated elements within the scene. - **Clarity & Brightness:** Ensure the image is sharp, clear, and well-exposed. Avoid excessive blur or motion artifacts unless intentionally used for artistic effect (like long exposure for rain). - **Lighting Enhancement:** - Even in overcast conditions (high #{weather_data[:cloud]}), maintain visual appeal with soft, diffused light, ensuring details in shadows are visible and colors remain natural yet engaging. - On sunny days (low #{weather_data[:cloud]}%), emphasize the brightness, warmth, contrast, and potentially lens flare for added realism. - **Avoid:** Do NOT produce illustrations, paintings, sketches, anime, cartoons, or overly stylized digital art. The final image must look like a real photograph. **Output Format:** Directly output the complete, detailed image generation prompt string only. No introductory text, labels, or explanations. PROMPT end end