|
from flask import Flask, request, Response, jsonify, stream_with_context
|
|
import requests
|
|
import json
|
|
import uuid
|
|
import time
|
|
|
|
app = Flask(__name__)
|
|
|
|
@app.route('/v1/chat/completions', methods=['POST'])
|
|
def chat_completions():
|
|
auth_header = request.headers.get('Authorization', '')
|
|
if auth_header.startswith('Bearer '):
|
|
token = auth_header[7:]
|
|
else:
|
|
return jsonify({"error": "Authorization header must be a Bearer token"}), 401
|
|
|
|
try:
|
|
openai_request = request.json
|
|
messages = openai_request.get('messages', [])
|
|
|
|
user_message = ""
|
|
for msg in reversed(messages):
|
|
if msg.get('role') == 'user':
|
|
user_message = msg.get('content', '')
|
|
break
|
|
|
|
if not user_message:
|
|
return jsonify({"error": "No user message found"}), 400
|
|
|
|
yun_api_url = 'https://ai.yun.139.com/api/outer/assistant/chat/add'
|
|
|
|
yun_headers = {
|
|
'User-Agent': 'Mozilla/5.0 (Linux; Android 14; 23049RAD8C Build/UKQ1.230804.001; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/118.0.0.0 Mobile Safari/537.36 MCloudApp/11.4.4',
|
|
'Accept': 'text/event-stream',
|
|
'Content-Type': 'application/json',
|
|
'sec-ch-ua': '"Chromium";v="118", "Android WebView";v="118", "Not=A?Brand";v="99"',
|
|
'x-yun-app-channel': '101',
|
|
'sec-ch-ua-mobile': '?1',
|
|
'authorization': f'Basic {token}',
|
|
'x-yun-api-version': 'v4',
|
|
'sec-ch-ua-platform': '"Android"',
|
|
'origin': 'https://yun.139.com',
|
|
'x-requested-with': 'com.chinamobile.mcloud',
|
|
'sec-fetch-site': 'same-site',
|
|
'sec-fetch-mode': 'cors',
|
|
'sec-fetch-dest': 'empty',
|
|
'referer': 'https://yun.139.com/',
|
|
'accept-language': 'zh,zh-CN;q=0.9,en-US;q=0.8,en;q=0.7'
|
|
}
|
|
|
|
yun_data = {
|
|
"userId": "",
|
|
"sessionId": "",
|
|
"content": {
|
|
"dialogue": user_message,
|
|
"prompt": "",
|
|
"commands": "",
|
|
"resourceType": "0",
|
|
"resourceId": "",
|
|
"dialogueType": "0",
|
|
"sourceChannel": "101",
|
|
"extInfo": "{\"h5Version\":\"1.7.4\"}"
|
|
},
|
|
"applicationType": "chat",
|
|
"applicationId": ""
|
|
}
|
|
|
|
stream_mode = openai_request.get('stream', False)
|
|
|
|
if stream_mode:
|
|
def generate():
|
|
response_id = f"chatcmpl-{str(uuid.uuid4())}"
|
|
start_time = time.time()
|
|
|
|
response = requests.post(yun_api_url, headers=yun_headers, json=yun_data, stream=True)
|
|
|
|
collected_text = ""
|
|
for line in response.iter_lines():
|
|
if line:
|
|
line_text = line.decode('utf-8')
|
|
if line_text.startswith('data:'):
|
|
data_json = json.loads(line_text[5:].strip())
|
|
if 'content' in data_json:
|
|
delta_text = data_json['content']
|
|
collected_text += delta_text
|
|
|
|
chunk = {
|
|
"id": response_id,
|
|
"object": "chat.completion.chunk",
|
|
"created": int(time.time()),
|
|
"model": "DeepSeek-R1",
|
|
"choices": [
|
|
{
|
|
"index": 0,
|
|
"delta": {
|
|
"content": delta_text
|
|
},
|
|
"finish_reason": None
|
|
}
|
|
]
|
|
}
|
|
|
|
yield f"data: {json.dumps(chunk)}\n\n"
|
|
|
|
final_chunk = {
|
|
"id": response_id,
|
|
"object": "chat.completion.chunk",
|
|
"created": int(time.time()),
|
|
"model": "DeepSeek-R1",
|
|
"choices": [
|
|
{
|
|
"index": 0,
|
|
"delta": {},
|
|
"finish_reason": "stop"
|
|
}
|
|
]
|
|
}
|
|
yield f"data: {json.dumps(final_chunk)}\n\n"
|
|
yield "data: [DONE]\n\n"
|
|
|
|
return Response(stream_with_context(generate()), content_type='text/event-stream')
|
|
|
|
else:
|
|
response = requests.post(yun_api_url, headers=yun_headers, json=yun_data)
|
|
response_data = response.json()
|
|
|
|
assistant_message = ""
|
|
if 'data' in response_data and 'content' in response_data['data']:
|
|
assistant_message = response_data['data']['content']
|
|
|
|
openai_response = {
|
|
"id": f"chatcmpl-{str(uuid.uuid4())}",
|
|
"object": "chat.completion",
|
|
"created": int(time.time()),
|
|
"model": "DeepSeek-R1",
|
|
"choices": [
|
|
{
|
|
"index": 0,
|
|
"message": {
|
|
"role": "assistant",
|
|
"content": assistant_message
|
|
},
|
|
"finish_reason": "stop"
|
|
}
|
|
],
|
|
"usage": {
|
|
"prompt_tokens": len(user_message),
|
|
"completion_tokens": len(assistant_message),
|
|
"total_tokens": len(user_message) + len(assistant_message)
|
|
}
|
|
}
|
|
|
|
return jsonify(openai_response)
|
|
|
|
except Exception as e:
|
|
return jsonify({"error": str(e)}), 500
|
|
|
|
@app.route('/v1/models', methods=['GET'])
|
|
def list_models():
|
|
models = {
|
|
"object": "list",
|
|
"data": [
|
|
{
|
|
"id": "DeepSeek-R1",
|
|
"object": "model",
|
|
"created": int(time.time()),
|
|
"owned_by": "139.com"
|
|
}
|
|
]
|
|
}
|
|
return jsonify(models)
|
|
|
|
if __name__ == '__main__':
|
|
app.run(host='0.0.0.0', port=8080, debug=True) |