#! .\venv\
# encoding: utf-8
# @Time : 2023/4/18
# @Author : Spike
# @Descr :
import ast
import copy
import hashlib
import io
import json
import os.path
import subprocess
import threading
import time
from concurrent.futures import ThreadPoolExecutor
import Levenshtein
import psutil
import re
import tempfile
import shutil
from contextlib import ExitStack
import logging
import yaml
import requests
import tiktoken
logger = logging
from sklearn.feature_extraction.text import CountVectorizer
import numpy as np
from scipy.linalg import norm
import pyperclip
import random
import gradio as gr
import toolbox
from prompt_generator import SqliteHandle
"""contextlib 是 Python 标准库中的一个模块,提供了一些工具函数和装饰器,用于支持编写上下文管理器和处理上下文的常见任务,例如资源管理、异常处理等。
官网:https://docs.python.org/3/library/contextlib.html"""
class Shell(object):
def __init__(self, args, stream=False):
self.args = args
self.subp = subprocess.Popen(args, shell=True,
stdin=subprocess.PIPE, stderr=subprocess.PIPE,
stdout=subprocess.PIPE, encoding='utf-8',
errors='ignore', close_fds=True)
self.__stream = stream
self.__temp = ''
def read(self):
logger.debug(f'The command being executed is: "{self.args}"')
if self.__stream:
sysout = self.subp.stdout
try:
with sysout as std:
for i in std:
logger.info(i.rstrip())
self.__temp += i
except KeyboardInterrupt as p:
return 3, self.__temp + self.subp.stderr.read()
finally:
return 3, self.__temp + self.subp.stderr.read()
else:
sysout = self.subp.stdout.read()
syserr = self.subp.stderr.read()
self.subp.stdin
if sysout:
logger.debug(f"{self.args} \n{sysout}")
return 1, sysout
elif syserr:
logger.error(f"{self.args} \n{syserr}")
return 0, syserr
else:
logger.debug(f"{self.args} \n{[sysout], [sysout]}")
return 2, '\n{}\n{}'.format(sysout, sysout)
def sync(self):
logger.debug('The command being executed is: "{}"'.format(self.args))
for i in self.subp.stdout:
logger.debug(i.rstrip())
self.__temp += i
yield self.__temp
for i in self.subp.stderr:
logger.debug(i.rstrip())
self.__temp += i
yield self.__temp
def timeStatistics(func):
"""
统计函数执行时常的装饰器
"""
def statistics(*args, **kwargs):
startTiem = time.time()
obj = func(*args, **kwargs)
endTiem = time.time()
ums = startTiem - endTiem
print('func:{} > Time-consuming: {}'.format(func, ums))
return obj
return statistics
def copy_temp_file(file):
if os.path.exists(file):
exdir = tempfile.mkdtemp()
temp_ = shutil.copy(file, os.path.join(exdir, os.path.basename(file)))
return temp_
else:
return None
def md5_str(st):
# 创建一个 MD5 对象
md5 = hashlib.md5()
# 更新 MD5 对象的内容
md5.update(str(st).encode())
# 获取加密后的结果
result = md5.hexdigest()
return result
def html_tag_color(tag, color=None, font='black'):
"""
将文本转换为带有高亮提示的html代码
"""
if not color:
rgb = (random.randint(0, 255), random.randint(0, 255), random.randint(0, 255))
color = f"rgb{rgb}"
tag = f' {tag} '
return tag
def html_a_blank(__href, name=''):
if not name:
name = __href
a = f'{name}'
return a
def html_download_blank(__href, file_name='temp', dir_name=''):
if os.path.exists(__href):
__href = f'/file={__href}'
if not dir_name:
dir_name = file_name
a = f'{file_name}'
return a
def html_local_img(__file):
a = f'
|<\/p><\/div>$')
pattern_markdown_p = re.compile(r'^
|<\/div>$')
def thread_write_chat(chatbot, history):
"""
对话记录写入数据库
"""
private_key = toolbox.get_conf('private_key')[0]
chat_title = chatbot[0][1].split()
i_say = pattern_markdown.sub('', chatbot[-1][0])
if history:
gpt_result = history
else: # 如果历史对话不存在,那么读取对话框
gpt_result = [pattern_markdown.sub('', v) for i in chatbot for v in i]
if private_key in chat_title:
SqliteHandle(f'ai_private_{chat_title[-2]}').inset_prompt({i_say: gpt_result})
else:
SqliteHandle(f'ai_common_{chat_title[-2]}').inset_prompt({i_say: gpt_result})
base_path = os.path.dirname(__file__)
prompt_path = os.path.join(base_path, 'prompt_users')
def reuse_chat(result, chatbot, history, pro_numb):
"""复用对话记录"""
if result is None or result == []:
return chatbot, history, gr.update(), gr.update(), '', gr.Column.update()
else:
if pro_numb:
chatbot += result
history += [pattern_markdown.sub('', _) for i in result for _ in i]
else:
chatbot.append(result[-1])
history += [pattern_markdown.sub('', _) for i in result[-2:] for _ in i]
print(chatbot[-1][0])
i_say = pattern_markdown.sub('', chatbot[-1][0])
return chatbot, history, i_say, gr.Tabs.update(selected='chatbot'), '', gr.Column.update(visible=False)
def num_tokens_from_string(listing: list, encoding_name: str = 'cl100k_base') -> int:
"""Returns the number of tokens in a text string."""
count_tokens = 0
for i in listing:
encoding = tiktoken.get_encoding(encoding_name)
count_tokens += len(encoding.encode(i))
return count_tokens
def spinner_chatbot_loading(chatbot):
loading = [''.join(['.' * random.randint(1, 5)])]
# 将元组转换为列表并修改元素
loading_msg = copy.deepcopy(chatbot)
temp_list = list(loading_msg[-1])
if pattern_markdown.match(temp_list[1]):
temp_list[1] = pattern_markdown.sub('', temp_list[1]) + f'{random.choice(loading)}'
else:
temp_list[1] = pattern_markdown_p.sub('', temp_list[1]) + f'{random.choice(loading)}'
# 将列表转换回元组并替换原始元组
loading_msg[-1] = tuple(temp_list)
return loading_msg
def refresh_load_data(chat, history, prompt, crazy_list):
"""
Args:
chat: 聊天组件
history: 对话记录
prompt: prompt dataset组件
Returns:
预期是每次刷新页面,加载最新
"""
is_all = toolbox.get_conf('prompt_list')[0]['key'][0]
data = prompt_retrieval(is_all=[is_all])
prompt.samples = data
selected = random.sample(crazy_list, 4)
return prompt.update(samples=data, visible=True), prompt, chat, history, gr.Dataset.update(samples=[[i] for i in selected]), selected
def txt_converter_json(input_string):
try:
if input_string.startswith("{") and input_string.endswith("}"):
# 尝试将字符串形式的字典转换为字典对象
dict_object = ast.literal_eval(input_string)
else:
# 尝试将字符串解析为JSON对象
dict_object = json.loads(input_string)
formatted_json_string = json.dumps(dict_object, indent=4, ensure_ascii=False)
return formatted_json_string
except (ValueError, SyntaxError):
return input_string
def clean_br_string(s):
s = re.sub('<\s*br\s*/?>', '\n', s) # 使用正则表达式同时匹配
、
、
、< br>和< br/>
return s
def update_btn(self,
value: str = None,
variant: str = None,
visible: bool = None,
interactive: bool = None,
elem_id: str = None,
label: str = None
):
if not variant: variant = self.variant
if not visible: visible = self.visible
if not value: value = self.value
if not interactive: interactive = self.interactive
if not elem_id: elem_id = self.elem_id
if not elem_id: label = self.label
return {
"variant": variant,
"visible": visible,
"value": value,
"interactive": interactive,
'elem_id': elem_id,
'label': label,
"__type__": "update",
}
def update_txt(self,
value: str = None,
lines: int = None,
max_lines: int = None,
placeholder: str = None,
label: str = None,
show_label: bool = None,
visible: bool = None,
interactive: bool = None,
type: str = None,
elem_id: str = None
):
return {
"lines": self.lines,
"max_lines": self.max_lines,
"placeholder": self.placeholder,
"label": self.label,
"show_label": self.show_label,
"visible": self.visible,
"value": self.value,
"type": self.type,
"interactive": self.interactive,
"elem_id": elem_id,
"__type__": "update",
}
def txtx(f, q):
return f
def git_log_list():
ll = Shell("git log --pretty=format:'%s | %h' -n 10").read()[1].splitlines()
return [i.split('|') for i in ll if 'branch' not in i][:5]
class YamlHandle:
def __init__(self, file=os.path.join(prompt_path, 'ai_common.yaml')):
if not os.path.exists(file):
Shell(f'touch {file}').read()
self.file = file
self._load = self.load()
def load(self) -> dict:
with open(file=self.file, mode='r') as f:
data = yaml.safe_load(f)
return data
def update(self, key, value):
date = self._load
if not date:
date = {}
date[key] = value
with open(file=self.file, mode='w') as f:
yaml.dump(date, f, allow_unicode=True)
return date
def dump_dict(self, new_dict):
date = self._load
if not date:
date = {}
date.update(new_dict)
with open(file=self.file, mode='w') as f:
yaml.dump(date, f, allow_unicode=True)
return date
class JsonHandle:
def __init__(self, file):
self.file = file
def load(self) -> object:
with open(self.file, 'r') as f:
data = json.load(f)
return data
if __name__ == '__main__':
html_local_img("docs/imgs/openai-api-key-billing-paid-account.png")