feat: add support for multiple image generation models
- Introduced constant MODELS for managing model names. - Updated the `generate_image` method to switch between FLUX and DALL-E 3. - Added `generate_image_dalle` and `generate_image_flux` methods for respective API calls. - Enhanced prompts for image generation across both models, ensuring correct message construction. This update enables users to generate images using different AI models dynamically, allowing for flexible integration and improved user experience. The handling of errors now falls back to the DALL-E model if the FLUX API fails.
This commit is contained in:
parent
719a523cc9
commit
ab50ed3036
@ -1,4 +1,9 @@
|
|||||||
class AiService
|
class AiService
|
||||||
|
MODELS = {
|
||||||
|
dalle: "dall-e-3",
|
||||||
|
flux: "black-forest-labs/FLUX.1-schnell"
|
||||||
|
}.freeze
|
||||||
|
|
||||||
def initialize
|
def initialize
|
||||||
@client = OpenAI::Client.new(
|
@client = OpenAI::Client.new(
|
||||||
access_token: Rails.application.credentials.openai.token,
|
access_token: Rails.application.credentials.openai.token,
|
||||||
@ -6,14 +11,18 @@ class AiService
|
|||||||
log_errors: Rails.env.development?, # 只在开发环境下启用
|
log_errors: Rails.env.development?, # 只在开发环境下启用
|
||||||
request_timeout: 240
|
request_timeout: 240
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# 这里假设你已经在credentials中添加了siliconflow相关配置
|
||||||
|
@flux_token = Rails.application.credentials.siliconflow.token
|
||||||
|
@flux_api_url = Rails.application.credentials.siliconflow.url
|
||||||
end
|
end
|
||||||
|
|
||||||
def generate_prompt(city, weather_data)
|
def generate_prompt(city, weather_data)
|
||||||
city_desc = generate_location_desc(city)
|
city_desc = generate_location_desc(city)
|
||||||
|
|
||||||
system_message =
|
system_message =
|
||||||
"You are a professional artist creating prompts for DALL-E 3. Create realistic, artistic weather scenes featuring iconic landmarks."
|
"You are a professional artist creating prompts for image generation. Create realistic, artistic weather scenes featuring iconic landmarks."
|
||||||
user_message = generate_dall_e_3_prompt_request(city, weather_data, city_desc)
|
user_message = generate_image_prompt_request(city, weather_data, city_desc)
|
||||||
ask_ai(system_message, user_message)
|
ask_ai(system_message, user_message)
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -29,13 +38,23 @@ class AiService
|
|||||||
ask_ai(system_message, user_message)
|
ask_ai(system_message, user_message)
|
||||||
end
|
end
|
||||||
|
|
||||||
def generate_image(prompt)
|
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(
|
response = @client.images.generate(
|
||||||
parameters: {
|
parameters: {
|
||||||
model: "dall-e-3",
|
model: MODELS[:dalle],
|
||||||
prompt: prompt,
|
prompt: prompt,
|
||||||
size: "1792x1024",
|
size: "1792x1024",
|
||||||
# quality: "standard",
|
|
||||||
quality: "hd",
|
quality: "hd",
|
||||||
n: 1
|
n: 1
|
||||||
}
|
}
|
||||||
@ -44,6 +63,43 @@ class AiService
|
|||||||
response.dig("data", 0, "url")
|
response.dig("data", 0, "url")
|
||||||
end
|
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
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def ask_ai(system_message, user_message)
|
def ask_ai(system_message, user_message)
|
||||||
@ -65,13 +121,13 @@ class AiService
|
|||||||
response.dig("choices", 0, "message", "content")
|
response.dig("choices", 0, "message", "content")
|
||||||
end
|
end
|
||||||
|
|
||||||
def generate_dall_e_3_prompt_request(city, weather_data, city_desc)
|
def generate_image_prompt_request(city, weather_data, city_desc)
|
||||||
region = city.country.region&.name || ""
|
region = city.country.region&.name || ""
|
||||||
country = city.country.name || ""
|
country = city.country.name || ""
|
||||||
state = city.state&.name || ""
|
state = city.state&.name || ""
|
||||||
|
|
||||||
<<~PROMPT
|
<<~PROMPT
|
||||||
Generate a highly detailed and photorealistic DALL-E 3 prompt capturing a specific weather moment in #{city.name}, #{state}, #{country}, #{region}.
|
Generate a highly detailed and photorealistic image prompt capturing a specific weather moment in #{city.name}, #{state}, #{country}, #{region}.
|
||||||
|
|
||||||
**Scene Inspiration:**
|
**Scene Inspiration:**
|
||||||
#{city_desc}
|
#{city_desc}
|
||||||
@ -92,7 +148,7 @@ class AiService
|
|||||||
- On sunny days (low #{weather_data[:cloud]}%), emphasize the brightness, warmth, contrast, and potentially lens flare for added realism.
|
- 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.
|
- **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 DALL-E prompt string only. No introductory text, labels, or explanations.
|
**Output Format:** Directly output the complete, detailed image generation prompt string only. No introductory text, labels, or explanations.
|
||||||
PROMPT
|
PROMPT
|
||||||
end
|
end
|
||||||
end
|
end
|
@ -1 +1 @@
|
|||||||
GXPLZ7WnqRPuVOb5CjAWuW8so7pSi33VRciByZhhz4ZuY2trbHG+qmx/3pfifdmoKDLr9ixVpbfHmQ3QhwOKs3FrtjZsY/bjk4W27pHX74M0mFIuv/KpdQLpiKEYEjdYeZl5RfTLaLfFYAfa1lPo6kQfpLX5vHsPmy+SSVXbrTfHWGHiEnnj3QD6hvWFEfYQ3VjIs5Dc8eP1Oc8xcif78RqBkp6B83e5HYeFwVAv8bAHXFksPXWEXmdCL9xBLvt3zPSDNMtDeAyJIXB7s71zNaeF/i7UF3exA7sJz2XMztowKocELwd34FUpSuWqkdOcHOcPZfizAmLW18Hu23IgI5xVkJs+1IOoaVcmiAU/TwvAdj9tSnpDGmjx6i5fINeiM/aQyu0PQnqQxscezWcP+NF0jsVHRgsSIjvelRk4FuUGPhCV5Lm9OzlBfz9HakKEq6F5MdxTPH6YUduTM/9Xbk64VAO8HIt9irOB2aVLz89bwhGvlI9OVsUWnevfkfbiAFz89RyMEbvqcx0GOxJnFMsms0MBwNyr1AgyZQBQ/kKDYQVtstQ7jGQYqpN0pToqUnrktJ0HHXgZ280F0WFzaqx2of/8QnmMhVsOQI7ZIGdAESpriNz9rk90xfzIFmGO8OnikMoqH7tM7Ghd9mZvQqODRD26t/88WuDqxAkQyQObv93Fuy6YwB2IQZLDrsw/MA6UCp60HLkm28ShMap7bl6DRY38Ie+Z+RELm/LHlTLzL07tIAb9FeWbcrSeYzYYDTGyZDsRcXW9nBmtpHeNBOBHE9bUmiYuE28Z+hLPd7SOAtDQcToO3DRojUwVQzekx8ENeGLskFZ9NUMCtrqZgIyzuC+GsBrMYV4k4/P7mEVuT1V8y4V/5LDQqloyY5DfoNWCvZZytZ1dzzt7yCbzxsC/9O+WiW1Byk4gOogkAjQyNz/5NCVLRcdNC4/xLeBPPzVZpGchlWIkIe3aIHTnvmoglK8MSttKTw2aLZAcnHz9I0H/TGdSEKDCs427iDIkYp1f3YROnFPZ04HYNsMXdcjkpjQn6w7kcYl5GJVUj4uKPbTxMwhmM00vBRFlTLqt/Skip5GHWBYtPgAaZc4a1UkgvOWX6Z9dXdwY3Iuo3pf/zNYNuzJXHfGSEfwfkAzMkLn9NZ7Lmlk2/Ez2AodXIcA+sKwnEztxfhmgi3MhDfKtG0upf+9wYnDGW1G+AiJpHuyJNqnz/PeVzOZJcSPVvbt7Ps67zmgTtyry1UweQzeEw9nT8cxH6J3gl7FIezYQV8hAC7xWubFOyZtoDvZXddpSLcw79UblHE8jrQ5gOP3oeqZXJturgqSwJM/K1gerAWmSN14eR4CO14e7skmWtyXHCsNOiRxtLvifcaqmix6uAkd+1XWl0avKwTiIZuFlzmR4sOwXm6fgFjodT+Bss7abaH8Wka5iBBalJiGclFoJeed75pxnXDPr1GezRF8zYBLDMAqV/7HMxzWbd6Qqx1eQEhAgDC+ACA6HCVEP9cWg8U03ZTEpqfN8oCsppp00kkHPJiDwzmoRyqzl+L6ZY0cFgUeB38E/kQnnTOJ8lhsxtDsyuyJugPqiDkqqfbGSMp/eXlJfKdNFftpJ+6i1q2Mm2vNZhgpzdSVPU+GIMaNyO4/yu91yEWspUKT5YcBPDw2FzyLJ6Vk6LHtbzJRjNDHBqiq79sj1d5ciazhMAvFzd5msjEBxsMrFRA0B8LmtVvgUEz5D4jjlmCQEThfhvXTScvvz/kIJwygOaQOt5PbDZuamHY/bk/jPwxNoc8DhEGsvwvt4YlNFnWSWAcKFM64rR21vjSFH7gIdvRpi9GxVrMNRlh9YSGQ2u7x81VabwoL4ZgbQ2gKtFrHE2gJWbD/zJIM0XGQq2faqBqccEzc9H7EduAvLstdcL6aj8o5HU+FoI9aY8ArTfB9XuenYbn+TVC3t0i7tBWlOxaBnj0rELmnlAls2yLWZKvAzTUu4pWqnUMhvuXmhPGsXcLJgoGXOa3sbBpk6eYEkLH/H5VopYg2DYXrmmo/arKrTRao3QN+3tZeGu4aLKWKa7NEjeJly2qMa2+Bwwy6EbkNBeXvvjEILqqqbhLK9hiGW7Md0sojganEBU89Qd9UhAT/l1038JhIsUNf59BEXg4Ac3IPweyrvUEgBwf+68oIp+Yz8unMlkniOsu+ttg4AjhUBxrog6csE0Bng0mjh8LSGvFAY598dmKmgY2rpza0rNihsv3NUr0buzijGP/GpQ0H13ikkOS/Q4WiT5LaLjx1E4LTy/NPMnR159AXFDQleHWWdNByMEhE6+ywo9dSa3MipYI9ZZ0TwI31UgU5+5njPTUKbG5zrqWEobc78mbxylK3qGdd+Qcy/j+H5SMH5HaAzfbW1fNJiSV1lWERMq2QtwjIrPyP5dbp2zzNFKgwMFRz+clE7/UNXldisnMXbZO452r/IpeklfR409stq0PugJPiewo3Ks2vWymJS1Yfn1XlqICnN2qIWX26ywNzPWPCblLzQDCusWUCX2NIQ2BuNJ9zbCyuPqvlVUN7FBs0lch+A4FPFlzy0UczI5IcehgsMAQh3NBN42OtB+cJjCaWT3kyobJU6G6+E9sMOTjx/SN2MDfVrzMtgutSDTtyElqiNZ1pHyhF8znGez7LTMLi3aQJwLdqeF7OWkS7m/axAHOpt5o9t7HU7XyAgmCTxeF9Gj7nEGyKFzf8lePttmuj6KOI/7yL6slyloU2EJeXrF8R9I+ReYlIi3mSUgqqOLWWFVJuH8r5eH5R7EEiNztdjSsQU5CTH//8xapAKRX1FHXsIyrZA+yZALcuqT3fZQhlnAVfBCH8v71oESEKlFaLjC8yoh6ZKO/OdwnXUcey6NPXtMIg9kHZ3bdMdE5lJvtskJfVOI/veNl54L/EGfppsxkdQlaUXQ2aL4vA4eu0ev074MaLSR1IefsyT5apN8vZp/BXWP/tpFIM/a4l3bNqJJt0dGOjtMws37UGOyCxC2NbgY47EdnROcpTC0TZwik7yO7YfjL1WOpJsQmXHfyiBVbaaaQH/xB6pvwq2mqJMIfNDMqKRnRmDnd5o4NIHUaHREaKf5PMrgiXvH2UGL0kMhRGLYpRIMR4Qk04fFMEgzE6p6Dbcp8G4sarEPkb58ZCIhxvDaCYxHIy63ufwETzFKGxHwM4orsVU5B99mk5jTwcmju/J4qC/+rwkQdsfD+0RcBXN8uop/OqWGvJrEHgJ0OrQUlMvLG3rnIwfLFUt1x9b+ZzdOVXDNB/tuORrwrZfD8cWLlRgI0dLDZXT83hDilPsGDCF9s5VAXdO1Sbg6V7UPXGeKNRsqodwvsW2+Sv8ugqpj9d+Ckstr6kMxLvIDCwP505Gp0tKhj3o4T09AGjTKiZJU377HRfnTF1AfZ7fFasR2fKWKY2p7ZAPTrycKVNLeIb0p0qMX5KHQR689uG/T2Q6+U7B/vmS0AoYyNyCEA9IHYKEao9lnUXtBpn+KzYaa8YbDjX9/Hqhikvc6fLtzxbCNvaARQ9z9n7P3kcFAsT9bwXKcquPAb5P5PvAK9MbJ/qNjMQKkVafWOn9wgwz+pvGQ2MOZVZfLUeubJwLaGzZRtcMTBRMylhK2Zub9dhQ/gJS2MvS3eB2/QbaSCHA1NarTDzbsmMX+qu0Ni/B2jzk60poWiRQo+h+E3kkx3viTvMWuqSjrySug9T3ReZNZov5H8OMXwhPX69qalCUyjPw8Zm1jnxWI1YtDroJh40ZmI9nYXNZugqf7iJXiLQV2WBzBplhuNLGQqAgUaFbIFVVFnbBG3fVnlqYzXn04UWUI6LdhZMHGT1swkNyN7r3CHXpzrH67m09SyJxuGUjoQkJhwYwPR9ATr6pHwq0Hr3r77wTPlDd4m5YgNeB/zbrFkh+U1Qf6nF3/h5PsK8pgzdxE2+lT6po2d1GBIICjT8fKYCn3tkTgBxuqX8Nm1WJ9VBV6/NatVORXktlIKLgHR7tTgT9Yg6O5S/RaJIOJnMkaapKWtLgEeDsZPCAyF5U8wCdH8v6GcDy47MXk9f8Pgf5w83lD24T/2GCVFZKk0jJMTaYyg8/N7fMrhkV37n5vci5JLYSPuFSoG1iHgt4dDxMSFX2gi4Ly5oM14ZaT5qeq0cwO+mNeHci44c/5phX3FDbAqrh8QquKpvym10W+HnC58Kwlg4FXl6+NHe4UuJ4sGh5SYDeRoxVfSyrGubRAc7YLLGf6RXM28ZCfCvB6bZeOrd5NaQYEeQcMZhPslgVu8OhkqbkfQw66l9WwzuC/4huCeWv5+xuTN+DPULSOxzkuHT9fdt67654zX4MQ7qoBvd2ZDLMB70B2lHnFMuMIc/sKXnO8jmv4rjvyWJQ4FiL9pE/cdqvmeJvYWdf58g1JfCswyO8d/UH4bV7UXaUqN98suxPTVrhghoJY3tuEabDO+N+Ytqn2gBHahVBZR7y3TRZIHDVaSMLpsYGNYsG0sXLza/4YP9mYTog1o4ycvHYqYLHSTWnZQBypbMm8+vChoIqJFGc0szpoQJzy0aB4TMCBDZ/XtG6e4mKL390uEvcoPwjUDN7--NoWqPB3RsXQtcokp--t2ygZml0sjj/3J3lrKsguQ==
|
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--d7o8roTgR6J0L8GM--7Im0i3w2N7jwl89+qBJApg==
|
Loading…
Reference in New Issue
Block a user