| from flask import Flask, request, jsonify, Response, render_template_string, render_template, redirect, url_for, session as flask_session |
| import requests |
| import time |
| import json |
| import uuid |
| import random |
| import io |
| import re |
| from functools import wraps |
| import hashlib |
| import jwt |
| import os |
| import threading |
| from datetime import datetime, timedelta |
|
|
| app = Flask(__name__, template_folder='templates') |
| app.secret_key = os.environ.get("SECRET_KEY", "abacus_chat_proxy_secret_key") |
| app.config['PERMANENT_SESSION_LIFETIME'] = timedelta(days=7) |
|
|
| |
| TOKENIZER_SERVICE_URL = "https://malt666-tokenizer.hf.space/count_tokens" |
|
|
| API_ENDPOINT_URL = "https://abacus.ai/api/v0/describeDeployment" |
| MODEL_LIST_URL = "https://abacus.ai/api/v0/listExternalApplications" |
| CHAT_URL = "https://apps.abacus.ai/api/_chatLLMSendMessageSSE" |
| USER_INFO_URL = "https://abacus.ai/api/v0/_getUserInfo" |
| COMPUTE_POINTS_URL = "https://apps.abacus.ai/api/_getOrganizationComputePoints" |
| COMPUTE_POINTS_LOG_URL = "https://abacus.ai/api/v0/_getOrganizationComputePointLog" |
| CREATE_CONVERSATION_URL = "https://apps.abacus.ai/api/createDeploymentConversation" |
| DELETE_CONVERSATION_URL = "https://apps.abacus.ai/api/deleteDeploymentConversation" |
| GET_CONVERSATION_URL = "https://apps.abacus.ai/api/getDeploymentConversation" |
| COMPUTE_POINT_TOGGLE_URL = "https://abacus.ai/api/v0/_updateOrganizationComputePointToggle" |
|
|
|
|
| USER_AGENTS = [ |
| "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36" |
| ] |
|
|
|
|
| PASSWORD = None |
| USER_NUM = 0 |
| USER_DATA = [] |
| CURRENT_USER = -1 |
| MODELS = set() |
|
|
| |
| LAST_CONVERSATION_IDS = [None] * 100 |
| DELETE_CHAT = True |
|
|
| TRACE_ID = "3042e28b3abf475d8d973c7e904935af" |
| SENTRY_TRACE = f"{TRACE_ID}-80d9d2538b2682d0" |
|
|
|
|
| |
| health_check_counter = 0 |
|
|
|
|
| |
| model_usage_stats = {} |
| total_tokens = { |
| "prompt": 0, |
| "completion": 0, |
| "total": 0 |
| } |
|
|
| |
| model_usage_records = [] |
| MODEL_USAGE_RECORDS_FILE = "model_usage_records.json" |
|
|
| |
| compute_points = { |
| "left": 0, |
| "total": 0, |
| "used": 0, |
| "percentage": 0, |
| "last_update": None |
| } |
|
|
| |
| compute_points_log = { |
| "columns": {}, |
| "log": [] |
| } |
|
|
| |
| users_compute_points = [] |
|
|
| |
| START_TIME = datetime.utcnow() + timedelta(hours=8) |
|
|
|
|
| |
| class DateTimeEncoder(json.JSONEncoder): |
| def default(self, obj): |
| if isinstance(obj, datetime): |
| return obj.strftime('%Y-%m-%d %H:%M:%S') |
| return super(DateTimeEncoder, self).default(obj) |
|
|
|
|
| |
| def load_model_usage_records(): |
| global model_usage_records |
| try: |
| if os.path.exists(MODEL_USAGE_RECORDS_FILE): |
| with open(MODEL_USAGE_RECORDS_FILE, 'r', encoding='utf-8') as f: |
| records = json.load(f) |
| if isinstance(records, list): |
| model_usage_records = records |
| print(f"成功加载 {len(model_usage_records)} 条模型调用记录") |
| else: |
| print("调用记录文件格式不正确,初始化为空列表") |
| except Exception as e: |
| print(f"加载模型调用记录失败: {e}") |
| model_usage_records = [] |
|
|
| |
| def save_model_usage_records(): |
| try: |
| with open(MODEL_USAGE_RECORDS_FILE, 'w', encoding='utf-8') as f: |
| json.dump(model_usage_records, f, ensure_ascii=False, indent=2, cls=DateTimeEncoder) |
| print(f"成功保存 {len(model_usage_records)} 条模型调用记录") |
| except Exception as e: |
| print(f"保存模型调用记录失败: {e}") |
|
|
|
|
| def update_conversation_id(user_index, conversation_id): |
| """更新用户的conversation_id并保存到配置文件""" |
| try: |
| with open("config.json", "r") as f: |
| config = json.load(f) |
| |
| if "config" in config and user_index < len(config["config"]): |
| config["config"][user_index]["conversation_id"] = conversation_id |
| |
| |
| with open("config.json", "w") as f: |
| json.dump(config, f, indent=4) |
| |
| print(f"已将用户 {user_index+1} 的conversation_id更新为: {conversation_id}") |
| else: |
| print(f"更新conversation_id失败: 配置文件格式错误或用户索引越界") |
| except Exception as e: |
| print(f"更新conversation_id失败: {e}") |
|
|
|
|
| def resolve_config(): |
| |
| config_list = [] |
| i = 1 |
| while True: |
| cookie = os.environ.get(f"cookie_{i}") |
| if not cookie: |
| break |
| |
| |
| config_list.append({ |
| "conversation_id": "", |
| "cookies": cookie |
| }) |
| i += 1 |
| |
| |
| if config_list: |
| print(f"从环境变量加载了 {len(config_list)} 个配置") |
| return config_list |
| |
| |
| try: |
| with open("config.json", "r") as f: |
| config = json.load(f) |
| config_list = config.get("config") |
| return config_list |
| except FileNotFoundError: |
| print("未找到config.json文件") |
| return [] |
| except json.JSONDecodeError: |
| print("config.json格式错误") |
| return [] |
|
|
|
|
| def get_password(): |
| global PASSWORD |
| |
| env_password = os.environ.get("password") |
| if env_password: |
| PASSWORD = hashlib.sha256(env_password.encode()).hexdigest() |
| return |
|
|
| |
| try: |
| with open("password.txt", "r") as f: |
| PASSWORD = f.read().strip() |
| except FileNotFoundError: |
| with open("password.txt", "w") as f: |
| PASSWORD = None |
|
|
|
|
| def require_auth(f): |
| @wraps(f) |
| def decorated(*args, **kwargs): |
| if not PASSWORD: |
| return f(*args, **kwargs) |
| |
| |
| if flask_session.get('logged_in'): |
| return f(*args, **kwargs) |
| |
| |
| auth = request.authorization |
| if not auth or not check_auth(auth.token): |
| |
| if request.headers.get('Accept', '').find('text/html') >= 0: |
| return redirect(url_for('login')) |
| return jsonify({"error": "Unauthorized access"}), 401 |
| return f(*args, **kwargs) |
|
|
| return decorated |
|
|
|
|
| def check_auth(token): |
| return hashlib.sha256(token.encode()).hexdigest() == PASSWORD |
|
|
|
|
| def is_token_expired(token): |
| if not token: |
| return True |
| |
| try: |
| |
| payload = jwt.decode(token, options={"verify_signature": False}) |
| |
| return payload.get('exp', 0) - time.time() < 300 |
| except: |
| return True |
|
|
|
|
| def refresh_token(session, cookies): |
| """Uzu kuketon por refreŝigi session token, nur revenigu novan tokenon""" |
| headers = { |
| "accept": "application/json, text/plain, */*", |
| "accept-language": "zh-CN,zh;q=0.9", |
| "content-type": "application/json", |
| "reai-ui": "1", |
| "sec-ch-ua": "\"Chromium\";v=\"116\", \"Not)A;Brand\";v=\"24\", \"Google Chrome\";v=\"116\"", |
| "sec-ch-ua-mobile": "?0", |
| "sec-ch-ua-platform": "\"Windows\"", |
| "sec-fetch-dest": "empty", |
| "sec-fetch-mode": "cors", |
| "sec-fetch-site": "same-site", |
| "x-abacus-org-host": "apps", |
| "user-agent": random.choice(USER_AGENTS), |
| "origin": "https://apps.abacus.ai", |
| "referer": "https://apps.abacus.ai/", |
| "cookie": cookies |
| } |
| |
| try: |
| response = session.post( |
| USER_INFO_URL, |
| headers=headers, |
| json={}, |
| cookies=None |
| ) |
| |
| if response.status_code == 200: |
| response_data = response.json() |
| if response_data.get('success') and 'sessionToken' in response_data.get('result', {}): |
| return response_data['result']['sessionToken'] |
| else: |
| print(f"刷新token失败: {response_data.get('error', '未知错误')}") |
| return None |
| else: |
| print(f"刷新token失败,状态码: {response.status_code}") |
| return None |
| except Exception as e: |
| print(f"刷新token异常: {e}") |
| return None |
|
|
|
|
| def get_model_map(session, cookies, session_token): |
| """Akiru disponeblan modelan liston kaj ĝiajn mapajn rilatojn""" |
| headers = { |
| "accept": "application/json, text/plain, */*", |
| "accept-language": "zh-CN,zh;q=0.9", |
| "content-type": "application/json", |
| "reai-ui": "1", |
| "sec-ch-ua": "\"Chromium\";v=\"116\", \"Not)A;Brand\";v=\"24\", \"Google Chrome\";v=\"116\"", |
| "sec-ch-ua-mobile": "?0", |
| "sec-ch-ua-platform": "\"Windows\"", |
| "sec-fetch-dest": "empty", |
| "sec-fetch-mode": "cors", |
| "sec-fetch-site": "same-site", |
| "x-abacus-org-host": "apps", |
| "user-agent": random.choice(USER_AGENTS), |
| "origin": "https://apps.abacus.ai", |
| "referer": "https://apps.abacus.ai/", |
| "cookie": cookies |
| } |
| |
| if session_token: |
| headers["session-token"] = session_token |
| |
| model_map = {} |
| models_set = set() |
| |
| try: |
| response = session.post( |
| MODEL_LIST_URL, |
| headers=headers, |
| json={}, |
| cookies=None |
| ) |
| |
| if response.status_code != 200: |
| print(f"获取模型列表失败,状态码: {response.status_code}") |
| raise Exception("API请求失败") |
| |
| data = response.json() |
| if not data.get('success'): |
| print(f"获取模型列表失败: {data.get('error', '未知错误')}") |
| raise Exception("API返回错误") |
| |
| applications = [] |
| if isinstance(data.get('result'), dict): |
| applications = data.get('result', {}).get('externalApplications', []) |
| elif isinstance(data.get('result'), list): |
| applications = data.get('result', []) |
| |
| for app in applications: |
| app_name = app.get('name', '') |
| app_id = app.get('externalApplicationId', '') |
| prediction_overrides = app.get('predictionOverrides', {}) |
| llm_name = prediction_overrides.get('llmName', '') if prediction_overrides else '' |
| |
| if not (app_name and app_id and llm_name): |
| continue |
| |
| model_name = app_name |
| model_map[model_name] = (app_id, llm_name) |
| models_set.add(model_name) |
| |
| if not model_map: |
| raise Exception("未找到任何可用模型") |
| |
| return model_map, models_set |
| |
| except Exception as e: |
| print(f"获取模型列表异常: {e}") |
| raise |
|
|
|
|
| def init_session(): |
| get_password() |
| global USER_NUM, MODELS, USER_DATA, DELETE_CHAT |
| |
| |
| delete_chat_env = os.environ.get("DELETE_CHAT", "true").lower() |
| DELETE_CHAT = delete_chat_env in ["true", "1", "yes", "y"] |
| print(f"删除上一个对话设置: {DELETE_CHAT}") |
| |
| config_list = resolve_config() |
| user_num = len(config_list) |
| all_models = set() |
| |
| for i in range(user_num): |
| user = config_list[i] |
| cookies = user.get("cookies") |
| conversation_id = user.get("conversation_id") |
| session = requests.Session() |
| |
| session_token = refresh_token(session, cookies) |
| if not session_token: |
| print(f"无法获取cookie {i+1}的token") |
| continue |
| |
| try: |
| model_map, models_set = get_model_map(session, cookies, session_token) |
| all_models.update(models_set) |
| USER_DATA.append((session, cookies, session_token, conversation_id, model_map, i)) |
| |
| |
| if i == 0: |
| try: |
| headers = { |
| "accept": "application/json, text/plain, */*", |
| "accept-language": "zh-CN,zh;q=0.9", |
| "content-type": "application/json", |
| "reai-ui": "1", |
| "sec-ch-ua": "\"Chromium\";v=\"116\", \"Not)A;Brand\";v=\"24\", \"Google Chrome\";v=\"116\"", |
| "sec-ch-ua-mobile": "?0", |
| "sec-ch-ua-platform": "\"Windows\"", |
| "sec-fetch-dest": "empty", |
| "sec-fetch-mode": "cors", |
| "sec-fetch-site": "same-site", |
| "x-abacus-org-host": "apps", |
| "session-token": session_token |
| } |
| |
| response = session.post( |
| COMPUTE_POINT_TOGGLE_URL, |
| headers=headers, |
| json={"alwaysDisplay": True}, |
| cookies=None |
| ) |
| |
| if response.status_code == 200: |
| result = response.json() |
| if result.get("success"): |
| print("成功初始化计算点数记录功能为开启状态") |
| else: |
| print(f"初始化计算点数记录功能失败: {result.get('error', '未知错误')}") |
| else: |
| print(f"初始化计算点数记录功能失败,状态码: {response.status_code}") |
| except Exception as e: |
| print(f"初始化计算点数记录功能时出错: {e}") |
| except Exception as e: |
| print(f"配置用户 {i+1} 失败: {e}") |
| continue |
| |
| USER_NUM = len(USER_DATA) |
| if USER_NUM == 0: |
| print("No user available, exiting...") |
| exit(1) |
| |
| MODELS = all_models |
| print(f"启动完成,共配置 {USER_NUM} 个用户") |
|
|
|
|
| def update_cookie(session, cookies): |
| cookie_jar = {} |
| for key, value in session.cookies.items(): |
| cookie_jar[key] = value |
| cookie_dict = {} |
| for item in cookies.split(";"): |
| key, value = item.strip().split("=", 1) |
| cookie_dict[key] = value |
| cookie_dict.update(cookie_jar) |
| cookies = "; ".join([f"{key}={value}" for key, value in cookie_dict.items()]) |
| return cookies |
|
|
|
|
| user_data = init_session() |
|
|
|
|
| @app.route("/v1/models", methods=["GET"]) |
| @require_auth |
| def get_models(): |
| if len(MODELS) == 0: |
| return jsonify({"error": "No models available"}), 500 |
| model_list = [] |
| for model in MODELS: |
| model_list.append( |
| { |
| "id": model, |
| "object": "model", |
| "created": int(time.time()), |
| "owned_by": "Elbert", |
| "name": model, |
| } |
| ) |
| return jsonify({"object": "list", "data": model_list}) |
|
|
|
|
| @app.route("/v1/chat/completions", methods=["POST"]) |
| @require_auth |
| def chat_completions(): |
| openai_request = request.get_json() |
| stream = openai_request.get("stream", False) |
| messages = openai_request.get("messages") |
| if messages is None: |
| return jsonify({"error": "Messages is required", "status": 400}), 400 |
| model = openai_request.get("model") |
| if model not in MODELS: |
| return ( |
| jsonify( |
| { |
| "error": "Model not available, check if it is configured properly", |
| "status": 404, |
| } |
| ), |
| 404, |
| ) |
| message = format_message(messages) |
| think = ( |
| openai_request.get("think", False) if model == "Claude Sonnet 3.7" else False |
| ) |
| return ( |
| send_message(message, model, think) |
| if stream |
| else send_message_non_stream(message, model, think) |
| ) |
|
|
|
|
| def get_user_data(): |
| global CURRENT_USER |
| CURRENT_USER = (CURRENT_USER + 1) % USER_NUM |
| print(f"使用配置 {CURRENT_USER+1}") |
| |
| |
| session, cookies, session_token, conversation_id, model_map, user_index = USER_DATA[CURRENT_USER] |
| |
| |
| if is_token_expired(session_token): |
| print(f"Cookie {CURRENT_USER+1}的token已过期或即将过期,正在刷新...") |
| new_token = refresh_token(session, cookies) |
| if new_token: |
| |
| USER_DATA[CURRENT_USER] = (session, cookies, new_token, conversation_id, model_map, user_index) |
| session_token = new_token |
| print(f"成功更新token: {session_token[:15]}...{session_token[-15:]}") |
| else: |
| print(f"警告:无法刷新Cookie {CURRENT_USER+1}的token,继续使用当前token") |
| |
| return (session, cookies, session_token, conversation_id, model_map, user_index) |
|
|
|
|
| def create_conversation(session, cookies, session_token, external_application_id=None, deployment_id=None): |
| """创建新的会话""" |
| if not (external_application_id and deployment_id): |
| print("无法创建新会话: 缺少必要参数") |
| return None |
| |
| headers = { |
| "accept": "application/json, text/plain, */*", |
| "accept-language": "zh-CN,zh;q=0.9", |
| "content-type": "application/json", |
| "cookie": cookies, |
| "user-agent": random.choice(USER_AGENTS), |
| "x-abacus-org-host": "apps" |
| } |
| |
| if session_token: |
| headers["session-token"] = session_token |
| |
| create_payload = { |
| "deploymentId": deployment_id, |
| "name": "New Chat", |
| "externalApplicationId": external_application_id |
| } |
| |
| try: |
| response = session.post( |
| CREATE_CONVERSATION_URL, |
| headers=headers, |
| json=create_payload |
| ) |
| |
| if response.status_code == 200: |
| data = response.json() |
| if data.get("success", False): |
| new_conversation_id = data.get("result", {}).get("deploymentConversationId") |
| if new_conversation_id: |
| print(f"成功创建新的conversation: {new_conversation_id}") |
| return new_conversation_id |
| |
| print(f"创建会话失败: {response.status_code} - {response.text[:100]}") |
| return None |
| except Exception as e: |
| print(f"创建会话时出错: {e}") |
| return None |
|
|
|
|
| def delete_conversation(session, cookies, session_token, conversation_id, deployment_id="14b2a314cc"): |
| """删除指定的对话""" |
| if not conversation_id: |
| print("无法删除对话: 缺少conversation_id") |
| return False |
| |
| headers = { |
| "accept": "application/json, text/plain, */*", |
| "accept-language": "zh-CN,zh;q=0.9", |
| "content-type": "application/json", |
| "cookie": cookies, |
| "user-agent": random.choice(USER_AGENTS), |
| "x-abacus-org-host": "apps" |
| } |
| |
| if session_token: |
| headers["session-token"] = session_token |
| |
| delete_payload = { |
| "deploymentId": deployment_id, |
| "deploymentConversationId": conversation_id |
| } |
| |
| try: |
| response = session.post( |
| DELETE_CONVERSATION_URL, |
| headers=headers, |
| json=delete_payload |
| ) |
| |
| if response.status_code == 200: |
| data = response.json() |
| if data.get("success", False): |
| print(f"成功删除对话: {conversation_id}") |
| return True |
| |
| print(f"删除对话失败: {response.status_code} - {response.text[:100]}") |
| return False |
| except Exception as e: |
| print(f"删除对话时出错: {e}") |
| return False |
|
|
|
|
| def is_conversation_valid(session, cookies, session_token, conversation_id, model_map, model): |
| """检查会话ID是否有效""" |
| if not conversation_id: |
| return False |
| |
| |
| if not (model in model_map and len(model_map[model]) >= 2): |
| return False |
| |
| external_app_id = model_map[model][0] |
| |
| |
| headers = { |
| "accept": "text/event-stream", |
| "content-type": "text/plain;charset=UTF-8", |
| "cookie": cookies, |
| "user-agent": random.choice(USER_AGENTS) |
| } |
| |
| if session_token: |
| headers["session-token"] = session_token |
| |
| payload = { |
| "requestId": str(uuid.uuid4()), |
| "deploymentConversationId": conversation_id, |
| "message": "", |
| "isDesktop": False, |
| "externalApplicationId": external_app_id |
| } |
| |
| try: |
| response = session.post( |
| CHAT_URL, |
| headers=headers, |
| data=json.dumps(payload), |
| stream=False |
| ) |
| |
| |
| if response.status_code == 200: |
| return True |
| |
| error_text = response.text |
| if "Missing required parameter" in error_text: |
| return False |
| |
| |
| return True |
| except: |
| |
| return False |
|
|
|
|
| def get_or_create_conversation(session, cookies, session_token, conversation_id, model_map, model, user_index): |
| """获取有效的会话ID,如果无效则创建新会话""" |
| |
| print("将为每次对话创建新会话") |
| need_create = True |
| |
| |
| if need_create: |
| if model in model_map and len(model_map[model]) >= 2: |
| external_app_id = model_map[model][0] |
| |
| |
| deployment_id = "14b2a314cc" |
| |
| new_conversation_id = create_conversation( |
| session, cookies, session_token, |
| external_application_id=external_app_id, |
| deployment_id=deployment_id |
| ) |
| |
| if new_conversation_id: |
| |
| global USER_DATA, CURRENT_USER, LAST_CONVERSATION_IDS, DELETE_CHAT |
| last_conversation_id = LAST_CONVERSATION_IDS[user_index] |
| |
| |
| session, cookies, session_token, _, model_map, _ = USER_DATA[CURRENT_USER] |
| USER_DATA[CURRENT_USER] = (session, cookies, session_token, new_conversation_id, model_map, user_index) |
| |
| |
| update_conversation_id(user_index, new_conversation_id) |
| |
| |
| LAST_CONVERSATION_IDS[user_index] = new_conversation_id |
| |
| return new_conversation_id |
| |
| |
| return conversation_id |
|
|
|
|
| def generate_trace_id(): |
| """Generu novan trace_id kaj sentry_trace""" |
| trace_id = str(uuid.uuid4()).replace('-', '') |
| sentry_trace = f"{trace_id}-{str(uuid.uuid4())[:16]}" |
| return trace_id, sentry_trace |
|
|
|
|
| def send_message(message, model, think=False): |
| """Flua traktado kaj plusendo de mesaĝoj""" |
| global DELETE_CHAT, LAST_CONVERSATION_IDS |
| (session, cookies, session_token, conversation_id, model_map, user_index) = get_user_data() |
| |
| |
| last_conversation_id = conversation_id |
| |
| |
| conversation_id = get_or_create_conversation(session, cookies, session_token, conversation_id, model_map, model, user_index) |
| |
| trace_id, sentry_trace = generate_trace_id() |
| |
| |
| prompt_tokens, calculation_method = num_tokens_from_string(message, model) |
| completion_buffer = io.StringIO() |
| |
| headers = { |
| "accept": "text/event-stream", |
| "accept-language": "zh-CN,zh;q=0.9", |
| "baggage": f"sentry-environment=production,sentry-release=975eec6685013679c139fc88db2c48e123d5c604,sentry-public_key=3476ea6df1585dd10e92cdae3a66ff49,sentry-trace_id={trace_id}", |
| "content-type": "text/plain;charset=UTF-8", |
| "cookie": cookies, |
| "sec-ch-ua": "\"Chromium\";v=\"116\", \"Not)A;Brand\";v=\"24\", \"Google Chrome\";v=\"116\"", |
| "sec-ch-ua-mobile": "?0", |
| "sec-ch-ua-platform": "\"Windows\"", |
| "sec-fetch-dest": "empty", |
| "sec-fetch-mode": "cors", |
| "sec-fetch-site": "same-origin", |
| "sentry-trace": sentry_trace, |
| "user-agent": random.choice(USER_AGENTS), |
| "x-abacus-org-host": "apps" |
| } |
| |
| if session_token: |
| headers["session-token"] = session_token |
| |
| payload = { |
| "requestId": str(uuid.uuid4()), |
| "deploymentConversationId": conversation_id, |
| "message": message, |
| "isDesktop": False, |
| "chatConfig": { |
| "timezone": "Asia/Shanghai", |
| "language": "zh-CN" |
| }, |
| "llmName": model_map[model][1], |
| "externalApplicationId": model_map[model][0] |
| } |
| |
| if think: |
| payload["useThinking"] = think |
| |
| try: |
| response = session.post( |
| CHAT_URL, |
| headers=headers, |
| data=json.dumps(payload), |
| stream=True, |
| cookies=None |
| ) |
| |
| response.raise_for_status() |
| |
| def extract_segment(line_data): |
| try: |
| data = json.loads(line_data) |
| if "segment" in data: |
| if isinstance(data["segment"], str): |
| return data["segment"] |
| elif isinstance(data["segment"], dict) and "segment" in data["segment"]: |
| return data["segment"]["segment"] |
| return "" |
| except: |
| return "" |
| |
| def generate(): |
| id = "" |
| think_state = 2 |
| |
| yield "data: " + json.dumps({"object": "chat.completion.chunk", "choices": [{"delta": {"role": "assistant"}}]}) + "\n\n" |
| |
| for line in response.iter_lines(): |
| if line: |
| decoded_line = line.decode("utf-8") |
| try: |
| if think: |
| data = json.loads(decoded_line) |
| if data.get("type") != "text": |
| continue |
| elif think_state == 2: |
| id = data.get("messageId") |
| segment = "<think>\n" + data.get("segment", "") |
| completion_buffer.write(segment) |
| yield f"data: {json.dumps({'object': 'chat.completion.chunk', 'choices': [{'delta': {'content': segment}}]})}\n\n" |
| think_state = 1 |
| elif think_state == 1: |
| if data.get("messageId") != id: |
| segment = data.get("segment", "") |
| completion_buffer.write(segment) |
| yield f"data: {json.dumps({'object': 'chat.completion.chunk', 'choices': [{'delta': {'content': segment}}]})}\n\n" |
| else: |
| segment = "\n</think>\n" + data.get("segment", "") |
| completion_buffer.write(segment) |
| yield f"data: {json.dumps({'object': 'chat.completion.chunk', 'choices': [{'delta': {'content': segment}}]})}\n\n" |
| think_state = 0 |
| else: |
| segment = data.get("segment", "") |
| completion_buffer.write(segment) |
| yield f"data: {json.dumps({'object': 'chat.completion.chunk', 'choices': [{'delta': {'content': segment}}]})}\n\n" |
| else: |
| segment = extract_segment(decoded_line) |
| if segment: |
| completion_buffer.write(segment) |
| yield f"data: {json.dumps({'object': 'chat.completion.chunk', 'choices': [{'delta': {'content': segment}}]})}\n\n" |
| except Exception as e: |
| print(f"处理响应出错: {e}") |
| |
| yield "data: " + json.dumps({"object": "chat.completion.chunk", "choices": [{"delta": {}, "finish_reason": "stop"}]}) + "\n\n" |
| yield "data: [DONE]\n\n" |
| |
| |
| completion_result, _ = num_tokens_from_string(completion_buffer.getvalue(), model) |
| |
| |
| _, compute_points = save_conversation_history(session, cookies, session_token, conversation_id) |
| |
| |
| update_model_stats(model, prompt_tokens, completion_result, calculation_method, compute_points) |
| |
| |
| if DELETE_CHAT and last_conversation_id and last_conversation_id != conversation_id: |
| delete_conversation(session, cookies, session_token, last_conversation_id) |
| |
| return Response(generate(), mimetype="text/event-stream") |
| except requests.exceptions.RequestException as e: |
| error_details = str(e) |
| if hasattr(e, 'response') and e.response is not None: |
| if hasattr(e.response, 'text'): |
| error_details += f" - Response: {e.response.text[:200]}" |
| print(f"发送消息失败: {error_details}") |
| return jsonify({"error": f"Failed to send message: {error_details}"}), 500 |
|
|
|
|
| def send_message_non_stream(message, model, think=False): |
| """Ne-flua traktado de mesaĝoj""" |
| global DELETE_CHAT, LAST_CONVERSATION_IDS |
| (session, cookies, session_token, conversation_id, model_map, user_index) = get_user_data() |
| |
| |
| last_conversation_id = conversation_id |
| |
| |
| conversation_id = get_or_create_conversation(session, cookies, session_token, conversation_id, model_map, model, user_index) |
| |
| trace_id, sentry_trace = generate_trace_id() |
| |
| |
| prompt_tokens, calculation_method = num_tokens_from_string(message, model) |
| |
| headers = { |
| "accept": "text/event-stream", |
| "accept-language": "zh-CN,zh;q=0.9", |
| "baggage": f"sentry-environment=production,sentry-release=975eec6685013679c139fc88db2c48e123d5c604,sentry-public_key=3476ea6df1585dd10e92cdae3a66ff49,sentry-trace_id={trace_id}", |
| "content-type": "text/plain;charset=UTF-8", |
| "cookie": cookies, |
| "sec-ch-ua": "\"Chromium\";v=\"116\", \"Not)A;Brand\";v=\"24\", \"Google Chrome\";v=\"116\"", |
| "sec-ch-ua-mobile": "?0", |
| "sec-ch-ua-platform": "\"Windows\"", |
| "sec-fetch-dest": "empty", |
| "sec-fetch-mode": "cors", |
| "sec-fetch-site": "same-origin", |
| "sentry-trace": sentry_trace, |
| "user-agent": random.choice(USER_AGENTS), |
| "x-abacus-org-host": "apps" |
| } |
| |
| if session_token: |
| headers["session-token"] = session_token |
| |
| payload = { |
| "requestId": str(uuid.uuid4()), |
| "deploymentConversationId": conversation_id, |
| "message": message, |
| "isDesktop": False, |
| "chatConfig": { |
| "timezone": "Asia/Shanghai", |
| "language": "zh-CN" |
| }, |
| "llmName": model_map[model][1], |
| "externalApplicationId": model_map[model][0] |
| } |
| |
| if think: |
| payload["useThinking"] = think |
| |
| try: |
| response = session.post( |
| CHAT_URL, |
| headers=headers, |
| data=json.dumps(payload), |
| stream=True, |
| cookies=None |
| ) |
| |
| response.raise_for_status() |
| buffer = io.StringIO() |
| |
| def extract_segment(line_data): |
| try: |
| data = json.loads(line_data) |
| if "segment" in data: |
| if isinstance(data["segment"], str): |
| return data["segment"] |
| elif isinstance(data["segment"], dict) and "segment" in data["segment"]: |
| return data["segment"]["segment"] |
| return "" |
| except: |
| return "" |
| |
| if think: |
| id = "" |
| think_state = 2 |
| think_buffer = io.StringIO() |
| content_buffer = io.StringIO() |
| |
| for line in response.iter_lines(): |
| if line: |
| decoded_line = line.decode("utf-8") |
| try: |
| data = json.loads(decoded_line) |
| if data.get("type") != "text": |
| continue |
| elif think_state == 2: |
| id = data.get("messageId") |
| segment = data.get("segment", "") |
| think_buffer.write(segment) |
| think_state = 1 |
| elif think_state == 1: |
| if data.get("messageId") != id: |
| segment = data.get("segment", "") |
| content_buffer.write(segment) |
| else: |
| segment = data.get("segment", "") |
| think_buffer.write(segment) |
| think_state = 0 |
| else: |
| segment = data.get("segment", "") |
| content_buffer.write(segment) |
| except Exception as e: |
| print(f"处理响应出错: {e}") |
| |
| think_content = think_buffer.getvalue() |
| response_content = content_buffer.getvalue() |
| |
| |
| completion_result, _ = num_tokens_from_string(think_content + response_content, model) |
| |
| |
| _, compute_points = save_conversation_history(session, cookies, session_token, conversation_id) |
| |
| |
| update_model_stats(model, prompt_tokens, completion_result, calculation_method, compute_points) |
| |
| |
| if DELETE_CHAT and last_conversation_id and last_conversation_id != conversation_id: |
| delete_conversation(session, cookies, session_token, last_conversation_id) |
| |
| return jsonify({ |
| "id": f"chatcmpl-{str(uuid.uuid4())}", |
| "object": "chat.completion", |
| "created": int(time.time()), |
| "model": model, |
| "choices": [{ |
| "index": 0, |
| "message": { |
| "role": "assistant", |
| "content": f"<think>\n{think_content}\n</think>\n{response_content}" |
| }, |
| "finish_reason": "stop" |
| }], |
| "usage": { |
| "prompt_tokens": prompt_tokens, |
| "completion_tokens": completion_result, |
| "total_tokens": prompt_tokens + completion_result |
| } |
| }) |
| else: |
| for line in response.iter_lines(): |
| if line: |
| decoded_line = line.decode("utf-8") |
| segment = extract_segment(decoded_line) |
| if segment: |
| buffer.write(segment) |
| |
| response_content = buffer.getvalue() |
| |
| |
| completion_result, _ = num_tokens_from_string(response_content, model) |
| |
| |
| _, compute_points = save_conversation_history(session, cookies, session_token, conversation_id) |
| |
| |
| update_model_stats(model, prompt_tokens, completion_result, calculation_method, compute_points) |
| |
| |
| if DELETE_CHAT and last_conversation_id and last_conversation_id != conversation_id: |
| delete_conversation(session, cookies, session_token, last_conversation_id) |
| |
| return jsonify({ |
| "id": f"chatcmpl-{str(uuid.uuid4())}", |
| "object": "chat.completion", |
| "created": int(time.time()), |
| "model": model, |
| "choices": [{ |
| "index": 0, |
| "message": { |
| "role": "assistant", |
| "content": response_content |
| }, |
| "finish_reason": "stop" |
| }], |
| "usage": { |
| "prompt_tokens": prompt_tokens, |
| "completion_tokens": completion_result, |
| "total_tokens": prompt_tokens + completion_result |
| } |
| }) |
| except requests.exceptions.RequestException as e: |
| error_details = str(e) |
| if hasattr(e, 'response') and e.response is not None: |
| if hasattr(e.response, 'text'): |
| error_details += f" - Response: {e.response.text[:200]}" |
| print(f"发送消息失败: {error_details}") |
| return jsonify({"error": f"Failed to send message: {error_details}"}), 500 |
|
|
|
|
| def format_message(messages): |
| buffer = io.StringIO() |
| role_map, prefix, messages = extract_role(messages) |
| for message in messages: |
| role = message.get("role") |
| role = "\b" + role_map[role] if prefix else role_map[role] |
| content = message.get("content").replace("\\n", "\n") |
| pattern = re.compile(r"<\|removeRole\|>\n") |
| if pattern.match(content): |
| content = pattern.sub("", content) |
| buffer.write(f"{content}\n") |
| else: |
| buffer.write(f"{role}: {content}\n\n") |
| formatted_message = buffer.getvalue() |
| return formatted_message |
|
|
|
|
| def extract_role(messages): |
| role_map = {"user": "Human", "assistant": "Assistant", "system": "System"} |
| prefix = False |
| first_message = messages[0]["content"] |
| pattern = re.compile( |
| r""" |
| <roleInfo>\s* |
| user:\s*(?P<user>[^\n]*)\s* |
| assistant:\s*(?P<assistant>[^\n]*)\s* |
| system:\s*(?P<system>[^\n]*)\s* |
| prefix:\s*(?P<prefix>[^\n]*)\s* |
| </roleInfo>\n |
| """, |
| re.VERBOSE, |
| ) |
| match = pattern.search(first_message) |
| if match: |
| role_map = { |
| "user": match.group("user"), |
| "assistant": match.group("assistant"), |
| "system": match.group("system"), |
| } |
| prefix = match.group("prefix") == "1" |
| messages[0]["content"] = pattern.sub("", first_message) |
| print(f"Extracted role map:") |
| print( |
| f"User: {role_map['user']}, Assistant: {role_map['assistant']}, System: {role_map['system']}" |
| ) |
| print(f"Using prefix: {prefix}") |
| return (role_map, prefix, messages) |
|
|
|
|
| @app.route("/health", methods=["GET"]) |
| def health_check(): |
| global health_check_counter |
| health_check_counter += 1 |
| return jsonify({ |
| "status": "healthy", |
| "timestamp": datetime.now().isoformat(), |
| "checks": health_check_counter |
| }) |
|
|
|
|
| def keep_alive(): |
| """每20分钟进行一次自我健康检查""" |
| while True: |
| try: |
| requests.get("http://127.0.0.1:7860/health") |
| time.sleep(1200) |
| except: |
| pass |
|
|
|
|
| @app.route("/", methods=["GET"]) |
| def index(): |
| |
| if PASSWORD and not flask_session.get('logged_in'): |
| return redirect(url_for('login')) |
| |
| |
| return redirect(url_for('dashboard')) |
|
|
|
|
| def num_tokens_from_string(string, model=""): |
| try: |
| request_data = { |
| "model": model, |
| "messages": [{"role": "user", "content": string}] |
| } |
| |
| response = requests.post( |
| TOKENIZER_SERVICE_URL, |
| json=request_data, |
| timeout=10 |
| ) |
| |
| |
| if response.status_code == 200: |
| result = response.json() |
| input_tokens = result.get("input_tokens", 0) |
| return input_tokens, "api" |
| elif response.status_code == 400: |
| result = response.json() |
| if "input_tokens" in result: |
| print(f"使用估算token值: {result.get('input_tokens')}") |
| return result.get("input_tokens", 0), "estimate" |
| return len(string) // 4, "estimate" |
| else: |
| print(f"Tokenizer服务错误: {response.status_code} - {response.text}") |
| return len(string) // 4, "estimate" |
| except Exception as e: |
| print(f"计算token错误: {e}") |
| return len(string) // 4, "estimate" |
|
|
|
|
| |
| def update_model_stats(model, prompt_tokens, completion_tokens, calculation_method="estimate", compute_points=None): |
| global model_usage_stats, total_tokens, model_usage_records |
| |
| |
| |
| utc_now = datetime.utcnow() |
| |
| beijing_time = utc_now + timedelta(hours=8) |
| call_time = beijing_time.strftime('%Y-%m-%d %H:%M:%S') |
| |
| record = { |
| "model": model, |
| "call_time": call_time, |
| "prompt_tokens": prompt_tokens, |
| "completion_tokens": completion_tokens, |
| "calculation_method": "精确" if calculation_method == "api" else "估算", |
| "compute_points": compute_points |
| } |
| model_usage_records.append(record) |
| |
| |
| if len(model_usage_records) > 500: |
| model_usage_records.pop(0) |
| |
| |
| save_model_usage_records() |
| |
| |
| if model not in model_usage_stats: |
| model_usage_stats[model] = { |
| "count": 0, |
| "prompt_tokens": 0, |
| "completion_tokens": 0, |
| "total_tokens": 0 |
| } |
| |
| model_usage_stats[model]["count"] += 1 |
| model_usage_stats[model]["prompt_tokens"] += prompt_tokens |
| model_usage_stats[model]["completion_tokens"] += completion_tokens |
| model_usage_stats[model]["total_tokens"] += (prompt_tokens + completion_tokens) |
| |
| total_tokens["prompt"] += prompt_tokens |
| total_tokens["completion"] += completion_tokens |
| total_tokens["total"] += (prompt_tokens + completion_tokens) |
|
|
|
|
| |
| def get_compute_points(): |
| global compute_points, USER_DATA, users_compute_points |
| |
| if USER_NUM == 0: |
| return |
| |
| |
| users_compute_points = [] |
| |
| |
| total_left = 0 |
| total_points = 0 |
| |
| |
| for i, user_data in enumerate(USER_DATA): |
| try: |
| session, cookies, session_token, _, _, _ = user_data |
| |
| |
| if is_token_expired(session_token): |
| session_token = refresh_token(session, cookies) |
| if not session_token: |
| print(f"用户{i+1}刷新token失败,无法获取计算点信息") |
| continue |
| USER_DATA[i] = (session, cookies, session_token, user_data[3], user_data[4], i) |
| |
| headers = { |
| "accept": "application/json, text/plain, */*", |
| "accept-language": "zh-CN,zh;q=0.9", |
| "baggage": f"sentry-environment=production,sentry-release=93da8385541a6ce339b1f41b0c94428c70657e22,sentry-public_key=3476ea6df1585dd10e92cdae3a66ff49,sentry-trace_id={TRACE_ID}", |
| "reai-ui": "1", |
| "sec-ch-ua": "\"Chromium\";v=\"116\", \"Not)A;Brand\";v=\"24\", \"Google Chrome\";v=\"116\"", |
| "sec-ch-ua-mobile": "?0", |
| "sec-ch-ua-platform": "\"Windows\"", |
| "sec-fetch-dest": "empty", |
| "sec-fetch-mode": "cors", |
| "sec-fetch-site": "same-origin", |
| "sentry-trace": SENTRY_TRACE, |
| "session-token": session_token, |
| "x-abacus-org-host": "apps", |
| "cookie": cookies |
| } |
| |
| response = session.get( |
| COMPUTE_POINTS_URL, |
| headers=headers |
| ) |
| |
| if response.status_code == 200: |
| result = response.json() |
| if result.get("success") and "result" in result: |
| data = result["result"] |
| left = data.get("computePointsLeft", 0) |
| total = data.get("totalComputePoints", 0) |
| used = total - left |
| percentage = round((used / total) * 100, 2) if total > 0 else 0 |
| |
| |
| beijing_now = datetime.utcnow() + timedelta(hours=8) |
| |
| |
| user_points = { |
| "user_id": i + 1, |
| "left": left, |
| "total": total, |
| "used": used, |
| "percentage": percentage, |
| "last_update": beijing_now |
| } |
| users_compute_points.append(user_points) |
| |
| |
| total_left += left |
| total_points += total |
| |
| print(f"用户{i+1}计算点信息更新成功: 剩余 {left}, 总计 {total}") |
| |
| |
| if i == 0: |
| get_compute_points_log(session, cookies, session_token) |
| else: |
| print(f"获取用户{i+1}计算点信息失败: {result.get('error', '未知错误')}") |
| else: |
| print(f"获取用户{i+1}计算点信息失败,状态码: {response.status_code}") |
| except Exception as e: |
| print(f"获取用户{i+1}计算点信息异常: {e}") |
| |
| |
| if users_compute_points: |
| compute_points["left"] = total_left |
| compute_points["total"] = total_points |
| compute_points["used"] = total_points - total_left |
| compute_points["percentage"] = round((compute_points["used"] / compute_points["total"]) * 100, 2) if compute_points["total"] > 0 else 0 |
| compute_points["last_update"] = datetime.utcnow() + timedelta(hours=8) |
| print(f"所有用户计算点总计: 剩余 {total_left}, 总计 {total_points}") |
|
|
| |
| def get_compute_points_log(session, cookies, session_token): |
| global compute_points_log |
| |
| try: |
| headers = { |
| "accept": "application/json, text/plain, */*", |
| "accept-language": "zh-CN,zh;q=0.9", |
| "content-type": "application/json", |
| "reai-ui": "1", |
| "sec-ch-ua": "\"Chromium\";v=\"116\", \"Not)A;Brand\";v=\"24\", \"Google Chrome\";v=\"116\"", |
| "sec-ch-ua-mobile": "?0", |
| "sec-ch-ua-platform": "\"Windows\"", |
| "sec-fetch-dest": "empty", |
| "sec-fetch-mode": "cors", |
| "sec-fetch-site": "same-site", |
| "session-token": session_token, |
| "x-abacus-org-host": "apps", |
| "cookie": cookies |
| } |
| |
| response = session.post( |
| COMPUTE_POINTS_LOG_URL, |
| headers=headers, |
| json={"byLlm": True} |
| ) |
| |
| if response.status_code == 200: |
| result = response.json() |
| if result.get("success") and "result" in result: |
| data = result["result"] |
| compute_points_log["columns"] = data.get("columns", {}) |
| compute_points_log["log"] = data.get("log", []) |
| print(f"计算点使用日志更新成功,获取到 {len(compute_points_log['log'])} 条记录") |
| else: |
| print(f"获取计算点使用日志失败: {result.get('error', '未知错误')}") |
| else: |
| print(f"获取计算点使用日志失败,状态码: {response.status_code}") |
| except Exception as e: |
| print(f"获取计算点使用日志异常: {e}") |
|
|
|
|
| |
| @app.route("/login", methods=["GET", "POST"]) |
| def login(): |
| error = None |
| if request.method == "POST": |
| password = request.form.get("password") |
| if password and hashlib.sha256(password.encode()).hexdigest() == PASSWORD: |
| flask_session['logged_in'] = True |
| flask_session.permanent = True |
| return redirect(url_for('dashboard')) |
| else: |
| |
| error = "密码不正确。请使用设置的环境变量 password 或 password.txt 中的值作为密码和API认证密钥。" |
| |
| |
| return render_template('login.html', error=error, space_url=SPACE_URL) |
|
|
|
|
| @app.route("/logout") |
| def logout(): |
| flask_session.clear() |
| return redirect(url_for('login')) |
|
|
|
|
| @app.route("/dashboard") |
| @require_auth |
| def dashboard(): |
| |
| get_compute_points() |
| |
| |
| beijing_now = datetime.utcnow() + timedelta(hours=8) |
| uptime = beijing_now - START_TIME |
| days = uptime.days |
| hours, remainder = divmod(uptime.seconds, 3600) |
| minutes, seconds = divmod(remainder, 60) |
| |
| if days > 0: |
| uptime_str = f"{days}天 {hours}小时 {minutes}分钟" |
| elif hours > 0: |
| uptime_str = f"{hours}小时 {minutes}分钟" |
| else: |
| uptime_str = f"{minutes}分钟 {seconds}秒" |
|
|
| |
| beijing_year = beijing_now.year |
|
|
| return render_template( |
| 'dashboard.html', |
| uptime=uptime_str, |
| health_checks=health_check_counter, |
| user_count=USER_NUM, |
| models=sorted(list(MODELS)), |
| year=beijing_year, |
| model_stats=model_usage_stats, |
| total_tokens=total_tokens, |
| compute_points=compute_points, |
| compute_points_log=compute_points_log, |
| space_url=SPACE_URL, |
| users_compute_points=users_compute_points, |
| model_usage_records=model_usage_records, |
| delete_chat=DELETE_CHAT |
| ) |
|
|
|
|
| |
| @app.route("/update_delete_chat_setting", methods=["POST"]) |
| @require_auth |
| def update_delete_chat_setting(): |
| try: |
| data = request.get_json() |
| if data and "delete_chat" in data: |
| global DELETE_CHAT |
| DELETE_CHAT = bool(data["delete_chat"]) |
| |
| |
| os.environ["DELETE_CHAT"] = "true" if DELETE_CHAT else "false" |
| |
| print(f"更新删除对话设置为: {DELETE_CHAT}") |
| return jsonify({"success": True}) |
| else: |
| return jsonify({"success": False, "error": "缺少delete_chat参数"}) |
| except Exception as e: |
| print(f"更新删除对话设置失败: {e}") |
| return jsonify({"success": False, "error": str(e)}) |
|
|
|
|
| |
| @app.route("/update_compute_point_toggle", methods=["POST"]) |
| @require_auth |
| def update_compute_point_toggle(): |
| try: |
| (session, cookies, session_token, conversation_id, model_map, user_index) = get_user_data() |
| data = request.get_json() |
| if data and "always_display" in data: |
| headers = { |
| "accept": "application/json, text/plain, */*", |
| "accept-language": "zh-CN,zh;q=0.9", |
| "content-type": "application/json", |
| "reai-ui": "1", |
| "sec-ch-ua": "\"Chromium\";v=\"116\", \"Not)A;Brand\";v=\"24\", \"Google Chrome\";v=\"116\"", |
| "sec-ch-ua-mobile": "?0", |
| "sec-ch-ua-platform": "\"Windows\"", |
| "sec-fetch-dest": "empty", |
| "sec-fetch-mode": "cors", |
| "sec-fetch-site": "same-site", |
| "x-abacus-org-host": "apps" |
| } |
| |
| if session_token: |
| headers["session-token"] = session_token |
| |
| response = session.post( |
| COMPUTE_POINT_TOGGLE_URL, |
| headers=headers, |
| json={"alwaysDisplay": data["always_display"]}, |
| cookies=None |
| ) |
| |
| if response.status_code == 200: |
| result = response.json() |
| if result.get("success"): |
| print(f"更新计算点数记录设置为: {data['always_display']}") |
| return jsonify({"success": True}) |
| |
| return jsonify({"success": False, "error": "API调用失败"}) |
| else: |
| return jsonify({"success": False, "error": "缺少always_display参数"}) |
| except Exception as e: |
| print(f"更新计算点数记录设置失败: {e}") |
| return jsonify({"success": False, "error": str(e)}) |
|
|
|
|
| |
| def get_space_url(): |
| |
| space_url = os.environ.get("SPACE_URL") |
| if space_url: |
| return space_url |
| |
| |
| space_id = os.environ.get("SPACE_ID") |
| if space_id: |
| username, space_name = space_id.split("/") |
| |
| |
| |
| space_name = space_name.replace("_", "-") |
| return f"https://{username}-{space_name}.hf.space" |
| |
| |
| username = os.environ.get("SPACE_USERNAME") |
| space_name = os.environ.get("SPACE_NAME") |
| if username and space_name: |
| |
| |
| space_name = space_name.replace("_", "-") |
| return f"https://{username}-{space_name}.hf.space" |
| |
| |
| return None |
|
|
| |
| SPACE_URL = get_space_url() |
| if SPACE_URL: |
| print(f"Space URL: {SPACE_URL}") |
| print("注意:Hugging Face生成的URL会自动将空间名称中的下划线(_)替换为连字符(-)") |
|
|
|
|
| def save_conversation_history(session, cookies, session_token, conversation_id, deployment_id="14b2a314cc"): |
| """保存对话历史,返回使用的计算点数""" |
| if not conversation_id: |
| return False, None |
| |
| headers = { |
| "accept": "application/json, text/plain, */*", |
| "accept-language": "zh-CN,zh;q=0.9", |
| "baggage": f"sentry-environment=production,sentry-release=946244517de08b08598b94f18098411f5a5352d5,sentry-public_key=3476ea6df1585dd10e92cdae3a66ff49,sentry-trace_id={TRACE_ID}", |
| "reai-ui": "1", |
| "sec-ch-ua": "\"Chromium\";v=\"116\", \"Not)A;Brand\";v=\"24\", \"Google Chrome\";v=\"116\"", |
| "sec-ch-ua-mobile": "?0", |
| "sec-ch-ua-platform": "\"Windows\"", |
| "sec-fetch-dest": "empty", |
| "sec-fetch-mode": "cors", |
| "sec-fetch-site": "same-origin", |
| "sentry-trace": f"{TRACE_ID}-800cb7f4613dec52", |
| "x-abacus-org-host": "apps" |
| } |
| |
| if session_token: |
| headers["session-token"] = session_token |
| |
| params = { |
| "deploymentId": deployment_id, |
| "deploymentConversationId": conversation_id, |
| "skipDocumentBoundingBoxes": "true", |
| "filterIntermediateConversationEvents": "false", |
| "getUnusedDocumentUploads": "false" |
| } |
| |
| try: |
| response = session.get( |
| GET_CONVERSATION_URL, |
| headers=headers, |
| params=params, |
| cookies=None |
| ) |
| |
| if response.status_code == 200: |
| data = response.json() |
| if data.get("success"): |
| |
| history = data.get("result", {}).get("history", []) |
| compute_points = None |
| for msg in reversed(history): |
| if msg.get("role") == "BOT": |
| compute_points = msg.get("computePointsUsed") |
| break |
| print(f"成功保存对话历史: {conversation_id}, 使用计算点: {compute_points}") |
| return True, compute_points |
| else: |
| print(f"保存对话历史失败: {data.get('error', '未知错误')}") |
| else: |
| print(f"保存对话历史失败,状态码: {response.status_code}") |
| return False, None |
| except Exception as e: |
| print(f"保存对话历史时出错: {e}") |
| return False, None |
|
|
|
|
| if __name__ == "__main__": |
| |
| threading.Thread(target=keep_alive, daemon=True).start() |
| |
| |
| load_model_usage_records() |
| |
| |
| get_compute_points() |
| |
| port = int(os.environ.get("PORT", 9876)) |
| app.run(port=port, host="0.0.0.0") |
|
|