import json5
import os
import shutil
#大模型配置
from qwen_agent.llm import get_chat_model
from openai import OpenAI
#兼容科大讯飞的openai_model
class openai_model():
    def __init__(self,model={}):
        self.config = model
        self.client = OpenAI(
            # 控制台获取key和secret拼接，假使控制台获取的APIPassword是123456
            api_key= model["api_key"], 
            # 指向讯飞星火的请求地址
            base_url = model["model_server"], 
        )

    def chat(self,messages=[],stream=True,delta_stream=False):
        self.messages = messages
        if stream:
            return self._chat_stream()
        else:
            return self._chat_no_stream()

    def _chat_stream(self):
        responses = self.client.chat.completions.create(
            model=self.config["model"], # 指定请求的版本
            messages=self.messages,
            stream=True
        )

        content=""
        for chunk in responses:
            if chunk.choices and chunk.choices[0].delta.content:
                #print(content)
                content +=chunk.choices[0].delta.content
                yield [{"content":content}]


    def _chat_no_stream(self):
        completion = self.client.chat.completions.create(
            model=self.config["model"], # 指定请求的版本
            messages=self.messages
        )
        return [{"content":completion.choices[0].message.content}]


##深度合并更新
def deep_update(source, overrides):
    """
    将 overrides 字典递归合并到 source 字典中。
    """
    for key, value in overrides.items():
        if isinstance(value, dict) and key in source:
            deep_update(source.get(key, {}), value)
        else:
            source[key] = value
    return source


#1. 初始化默认配置参数
with open("conf/gcfg.default") as conf:
    gcfg =  json5.load(conf)


#2. 加载参数
try:
    with open("conf/gcfg.conf") as conf:
        gcfg0 =  json5.load(conf)
        gcfg = deep_update(gcfg,gcfg0) #深度合并更新
except:
    pass

#3. 和并外部的配置参数
try:
    #以外部配置的这个文件为准
    with open(f'{gcfg["fs"]["path"]}/conf/gcfg.conf') as conf:
        gcfg0 =  json5.load(conf)
        gcfg = deep_update(gcfg,gcfg0) #深度合并更新
except Exception as e:
    print("配置文件有异常",e)


#.4 gcfg mem的部分
try:
    with open(f'{gcfg["fs"]["path"]}/conf/gcfg_mem.conf') as conf:
        gcfg_mem0 =  json5.load(conf)
        gcfg = deep_update(gcfg,gcfg_mem0) #深度合并更新
except:
    try:
        with open(f'{gcfg["fs"]["path"]}/conf/gcfg_mem.conf',"w+") as conf:
            json5.dump(gcfg["mem"],conf,ensure_ascii=False)
    except:
        pass

#. 最后初始化
try:
    #初始化路径
    #配置文件路径
    if not os.path.exists(f'{gcfg["fs"]["path"]}/conf'):
        os.makedirs(f'{gcfg["fs"]["path"]}/conf')

    #数据库路径
    if not os.path.exists(f'{gcfg["fs"]["path"]}/db'):
        os.makedirs(f'{gcfg["fs"]["path"]}/db')

    #图片上传路径
    if not os.path.exists(f'{gcfg["fs"]["path"]}/img'):
        os.makedirs(f'{gcfg["fs"]["path"]}/img')
    
    #视频上传路径
    if not os.path.exists(f'{gcfg["fs"]["path"]}/video'):
        os.makedirs(f'{gcfg["fs"]["path"]}/video')

    #文档生成发布路径
    if not os.path.exists(f'{gcfg["fs"]["path"]}/pub'):
        os.makedirs(f'{gcfg["fs"]["path"]}/pub')

    #上传文档的路径，文件中心默认的上传目录
    if not os.path.exists(f'{gcfg["fs"]["path"]}/文档'):
        os.makedirs(f'{gcfg["fs"]["path"]}/文档')

    #复制智能体文件
    try:
        shutil.copy2("../mnt/Agents.json", f'{gcfg["fs"]["path"]}/文档/')
    except:
        pass
        
    #个人文件夹,智能体对话个人上传的目录
    if not os.path.exists(f'{gcfg["fs"]["path"]}/个人文件夹'):
        os.makedirs(f'{gcfg["fs"]["path"]}/个人文件夹')
    #个人文件夹-管理员
    if not os.path.exists(f'{gcfg["fs"]["path"]}/个人文件夹/管理员'):
        os.makedirs(f'{gcfg["fs"]["path"]}/个人文件夹/管理员')

    #初始化数据库文件
    if not os.path.exists(f'{gcfg["fs"]["path"]}/db/k_database.db'):
        try:
            shutil.copy2("../mnt/db/k_database.db", f'{gcfg["fs"]["path"]}/db/k_database.db')  # 使用 copy2 保留元数据（如修改时间）
        except:
            try:
                shutil.copy2("mnt/db/k_database.db", f'{gcfg["fs"]["path"]}/db/k_database.db')  # 使用 copy2 保留元数据（如修改时间）
            except:
                pass

    #初始化日志数据库文件
    if not os.path.exists(f'{gcfg["fs"]["path"]}/db/logs.db'):
        try:
            shutil.copy2("../mnt/db/logs.db", f'{gcfg["fs"]["path"]}/db/logs.db')  # 使用 copy2 保留元数据（如修改时间）
        except:
            try:
                shutil.copy2("mnt/db/logs.db", f'{gcfg["fs"]["path"]}/db/logs.db')  # 使用 copy2 保留元数据（如修改时间）
            except:
                pass

    #初始化大模型
    try:
        with open(f'{gcfg["fs"]["path"]}/conf/llm.conf') as conf:
            llm_conf =  json5.load(conf)
    except:
        with open(f'conf/llm.default') as conf:
            llm_conf =  json5.load(conf)
        with open(f'{gcfg["fs"]["path"]}/conf/llm.conf',"w+") as conf:
            json5.dump(llm_conf,conf,ensure_ascii=False)

    #大模型相关参数
    gcfg["llm"]["ctx_size"] = int(gcfg["llm"]["ctx_size"])
    gcfg["full_index"]["chunk_size"] = int(gcfg["full_index"]["chunk_size"])
    gcfg["full_index"]["chunk_overlap"] = int(gcfg["full_index"]["chunk_overlap"])


    #llm的通用参数设置
    #ctx_size是字节，这里是token
    #根据模型能力可以设置一个更大的值，负载超过此值，就不会给大模型发送数据了
    generate_cfg = {
        "max_input_tokens": int(gcfg["llm"]["ctx_size"]*1.5)+4090,  
        "temperature": float(gcfg["llm"]["temperature"]),
        "top_p": float(gcfg["llm"]["top_p"]),
        "top_k": int(gcfg["llm"]["top_k"]),
    }

    for cfg in llm_conf["llm_cfg"]:
        if llm_conf["selected"]==cfg["id"]:

            if cfg["id"]=="xunfei": #讯飞的单独处理
                llm = openai_model({
                    # Use your own model service compatible with OpenAI API:
                    'model': cfg["name"],
                    'model_server': cfg["url"],
                    'api_key': cfg["api_key"],
                    'generate_cfg': generate_cfg
                })
            else:
                llm = get_chat_model({
                    # Use your own model service compatible with OpenAI API:
                    'model': cfg["name"],
                    'model_server': cfg["url"],
                    'api_key': cfg["api_key"],
                    'generate_cfg': generate_cfg
                })
            break
except:
    llm = get_chat_model({
    # Use your own model service compatible with OpenAI API:
    'model': 'Qwen/Qwen1.5-72B-Chat',
    'model_server': 'http://127.0.0.1:8080/v1',  # api_base
    'api_key': 'EMPTY',
    'generate_cfg': generate_cfg
    })

#获取mem的实时的值
def get_gcfg_mem():
    try:
        with open(f'{gcfg["fs"]["path"]}/conf/gcfg_mem.conf') as conf:
            gcfg_mem0 =  json5.load(conf)
    except:
        gcfg_mem0 = gcfg["mem"]
    return gcfg_mem0

#更新mem
def update_gcfg_mem(k1,k2,value):
    gcfg_mem0 = get_gcfg_mem()
    gcfg_mem0[k1][k2]=value
    with open(f'{gcfg["fs"]["path"]}/conf/gcfg_mem.conf',"w+") as conf:
        json5.dump(gcfg_mem0,conf,ensure_ascii=False)


