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)