mirror of
https://github.com/Kakune55/PyGetGPT.git
synced 2025-09-19 08:02:20 +08:00
Compare commits
10 Commits
dfc0071d1f
...
main
Author | SHA1 | Date | |
---|---|---|---|
aab5043fed | |||
98ce021726 | |||
c10d5d6ff8 | |||
64f58ab5ec | |||
dc9d9d9369 | |||
8e086129b7 | |||
4a809254cd | |||
d6dffde18f | |||
d533cfc6d1 | |||
|
68ae60d529 |
1
.gitattributes
vendored
Normal file
1
.gitattributes
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
*.html linguist-language=Python
|
@@ -1,7 +1,7 @@
|
|||||||
import openai , config
|
import openai , config
|
||||||
|
|
||||||
openai.api_key = config.readConf()["gpt3.5turbo"]["Authorization"]
|
openai.api_key = config.readConf()["gpt4.0turbo"]["Authorization"]
|
||||||
openai.base_url = config.readConf()["gpt3.5turbo"]["url"]
|
openai.base_url = config.readConf()["gpt4.0turbo"]["url"]
|
||||||
|
|
||||||
def service(prompt,history = ""):
|
def service(prompt,history = ""):
|
||||||
if history == "":
|
if history == "":
|
||||||
|
79
app_control.sh
Normal file
79
app_control.sh
Normal file
@@ -0,0 +1,79 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
VENV_DIR=".venv"
|
||||||
|
PYTHON_APP="main.py"
|
||||||
|
LOG_FILE="output.log"
|
||||||
|
PID_FILE="app.pid"
|
||||||
|
|
||||||
|
start_app() {
|
||||||
|
if [ ! -d "$VENV_DIR" ]; then
|
||||||
|
echo -e "\033[31m Virtual environment directory $VENV_DIR not found! \033[0m"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ ! -f "$PYTHON_APP" ]; then
|
||||||
|
echo -e "\033[31m Python application $PYTHON_APP not found! \033[0m"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
source "$VENV_DIR/bin/activate"
|
||||||
|
nohup python3 "$PYTHON_APP" > "$LOG_FILE" 2>&1 &
|
||||||
|
echo $! > "$PID_FILE"
|
||||||
|
echo -e "\033[32m Application started! \033[0m"
|
||||||
|
}
|
||||||
|
|
||||||
|
stop_app() {
|
||||||
|
if [ ! -f "$PID_FILE" ]; then
|
||||||
|
echo -e "\033[31m PID file not found! \033[0m"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
pid=$(cat "$PID_FILE")
|
||||||
|
if [ -n "$pid" ] && kill -0 "$pid" 2>/dev/null; then
|
||||||
|
kill "$pid"
|
||||||
|
rm "$PID_FILE"
|
||||||
|
echo -e "\033[32m Application ended! \033[0m"
|
||||||
|
else
|
||||||
|
echo -e "\033[31m Application not running or PID not found! \033[0m"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
check_app_status() {
|
||||||
|
if [ ! -f "$PID_FILE" ]; then
|
||||||
|
echo -e "\033[31m Application not running! \033[0m"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
pid=$(cat "$PID_FILE")
|
||||||
|
if [ -n "$pid" ] && kill -0 "$pid" 2>/dev/null; then
|
||||||
|
echo -e "PID: $pid"
|
||||||
|
echo -e "\033[32m Application running! \033[0m"
|
||||||
|
else
|
||||||
|
echo -e "\033[31m Application not running! \033[0m"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
restart_app() {
|
||||||
|
stop_app
|
||||||
|
start_app
|
||||||
|
echo -e "\033[32m Application restarted! \033[0m"
|
||||||
|
}
|
||||||
|
|
||||||
|
case "$1" in
|
||||||
|
start)
|
||||||
|
start_app
|
||||||
|
;;
|
||||||
|
stop)
|
||||||
|
stop_app
|
||||||
|
;;
|
||||||
|
status)
|
||||||
|
check_app_status
|
||||||
|
;;
|
||||||
|
restart)
|
||||||
|
restart_app
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo -e "\033[33m Usage: $0 {start|stop|status|restart} \033[0m"
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
89
db.py
89
db.py
@@ -33,6 +33,15 @@ def init():
|
|||||||
userkey TEXT,
|
userkey TEXT,
|
||||||
surplus INT);
|
surplus INT);
|
||||||
''')
|
''')
|
||||||
|
cursor.execute(
|
||||||
|
'''
|
||||||
|
CREATE TABLE log (
|
||||||
|
ip TEXT,
|
||||||
|
time INT,
|
||||||
|
tokens INT,
|
||||||
|
model TEXT,
|
||||||
|
userkey TEXT);
|
||||||
|
''')
|
||||||
# 提交事务
|
# 提交事务
|
||||||
db.commit()
|
db.commit()
|
||||||
|
|
||||||
@@ -46,7 +55,7 @@ def userSurplus(userkey): #查询userkey剩余配额
|
|||||||
cursor = db.cursor()
|
cursor = db.cursor()
|
||||||
|
|
||||||
# 使用 execute() 方法执行 SQL 查询
|
# 使用 execute() 方法执行 SQL 查询
|
||||||
cursor.execute(f"SELECT surplus FROM usersurplus WHERE userkey = ?;",[userkey])
|
cursor.execute("SELECT surplus FROM usersurplus WHERE userkey = ?;",[userkey])
|
||||||
# 使用 fetchone() 方法获取单条数据.
|
# 使用 fetchone() 方法获取单条数据.
|
||||||
data = cursor.fetchone()
|
data = cursor.fetchone()
|
||||||
|
|
||||||
@@ -64,7 +73,7 @@ def reduce_value(userkey, value): # 减去对应的值
|
|||||||
cursor = db.cursor()
|
cursor = db.cursor()
|
||||||
|
|
||||||
# 执行 SQL 查询以获取当前值
|
# 执行 SQL 查询以获取当前值
|
||||||
cursor.execute(f"SELECT surplus FROM usersurplus WHERE userkey = ?;",[userkey])
|
cursor.execute("SELECT surplus FROM usersurplus WHERE userkey = ?;",[userkey])
|
||||||
current_value = cursor.fetchone()[0]
|
current_value = cursor.fetchone()[0]
|
||||||
|
|
||||||
# 如果没有找到用户,则返回错误信息
|
# 如果没有找到用户,则返回错误信息
|
||||||
@@ -76,7 +85,7 @@ def reduce_value(userkey, value): # 减去对应的值
|
|||||||
new_value = current_value - value
|
new_value = current_value - value
|
||||||
|
|
||||||
# 更新数据库中的值
|
# 更新数据库中的值
|
||||||
cursor.execute(f"UPDATE usersurplus SET surplus= ? WHERE userkey= ?;",[new_value,userkey])
|
cursor.execute("UPDATE usersurplus SET surplus= ? WHERE userkey= ?;",[new_value,userkey])
|
||||||
|
|
||||||
# 提交事务
|
# 提交事务
|
||||||
db.commit()
|
db.commit()
|
||||||
@@ -94,7 +103,7 @@ def getAllKey():
|
|||||||
cursor = db.cursor()
|
cursor = db.cursor()
|
||||||
|
|
||||||
# 使用 execute() 方法执行 SQL 查询
|
# 使用 execute() 方法执行 SQL 查询
|
||||||
cursor.execute(f"SELECT * FROM usersurplus ;")
|
cursor.execute("SELECT * FROM usersurplus ;")
|
||||||
# 使用 fetchall() 方法获取结果集
|
# 使用 fetchall() 方法获取结果集
|
||||||
data = cursor.fetchall()
|
data = cursor.fetchall()
|
||||||
|
|
||||||
@@ -111,7 +120,7 @@ def delKey(userkey):
|
|||||||
cursor = db.cursor()
|
cursor = db.cursor()
|
||||||
|
|
||||||
# 使用 execute() 方法执行 SQL 查询
|
# 使用 execute() 方法执行 SQL 查询
|
||||||
cursor.execute(f"DELETE FROM usersurplus WHERE userkey = ?;", [userkey])
|
cursor.execute("DELETE FROM usersurplus WHERE userkey = ?;", [userkey])
|
||||||
|
|
||||||
# 提交事务
|
# 提交事务
|
||||||
db.commit()
|
db.commit()
|
||||||
@@ -136,9 +145,9 @@ def createKey(quota,number=1,key="null"):
|
|||||||
for i in range(int(number)):
|
for i in range(int(number)):
|
||||||
key = str(uuid.uuid1())
|
key = str(uuid.uuid1())
|
||||||
output.append(key)
|
output.append(key)
|
||||||
cursor.execute(f"INSERT INTO usersurplus (userkey,surplus) VALUES (?, ?);", [key, quota])
|
cursor.execute("INSERT INTO usersurplus (userkey,surplus) VALUES (?, ?);", [key, quota])
|
||||||
else:
|
else:
|
||||||
cursor.execute(f"INSERT INTO usersurplus (userkey,surplus) VALUES (?, ?);", [key, quota])
|
cursor.execute("INSERT INTO usersurplus (userkey,surplus) VALUES (?, ?);", [key, quota])
|
||||||
output.append(key)
|
output.append(key)
|
||||||
|
|
||||||
|
|
||||||
@@ -149,3 +158,69 @@ def createKey(quota,number=1,key="null"):
|
|||||||
|
|
||||||
return output
|
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]
|
||||||
|
26
log.py
Normal file
26
log.py
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
import json
|
||||||
|
import time as times
|
||||||
|
import db
|
||||||
|
|
||||||
|
def newLog(ip:str,tokens:int, model:str, userkey:str):
|
||||||
|
db.newLog(ip, int(times.time()), tokens, model, userkey)
|
||||||
|
|
||||||
|
def getlog(num:int):
|
||||||
|
if num < 0:
|
||||||
|
num = 10
|
||||||
|
rawdata = db.getlog(num)
|
||||||
|
data = []
|
||||||
|
for i in rawdata:
|
||||||
|
item = list(i)
|
||||||
|
item[1] = times.strftime("%Y-%m-%d %H:%M:%S",times.localtime(i[1]))
|
||||||
|
data.append(item)
|
||||||
|
|
||||||
|
return data
|
||||||
|
|
||||||
|
def modelChartsData(): #按模型用量统计
|
||||||
|
data = []
|
||||||
|
model = db.getLogAllModel()
|
||||||
|
for item in model:
|
||||||
|
data.append({'value':db.countLog("model",item[0]),'name':item[0]})
|
||||||
|
return data
|
||||||
|
|
25
main.py
25
main.py
@@ -1,11 +1,12 @@
|
|||||||
import flask
|
import flask
|
||||||
from flask_cors import CORS
|
from flask_cors import CORS
|
||||||
import db , config
|
import db , config , log
|
||||||
from apiModule import qwenTurbo , chatglmTurbo , gpt35Turbo , gpt4Turbo
|
from apiModule import qwenTurbo , chatglmTurbo , gpt35Turbo , gpt4Turbo
|
||||||
|
|
||||||
app = flask.Flask(__name__)
|
app = flask.Flask(__name__)
|
||||||
CORS(app,origins="*")
|
CORS(app,origins="*")
|
||||||
app.secret_key = b'SQ-{kJE;m(jEBi|{yq]v'
|
app.secret_key = b'SQ-{kJE;m(jEBi|{yq]v'
|
||||||
|
app.config['TRUSTED_PROXIES'] = ['proxy_ip']
|
||||||
|
|
||||||
@app.route('/api/user', methods=['POST'])
|
@app.route('/api/user', methods=['POST'])
|
||||||
def post_data():
|
def post_data():
|
||||||
@@ -48,6 +49,7 @@ def post_data():
|
|||||||
code , output , tokenUsed = gpt4Turbo.service(userRequest['prompt'])
|
code , output , tokenUsed = gpt4Turbo.service(userRequest['prompt'])
|
||||||
|
|
||||||
db.reduce_value(userRequest['userkey'], tokenUsed)
|
db.reduce_value(userRequest['userkey'], tokenUsed)
|
||||||
|
log.newLog(flask.request.headers.get('X-Forwarded-For').split(",")[0], tokenUsed, userRequest["model"], userRequest['userkey'])
|
||||||
return {"code":code,"output":output,"surplus":surplusToken}
|
return {"code":code,"output":output,"surplus":surplusToken}
|
||||||
|
|
||||||
|
|
||||||
@@ -83,6 +85,27 @@ def adminList():
|
|||||||
return flask.render_template("keylist.html",data=data)
|
return flask.render_template("keylist.html",data=data)
|
||||||
return flask.redirect('login')
|
return flask.redirect('login')
|
||||||
|
|
||||||
|
@app.route('/api/modelcount')
|
||||||
|
def apiModelCount():
|
||||||
|
if "admin" in flask.session :
|
||||||
|
data = log.modelChartsData()
|
||||||
|
return data
|
||||||
|
return flask.abort(403)
|
||||||
|
|
||||||
|
@app.route('/admin/log', methods=['GET'])
|
||||||
|
def adminListLog():
|
||||||
|
if "admin" in flask.session :
|
||||||
|
if 'show' in flask.request.args:
|
||||||
|
try:
|
||||||
|
shownum = int(flask.request.values.get('show'))
|
||||||
|
except:
|
||||||
|
return flask.abort(400)
|
||||||
|
else:
|
||||||
|
return flask.abort(400)
|
||||||
|
data = log.getlog(shownum)
|
||||||
|
return flask.render_template("loglist.html",data=data)
|
||||||
|
return flask.redirect('login')
|
||||||
|
|
||||||
@app.route('/admin/createkey', methods=['POST','GET'])
|
@app.route('/admin/createkey', methods=['POST','GET'])
|
||||||
def createkey():
|
def createkey():
|
||||||
if "admin" in flask.session :
|
if "admin" in flask.session :
|
||||||
|
6
requirements.txt
Normal file
6
requirements.txt
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
pymysql
|
||||||
|
requests
|
||||||
|
flask
|
||||||
|
zhipuai
|
||||||
|
openai
|
||||||
|
flask_cors
|
12
start.sh
12
start.sh
@@ -1,12 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
|
|
||||||
# 定义要运行的Python文件
|
|
||||||
PYTHON_APP="main.py"
|
|
||||||
|
|
||||||
# 使用nohup命令启动Python程序,并将其输出重定向到日志文件
|
|
||||||
nohup python3 $PYTHON_APP > output.log 2>&1 &
|
|
||||||
|
|
||||||
# 打印消息,通知用户程序已启动
|
|
||||||
echo "Python application started!"
|
|
||||||
|
|
||||||
# 可以添加任何其他需要的启动逻辑
|
|
45
static/echarts.min.js
vendored
Normal file
45
static/echarts.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
BIN
static/img/loading.gif
Normal file
BIN
static/img/loading.gif
Normal file
Binary file not shown.
After Width: | Height: | Size: 134 KiB |
78
static/index.css
Normal file
78
static/index.css
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
body {
|
||||||
|
font-family: Arial, sans-serif;
|
||||||
|
background-color: #f5f5f5;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
height: 100vh;
|
||||||
|
margin: 0;
|
||||||
|
background-image: url("../static/img/bg_circles.png");
|
||||||
|
background-repeat: repeat;
|
||||||
|
}
|
||||||
|
#chat-container {
|
||||||
|
width: 80%; /* 使用百分比宽度 */
|
||||||
|
max-width: 1300px; /* 最大宽度,防止界面变得过宽 */
|
||||||
|
background-color: #fff;
|
||||||
|
border: 1px solid #ccc;
|
||||||
|
border-radius: 10px;
|
||||||
|
padding: 20px;
|
||||||
|
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
|
||||||
|
}
|
||||||
|
#chat-messages {
|
||||||
|
max-height: 500px;
|
||||||
|
overflow-y: auto;
|
||||||
|
border: 1px solid #ddd;
|
||||||
|
border-radius: 5px;
|
||||||
|
padding: 10px;
|
||||||
|
background-color: #f9f9f9;
|
||||||
|
word-wrap: break-word; /* 自动换行 */
|
||||||
|
white-space: pre-wrap; /* 保留空格并自动换行 */
|
||||||
|
}
|
||||||
|
.message-divider {
|
||||||
|
border-top: 1px solid #ccc;
|
||||||
|
margin: 10px 0;
|
||||||
|
}
|
||||||
|
#user-input {
|
||||||
|
width: 97%;
|
||||||
|
padding: 10px;
|
||||||
|
border: 1px solid #ccc;
|
||||||
|
border-radius: 5px;
|
||||||
|
margin-top: 10px;
|
||||||
|
}
|
||||||
|
#user-input:focus {
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
#user-input::placeholder {
|
||||||
|
color: #999;
|
||||||
|
}
|
||||||
|
#user-input-button {
|
||||||
|
background-color: #007bff;
|
||||||
|
color: #fff;
|
||||||
|
border: none;
|
||||||
|
border-radius: 5px;
|
||||||
|
padding: 10px 20px;
|
||||||
|
margin-top: 10px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
#user-input-button:disabled {
|
||||||
|
background-color: #ccc;
|
||||||
|
cursor: not-allowed;
|
||||||
|
}
|
||||||
|
/* 新增样式 */
|
||||||
|
#additional-controls {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between; /* 左右对齐 */
|
||||||
|
margin-top: 10px;
|
||||||
|
}
|
||||||
|
#additional-controls input[type="checkbox"] {
|
||||||
|
margin-right: 10px;
|
||||||
|
}
|
||||||
|
#additional-controls button {
|
||||||
|
background-color: #466d2b;
|
||||||
|
color: #fff;
|
||||||
|
border: none;
|
||||||
|
border-radius: 5px;
|
||||||
|
padding: 10px 20px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
270
static/loading.css
Normal file
270
static/loading.css
Normal file
@@ -0,0 +1,270 @@
|
|||||||
|
.loading {
|
||||||
|
width: 100%;
|
||||||
|
height: 100vh;
|
||||||
|
opacity: 1;
|
||||||
|
position: fixed;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
z-index: 3;
|
||||||
|
background-color: #fbfbfb;
|
||||||
|
transition: opacity 1s ease;
|
||||||
|
pointer-events: none; /* 确保遮罩不影响下方元素的交互 */
|
||||||
|
}
|
||||||
|
|
||||||
|
.typewriter {
|
||||||
|
--blue: #5C86FF;
|
||||||
|
--blue-dark: #275EFE;
|
||||||
|
--key: #fff;
|
||||||
|
--paper: #EEF0FD;
|
||||||
|
--text: #D3D4EC;
|
||||||
|
--tool: #FBC56C;
|
||||||
|
--duration: 3s;
|
||||||
|
position: relative;
|
||||||
|
-webkit-animation: bounce05 var(--duration) linear infinite;
|
||||||
|
animation: bounce05 var(--duration) linear infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
.typewriter .slide {
|
||||||
|
width: 92px;
|
||||||
|
height: 20px;
|
||||||
|
border-radius: 3px;
|
||||||
|
margin-left: 14px;
|
||||||
|
transform: translateX(14px);
|
||||||
|
background: linear-gradient(var(--blue), var(--blue-dark));
|
||||||
|
-webkit-animation: slide05 var(--duration) ease infinite;
|
||||||
|
animation: slide05 var(--duration) ease infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
.typewriter .slide:before,
|
||||||
|
.typewriter .slide:after,
|
||||||
|
.typewriter .slide i:before {
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
background: var(--tool);
|
||||||
|
}
|
||||||
|
|
||||||
|
.typewriter .slide:before {
|
||||||
|
width: 2px;
|
||||||
|
height: 8px;
|
||||||
|
top: 6px;
|
||||||
|
left: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.typewriter .slide:after {
|
||||||
|
left: 94px;
|
||||||
|
top: 3px;
|
||||||
|
height: 14px;
|
||||||
|
width: 6px;
|
||||||
|
border-radius: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.typewriter .slide i {
|
||||||
|
display: block;
|
||||||
|
position: absolute;
|
||||||
|
right: 100%;
|
||||||
|
width: 6px;
|
||||||
|
height: 4px;
|
||||||
|
top: 4px;
|
||||||
|
background: var(--tool);
|
||||||
|
}
|
||||||
|
|
||||||
|
.typewriter .slide i:before {
|
||||||
|
right: 100%;
|
||||||
|
top: -2px;
|
||||||
|
width: 4px;
|
||||||
|
border-radius: 2px;
|
||||||
|
height: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.typewriter .paper {
|
||||||
|
position: absolute;
|
||||||
|
left: 24px;
|
||||||
|
top: -26px;
|
||||||
|
width: 40px;
|
||||||
|
height: 46px;
|
||||||
|
border-radius: 5px;
|
||||||
|
background: var(--paper);
|
||||||
|
transform: translateY(46px);
|
||||||
|
-webkit-animation: paper05 var(--duration) linear infinite;
|
||||||
|
animation: paper05 var(--duration) linear infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
.typewriter .paper:before {
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
left: 6px;
|
||||||
|
right: 6px;
|
||||||
|
top: 7px;
|
||||||
|
border-radius: 2px;
|
||||||
|
height: 4px;
|
||||||
|
transform: scaleY(0.8);
|
||||||
|
background: var(--text);
|
||||||
|
box-shadow: 0 12px 0 var(--text), 0 24px 0 var(--text), 0 36px 0 var(--text);
|
||||||
|
}
|
||||||
|
|
||||||
|
.typewriter .keyboard {
|
||||||
|
width: 120px;
|
||||||
|
height: 56px;
|
||||||
|
margin-top: -10px;
|
||||||
|
z-index: 1;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.typewriter .keyboard:before,
|
||||||
|
.typewriter .keyboard:after {
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
}
|
||||||
|
|
||||||
|
.typewriter .keyboard:before {
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
border-radius: 7px;
|
||||||
|
background: linear-gradient(135deg, var(--blue), var(--blue-dark));
|
||||||
|
transform: perspective(10px) rotateX(2deg);
|
||||||
|
transform-origin: 50% 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.typewriter .keyboard:after {
|
||||||
|
left: 2px;
|
||||||
|
top: 25px;
|
||||||
|
width: 11px;
|
||||||
|
height: 4px;
|
||||||
|
border-radius: 2px;
|
||||||
|
box-shadow: 15px 0 0 var(--key), 30px 0 0 var(--key), 45px 0 0 var(--key), 60px 0 0 var(--key), 75px 0 0 var(--key), 90px 0 0 var(--key), 22px 10px 0 var(--key), 37px 10px 0 var(--key), 52px 10px 0 var(--key), 60px 10px 0 var(--key), 68px 10px 0 var(--key), 83px 10px 0 var(--key);
|
||||||
|
-webkit-animation: keyboard05 var(--duration) linear infinite;
|
||||||
|
animation: keyboard05 var(--duration) linear infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes bounce05 {
|
||||||
|
|
||||||
|
85%,
|
||||||
|
92%,
|
||||||
|
100% {
|
||||||
|
transform: translateY(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
89% {
|
||||||
|
transform: translateY(-4px);
|
||||||
|
}
|
||||||
|
|
||||||
|
95% {
|
||||||
|
transform: translateY(2px);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes slide05 {
|
||||||
|
5% {
|
||||||
|
transform: translateX(14px);
|
||||||
|
}
|
||||||
|
|
||||||
|
15%,
|
||||||
|
30% {
|
||||||
|
transform: translateX(6px);
|
||||||
|
}
|
||||||
|
|
||||||
|
40%,
|
||||||
|
55% {
|
||||||
|
transform: translateX(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
65%,
|
||||||
|
70% {
|
||||||
|
transform: translateX(-4px);
|
||||||
|
}
|
||||||
|
|
||||||
|
80%,
|
||||||
|
89% {
|
||||||
|
transform: translateX(-12px);
|
||||||
|
}
|
||||||
|
|
||||||
|
100% {
|
||||||
|
transform: translateX(14px);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes paper05 {
|
||||||
|
5% {
|
||||||
|
transform: translateY(46px);
|
||||||
|
}
|
||||||
|
|
||||||
|
20%,
|
||||||
|
30% {
|
||||||
|
transform: translateY(34px);
|
||||||
|
}
|
||||||
|
|
||||||
|
40%,
|
||||||
|
55% {
|
||||||
|
transform: translateY(22px);
|
||||||
|
}
|
||||||
|
|
||||||
|
65%,
|
||||||
|
70% {
|
||||||
|
transform: translateY(10px);
|
||||||
|
}
|
||||||
|
|
||||||
|
80%,
|
||||||
|
85% {
|
||||||
|
transform: translateY(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
92%,
|
||||||
|
100% {
|
||||||
|
transform: translateY(46px);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes keyboard05 {
|
||||||
|
|
||||||
|
5%,
|
||||||
|
12%,
|
||||||
|
21%,
|
||||||
|
30%,
|
||||||
|
39%,
|
||||||
|
48%,
|
||||||
|
57%,
|
||||||
|
66%,
|
||||||
|
75%,
|
||||||
|
84% {
|
||||||
|
box-shadow: 15px 0 0 var(--key), 30px 0 0 var(--key), 45px 0 0 var(--key), 60px 0 0 var(--key), 75px 0 0 var(--key), 90px 0 0 var(--key), 22px 10px 0 var(--key), 37px 10px 0 var(--key), 52px 10px 0 var(--key), 60px 10px 0 var(--key), 68px 10px 0 var(--key), 83px 10px 0 var(--key);
|
||||||
|
}
|
||||||
|
|
||||||
|
9% {
|
||||||
|
box-shadow: 15px 2px 0 var(--key), 30px 0 0 var(--key), 45px 0 0 var(--key), 60px 0 0 var(--key), 75px 0 0 var(--key), 90px 0 0 var(--key), 22px 10px 0 var(--key), 37px 10px 0 var(--key), 52px 10px 0 var(--key), 60px 10px 0 var(--key), 68px 10px 0 var(--key), 83px 10px 0 var(--key);
|
||||||
|
}
|
||||||
|
|
||||||
|
18% {
|
||||||
|
box-shadow: 15px 0 0 var(--key), 30px 0 0 var(--key), 45px 0 0 var(--key), 60px 2px 0 var(--key), 75px 0 0 var(--key), 90px 0 0 var(--key), 22px 10px 0 var(--key), 37px 10px 0 var(--key), 52px 10px 0 var(--key), 60px 10px 0 var(--key), 68px 10px 0 var(--key), 83px 10px 0 var(--key);
|
||||||
|
}
|
||||||
|
|
||||||
|
27% {
|
||||||
|
box-shadow: 15px 0 0 var(--key), 30px 0 0 var(--key), 45px 0 0 var(--key), 60px 0 0 var(--key), 75px 0 0 var(--key), 90px 0 0 var(--key), 22px 12px 0 var(--key), 37px 10px 0 var(--key), 52px 10px 0 var(--key), 60px 10px 0 var(--key), 68px 10px 0 var(--key), 83px 10px 0 var(--key);
|
||||||
|
}
|
||||||
|
|
||||||
|
36% {
|
||||||
|
box-shadow: 15px 0 0 var(--key), 30px 0 0 var(--key), 45px 0 0 var(--key), 60px 0 0 var(--key), 75px 0 0 var(--key), 90px 0 0 var(--key), 22px 10px 0 var(--key), 37px 10px 0 var(--key), 52px 12px 0 var(--key), 60px 12px 0 var(--key), 68px 12px 0 var(--key), 83px 10px 0 var(--key);
|
||||||
|
}
|
||||||
|
|
||||||
|
45% {
|
||||||
|
box-shadow: 15px 0 0 var(--key), 30px 0 0 var(--key), 45px 0 0 var(--key), 60px 0 0 var(--key), 75px 0 0 var(--key), 90px 2px 0 var(--key), 22px 10px 0 var(--key), 37px 10px 0 var(--key), 52px 10px 0 var(--key), 60px 10px 0 var(--key), 68px 10px 0 var(--key), 83px 10px 0 var(--key);
|
||||||
|
}
|
||||||
|
|
||||||
|
54% {
|
||||||
|
box-shadow: 15px 0 0 var(--key), 30px 2px 0 var(--key), 45px 0 0 var(--key), 60px 0 0 var(--key), 75px 0 0 var(--key), 90px 0 0 var(--key), 22px 10px 0 var(--key), 37px 10px 0 var(--key), 52px 10px 0 var(--key), 60px 10px 0 var(--key), 68px 10px 0 var(--key), 83px 10px 0 var(--key);
|
||||||
|
}
|
||||||
|
|
||||||
|
63% {
|
||||||
|
box-shadow: 15px 0 0 var(--key), 30px 0 0 var(--key), 45px 0 0 var(--key), 60px 0 0 var(--key), 75px 0 0 var(--key), 90px 0 0 var(--key), 22px 10px 0 var(--key), 37px 10px 0 var(--key), 52px 10px 0 var(--key), 60px 10px 0 var(--key), 68px 10px 0 var(--key), 83px 12px 0 var(--key);
|
||||||
|
}
|
||||||
|
|
||||||
|
72% {
|
||||||
|
box-shadow: 15px 0 0 var(--key), 30px 0 0 var(--key), 45px 2px 0 var(--key), 60px 0 0 var(--key), 75px 0 0 var(--key), 90px 0 0 var(--key), 22px 10px 0 var(--key), 37px 10px 0 var(--key), 52px 10px 0 var(--key), 60px 10px 0 var(--key), 68px 10px 0 var(--key), 83px 10px 0 var(--key);
|
||||||
|
}
|
||||||
|
|
||||||
|
81% {
|
||||||
|
box-shadow: 15px 0 0 var(--key), 30px 0 0 var(--key), 45px 0 0 var(--key), 60px 0 0 var(--key), 75px 0 0 var(--key), 90px 0 0 var(--key), 22px 10px 0 var(--key), 37px 12px 0 var(--key), 52px 10px 0 var(--key), 60px 10px 0 var(--key), 68px 10px 0 var(--key), 83px 10px 0 var(--key);
|
||||||
|
}
|
||||||
|
}
|
52
static/menu.css
Normal file
52
static/menu.css
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
body {
|
||||||
|
margin: 0;
|
||||||
|
font-family: 'Arial', sans-serif;
|
||||||
|
overflow-x: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
#sidebar {
|
||||||
|
height: 100vh;
|
||||||
|
width: 250px;
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
left: -200px;
|
||||||
|
background-color: #006699;
|
||||||
|
overflow-x: hidden;
|
||||||
|
transition: 0.5s;
|
||||||
|
padding-top: 60px;
|
||||||
|
color: white;
|
||||||
|
z-index: 2; /* 保证遮罩在页面上方 */
|
||||||
|
}
|
||||||
|
|
||||||
|
#sidebar a {
|
||||||
|
padding: 15px 10px;
|
||||||
|
text-decoration: none;
|
||||||
|
font-size: 18px;
|
||||||
|
color: white;
|
||||||
|
display: block;
|
||||||
|
transition: 0.3s;
|
||||||
|
}
|
||||||
|
|
||||||
|
#sidebar a:hover {
|
||||||
|
background-color: #3366CC;
|
||||||
|
}
|
||||||
|
|
||||||
|
#main {
|
||||||
|
padding: 30px;
|
||||||
|
padding-left: 80px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#global-blur {
|
||||||
|
background-color: rgba(255, 255, 255, 0);
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
backdrop-filter: blur(8px); /* 模糊度可以根据需要调整 */
|
||||||
|
transition: display;
|
||||||
|
z-index: 1; /* 保证遮罩在页面上方 */
|
||||||
|
pointer-events: none; /* 确保遮罩不影响下方元素的交互 */
|
||||||
|
opacity: 0;
|
||||||
|
transition: opacity 0.3s ease
|
||||||
|
}
|
9
static/menu.js
Normal file
9
static/menu.js
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
function openNav() {
|
||||||
|
document.getElementById("sidebar").style.left = "0";
|
||||||
|
document.getElementById("global-blur").style.opacity = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
function closeNav() {
|
||||||
|
document.getElementById("sidebar").style.left = "-200px";
|
||||||
|
document.getElementById("global-blur").style.opacity = 0;
|
||||||
|
}
|
158
static/popup.css
158
static/popup.css
@@ -1,26 +1,37 @@
|
|||||||
#popup-container {
|
#global-blur {
|
||||||
|
background-color: rgba(255, 255, 255, 0);
|
||||||
position: fixed;
|
position: fixed;
|
||||||
top: 0;
|
top: 0;
|
||||||
right: -100%;
|
left: 0;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
background: rgba(0, 0, 0, 0.5);
|
backdrop-filter: blur(8px);
|
||||||
|
/* 模糊度可以根据需要调整 */
|
||||||
|
transition: display;
|
||||||
|
z-index: 1;
|
||||||
|
/* 保证遮罩在页面上方 */
|
||||||
|
pointer-events: none;
|
||||||
|
/* 确保遮罩不影响下方元素的交互 */
|
||||||
|
opacity: 0;
|
||||||
|
transition: opacity 0.3s ease
|
||||||
}
|
}
|
||||||
|
|
||||||
#popup {
|
#popup-container {
|
||||||
position: absolute;
|
background-color: #f1f1f1;
|
||||||
|
height: 100%;
|
||||||
|
width: 250px;
|
||||||
|
position: fixed;
|
||||||
top: 0;
|
top: 0;
|
||||||
right: 0;
|
right: 0;
|
||||||
height: 100%;
|
overflow-x: hidden;
|
||||||
width: 20%;
|
padding-top: 60px;
|
||||||
min-width: 150px;
|
z-index: 2;
|
||||||
min-width: 200px;
|
transition: transform 0.4s ease;
|
||||||
background: white;
|
transform: translateX(250px);
|
||||||
padding: 20px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.hidden {
|
#popup-container.show {
|
||||||
display: none;
|
transform: translateX(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
#close-popup {
|
#close-popup {
|
||||||
@@ -31,17 +42,130 @@
|
|||||||
|
|
||||||
#dropdown {
|
#dropdown {
|
||||||
margin: auto;
|
margin: auto;
|
||||||
width: 80%; /* 让<select>元素宽度占满容器 */
|
width: 80%;
|
||||||
margin-bottom: 10px; /* 添加一些底部间距 */
|
/* 让<select>元素宽度占满容器 */
|
||||||
|
margin-bottom: 10px;
|
||||||
|
/* 添加一些底部间距 */
|
||||||
}
|
}
|
||||||
|
|
||||||
#buttons {
|
#buttons {
|
||||||
margin: auto;
|
margin: auto;
|
||||||
width: 50%;
|
width: 50%;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column; /* 设置按钮垂直排列 */
|
flex-direction: column;
|
||||||
|
/* 设置按钮垂直排列 */
|
||||||
}
|
}
|
||||||
|
|
||||||
#buttons button {
|
#buttons button {
|
||||||
margin: 10px 0; /* 添加按钮之间的垂直间距 */
|
margin: 10px 0;
|
||||||
|
/* 添加按钮之间的垂直间距 */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 弹窗消息框CSS */
|
||||||
|
|
||||||
|
/* 定义通知框的样式 */
|
||||||
|
.notification {
|
||||||
|
display: none;
|
||||||
|
/* 初始状态下通知框不显示 */
|
||||||
|
position: fixed;
|
||||||
|
top: 10px;
|
||||||
|
right: 10px;
|
||||||
|
width: 300px;
|
||||||
|
background-color: #f1f1f1;
|
||||||
|
padding: 10px;
|
||||||
|
border: 1px solid #ddd;
|
||||||
|
border-radius: 5px;
|
||||||
|
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
|
||||||
|
opacity: 0;
|
||||||
|
/* 初始透明度为 0,即不可见 */
|
||||||
|
transform: translateY(-20px);
|
||||||
|
/* 初始向上平移20px,用于动画效果 */
|
||||||
|
transition: opacity 0.3s ease, transform 0.3s ease;
|
||||||
|
/* 添加过渡效果 */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 定义显示状态下的通知框样式 */
|
||||||
|
.notification.show {
|
||||||
|
opacity: 1;
|
||||||
|
/* 显示状态下透明度为 1,即完全可见 */
|
||||||
|
transform: translateY(0);
|
||||||
|
/* 平移恢复到原位,显示的过渡效果 */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 定义通知框内的内容容器样式 */
|
||||||
|
.notification-content {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 定义关闭按钮的样式 */
|
||||||
|
.close {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
right: 0;
|
||||||
|
font-size: 18px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 定义进度条样式 */
|
||||||
|
.progress-bar {
|
||||||
|
height: 10px;
|
||||||
|
background-color: #ddd;
|
||||||
|
border-radius: 5px;
|
||||||
|
margin-top: 10px;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 定义进度条内部样式 */
|
||||||
|
.progress-bar-inner {
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
background-color: #4caf50;
|
||||||
|
transition: width 0.3s linear;
|
||||||
|
/* 添加进度条宽度变化的线性过渡效果 */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* --------------公告栏部分-------------- */
|
||||||
|
|
||||||
|
/* 模态框样式 */
|
||||||
|
.modal {
|
||||||
|
display: none;
|
||||||
|
/* 默认隐藏 */
|
||||||
|
position: fixed;
|
||||||
|
/* 固定位置 */
|
||||||
|
z-index: 1;
|
||||||
|
/* 位于顶层 */
|
||||||
|
left: 0;
|
||||||
|
top: 0;
|
||||||
|
width: 100%;
|
||||||
|
/* 宽度为全屏 */
|
||||||
|
height: 100%;
|
||||||
|
/* 高度为全屏 */
|
||||||
|
overflow: auto;
|
||||||
|
/* 如果需要滚动条,则启用 */
|
||||||
|
background-color: rgba(0, 0, 0, 0.4);
|
||||||
|
/* 半透明背景 */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 模态框内容样式 */
|
||||||
|
.modal-content {
|
||||||
|
background-color: #fefefe;
|
||||||
|
margin: 15% auto;
|
||||||
|
/* 位于页面中心 */
|
||||||
|
padding: 20px;
|
||||||
|
border: 1px solid #888;
|
||||||
|
width: 80%;
|
||||||
|
/* 宽度 */
|
||||||
|
border-radius: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-content button {
|
||||||
|
display: flex;
|
||||||
|
left: 20px;
|
||||||
|
background-color: #007bff;
|
||||||
|
color: #fff;
|
||||||
|
border: none;
|
||||||
|
border-radius: 5px;
|
||||||
|
padding: 10px 20px;
|
||||||
|
margin-top: 10px;
|
||||||
|
cursor: pointer;
|
||||||
}
|
}
|
59
static/popupMessagesBox.js
Normal file
59
static/popupMessagesBox.js
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
// 消息框的js代码
|
||||||
|
|
||||||
|
// 获取页面元素
|
||||||
|
var notification = document.getElementById('notification');
|
||||||
|
var showNotificationBtn = document.getElementById('showNotificationBtn');
|
||||||
|
var notificationText = document.getElementById('notificationText');
|
||||||
|
var progressBarInner = document.getElementById('progressBarInner');
|
||||||
|
|
||||||
|
// 显示通知函数
|
||||||
|
function showNotification(message) {
|
||||||
|
// 设置通知文本
|
||||||
|
notificationText.innerText = message;
|
||||||
|
// 显示通知框
|
||||||
|
notification.style.display = 'block';
|
||||||
|
|
||||||
|
// 触发回流(reflow)以启用动画效果
|
||||||
|
notification.offsetHeight;
|
||||||
|
|
||||||
|
// 添加显示状态的类,触发过渡效果
|
||||||
|
notification.classList.add('show');
|
||||||
|
|
||||||
|
// 启动倒计时
|
||||||
|
startCountdown(5); // 延迟时间
|
||||||
|
}
|
||||||
|
|
||||||
|
// 倒计时函数
|
||||||
|
function startCountdown(duration) {
|
||||||
|
var startTime = Date.now();
|
||||||
|
var interval = setInterval(function () {
|
||||||
|
var currentTime = Date.now();
|
||||||
|
var elapsedTime = currentTime - startTime;
|
||||||
|
var remainingTime = duration * 1000 - elapsedTime;
|
||||||
|
|
||||||
|
if (remainingTime <= 0) {
|
||||||
|
clearInterval(interval);
|
||||||
|
closeNotification();
|
||||||
|
} else {
|
||||||
|
var progressPercent = (remainingTime / (duration * 1000)) * 100;
|
||||||
|
updateProgressBar(progressPercent);
|
||||||
|
}
|
||||||
|
}, 100);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 更新进度条函数
|
||||||
|
function updateProgressBar(percent) {
|
||||||
|
progressBarInner.style.width = percent + '%';
|
||||||
|
}
|
||||||
|
|
||||||
|
// 关闭通知函数
|
||||||
|
function closeNotification() {
|
||||||
|
// 移除显示状态的类,触发过渡效果
|
||||||
|
notification.classList.remove('show');
|
||||||
|
// 延时等待动画完成后隐藏通知框
|
||||||
|
setTimeout(function () {
|
||||||
|
notification.style.display = 'none';
|
||||||
|
// 重置进度条宽度为 100%
|
||||||
|
progressBarInner.style.width = '100%';
|
||||||
|
}, 300); // 等待动画完成再隐藏
|
||||||
|
}
|
18
stop.sh
18
stop.sh
@@ -1,18 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
|
|
||||||
# 定义要停止的Python文件
|
|
||||||
PYTHON_APP="main.py"
|
|
||||||
|
|
||||||
# 使用ps命令查找Python进程,并使用grep过滤出要停止的进程
|
|
||||||
PID=$(ps -ef | grep $PYTHON_APP | grep -v grep | awk '{print $2}')
|
|
||||||
|
|
||||||
# 检查是否找到了进程
|
|
||||||
if [ -z "$PID" ]; then
|
|
||||||
echo "Python application is not running!"
|
|
||||||
else
|
|
||||||
# 使用kill命令停止进程
|
|
||||||
kill $PID
|
|
||||||
echo "Python application stopped!"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# 可以添加任何其他需要的停止逻辑
|
|
@@ -4,6 +4,8 @@
|
|||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<title>创建密钥</title>
|
<title>创建密钥</title>
|
||||||
|
<link rel="stylesheet" type="text/css" href="../static/menu.css">
|
||||||
|
<script src="../static/echarts.min.js"></script>
|
||||||
<style>
|
<style>
|
||||||
body {
|
body {
|
||||||
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
|
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
|
||||||
@@ -21,6 +23,17 @@
|
|||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
|
<div id="global-blur"></div>
|
||||||
|
<div id="sidebar" onmouseover="openNav()" onmouseout="closeNav()">
|
||||||
|
<a href="/admin" class="nodecoration">仪表盘</a>
|
||||||
|
<a href="/admin/list" class="nodecoration">列出所有Key</a>
|
||||||
|
<a href="/admin/lookupkey" class="nodecoration">查询密钥</a>
|
||||||
|
<a href="/admin/createkey" class="nodecoration">创建密钥</a>
|
||||||
|
<a href="/admin/log?show=500" class="nodecoration">查看日志</a>
|
||||||
|
<!-- 添加更多菜单项 -->
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="main">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<h2>创建单个密钥</h2>
|
<h2>创建单个密钥</h2>
|
||||||
<form method="post">
|
<form method="post">
|
||||||
@@ -53,9 +66,9 @@
|
|||||||
{% endfor %}
|
{% endfor %}
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<script>
|
</div>
|
||||||
|
|
||||||
</script>
|
<script src="../static/menu.js"></script>
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
</html>
|
</html>
|
@@ -1,99 +1,49 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html>
|
<html>
|
||||||
|
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
<title>KakuAI</title>
|
<title>KakuAI</title>
|
||||||
<link rel="stylesheet" type="text/css" href="../static/popup.css">
|
<link rel="stylesheet" type="text/css" href="../static/popup.css">
|
||||||
<style>
|
<link rel="stylesheet" type="text/css" href="../static/index.css">
|
||||||
body {
|
<link rel="stylesheet" type="text/css" href="../static/loading.css">
|
||||||
font-family: Arial, sans-serif;
|
|
||||||
background-color: #f5f5f5;
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
height: 100vh;
|
|
||||||
margin: 0;
|
|
||||||
background-image: url("../static/img/bg_circles.png");
|
|
||||||
background-repeat: repeat;
|
|
||||||
}
|
|
||||||
#chat-container {
|
|
||||||
width: 80%; /* 使用百分比宽度 */
|
|
||||||
max-width: 1300px; /* 最大宽度,防止界面变得过宽 */
|
|
||||||
background-color: #fff;
|
|
||||||
border: 1px solid #ccc;
|
|
||||||
border-radius: 10px;
|
|
||||||
padding: 20px;
|
|
||||||
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
|
|
||||||
}
|
|
||||||
#chat-messages {
|
|
||||||
max-height: 500px;
|
|
||||||
overflow-y: auto;
|
|
||||||
border: 1px solid #ddd;
|
|
||||||
border-radius: 5px;
|
|
||||||
padding: 10px;
|
|
||||||
background-color: #f9f9f9;
|
|
||||||
word-wrap: break-word; /* 自动换行 */
|
|
||||||
white-space: pre-wrap; /* 保留空格并自动换行 */
|
|
||||||
}
|
|
||||||
.message-divider {
|
|
||||||
border-top: 1px solid #ccc;
|
|
||||||
margin: 10px 0;
|
|
||||||
}
|
|
||||||
#user-input {
|
|
||||||
width: 97%;
|
|
||||||
padding: 10px;
|
|
||||||
border: 1px solid #ccc;
|
|
||||||
border-radius: 5px;
|
|
||||||
margin-top: 10px;
|
|
||||||
}
|
|
||||||
#user-input:focus {
|
|
||||||
outline: none;
|
|
||||||
}
|
|
||||||
#user-input::placeholder {
|
|
||||||
color: #999;
|
|
||||||
}
|
|
||||||
#user-input-button {
|
|
||||||
background-color: #007bff;
|
|
||||||
color: #fff;
|
|
||||||
border: none;
|
|
||||||
border-radius: 5px;
|
|
||||||
padding: 10px 20px;
|
|
||||||
margin-top: 10px;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
#user-input-button:disabled {
|
|
||||||
background-color: #ccc;
|
|
||||||
cursor: not-allowed;
|
|
||||||
}
|
|
||||||
/* 新增样式 */
|
|
||||||
#additional-controls {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: space-between; /* 左右对齐 */
|
|
||||||
margin-top: 10px;
|
|
||||||
}
|
|
||||||
#additional-controls input[type="checkbox"] {
|
|
||||||
margin-right: 10px;
|
|
||||||
}
|
|
||||||
#additional-controls button {
|
|
||||||
background-color: #466d2b;
|
|
||||||
color: #fff;
|
|
||||||
border: none;
|
|
||||||
border-radius: 5px;
|
|
||||||
padding: 10px 20px;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
</head>
|
</head>
|
||||||
<body onload="checkCookie()">
|
|
||||||
|
<body onload="init()">
|
||||||
|
<div id="loading" class="loading">
|
||||||
|
<div class="typewriter">
|
||||||
|
<div class="slide"><i></i></div>
|
||||||
|
<div class="paper"></div>
|
||||||
|
<div class="keyboard"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!--全局遮罩-->
|
||||||
|
<div id="global-blur"></div>
|
||||||
|
<!-- 通知框容器 -->
|
||||||
|
<div id="notification" class="notification">
|
||||||
|
<!-- 通知框内容容器 -->
|
||||||
|
<div class="notification-content">
|
||||||
|
<!-- 关闭按钮 -->
|
||||||
|
<span class="close" onclick="closeNotification()">×</span>
|
||||||
|
<!-- 通知文本 -->
|
||||||
|
<p id="notificationText">这是一条通知。</p>
|
||||||
|
<!-- 进度条容器 -->
|
||||||
|
<div class="progress-bar">
|
||||||
|
<!-- 进度条内部 -->
|
||||||
|
<div id="progressBarInner" class="progress-bar-inner"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div id="chat-container">
|
<div id="chat-container">
|
||||||
<div id="chat-messages"></div>
|
<div id="chat-messages"></div>
|
||||||
<input type="text" id="user-input" placeholder="输入消息..."> <!-- 用户输入消息的输入框 -->
|
<input type="text" id="user-input" placeholder="输入消息..."> <!-- 用户输入消息的输入框 -->
|
||||||
<button id="user-input-button" disabled>发送</button> <!-- 发送消息按钮初始状态禁用 -->
|
<button id="user-input-button" disabled>发送</button> <!-- 发送消息按钮初始状态禁用 -->
|
||||||
<!-- 新增复选框、文本和附加功能按钮 -->
|
<!-- 新增复选框、文本和附加功能按钮 -->
|
||||||
<img id="loadingico" alt="Loading..." src="https://www.intogif.com/resource/image/loading/radio.gif" style="height: 50px;transform: translate(10px, 20px);display: none;"/>
|
<img id="loadingico" alt="Loading..." src="../static/img/loading.gif"
|
||||||
|
style="height: 50px;transform: translate(10px, 20px);display: none;" />
|
||||||
<div id="additional-controls">
|
<div id="additional-controls">
|
||||||
<label>
|
<label>
|
||||||
<input type="checkbox" id="additional-checkbox"> 联系上文 <a id="showtoken"><br>剩余Token将会被显示在这里</a>
|
<input type="checkbox" id="additional-checkbox"> 联系上文 <a id="showtoken"><br>剩余Token将会被显示在这里</a>
|
||||||
@@ -102,12 +52,13 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="popup-container" class="hidden"> <!--菜单部分-->
|
<div id="popup-container"> <!--菜单部分-->
|
||||||
<div id="popup">
|
<div style="padding: 20px;">
|
||||||
<button id="close-popup">关闭</button>
|
<button id="close-popup">关闭</button>
|
||||||
<h1>设置</h1>
|
<h1>设置</h1>
|
||||||
<p>使用的AI模型</p>
|
<p>使用的AI模型</p>
|
||||||
<select id="setUpDropdown" defaultValue="qwen-turbo" onchange="setCookie('modelSet', document.getElementById('setUpDropdown').value, 265)">
|
<select id="setUpDropdown" defaultValue="qwen-turbo"
|
||||||
|
onchange="setCookie('modelSet', document.getElementById('setUpDropdown').value, 265)">
|
||||||
<option value="qwen-turbo">qwen-turbo</option>
|
<option value="qwen-turbo">qwen-turbo</option>
|
||||||
<option value="chatglm-turbo">chatglmTurbo</option>
|
<option value="chatglm-turbo">chatglmTurbo</option>
|
||||||
<option value="gpt3.5-turbo">gpt3.5-turbo(X3 Token)</option>
|
<option value="gpt3.5-turbo">gpt3.5-turbo(X3 Token)</option>
|
||||||
@@ -119,11 +70,24 @@
|
|||||||
<hr>
|
<hr>
|
||||||
<div id="buttons">
|
<div id="buttons">
|
||||||
<button id="setUpButton1">设置UserKey</button>
|
<button id="setUpButton1">设置UserKey</button>
|
||||||
<button id="setUpButton2" onclick="window.location.href = 'https://afdian.net/a/kaku55'">获取更多Token</button>
|
<button id="setUpButton2"
|
||||||
|
onclick="window.location.href = 'https://afdian.net/a/kaku55'">获取更多Token</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- 公告模态框 -->
|
||||||
|
<div id="announcementModal" class="modal">
|
||||||
|
<!-- 模态框内容 -->
|
||||||
|
<div class="modal-content">
|
||||||
|
<h2>公告标题</h2>
|
||||||
|
<p id="modal-text">这里是公告内容。</p>
|
||||||
|
<button id="closeModel">确定公告</button>
|
||||||
|
<input id="dontShowNextTime" type="checkbox"><label>有新消息前不再显示</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script src="../static/popupMessagesBox.js"></script>
|
||||||
<script>
|
<script>
|
||||||
const chatMessages = document.getElementById('chat-messages'); // 聊天消息容器
|
const chatMessages = document.getElementById('chat-messages'); // 聊天消息容器
|
||||||
const userInput = document.getElementById('user-input'); // 用户输入消息的输入框
|
const userInput = document.getElementById('user-input'); // 用户输入消息的输入框
|
||||||
@@ -133,6 +97,7 @@
|
|||||||
const popupContainer = document.getElementById('popup-container'); // 菜单容器
|
const popupContainer = document.getElementById('popup-container'); // 菜单容器
|
||||||
const closePopup = document.getElementById('close-popup'); // 关闭菜单按钮
|
const closePopup = document.getElementById('close-popup'); // 关闭菜单按钮
|
||||||
const setUpButton1 = document.getElementById('setUpButton1');// 菜单按钮1
|
const setUpButton1 = document.getElementById('setUpButton1');// 菜单按钮1
|
||||||
|
const globalBlur = document.getElementById('global-blur'); //全局遮罩
|
||||||
|
|
||||||
var userhs1 = "x"; // 历史记录的保存
|
var userhs1 = "x"; // 历史记录的保存
|
||||||
var userhs0 = "x";
|
var userhs0 = "x";
|
||||||
@@ -141,8 +106,8 @@
|
|||||||
|
|
||||||
// 关闭菜单
|
// 关闭菜单
|
||||||
closePopup.addEventListener('click', () => {
|
closePopup.addEventListener('click', () => {
|
||||||
popupContainer.style.right = '-100%';
|
popupContainer.classList.remove('show');
|
||||||
popupContainer.classList.add('hidden');
|
globalBlur.style.opacity = 0;
|
||||||
});
|
});
|
||||||
|
|
||||||
// 点击发送按钮后的处理函数
|
// 点击发送按钮后的处理函数
|
||||||
@@ -152,13 +117,14 @@
|
|||||||
// 点击附加功能按钮后的处理函数
|
// 点击附加功能按钮后的处理函数
|
||||||
additionalButton.addEventListener('click', additionalFunction);
|
additionalButton.addEventListener('click', additionalFunction);
|
||||||
// 菜单按钮的处理函数
|
// 菜单按钮的处理函数
|
||||||
setUpButton1.addEventListener('click',resetCookie);
|
setUpButton1.addEventListener('click', resetCookie);
|
||||||
|
|
||||||
// 发送消息函数
|
// 发送消息函数
|
||||||
function sendMessage() {
|
function sendMessage() {
|
||||||
document.getElementById("loadingico").style.display = "";
|
document.getElementById("loadingico").style.display = "";
|
||||||
const userMessage = userInput.value; // 获取用户输入的消息
|
const userMessage = userInput.value; // 获取用户输入的消息
|
||||||
appendMessage('你', userMessage); // 在聊天界面中添加用户消息
|
appendMessage('你', userMessage); // 在聊天界面中添加用户消息
|
||||||
|
chatMessages.scrollTop = chatMessages.scrollHeight; //自动滚动
|
||||||
userInput.value = ''; // 清空输入框
|
userInput.value = ''; // 清空输入框
|
||||||
|
|
||||||
// 立即禁用发送按钮
|
// 立即禁用发送按钮
|
||||||
@@ -166,7 +132,7 @@
|
|||||||
|
|
||||||
// 在实际应用中,你可以将用户消息发送到后端进行处理
|
// 在实际应用中,你可以将用户消息发送到后端进行处理
|
||||||
// 在这个示例中,我们模拟了来自助手的响应
|
// 在这个示例中,我们模拟了来自助手的响应
|
||||||
setTimeout(function() {
|
setTimeout(function () {
|
||||||
requestAPI(userMessage);
|
requestAPI(userMessage);
|
||||||
}, 500);
|
}, 500);
|
||||||
}
|
}
|
||||||
@@ -186,8 +152,8 @@
|
|||||||
// 附加功能按钮的处理函数
|
// 附加功能按钮的处理函数
|
||||||
function additionalFunction() {
|
function additionalFunction() {
|
||||||
// 处理附加功能按钮的点击事件
|
// 处理附加功能按钮的点击事件
|
||||||
popupContainer.classList.remove('hidden');
|
popupContainer.classList.add('show');
|
||||||
popupContainer.style.right = '0';
|
globalBlur.style.opacity = 1; //开启毛玻璃效果
|
||||||
}
|
}
|
||||||
|
|
||||||
// 用户输入框的输入事件处理函数
|
// 用户输入框的输入事件处理函数
|
||||||
@@ -203,6 +169,15 @@
|
|||||||
var expires = "expires=" + d.toGMTString();
|
var expires = "expires=" + d.toGMTString();
|
||||||
document.cookie = cname + "=" + cvalue + "; " + expires;
|
document.cookie = cname + "=" + cvalue + "; " + expires;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function init() {
|
||||||
|
setTimeout(function () {
|
||||||
|
checkCookie()
|
||||||
|
document.getElementById("loading").style.opacity = 0;
|
||||||
|
}, 1000);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
function getCookie(cname) {
|
function getCookie(cname) {
|
||||||
var name = cname + "=";
|
var name = cname + "=";
|
||||||
var ca = document.cookie.split(';');
|
var ca = document.cookie.split(';');
|
||||||
@@ -215,7 +190,7 @@
|
|||||||
function checkCookie() {
|
function checkCookie() {
|
||||||
var user = getCookie("userkey");
|
var user = getCookie("userkey");
|
||||||
if (user != "") {
|
if (user != "") {
|
||||||
alert("欢迎回来 UserKey:" + user +"\n当前选择模型:" + getCookie("modelSet"));
|
showNotification("欢迎回来\nUserKey:" + user + "\n当前选择模型:" + getCookie("modelSet"));
|
||||||
document.getElementById("showUserKey").innerHTML = user;
|
document.getElementById("showUserKey").innerHTML = user;
|
||||||
document.getElementById('setUpDropdown').value = getCookie("modelSet");
|
document.getElementById('setUpDropdown').value = getCookie("modelSet");
|
||||||
}
|
}
|
||||||
@@ -240,13 +215,13 @@
|
|||||||
function requestAPI(message) {
|
function requestAPI(message) {
|
||||||
// 创建包含JSON数据的对象
|
// 创建包含JSON数据的对象
|
||||||
var requestData = {
|
var requestData = {
|
||||||
"model":document.getElementById("setUpDropdown").value,
|
"model": document.getElementById("setUpDropdown").value,
|
||||||
"prompt": message,
|
"prompt": message,
|
||||||
"userkey": getCookie("userkey"),
|
"userkey": getCookie("userkey"),
|
||||||
"context": Number(additionalCheckbox.checked),
|
"context": Number(additionalCheckbox.checked),
|
||||||
"history": [
|
"history": [
|
||||||
{
|
{
|
||||||
"user": userhs1 ,
|
"user": userhs1,
|
||||||
"bot": boths1
|
"bot": boths1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -268,17 +243,18 @@
|
|||||||
.then(data => {
|
.then(data => {
|
||||||
// 在这里处理返回的JSON数据
|
// 在这里处理返回的JSON数据
|
||||||
if (data["code"] == 200) {
|
if (data["code"] == 200) {
|
||||||
appendMessage("KakuAI"+"("+document.getElementById("setUpDropdown").value+")",data["output"]);
|
appendMessage("KakuAI" + "(" + document.getElementById("setUpDropdown").value + ")", data["output"]);
|
||||||
document.getElementById("showtoken").innerHTML = "<br>剩余Tokens:" + data["surplus"];
|
document.getElementById("showtoken").innerHTML = "<br>剩余Tokens:" + data["surplus"];
|
||||||
}
|
}
|
||||||
else{
|
else {
|
||||||
alert("ErrCode:"+data["code"]+" "+data["output"])
|
alert("ErrCode:" + data["code"] + " " + data["output"])
|
||||||
}
|
}
|
||||||
userhs1 = userhs0;
|
userhs1 = userhs0;
|
||||||
boths1 = boths0;
|
boths1 = boths0;
|
||||||
userhs0 = message;
|
userhs0 = message;
|
||||||
boths0 = data["output"];
|
boths0 = data["output"];
|
||||||
loading = false;
|
loading = false;
|
||||||
|
chatMessages.scrollTop = chatMessages.scrollHeight; //自动滚动
|
||||||
document.getElementById("loadingico").style.display = "none";
|
document.getElementById("loadingico").style.display = "none";
|
||||||
// 可以根据返回的数据执行相应的操作
|
// 可以根据返回的数据执行相应的操作
|
||||||
})
|
})
|
||||||
@@ -286,11 +262,21 @@
|
|||||||
console.error('请求出错:', error);
|
console.error('请求出错:', error);
|
||||||
alert('请求出错:', error);
|
alert('请求出错:', error);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
document.addEventListener('DOMContentLoaded', function () { //回车发送消息功能
|
||||||
|
function handleKey(event) {
|
||||||
|
if (event.keyCode === 13) {
|
||||||
|
// 在这里执行你希望回车键触发的操作
|
||||||
|
sendButton.click(); // 模拟按钮点击
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 绑定事件到输入框
|
||||||
|
userInput.addEventListener('keypress', handleKey);
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
</html>
|
</html>
|
@@ -4,6 +4,8 @@
|
|||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<title>列出密钥</title>
|
<title>列出密钥</title>
|
||||||
|
<link rel="stylesheet" type="text/css" href="../static/menu.css">
|
||||||
|
<script src="../static/echarts.min.js"></script>
|
||||||
<style>
|
<style>
|
||||||
body {
|
body {
|
||||||
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
|
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
|
||||||
@@ -37,6 +39,17 @@
|
|||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
|
<div id="global-blur"></div>
|
||||||
|
<div id="sidebar" onmouseover="openNav()" onmouseout="closeNav()">
|
||||||
|
<a href="/admin" class="nodecoration">仪表盘</a>
|
||||||
|
<a href="/admin/list" class="nodecoration">列出所有Key</a>
|
||||||
|
<a href="/admin/lookupkey" class="nodecoration">查询密钥</a>
|
||||||
|
<a href="/admin/createkey" class="nodecoration">创建密钥</a>
|
||||||
|
<a href="/admin/log?show=500" class="nodecoration">查看日志</a>
|
||||||
|
<!-- 添加更多菜单项 -->
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="main">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<h2>列出密钥</h2>
|
<h2>列出密钥</h2>
|
||||||
<table>
|
<table>
|
||||||
@@ -58,11 +71,11 @@
|
|||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
<hr/>
|
<hr />
|
||||||
|
|
||||||
<script>
|
</div>
|
||||||
// 在这里可以添加一些交互逻辑,例如点击某个状态显示更多信息
|
|
||||||
</script>
|
<script src="../static/menu.js"></script>
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
</html>
|
</html>
|
84
templates/loglist.html
Normal file
84
templates/loglist.html
Normal file
@@ -0,0 +1,84 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="zh-CN">
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<title>列出日志</title>
|
||||||
|
<link rel="stylesheet" type="text/css" href="../static/menu.css">
|
||||||
|
<script src="../static/echarts.min.js"></script>
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
|
||||||
|
background-color: #f7f7f7;
|
||||||
|
padding: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.container {
|
||||||
|
background-color: #fff;
|
||||||
|
padding: 20px;
|
||||||
|
border-radius: 8px;
|
||||||
|
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
table {
|
||||||
|
width: 100%;
|
||||||
|
border-collapse: collapse;
|
||||||
|
}
|
||||||
|
|
||||||
|
th,
|
||||||
|
td {
|
||||||
|
border: 1px solid #ddd;
|
||||||
|
padding: 8px;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
th {
|
||||||
|
background-color: #f2f2f2;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<div id="global-blur"></div>
|
||||||
|
<div id="sidebar" onmouseover="openNav()" onmouseout="closeNav()">
|
||||||
|
<a href="/admin" class="nodecoration">仪表盘</a>
|
||||||
|
<a href="/admin/list" class="nodecoration">列出所有Key</a>
|
||||||
|
<a href="/admin/lookupkey" class="nodecoration">查询密钥</a>
|
||||||
|
<a href="/admin/createkey" class="nodecoration">创建密钥</a>
|
||||||
|
<a href="/admin/log?show=500" class="nodecoration">查看日志</a>
|
||||||
|
<!-- 添加更多菜单项 -->
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="main">
|
||||||
|
<div class="container">
|
||||||
|
<h2>列出日志</h2>
|
||||||
|
<table>
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>IP</th>
|
||||||
|
<th>时间</th>
|
||||||
|
<th>token用量</th>
|
||||||
|
<th>使用模型</th>
|
||||||
|
<th>UserKey</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{% for item in data %}
|
||||||
|
<tr>
|
||||||
|
<td>{{item[0]}}</td>
|
||||||
|
<td>{{item[1]}}</td>
|
||||||
|
<td>{{item[2]}}</td>
|
||||||
|
<td>{{item[3]}}</td>
|
||||||
|
<td>{{item[4]}}</td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
<hr />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script src="../static/menu.js"></script>
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
@@ -4,6 +4,8 @@
|
|||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<title>查询密钥</title>
|
<title>查询密钥</title>
|
||||||
|
<link rel="stylesheet" type="text/css" href="../static/menu.css">
|
||||||
|
<script src="../static/echarts.min.js"></script>
|
||||||
<style>
|
<style>
|
||||||
body {
|
body {
|
||||||
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
|
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
|
||||||
@@ -21,6 +23,17 @@
|
|||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
|
<div id="global-blur"></div>
|
||||||
|
<div id="sidebar" onmouseover="openNav()" onmouseout="closeNav()">
|
||||||
|
<a href="/admin" class="nodecoration">仪表盘</a>
|
||||||
|
<a href="/admin/list" class="nodecoration">列出所有Key</a>
|
||||||
|
<a href="/admin/lookupkey" class="nodecoration">查询密钥</a>
|
||||||
|
<a href="/admin/createkey" class="nodecoration">创建密钥</a>
|
||||||
|
<a href="/admin/log?show=500" class="nodecoration">查看日志</a>
|
||||||
|
<!-- 添加更多菜单项 -->
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="main">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<h2>查询密钥</h2>
|
<h2>查询密钥</h2>
|
||||||
<form method="post">
|
<form method="post">
|
||||||
@@ -40,9 +53,9 @@
|
|||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<script>
|
</div>
|
||||||
|
|
||||||
</script>
|
<script src="../static/menu.js"></script>
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
</html>
|
</html>
|
@@ -4,6 +4,8 @@
|
|||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<title>后台管理</title>
|
<title>后台管理</title>
|
||||||
|
<link rel="stylesheet" type="text/css" href="../static/menu.css">
|
||||||
|
<script src="../static/echarts.min.js"></script>
|
||||||
<style>
|
<style>
|
||||||
body {
|
body {
|
||||||
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
|
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
|
||||||
@@ -42,13 +44,29 @@
|
|||||||
color: red;
|
color: red;
|
||||||
}
|
}
|
||||||
|
|
||||||
.nodecoration{
|
.nodecoration {
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
|
<div id="global-blur"></div>
|
||||||
|
<div id="sidebar" onmouseover="openNav()" onmouseout="closeNav()">
|
||||||
|
<a href="/admin" class="nodecoration">仪表盘</a>
|
||||||
|
<a href="/admin/list" class="nodecoration">列出所有Key</a>
|
||||||
|
<a href="/admin/lookupkey" class="nodecoration">查询密钥</a>
|
||||||
|
<a href="/admin/createkey" class="nodecoration">创建密钥</a>
|
||||||
|
<a href="/admin/log?show=500" class="nodecoration">查看日志</a>
|
||||||
|
<!-- 添加更多菜单项 -->
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="main">
|
||||||
|
<div class="container">
|
||||||
|
<h2>概况</h2>
|
||||||
|
<div id="echart1" style="width: 600px;height:400px;"></div>
|
||||||
|
</div>
|
||||||
|
<hr />
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<h2>状态</h2>
|
<h2>状态</h2>
|
||||||
<table>
|
<table>
|
||||||
@@ -78,34 +96,56 @@
|
|||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
<hr/>
|
|
||||||
<div class="container">
|
|
||||||
<h2>管理</h2>
|
|
||||||
<table>
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th>项目</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
<tr>
|
|
||||||
<td><a href="/admin/list" class="nodecoration">列出所有Key</a></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td><a href="/admin/lookupkey" class="nodecoration">查询密钥</a></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td><a href="/admin/createkey" class="nodecoration">创建密钥</a></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>阿巴阿巴</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script>
|
<script src="../static/menu.js"></script>
|
||||||
|
<script type="text/javascript">
|
||||||
|
const apiURL = '/api/modelcount';
|
||||||
|
datajson = null
|
||||||
|
// 基于准备好的dom,初始化echarts实例
|
||||||
|
var myChart = echarts.init(document.getElementById('echart1'));
|
||||||
|
//使用fetch API发送GET请求
|
||||||
|
fetch(apiURL)
|
||||||
|
.then(response => {
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error('Network response was not ok');
|
||||||
|
}
|
||||||
|
return response.json(); // 确保返回的是JSON对象
|
||||||
|
})
|
||||||
|
.then(data => {
|
||||||
|
// 确保 data 是一个数组,并且每个元素都有 value 和 name 属性
|
||||||
|
if (data && Array.isArray(data) && data.every(item => item.value && item.name)) {
|
||||||
|
myChart.setOption({
|
||||||
|
title: {
|
||||||
|
text: '模型调用',
|
||||||
|
left: 'center',
|
||||||
|
top: 'center',
|
||||||
|
textStyle: {
|
||||||
|
fontSize: '25',
|
||||||
|
fontWeight: 'bold'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
series: [{
|
||||||
|
name: '模型调用',
|
||||||
|
type: 'pie',
|
||||||
|
radius: '55%',
|
||||||
|
data: data,
|
||||||
|
radius: ['30%', '65%'],
|
||||||
|
label: {
|
||||||
|
show: true, //开启显示
|
||||||
|
fontSize: '16',
|
||||||
|
formatter: '{b}:{c}' + '\n\r' + '({d}%)',
|
||||||
|
fontWeight: 'bold'
|
||||||
|
}
|
||||||
|
}]
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
console.error('Data received is not in the correct format for ECharts pie chart:', data);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
console.error('There has been a problem with your fetch operation:', error);
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user