XFE Git
XFE Studio Git
Git 首页 全局搜索
XFE 主站 文档 NuGet
公开
关注 0 Fork 0 Star 0
返回提交历史

XFEstudio/gpt4free

Add Kimi provider, add vision support to LMArenaBeta

8892b00a
hlohaus <983577+hlohaus@users.noreply.github.com>
提交于

代码差异

8 个文件 +134 -5
Modified .gitignore +2 -1
@@ -36,4 +36,5 @@ projects/windows/
36 36
37 37 *.bak
38 38 *.backup
39 .env
39 .env
40 g4f.dev/
Modified docker/Dockerfile +1 -1
@@ -19,7 +19,7 @@ RUN if [ "$G4F_VERSION" = "" ] ; then \
19 19 RUN apt-get -qqy update \
20 20 && apt-get -qqy upgrade \
21 21 && apt-get -qyy autoremove \
22 && apt-get -qqy install python3 python-is-python3 pip ffmpeg flac \
22 && apt-get -qqy install python3 python-is-python3 pip ffmpeg flac libavcodec-extra \
23 23 && apt-get -qyy remove openjdk-11-jre-headless \
24 24 && apt-get -qyy autoremove \
25 25 && apt-get -qyy clean \
Deleted g4f.dev +0 -1
@@ -1 +0,0 @@
1 Subproject commit b3a9831dd9b10e90f17bcf6524ff48863ac8112d
Added g4f/Provider/Kimi.py +104 -0
@@ -0,0 +1,104 @@
1 from __future__ import annotations
2
3 import random
4 from typing import AsyncIterator
5
6 from .base_provider import AsyncAuthedProvider, ProviderModelMixin
7 from ..providers.helper import get_last_user_message
8 from ..requests import StreamSession, see_stream
9 from ..providers.response import AuthResult, TitleGeneration, JsonConversation, FinishReason
10 from ..typing import AsyncResult, Messages
11
12 class Kimi(AsyncAuthedProvider, ProviderModelMixin):
13 url = "https://www.kimi.com"
14 working = True
15 active_by_default = True
16 default_model = "kimi-k2"
17 models = [default_model]
18
19 @classmethod
20 async def on_auth_async(cls, proxy: str = None, **kwargs) -> AsyncIterator:
21 device_id = str(random.randint(1000000000000000, 9999999999999999))
22 async with StreamSession(proxy=proxy, impersonate="chrome") as session:
23 async with session.post(
24 "https://www.kimi.com/api/device/register",
25 json={},
26 headers={
27 "x-msh-device-id": device_id,
28 "x-msh-platform": "web",
29 "x-traffic-id": device_id
30 }
31 ) as response:
32 if response.status != 200:
33 raise Exception("Failed to register device")
34 data = await response.json()
35 if not data.get("access_token"):
36 raise Exception("No access token received")
37 yield AuthResult(
38 api_key=data.get("access_token"),
39 device_id=device_id,
40 )
41
42 @classmethod
43 async def create_authed(
44 cls,
45 model: str,
46 messages: Messages,
47 auth_result: AuthResult,
48 proxy: str = None,
49 conversation: JsonConversation = None,
50 web_search: bool = False,
51 **kwargs
52 ) -> AsyncResult:
53 pass
54 async with StreamSession(
55 proxy=proxy,
56 impersonate="chrome",
57 headers={
58 "Authorization": f"Bearer {auth_result.api_key}",
59 }
60 ) as session:
61 if conversation is None:
62 async with session.post("https://www.kimi.com/api/chat", json={
63 "name":"未命名会话",
64 "born_from":"home",
65 "kimiplus_id":"kimi",
66 "is_example":False,
67 "source":"web",
68 "tags":[]
69 }) as response:
70 if response.status != 200:
71 raise Exception("Failed to create chat")
72 chat_data = await response.json()
73 conversation = JsonConversation(chat_id=chat_data.get("id"))
74 data = {
75 "kimiplus_id": "kimi",
76 "extend": {"sidebar": True},
77 "model": model,
78 "use_search": web_search,
79 "messages": [
80 {
81 "role": "user",
82 "content": get_last_user_message(messages)
83 }
84 ],
85 "refs": [],
86 "history": [],
87 "scene_labels": [],
88 "use_semantic_memory": False,
89 "use_deep_research": False
90 }
91 async with session.post(
92 f"https://www.kimi.com/api/chat/{conversation.chat_id}/completion/stream",
93 json=data
94 ) as response:
95 if response.status != 200:
96 raise Exception("Failed to start chat completion")
97 async for line in see_stream(response):
98 if line.get("event") == "cmpl":
99 yield line.get("text")
100 elif line.get("event") == "rename":
101 yield TitleGeneration(line.get("text"))
102 elif line.get("event") == "all_done":
103 yield FinishReason("stop")
104 break
Modified g4f/Provider/__init__.py +1 -0
@@ -41,6 +41,7 @@ from .DeepInfraChat import DeepInfraChat
41 41 from .DuckDuckGo import DuckDuckGo
42 42 from .Free2GPT import Free2GPT
43 43 from .ImageLabs import ImageLabs
44 from .Kimi import Kimi
44 45 from .LambdaChat import LambdaChat
45 46 from .LegacyLMArena import LegacyLMArena
46 47 from .OIVSCodeSer2 import OIVSCodeSer2
Modified g4f/Provider/needs_auth/LMArenaBeta.py +25 -2
@@ -4,12 +4,14 @@ import time
4 4 import uuid
5 5 import json
6 6 import asyncio
7 import os
7 8
8 from ...typing import AsyncResult, Messages
9 from ...typing import AsyncResult, Messages, MediaListType
9 10 from ...requests import StreamSession, get_args_from_nodriver, raise_for_status, merge_cookies
10 11 from ...requests import DEFAULT_HEADERS, has_nodriver
11 12 from ...errors import ModelNotFoundError
12 13 from ...providers.response import FinishReason, Usage, JsonConversation, ImageResponse
14 from ...tools.media import merge_media
13 15 from ..base_provider import AsyncGeneratorProvider, ProviderModelMixin,AuthFileMixin
14 16 from ..helper import get_last_user_message
15 17 from ... import debug
@@ -114,6 +116,7 @@ models = [
114 116 ]
115 117 text_models = {model["publicName"]: model["id"] for model in models if "text" in model["capabilities"]["outputCapabilities"]}
116 118 image_models = {model["publicName"]: model["id"] for model in models if "image" in model["capabilities"]["outputCapabilities"]}
119 vision_models = [model["publicName"] for model in models if "image" in model["capabilities"]["inputCapabilities"]]
117 120
118 121 class LMArenaBeta(AsyncGeneratorProvider, ProviderModelMixin, AuthFileMixin):
119 122 label = "LMArena (New)"
@@ -124,6 +127,7 @@ class LMArenaBeta(AsyncGeneratorProvider, ProviderModelMixin, AuthFileMixin):
124 127 default_model = list(text_models.keys())[0]
125 128 models = list(text_models) + list(image_models)
126 129 image_models = list(image_models)
130 vision_models = vision_models
127 131
128 132 @classmethod
129 133 async def create_async_generator(
@@ -131,6 +135,7 @@ class LMArenaBeta(AsyncGeneratorProvider, ProviderModelMixin, AuthFileMixin):
131 135 model: str,
132 136 messages: Messages,
133 137 conversation: JsonConversation = None,
138 media: MediaListType = None,
134 139 proxy: str = None,
135 140 timeout: int = None,
136 141 **kwargs
@@ -181,7 +186,15 @@ class LMArenaBeta(AsyncGeneratorProvider, ProviderModelMixin, AuthFileMixin):
181 186 "id": userMessageId,
182 187 "role": "user",
183 188 "content": prompt,
184 "experimental_attachments": [],
189 "experimental_attachments": [
190 {
191 "name": name or os.path.basename(url),
192 "contentType": get_content_type(url),
193 "url": url
194 }
195 for url, name in list(merge_media(media, messages))
196 if url.startswith("https://")
197 ],
185 198 "parentMessageIds": [] if conversation is None else conversation.message_ids,
186 199 "participantPosition": "a",
187 200 "modelId": None,
@@ -233,3 +246,13 @@ class LMArenaBeta(AsyncGeneratorProvider, ProviderModelMixin, AuthFileMixin):
233 246 # Save the args to cache file
234 247 with cache_file.open("w") as f:
235 248 json.dump(args, f)
249
250 def get_content_type(url: str) -> str:
251 if url.endswith(".webp"):
252 return "image/webp"
253 elif url.endswith(".png"):
254 return "image/png"
255 elif url.endswith(".jpg") or url.endswith(".jpeg"):
256 return "image/jpeg"
257 else:
258 return "application/octet-stream"
Deleted g4f/Provider/needs_auth/Sora.py +0 -0
此文件没有可显示的逐行差异。
Modified g4f/tools/run_tools.py +1 -0
@@ -129,6 +129,7 @@ class AuthManager:
129 129 "GeminiPro": "Gemini",
130 130 "PollinationsAI": "Pollinations",
131 131 "OpenaiAPI": "Openai",
132 "PuterJS": "Puter",
132 133 }
133 134
134 135 @classmethod