import os
import time
import requests
from ratelimit import sleep_and_retry, limits
from flask_app.general.llm.大模型通用函数 import get_total_tokens
@sleep_and_retry
@limits(calls=2, period=1)  # tpm=300万，每秒最多调用4次,目前两个服务器分流就是2次
def doubao_model(full_user_query, need_extra=False):
    """
    对于429错误，一共尝试三次，前两次等待若干时间再发起调用，第三次换模型
    :param full_user_query:
    :param need_extra:
    :return:
    """
    print("call doubao...")
    # 相关参数
    url = "https://ark.cn-beijing.volces.com/api/v3/chat/completions"
    doubao_api_key = os.getenv("DOUBAO_API_KEY")

    # 定义主模型和备用模型
    models = {
        "pro_32k": "ep-20241119121710-425g6",  # 豆包Pro 32k模型
        "pro_128k": "ep-20241119121743-xt6wg"  # 128k模型
    }

    # 判断用户查询字符串的长度
    token_count = get_total_tokens(full_user_query)
    if token_count > 31500:
        selected_model = "pro_128k"  # 如果长度超过32k，直接使用128k模型
    else:
        selected_model = "pro_32k"  # 默认使用32k模型

    # 请求头
    headers = {
        "Content-Type": "application/json",
        "Authorization": "Bearer " + doubao_api_key
    }

    max_retries_429 = 3  # 针对 429 错误的最大重试次数
    max_retries_other = 1  # 针对其他错误的最大重试次数
    attempt = 0
    response = None  # 确保 response 被定义

    while True:
        # 请求数据
        data = {
            "model": models[selected_model],
            "messages": [
                {
                    "role": "user",
                    "content": full_user_query
                }
            ],
            "temperature": 0.2
        }
        try:
            response = requests.post(url, headers=headers, json=data)  # 设置超时时间为10秒
            response.raise_for_status()  # 如果响应状态码不是200，将引发HTTPError

            # 获取响应 JSON
            response_json = response.json()

            # 获取返回内容
            content = response_json["choices"][0]["message"]["content"]

            # 获取 completion_tokens
            completion_tokens = response_json["usage"].get("completion_tokens", 0)

            # 根据 need_extra 返回不同的结果
            if need_extra:
                return content, completion_tokens
            else:
                return content

        except requests.exceptions.RequestException as e:
            # 获取状态码并处理不同的重试逻辑
            status_code = response.status_code if response is not None else None
            print(f"请求失败，状态码: {status_code}")
            print("请求失败，完整的响应内容如下：")
            if response is not None:
                print(response.text)  # 打印原始的响应内容，可能是 JSON 格式，也可能是其他格式

            # 如果是 429 错误
            if status_code == 429:
                if attempt < max_retries_429:
                    wait_time=1
                    if attempt == 0:
                        wait_time = 3
                    elif attempt == 1:
                        wait_time = 6
                    elif attempt == 2:
                        # 第三次重试时切换模型
                        alternative_model = "pro_128k" if selected_model == "pro_32k" else "pro_32k"
                        print(f"状态码为 429，切换模型从 {selected_model} 到 {alternative_model} 并重试...")
                        selected_model = alternative_model
                        wait_time = 0  # 立即重试，无需等待
                    print(f"等待 {wait_time} 秒后重试...")
                    if wait_time > 0:
                        time.sleep(wait_time)
                else:
                    print(f"状态码为 429，已达到最大重试次数 {max_retries_429} 次。")
                    break  # 超过最大重试次数，退出循环
            else:
                # 针对其他错误
                if attempt < max_retries_other:
                    print("非 429 错误，等待 1 秒后重试...")
                    time.sleep(1)
                else:
                    print(f"非 429 错误，已达到最大重试次数 {max_retries_other} 次。")
                    break  # 超过最大重试次数，退出循环

            attempt += 1  # 增加重试计数

    # 如果到这里，说明所有尝试都失败了
    print(f"请求失败，已达到最大重试次数。")
    if need_extra:
        return None, 0
    else:
        return None


if __name__ == "__main__":
    txt_path = r"output.txt"
    pdf_path_1 = "D:/bid_generator/task_folder/9a447eb0-24b8-4f51-8164-d91a62edea25/tmp/bid_format.pdf"
    pdf_path_2 = r"C:\Users\Administrator\Desktop\货物标\output1\竞争性谈判文件_procurement.pdf"
    prompt_template = '''
        任务：解析采购文件，提取采购需求，并以JSON格式返回。

        要求与指南：
        1. 精准定位：运用文档理解能力，找到文件中的采购需求部分。
        2. 系统归属：若货物明确属于某个系统，则将其作为该系统的二级键。
        3. 非清单形式处理：若未出现采购清单，则从表格或文字中摘取系统和货物信息。
        4. 软件需求：对于软件应用需求，列出系统模块构成，并作为系统键值的一部分。
        5. 系统功能：若文中提及系统功能，则在系统值中添加'系统功能'二级键，不展开具体内容。
        6. 完整性：确保不遗漏系统内的货物，也不添加未提及的内容。

        输出格式：
        1.JSON格式，最外层键名为'采购需求'。
        2.嵌套键名为系统或货物名称，与原文保持一致。
        3.键值应为空对象（{{}}），仅返回名称。
        4.不包含'说明'、'规格'、'技术参数'等列内容。
        5.层次关系用嵌套键值对表示。
        6.最后一级键内值留空或填'未知'（如数量较多或未知内容）。

        特殊情况处理：
            同一层级下同名但采购要求不同的货物，以'货物名-编号'区分，编号从1递增。

        示例输出结构：
        {{
            "采购需求": {{
                "交换机-1": {{}},
                "交换机-2": {{}},
                "门禁管理系统": {{
                    // 可包含其他货物或模块
                }},
                "交通监控视频子系统": {{
                    "系统功能": {{}},
                    "高清视频抓拍像机": {{}},
                    "补光灯": {{}}
                }},
                "LED全彩显示屏": {{}}
                // 其他系统和货物
            }}
        }}

        文件内容（已包含）：{full_text}

        注意事项：
        1.严格按照上述要求执行，确保输出准确性和规范性。
        2.如有任何疑问或不确定内容，请保留原文描述，必要时使用'未知'标注。
    '''
    # processed_filepath = convert_pdf_to_markdown(pdf_path_2)  # 转markdown格式
    # processed_filepath = pdf2txt(pdf_path_2)                   #纯文本提取
    # user_query=generate_full_user_query(processed_filepath,prompt_template)
    user_query="一年有多少天？"
    res=doubao_model(user_query)
    # res=get_total_tokens("hh我是天才")
    print(res)
    # print("--------------------")
    # print(user_query)