lydgs commited on
Commit
c78c47f
·
verified ·
1 Parent(s): 86d14ea

Update Dockerfile

Browse files
Files changed (1) hide show
  1. Dockerfile +93 -34
Dockerfile CHANGED
@@ -2,65 +2,124 @@ FROM python:3.11-slim
2
 
3
  WORKDIR /app
4
 
5
- # 安装依赖
6
  RUN pip install fastapi uvicorn google-genai
7
 
8
- # 生成 main.py(支持自动获取模型列表)
9
  RUN cat > main.py << 'PYEOF'
10
  from fastapi import FastAPI, Request
11
- from fastapi.responses import JSONResponse
12
  from google import genai
13
- import os, uvicorn
14
 
15
  app = FastAPI()
16
  GOOGLE_API_KEY = os.environ["GOOGLE_API_KEY"]
17
  client = genai.Client(api_key=GOOGLE_API_KEY)
18
 
19
- # 静态模型列表:作为 API 调用失败时的后备方案
20
- STATIC_MODELS = [
21
- {"id": "gemini-embedding-001", "object": "model", "owned_by": "gemini"},
22
- {"id": "gemini-embedding-2-preview", "object": "model", "owned_by": "gemini"},
23
- ]
24
-
25
- # 模型名称映射(短名称 -> 完整路径),用于 /v1/embeddings 端点
26
  MODEL_MAP = {
27
- "text-embedding-004": "models/text-embedding-004",
 
 
 
 
 
 
28
  "gemini-embedding-001": "models/gemini-embedding-001",
29
  "gemini-embedding-2-preview": "models/gemini-embedding-2-preview",
30
  }
31
 
32
- def fetch_embedding_models():
33
- """动态获取支持 embedContent 的 Gemini Embedding 模型列表"""
34
- try:
35
- all_models = client.models.list()
36
- embedding_models = []
37
- for m in all_models:
38
- if hasattr(m, 'supported_actions') and 'embedContent' in m.supported_actions:
39
- # 提取短名称 (e.g., "models/gemini-embedding-001" -> "gemini-embedding-001")
40
- model_id = m.name.split('/')[-1]
41
- embedding_models.append({
42
- "id": model_id,
43
- "object": "model",
44
- "owned_by": "gemini"
45
- })
46
- return embedding_models
47
- except Exception as e:
48
- print(f"动态获取模型列表失败,回退到静态列表: {e}")
49
- return STATIC_MODELS
50
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
51
  @app.get("/v1/models")
52
  async def list_models():
53
- models = fetch_embedding_models()
54
- return JSONResponse({"object": "list", "data": models})
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
55
 
56
  @app.post("/v1/embeddings")
57
  async def create_embeddings(request: Request):
 
58
  try:
59
  body = await request.json()
60
  model_short = body.get("model", "gemini-embedding-001")
61
- # 自动补全模型名称为完整路径
62
- model_full = MODEL_MAP.get(model_short, f"models/{model_short}")
63
  input_text = body.get("input", "")
 
 
64
  result = client.models.embed_content(
65
  model=model_full,
66
  contents=input_text
 
2
 
3
  WORKDIR /app
4
 
5
+ # 安装必要库
6
  RUN pip install fastapi uvicorn google-genai
7
 
8
+ # 生成全新的 main.py,支持 Chat Completions、Embeddings、Models
9
  RUN cat > main.py << 'PYEOF'
10
  from fastapi import FastAPI, Request
11
+ from fastapi.responses import JSONResponse, StreamingResponse
12
  from google import genai
13
+ import os, uvicorn, json, time
14
 
15
  app = FastAPI()
16
  GOOGLE_API_KEY = os.environ["GOOGLE_API_KEY"]
17
  client = genai.Client(api_key=GOOGLE_API_KEY)
18
 
19
+ # ---------- 模型名称映射(短名 -> 完整 resources 名)----------
 
 
 
 
 
 
20
  MODEL_MAP = {
21
+ # 聊天模型
22
+ "gemini-2.5-flash": "models/gemini-2.5-flash",
23
+ "gemini-2.5-pro": "models/gemini-2.5-pro",
24
+ "gemini-2.5-pro-preview-03-25": "models/gemini-2.5-pro-preview-03-25",
25
+ "gemini-1.5-flash": "models/gemini-1.5-flash",
26
+ "gemini-1.5-pro": "models/gemini-1.5-pro",
27
+ # 嵌入模型
28
  "gemini-embedding-001": "models/gemini-embedding-001",
29
  "gemini-embedding-2-preview": "models/gemini-embedding-2-preview",
30
  }
31
 
32
+ # 预定义的所有可用模型列表(用于 /v1/models)
33
+ AVAILABLE_MODELS = [
34
+ {"id": "gemini-2.5-flash", "object": "model", "owned_by": "gemini"},
35
+ {"id": "gemini-2.5-pro", "object": "model", "owned_by": "gemini"},
36
+ {"id": "gemini-1.5-flash", "object": "model", "owned_by": "gemini"},
37
+ {"id": "gemini-1.5-pro", "object": "model", "owned_by": "gemini"},
38
+ {"id": "gemini-embedding-001", "object": "model", "owned_by": "gemini"},
39
+ {"id": "gemini-embedding-2-preview", "object": "model", "owned_by": "gemini"},
40
+ ]
41
+
42
+ # ---------- 辅助函数 ----------
43
+ def get_full_model_name(short_name: str) -> str:
44
+ """将短模型名转换为完整的 resources 路径,若未找到则自动添加 models/ 前缀"""
45
+ return MODEL_MAP.get(short_name, f"models/{short_name}")
 
 
 
 
46
 
47
+ def convert_openai_messages(messages: list) -> list:
48
+ """将 OpenAI 格式的 messages 转换为 Gemini 要求的 contents 格式"""
49
+ contents = []
50
+ for msg in messages:
51
+ role = msg.get("role", "user")
52
+ text = msg.get("content", "")
53
+ # Gemini 使用 "user" 和 "model" 角色,将 "assistant" 映射为 "model"
54
+ if role == "assistant":
55
+ role = "model"
56
+ elif role not in ("user", "model"):
57
+ role = "user" # 其他角色一律视为 user
58
+ contents.append({"role": role, "parts": [{"text": text}]})
59
+ return contents
60
+
61
+ # ---------- API 端点 ----------
62
  @app.get("/v1/models")
63
  async def list_models():
64
+ """返回可用模型列表(可手动扩展)"""
65
+ return JSONResponse({"object": "list", "data": AVAILABLE_MODELS})
66
+
67
+ @app.post("/v1/chat/completions")
68
+ async def chat_completions(request: Request):
69
+ """OpenAI 兼容的聊天补全端点(非流式)"""
70
+ try:
71
+ body = await request.json()
72
+ model_short = body.get("model", "gemini-2.5-flash")
73
+ messages = body.get("messages", [])
74
+ temperature = body.get("temperature", 0.7)
75
+ max_tokens = body.get("max_tokens", 1000)
76
+
77
+ model_full = get_full_model_name(model_short)
78
+ contents = convert_openai_messages(messages)
79
+
80
+ # 调用 Gemini API
81
+ response = client.models.generate_content(
82
+ model=model_full,
83
+ contents=contents,
84
+ config={
85
+ "temperature": temperature,
86
+ "max_output_tokens": max_tokens,
87
+ }
88
+ )
89
+
90
+ # 构造 OpenAI 兼容响应
91
+ choice = {
92
+ "index": 0,
93
+ "message": {
94
+ "role": "assistant",
95
+ "content": response.text
96
+ },
97
+ "finish_reason": "stop"
98
+ }
99
+ return JSONResponse({
100
+ "id": f"chatcmpl-{int(time.time())}",
101
+ "object": "chat.completion",
102
+ "created": int(time.time()),
103
+ "model": model_short,
104
+ "choices": [choice],
105
+ "usage": {
106
+ "prompt_tokens": response.usage_metadata.prompt_token_count,
107
+ "completion_tokens": response.usage_metadata.candidates_token_count,
108
+ "total_tokens": response.usage_metadata.total_token_count
109
+ }
110
+ })
111
+ except Exception as e:
112
+ return JSONResponse({"error": str(e)}, status_code=500)
113
 
114
  @app.post("/v1/embeddings")
115
  async def create_embeddings(request: Request):
116
+ """OpenAI 兼容的嵌入端点"""
117
  try:
118
  body = await request.json()
119
  model_short = body.get("model", "gemini-embedding-001")
 
 
120
  input_text = body.get("input", "")
121
+ model_full = get_full_model_name(model_short)
122
+
123
  result = client.models.embed_content(
124
  model=model_full,
125
  contents=input_text