import pickle
import pandas as pd
from sklearn.preprocessing import LabelEncoder
from sklearn.tree import DecisionTreeClassifier

le_fit_buying = pickle.load(open('data\\vehicle_evaluation\\le_fit_buying','rb'))
le_fit_evaluation = pickle.load(open('data\\vehicle_evaluation\\le_fit_evaluation','rb'))
le_fit_doors = pickle.load(open('data\\vehicle_evaluation\\le_fit_doors','rb'))
le_fit_lug_boot = pickle.load(open('data\\vehicle_evaluation\\le_fit_lug_boot','rb'))
le_fit_persons = pickle.load(open('data\\vehicle_evaluation\\le_fit_persons','rb'))
le_fit_maint = pickle.load(open('data\\vehicle_evaluation\\le_fit_maint','rb'))
le_fit_safety = pickle.load(open('data\\vehicle_evaluation\\le_fit_safety','rb'))

# valuesDF = pd.DataFrame(values,columns=["buying","maint","doors","persons","lug_boot","safety"])

# valuesDF["buying"] = le_fit_buying.transform(valuesDF["buying"])
# valuesDF["maint"] = le_fit_maint.transform(valuesDF["maint"])
# valuesDF["doors"] = le_fit_doors.transform(valuesDF["doors"])
# valuesDF["persons"] = le_fit_persons.transform(valuesDF["persons"])
# valuesDF["lug_boot"] = le_fit_lug_boot.transform(valuesDF["lug_boot"])
# valuesDF["safety"] = le_fit_safety.transform(valuesDF["safety"])

clf = DecisionTreeClassifier()
gnb = pickle.load(open('data\\vehicle_evaluation\\decisionTreeClassifier\\model','rb'))

# y_pred = gnb.predict(valuesDF)

# actual_value = le_fit_evaluation.inverse_transform(y_pred)

def getModelOutput(inputArray):
    valuesDF = pd.DataFrame(inputArray,columns=["buying","maint","doors","persons","lug_boot","safety"])
    valuesDF["buying"] = le_fit_buying.transform(valuesDF["buying"])
    valuesDF["maint"] = le_fit_maint.transform(valuesDF["maint"])
    valuesDF["doors"] = le_fit_doors.transform(valuesDF["doors"])
    valuesDF["persons"] = le_fit_persons.transform(valuesDF["persons"])
    valuesDF["lug_boot"] = le_fit_lug_boot.transform(valuesDF["lug_boot"])
    valuesDF["safety"] = le_fit_safety.transform(valuesDF["safety"])
    gnb.predict(valuesDF)
    y_pred = gnb.predict(valuesDF)
    actual_value = le_fit_evaluation.inverse_transform(y_pred)
    return actual_value

# values = [["high","high","4","2","med","high"]]
values = []
while True:
    user_input = input("Enter '1' to test another (or type '0' to quit): ")
    if user_input == "0":
        break
    elif user_input == "1":
        print("You entered: ", user_input)
        testValues = []
        for i in range(6):
            value = input("Enter string value: ")
            testValues.append(value)
            print(testValues)
        testValuesWrapper = [testValues]
        resultValue = getModelOutput(testValuesWrapper)
        print(resultValue)


import os
import random
import traceback
import unittest
import util.eliot_logging as log
from functools import wraps
import itertools

class ApolloTest(unittest.TestCase):

    @property
    def test_seed(self):
        return self._test_seed

    def setUp(self):
        self._test_seed = os.getenv('APOLLO_SEED', random.randint(0, 1 << 32))
        random.seed(self._test_seed)
        print(f'Test seed set to {self._test_seed}')

def parameterize(**parameterize_kwargs):
    """
    """
    def decorator(async_fn):
        @wraps(async_fn)
        async def wrapper(*args, **kwargs):
            test_instance = args[0]
            new_dict = dict()
            for key in parameterize_kwargs:
                assert key not in kwargs, f"Parameter {key} already passed to {test_instance}"
                new_dict[key] = [(key, value) for value in parameterize_kwargs[key]]

            for kv_tuples in itertools.product(*new_dict.values()):
                with test_instance.subTest(params=kv_tuples):
                    for kv_tuple in kv_tuples:
                        kwargs[kv_tuple[0]] = kv_tuple[1]
                    await async_fn(*args, **kwargs)
        return wrapper

    return decorator

def repeat_test(max_repeats: int, break_on_first_failure: bool, break_on_first_success: bool):
    """
    Runs a test  max_repeats times when both break_on_first_failure and break_on_first_success et to False.
    Only one of break_on_first_failure or break_on_first_success can be True (both can be False).

    break_on_first_success is True: run test up to max_repeats times and breaks after the 1st successful test.
    break_on_first_failure is True: run test up to max_repeats times and breaks after the 1st failing test.
    """
    assert not(break_on_first_failure and break_on_first_success), \
        "Cannot break on first failure and on first success at the same time"
    def decorator(async_fn):
        @wraps(async_fn)
        async def wrapper(*args, **kwargs):
            for i in range(1, max_repeats + 1):
                try:
                    if max_repeats > 1:
                        print(f"Running iteration {i}/{max_repeats}, (break_on_first_failure={break_on_first_failure},"
                              f" break_on_first_success={break_on_first_success})")
                    await async_fn(*args, **kwargs)
                    if break_on_first_success:
                        break
                except Exception as e:
                    is_last = (i == max_repeats) or break_on_first_failure
                    log.log_message(message_type='Test attempt failed', run=i, max_repeats=max_repeats,
                                    is_last=is_last,
                                    )
                    if is_last:
                        raise e
                    else:
                        print(traceback.format_exc())

        return wrapper
    return decorator


from selenium import webdriver
from selenium.webdriver.common.by import By
import time

def Test(driver):
    link= "https://www.calculator.net/fuel-cost-calculator.html"
    driver.get(link)
    time.sleep(3)
    distance= driver.find_element(By.NAME, "tripdistance")
    distance.clear()
    distance.send_keys("300")
    print("Trip Distance set to 300 km")
    fuel= driver.find_element(By.NAME,"fuelefficiency")
    fuel.clear()
    fuel.send_keys("4")
    print("Fuel Efficiency set to 4")
    price= driver.find_element(By.NAME,"gasprice")
    price.clear()
    price.send_keys("6")
    print("Gas/Fuel Price set to $6")
    time.sleep(1)
    driver.find_element(By.NAME,"x").click()
    print("Calculating trip data")
    time.sleep(3)
    result = driver.find_element(By.CLASS_NAME, "verybigtext")
    print(result.text)
    if result.text == "This trip will require 12 liters of fuel, which amounts to a fuel cost of $72.":
        print("Calculation successful.")
    else:
        print("Calculation unsuccessful.")
    time.sleep(3)
    driver.quit()
Test(webdriver.Firefox())
Test(webdriver.Chrome())


from bs4 import BeautifulSoup
import requests
import pymongo
import json

url = 'https://www.bolsamadrid.es/esp/aspx/Mercados/Precios.aspx?indice=ESI100000000&punto=indice'
page = requests.get(url)
soup = BeautifulSoup(page.content, 'html.parser')

tabla = soup.find(id='ctl00_Contenido_tblAcciones')
filas = tabla.findAll('tr')

empresasDict = {}
hora = {}

for row in filas[1:]:
    datos_html = row.find_all("td")
    datos_fila = list(map(lambda data: data.text, datos_html))

    nombre = datos_fila[0]
    fecha = datos_fila[7]
    hora[str(nombre)] = datos_fila[8]

    empresasDict[str(nombre)] = {
        "nombre": nombre,
        "fecha": fecha,
        "hora": str(hora[str(nombre)]),
        "ultimo": float(datos_fila[1].replace(",", ".")),
        "%dif": float(datos_fila[2].replace(",", ".")),
        "max": float(datos_fila[3].replace(",", ".")),
        "min": float(datos_fila[4].replace(",", ".")),
        "volumen": int(datos_fila[5].replace(".", "")),
        "efectivo": float(datos_fila[6].replace(".", "").replace(",", "."))
    }

client = pymongo.MongoClient("mongodb://admin:password@localhost:7070/bolsa")

db = client["bolsa"]
col = db["empresas"]
col2 = db["datos"]

for key in empresasDict:
    col.insert_one(empresasDict[key])
    col2.insert_one(empresasDict[key])


import requests, jsonpath, pytest, ast, os, allure, time, webbrowser, subprocess
from xToolkit import xfile
from string import Template
from Utils.parameter_dict import parameter_dict

"""
Created by: juzi
Created time: 2023/6/5 1:17
Purpose:
"""
# 读取测试用例文档
testSuite = xfile.read("接口测试用例.xls").excel_to_dict(sheet=0)

# 创建以时间戳命名的文件夹
timestamp = time.strftime("%Y-%m-%d_%H%M%S", time.localtime())

# pytest装饰器 循环读取测试用例文档内容 自带循环 遍历数据  括号内的含义  变量名，数据
@pytest.mark.parametrize("case_info", testSuite)
def test_requests(case_info):
    url = case_info["请求url"]
    text_dict = parameter_dict().show_parameter()
    print("保存的参数字典：", text_dict)
    if "$" in url:
        url = Template(url).substitute(text_dict)
    api_url = case_info["host参数"] + url
    api_method = case_info["请求方式"]
    api_params = case_info["url携带参数"]
    api_data = case_info["data参数"]
    api_headers = case_info["请求头参数"]
    api_code = case_info["预期响应码"]
    if "$" in api_data:
        api_data = Template(api_data).substitute(text_dict)
    api_response = requests.request(
        url=api_url,
        data=eval(api_data),
        headers=ast.literal_eval(api_headers),
        params=eval(api_params),
        method=api_method)
    # assert login_response.status_code == 200
    if api_response.status_code == api_code:
        print("状态码断言成功！", api_response.status_code)
    else:
        print("状态码断言失败", api_response.status_code)
    extract_parameters = case_info["提取参数"].strip()
    if extract_parameters != "" or len(extract_parameters) != 0:
        if "," in extract_parameters:
            extract_parameters = ast.literal_eval(extract_parameters)
            for i in extract_parameters:
                response_parameters_data = jsonpath.jsonpath(
                    api_response.json(), "$.." + i)
                # 循环保存需要的参数数据到字典
                parameter_dict().set_parameter(i, response_parameters_data[0])
                print("提取参数：" + i + ":" + response_parameters_data[0] + " 保存字典完毕!")
        else:
            extract_parameters = ast.literal_eval(extract_parameters)
            response_parameters_data = jsonpath.jsonpath(
                api_response.json(), "$.." + extract_parameters)
            # 循环保存需要的参数数据到字典
            parameter_dict().set_parameter(extract_parameters, response_parameters_data[0])
            print("提取参数：" + extract_parameters + "：" + response_parameters_data[0] + " 保存字典完毕!")

    else:
        print("提取参数为空，不做相关提取操作,继续执行下一条案例！")

    print(case_info["用例名称"], "执行完毕！")
    print(api_response.text)

    """
    自动生成测试报告 -- allure
    """

if __name__ == '__main__':
    # 运行pytest命令并指定保存结果的文件夹
    pytest_command = f"pytest -vs --capture=sys main.py --clean-alluredir --alluredir=allure-results/{timestamp}"
    subprocess.run(pytest_command, shell=True)
    # 保存pytest测试数据到allure-results/下
    serve_command = f"allure generate allure-results/{timestamp} -o allure_html/{timestamp}/ --clean"
    subprocess.run(serve_command, shell=True)
    # 打开浏览器运行测试报告
    file_path = f"http://localhost:63342/接口自动化框架/allure_html/{timestamp}/index.html"  # 替换为你的index.html文件路径
    webbrowser.open(file_path)


from fastapi import FastAPI
from .models import Item

app = FastAPI()

def __init__(self):
    pass

# v1=================================================================================================
# http://127.0.0.1:8000/
@app.get('/')
def index():
    return {'hello': 'word'}

# http://127.0.0.1:8000/v1/index
@app.get('/v1/index')
def index():
    return {'name': 'flack'}

# http://127.0.0.1:8000/v1/items/123?q=safdf
@app.get('/v1/items/{item_id}')
def get_items(item_id: int, q: str = None):
    return {'item_id': item_id, 'q': q}

@app.put('/v1/items/{item_id}')
async def update_item(item_id: int, item: Item):
    return {'item_id': item_id, 'item_name': item.name}

@app.get('/v1/user/{uid}')
async def user(uid: str):
    return {
        'uid': uid,
        'name': 'flack',
        'age': 23,
        'address': 'shenzhen',
        'score': 100,
        'work': 10
    }

# async def app(scope, receive, send):
#     assert scope['type'] == 'http'
#
#     await send({
#         'type': 'http.response.start',
#         'status': 200,
#         'headers': [
#             [b'content-type', b'text/plain'],
#         ],
#     })
#     await send({
#         'type': 'http.response.body',
#         'body': b'Hello, world!',
#     })

# async def hello_world(message, channels):
#     content = b'
Hello World
'
#     resp = {
#         'status': 200,
#         'headers': [[b'content-type', b'text/html'], ],
#         'content': content,
#     }
#
#     await channels['reply'].send(resp)

def run():
    print('factory api running...')
    return app

# v1=================================================================================================


from django.contrib.auth.models import User
from django.contrib.auth import get_user_model
from rest_framework import authentication
from rest_framework import exceptions
from .hanko import authenticate as hanko_authenticate

User = get_user_model()

def deny(reason):
    raise exceptions.AuthenticationFailed(str(reason))

def extract_token_from_header(header: str) -> str:
    parts = header.split()
    return parts[1] if len(parts) == 2 and parts[0].lower() == "bearer" else None

class HankoAuthentication(authentication.BaseAuthentication):
    def authenticate(self, request):
        authorization = request.headers.get("Authorization")
        if not authorization:
            return None

        token = extract_token_from_header(authorization)
        if not token:
            return deny('No token')

        valid,token_data = hanko_authenticate(token)
        if not valid:
            return deny(token_data)
        if valid:
            if not token_data:
                deny("No data in token")

        hanko_id = token_data.get('sub')

        try:
            user = User.objects.get(hankoprofile__hanko_id = hanko_id)
        except User.DoesNotExist:
            deny('No such user')
        return (user, None)


from datetime import datetime, timezone
from pathlib import Path
from typing import Optional, List, Dict

from datamodel_code_generator import PythonVersion, chdir
from datamodel_code_generator.format import CodeFormatter
from jinja2 import Environment, FileSystemLoader

from fastapi_scaffolder.consts import MODEL_PATH, BUILTIN_TEMPLATE_DIR, BUILTIN_VISITOR_DIR
from fastapi_scaffolder.parser import OpenAPIParser
from fastapi_scaffolder.utils.load_module import dynamic_load_module
from fastapi_scaffolder.visitor import Visitor

class BackendGenerator:
    def __init__(
        self,
        input_name: str,
        input_text: str,
        output_dir: Path,
        template_dir: Optional[Path],
        model_path: Optional[Path] = None,
        enum_field_as_literal: Optional[str] = None,
        custom_visitors: Optional[List[Path]] = None,
    ):
        self.input_name = input_name
        self.input_text = input_text
        self.output_dir = output_dir
        self.template_dir = template_dir or BUILTIN_TEMPLATE_DIR
        self.model_path = model_path or MODEL_PATH
        self.enum_field_as_literal = enum_field_as_literal
        self.custom_visitors = custom_visitors

        self.parser = None
        self.environment = Environment(
            loader=FileSystemLoader(
                self.template_dir or f"{Path(__file__).parent}/template",
                encoding="utf8",
            ),
        )
        self.code_formatter = CodeFormatter(PythonVersion.PY_38, Path().resolve())
        self.visitors: List[Visitor] = []

    def generate_code(self):
        if not self.output_dir.exists():
            self.output_dir.mkdir(parents=True)
        self.generate_models()
        if not self.parser:
            return
        self.generate_templates()
        if self.custom_visitors:
            self.generate_templates(self.custom_visitors)

    def generate_models(self):
        self.parser = OpenAPIParser(self.input_text, enum_field_as_literal=self.enum_field_as_literal or None)
        with chdir(self.output_dir):
            models = self.parser.parse()
        if not models:
            return
        elif isinstance(models, str):
            output = self.output_dir / self.model_path
            modules = {output: (self.input_name, models)}
        else:
            raise Exception('Modular references are not supported in this version')

        timestamp = datetime.now(timezone.utc).replace(microsecond=0).isoformat()
        header = f'''\
#   models file generated by fastapi-scaffolder:
#   filename:  {{filename}}
#   timestamp: {timestamp}'''

        for path, filename_and_body in modules.items():
            filename, body = filename_and_body
            if path is None:
                file = None
            else:
                if not path.parent.exists():
                    path.parent.mkdir(parents=True)
                file = path.open('wt', encoding='utf8')

            print(header.format(filename=filename), file=file)
            if body:
                print('', file=file)
                sql_modeled = body\
                    .rstrip()\
                    .replace("from pydantic", "from sqlmodel")\
                    .replace("BaseModel", "SQLModel")
                print(sql_modeled, file=file)

            if file is not None:
                file.close()

    def generate_templates(self, custom_visitors: Optional[List[Path]] = None):
        results: Dict[Path, str] = {}

        # vars in key-value format
        # keys are used in template, values are injected by template.render
        # initially adding info section from openapi file
        template_vars: Dict[str, object] = {"info": self.parser.parse_info()}

        # load visitors
        visitors_path = custom_visitors or BUILTIN_VISITOR_DIR.rglob("*.py")
        for visitor_path in visitors_path:
            module = dynamic_load_module(visitor_path)
            if hasattr(module, "visit"):
                self.visitors.append(module.visit)
            else:
                raise Exception(f"{visitor_path.stem} does not have any visit function")

        # Call visitors to build template_vars
        for visitor in self.visitors:
            visitor_result = visitor(self.parser, self.model_path)
            template_vars = {**template_vars, **visitor_result}

        for target in self.template_dir.rglob("*"):
            relative_path = target.relative_to(self.template_dir)
            template = self.environment.get_template(str(relative_path))
            result = template.render(template_vars)
            results[relative_path] = self.code_formatter.format_code(result)

        timestamp = datetime.now(timezone.utc).replace(microsecond=0).isoformat()
        header = f"""\
#   file generated by fastapi-scaffolder:
#   filename:  {Path(self.input_name).name}
#   timestamp: {timestamp}"""

        for path, code in results.items():
            with self.output_dir.joinpath(path.with_suffix(".py")).open("wt") as file:
                print(header, file=file)
                print("", file=file)
                print(code.rstrip(), file=file)


import sys
import datetime

'''
redshift_utils_helper.py

Utility modules for the amazon-redshift-utils family of tools

Ian Meyers
Amazon Web Services (2017)
'''

debug = False

# emit a single cloudwatch metric with the given dimensions
def put_metric(cw, namespace, metric_name, dimensions, timestamp, value, unit):
    emit_metrics(cw, namespace, [{
        'MetricName': metric_name,
        'Dimensions': dimensions,
        'Timestamp': datetime.datetime.utcnow() if timestamp is None else timestamp,
        'Value': value,
        'Unit': unit
    }])

# emit all the provided cloudwatch metrics consistent with API limits around batching
def emit_metrics(cw, namespace, put_metrics):
    max_metrics = 20
    group = 0
    print("Publishing %s CloudWatch Metrics" % (len(put_metrics)))

    for x in range(0, len(put_metrics), max_metrics):
        group += 1

        # slice the metrics into blocks of 20 or just the remaining metrics
        put = put_metrics[x:(x + max_metrics)]

        if debug:
            print("Metrics group %s: %s Datapoints" % (group, len(put)))
            print(put)
        try:
            cw.put_metric_data(
                Namespace=namespace,
                MetricData=put
            )
        except:
            print('Pushing metrics to CloudWatch failed: exception %s' % sys.exc_info()[1])

def set_search_paths(conn, schema_name, set_target_schema=None, exclude_external_schemas=False):
    get_schemas_statement = '''
        select nspname
        from pg_catalog.pg_namespace
        where nspname ~ '%s'
    ''' % schema_name

    if exclude_external_schemas is True:
        get_schemas_statement += " and nspname not in (select schemaname from svv_external_schemas)"

    # set default search path
    search_path = 'set search_path = \'$user\',public'

    # add the target schema to the search path
    if set_target_schema is not None and set_target_schema != schema_name:
        search_path = search_path + ', %s' % set_target_schema

    # add all matched schemas to the search path - this could be a single schema, or a pattern
    c = conn.cursor()
    c.execute(get_schemas_statement)
    results = c.fetchall()

    for r in results:
        search_path = search_path + ', %s' % r[0]

    if debug:
        print(search_path)

    c = conn.cursor()
    c.execute(search_path)


import cv2
import numpy as np
from detect_board import *

file_path = "./imgs/chess-9.jpg"

image = cv2.cvtColor(cv2.imread(file_path), cv2.COLOR_BGR2GRAY)

image[image <= 60] = 0
image[image > 60] = 255

image = cv2.cvtColor(image, cv2.COLOR_GRAY2RGB)

distorted = distort_chess_board(image)
plt.imshow(distorted)
plt.show()
# detect_checker_board_corners(image)


from sklearn.neighbors import KNeighborsRegressor
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from sklearn.metrics import mean_absolute_error

def knn_regressor(inputs, output):
  k_mae = []
  for k in range(10):
    # Setting testing and training data
    x_train, x_test, y_train, y_test = train_test_split(inputs, output, test_size=0.1, train_size=0.9)

    scaler = StandardScaler()
    x_train = scaler.fit_transform(x_train)
    x_test = scaler.fit_transform(x_test)

    # Instantiating KNN regressor
    knn_regressor = KNeighborsRegressor(n_neighbors=k+1)
    knn_regressor.fit(x_train, y_train)

    # Defining predictions
    y_pred = knn_regressor.predict(x_test)

    # Getting mean absolute error
    mae = mean_absolute_error(y_test, y_pred)
    k_mae.append(mae)

  return k_mae


from typing import Callable, Dict, Hashable, Optional

import networkx as nx
import numpy as np
from nfp.frameworks import tf
from nfp.preprocessing import features
from nfp.preprocessing.preprocessor import Preprocessor
from nfp.preprocessing.tokenizer import Tokenizer

try:
    import rdkit.Chem
except ImportError:
    rdkit = None

class MolPreprocessor(Preprocessor):
    def __init__(
        self,
        atom_features: Optional[Callable[["rdkit.Chem.Atom"], Hashable]] = None,
        bond_features: Optional[Callable[["rdkit.Chem.Bond"], Hashable]] = None,
        **kwargs,
    ) -> None:
        super(MolPreprocessor, self).__init__(**kwargs)

        self.atom_tokenizer = Tokenizer()
        self.bond_tokenizer = Tokenizer()

        if atom_features is None:
            atom_features = features.atom_features_v1

        if bond_features is None:
            bond_features = features.bond_features_v1

        self.atom_features = atom_features
        self.bond_features = bond_features

    def create_nx_graph(self, mol: "rdkit.Chem.Mol", **kwargs) -> nx.DiGraph:
        g = nx.Graph(mol=mol)
        g.add_nodes_from(((atom.GetIdx(), {"atom": atom}) for atom in mol.GetAtoms()))
        g.add_edges_from(
            (
                (bond.GetBeginAtomIdx(), bond.GetEndAtomIdx(), {"bond": bond})
                for bond in mol.GetBonds()
            )
        )
        return nx.DiGraph(g)

    def get_edge_features(
        self, edge_data: list, max_num_edges
    ) -> Dict[str, np.ndarray]:
        bond_feature_matrix = np.zeros(max_num_edges, dtype=self.output_dtype)
        for n, (start_atom, end_atom, bond_dict) in enumerate(edge_data):
            flipped = start_atom == bond_dict["bond"].GetEndAtomIdx()
            bond_feature_matrix[n] = self.bond_tokenizer(
                self.bond_features(bond_dict["bond"], flipped=flipped)
            )

        return {"bond": bond_feature_matrix}

    def get_node_features(
        self, node_data: list, max_num_nodes
    ) -> Dict[str, np.ndarray]:
        atom_feature_matrix = np.zeros(max_num_nodes, dtype=self.output_dtype)
        for n, atom_dict in node_data:
            atom_feature_matrix[n] = self.atom_tokenizer(
                self.atom_features(atom_dict["atom"])
            )
        return {"atom": atom_feature_matrix}

    def get_graph_features(self, graph_data: dict) -> Dict[str, np.ndarray]:
        return {}

    @property
    def atom_classes(self) -> int:
        """The number of atom types found (includes the 0 null-atom type)"""
        return self.atom_tokenizer.num_classes + 1

    @property
    def bond_classes(self) -> int:
        """The number of bond types found (includes the 0 null-bond type)"""
        return self.bond_tokenizer.num_classes + 1

    @property
    def output_signature(self) -> Dict[str, tf.TensorSpec]:
        if tf is None:
            raise ImportError("Tensorflow was not found")
        return {
            "atom": tf.TensorSpec(shape=(None,), dtype=self.output_dtype),
            "bond": tf.TensorSpec(shape=(None,), dtype=self.output_dtype),
            "connectivity": tf.TensorSpec(shape=(None, 2), dtype=self.output_dtype),
        }

    @property
    def padding_values(self) -> Dict[str, tf.constant]:
        """Defaults to zero for each output"""
        if tf is None:
            raise ImportError("Tensorflow was not found")
        return {
            key: tf.constant(0, dtype=self.output_dtype)
            for key in self.output_signature.keys()
        }

    @property
    def tfrecord_features(self) -> Dict[str, tf.io.FixedLenFeature]:
        """For loading preprocessed inputs from a tf records file"""
        if tf is None:
            raise ImportError("Tensorflow was not found")
        return {
            key: tf.io.FixedLenFeature(
                [], dtype=self.output_dtype if len(val.shape) == 0 else tf.string
            )
            for key, val in self.output_signature.items()
        }

class SmilesPreprocessor(MolPreprocessor):
    def __init__(self, *args, explicit_hs: bool = True, **kwargs):
        super(SmilesPreprocessor, self).__init__(*args, **kwargs)
        self.explicit_hs = explicit_hs
        assert rdkit is not None, "rdkit required for SmilesPreprocessor"

    def create_nx_graph(self, smiles: str, *args, **kwargs) -> nx.DiGraph:
        mol = rdkit.Chem.MolFromSmiles(smiles)
        if self.explicit_hs:
            mol = rdkit.Chem.AddHs(mol)
        return super(SmilesPreprocessor, self).create_nx_graph(mol, *args, **kwargs)

class BondIndexPreprocessor(MolPreprocessor):
    def get_edge_features(
        self, edge_data: list, max_num_edges
    ) -> Dict[str, np.ndarray]:
        bond_indices = np.zeros(max_num_edges, dtype=self.output_dtype)
        for n, (_, _, edge_dict) in enumerate(edge_data):
            bond_indices[n] = edge_dict["bond"].GetIdx()
        edge_features = super(BondIndexPreprocessor, self).get_edge_features(
            edge_data, max_num_edges
        )
        return {"bond_indices": bond_indices, **edge_features}

    @property
    def output_signature(self) -> Dict[str, tf.TensorSpec]:
        if tf is None:
            raise ImportError("Tensorflow was not found")

        signature = super(BondIndexPreprocessor, self).output_signature
        signature["bond_indices"] = tf.TensorSpec(
            shape=(None,), dtype=self.output_dtype
        )
        return signature

class SmilesBondIndexPreprocessor(SmilesPreprocessor, BondIndexPreprocessor):
    pass


# Here the already provided tools for testing the network are
# reorganized into funtions to be used in the notebook when needed

import os
import torch
import numpy as np
import matplotlib.pyplot as plt

import random
import imageio

# Plot and store the comparison image between an original
# sample and the reconstructed one (already provided)
def plot_comparison(net, sample, store_fig=False):

    # build comparison image
    #img = test_dataset[0][0].unsqueeze(0).to(device)
    img = sample[0].unsqueeze(0).to(net.device)
    net.eval()
    with torch.no_grad():
        rec_img  = net(img)
    fig, axs = plt.subplots(1, 2, figsize=(12,6))
    axs[0].imshow(img.cpu().squeeze().numpy(), cmap='gist_gray')
    axs[0].set_title('Original image')
    axs[1].imshow(rec_img.cpu().squeeze().numpy(), cmap='gist_gray')
    axs[1].set_title('Reconstructed image')
    plt.tight_layout()
    plt.pause(0.1)

    # Show figure and store them if desired
    if store_fig:
        plt.savefig('Comparison_plot.png')
    plt.show()
    plt.close()
    return

# Function to plot the first two variables of the encoded
# representation of the encoded samples given as argument
def plot_encoded_space(encoded_samples, n_samples_to_plot = 1000):

    # define colors associated to each label
    color_map = { 0: '#1f77b4',
                  1: '#ff7f0e',
                  2: '#2ca02c',
                  3: '#d62728',
                  4: '#9467bd',
                  5: '#8c564b',
                  6: '#e377c2',
                  7: '#7f7f7f',
                  8: '#bcbd22',
                  9: '#17becf' }

    ### Visualize encoded space
    encoded_samples_reduced = random.sample(encoded_samples, n_samples_to_plot)
    plt.figure(figsize=(8,6))
    for enc_sample, label in tqdm(encoded_samples_reduced):
        plt.plot(enc_sample[0], enc_sample[1], marker='.', color=color_map[label])
    plt.grid(True)
    plt.legend([plt.Line2D([0], [0], ls='', marker='.', color=c, label=l) for l, c in color_map.items()], color_map.keys())
    plt.tight_layout()
    plt.show()

    return

# Function that takes two digits, start from the corresponding
# centroids of the encoded digits and build the gif of the
# reconstructed images of the points between them (to see the evolution)
def morphing_digits_gif(net, encoded_samples, start_digit, end_digit,
                        t_update=0.1, n_frames=200, gif_directory='results/'):

    # Find centroids of the two digits in the endoded space
    start_samples = encoded_samples[ encoded_samples[:,1] == start_digit ]
    end_samples = encoded_samples[ encoded_samples[:,1] == end_digit ]
    start_centroid = np.stack(start_samples[:,0]).mean(axis=0)
    end_centroid = np.stack(end_samples[:,0]).mean(axis=0)

    # Compute array with intermediate points
    middle_points = np.array([ np.linspace(start_centroid[0], end_centroid[0], n_frames),
                               np.linspace(start_centroid[1], end_centroid[1], n_frames),
                               np.linspace(start_centroid[2], end_centroid[2], n_frames),
                               np.linspace(start_centroid[3], end_centroid[3], n_frames) ])

    # Decode every intermediate point and store the correspondent image in a temp folder
    os.makedirs('tmp_gif_dir')
    for i in range(n_frames):
        filename = 'tmp_gif_dir/image_'+str(i).zfill(3)+'.png'
        net.generate_from_encoded_sample(middle_points[:,i], filename)

    # Order all filenames
    all_filenames = os.listdir('tmp_gif_dir')
    all_filenames = sorted(all_filenames)

    # Build the GIF
    images = []
    for filename in all_filenames:
        images.append(imageio.imread('tmp_gif_dir/'+filename))

    # Store the GIF
    gif_filename = gif_directory+'from_'+str(start_digit)+'_to_'+str(end_digit)+'_smooth_evol.gif'
    imageio.mimsave(gif_filename, images, format='GIF', duration=t_update)
    print('GIF is stored as '+gif_filename)

    # Delete temp files and folder
    for filename in all_filenames:
        os.remove('tmp_gif_dir/'+filename)
    os.rmdir('tmp_gif_dir/')
    return


import json
from channels.generic.websocket import AsyncWebsocketConsumer
from .models import Message, Group
from asgiref.sync import sync_to_async

class GroupChatConsumer(AsyncWebsocketConsumer):
    async def connect(self):
        self.group_id = self.scope['url_route']['kwargs']['group_id']
        self.group = await self.get_group_or_error(self.group_id)
        print("id",self.group_id)

        # Join the group channel
        await self.channel_layer.group_add(
            self.group.name,
            self.channel_name
        )

        await self.accept()

    async def disconnect(self, close_code):
        # Leave the group channel
        await self.channel_layer.group_discard(
            self.group.name,
            self.channel_name
        )

    async def receive(self, text_data):
        data = json.loads(text_data)
        message_content = data['message']
        user = self.scope['user']

        # Create and save the message to the database
        # message = await Message.objects.create(
        #     user=user,
        #     group=self.group,
        #     content=message_content
        # )

        message = await self.save_message_to_database(user,group =self.group, content = message_content)

        # Send the message to the group
        await self.channel_layer.group_send(
            self.group.name,
            {
                'type': 'chat_message',
                'message': message_content,
                'username': user.username,
                'timestamp': message.timestamp.strftime('%Y-%m-%d %H:%M:%S'),
            }
        )

    async def chat_message(self, event):
        await self.send(text_data=json.dumps(event))

    @sync_to_async
    def save_message_to_database(self, user, group, content):
        message = Message.objects.create(
            user=user,
            group=group,
            content=content,
        )
        return message

    @sync_to_async
    def get_group_or_error(self, group_id):
        try:
            group = Group.objects.get(id=group_id)
            print(self.scope['user'])
            if not self.scope['user'].members.filter(id=group.id).exists():
                raise ValueError('You do not have permission to join this group.')
            return group
        except Group.DoesNotExist:
            raise ValueError('Group not found.')


import ifaddr

adapters = ifaddr.get_adapters(include_unconfigured=True)

for adapter in adapters:
        print("IPs of network adapter " + adapter.nice_name)
        for ip in adapter.ips:
            if ip.is_IPv4:
                addr = ip.ip.split(".")
                addr[len(addr) - 1] = "51"
                addr1 = ".".join(addr)
                print("IPv4: " + addr1)


# coding: utf-8

import csv
import math
import random
import re
import time

import requests
from pyquery import PyQuery as pq
from selenium import webdriver
from selenium.common import exceptions
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.ui import WebDriverWait
from user_agent import generate_user_agent

class DianPingSpider(object):
    def __init__(self):
        # self.have_data = self.compare_down_data()
        self.header_css = {
            'Host': 's3plus.meituan.net',
            'Accept-Encoding': 'gzip',
            'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.90 Safari/537.36'
        }
        self.iframe = (By.TAG_NAME, 'iframe')

    def start_driver(self):
        '''启动firefox57,设置firefox的请求头'''
        random_user_agent = generate_user_agent(os=('win', 'linux'))
        fp = webdriver.FirefoxProfile()
        fp.set_preference("general.useragent.override", random_user_agent)
        fp.update_preferences()
        shopdriver = webdriver.Firefox(firefox_profile=fp)
        return shopdriver

    def dianping_login(self, shopdriver):
        shopdriver.get('http://account.dianping.com/login')
        print(input('请扫描屏幕二维码登录'))
        return 'ok, 登陆成功了!'

    def get_dianping_provinces(self, shopdriver):
        '''访问大众点评城市列表,获取所有的城市列表和的对应的森马门店链接'''
        shopdriver.get('http://www.dianping.com/citylist')
        shopdriver.find_element_by_css_selector('#main > div.underline.province > div.choose-city > div > div.province-choose > p').click()
        all_provinces = shopdriver.find_elements_by_css_selector('#main > div.underline.province > div.choose-city > div > div.province-choose > div > div > span')
        # 获取所有的省份列表
        total_provinces = len(all_provinces)
        for index in range(1, total_provinces + 1):
            # 点击省份下拉框列表
            shopdriver.find_element_by_css_selector('#main > div.underline.province > div.choose-city > div > div.province-choose > p').click()
            # 获取其中某个省份的名称
            name_css_selector = '#main > div.underline.province > div.choose-city > div > div.province-choose > div > div > span:nth-child({index})'.format(index=index)
            province_name = shopdriver.find_element_by_css_selector(name_css_selector).text
            # 选择某个省份
            province_select_js = '''document.querySelector('#main > div.underline.province > div.choose-city > div > div.province-choose > div > div > span:nth-child({index})').click()'''.format(index=index)
            # 不知什么原因,导致用js无法获得省份名称,只能用selenium定位元素
            #     province_name_js = '''return document.querySelector('#main > div.underline.province > div.choose-city > div > div.province-choose > div > div > span:nth-child({index})').innerText;'''.format(index=index)
            #     province_name = shopdriver.execute_script(province_name_js)
            shopdriver.execute_script(province_select_js)
            #     shopdriver.implicitly_wait(10)
            time.sleep(2)
            # 再选择一个省份之后,点击获取城市的清单
            shopdriver.find_element_by_css_selector('#main > div.underline.province > div.choose-city > div > div.city-choose').click()
            citys = shopdriver.find_elements_by_css_selector('#main > div.underline.province > div.choose-city > div > div.city-choose > div > div > a')
            # 循环获取每一个城市的名称和对应链接
            time.sleep(3)
            for city_index in range(1, len(citys) + 1):
                #         city_name_js = '''return document.querySelector('#main > div.underline.province > div.choose-city > div > div.city-choose > div > div > a:nth-child({city_index})').innerText'''.format(city_index=city_index)
                #         one_city_name = shopdriver.execute_script(city_name_js)
                # 获取城市列表中的城市名称
                city_css_selector = '#main > div.underline.province > div.choose-city > div > div.city-choose > div > div > a:nth-child({index})'.format(index=city_index)
                one_city_name = shopdriver.find_element_by_css_selector(city_css_selector).text
                # 获得城市列表中每个城市的链接
                one_city_href = shopdriver.find_element_by_css_selector(city_css_selector).get_attribute('href')
                #         city_click_js = '''document.querySelector('#main > div.underline.province > div.choose-city > div > div.city-choose > div > div > a:nth-child({index})').click()'''.format(index=city_index)
                #         shopdriver.execute_script(city_click_js)
                # 将访问获得的城市链接保存本地
                with open('d:\\test\\dianping_provinces', 'a+', encoding='utf-8') as f:
                    if one_city_name != '':
                        one_row = '{}, {}, {}\n'.format(province_name, one_city_name, one_city_href)
                        print(one_row)
                        f.write(one_row)
                yield province_name, one_city_name, one_city_href

    def search_semir_new_window(self, one_city_href, shopdriver):
        shopdriver.get(one_city_href)
        default_handle = shopdriver.current_window_handle
        search_input = (By.ID, 'J-search-input')
        input_box = WebDriverWait(shopdriver, 5).until(EC.presence_of_element_located(search_input))
        input_box.clear()
        try:
            shopdriver.implicitly_wait(10)
            shopdriver.find_element_by_id('J-search-input').send_keys('森马')
            shopdriver.find_element_by_id('J-all-btn').click()
        except exceptions.NoSuchElementException as e:
            print('搜索框无法搜索到')
        print('搜索跳转成功,开始循环抓取店铺列表\n')
        return default_handle

    def get_total_semir_href(self, shopdriver):
        for province_name, one_city_name, one_city_href in self.get_dianping_provinces(shopdriver):
            default_handle = self.search_semir_new_window(one_city_href, shopdriver)
            handles = shopdriver.window_handles
            if len(handles) >= 2:
                handles.remove(default_handle)
                search_handle = handles[0]
                shopdriver.switch_to.window(search_handle)
            time.sleep(random.random() * 5)
            total_shop_contents = shopdriver.find_element_by_css_selector('body > div.section.Fix.J-shop-search > div.bread.J_bread > span:nth-child(3)').text
            total_shop_counts = int(re.findall('[0-9]{1,10}', total_shop_contents)[0])
            shop_lst_pages = math.ceil(total_shop_counts / 15)
            real_url = shopdriver.current_url
            one_city = []
            for i in range(1, shop_lst_pages + 1):
                page_url = real_url + '/p' + str(i)
                shopdriver.get(page_url)
                time.sleep(random.random() * 5)
                total_shops = shopdriver.find_elements_by_css_selector('#shop-all-list > ul > li')
                for one_shop in total_shops:
                    one_shop_href = one_shop.find_element_by_css_selector('div.pic > a').get_attribute('href')
                    one_shop_title = one_shop.find_element_by_css_selector('div.txt > div.tit > a').get_attribute(
                        'title')
                    one_shop_comment_star = one_shop.find_element_by_css_selector(
                        'div.txt > div.comment > span').get_attribute('title')
                    one_shop_comment_href = one_shop.find_element_by_css_selector(
                        'div.txt > div.comment > a').get_attribute('href')
                    one_city.append((one_shop_href, one_shop_title, one_shop_comment_star))
                    with open('d:\\test\\dianping_semir', 'a+', encoding='utf-8') as f:
                        one_row = '{}, {}, {}, {}, {}, {}\n'.format(province_name, one_city_name, total_shop_counts,
                                                                    one_shop_href, one_shop_title,
                                                                    one_shop_comment_star)
                        print(one_row)
                        f.write(one_row)
            shopdriver.close()
            shopdriver.switch_to.window(default_handle)

    def pinglun_deal(self, data):
        #     每一条评论的提取,删除评论中不需要的信息
        pinglun = data("div.review-words.Hide").html()
        try:
            len(pinglun)
        except:
            pinglun = data("div.review-words").html()
        less_words_loc = pinglun.find('less-words')
        if less_words_loc != -1:
            pinglun = pinglun[:less_words_loc - 14]
        return pinglun

    def css_get(self, doc):
        total_lst_dict = {}
        css_link = "http:" + doc("head > link:nth-child(9)").attr("href")
        background_link = requests.get(css_link, headers=self.header_css, timeout=30)
        css_text = background_link.text
        r = r'background-image: url(.*?);'
        r2 = r'(background-image: url.*?;)'
        need_replace_text = re.findall(r2, css_text)
        total_matches = re.findall(r, background_link.text)
        for i in need_replace_text:
            css_text = css_text.replace(i, '')
        total_lst = []
        if total_matches:
            for one_match in total_matches:
                svg_link = one_match.replace(")", "").replace("(", "http:")
                status, list_svg_y = self.svg_text(svg_link)
                total_lst.extend(list_svg_y)
        # 对css进行解析,明白css中background对应的坐标的数据的转换
        dict_css = self.css_dict(css_text)
        for x, y, c in total_lst:
            total_lst_dict[y] = (x, c)
        return total_lst_dict, dict_css

    # 2-字体库链接和字体库
    def svg_text(sefl, url):
        html = requests.get(url, timeout=30)
        svg_text_r2 = r'<text x="(.*?)" y="(.*?)">(.*?)</text>'
        svg_text_re = re.findall(svg_text_r2, html.text)
        if svg_text_re:
            return 1, svg_text_re
        else:
            svg_text_r = r'<textPath xlink:href="(.*?)" textLength="(.*?)">(.*?)</textPath>'
            svg_text_re = re.findall(svg_text_r, html.text)
            dict_avg = {}
            # 生成svg加密字体库字典
            for data in svg_text_re:
                dict_avg[data[0].replace("#", "")] = list(data[2])
            svg_y_r = r'<path id="(.*?)" d="(.*?) (.*?) (.*?)"/>'
            svg_y_re = re.findall(svg_y_r, html.text)
            list_y = []
            # 存储('18', 'M0', '748', 'H600') eg:(x坐标，未知，y坐标，未知)
            for data in svg_y_re:
                list_y.append([data[0], data[2]])
            res_yindex_words = []
            for index, one_y in enumerate(list_y):
                mixed_words = ''.join(dict_avg[str(index + 1)])
                one_y.append(mixed_words)
                res_yindex_words.append(one_y)
            return 2, res_yindex_words

    # 3-生成css字库字典
    def css_dict(self, html):
        css_text_r = r'.([a-zA-Z0-9]{1,6}){background:(.*?)px (.*?)px;}'
        css_text_re = re.findall(css_text_r, html)
        dict_css = {}
        for data in css_text_re:
            """
            加密字库.gqi4j {background: -98.0px -745.0px;}与svg文件对应关系，x/14，就是svg文件加密字体下标
            y，原样返回，需要在svg函数中做处理
            """
            x = int(float(data[1]) / -14)
            y = -int(float(data[2]))
            dict_css[data[0]] = (data[1], data[2], x, y)
        return dict_css

    def css_decode(self, total_lst_dict, dict_css, pinglun):
        #     每一条评论数据,将其字符串化,然后删除掉不需要的信息
        pinglun_text = pinglun.replace('<svgmtsi class="', ',').replace('"/>', ",").replace('">', ",")
        pinglun_list = [x.strip('\n').strip(' ') for x in pinglun_text.split(",") if x != '']
        pinglun_list = [x for x in pinglun_list if x != '']
        #     获取加密后的所有文字列表
        encryt_words_lst = list(dict_css.keys())
        #     循环每个字符,对加密的字符,匹配解密
        pinglun_str = []
        for msg in pinglun_list:
            # 如果有加密标签
            if msg in encryt_words_lst:
                # 参数说明：[x,y] css样式中background 的[x/14，y]
                x = dict_css[msg][2]
                y = dict_css[msg][3]
                for g in total_lst_dict.keys():
                    if y < int(g):
                        try:
                            pinglun_str.append(total_lst_dict[g][1][x])
                            break
                        except IndexError:
                            pinglun_str.append(' ')
                            break
            # 没有加密标签
            else:
                pinglun_str.append(msg.replace("\n", ""))
        #     将所有的解密后的字符,拼接起来.得到真实评论数据
        if pinglun_str:
            str_pinglun = ''.join(pinglun_str)
            # 删除掉所有的空格数据
            str_pinglun = str_pinglun.strip(' ')
        else:
            str_pinglun = ''
        return str_pinglun

    def down_one_shop_comments(self, shopdriver, have_data):
        fieldnames = ['province_name', 'city_name', 'one_city_one_shop_url', 'one_city_one_shop_name', 'userName',
                      'userID', 'startShop', 'describeShop', 'pinglunTime', 'pinglun']
        # 对于已经下载的大众点评的所有森马门店数据重新读入(这里筛选了没有星级评分的店铺)
        with open(r"D:\Test\dazhongdianping_semir_address.csv", 'r', encoding='utf-8') as f:
            total_rows = f.read().split('\n')
        # 将每一条记录变成列表
        # file = [i.split(',') for i in total_rows]
        # file =  self.have_data
        file = have_data
        for province_name, city_name, total_shops, one_city_one_shop_url, one_city_one_shop_name, shop_stars in file:
            # 根据实际情况,得到所有的评论链接,后缀为 "/review_all",所有点评的页面的数据的加密方式比较一致
            review_all_url = one_city_one_shop_url + '/review_all'
            shopdriver.get(review_all_url)
            shopdriver.implicitly_wait(30)
            time.sleep(2)
            try:
                # 读取页面上评论计数，并将文字描述中的数字提取出来，当作总评论数，根据每页15条评论，计算出总页数
                comments_contents = shopdriver.find_element_by_css_selector('html > body > div#index-main >  div#review-list.review-list > div.review-list-container > div.review-shop-wrap > div.rank-info span.reviews').text
                comment_count = int(re.findall('[0-9]{1,10000}', comments_contents)[0])
                commnet_pages = math.ceil(comment_count / 15)
                print('{}一共有{}页{}条评论'.format(one_city_one_shop_name, commnet_pages, comment_count))
                # 如果评论为0，直接跳过，对下一个门店继续操作
                if comment_count == 0:
                    one_comment_dict = {
                        "province_name": province_name,
                        "city_name": city_name,
                        "one_city_one_shop_url": one_city_one_shop_url,
                        "one_city_one_shop_name": one_city_one_shop_name,
                        "userName": '',
                        "userID": '',
                        "startShop": '',
                        "describeShop": '',
                        "pinglunTime": '',
                        "pinglun": ''
                    }
                    with open('total_semir_comments_deal.csv', 'a+', newline='', errors='ignore',  encoding='utf-8') as f:
                        f_csv = csv.DictWriter(f, fieldnames=fieldnames)
                        f_csv.writeheader()
                        f_csv.writerow(one_comment_dict)
                    print('没有评论, 跳过')
                else:
                    # 通过总页数，每页访问，获得评论数据
                    for one_page in range(1, commnet_pages + 1):
                        print('{}的第{}页评论正在下载中……'.format(one_city_one_shop_name, one_page))
                        if one_page == 1:
                            # 如果是第一页，不对链接进行操作，如果是后续页面，则加上“/p页数”
                            pass
                        else:
                            review_all_url = one_city_one_shop_url + '/review_all/p{}'.format(one_page)
                            # 访问新的页数,抓取评论
                            shopdriver.get(review_all_url)
                            shopdriver.implicitly_wait(5)
                            time.sleep(3)
                        # 调用pyquery,对网页源码进行解析,参考csdn上大神的思路
                        doc = pq(shopdriver.page_source)
                        # 获取当前页面的字体css和svg数据,并处理成规范格式
                        time.sleep(1)
                        total_lst_dict, dict_css = self.css_get(doc)
                        pinglunLi = list(doc("div.reviews-items > ul > li").items())
                        time.sleep(8)
                        # 通过解密，获得一页评论的所有数据
                        # 针对部分店铺数据计数有两条评论,但是实际上没有评论的问题,在pinglunLi的评论列表中进行判断,如果pinglunLi不为空,继续执行
                        if pinglunLi:
                            for data in pinglunLi:
                                # 用户名
                                userName = data("div.main-review > div.dper-info > a").text()
                                if userName == '':
                                    userName = data("div.main-review > div.dper-info > span").html()
                                # 用户ID链接
                                try:
                                    userID = "http://www.dianping.com" + data("div.main-review > div.dper-info > a").attr("href")
                                # except TypeError:
                                #     userID = "http://www.dianping.com/" + data("div.main-review > div.dper-info > span").html()
                                except:
                                    userID = ''
                                # 用户评分星级[10-50]
                                try:
                                    startShop = str(data("div.review-rank > span").attr("class")).split(" ")[1].replace("sml-str", "")
                                except IndexError:
                                    startShop = ''
                                # 用户描述：机器：非常好 环境：非常好 服务：非常好 人均：0元
                                describeShop = data("div.review-rank > span.score").text()
                                # 关键部分，评论HTML,待处理，评论包含隐藏部分和直接展示部分，默认从隐藏部分获取数据，没有则取默认部分。（查看更多）
                                time.sleep(1)
                                pinglun = self.pinglun_deal(data)
                                #  print(css_decode(total_lst_dict, dict_css, pinglun))
                                # 发表评论的时间
                                pinglunTime = data("div.main-review > div.misc-info.clearfix > span.time").text()
                                one_comment_dict = {
                                    "province_name": province_name,
                                    "city_name": city_name,
                                    "one_city_one_shop_url": one_city_one_shop_url,
                                    "one_city_one_shop_name": one_city_one_shop_name,
                                    "userName": userName,
                                    "userID": userID,
                                    "startShop": startShop,
                                    "describeShop": describeShop,
                                    "pinglunTime": pinglunTime,
                                    "pinglun": self.css_decode(total_lst_dict, dict_css, pinglun)
                                }
                                print('{}: {}'.format(userName, one_comment_dict["pinglun"]))
                                with open('total_semir_comments_deal.csv', 'a+', newline='', errors='ignore', encoding='utf-8') as f:
                                    f_csv = csv.DictWriter(f, fieldnames=fieldnames)
                                    f_csv.writeheader()
                                    f_csv.writerow(one_comment_dict)
                                print('{}的评论下载完成\n'.format(one_city_one_shop_name))
                        else:
                            print('计数上有数据,但实际无数据')
            except exceptions.InvalidSessionIdException:
                print('浏览器已经关闭')
                shopdriver.quit()
                break
            except Exception as e:
                print(e)
                wrong_page = shopdriver.find_elements_by_css_selector('html > body > div.not-found > div.not-found-content > div.not-found-right > p.not-found-words1')
                if wrong_page:
                    print('需要重新登录,更换请求头', one_city_one_shop_url)
                    shopdriver.quit()
                    break
                    # continue
                else:
                    print('出现了错误,请及时处理', one_city_one_shop_url)
                    continue

    def compare_down_data(self):
        not_down_shop_file = []
        with open(r'D:\Python\VisualCode\total_semir_comments_deal.csv', 'r', encoding='utf-8') as f1:
            f_csv1 = csv.reader(f1)
            file_down = list(f_csv1)
        coments_shop_url = [i[2] for i in file_down if i[2] != 'one_city_one_shop_url']
        with open(r"D:\Test\dazhongdianping_semir_address.csv", 'r', encoding='utf-8') as f2:
            total_rows =  csv.reader(f2)
            file_config = list(total_rows)
        config_shop_url = [i[3] for i in file_config]
        not_down_href = list(set(config_shop_url).difference(set(coments_shop_url)))
        for one_href in not_down_href:
            for one_row in file_config:
                if one_href in one_row:
                    not_down_shop_file.append(one_row)
        print('还有{}家等待抓取'.format(len(not_down_shop_file)))
        return not_down_shop_file

    def restart_driver_down(self):
        count = 1
        while True:
            have_data = self.compare_down_data()
            shopdriver = self.start_driver()
            self.dianping_login(shopdriver)
            self.down_one_shop_comments(shopdriver, have_data)
            if count > 10:
                break
            count += 1

if __name__ == "__main__":
    one_comment = DianPingSpider()
    # shopdriver = one_comment.start_driver()
    # one_comment.dianping_login(shopdriver)
    # one_comment.get_total_semir_href(shopdriver)
    one_comment.restart_driver_down()
    # print(one_comment.have_data)


"""
Simple training loop; Boilerplate that could apply to any arbitrary neural network,
so nothing in this file really has anything to do with GPT specifically.
"""

import time
from collections import defaultdict

import torch
from torch.utils.data.dataloader import DataLoader

from utils.min_gpt_utils import CfgNode

class Trainer:

    @staticmethod
    def get_default_config():
        C = CfgNode()
        # device to train on
        C.device = 'auto'
        # dataloder parameters
        C.num_workers = 4
        # optimizer parameters
        C.max_iters = None
        C.batch_size = 64
        C.learning_rate = 3e-4
        C.betas = (0.9, 0.95)
        C.weight_decay = 0.1  # only applied on matmul weights
        C.grad_norm_clip = 1.0
        return C

    def __init__(self, config, model, train_dataset, val_dataset, save_weights_path=None):
        self.config = config
        self.model = model
        self.optimizer = None
        self.train_dataset = train_dataset
        self.val_dataset = val_dataset
        self.save_weights_path = save_weights_path  # string where to save weights i.e. "best_model_path.pth"
        self.callbacks = defaultdict(list)

        # determine the device we'll train on
        if config.device == 'auto':
            self.device = 'cuda' if torch.cuda.is_available() else 'cpu'
        else:
            self.device = config.device
        self.model = self.model.to(self.device)
        print("running on device", self.device)

        # variables that will be assigned to trainer class later for logging and etc
        self.iter_num = 0
        self.iter_time = 0.0
        self.iter_dt = 0.0

    def add_callback(self, onevent: str, callback):
        self.callbacks[onevent].append(callback)

    def set_callback(self, onevent: str, callback):
        self.callbacks[onevent] = [callback]

    def trigger_callbacks(self, onevent: str):
        for callback in self.callbacks.get(onevent, []):
            callback(self)

    def run(self, log_level=0):
        model, config = self.model, self.config

        # set up the optimizer
        self.optimizer = model.configure_optimizers(config)

        # set up the dataloader
        train_loader = DataLoader(
            self.train_dataset,
            sampler=torch.utils.data.RandomSampler(self.train_dataset, replacement=True, num_samples=int(1e10)),
            shuffle=False,
            # pin_memory=True,
            batch_size=config.batch_size,
            num_workers=config.num_workers,
        )

        # set up the validation dataloader
        val_loader = DataLoader(
            self.val_dataset,
            shuffle=False,
            batch_size=config.batch_size,
            num_workers=config.num_workers,
        )

        model.train()
        self.iter_num = 0
        self.iter_time = time.time()
        data_iter = iter(train_loader)

        best_val_loss = float('inf')
        epochs_without_improvement = 0

        while True:

            # fetch the next batch (x, y) and re-init iterator if needed
            try:
                batch = next(data_iter)
            except StopIteration:
                data_iter = iter(train_loader)
                batch = next(data_iter)
            batch = [t.to(self.device) for t in batch]
            x, y = batch

            # forward the model
            logits, self.loss = model(x, y)

            # backprop and update the parameters
            model.zero_grad(set_to_none=True)
            self.loss.backward()
            torch.nn.utils.clip_grad_norm_(model.parameters(), config.grad_norm_clip)
            self.optimizer.step()

            # Validation
            if self.iter_num % config.val_interval == 0:
                if log_level:
                    tnow = time.time()
                    self.iter_dt = tnow - self.iter_time
                    self.iter_time = tnow
                    print(f"iter_dt {self.iter_dt * 1000:.2f}ms; iter {self.iter_num}: train loss {self.loss.item():.5f}")

                model.eval()  # Set the model to evaluation mode
                with torch.no_grad():
                    val_losses = []
                    for val_batch in val_loader:
                        val_batch = [t.to(self.device) for t in val_batch]
                        val_x, val_y = val_batch
                        val_logits, val_loss = model(val_x, val_y)
                        val_losses.append(val_loss.item())
                    average_val_loss = sum(val_losses) / len(val_losses)
                    if log_level:
                        print("avg val loss: ", average_val_loss)

                # Update the best validation loss and check for improvement
                if average_val_loss < best_val_loss:
                    best_val_loss = average_val_loss
                    epochs_without_improvement = 0
                    # Save the model weights
                    if self.save_weights_path:
                        torch.save(model.state_dict(), self.save_weights_path)
                else:
                    epochs_without_improvement += 1

                # Terminate if validation loss doesn't improve for a certain number of epochs
                if epochs_without_improvement >= config.patience:
                    break

                model.train()  # set model back to train

            # iter termination conditions
            self.iter_num += 1

            if config.max_iters is not None and self.iter_num >= config.max_iters:
                break


import numpy as np
import torch
if torch.cuda.is_available():
    DEVICE = "cuda:0"
else:
    DEVICE = "cpu"

class LeNetWeakLabeler(torch.nn.Module):

    # Need to input input dims and output dims
    # Can input dict_training_param: {learning rate, num batches, num epoches, fc1 size, fc2 size}
    def __init__(self, in_dim_h=28, in_dim_w=28, in_dim_c=1, out_dim=2, dict_training_param=None):
        super(LeNetWeakLabeler, self).__init__()

        self.in_dim_h = in_dim_h
        self.in_dim_w = in_dim_w
        self.in_dim_c = in_dim_c
        self.out_dim = out_dim

        if dict_training_param is not None:
            self.learning_rate = dict_training_param["learning_rate"]
            self.num_batches = dict_training_param["num_batches"]
            self.num_epochs = dict_training_param["num_epochs"]
            if "dropout" in dict_training_param.keys():
                self.dropout = dict_training_param["dropout"]
            else:
                self.dropout = False
        else:  # If training params not specified, use random params as follows
            self.learning_rate = 1e-3
            self.num_batches = 5
            self.num_epochs = 80
            self.dropout = False

        # architecture parameters
        self.out_c_conv1 = 6
        self.k_conv1 = 5
        self.p_conv1 = 2
        self.k_pool1 = 2
        self.s_pool1 = 2
        self.out_c_conv2 = 16
        self.k_conv2 = 5
        self.k_pool2 = 2
        self.s_pool2 = 2
        self.d_fc1 = self.compute_fc_size()
        self.d_fc2 = 45
        self.d_fc3 = 21

        self.conv1 = torch.nn.Conv2d(in_channels=self.in_dim_c, out_channels=self.out_c_conv1, kernel_size=self.k_conv1, padding=self.p_conv1)
        self.dropout1 = torch.nn.Dropout2d(p=0.2)
        self.avgpool1 = torch.nn.AvgPool2d(kernel_size=self.k_pool1, stride=self.s_pool1)
        self.conv2 = torch.nn.Conv2d(in_channels=self.out_c_conv1, out_channels=self.out_c_conv2, kernel_size=self.k_conv2)
        self.dropout2 = torch.nn.Dropout2d(p=0.3)
        self.avgpool2 = torch.nn.AvgPool2d(kernel_size=self.k_pool2, stride=self.s_pool2)
        self.flatten = torch.nn.Flatten()

        self.fc1 = torch.nn.Sequential(torch.nn.Linear(self.d_fc1, self.d_fc2), torch.nn.Sigmoid())
        self.dropout3 = torch.nn.Dropout(p=0.5)
        self.fc2 = torch.nn.Sequential(torch.nn.Linear(self.d_fc2, self.d_fc3), torch.nn.Sigmoid())
        self.fc3 = torch.nn.Sequential(torch.nn.Linear(self.d_fc3, self.out_dim), torch.nn.Softmax())

    def forward(self, x):
        out = self.conv1(x)
        out = torch.sigmoid(out)
        if self.dropout:
            out = self.dropout1(out)
        out = self.avgpool1(out)
        out = self.conv2(out)
        out = torch.sigmoid(out)
        if self.dropout:
            out = self.dropout2(out)
        out = self.avgpool2(out)
        out = self.flatten(out)
        out = self.fc1(out)
        if self.dropout:
            out = self.dropout3(out)
        out = self.fc2(out)
        out = self.fc3(out)
        return out

    # update training params
    def update_training_params(self, dict_training_param: dict):
        self.learning_rate = dict_training_param["learning_rate"]
        self.num_batches = dict_training_param["num_batches"]
        self.num_epochs = dict_training_param["num_epochs"]
        if "dropout" in dict_training_param.keys():
            self.dropout = dict_training_param["dropout"]
        else:
            self.dropout = False
        return

    # compute shape of tensor output from previous params to determine first fc size
    def compute_fc_size(self):
        h_conv1 = compute_next_shape(prev_shape=self.in_dim_h, padding=self.p_conv1, dilation=1, kernel_size=self.k_conv1, stride=1)
        h_pool1 = compute_next_shape(prev_shape=h_conv1, padding=0, dilation=1, kernel_size=self.k_pool1, stride=self.s_pool1)
        h_conv2 = compute_next_shape(prev_shape=h_pool1, padding=0, dilation=1, kernel_size=self.k_conv2, stride=1)
        h_pool2 = compute_next_shape(prev_shape=h_conv2, padding=0, dilation=1, kernel_size=self.k_pool2, stride=self.s_pool2)
        w_conv1 = compute_next_shape(prev_shape=self.in_dim_w, padding=self.p_conv1, dilation=1, kernel_size=self.k_conv1, stride=1)
        w_pool1 = compute_next_shape(prev_shape=w_conv1, padding=0, dilation=1, kernel_size=self.k_pool1, stride=self.s_pool1)
        w_conv2 = compute_next_shape(prev_shape=w_pool1, padding=0, dilation=1, kernel_size=self.k_conv2, stride=1)
        w_pool2 = compute_next_shape(prev_shape=w_conv2, padding=0, dilation=1, kernel_size=self.k_pool2, stride=self.s_pool2)
        fc_size = self.out_c_conv2 * h_pool2 * w_pool2
        return fc_size

    # retrieve variable tensors
    def get_parameters(self):
        conv1_w = self.conv1.weight
        conv1_b = self.conv1.bias
        conv2_w = self.conv2.weight
        conv2_b = self.conv2.bias
        fc1_w = self.fc1[0].weight
        fc1_b = self.fc1[0].bias
        fc2_w = self.fc2[0].weight
        fc2_b = self.fc2[0].bias
        fc3_w = self.fc3[0].weight
        fc3_b = self.fc3[0].bias
        return {"conv1_w": conv1_w, "conv1_b": conv1_b, "conv2_w": conv2_w, "conv2_b": conv2_b,
                "fc1_w": fc1_w, "fc1_b": fc1_b, "fc2_w": fc2_w, "fc2_b": fc2_b, "fc3_w": fc3_w, "fc3_b": fc3_b}

    # retrieve size of the model in bytes
    def get_size(self):
        dict_params = self.get_parameters()
        size = 0
        for key in dict_params.keys():
            size += torch.numel(dict_params[key])
        return size * 4

    # input float tensor output prob of class 1 as numpy array
    def marginal(self, X):
        # if X.shape[0] >= 100:
        #     num_split = 100
        # else:
        #     num_split = 1
        # X_split = np.split(X, num_split, axis=0)
        # out_all = []
        # for i in range(num_split):
        #     X_tensor = torch.from_numpy(X_split[i]).to(DEVICE)
        #     out = self(X_tensor).cpu().detach().numpy()
        #     out_all.append(out)
        # out_all = np.concatenate(out_all)
        # return out_all[:, 1]
        X_tensor = torch.from_numpy(X).to(DEVICE)
        out = self(X_tensor).cpu().detach().numpy()
        return out[:, 1]

    # input float tensor output entire prob matrix as numpy array
    def prob_matrix(self, X):
        # if X.shape[0] >= 100:
        #     num_split = 100
        # else:
        #     num_split = 1
        # X_split = np.split(X, num_split, axis=0)
        # out_all = []
        # for i in range(num_split):
        #     X_tensor = torch.from_numpy(X_split[i]).to(DEVICE)
        #     out = self(X_tensor).cpu().detach().numpy()
        #     out_all.append(out)
        # out_all = np.concatenate(out_all)
        # return out_all
        X_tensor = torch.from_numpy(X).to(DEVICE)
        out = self(X_tensor).cpu().detach().numpy()
        return out

    # train the model
    def train_cnn(self, X, y, verbose=False):

        criterion = torch.nn.CrossEntropyLoss()
        optimizer = torch.optim.Adam(self.parameters(), lr=self.learning_rate)

        loss_list = []
        acc_list = []
        total_step = self.num_batches

        batches = batch_loader(X, y, num_batches=self.num_batches)

        for epoch in range(self.num_epochs):
            for i, (images, labels) in enumerate(batches):
                images_tensor = torch.from_numpy(images).to(DEVICE)
                labels_tensor = torch.from_numpy(labels).long().to(DEVICE)
                # Run the forward pass
                outputs = self(images_tensor)
                loss = criterion(outputs, labels_tensor)
                loss_list.append(loss.item())
                # Backprop and perform Adam optimisation
                optimizer.zero_grad()
                loss.backward()
                optimizer.step()

                if verbose:
                    # Track the accuracy
                    total = labels.shape[0]
                    _, predicted = torch.max(outputs.data, 1)
                    correct = (predicted == labels_tensor).sum().item()
                    acc_list.append(correct / total)
                    print('Epoch [{}/{}], Step [{}/{}], Loss: {:.4f}, Accuracy: {:.2f}%'
                          .format(epoch + 1, self.num_epochs, i + 1, total_step, loss.item(), (correct / total) * 100))
        return self

# compare if two models have the same parameters
def cnn_equal(model1, model2):
    params1 = model1.get_parameters()
    params2 = model2.get_parameters()
    for key in params1.keys():
        if key not in params2.keys():
            return False
        if not torch.equal(params1[key], params2[key]):
            return False
    return True

# batch loader of data, input X, y are numpy arrays
def batch_loader(X, y, num_batches):
    shuffler = np.random.permutation(X.shape[0])
    X_shuffled = X[shuffler]
    y_shuffled = y[shuffler]
    X_split = np.array_split(X_shuffled, num_batches)
    y_split = np.array_split(y_shuffled, num_batches)

    data = []
    for i in range(num_batches):
        data.append((X_split[i], y_split[i]))

    return data

# compute shape of next layer in one dimension
def compute_next_shape(prev_shape, padding, dilation, kernel_size, stride):
    return (prev_shape + 2 * padding - dilation * (kernel_size - 1) - 1) // stride + 1


import pandas as pd
from typing import Dict, Any, Optional
from datetime import timedelta

class MotuPayloadGenerator:

    def __init__(self, data: pd.DataFrame, payload: Dict[str, Any], output_filename: str,
                 days_offset: Optional[int] = 1):
        self.data = data
        self.payload = payload
        self.output_filename = output_filename
        self.area_details = []
        self.days_offset = days_offset

    def _process_row(self, row):
        tokens = self.output_filename.split(".")
        product_details = {
            'latitude_min': row["lat"],
            'longitude_min': row["lon"],
            'latitude_max': row["lat"],
            'longitude_max': row["lon"],
            'depth_min': row["depth"],
            'depth_max': row["depth"],
            'out_name': f"{row['ID']}-{tokens[0]}.{tokens[-1]}",
            'date_min': row['time'].strftime('%Y-%m-%d %H:%M:%S'),
            'date_max': (row['time'] + timedelta(days=self.days_offset)).strftime('%Y-%m-%d %H:%M:%S'),
        }
        product_details.update(self.payload)
        return product_details

    def run(self):
        return [self._process_row(row) for _, row in self.data.iterrows()]


from pathlib import Path
from typing import Literal, Optional

import soundfile as sf
from telegram import Update
from telegram.ext import CallbackContext, MessageHandler, filters

from assistantbot.ai.text.prompts.pronunciation import (
    GLOBAL_PRONUNCIATION_ASSESSMENT,
    WORD_PRONUNCIATION_ASSESSMENT_PARTICULAR,
    WORDS_PRONUNCIATION_ASSESSMENT_BASE,
)
from assistantbot.ai.voice.pronunciation import PronunciationAssessment
from assistantbot.ai.voice.synthesizer import VoiceSynthesizer
from assistantbot.ai.voice.whisper import transcript_audio
from assistantbot.conversation.base import ConversationHandler
from assistantbot.conversation.chains import (
    get_conversation_chain,
    update_memory,
)
from assistantbot.logs.configuration import logger

class VoiceHandler(ConversationHandler):
    def __init__(
        self,
        grading_system: Optional[
            Literal["hundred_mark", "five_points"]
        ] = "hundred_mark",
        granularity: Optional[
            Literal["phoneme", "word", "full"]
        ] = "phoneme",
    ):
        """
        This class handles the voice messages sent to the bot.

        Parameters
        ----------
        grading_system : Optional[Literal["hundred_mark", "five_points"]]
            The grading system to use for the pronunciation assessment,

        granularity : Optional[Literal["phoneme", "word", "full"]], optional
            The granularity to use for the pronunciation assessment,
        """
        super().__init__(filters.VOICE)
        self.pronuntiation_assessment = PronunciationAssessment(
            grading_system=grading_system, granularity=granularity
        )

    def handler(self) -> MessageHandler:
        """
        This function returns the message handler.

        Returns
        -------
        MessageHandler
            The message handler.
        """
        return MessageHandler(self._type, self.callback, block=False)

    async def callback(
        self, update: Update, context: CallbackContext
    ) -> None:
        """
        This function is called when a voice message is sent to the bot.

        Parameters
        ----------
        update : Update
            The update object from Telegram.
        context : _type_
            The context object from Telegram.
        """
        # Get the message text
        response_message = """
🚀 Hey there, folks!
We're moving to @lingolearn_bot for an even better English learning experience!
While this direction will no longer be available, rest assured that everything remains the same, just in a new direction.
See you there! 🌟📚😊
"""

        # Send the start message to the user
        await context.bot.send_message(
            chat_id=update.effective_chat.id,
            text=response_message,
        )

    @staticmethod
    def _process_incoming_audio(input_file: str, output_file: str) -> None:
        """
        This function converts an audio file to .wav format and saves it in
        the specified output file.

        Parameters
        ----------
        input_file : str
            The input audio file.
        output_file : str
            The output audio file.
        """
        # Convert the audio file to .wav
        data, samplerate = sf.read(input_file)
        sf.write(output_file, data, samplerate)

        # Delete the input file
        Path(input_file).unlink()

    @staticmethod
    async def _transcript_voice_message(input_file: str) -> str:
        """
        This function transcripts the voice message and returns the text
        using Whisper API.

        Parameters
        ----------
        input_file : str
            The input audio file.

        Returns
        -------
        str
            The text of the voice message.
        """
        transcription = await transcript_audio(input_file)
        return transcription

    async def _create_text_response(
        self, user_id: int, entry_message: str
    ) -> str:
        """
        This function creates the text response using the handler of the
        text conversation.

        Parameters
        ----------
        entry_message : str
            The text of the voice message.

        Returns
        -------
        str
            The text response.
        """
        # Get the conversation chain
        conversation_chain = get_conversation_chain(user_id)

        response_message = await conversation_chain.apredict(
            input=entry_message
        )

        # Update the memory
        update_memory(user_id, conversation_chain)

        return response_message

    async def _get_pronuntiation_assessment_response(
        self, reference_text: str, input_audio_path: str
    ) -> str:
        """
        This function performs the pronunciation assessment of a given audio
        file and returns the assessment.

        Parameters
        ----------
        reference_text : str
            The reference text to use for the assessment.
        input_audio_path : str
            The path of the input audio file.

        Returns
        -------
        str
            The string with the assessment of the pronunciation.
        """
        (
            json_recognition_result,
            assessment_result,
        ) = await self.pronuntiation_assessment.get_assessment(
            reference_text, input_audio_path
        )

        # Get the global assessment result
        global_assessment = self.pronuntiation_assessment.get_global_scores(
            assessment_result
        )

        # Get the word assessment result
        word_assessment = self.pronuntiation_assessment.get_words_scores(
            json_recognition_result
        )

        # Create the assessment string for word assessment
        assessment_words_string = WORDS_PRONUNCIATION_ASSESSMENT_BASE
        tagged_text = ""

        for word in word_assessment:
            # If there is a word with a bad pronunciation, add it to the
            # assessment string
            if word.accuracy_score <= 95:
                # Get the string of the syllabes
                syllabes_string = "".join(
                    f"{s.syllabe} ({s.accuracy_score})"
                    + f"{'❗' if s.accuracy_score <= 85 else '✅'}"
                    for s in word.syllabes
                )

                assessment_words_string += (
                    WORD_PRONUNCIATION_ASSESSMENT_PARTICULAR.format(
                        word=word.word, syllabes_string=syllabes_string
                    )
                )

            # Add the word to the colored text
            if word.accuracy_score >= 95:
                tag = "i"
            elif word.accuracy_score >= 90:
                tag = "u"
            else:
                tag = "s"
            tagged_text += f"<{tag}>{word.word}</{tag}> "

        def __create_score_assessment(score: int) -> str:
            """
            This function creates a string with the score and the emoji
            depending on the score.

            Parameters
            ----------
            score : int
                The score.

            Returns
            -------
            str
                The string with the score and the emoji.
            """
            return str(score) + f"{'❗' if score <= 85 else '✅'}"

        # Create the assessment string for global assessment
        assessment_global_string = GLOBAL_PRONUNCIATION_ASSESSMENT.format(
            phrase=tagged_text,
            pronunciation_score=__create_score_assessment(
                global_assessment.pronunciation_score
            ),
            accuracy_score=__create_score_assessment(
                global_assessment.accuracy_score
            ),
            fluency_score=__create_score_assessment(
                global_assessment.fluency_score
            ),
        )

        if assessment_words_string == WORDS_PRONUNCIATION_ASSESSMENT_BASE:
            # If there are no words with a bad pronunciation, return only the
            # global assessment
            assessment_words_string = (
                "\n Nice! You pronounced all" " the words correctly!"
            )

        return assessment_global_string + assessment_words_string