Skip to content

Commit 4ad7332

Browse files
committed
feat: add get models api
1 parent 4fabe58 commit 4ad7332

File tree

6 files changed

+68
-22
lines changed

6 files changed

+68
-22
lines changed

app/api/v1/__init__.py

Lines changed: 0 additions & 5 deletions
This file was deleted.

app/api/v1/chat.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
Chat Completions API 路由
33
"""
44

5-
from typing import Any, Dict, List, Literal, Optional, Union
5+
from typing import Any, Dict, List, Optional, Union
66

77
from fastapi import APIRouter
88
from fastapi.responses import StreamingResponse, JSONResponse

app/api/v1/image.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@
1414
from app.services.grok.model import ModelService
1515
from app.services.grok.processor import ImageStreamProcessor, ImageCollectProcessor
1616
from app.services.token import get_token_manager
17-
from app.core.config import get_config
1817
from app.core.exceptions import ValidationException, AppException, ErrorType
1918
from app.core.logger import logger
2019

app/api/v1/models.py

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
"""
2+
Models API 路由
3+
"""
4+
5+
from fastapi import APIRouter
6+
7+
from app.services.grok.model import ModelService
8+
9+
10+
router = APIRouter(tags=["Models"])
11+
12+
13+
@router.get("/models")
14+
async def list_models():
15+
"""OpenAI 兼容 models 列表接口"""
16+
data = [
17+
{
18+
"id": m.model_id,
19+
"object": "model",
20+
"created": 0,
21+
"owned_by": "grok2api",
22+
}
23+
for m in ModelService.list()
24+
]
25+
return {"object": "list", "data": data}
26+
27+
28+
__all__ = ["router"]

app/services/grok/chat.py

Lines changed: 37 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
import uuid
66
import orjson
7-
from typing import Dict, List, Any, Optional
7+
from typing import Dict, List, Any
88
from dataclasses import dataclass
99

1010
from curl_cffi.requests import AsyncSession
@@ -18,11 +18,11 @@
1818
ErrorType
1919
)
2020
from app.services.grok.statsig import StatsigService
21-
from app.services.grok.model import ModelService, Cost
21+
from app.services.grok.model import ModelService
2222
from app.services.grok.assets import UploadService
2323
from app.services.grok.processor import StreamProcessor, CollectProcessor
2424
from app.services.grok.retry import retry_on_status
25-
from app.services.token import get_token_manager, EffortType
25+
from app.services.token import get_token_manager
2626

2727

2828
CHAT_API = "https://grok.com/rest/app-chat/conversations/new"
@@ -64,34 +64,38 @@ def extract(messages: List[Dict[str, Any]], is_video: bool = False) -> tuple[str
6464
"""
6565
texts = []
6666
attachments = [] # 需要上传的附件 (URL 或 base64)
67-
67+
68+
# 先抽取每条消息的文本,保留角色信息用于合并
69+
extracted: List[Dict[str, str]] = []
70+
6871
for msg in messages:
72+
role = msg.get("role", "")
6973
content = msg.get("content", "")
70-
74+
parts = []
75+
7176
# 简单字符串内容
7277
if isinstance(content, str):
7378
if content.strip():
74-
texts.append(content)
75-
continue
76-
79+
parts.append(content)
80+
7781
# 列表格式内容
78-
if isinstance(content, list):
82+
elif isinstance(content, list):
7983
for item in content:
8084
item_type = item.get("type", "")
81-
85+
8286
# 文本类型
8387
if item_type == "text":
8488
text = item.get("text", "")
8589
if text.strip():
86-
texts.append(text)
87-
90+
parts.append(text)
91+
8892
# 图片类型
8993
elif item_type == "image_url":
9094
image_data = item.get("image_url", {})
9195
url = image_data.get("url", "") if isinstance(image_data, dict) else str(image_data)
9296
if url:
9397
attachments.append(("image", url))
94-
98+
9599
# 音频类型
96100
elif item_type == "input_audio":
97101
if is_video:
@@ -100,7 +104,7 @@ def extract(messages: List[Dict[str, Any]], is_video: bool = False) -> tuple[str
100104
data = audio_data.get("data", "") if isinstance(audio_data, dict) else str(audio_data)
101105
if data:
102106
attachments.append(("audio", data))
103-
107+
104108
# 文件类型
105109
elif item_type == "file":
106110
if is_video:
@@ -112,7 +116,25 @@ def extract(messages: List[Dict[str, Any]], is_video: bool = False) -> tuple[str
112116
url = file_data
113117
if url:
114118
attachments.append(("file", url))
115-
119+
120+
if parts:
121+
extracted.append({"role": role, "text": "\n".join(parts)})
122+
123+
# 合并文本
124+
last_user_index = None
125+
for i in range(len(extracted) - 1, -1, -1):
126+
if extracted[i]["role"] == "user":
127+
last_user_index = i
128+
break
129+
130+
for i, item in enumerate(extracted):
131+
role = item["role"] or "user"
132+
text = item["text"]
133+
if i == last_user_index:
134+
texts.append(text)
135+
else:
136+
texts.append(f"{role}: {text}")
137+
116138
# 换行拼接文本
117139
message = "\n\n".join(texts)
118140
return message, attachments

main.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
from app.api.v1.chat import router as chat_router
3131
from app.api.v1.image import router as image_router
3232
from app.api.v1.files import router as files_router
33+
from app.api.v1.models import router as models_router
3334
from app.services.token import get_scheduler
3435

3536

@@ -100,6 +101,7 @@ def create_app() -> FastAPI:
100101
# 注册路由
101102
app.include_router(chat_router, prefix="/v1", dependencies=[Depends(verify_api_key)])
102103
app.include_router(image_router, prefix="/v1", dependencies=[Depends(verify_api_key)])
104+
app.include_router(models_router, prefix="/v1", dependencies=[Depends(verify_api_key)])
103105
app.include_router(files_router, prefix="/v1/files")
104106

105107
# 静态文件服务

0 commit comments

Comments
 (0)