Update gemini.py
Browse files
gemini.py
CHANGED
|
@@ -1890,202 +1890,6 @@ def build_openai_response_content(chat_response: ChatResponse, host_url: str) ->
|
|
| 1890 |
return result_text
|
| 1891 |
|
| 1892 |
|
| 1893 |
-
@app.route('/v1/images/generations', methods=['POST'])
|
| 1894 |
-
@require_api_auth
|
| 1895 |
-
def create_image():
|
| 1896 |
-
"""OpenAI 兼容的图片生成接口"""
|
| 1897 |
-
try:
|
| 1898 |
-
# 每次请求时清理过期图片
|
| 1899 |
-
cleanup_expired_images()
|
| 1900 |
-
|
| 1901 |
-
data = request.json or {}
|
| 1902 |
-
prompt = data.get('prompt', '')
|
| 1903 |
-
if not prompt:
|
| 1904 |
-
return jsonify({"error": {"message": "prompt is required", "type": "invalid_request_error"}}), 400
|
| 1905 |
-
|
| 1906 |
-
# OpenAI 兼容参数
|
| 1907 |
-
n = data.get('n', 1) # 生成图片数量,默认1
|
| 1908 |
-
size = data.get('size', '1024x1024') # 图片尺寸(提示用,实际由Gemini决定)
|
| 1909 |
-
quality = data.get('quality', 'standard') # 质量(提示用)
|
| 1910 |
-
response_format = data.get('response_format', 'url') # 响应格式:url 或 b64_json
|
| 1911 |
-
model = data.get('model', 'dall-e-3') # 模型名称(提示用)
|
| 1912 |
-
|
| 1913 |
-
# 限制生成数量
|
| 1914 |
-
if n < 1 or n > 10:
|
| 1915 |
-
return jsonify({"error": {"message": "n must be between 1 and 10", "type": "invalid_request_error"}}), 400
|
| 1916 |
-
|
| 1917 |
-
# 构建图片生成提示词
|
| 1918 |
-
image_prompt = f"请生成图片:{prompt}"
|
| 1919 |
-
if size:
|
| 1920 |
-
image_prompt += f",尺寸:{size}"
|
| 1921 |
-
if quality == 'hd':
|
| 1922 |
-
image_prompt += ",高质量"
|
| 1923 |
-
|
| 1924 |
-
# 检查是否指定了特定账号
|
| 1925 |
-
specified_account_id = data.get('account_id')
|
| 1926 |
-
|
| 1927 |
-
if specified_account_id is not None:
|
| 1928 |
-
# 使用指定的账号
|
| 1929 |
-
accounts = account_manager.accounts
|
| 1930 |
-
if specified_account_id < 0 or specified_account_id >= len(accounts):
|
| 1931 |
-
return jsonify({"error": {"message": f"无效的账号ID: {specified_account_id}", "type": "invalid_request_error"}}), 400
|
| 1932 |
-
account = accounts[specified_account_id]
|
| 1933 |
-
if not account.get('enabled', True):
|
| 1934 |
-
return jsonify({"error": {"message": f"账号 {specified_account_id} 已禁用", "type": "invalid_request_error"}}), 400
|
| 1935 |
-
# 检查是否在冷却中
|
| 1936 |
-
cooldown_until = account.get('cooldown_until', 0)
|
| 1937 |
-
if cooldown_until > time.time():
|
| 1938 |
-
return jsonify({"error": {"message": f"账号 {specified_account_id} 正在冷却中,请稍后重试", "type": "rate_limit_error"}}), 429
|
| 1939 |
-
|
| 1940 |
-
account_idx = specified_account_id
|
| 1941 |
-
all_images = []
|
| 1942 |
-
last_error = None
|
| 1943 |
-
try:
|
| 1944 |
-
session, jwt, team_id = ensure_session_for_account(account_idx, account)
|
| 1945 |
-
proxy = get_proxy()
|
| 1946 |
-
|
| 1947 |
-
# 生成图片(可能需要多次调用以满足 n 参数)
|
| 1948 |
-
for i in range(n):
|
| 1949 |
-
chat_response = stream_chat_with_images(jwt, session, image_prompt, proxy, team_id, [])
|
| 1950 |
-
all_images.extend(chat_response.images)
|
| 1951 |
-
if len(all_images) >= n:
|
| 1952 |
-
break
|
| 1953 |
-
|
| 1954 |
-
# 只返回前 n 张图片
|
| 1955 |
-
all_images = all_images[:n]
|
| 1956 |
-
|
| 1957 |
-
except AccountRateLimitError as e:
|
| 1958 |
-
last_error = e
|
| 1959 |
-
pt_wait = seconds_until_next_pt_midnight()
|
| 1960 |
-
cooldown_seconds = max(account_manager.rate_limit_cooldown, pt_wait)
|
| 1961 |
-
account_manager.mark_account_cooldown(account_idx, str(e), cooldown_seconds)
|
| 1962 |
-
except AccountAuthError as e:
|
| 1963 |
-
last_error = e
|
| 1964 |
-
account_manager.mark_account_cooldown(account_idx, str(e), account_manager.auth_error_cooldown)
|
| 1965 |
-
except AccountRequestError as e:
|
| 1966 |
-
last_error = e
|
| 1967 |
-
account_manager.mark_account_cooldown(account_idx, str(e), account_manager.generic_error_cooldown)
|
| 1968 |
-
except Exception as e:
|
| 1969 |
-
last_error = e
|
| 1970 |
-
else:
|
| 1971 |
-
# 轮训获取账号
|
| 1972 |
-
available_accounts = account_manager.get_available_accounts()
|
| 1973 |
-
if not available_accounts:
|
| 1974 |
-
next_cd = account_manager.get_next_cooldown_info()
|
| 1975 |
-
wait_msg = ""
|
| 1976 |
-
if next_cd:
|
| 1977 |
-
wait_msg = f"(最近冷却账号 {next_cd['index']},约 {int(next_cd['cooldown_until']-time.time())} 秒后可重试)"
|
| 1978 |
-
return jsonify({"error": {"message": f"没有可用的账号{wait_msg}", "type": "rate_limit_error"}}), 429
|
| 1979 |
-
|
| 1980 |
-
max_retries = len(available_accounts)
|
| 1981 |
-
last_error = None
|
| 1982 |
-
all_images = []
|
| 1983 |
-
account_idx = None
|
| 1984 |
-
|
| 1985 |
-
for retry_idx in range(max_retries):
|
| 1986 |
-
try:
|
| 1987 |
-
account_idx, account = account_manager.get_next_account()
|
| 1988 |
-
session, jwt, team_id = ensure_session_for_account(account_idx, account)
|
| 1989 |
-
proxy = get_proxy()
|
| 1990 |
-
|
| 1991 |
-
# 生成图片(可能需��多次调用以满足 n 参数)
|
| 1992 |
-
for i in range(n):
|
| 1993 |
-
chat_response = stream_chat_with_images(jwt, session, image_prompt, proxy, team_id, [])
|
| 1994 |
-
all_images.extend(chat_response.images)
|
| 1995 |
-
if len(all_images) >= n:
|
| 1996 |
-
break
|
| 1997 |
-
|
| 1998 |
-
# 只返回前 n 张图片
|
| 1999 |
-
all_images = all_images[:n]
|
| 2000 |
-
break
|
| 2001 |
-
|
| 2002 |
-
except AccountRateLimitError as e:
|
| 2003 |
-
last_error = e
|
| 2004 |
-
if account_idx is not None:
|
| 2005 |
-
pt_wait = seconds_until_next_pt_midnight()
|
| 2006 |
-
cooldown_seconds = max(account_manager.rate_limit_cooldown, pt_wait)
|
| 2007 |
-
account_manager.mark_account_cooldown(account_idx, str(e), cooldown_seconds)
|
| 2008 |
-
print(f"[图片生成] 第{retry_idx+1}次尝试失败(限额): {e}")
|
| 2009 |
-
continue
|
| 2010 |
-
except AccountAuthError as e:
|
| 2011 |
-
last_error = e
|
| 2012 |
-
if account_idx is not None:
|
| 2013 |
-
account_manager.mark_account_cooldown(account_idx, str(e), account_manager.auth_error_cooldown)
|
| 2014 |
-
print(f"[图片生成] 第{retry_idx+1}次尝试失败(凭证): {e}")
|
| 2015 |
-
continue
|
| 2016 |
-
except AccountRequestError as e:
|
| 2017 |
-
last_error = e
|
| 2018 |
-
if account_idx is not None:
|
| 2019 |
-
account_manager.mark_account_cooldown(account_idx, str(e), account_manager.generic_error_cooldown)
|
| 2020 |
-
print(f"[图片生成] 第{retry_idx+1}次尝试失败(请求异常): {e}")
|
| 2021 |
-
continue
|
| 2022 |
-
except Exception as e:
|
| 2023 |
-
last_error = e
|
| 2024 |
-
print(f"[图片生成] 第{retry_idx+1}次尝试失败: {type(e).__name__}: {e}")
|
| 2025 |
-
if account_idx is None:
|
| 2026 |
-
break
|
| 2027 |
-
continue
|
| 2028 |
-
|
| 2029 |
-
if not all_images:
|
| 2030 |
-
error_message = last_error or "图片生成失败"
|
| 2031 |
-
status_code = 429 if isinstance(last_error, (AccountRateLimitError, NoAvailableAccount)) else 500
|
| 2032 |
-
err_type = "rate_limit_error" if status_code == 429 else "api_error"
|
| 2033 |
-
return jsonify({"error": {"message": error_message, "type": err_type}}), status_code
|
| 2034 |
-
|
| 2035 |
-
# 构建 OpenAI 格式响应
|
| 2036 |
-
base_url = get_image_base_url(request.host_url)
|
| 2037 |
-
image_data_list = []
|
| 2038 |
-
|
| 2039 |
-
for img in all_images:
|
| 2040 |
-
image_item = {}
|
| 2041 |
-
|
| 2042 |
-
if response_format == 'b64_json':
|
| 2043 |
-
# 返回 base64 编码的图片
|
| 2044 |
-
if img.base64_data:
|
| 2045 |
-
image_item["b64_json"] = img.base64_data
|
| 2046 |
-
else:
|
| 2047 |
-
# 如果没有 base64 数据,尝试从文件读取
|
| 2048 |
-
if img.local_path and os.path.exists(img.local_path):
|
| 2049 |
-
with open(img.local_path, 'rb') as f:
|
| 2050 |
-
image_bytes = f.read()
|
| 2051 |
-
image_item["b64_json"] = base64.b64encode(image_bytes).decode('utf-8')
|
| 2052 |
-
else:
|
| 2053 |
-
# 降级为 URL
|
| 2054 |
-
if img.file_name:
|
| 2055 |
-
image_item["url"] = f"{base_url}image/{img.file_name}"
|
| 2056 |
-
else:
|
| 2057 |
-
# 返回 URL(默认)
|
| 2058 |
-
if img.file_name:
|
| 2059 |
-
image_item["url"] = f"{base_url}image/{img.file_name}"
|
| 2060 |
-
elif img.base64_data:
|
| 2061 |
-
# 如果没有文件名但有 base64,保存到缓存
|
| 2062 |
-
try:
|
| 2063 |
-
decoded = base64.b64decode(img.base64_data)
|
| 2064 |
-
filename = save_image_to_cache(decoded, img.mime_type or "image/png")
|
| 2065 |
-
image_item["url"] = f"{base_url}image/{filename}"
|
| 2066 |
-
except Exception:
|
| 2067 |
-
# 降级为 base64
|
| 2068 |
-
image_item["b64_json"] = img.base64_data
|
| 2069 |
-
|
| 2070 |
-
# 可选:添加修订后的提示词
|
| 2071 |
-
if prompt:
|
| 2072 |
-
image_item["revised_prompt"] = prompt
|
| 2073 |
-
|
| 2074 |
-
image_data_list.append(image_item)
|
| 2075 |
-
|
| 2076 |
-
response = {
|
| 2077 |
-
"created": int(time.time()),
|
| 2078 |
-
"data": image_data_list
|
| 2079 |
-
}
|
| 2080 |
-
|
| 2081 |
-
return jsonify(response)
|
| 2082 |
-
|
| 2083 |
-
except Exception as e:
|
| 2084 |
-
import traceback
|
| 2085 |
-
traceback.print_exc()
|
| 2086 |
-
return jsonify({"error": {"message": str(e), "type": "api_error"}}), 500
|
| 2087 |
-
|
| 2088 |
-
|
| 2089 |
# ==================== 图片服务接口 ====================
|
| 2090 |
|
| 2091 |
@app.route('/image/<path:filename>')
|
|
@@ -2687,4 +2491,4 @@ if __name__ == '__main__':
|
|
| 2687 |
if not account_manager.accounts:
|
| 2688 |
print("[!] 警告: 没有配置任何账号")
|
| 2689 |
|
| 2690 |
-
app.run(host='0.0.0.0', port=7860, debug=False)
|
|
|
|
| 1890 |
return result_text
|
| 1891 |
|
| 1892 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1893 |
# ==================== 图片服务接口 ====================
|
| 1894 |
|
| 1895 |
@app.route('/image/<path:filename>')
|
|
|
|
| 2491 |
if not account_manager.accounts:
|
| 2492 |
print("[!] 警告: 没有配置任何账号")
|
| 2493 |
|
| 2494 |
+
app.run(host='0.0.0.0', port=7860, debug=False)
|