File size: 7,902 Bytes
ef881c7
 
 
 
 
 
 
 
 
 
 
 
 
 
e406d5a
9c93dcd
ef881c7
 
e406d5a
ef881c7
e406d5a
ef881c7
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
e406d5a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
ef881c7
e406d5a
 
 
 
 
 
 
 
 
 
 
 
 
ef881c7
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
e406d5a
ef881c7
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
e406d5a
ef881c7
 
e406d5a
 
 
ef881c7
 
e406d5a
ef881c7
e406d5a
ef881c7
e406d5a
 
 
ef881c7
 
e406d5a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
ef881c7
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
import json
import time
import hashlib
import base64
import asyncio
import aiohttp
from fastapi import FastAPI, Request, Response
from typing import Optional, Dict, List, Any
import uvicorn
from pydantic import BaseModel

# Configuration
API_CHALLENGE_URL = 'https://api.eqing.tech/api/altcaptcha/challenge'
NEXTWAY_CHAT_URL = 'https://origin.eqing.tech/api/openai/v1/chat/completions'
CREDENTIAL_EXPIRY_MARGIN = 60 * 1000
PORT = 7860
API_ENDPOINT = '/v1/chat/completions'
MODEL_NAME = "gpt-4o-free"
REQUEST_TIMEOUT = 480
MAX_RETRIES = 3
RETRY_DELAY = 1

# Global variables
current_credential = None
credential_expiry = None
is_refreshing_credential = False

MODEL_MAPPING = {
    'gpt-4o-all-lite': 'gpt-4o-mini',
    'gpt-4o-image': 'gpt-4o-mini-image-free',
    'grok-3-re': 'grok-3-free',
    'gemini-2.0-flash': 'gemini-2.0-flash-free'
}

app = FastAPI()

class ChatRequest(BaseModel):
    messages: List[Dict[str, str]]
    model: Optional[str]
    stream: Optional[bool] = True
    temperature: Optional[float] = 0.5
    presence_penalty: Optional[float] = 0
    frequency_penalty: Optional[float] = 0
    top_p: Optional[float] = 1
    max_tokens: Optional[int] = 4000

async def extract_streaming_content(response):
    buffer = ""
    complete_response = ""
    async for chunk in response.content:
        buffer += chunk.decode()
        lines = buffer.split('\n')
        
        # Process complete lines
        for line in lines[:-1]:
            line = line.strip()
            if line.startswith('data: '):
                content = process_data_line(line[5:].strip())
                if content:
                    complete_response += content
        
        # Keep the last incomplete line in buffer
        buffer = lines[-1] if lines else ""
    
    # Process any remaining data
    if buffer:
        line = buffer.strip()
        if line.startswith('data: '):
            content = process_data_line(line[5:].strip())
            if content:
                complete_response += content
    
    return complete_response

def process_data_line(data_str: str) -> str:
    if not data_str or data_str in ['[ORIGIN]', '[DONE]']:
        return ''
    
    try:
        json_data = json.loads(data_str)
        if (json_data.get('choices') and 
            json_data['choices'][0].get('delta') and 
            'content' in json_data['choices'][0]['delta']):
            return json_data['choices'][0]['delta']['content']
    except json.JSONDecodeError:
        print(f'Invalid JSON data: {data_str}')
    return ''

async def solve_challenge(challenge: str, salt: str, algorithm: str = "SHA-512", max_number: int = 1000000):
    start_time = time.time()
    
    for number in range(max_number):
        hash_value = await verify_hash(salt, number, algorithm)
        if hash_value == challenge:
            return {"number": number, "took": int((time.time() - start_time) * 1000)}
    
    return None

async def verify_hash(salt: str, number: int, algorithm: str) -> str:
    input_str = f"{salt}{number}"
    
    if algorithm == "SHA-512":
        hash_obj = hashlib.sha512(input_str.encode())
        return hash_obj.hexdigest()
    elif algorithm == "SHA-256":
        hash_obj = hashlib.sha256(input_str.encode())
        return hash_obj.hexdigest()
    else:
        raise ValueError(f"Unsupported algorithm: {algorithm}")

async def generate_credential():
    global current_credential, credential_expiry
    
    async with aiohttp.ClientSession() as session:
        try:
            async with session.get(API_CHALLENGE_URL) as response:
                if response.status != 200:
                    print(f"Challenge request failed with status {response.status}")
                    return None
                
                data = await response.json()
                solution = await solve_challenge(
                    data['challenge'],
                    data['salt'],
                    data['algorithm'],
                    data['maxnumber']
                )

                if not solution:
                    print("Failed to solve challenge")
                    return None

                credential_obj = {
                    "algorithm": data['algorithm'],
                    "challenge": data['challenge'],
                    "number": solution['number'],
                    "salt": data['salt'],
                    "signature": data['signature'],
                    "took": solution['took']
                }

                credential = base64.b64encode(json.dumps(credential_obj).encode()).decode()
                expiry = int(data['salt'].split('?expires=')[1]) * 1000

                return {"credential": credential, "expiry": expiry}

        except Exception as e:
            print(f"Error generating credential: {e}")
            return None

async def get_credential():
    global current_credential, credential_expiry, is_refreshing_credential
    
    if (not current_credential or 
        not credential_expiry or 
        credential_expiry <= time.time() * 1000 + CREDENTIAL_EXPIRY_MARGIN):
        
        if not is_refreshing_credential:
            is_refreshing_credential = True
            try:
                cred_data = await generate_credential()
                if cred_data:
                    current_credential = cred_data['credential']
                    credential_expiry = cred_data['expiry']
            finally:
                is_refreshing_credential = False
        else:
            await asyncio.sleep(2)
    
    return current_credential

async def handle_chat_request(model: str, messages: List[Dict[str, str]], retries=0):
    captcha_token = await get_credential()
    if not captcha_token:
        return None

    body = {
        "messages": messages,
        "stream": True,
        "model": model,
        "temperature": 0.5,
        "presence_penalty": 0,
        "frequency_penalty": 0,
        "top_p": 1,
        "max_tokens": 4000,
        "captchaToken": captcha_token
    }

    async with aiohttp.ClientSession() as session:
        try:
            async with session.post(
                NEXTWAY_CHAT_URL,
                json=body,
                timeout=aiohttp.ClientTimeout(total=REQUEST_TIMEOUT)
            ) as response:
                if response.status != 200:
                    if retries < MAX_RETRIES:
                        await asyncio.sleep(RETRY_DELAY)
                        return await handle_chat_request(model, messages, retries + 1)
                    return None

                return await extract_streaming_content(response)

        except (aiohttp.ClientError, asyncio.TimeoutError) as e:
            print(f"Error in chat request: {e}")
            if retries < MAX_RETRIES:
                await asyncio.sleep(RETRY_DELAY)
                return await handle_chat_request(model, messages, retries + 1)
            return None

@app.post(API_ENDPOINT)
async def chat_endpoint(request: ChatRequest):
    try:
        model = MODEL_MAPPING.get(request.model, request.model or MODEL_NAME)
        response_content = await handle_chat_request(model, request.messages)
        
        if response_content is None:
            return Response(
                content="Failed to get response from API",
                status_code=500
            )

        return {
            "choices": [{
                "message": {
                    "role": "assistant",
                    "content": response_content.strip()
                },
                "finish_reason": "stop",
                "index": 0
            }],
            "model": model,
            "object": "chat.completion"
        }

    except Exception as e:
        print(f"Error handling chat request: {e}")
        return Response(content="Internal server error", status_code=500)

if __name__ == "__main__":
    uvicorn.run(app, host="0.0.0.0", port=PORT)