diff --git a/application/lib/dictionary/stardict/stardict.py b/application/lib/dictionary/stardict/stardict.py
index 695775f4..8c1ea837 100644
--- a/application/lib/dictionary/stardict/stardict.py
+++ b/application/lib/dictionary/stardict/stardict.py
@@ -58,7 +58,7 @@ def definition(self, word, language=''):
ret = ret.decode('utf-8')
#每条释义的前面添加一个换行
ret = re.sub(r'(\s*\d+)', r'
\1', ret, flags=re.IGNORECASE)
- lines = [line.strip() for line in str(ret).split('\n') if line.strip()]
+ lines = [line.strip() for line in str(ret).splitlines() if line.strip()]
if lines and lines[0] in (word, f'{word}'): #去掉开头的词条
lines = lines[1:]
diff --git a/application/lib/ebook_tts/html_audiolator.py b/application/lib/ebook_tts/html_audiolator.py
index c4ed9f2d..6f1dc231 100644
--- a/application/lib/ebook_tts/html_audiolator.py
+++ b/application/lib/ebook_tts/html_audiolator.py
@@ -142,7 +142,7 @@ def split_strings(self, strings, max_len):
for item in step1:
if len(item) > max_len + 1: #拆分
subItems = []
- for line in item.split('\n'): #按照回车进行分割
+ for line in item.splitlines(): #按照回车进行分割
if len(line) > max_len:
#再按照空格进行分割
words = line.split()
diff --git a/application/lib/simple_ai_provider.py b/application/lib/simple_ai_provider.py
index 29f3bb7f..d176a4d2 100644
--- a/application/lib/simple_ai_provider.py
+++ b/application/lib/simple_ai_provider.py
@@ -29,7 +29,7 @@
{'name': 'claude-3', 'rpm': 5, 'context': 200000},
{'name': 'claude-2.1', 'rpm': 5, 'context': 100000},],
'Grok': [
- {'name': 'grok-beta', 'rpm': 10, 'context': 128000},],
+ {'name': 'grok-beta', 'rpm': 60, 'context': 128000},],
'Mistral': [
{'name': 'open-mistral-7b', 'rpm': 60, 'context': 32000},
{'name': 'mistral-small-latest', 'rpm': 60, 'context': 32000},
@@ -135,15 +135,23 @@ def _openai_chat(self, message, defaultUrl='https://api.openai.com/v1/chat/compl
#anthropic的chat接口
def _anthropic_chat(self, message):
url = self.api_host if self.api_host else 'https://api.anthropic.com/v1/complete'
- headers = {'Accept': 'application/json',
- 'Anthropic-Version': '2023-06-01',
- 'Content-Type': 'application/json',
- 'x-api-key': self.api_key}
- payload = {
- "prompt": f"\n\nHuman: {message}\n\nAssistant:",
- "model": self._model,
- "max_tokens_to_sample": 256,
- }
+ headers = {'Accept': 'application/json', 'Anthropic-Version': '2023-06-01',
+ 'Content-Type': 'application/json', 'x-api-key': self.api_key}
+
+ if isinstance(message, list): #将openai的payload格式转换为anthropic的格式
+ msg = []
+ for item in message:
+ role = 'Human' if (item.get('role') != 'assistant') else 'Assistant'
+ content = item.get('content', '')
+ msg.append(f"\n\n{role}: {content}")
+ prompt = ''.join(msg) + "\n\nAssistant:"
+ payload = {"prompt": prompt, "model": self.model, "max_tokens_to_sample": 256}
+ elif isinstance(message, dict):
+ payload = message
+ else:
+ prompt = f"\n\nHuman: {message}\n\nAssistant:"
+ payload = {"prompt": prompt, "model": self.model, "max_tokens_to_sample": 256}
+
response = self.opener.post(url, headers=headers, json=payload)
response.raise_for_status()
return response.json()["completion"]
@@ -154,7 +162,18 @@ def _gemini_chat(self, message):
url = f'{self.api_host}?key={self.api_key}'
else:
url = f'https://generativelanguage.googleapis.com/v1beta/models/{self._model}:generateContent?key={self.api_key}'
- payload = {'contents': [{'parts': [{'text': message}]}]}
+
+ if isinstance(message, list): #将openai的payload格式转换为gemini的格式
+ msg = []
+ for item in message:
+ role = 'user' if (item.get('role') != 'assistant') else 'model'
+ content = item.get('content', '')
+ msg.append({'role': role, 'parts': [{'text': content}]})
+ payload = {'contents': msg}
+ elif isinstance(message, dict):
+ payload = message
+ else:
+ payload = {'contents': [{'role': 'user', 'parts': [{'text': message}]}]}
response = self.opener.post(url, json=payload)
response.raise_for_status()
contents = response.json()["candidates"][0]["content"]
diff --git a/application/view/adv.py b/application/view/adv.py
index 7b5f97b1..a5044e34 100644
--- a/application/view/adv.py
+++ b/application/view/adv.py
@@ -2,7 +2,7 @@
# -*- coding:utf-8 -*-
#一些高级设置功能页面
#Author: cdhigh
-import re, io, textwrap, json
+import re, io, textwrap, json, base64
from urllib.parse import unquote, urljoin, urlparse
from bs4 import BeautifulSoup
from html import escape
@@ -440,26 +440,47 @@ def AdvProxyPost(user: KeUser):
return adv_render_template('adv_proxy.html', 'proxy', proxy=proxy, user=user, tips=tips)
#测试代理是否正常
-@bpAdv.route("/fwd", endpoint='AdvFwdRoute')
-@login_required()
-def AdvFwdRoute(user: KeUser):
- UrlOpener.set_proxy(user.cfg('proxy'))
- url = request.args.get('url')
- if url:
- url = unquote(url)
- if not url.startswith('http'):
- url = 'https://' + url
- try:
- resp = UrlOpener().open(url)
- headers = dict(resp.headers)
- headers.pop('Transfer-Encoding', None)
- headers.pop('Content-Encoding', None)
- return Response(resp.content, status=resp.status_code, headers=headers)
- except Exception as e:
- return str(e)
- else:
- return 'param "url" is empty'
+#这个函数很强大,简单的利用都可以用来临时翻墙了
+#登录状态只需要 url 一个参数,否则需要 url, username, key, enc(可选)
+@bpAdv.route("/fwd", methods=['GET', 'POST'])
+def AdvFwdRoute():
+ #要不是正在登录状态,要不就传递用户名和分享密码
+ user = get_login_user()
+ args = request.args
+ url = args.get('url')
+ enc = args.get('enc')
+ if not user:
+ name = args.get('username')
+ user = KeUser.get_or_none(KeUser.name == name) if name else None
+ if user and user.share_links.get('key') != args.get('key'):
+ user = None
+
+ if not url or not user:
+ return _("Some parameters are missing or wrong."), 400
+
+ #为避免url泄露,可以在客户端简单"加密"
+ if enc == 'base64':
+ url = base64.b64decode(url).decode('utf-8')
+ elif enc == 'ke':
+ url = ke_decrypt(url, user.cfg('secret_key'))
+ UrlOpener.set_proxy(user.cfg('proxy'))
+ url = unquote(url)
+ if not url.startswith('http'):
+ url = 'https://' + url
+ inHeaders = {k: v for k, v in request.headers if k != 'Host'}
+ try:
+ if request.method == 'GET':
+ resp = UrlOpener().get(url, headers=inHeaders)
+ else:
+ resp = UrlOpener().post(url, data=request.data, headers=inHeaders)
+ headers = dict(resp.headers)
+ headers.pop('Transfer-Encoding', None)
+ headers.pop('Content-Encoding', None)
+ return Response(resp.content, status=resp.status_code, headers=headers)
+ except Exception as e:
+ return f"Unexpected error: {str(e)}", 500
+
#设置calibre的参数
@bpAdv.route("/adv/calibre", endpoint='AdvCalibreOptions')
@login_required()
diff --git a/application/view/inbound_email.py b/application/view/inbound_email.py
index e63d9e62..133ce231 100644
--- a/application/view/inbound_email.py
+++ b/application/view/inbound_email.py
@@ -283,7 +283,7 @@ def ConvertTextToHtml(subject, text):
#转换纯文本到html时需要将里面的文本链接变成tag a
bodyUrls = []
- for line in text.split('\n'):
+ for line in text.splitlines():
line = line.strip()
if not line:
continue
diff --git a/docker/compose_up.sh b/docker/compose_up.sh
deleted file mode 100644
index a1a58701..00000000
--- a/docker/compose_up.sh
+++ /dev/null
@@ -1,2 +0,0 @@
-sudo docker-compose rm -fs
-sudo docker-compose up -d
diff --git a/docker/dockerd b/docker/dockerd
deleted file mode 100644
index 3bfbdaa4..00000000
--- a/docker/dockerd
+++ /dev/null
@@ -1,5 +0,0 @@
-FROM --platform=$TARGETPLATFORM golang:latest
-LABEL maintainer="cppla "
-WORKDIR /app
-RUN go install github.com/dmulholl/mp3cat@latest
-CMD ["sh"]
\ No newline at end of file
diff --git a/main.py b/main.py
index 3646e27d..35a12296 100644
--- a/main.py
+++ b/main.py
@@ -4,7 +4,7 @@
# Visit for the latest version
# Author: cdhigh
-__Version__ = '3.2.1'
+__Version__ = '3.2.2'
import os, sys, builtins, logging
from application.lib import clogging