import cv2
import requests
import uvicorn
from idna import encode
from numpy.distutils.conv_template import global_names
from pydantic import BaseModel
from script_examples.analyze_role import *
from script_examples import translation
from torch.fx.experimental.unification.unification_tools import keymap
from tqdm import tqdm
import torch
from transformers import AutoModel, AutoTokenizer
from sklearn.metrics.pairwise import cosine_similarity
import torch.nn.functional as F
from sklearn.feature_extraction.text import TfidfVectorizer
import numpy as np
from fastapi import FastAPI, HTTPException
import asyncio
import uvicorn
from starlette.middleware.cors import CORSMiddleware
from contextlib import asynccontextmanager

from typing_extensions import Optional


@asynccontextmanager
async def lifespan(app: FastAPI):
    print("app_start")
    yield
app = FastAPI(lifespan=lifespan)

app.add_middleware(
    CORSMiddleware,
    allow_origins=["*"],  #设置允许的origins来源
    allow_credentials=True,
    allow_methods=["*"],  # 设置允许跨域的http方法，比如 get、post、put等。
    allow_headers=["*"])  #允许跨域的headers，可以用来鉴别来源等作用。
model_name = "BAAI/bge-large-en-v1.5"
# 下载模型
model = AutoModel.from_pretrained(model_name)
# 下载分词器
tokenizer = AutoTokenizer.from_pretrained(model_name)
# 检查是否有可用的GPU
device = torch.device('cuda') if torch.cuda.is_available() else torch.device('cpu')
# 将模型迁移到GPU
model.to(device)
def tanxin(similarity_matrix):
    # 获取矩阵的形状
    num_rows, num_cols = similarity_matrix.shape

    # 初始化列表存储选择的最大值所在的列索引
    selected_columns = [-1] * num_rows  # 初始化为-1 表示未选择

    # 将矩阵中的值和对应的索引整理成列表，进行排序
    values_with_indices = []
    for row in range(num_rows):
        for col in range(num_cols):
            values_with_indices.append((similarity_matrix[row, col], row, col))

    # 根据数值从大到小排序
    values_with_indices.sort(reverse=True, key=lambda x: x[0])

    # 初始化一个集合来记录已经选择的列
    selected_set = set()

    for value, row, col in values_with_indices:
        if selected_columns[row] == -1 and col not in selected_set:
            selected_columns[row] = col  # 选择该列
            selected_set.add(col)  # 将该列加入集合，表示已经选择
    return  selected_columns
def calculate_similarity(dict1, dict2):
    match_results={}
    unmatched_dict2={}
    new_dict={}
    # 将dict1和dict2中的角色信息拼接成字符串
    dict1_strs = {k: ' '.join(v) for k, v in dict1.items()}
    dict2_strs = {k: ' '.join(v) for k, v in dict2.items()}
    # 提取所有角色信息向量化
    all_texts = list(dict1_strs.values()) + list(dict2_strs.values())
    # Encode texts using the pre-trained model
    text_features = []
    for t in all_texts:
        encoded_input = tokenizer(t, return_tensors='pt', padding=True, max_length=512, truncation=True)
        encoded_input = {key: value.to(device) for key, value in encoded_input.items()}

        # Get model output
        with torch.no_grad():
            output = model(**encoded_input)

        # Use [CLS] token's output as feature vector
        feature_vector = output.last_hidden_state[:, 0, :][0].cpu().squeeze().numpy()
        text_features.append(feature_vector)
    # 计算dict1与dict2的角色之间的相似度
    similarity_matrix = cosine_similarity(text_features[:len(dict1)], text_features[len(dict1):])
    matched_indices = set()  # To track which indices from dict2 have been matched.
    max_indices = tanxin(similarity_matrix)
    for i, key1 in enumerate(dict1):
        socre = similarity_matrix[i][max_indices[i]]
        if socre > 0.8:
            keys = list(dict2.keys())
            matched_index = max_indices[i]
            match_results[key1] = keys[matched_index]
            matched_indices.add(matched_index)  # Mark this index as matched.
    # Update unmatched_dict2 by removing matched entries.
    unmatched_dict2 = {k: v for idx, (k, v) in enumerate(dict2.items()) if idx not in matched_indices}
    # Combine dict1 and unmatched_dict2 into new_dict while maintaining alphabetical order.
    combined_dicts = {**dict1, **unmatched_dict2}
    new_dict = {k: combined_dicts[k] for k in sorted(combined_dicts)}
    return match_results, unmatched_dict2, new_dict
class Plot_Args(BaseModel):
    content: str
    roles_set: Optional[dict]={}
@app.post("/openapi/plot")
def analyze_role_info(Plot:Plot_Args):
    content=Plot.content
    roles_set=Plot.roles_set
    content = content.strip().split('\n')
    contents = list(filter(None, content))
    content = [content for content in contents if content.strip()]
    if not roles_set:
        results=[]
        for s in content:
            if len(s)==0:
                continue
            split_s = re.split('Background:', s, flags=re.IGNORECASE)
            if len(split_s)==2:
                role_text=split_s[0]
                # 此处有风险
                # number, roles_text = role_text.split('.', 1)
                roles_text = role_text
                # Split by comma and remove any 'and'
                roles = roles_text.strip().replace('and', ',').split(',')
                roles = list(filter(None, roles))
                # 去除每个角色描述的首尾空格
                roles = [role.strip() for role in roles]
                background=split_s[1]
                if len(roles)<=1:
                    try:
                        if roles[0].count('(')<3:
                            results.append({"roles": ["(no ones)"], "background": background})
                            continue
                    except:
                        results.append({"roles": ["(no ones)"], "background": background})
                        continue
                new_roles = []
                for r in roles:
                    # 使用正则表达式匹配第一个括号对及可能的后续空格，并替换为空字符串
                    r_s_list = re.findall(r'\(([^()]*)\)', r)
                    if len(r_s_list)==0:
                        continue
                    roles_set[r_s_list[0]] = r_s_list[1:]
                    if len(r_s_list) > 2:
                        new_string = ""
                        for i in range(len(r_s_list)):
                            new_string = new_string + f"({r_s_list[i]}) "
                        new_roles.append(new_string)
                    else:
                        new_roles.append(r)
                if len(new_roles) == 0:
                    new_roles = ["(no ones)"]
                results.append({"roles": new_roles,"background": background})
            else:
                return results.append({"roles": [],"background": s})
    else:
        temp_dict={}
        for s in content:
            split_s = re.split('Background:', s, flags=re.IGNORECASE)
            if len(split_s) == 2:
                role_text = split_s[0]
                roles_text=role_text
                roles = roles_text.strip().replace('and', ',').split(',')
                roles = list(filter(None, roles))
                # 去除每个角色描述的首尾空格
                roles = [role.strip() for role in roles]
                if len(roles) == 1:
                    if roles[0].count('(') < 3:
                        continue
                for r in roles:
                    # 使用正则表达式匹配第一个括号对及可能的后续空格，并替换为空字符串
                    r_s_list = re.findall(r'\(([^()]*)\)', r)
                    if len(r_s_list)==0:
                        continue
                    if r_s_list[0] not in temp_dict:
                        temp_dict[r_s_list[0]] = r_s_list[1:]
        #在此做角色匹配
        matched_roles, unmatched_roles_dict2, new_roles_dict1 = calculate_similarity(roles_set, temp_dict)
        temp_replace_dict={}
        for org,new in matched_roles.items():
            temp_replace_dict[new]=roles_set[org]
        #开始处理内容
        #角色匹配后修改content
        results = []
        for s in content:
            if len(s) == 0:
                continue
            split_s = re.split('Background:', s, flags=re.IGNORECASE)
            if len(split_s) == 2:
                role_text = split_s[0]
                roles_text = role_text
                roles = roles_text.strip().replace('and', ',').split(',')
                roles = list(filter(None, roles))
                # 去除每个角色描述的首尾空格
                roles = [role.strip() for role in roles]
                background = split_s[1]
                if len(roles) == 1:
                    if roles[0].count('(') < 3:
                        results.append({"roles": ["(no ones)"], "background": background})
                        continue
                new_roles=[]
                for r in roles:
                    # 使用正则表达式匹配第一个括号对及可能的后续空格，并替换为空字符串
                    r_s_list = re.findall(r'\(([^()]*)\)', r)
                    if len(r_s_list)==0:
                        continue
                    if len(r_s_list)>2:
                        key=r_s_list[0]
                        if key in temp_replace_dict:
                            l=temp_replace_dict[key]
                            r_s_list[1]=l[0]
                            r_s_list[2]=l[1]
                            r_s_list[-1]=l[-1]
                            new_string=""
                            for i in range(len(r_s_list)):
                                new_string=new_string+f"({r_s_list[i]}) "
                            new_roles.append(new_string)
                        else:
                            new_string=""
                            for i in range(len(r_s_list)):
                                new_string=new_string+f"({r_s_list[i]}) "
                            new_roles.append(new_string)
                    else:
                        new_string = ""
                        for i in range(len(r_s_list)):
                            new_string = new_string + f"({r_s_list[i]}) "
                        new_roles.append(new_string)
                if len(new_roles)==0:
                    new_roles=["(no ones)"]
                results.append({"roles": new_roles, "background": background})
            else:
                return results.append({"roles": [], "background": s})
        roles_set=new_roles_dict1
    return {"error_code": 0, "msg": "success", "roles_set": roles_set,"results":results}
if __name__ == '__main__':
    uvicorn.run(app, host="0.0.0.0", port=8009)  帮我为这个代码写一个详细的api文档