Niansuh commited on
Commit
ba592f1
·
verified ·
1 Parent(s): efc46e8

Rename api/provider/amigochat.py to api/providers.py

Browse files
Files changed (2) hide show
  1. api/provider/amigochat.py +0 -265
  2. api/providers.py +163 -0
api/provider/amigochat.py DELETED
@@ -1,265 +0,0 @@
1
- import json
2
- import uuid
3
- import asyncio
4
- from aiohttp import ClientSession, ClientTimeout, ClientResponseError
5
- from fastapi import HTTPException
6
- from api.logger import setup_logger
7
- from api.config import MODEL_MAPPING
8
-
9
- logger = setup_logger(__name__)
10
-
11
- # Base URLs
12
- AMIGOCHAT_URL = "https://amigochat.io/chat/"
13
- CHAT_API_ENDPOINT = "https://api.amigochat.io/v1/chat/completions"
14
- IMAGE_API_ENDPOINT = "https://api.amigochat.io/v1/images/generations"
15
-
16
- # List of models supported by AmigoChat
17
- AMIGOCHAT_CHAT_MODELS = [
18
- 'gpt-4o',
19
- 'gpt-4o-mini',
20
- 'o1-preview',
21
- 'o1-mini',
22
- 'meta-llama/Meta-Llama-3.1-405B-Instruct-Turbo',
23
- 'meta-llama/Llama-3.2-90B-Vision-Instruct-Turbo',
24
- 'claude-3-sonnet-20240229',
25
- 'gemini-1.5-pro',
26
- ]
27
-
28
- AMIGOCHAT_IMAGE_MODELS = [
29
- 'flux-pro/v1.1',
30
- 'flux-realism',
31
- 'flux-pro',
32
- 'dalle-e-3',
33
- ]
34
-
35
- AMIGOCHAT_MODELS = AMIGOCHAT_CHAT_MODELS + AMIGOCHAT_IMAGE_MODELS
36
-
37
- AMIGOCHAT_MODEL_ALIASES = {
38
- "o1": "o1-preview",
39
- "llama-3.1-405b": "meta-llama/Meta-Llama-3.1-405B-Instruct-Turbo",
40
- "llama-3.2-90b": "meta-llama/Llama-3.2-90B-Vision-Instruct-Turbo",
41
- "claude-3.5-sonnet": "claude-3-sonnet-20240229",
42
- "gemini-pro": "gemini-1.5-pro",
43
- "dalle-3": "dalle-e-3",
44
- }
45
-
46
- PERSONA_IDS = {
47
- 'gpt-4o': "gpt",
48
- 'gpt-4o-mini': "amigo",
49
- 'o1-preview': "openai-o-one",
50
- 'o1-mini': "openai-o-one-mini",
51
- 'meta-llama/Meta-Llama-3.1-405B-Instruct-Turbo': "llama-three-point-one",
52
- 'meta-llama/Llama-3.2-90B-Vision-Instruct-Turbo': "llama-3-2",
53
- 'claude-3-sonnet-20240229': "claude",
54
- 'gemini-1.5-pro': "gemini-1-5-pro",
55
- 'flux-pro/v1.1': "flux-1-1-pro",
56
- 'flux-realism': "flux-realism",
57
- 'flux-pro': "flux-pro",
58
- 'dalle-e-3': "dalle-three",
59
- }
60
-
61
- def get_amigochat_model(model: str) -> str:
62
- model = MODEL_MAPPING.get(model, model)
63
- if model in AMIGOCHAT_MODELS:
64
- return model
65
- elif model in AMIGOCHAT_MODEL_ALIASES:
66
- return AMIGOCHAT_MODEL_ALIASES[model]
67
- else:
68
- # Default model
69
- return 'gpt-4o-mini'
70
-
71
- def get_persona_id(model: str) -> str:
72
- return PERSONA_IDS.get(model, "amigo")
73
-
74
- def is_image_model(model: str) -> bool:
75
- return model in AMIGOCHAT_IMAGE_MODELS
76
-
77
- async def process_streaming_response(request_data):
78
- model = get_amigochat_model(request_data.get('model'))
79
- messages = request_data.get('messages')
80
- stream = request_data.get('stream', False)
81
- if not messages:
82
- raise HTTPException(status_code=400, detail="Messages are required")
83
-
84
- device_uuid = str(uuid.uuid4())
85
-
86
- headers = {
87
- "accept": "*/*",
88
- "accept-language": "en-US,en;q=0.9",
89
- "authorization": "Bearer",
90
- "cache-control": "no-cache",
91
- "content-type": "application/json",
92
- "origin": AMIGOCHAT_URL,
93
- "pragma": "no-cache",
94
- "priority": "u=1, i",
95
- "referer": f"{AMIGOCHAT_URL}/",
96
- "sec-ch-ua": '"Chromium";v="129", "Not=A?Brand";v="8"',
97
- "sec-ch-ua-mobile": "?0",
98
- "sec-ch-ua-platform": '"Linux"',
99
- "user-agent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.0.0 Safari/537.36",
100
- "x-device-language": "en-US",
101
- "x-device-platform": "web",
102
- "x-device-uuid": device_uuid,
103
- "x-device-version": "1.0.32"
104
- }
105
-
106
- async with ClientSession(headers=headers) as session:
107
- if is_image_model(model):
108
- # Image generation does not support streaming
109
- response = await process_non_streaming_response(request_data)
110
- return iter([json.dumps(response)])
111
- else:
112
- # Chat completion
113
- data = {
114
- "messages": [{"role": m["role"], "content": m["content"]} for m in messages],
115
- "model": model,
116
- "personaId": get_persona_id(model),
117
- "frequency_penalty": 0,
118
- "max_tokens": 4000,
119
- "presence_penalty": 0,
120
- "stream": True,
121
- "temperature": 0.5,
122
- "top_p": 0.95
123
- }
124
-
125
- timeout = ClientTimeout(total=300) # 5 minutes timeout
126
-
127
- async def event_stream():
128
- try:
129
- async with session.post(CHAT_API_ENDPOINT, json=data, timeout=timeout) as resp:
130
- if resp.status not in (200, 201):
131
- error_text = await resp.text()
132
- raise HTTPException(status_code=resp.status, detail=error_text)
133
-
134
- async for line in resp.content:
135
- line = line.decode('utf-8').strip()
136
- if line.startswith('data: '):
137
- if line == 'data: [DONE]':
138
- break
139
- try:
140
- chunk = json.loads(line[6:]) # Remove 'data: ' prefix
141
- if 'choices' in chunk and len(chunk['choices']) > 0:
142
- choice = chunk['choices'][0]
143
- delta = choice.get('delta', {})
144
- content = delta.get('content')
145
- if content:
146
- # Yield the chunk in OpenAI format
147
- response_data = {
148
- "id": f"chatcmpl-{uuid.uuid4()}",
149
- "object": "chat.completion.chunk",
150
- "created": int(datetime.now().timestamp()),
151
- "model": model,
152
- "choices": [
153
- {
154
- "delta": {"content": content},
155
- "index": 0,
156
- "finish_reason": None,
157
- }
158
- ],
159
- }
160
- yield f"data: {json.dumps(response_data)}\n\n"
161
- except json.JSONDecodeError:
162
- pass
163
- # Signal the end of the stream
164
- yield "data: [DONE]\n\n"
165
- except Exception as e:
166
- logger.error(f"Error in streaming response: {e}")
167
- raise HTTPException(status_code=500, detail=str(e))
168
-
169
- return event_stream()
170
-
171
- async def process_non_streaming_response(request_data):
172
- model = get_amigochat_model(request_data.get('model'))
173
- messages = request_data.get('messages')
174
- if not messages:
175
- raise HTTPException(status_code=400, detail="Messages are required")
176
-
177
- device_uuid = str(uuid.uuid4())
178
-
179
- headers = {
180
- "accept": "*/*",
181
- "accept-language": "en-US,en;q=0.9",
182
- "authorization": "Bearer",
183
- "cache-control": "no-cache",
184
- "content-type": "application/json",
185
- "origin": AMIGOCHAT_URL,
186
- "pragma": "no-cache",
187
- "priority": "u=1, i",
188
- "referer": f"{AMIGOCHAT_URL}/",
189
- "sec-ch-ua": '"Chromium";v="129", "Not=A?Brand";v="8"',
190
- "sec-ch-ua-mobile": "?0",
191
- "sec-ch-ua-platform": '"Linux"',
192
- "user-agent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.0.0 Safari/537.36",
193
- "x-device-language": "en-US",
194
- "x-device-platform": "web",
195
- "x-device-uuid": device_uuid,
196
- "x-device-version": "1.0.32"
197
- }
198
-
199
- async with ClientSession(headers=headers) as session:
200
- if is_image_model(model):
201
- # Image generation
202
- prompt = messages[-1]['content']
203
- data = {
204
- "prompt": prompt,
205
- "model": model,
206
- "personaId": get_persona_id(model)
207
- }
208
- try:
209
- async with session.post(IMAGE_API_ENDPOINT, json=data) as response:
210
- response.raise_for_status()
211
- response_data = await response.json()
212
- if "data" in response_data:
213
- image_urls = []
214
- for item in response_data["data"]:
215
- if "url" in item:
216
- image_url = item["url"]
217
- image_urls.append(image_url)
218
- if image_urls:
219
- return {
220
- "id": f"imggen-{uuid.uuid4()}",
221
- "object": "image_generation",
222
- "created": int(datetime.now().timestamp()),
223
- "model": model,
224
- "data": image_urls,
225
- }
226
- raise HTTPException(status_code=500, detail="Image generation failed")
227
- except Exception as e:
228
- logger.error(f"Error in image generation: {e}")
229
- raise HTTPException(status_code=500, detail=str(e))
230
- else:
231
- # Chat completion
232
- data = {
233
- "messages": [{"role": m["role"], "content": m["content"]} for m in messages],
234
- "model": model,
235
- "personaId": get_persona_id(model),
236
- "frequency_penalty": 0,
237
- "max_tokens": 4000,
238
- "presence_penalty": 0,
239
- "stream": False,
240
- "temperature": 0.5,
241
- "top_p": 0.95
242
- }
243
-
244
- try:
245
- async with session.post(CHAT_API_ENDPOINT, json=data) as response:
246
- response.raise_for_status()
247
- response_data = await response.json()
248
- output = response_data.get('choices', [{}])[0].get('message', {}).get('content', '')
249
- return {
250
- "id": f"chatcmpl-{uuid.uuid4()}",
251
- "object": "chat.completion",
252
- "created": int(datetime.now().timestamp()),
253
- "model": model,
254
- "choices": [
255
- {
256
- "index": 0,
257
- "message": {"role": "assistant", "content": output},
258
- "finish_reason": "stop",
259
- }
260
- ],
261
- "usage": None,
262
- }
263
- except Exception as e:
264
- logger.error(f"Error in chat completion: {e}")
265
- raise HTTPException(status_code=500, detail=str(e))
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
api/providers.py ADDED
@@ -0,0 +1,163 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # api/providers.py
2
+
3
+ from __future__ import annotations
4
+
5
+ import json
6
+ import uuid
7
+ from aiohttp import ClientSession, ClientTimeout, ClientResponseError
8
+
9
+ from typing import AsyncGenerator, List, Dict, Any
10
+ from api.models import Message
11
+ from api.image import ImageResponse
12
+
13
+ class AmigoChat:
14
+ url = "https://amigochat.io"
15
+ chat_api_endpoint = "https://api.amigochat.io/v1/chat/completions"
16
+ image_api_endpoint = "https://api.amigochat.io/v1/images/generations"
17
+ default_model = 'gpt-4o-mini'
18
+
19
+ chat_models = [
20
+ 'gpt-4o',
21
+ default_model,
22
+ 'o1-preview',
23
+ 'o1-mini',
24
+ 'meta-llama/Meta-Llama-3.1-405B-Instruct-Turbo',
25
+ 'meta-llama/Llama-3.2-90B-Vision-Instruct-Turbo',
26
+ 'claude-3-sonnet-20240229',
27
+ 'gemini-1.5-pro',
28
+ ]
29
+
30
+ image_models = [
31
+ 'flux-pro/v1.1',
32
+ 'flux-realism',
33
+ 'flux-pro',
34
+ 'dalle-e-3',
35
+ ]
36
+
37
+ models = chat_models + image_models
38
+
39
+ model_aliases = {
40
+ "o1": "o1-preview",
41
+ "llama-3.1-405b": "meta-llama/Meta-Llama-3.1-405B-Instruct-Turbo",
42
+ "llama-3.2-90b": "meta-llama/Llama-3.2-90B-Vision-Instruct-Turbo",
43
+ "claude-3.5-sonnet": "claude-3-sonnet-20240229",
44
+ "gemini-pro": "gemini-1.5-pro",
45
+ "flux-pro": "flux-pro/v1.1",
46
+ "dalle-3": "dalle-e-3",
47
+ }
48
+
49
+ persona_ids = {
50
+ 'gpt-4o': "gpt",
51
+ 'gpt-4o-mini': "amigo",
52
+ 'o1-preview': "openai-o-one",
53
+ 'o1-mini': "openai-o-one-mini",
54
+ 'meta-llama/Meta-Llama-3.1-405B-Instruct-Turbo': "llama-three-point-one",
55
+ 'meta-llama/Llama-3.2-90B-Vision-Instruct-Turbo': "llama-3-2",
56
+ 'claude-3-sonnet-20240229': "claude",
57
+ 'gemini-1.5-pro': "gemini-1-5-pro",
58
+ 'flux-pro/v1.1': "flux-1-1-pro",
59
+ 'flux-realism': "flux-realism",
60
+ 'flux-pro': "flux-pro",
61
+ 'dalle-e-3': "dalle-three",
62
+ }
63
+
64
+ @classmethod
65
+ def get_model(cls, model: str) -> str:
66
+ return cls.model_aliases.get(model, model if model in cls.models else cls.default_model)
67
+
68
+ @classmethod
69
+ def get_persona_id(cls, model: str) -> str:
70
+ return cls.persona_ids.get(model, "amigo")
71
+
72
+ @classmethod
73
+ async def generate_response(
74
+ cls,
75
+ model: str,
76
+ messages: List[Dict[str, Any]],
77
+ stream: bool = False,
78
+ proxy: str = None,
79
+ ) -> AsyncGenerator[str, None]:
80
+ model = cls.get_model(model)
81
+ device_uuid = str(uuid.uuid4())
82
+
83
+ headers = {
84
+ "accept": "*/*",
85
+ "accept-language": "en-US,en;q=0.9",
86
+ "authorization": "Bearer",
87
+ "cache-control": "no-cache",
88
+ "content-type": "application/json",
89
+ "origin": cls.url,
90
+ "pragma": "no-cache",
91
+ "priority": "u=1, i",
92
+ "referer": f"{cls.url}/",
93
+ "sec-ch-ua": '"Chromium";v="129", "Not=A?Brand";v="8"',
94
+ "sec-ch-ua-mobile": "?0",
95
+ "sec-ch-ua-platform": '"Linux"',
96
+ "user-agent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.0.0 Safari/537.36",
97
+ "x-device-language": "en-US",
98
+ "x-device-platform": "web",
99
+ "x-device-uuid": device_uuid,
100
+ "x-device-version": "1.0.32"
101
+ }
102
+
103
+ async with ClientSession(headers=headers) as session:
104
+ if model in cls.chat_models:
105
+ # Chat completion
106
+ data = {
107
+ "messages": messages,
108
+ "model": model,
109
+ "personaId": cls.get_persona_id(model),
110
+ "frequency_penalty": 0,
111
+ "max_tokens": 4000,
112
+ "presence_penalty": 0,
113
+ "stream": stream,
114
+ "temperature": 0.5,
115
+ "top_p": 0.95
116
+ }
117
+
118
+ timeout = ClientTimeout(total=300)
119
+ async with session.post(cls.chat_api_endpoint, json=data, proxy=proxy, timeout=timeout) as response:
120
+ if response.status not in (200, 201):
121
+ error_text = await response.text()
122
+ raise Exception(f"Error {response.status}: {error_text}")
123
+
124
+ if stream:
125
+ async for line in response.content:
126
+ line = line.decode('utf-8').strip()
127
+ if line.startswith('data: '):
128
+ if line == 'data: [DONE]':
129
+ break
130
+ try:
131
+ chunk = json.loads(line[6:])
132
+ if 'choices' in chunk and len(chunk['choices']) > 0:
133
+ choice = chunk['choices'][0]
134
+ if 'delta' in choice:
135
+ content = choice['delta'].get('content')
136
+ elif 'text' in choice:
137
+ content = choice['text']
138
+ else:
139
+ content = None
140
+ if content:
141
+ yield content
142
+ except json.JSONDecodeError:
143
+ pass
144
+ else:
145
+ response_data = await response.json()
146
+ if 'choices' in response_data and len(response_data['choices']) > 0:
147
+ content = response_data['choices'][0]['message']['content']
148
+ yield content
149
+ else:
150
+ # Image generation
151
+ prompt = messages[-1]['content']
152
+ data = {
153
+ "prompt": prompt,
154
+ "model": model,
155
+ "personaId": cls.get_persona_id(model)
156
+ }
157
+ async with session.post(cls.image_api_endpoint, json=data, proxy=proxy) as response:
158
+ response.raise_for_status()
159
+ response_data = await response.json()
160
+ if "data" in response_data:
161
+ image_urls = [item["url"] for item in response_data["data"] if "url" in item]
162
+ if image_urls:
163
+ yield ImageResponse(image_urls, prompt)