返回提交历史
Modified
g4f/Provider/AutonomousAI.py
+6
-9
Modified
g4f/Provider/CablyAI.py
+12
-46
Modified
g4f/Provider/ChatGLM.py
+7
-6
Modified
g4f/Provider/ChatGptEs.py
+3
-11
Modified
g4f/Provider/ChatGptt.py
+2
-9
Modified
g4f/Provider/DDG.py
+57
-37
Modified
g4f/Provider/ImageLabs.py
+1
-1
Modified
g4f/Provider/Pizzagpt.py
+2
-0
Modified
g4f/Provider/PollinationsAI.py
+3
-4
Modified
g4f/Provider/hf_space/Qwen_Qwen_2_72B_Instruct.py
+9
-10
Modified
g4f/Provider/needs_auth/DeepSeek.py
+1
-1
Modified
g4f/Provider/needs_auth/OpenaiAPI.py
+1
-0
XFEstudio/gpt4free
Add conversation and continue support in DDG
64e6e47c
代码差异
12 个文件
+104
-134
@@ -6,8 +6,8 @@ import json
6
6
7
7
from ..typing import AsyncResult, Messages
8
8
from ..requests.raise_for_status import raise_for_status
9
from ..providers.response import FinishReason
9
10
from .base_provider import AsyncGeneratorProvider, ProviderModelMixin
10
from .helper import format_prompt
11
11
12
12
class AutonomousAI(AsyncGeneratorProvider, ProviderModelMixin):
13
13
url = "https://www.autonomous.ai/anon/"
@@ -32,7 +32,6 @@ class AutonomousAI(AsyncGeneratorProvider, ProviderModelMixin):
32
32
"qwen-2.5-coder-32b": "qwen_coder",
33
33
"hermes-3": "hermes",
34
34
"llama-3.2-90b": "vision",
35
"llama-3.3-70b": "summary"
36
35
}
37
36
38
37
@classmethod
@@ -57,12 +56,8 @@ class AutonomousAI(AsyncGeneratorProvider, ProviderModelMixin):
57
56
}
58
57
59
58
async with ClientSession(headers=headers) as session:
60
prompt = format_prompt(messages)
61
62
# Encode message
63
message = [{"role": "user", "content": prompt}]
64
message_json = json.dumps(message)
65
encoded_message = base64.b64encode(message_json.encode('utf-8')).decode('utf-8')
59
message_json = json.dumps(messages)
60
encoded_message = base64.b64encode(message_json.encode()).decode(errors="ignore")
66
61
67
62
data = {
68
63
"messages": encoded_message,
@@ -84,7 +79,9 @@ class AutonomousAI(AsyncGeneratorProvider, ProviderModelMixin):
84
79
chunk_data = json.loads(chunk_str.replace("data: ", ""))
85
80
if "choices" in chunk_data and chunk_data["choices"]:
86
81
delta = chunk_data["choices"][0].get("delta", {})
87
if "content" in delta:
82
if "content" in delta and delta["content"]:
88
83
yield delta["content"]
84
if "finish_reason" in chunk_data and chunk_data["finish_reason"]:
85
yield FinishReason(chunk_data["finish_reason"])
89
86
except json.JSONDecodeError:
90
87
continue
@@ -1,38 +1,26 @@
1
1
from __future__ import annotations
2
2
3
from aiohttp import ClientSession
4
import json
5
6
3
from ..typing import AsyncResult, Messages
7
from ..requests.raise_for_status import raise_for_status
8
from .base_provider import AsyncGeneratorProvider, ProviderModelMixin
9
from .helper import format_prompt
10
4
from .needs_auth import OpenaiAPI
11
5
12
class CablyAI(AsyncGeneratorProvider, ProviderModelMixin):
6
class CablyAI(OpenaiAPI):
13
7
url = "https://cablyai.com"
14
api_endpoint = "https://cablyai.com/v1/chat/completions"
15
8
login_url = None
9
needs_auth = False
10
api_base = "https://cablyai.com/v1"
16
11
working = True
17
supports_stream = True
18
supports_system_message = True
19
supports_message_history = True
20
12
21
13
default_model = "Cably-80B"
22
14
models = [default_model]
23
24
15
model_aliases = {"cably-80b": default_model}
25
16
26
17
@classmethod
27
async def create_async_generator(
18
def create_async_generator(
28
19
cls,
29
20
model: str,
30
21
messages: Messages,
31
stream: bool = False,
32
proxy: str = None,
33
22
**kwargs
34
23
) -> AsyncResult:
35
model = cls.get_model(model)
36
24
headers = {
37
25
'Accept': '*/*',
38
26
'Accept-Language': 'en-US,en;q=0.9',
@@ -41,31 +29,9 @@ class CablyAI(AsyncGeneratorProvider, ProviderModelMixin):
41
29
'Referer': 'https://cablyai.com/chat',
42
30
'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36'
43
31
}
44
45
async with ClientSession(headers=headers) as session:
46
data = {
47
"model": model,
48
"messages": messages,
49
"stream": stream
50
}
51
52
async with session.post(cls.api_endpoint, json=data, proxy=proxy) as response:
53
await raise_for_status(response)
54
buffer = ""
55
async for chunk in response.content:
56
if chunk:
57
buffer += chunk.decode()
58
while "\n\n" in buffer:
59
chunk_data, buffer = buffer.split("\n\n", 1)
60
if chunk_data.startswith("data: "):
61
try:
62
json_data = json.loads(chunk_data[6:])
63
if "choices" in json_data and json_data["choices"]:
64
content = json_data["choices"][0]["delta"].get("content", "")
65
if content:
66
yield content
67
except json.JSONDecodeError:
68
# Skip invalid JSON
69
pass
70
elif chunk_data.strip() == "data: [DONE]":
71
return
32
return super().create_async_generator(
33
model=model,
34
messages=messages,
35
headers=headers,
36
**kwargs
37
)
@@ -8,7 +8,6 @@ from aiohttp import ClientSession
8
8
from ..typing import AsyncResult, Messages
9
9
from ..requests.raise_for_status import raise_for_status
10
10
from .base_provider import AsyncGeneratorProvider, ProviderModelMixin
11
from .helper import format_prompt
12
11
13
12
class ChatGLM(AsyncGeneratorProvider, ProviderModelMixin):
14
13
url = "https://chatglm.cn"
@@ -17,7 +16,7 @@ class ChatGLM(AsyncGeneratorProvider, ProviderModelMixin):
17
16
working = True
18
17
supports_stream = True
19
18
supports_system_message = False
20
supports_message_history = True
19
supports_message_history = False
21
20
22
21
default_model = "all-tools-230b"
23
22
models = [default_model]
@@ -47,7 +46,6 @@ class ChatGLM(AsyncGeneratorProvider, ProviderModelMixin):
47
46
}
48
47
49
48
async with ClientSession(headers=headers) as session:
50
prompt = format_prompt(messages)
51
49
data = {
52
50
"assistant_id": "65940acff94777010aa6b796",
53
51
"conversation_id": "",
@@ -62,17 +60,19 @@ class ChatGLM(AsyncGeneratorProvider, ProviderModelMixin):
62
60
},
63
61
"messages": [
64
62
{
65
"role": "user",
63
"role": message["role"],
66
64
"content": [
67
65
{
68
66
"type": "text",
69
"text": prompt
67
"text": message["content"]
70
68
}
71
69
]
72
70
}
71
for message in messages
73
72
]
74
73
}
75
74
75
yield_text = 0
76
76
async with session.post(cls.api_endpoint, json=data, proxy=proxy) as response:
77
77
await raise_for_status(response)
78
78
async for chunk in response.content:
@@ -85,8 +85,9 @@ class ChatGLM(AsyncGeneratorProvider, ProviderModelMixin):
85
85
if parts:
86
86
content = parts[0].get('content', [])
87
87
if content:
88
text = content[0].get('text', '')
88
text = content[0].get('text', '')[yield_text:]
89
89
if text:
90
90
yield text
91
yield_text += len(text)
91
92
except json.JSONDecodeError:
92
93
pass
@@ -2,7 +2,6 @@ from __future__ import annotations
2
2
3
3
import os
4
4
import re
5
import json
6
5
7
6
from aiohttp import ClientSession
8
7
@@ -17,20 +16,14 @@ class ChatGptEs(AsyncGeneratorProvider, ProviderModelMixin):
17
16
18
17
working = True
19
18
supports_stream = True
20
supports_system_message = True
21
supports_message_history = True
19
supports_system_message = False
20
supports_message_history = False
22
21
23
22
default_model = 'gpt-4o'
24
23
models = ['gpt-4', default_model, 'gpt-4o-mini']
25
24
26
25
SYSTEM_PROMPT = "Your default language is English. Always respond in English unless the user's message is in a different language. If the user's message is not in English, respond in the language of the user's message. Maintain this language behavior throughout the conversation unless explicitly instructed otherwise. User input:"
27
26
28
@classmethod
29
def get_model(cls, model: str) -> str:
30
if model in cls.models:
31
return model
32
return cls.model_aliases[model]
33
34
27
@classmethod
35
28
async def create_async_generator(
36
29
cls,
@@ -68,10 +61,9 @@ class ChatGptEs(AsyncGeneratorProvider, ProviderModelMixin):
68
61
'wpaicg_chat_client_id': os.urandom(5).hex(),
69
62
'wpaicg_chat_history': None
70
63
}
71
print(payload['message'])
72
64
73
65
async with session.post(cls.api_endpoint, headers=headers, data=payload) as response:
74
response.raise_for_status()
66
await raise_for_status(response)
75
67
result = await response.json()
76
68
if "Du musst das Kästchen anklicken!" in result['data']:
77
69
raise ValueError(result['data'])
@@ -2,7 +2,6 @@ from __future__ import annotations
2
2
3
3
import os
4
4
import re
5
import json
6
5
7
6
from aiohttp import ClientSession
8
7
@@ -23,12 +22,6 @@ class ChatGptt(AsyncGeneratorProvider, ProviderModelMixin):
23
22
default_model = 'gpt-4o'
24
23
models = ['gpt-4', default_model, 'gpt-4o-mini']
25
24
26
@classmethod
27
def get_model(cls, model: str) -> str:
28
if model in cls.models:
29
return model
30
return cls.model_aliases[model]
31
32
25
@classmethod
33
26
async def create_async_generator(
34
27
cls,
@@ -64,7 +57,7 @@ class ChatGptt(AsyncGeneratorProvider, ProviderModelMixin):
64
57
'wpaicg_chat_history': None
65
58
}
66
59
67
async with session.post(cls.api_endpoint, headers=headers, data=payload) as response:
60
async with session.post(cls.api_endpoint, headers=headers, data=payload, proxy=proxy) as response:
68
61
await raise_for_status(response)
69
62
result = await response.json()
70
yield result['data']
63
yield result['data']
@@ -1,15 +1,23 @@
1
1
from __future__ import annotations
2
2
3
from aiohttp import ClientSession, ClientTimeout, ClientError
3
from aiohttp import ClientSession, ClientTimeout
4
4
import json
5
5
import asyncio
6
6
import random
7
7
8
from ..typing import AsyncResult, Messages
8
from ..typing import AsyncResult, Messages, Cookies
9
9
from ..requests.raise_for_status import raise_for_status
10
10
from .base_provider import AsyncGeneratorProvider, ProviderModelMixin
11
11
from .helper import format_prompt
12
from ..providers.response import FinishReason, JsonConversation
12
13
14
class Conversation(JsonConversation):
15
vqd: str = None
16
message_history: Messages = []
17
cookies: dict = {}
18
19
def __init__(self, model: str):
20
self.model = model
13
21
14
22
class DDG(AsyncGeneratorProvider, ProviderModelMixin):
15
23
label = "DuckDuckGo AI Chat"
@@ -74,42 +82,54 @@ class DDG(AsyncGeneratorProvider, ProviderModelMixin):
74
82
messages: Messages,
75
83
proxy: str = None,
76
84
timeout: int = 30,
85
cookies: Cookies = None,
86
conversation: Conversation = None,
87
return_conversation: bool = False,
77
88
**kwargs
78
89
) -> AsyncResult:
79
90
model = cls.get_model(model)
80
81
async with ClientSession(timeout=ClientTimeout(total=timeout)) as session:
82
try:
83
# Fetch VQD token with retries
84
vqd = await cls.fetch_vqd(session)
85
86
headers = {
87
"accept": "text/event-stream",
88
"content-type": "application/json",
89
"x-vqd-4": vqd,
90
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36"
91
}
92
93
data = {
94
"model": model,
95
"messages": [{"role": "user", "content": format_prompt(messages)}],
96
}
97
98
async with session.post(cls.api_endpoint, json=data, headers=headers, proxy=proxy) as response:
99
await raise_for_status(response)
100
async for line in response.content:
101
line = line.decode("utf-8").strip()
102
if line.startswith("data:"):
103
try:
104
message = json.loads(line[5:].strip())
105
if "message" in message:
91
if cookies is None and conversation is not None:
92
cookies = conversation.cookies
93
async with ClientSession(timeout=ClientTimeout(total=timeout), cookies=cookies) as session:
94
# Fetch VQD token
95
if conversation is None:
96
conversation = Conversation(model)
97
conversation.vqd = await cls.fetch_vqd(session)
98
conversation.message_history = [{"role": "user", "content": format_prompt(messages)}]
99
else:
100
conversation.message_history.append(messages[-1])
101
headers = {
102
"accept": "text/event-stream",
103
"content-type": "application/json",
104
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36",
105
"x-vqd-4": conversation.vqd,
106
}
107
data = {
108
"model": model,
109
"messages": conversation.message_history,
110
}
111
async with session.post(cls.api_endpoint, json=data, headers=headers, proxy=proxy) as response:
112
await raise_for_status(response)
113
reason = None
114
full_message = ""
115
async for line in response.content:
116
line = line.decode("utf-8").strip()
117
if line.startswith("data:"):
118
try:
119
message = json.loads(line[5:].strip())
120
if "message" in message:
121
if message["message"]:
106
122
yield message["message"]
107
except json.JSONDecodeError:
108
continue
109
110
except ClientError as e:
111
raise Exception(f"HTTP ClientError occurred: {e}")
112
except asyncio.TimeoutError:
113
raise Exception("Request timed out.")
114
except Exception as e:
115
raise Exception(f"An error occurred: {str(e)}")
123
full_message += message["message"]
124
reason = "length"
125
else:
126
reason = "stop"
127
except json.JSONDecodeError:
128
continue
129
if return_conversation:
130
conversation.message_history.append({"role": "assistant", "content": full_message})
131
conversation.vqd = response.headers.get("x-vqd-4", conversation.vqd)
132
conversation.cookies = {n: c.value for n, c in session.cookie_jar.filter_cookies(cls.url).items()}
133
yield conversation
134
if reason is not None:
135
yield FinishReason(reason)
@@ -48,7 +48,7 @@ class ImageLabs(AsyncGeneratorProvider, ProviderModelMixin):
48
48
}
49
49
50
50
async with ClientSession(headers=headers) as session:
51
prompt = messages[-1]["content"]
51
prompt = messages[-1]["content"] if prompt is None else prompt
52
52
53
53
# Generate image
54
54
payload = {
@@ -46,4 +46,6 @@ class Pizzagpt(AsyncGeneratorProvider, ProviderModelMixin):
46
46
response_json = await response.json()
47
47
content = response_json.get("answer", response_json).get("content")
48
48
if content:
49
if "misuse detected. please get in touch" in content:
50
raise ValueError(content)
49
51
yield content
@@ -11,14 +11,13 @@ from .base_provider import AsyncGeneratorProvider, ProviderModelMixin
11
11
from ..requests.raise_for_status import raise_for_status
12
12
from ..typing import AsyncResult, Messages
13
13
from ..image import ImageResponse
14
from .helper import format_prompt
15
14
16
15
class PollinationsAI(AsyncGeneratorProvider, ProviderModelMixin):
17
16
label = "Pollinations AI"
18
17
url = "https://pollinations.ai"
19
18
20
19
working = True
21
supports_stream = True
20
supports_stream = False
22
21
supports_system_message = True
23
22
supports_message_history = True
24
23
@@ -172,9 +171,9 @@ class PollinationsAI(AsyncGeneratorProvider, ProviderModelMixin):
172
171
params = {k: v for k, v in params.items() if v is not None}
173
172
174
173
async with ClientSession(headers=headers) as session:
175
prompt = quote(messages[-1]["content"] if prompt is None else prompt)
174
prompt = messages[-1]["content"] if prompt is None else prompt
176
175
param_string = "&".join(f"{k}={v}" for k, v in params.items())
177
url = f"{cls.image_api_endpoint}/prompt/{prompt}?{param_string}"
176
url = f"{cls.image_api_endpoint}/prompt/{quote(prompt)}?{param_string}"
178
177
179
178
async with session.head(url, proxy=proxy) as response:
180
179
if response.status == 200:
@@ -1,6 +1,5 @@
1
1
from __future__ import annotations
2
2
3
import asyncio
4
3
import aiohttp
5
4
import json
6
5
import uuid
@@ -9,7 +8,7 @@ import re
9
8
from ...typing import AsyncResult, Messages
10
9
from ..base_provider import AsyncGeneratorProvider, ProviderModelMixin
11
10
from ..helper import format_prompt
12
11
from ... import debug
13
12
14
13
class Qwen_Qwen_2_72B_Instruct(AsyncGeneratorProvider, ProviderModelMixin):
15
14
url = "https://qwen-qwen2-72b-instruct.hf.space"
@@ -49,10 +48,12 @@ class Qwen_Qwen_2_72B_Instruct(AsyncGeneratorProvider, ProviderModelMixin):
49
48
}
50
49
51
50
# Prepare the prompt
51
system_prompt = "\n".join([message["content"] for message in messages if message["role"] == "system"])
52
messages = [message for message in messages if message["role"] != "system"]
52
53
prompt = format_prompt(messages)
53
54
54
55
payload_join = {
55
"data": [prompt, [], ""],
56
"data": [prompt, [], system_prompt],
56
57
"event_data": None,
57
58
"fn_index": 0,
58
59
"trigger_id": 11,
@@ -87,7 +88,7 @@ class Qwen_Qwen_2_72B_Instruct(AsyncGeneratorProvider, ProviderModelMixin):
87
88
if decoded_line.startswith('data: '):
88
89
try:
89
90
json_data = json.loads(decoded_line[6:])
90
91
91
92
# Look for generation stages
92
93
if json_data.get('msg') == 'process_generating':
93
94
if 'output' in json_data and 'data' in json_data['output']:
@@ -97,10 +98,10 @@ class Qwen_Qwen_2_72B_Instruct(AsyncGeneratorProvider, ProviderModelMixin):
97
98
if isinstance(item, list) and len(item) > 1:
98
99
fragment = str(item[1])
99
100
# Ignore [0, 1] type fragments and duplicates
100
if not re.match(r'^\[.*\]$', fragment) and fragment not in full_response:
101
if not re.match(r'^\[.*\]$', fragment) and not full_response.endswith(fragment):
101
102
full_response += fragment
102
103
yield fragment
103
104
104
105
# Check for completion
105
106
if json_data.get('msg') == 'process_completed':
106
107
# Final check to ensure we get the complete response
@@ -117,8 +118,6 @@ class Qwen_Qwen_2_72B_Instruct(AsyncGeneratorProvider, ProviderModelMixin):
117
118
if final_full_response:
118
119
yield final_full_response
119
120
break
120
121
121
122
except json.JSONDecodeError:
122
print("Could not parse JSON:", decoded_line)
123
except Exception as e:
124
print(f"Error processing response: {e}")
123
debug.log("Could not parse JSON:", decoded_line)
@@ -12,4 +12,4 @@ class DeepSeek(OpenaiAPI):
12
12
supports_stream = True
13
13
supports_message_history = True
14
14
default_model = "deepseek-chat"
15
models = [default_model]
15
fallback_models = [default_model]
@@ -136,6 +136,7 @@ class OpenaiAPI(AsyncGeneratorProvider, ProviderModelMixin, RaiseErrorMixin):
136
136
finish = cls.read_finish_reason(choice)
137
137
if finish is not None:
138
138
yield finish
139
break
139
140
140
141
@staticmethod
141
142
def read_finish_reason(choice: dict) -> Optional[FinishReason]: