diff --git a/.gitattributes b/.gitattributes
index a28d821..e69de29 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -1 +0,0 @@
-*.html linguist-language=Python
diff --git a/.gitignore b/.gitignore
index 35df236..226cb85 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,37 @@
-/__pycache__
-*.json
-APPData.db
+__pycache__
+.venv
+test.py
+data
+
+
+# Logs
+logs
+*.log
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+pnpm-debug.log*
+lerna-debug.log*
+
+node_modules
+.DS_Store
+dist
+dist-ssr
+coverage
+*.local
+
+/cypress/videos/
+/cypress/screenshots/
+
+# Editor directories and files
+.vscode/*
+!.vscode/extensions.json
+.idea
+*.suo
+*.ntvs*
+*.njsproj
+*.sln
+*.sw?
+
+*.tsbuildinfo
+
diff --git a/README.md b/README.md
deleted file mode 100644
index 2545017..0000000
--- a/README.md
+++ /dev/null
@@ -1,17 +0,0 @@
-# PyGetGPT
-使用python构建的简易语言模型api调用系统
-使用web页面作为GUI易于部署
----
-## 使用的外部库
-- flask
-- flask_cors
-- zhipuai
-- pymysql
-- requests
-- openai
-
-## 使用pip安装依赖
-~~~ bash
-pip install pymysql requests flask zhipuai openai
-pip install pymysql requests flask zhipuai openai -i https://pypi.tuna.tsinghua.edu.cn/simple
-~~~
diff --git a/apiModule/__pycache__/chatglmTurbo.cpython-311.pyc b/apiModule/__pycache__/chatglmTurbo.cpython-311.pyc
deleted file mode 100644
index fb3b326..0000000
Binary files a/apiModule/__pycache__/chatglmTurbo.cpython-311.pyc and /dev/null differ
diff --git a/apiModule/__pycache__/gpt35Turbo.cpython-311.pyc b/apiModule/__pycache__/gpt35Turbo.cpython-311.pyc
deleted file mode 100644
index f07632c..0000000
Binary files a/apiModule/__pycache__/gpt35Turbo.cpython-311.pyc and /dev/null differ
diff --git a/apiModule/__pycache__/gpt4Turbo.cpython-311.pyc b/apiModule/__pycache__/gpt4Turbo.cpython-311.pyc
deleted file mode 100644
index eb9426f..0000000
Binary files a/apiModule/__pycache__/gpt4Turbo.cpython-311.pyc and /dev/null differ
diff --git a/apiModule/__pycache__/qwenTurbo.cpython-311.pyc b/apiModule/__pycache__/qwenTurbo.cpython-311.pyc
deleted file mode 100644
index e2b776b..0000000
Binary files a/apiModule/__pycache__/qwenTurbo.cpython-311.pyc and /dev/null differ
diff --git a/apiModule/chatglmTurbo.py b/apiModule/chatglmTurbo.py
deleted file mode 100644
index 7791b57..0000000
--- a/apiModule/chatglmTurbo.py
+++ /dev/null
@@ -1,27 +0,0 @@
-import zhipuai , config
-
-zhipuai.api_key = config.readConf()["chatglmturbo"]["Authorization"]
-
-def service(prompt,history = ""):
- if history == "":
- response = zhipuai.model_api.invoke(
- model="chatglm_turbo",
- prompt=[
- {"role": "user", "content": prompt},
- ]
- )
- else:
- response = zhipuai.model_api.invoke(
- model="chatglm_turbo",
- prompt=[
- {"role": "user", "content": history[1]["user"]},
- {"role": "assistant", "content": history[1]["bot"]},
- {"role": "user", "content": history[0]["user"]},
- {"role": "assistant", "content": history[0]["bot"]},
- {"role": "user", "content": prompt},
- ]
- )
- if response["code"] == 200:
- return 200, str(response["data"]["choices"][0]["content"]).split('"')[1], response["data"]["usage"]['total_tokens']
- else:
- return 50 , str(response["code"])+response["msg"], 0
diff --git a/apiModule/gpt35Turbo.py b/apiModule/gpt35Turbo.py
deleted file mode 100644
index 88002bf..0000000
--- a/apiModule/gpt35Turbo.py
+++ /dev/null
@@ -1,28 +0,0 @@
-import openai , config
-
-openai.api_key = config.readConf()["gpt3.5turbo"]["Authorization"]
-openai.base_url = config.readConf()["gpt3.5turbo"]["url"]
-
-def service(prompt,history = ""):
- if history == "":
- response = openai.chat.completions.create(
- model="gpt-3.5-turbo",
- messages=[
- {"role": "user", "content": prompt},
- ]
- )
- else:
- response = openai.chat.completions.create(
- model="gpt-3.5-turbo",
- messages=[
- {"role": "user", "content": history[1]["user"]},
- {"role": "assistant", "content": history[1]["bot"]},
- {"role": "user", "content": history[0]["user"]},
- {"role": "assistant", "content": history[0]["bot"]},
- {"role": "user", "content": prompt},
- ]
- )
- if response.choices[0].finish_reason == "stop":
- return 200, response.choices[0].message.content, int(response.usage.total_tokens*3) #三倍tokens消耗
- else:
- return 50 , "API Error!", 0
\ No newline at end of file
diff --git a/apiModule/gpt4Turbo.py b/apiModule/gpt4Turbo.py
deleted file mode 100644
index 0e41fbf..0000000
--- a/apiModule/gpt4Turbo.py
+++ /dev/null
@@ -1,28 +0,0 @@
-import openai , config
-
-openai.api_key = config.readConf()["gpt4.0turbo"]["Authorization"]
-openai.base_url = config.readConf()["gpt4.0turbo"]["url"]
-
-def service(prompt,history = ""):
- if history == "":
- response = openai.chat.completions.create(
- model="gpt-4-1106-preview",
- messages=[
- {"role": "user", "content": prompt},
- ]
- )
- else:
- response = openai.chat.completions.create(
- model="gpt-4-1106-preview",
- messages=[
- {"role": "user", "content": history[1]["user"]},
- {"role": "assistant", "content": history[1]["bot"]},
- {"role": "user", "content": history[0]["user"]},
- {"role": "assistant", "content": history[0]["bot"]},
- {"role": "user", "content": prompt},
- ]
- )
- if response.choices[0].finish_reason == "stop":
- return 200, response.choices[0].message.content, int(response.usage.total_tokens*45) #45倍tokens消耗
- else:
- return 50 , "API Error!", 0
\ No newline at end of file
diff --git a/apiModule/qwenTurbo.py b/apiModule/qwenTurbo.py
deleted file mode 100644
index 70344dd..0000000
--- a/apiModule/qwenTurbo.py
+++ /dev/null
@@ -1,31 +0,0 @@
-import requests , json , config
-
-# 设置请求的目标URL
-url = config.readConf()["qwenturbo"]["url"] # 替换为你的API端点URL
-header = {
- "Content-Type":"application/json",
- "Authorization":config.readConf()["qwenturbo"]["Authorization"]
-}
-
-def service(prompt,history = ""):
- # 设置请求数据
- if history == "":
- data = {
- "model": "qwen-turbo",
- "input":{
- "prompt":f"{prompt}"
- }
- }
- else:
- data = {
- "model": "qwen-turbo",
- "input":{
- "prompt":f"{prompt}",
- "history":history
- }
- }
- # 发送POST请求
- response = json.loads(requests.post(url, json=data ,headers=header).text)
- if 'code' in response:
- return 50,response['code']+response['message'],0
- return 200,response['output']['text'],response["usage"]["total_tokens"]
\ No newline at end of file
diff --git a/config.py b/config.py
deleted file mode 100644
index 4929030..0000000
--- a/config.py
+++ /dev/null
@@ -1,19 +0,0 @@
-import json
-
-def readConf():
- with open('config.json') as f:
- return json.load(f)
-
-def updateConf(data_dict):
- # 打开JSON文件并读取内容
- file_path = 'config.json'
- with open(file_path, 'r') as json_file:
- existing_data = json.load(json_file)
-
- # 将新的数据合并到现有的数据中
- existing_data.update(data_dict)
-
- # 再次打开文件(这次是以写模式),并将更新后的数据保存回文件
- with open(file_path, 'w') as json_file:
- json.dump(existing_data, json_file, indent=4, ensure_ascii=False)
-
diff --git a/configUtil.py b/configUtil.py
new file mode 100644
index 0000000..654cb2c
--- /dev/null
+++ b/configUtil.py
@@ -0,0 +1,84 @@
+import configparser
+
+class ConfigUtil:
+ # 初始化ConfigParser对象
+ config = configparser.ConfigParser()
+
+ def __init__(self,path:str):
+ # 读取并加载配置文件config.ini
+ self.config.read(path,encoding="utf-8")
+
+ def get(self, section: str, key: str) -> str:
+ """
+ 获取配置项的字符串值
+
+ 参数:
+ section (str): 配置文件中的节名
+ key (str): 节中的配置项键名
+
+ 返回:
+ str: 配置项的字符串值
+ """
+ return self.config.get(section, key)
+
+ def getBool(self, section: str, key: str) -> bool:
+ """
+ 获取配置项的布尔值
+
+ 参数:
+ section (str): 配置文件中的节名
+ key (str): 节中的配置项键名
+
+ 返回:
+ bool: 配置项的布尔值
+ """
+ return self.config.getboolean(section, key)
+
+ def getInt(self, section: str, key: str) -> int:
+ """
+ 获取配置项的整数值
+
+ 参数:
+ section (str): 配置文件中的节名
+ key (str): 节中的配置项键名
+
+ 返回:
+ int: 配置项的整数值
+ """
+ return self.config.getint(section, key)
+
+ def getFloat(self, section: str, key: str) -> float:
+ """
+ 获取配置项的浮点数值
+
+ 参数:
+ section (str): 配置文件中的节名
+ key (str): 节中的配置项键名
+
+ 返回:
+ float: 配置项的浮点数值
+ """
+ return self.config.getfloat(section, key)
+
+
+ def getSectionList(self) -> list:
+ """
+ 获取配置文件中的所有节名
+
+ 返回:
+ list: 所有节名的列表
+ """
+ return self.config.sections()
+
+
+ def getKeyList(self, section: str) -> list:
+ """
+ 获取指定节中的所有键名
+
+ 参数:
+ section (str): 配置文件中的节名
+
+ 返回:
+ list: 指定节中的所有键名的列表
+ """
+ return self.config.options(section)
\ No newline at end of file
diff --git a/dao/db/user.py b/dao/db/user.py
new file mode 100644
index 0000000..27cb792
--- /dev/null
+++ b/dao/db/user.py
@@ -0,0 +1,89 @@
+import sqlite3, time
+import configUtil
+
+def getConnection() -> sqlite3.Connection:
+ return sqlite3.connect(configUtil.ConfigUtil("config.ini").get("database","path"))
+
+
+def init():
+ conn = getConnection()
+ cursor = conn.cursor()
+ cursor.execute(
+ '''
+ CREATE TABLE User (
+ uid TEXT,
+ email TEXT,
+ password_hash TEXT,
+ created_at INT,
+ surplus INT);
+ '''
+ )
+ conn.commit()
+ cursor.close()
+ conn.close()
+ print("数据库初始化完成")
+
+
+def addUser(uid: str, email: str, password_hash: str) -> bool:
+ conn = getConnection()
+ cursor = conn.cursor()
+ try:
+ cursor.execute(
+ "INSERT INTO User (uid, email, password_hash, created_at, surplus) VALUES (?, ?, ?, ?, ?);",
+ [uid, email, password_hash, int(time.time()), 0]
+ )
+ conn.commit()
+ return True
+ except sqlite3.IntegrityError:
+ return False
+
+
+def checkUser(uid: str,password_hash) -> bool:
+ """检查用户与密码是否合法 可输入邮箱或uid"""
+ conn = getConnection()
+ cursor = conn.cursor()
+ cursor.execute("SELECT * FROM User WHERE ( uid = ? AND password_hash = ? ) OR ( email = ? AND password_hash = ? )",[uid,password_hash,uid,password_hash])
+ result = cursor.fetchone()
+ return result != None
+
+
+def getUser(uid: str) -> dict:
+ """获取用户信息"""
+ conn = getConnection()
+ cursor = conn.cursor()
+ cursor.execute("SELECT * FROM User WHERE uid = ?",[uid])
+ result = cursor.fetchone()
+ return {"uid":result[0],"email":result[1],"password_hash":result[2],"created_at":result[3],"surplus":result[4]}
+
+
+def updateUserSurplus(uid: str, surplus: int) -> bool:
+ """更新用户剩余额度"""
+ conn = getConnection()
+ cursor = conn.cursor()
+ try:
+ cursor.execute("UPDATE User SET surplus = ? WHERE uid = ?",[surplus,uid])
+ conn.commit()
+ cursor.close()
+ conn.close()
+ except: return False
+ return True
+
+def getUserSurplus(uid: str) -> int:
+ """获取用户剩余额度"""
+ return getUser(uid)["surplus"]
+
+
+def updateUserPasswd(uid: str, password_hash: str) -> bool:
+ """更新用户密码"""
+ conn = getConnection()
+ cursor = conn.cursor()
+ try:
+ cursor.execute("UPDATE User SET password_hash = ? WHERE uid = ?",[password_hash,uid])
+ conn.commit()
+ cursor.close()
+ conn.close()
+ except: return False
+ return True
+
+
+
diff --git a/db.py b/db.py
deleted file mode 100644
index 4000764..0000000
--- a/db.py
+++ /dev/null
@@ -1,226 +0,0 @@
-import config , uuid , pathlib
-
-def getconn():
- try:
- import sqlite3
- conn = sqlite3.connect(config.readConf()["db"]["path"])
- return conn
- except:
- print("DB ERROR")
- return 0
-
-def dbIsOK():
- #打开数据库连接
- path = pathlib.Path(config.readConf()["db"]["path"])
- if not path.is_file():
- init()
-
- try:
- getconn()
- return True
- except:
- return False
-
-def init():
- #打开数据库连接
- db = getconn()
- # 使用 cursor() 方法创建一个游标对象 cursor
- cursor = db.cursor()
- #建表
- cursor.execute(
- '''
- CREATE TABLE usersurplus (
- userkey TEXT,
- surplus INT);
- ''')
- cursor.execute(
- '''
- CREATE TABLE log (
- ip TEXT,
- time INT,
- tokens INT,
- model TEXT,
- userkey TEXT);
- ''')
- # 提交事务
- db.commit()
-
- # 关闭连接
- db.close()
-
-def userSurplus(userkey): #查询userkey剩余配额
- #打开数据库连接
- db = getconn()
- # 使用 cursor() 方法创建一个游标对象 cursor
- cursor = db.cursor()
-
- # 使用 execute() 方法执行 SQL 查询
- cursor.execute("SELECT surplus FROM usersurplus WHERE userkey = ?;",[userkey])
- # 使用 fetchone() 方法获取单条数据.
- data = cursor.fetchone()
-
- # 关闭连接
- db.close()
-
- if data != None:
- return data[0]
- return -99999
-
-def reduce_value(userkey, value): # 减去对应的值
- #打开数据库连接
- db = getconn()
- # 使用 cursor() 方法创建一个游标对象 cursor
- cursor = db.cursor()
-
- # 执行 SQL 查询以获取当前值
- cursor.execute("SELECT surplus FROM usersurplus WHERE userkey = ?;",[userkey])
- current_value = cursor.fetchone()[0]
-
- # 如果没有找到用户,则返回错误信息
- if current_value is None:
- db.close()
- return -1
-
- # 计算新的值
- new_value = current_value - value
-
- # 更新数据库中的值
- cursor.execute("UPDATE usersurplus SET surplus= ? WHERE userkey= ?;",[new_value,userkey])
-
- # 提交事务
- db.commit()
-
- # 关闭连接
- db.close()
-
- # 返回新值
- return 0
-
-def getAllKey():
- #打开数据库连接
- db = getconn()
- # 使用 cursor() 方法创建一个游标对象 cursor
- cursor = db.cursor()
-
- # 使用 execute() 方法执行 SQL 查询
- cursor.execute("SELECT * FROM usersurplus ;")
- # 使用 fetchall() 方法获取结果集
- data = cursor.fetchall()
-
- # 关闭连接
- db.close()
-
- return data
-
-
-def delKey(userkey):
- #打开数据库连接
- db = getconn()
- # 使用 cursor() 方法创建一个游标对象 cursor
- cursor = db.cursor()
-
- # 使用 execute() 方法执行 SQL 查询
- cursor.execute("DELETE FROM usersurplus WHERE userkey = ?;", [userkey])
-
- # 提交事务
- db.commit()
-
- if cursor.rowcount > 0:
- db.close() # 使用 rowcount() 方法查询受影响行数
- return True
- db.close()
- return False
-
-
-def createKey(quota,number=1,key="null"):
- #打开数据库连接
- db = getconn()
- # 使用 cursor() 方法创建一个游标对象 cursor
- cursor = db.cursor()
-
- # 使用 execute() 方法执行 SQL 查询
- output = []
-
- if key == "null":
- for i in range(int(number)):
- key = str(uuid.uuid1())
- output.append(key)
- cursor.execute("INSERT INTO usersurplus (userkey,surplus) VALUES (?, ?);", [key, quota])
- else:
- cursor.execute("INSERT INTO usersurplus (userkey,surplus) VALUES (?, ?);", [key, quota])
- output.append(key)
-
-
- # 提交事务
- db.commit()
-
- db.close()
-
- return output
-
-
-def newLog(ip:str, time:int, tokens:int, model:str, userkey:str):
- #打开数据库连接
- db = getconn()
- # 使用 cursor() 方法创建一个游标对象 cursor
- cursor = db.cursor()
-
- # 使用 execute() 方法执行 SQL 查询
-
- cursor.execute("INSERT INTO log (ip, time, tokens, model, userkey) VALUES (?, ?, ?, ?, ?);", [ip, time, tokens, model, userkey])
-
- # 提交事务
- db.commit()
-
- db.close()
-
-
-def getlog(num:int):
- #打开数据库连接
- db = getconn()
- # 使用 cursor() 方法创建一个游标对象 cursor
- cursor = db.cursor()
-
- # 使用 execute() 方法执行 SQL 查询
- cursor.execute("SELECT * FROM log order by time desc limit ?;", [num])
- # 使用 fetchall() 方法获取结果集
- data = cursor.fetchall()
-
- # 关闭连接
- db.close()
-
- return data
-
-def getLogAllModel():
- #打开数据库连接
- db = getconn()
- # 使用 cursor() 方法创建一个游标对象 cursor
- cursor = db.cursor()
-
- # 使用 execute() 方法执行 SQL 查询
- cursor.execute("SELECT DISTINCT model FROM log ;")
- # 使用 fetchall() 方法获取结果集
- data = cursor.fetchall()
-
- # 关闭连接
- db.close()
-
- return data
-
-def countLog(key:str, value:str):
- #打开数据库连接
- db = getconn()
- # 使用 cursor() 方法创建一个游标对象 cursor
- cursor = db.cursor()
- try:
- # 使用 execute() 方法执行 SQL 查询
- cursor.execute(f"SELECT COUNT(*) FROM log WHERE {key} = ?;", [value])
- # 使用 fetchone() 方法获取结果
- data = cursor.fetchone()
-
- # 关闭连接
- db.close()
- except Exception as e:
- return e
-
- return data[0]
diff --git a/doc/clientConfig.md b/doc/clientConfig.md
deleted file mode 100644
index 36afe45..0000000
--- a/doc/clientConfig.md
+++ /dev/null
@@ -1,7 +0,0 @@
-# 配置文件说明
-{"url": "<此处为api URL>", "userkey": "<此处为你的UserKey>", "context": <此处为1 开启上下位关联功能 默认0关闭>}
-注意:开启上下文关联会消耗大量的token
-# 什么是Token
-在大型语言模型中,"token"是指文本中的一个最小单位。 通常,一个token可以是一个单词、一个标点符号、一个数字、一个符号等。 在自然语言处理中,tokenization是将一个句子或文本分成tokens的过程。 在大型语言模型的训练和应用中,模型接收一串tokens作为输入,并尝试预测下一个最可能的token。
-# 上下文关联
-在使用上下文关联时,模型除了处理你当前的问题时还需要一并将历史对话的一部分共同处理。所以需要消耗更多的token。在本应用中token消耗平均值大约是不开启上下文功能的300%。
\ No newline at end of file
diff --git a/doc/serverapi.md b/doc/serverapi.md
deleted file mode 100644
index 66694e2..0000000
--- a/doc/serverapi.md
+++ /dev/null
@@ -1,17 +0,0 @@
-# server API 接口文档
-
-## 请求格式(json)
-| 键 | 类型 | 必选 | 示例 |
-|---------|------|-----|-----|
-| prompt | str | yes | "你好" |
-| userkey | str | yes | "2b3j41b2xh1hz1" |
-| history | list | no | "history":[{"user":"XXXXXX","bot":"XXXXXX"},{"user":"XXXXXX""bot":"XXXXXX"}] |
-
-
-## 返回格式(json)
-| 键 | 类型 | 示例 |
-|----|------|------|
-| code | int | 200 |
-| output | str | "你好" |
-| surplus | int | 10000 |
-| |
\ No newline at end of file
diff --git a/frontend/env.d.ts b/frontend/env.d.ts
new file mode 100644
index 0000000..ea4ee32
--- /dev/null
+++ b/frontend/env.d.ts
@@ -0,0 +1,3 @@
+///
=a)}}for(var h=this.__startIndex;h t.unconstrainedWidth?null:d:null;i.setStyle("width",f)}var g=i.getBoundingRect();o.width=g.width;var y=(i.style.margin||0)+2.1;o.height=g.height+y,o.y-=(o.height-c)/2}}}function _M(t){return"center"===t.position}function bM(t){var e,n,i=t.getData(),r=[],o=!1,a=(t.get("minShowLabelAngle")||0)*vM,s=i.getLayout("viewRect"),l=i.getLayout("r"),u=s.width,h=s.x,c=s.y,p=s.height;function d(t){t.ignore=!0}i.each((function(t){var s=i.getItemGraphicEl(t),c=s.shape,p=s.getTextContent(),f=s.getTextGuideLine(),g=i.getItemModel(t),y=g.getModel("label"),v=y.get("position")||g.get(["emphasis","label","position"]),m=y.get("distanceToLabelLine"),x=y.get("alignTo"),_=Ur(y.get("edgeDistance"),u),b=y.get("bleedMargin"),w=g.getModel("labelLine"),S=w.get("length");S=Ur(S,u);var M=w.get("length2");if(M=Ur(M,u),Math.abs(c.endAngle-c.startAngle)0?"right":"left":k>0?"left":"right"}var B=Math.PI,F=0,G=y.get("rotate");if(j(G))F=G*(B/180);else if("center"===v)F=0;else if("radial"===G||!0===G){F=k<0?-A+B:-A}else if("tangential"===G&&"outside"!==v&&"outer"!==v){var W=Math.atan2(k,L);W<0&&(W=2*B+W),L>0&&(W=B+W),F=W-B}if(o=!!F,p.x=I,p.y=T,p.rotation=F,p.setStyle({verticalAlign:"middle"}),P){p.setStyle({align:D});var H=p.states.select;H&&(H.x+=p.x,H.y+=p.y)}else{var Y=p.getBoundingRect().clone();Y.applyTransform(p.getComputedTransform());var X=(p.style.margin||0)+2.1;Y.y-=X/2,Y.height+=X,r.push({label:p,labelLine:f,position:v,len:S,len2:M,minTurnAngle:w.get("minTurnAngle"),maxSurfaceAngle:w.get("maxSurfaceAngle"),surfaceNormal:new De(k,L),linePoints:C,textAlign:D,labelDistance:m,labelAlignTo:x,edgeDistance:_,bleedMargin:b,rect:Y,unconstrainedWidth:Y.width,labelStyleWidth:p.style.width})}s.setTextConfig({inside:P})}})),!o&&t.get("avoidLabelOverlap")&&function(t,e,n,i,r,o,a,s){for(var l=[],u=[],h=Number.MAX_VALUE,c=-Number.MAX_VALUE,p=0;p i&&(i=e);var o=i%2?i+2:i+3;r=[];for(var a=0;a5)return;var i=this._model.coordinateSystem.getSlidedAxisExpandWindow([t.offsetX,t.offsetY]);"none"!==i.behavior&&this._dispatchExpand({axisExpandWindow:i.axisExpandWindow})}this._mouseDownPoint=null},mousemove:function(t){if(!this._mouseDownPoint&&Mk(this,"mousemove")){var e=this._model,n=e.coordinateSystem.getSlidedAxisExpandWindow([t.offsetX,t.offsetY]),i=n.behavior;"jump"===i&&this._throttledDispatchExpand.debounceNextCall(e.get("axisExpandDebounce")),this._throttledDispatchExpand("none"===i?null:{axisExpandWindow:n.axisExpandWindow,animation:"jump"===i?null:{duration:0}})}}};function Mk(t,e){var n=t._model;return n.get("axisExpandable")&&n.get("axisExpandTriggerOn")===e}var Ik=function(t){function e(){var n=null!==t&&t.apply(this,arguments)||this;return n.type=e.type,n}return n(e,t),e.prototype.init=function(){t.prototype.init.apply(this,arguments),this.mergeOption({})},e.prototype.mergeOption=function(t){var e=this.option;t&&C(e,t,!0),this._initDimensions()},e.prototype.contains=function(t,e){var n=t.get("parallelIndex");return null!=n&&e.getComponent("parallel",n)===this},e.prototype.setAxisExpand=function(t){E(["axisExpandable","axisExpandCenter","axisExpandCount","axisExpandWidth","axisExpandWindow"],(function(e){t.hasOwnProperty(e)&&(this.option[e]=t[e])}),this)},e.prototype._initDimensions=function(){var t=this.dimensions=[],e=this.parallelAxisIndex=[];E(B(this.ecModel.queryComponents({mainType:"parallelAxis"}),(function(t){return(t.get("parallelIndex")||0)===this.componentIndex}),this),(function(n){t.push("dim"+n.get("dim")),e.push(n.componentIndex)}))},e.type="parallel",e.dependencies=["parallelAxis"],e.layoutMode="box",e.defaultOption={z:0,left:80,top:60,right:80,bottom:60,layout:"horizontal",axisExpandable:!1,axisExpandCenter:null,axisExpandCount:0,axisExpandWidth:50,axisExpandRate:17,axisExpandDebounce:50,axisExpandSlideTriggerArea:[-.15,.05,.4],axisExpandTriggerOn:"click",parallelAxisDefault:null},e}(Rp),Tk=function(t){function e(e,n,i,r,o){var a=t.call(this,e,n,i)||this;return a.type=r||"value",a.axisIndex=o,a}return n(e,t),e.prototype.isHorizontal=function(){return"horizontal"!==this.coordinateSystem.getModel().get("layout")},e}(nb);function Ck(t,e,n,i,r,o){t=t||0;var a=n[1]-n[0];if(null!=r&&(r=Ak(r,[0,a])),null!=o&&(o=Math.max(o,null!=r?r:0)),"all"===i){var s=Math.abs(e[1]-e[0]);s=Ak(s,[0,a]),r=o=Ak(s,[r,o]),i=0}e[0]=Ak(e[0],n),e[1]=Ak(e[1],n);var l=Dk(e,i);e[i]+=t;var u,h=r||0,c=n.slice();return l.sign<0?c[0]+=h:c[1]-=h,e[i]=Ak(e[i],c),u=Dk(e,i),null!=r&&(u.sign!==l.sign||u.span