diff --git a/config.py b/config.py index 97ee20027..a75e3a202 100644 --- a/config.py +++ b/config.py @@ -45,7 +45,7 @@ # "qwen-turbo", "qwen-plus", "qwen-max", "qwen-local", # "moonshot-v1-128k", "moonshot-v1-32k", "moonshot-v1-8k", # "gpt-3.5-turbo-0613", "gpt-3.5-turbo-16k-0613", "gpt-3.5-turbo-0125" -# "claude-3-sonnet-20240229","claude-3-opus-20240229", "claude-2.1", "claude-instant-1.2", +# "claude-3-haiku-20240307","claude-3-sonnet-20240229","claude-3-opus-20240229", "claude-2.1", "claude-instant-1.2", # "moss", "llama2", "chatglm_onnx", "internlm", "jittorllms_pangualpha", "jittorllms_llama", # "yi-34b-chat-0205", "yi-34b-chat-200k" # ] @@ -158,7 +158,8 @@ AUTHENTICATION = [] -# 如果需要在二级路径下运行(常规情况下,不要修改!!)(需要配合修改main.py才能生效!) +# 如果需要在二级路径下运行(常规情况下,不要修改!!) +# (举例 CUSTOM_PATH = "/gpt_academic",可以让软件运行在 http://ip:port/gpt_academic/ 下。) CUSTOM_PATH = "/" @@ -378,4 +379,4 @@ └── MATHPIX_APPKEY -""" \ No newline at end of file +""" diff --git a/docs/translate_english.json b/docs/translate_english.json index c7e0e66d7..815262fdf 100644 --- a/docs/translate_english.json +++ b/docs/translate_english.json @@ -1392,7 +1392,7 @@ "1. 临时解决方案": "1. Temporary Solution", "直接在输入区键入api_key": "Enter the api_key Directly in the Input Area", "然后回车提交": "Submit after pressing Enter", - "2. 长效解决方案": "Long-term solution", + "2. 长效解决方案": "2. Long-term solution", "在config.py中配置": "Configure in config.py", "等待响应": "Waiting for response", "api-key不满足要求": "API key does not meet requirements", @@ -2184,7 +2184,8 @@ "接驳VoidTerminal": "Connect to VoidTerminal", "**很好": "**Very good", "对话|编程": "Conversation&ImageGenerating|Programming", - "对话|编程|学术": "Conversation&ImageGenerating|Programming|Academic", "4. 建议使用 GPT3.5 或更强的模型": "4. It is recommended to use GPT3.5 or a stronger model", + "对话|编程|学术": "Conversation|Programming|Academic", + "4. 建议使用 GPT3.5 或更强的模型": "4. It is recommended to use GPT3.5 or a stronger model", "「请调用插件翻译PDF论文": "Please call the plugin to translate the PDF paper", "3. 如果您使用「调用插件xxx」、「修改配置xxx」、「请问」等关键词": "3. If you use keywords such as 'call plugin xxx', 'modify configuration xxx', 'please', etc.", "以下是一篇学术论文的基本信息": "The following is the basic information of an academic paper", @@ -3006,5 +3007,746 @@ "GPT-Academic对话存档": "TranslatedText", "Arxiv论文精细翻译": "TranslatedText", "from crazy_functions.AdvancedFunctionTemplate import 测试图表渲染": "from crazy_functions.AdvancedFunctionTemplate import test_chart_rendering", - "测试图表渲染": "test_chart_rendering" -} + "测试图表渲染": "test_chart_rendering", + "请使用「LatexEnglishCorrection+高亮修正位置": "Please use 'LatexEnglishCorrection+highlight corrected positions", + "输出代码片段中!": "Output code snippet!", + "使用多种方式尝试切分文本": "Attempt to split the text in various ways", + "你是一个作家": "You are a writer", + "如果无法从中得到答案": "If unable to get an answer from it", + "无法读取以下数据": "Unable to read the following data", + "不允许直接报错": "Direct error reporting is not allowed", + "您也可以使用插件参数指定绘制的图表类型": "You can also specify the type of chart to be drawn using plugin parameters", + "不要包含太多情节": "Do not include too many plots", + "翻译为中文后重新编译为PDF": "Recompile into PDF after translating into Chinese", + "采样温度": "Sampling temperature", + "直接修改config.py": "Directly modify config.py", + "处理文件": "Handle file", + "判断返回是否正确": "Determine if the return is correct", + "gemini 不允许对话轮次为偶数": "Gemini does not allow the number of dialogue rounds to be even", + "8 象限提示图": "8-quadrant prompt diagram", + "基于上下文的prompt模版": "Context-based prompt template", + "^开始": "^Start", + "输出文本的最大tokens限制": "Maximum tokens limit for output text", + "在这个例子中": "In this example", + "以及处理PDF文件的示例代码": "And example code for handling PDF files", + "更新cookie": "Update cookie", + "获取公共缩进": "Get public indentation", + "请你给出围绕“{subject}”的序列图": "Please provide a sequence diagram around '{subject}'", + "请确保使用小写的模型名称": "Please ensure the use of lowercase model names", + "出现人物时": "When characters appear", + "azure模型对齐支持 -=-=-=-=-=-=-": "Azure model alignment support -=-=-=-=-=-=-", + "请一分钟后重试": "Please try again in one minute", + "解析GEMINI消息出错": "Error parsing GEMINI message", + "选择提示词": "Select prompt words", + "取值范围是": "The value range is", + "它会在": "It will be", + "加载文件": "Load file", + "是预定义按钮": "Is a predefined button", + "消息": "Message", + "默认搜索5条结果": "Default search for 5 results", + "第 2 部分": "Part 2", + "我们采样一个特殊的手段": "We sample a special method", + "后端开发": "Backend development", + "接下来提取md中的一级/二级标题作为摘要": "Next, extract the first/second-level headings in md as summaries", + "一个年轻人穿过天安门广场向纪念堂走去": "A young person walks through Tiananmen Square towards the Memorial Hall", + "将会使用这些摘要绘制图表": "Will use these summaries to draw charts", + "8-象限提示图": "8-quadrant prompt diagram", + "首先": "First", + "设计了此接口": "Designed this interface", + "本地模型": "Local model", + "所有图像仅在最后一个问题中提供": "All images are provided only in the last question", + "如连续3次判断失败将会使用流程图进行绘制": "If there are 3 consecutive failures, a flowchart will be used to draw", + "为了更灵活地接入one-api多模型管理界面": "To access the one-api multi-model management interface more flexibly", + "UI设计": "UI design", + "不允许在答案中添加编造成分": "Fabrication is not allowed in the answer", + "尽可能地": "As much as possible", + "先在前端快速清除chatbot&status": "First, quickly clear chatbot & status in the frontend", + "You exceeded your current quota. Cohere以账户额度不足为由": "You exceeded your current quota. Cohere due to insufficient account quota", + "合并所有的标题": "Merge all headings", + "跳过下载": "Skip download", + "中生产图表": "Production Chart", + "如输入区内容不是文件则直接返回输入区内容": "Return the content of the input area directly if it is not a file", + "用温度取样的另一种方法": "Another method of temperature sampling", + "不需要解释原因": "No need to explain the reason", + "一场延续了两万年的星际战争已接近尾声": "An interstellar war that has lasted for 20,000 years is drawing to a close", + "依次处理文件": "Process files in order", + "第一幕的字数少于300字": "The first act has fewer than 300 characters", + "已成功加载": "Successfully loaded", + "还是web渲染": "Web rendering", + "解析分辨率": "Resolution parsing", + "如果剩余文本的token数大于限制": "If the number of remaining text tokens exceeds the limit", + "你可以修改整个句子的顺序以确保翻译后的段落符合中文的语言习惯": "You can change the order of the whole sentence to ensure that the translated paragraph is in line with Chinese language habits", + "并同时充分考虑中文的语法、清晰、简洁和整体可读性": "And at the same time, fully consider Chinese grammar, clarity, conciseness, and overall readability", + "否则返回": "Otherwise return", + "一个特殊标记": "A special mark", + "4. 后续剧情发展4": "4. Plot development", + "恢复默认": "Restore default", + "转义点号": "Escape period", + "检查DASHSCOPE_API_KEY": "Check DASHSCOPE_API_KEY", + "阿里灵积云API_KEY": "Aliyun API_KEY", + "文件是否存在": "Check if the file exists", + "您的选择是": "Your choice is", + "处理用户对话": "Handle user dialogue", + "即": "That is", + "将会由对话模型首先判断适合的图表类型": "The dialogue model will first determine the appropriate chart type", + "以查看所有的配置信息": "To view all configuration information", + "用于初始化包的属性和导入模块": "For initializing package properties and importing modules", + "to_markdown_tabs 文件list 转换为 md tab": "to_markdown_tabs Convert file list to MD tab", + "更换模型": "Replace Model", + "从以下文本中提取摘要": "Extract Summary from the Following Text", + "表示捕获任意长度的文本": "Indicates Capturing Text of Arbitrary Length", + "可能是一个模块的初始化文件": "May Be an Initialization File for a Module", + "处理提问与输出": "Handle Questions and Outputs", + "需要的再做些简单调整即可": "Some Simple Adjustments Needed", + "所以这个没有用": "So This Is Not Useful", + "请配置 DASHSCOPE_API_KEY": "Please Configure DASHSCOPE_API_KEY", + "不是预定义按钮": "Not a Predefined Button", + "让读者能够感受到你的故事世界": "Let Readers Feel Your Story World", + "开始整理headers与message": "Start Organizing Headers and Messages", + "兼容最新的智谱Ai": "Compatible with the Latest ZhiPu AI", + "对于某些PDF会有第一个段落就以小写字母开头": "For Some PDFs, the First Paragraph May Start with a Lowercase Letter", + "问题是": "The Issue Is", + "也就是说它会匹配尽可能少的字符": "That Is, It Will Match the Least Amount of Characters Possible", + "未能成功加载": "Failed to Load Successfully", + "接入通义千问在线大模型 https": "Access TongYi QianWen Online Large Model HTTPS", + "用不太优雅的方式处理一个core_functional.py中出现的mermaid渲染特例": "Handle a Mermaid Rendering Special Case in core_functional.py in an Ugly Way", + "您也可以选择给出其他故事走向": "You Can Also Choose to Provide Alternative Storylines", + "改善非markdown输入的显示效果": "Improve Display Effects for Non-Markdown Input", + "在二十二世纪编年史中": "In the Chronicle of the 22nd Century", + "docs 为Document列表": "docs Are a List of Documents", + "互动写故事": "Interactive Story Writing", + "4 饼图": "Pie Chart", + "正在生成插图中": "Generating Illustration", + "路径不存在": "Path Does Not Exist", + "PDF翻译中文": "PDF Translation to Chinese", + "进行简短的环境描写": "Conduct a Brief Environmental Description", + "学术英中互译": "Academic English-Chinese Translation", + "且少于2个段落": "And less than 2 paragraphs", + "html_view_blank 超链接": "HTML View Blank Hyperlink", + "处理 history": "Handle History", + "非Cohere官方接口返回了错误": "Non-Cohere Official Interface Returned an Error", + "缺失 MATHPIX_APPID 和 MATHPIX_APPKEY": "Missing MATHPIX_APPID and MATHPIX_APPKEY", + "搜索知识库内容条数": "Search Knowledge Base Content Count", + "返回数据": "Return Data", + "没有相关文件": "No Relevant Files", + "知识库路径": "Knowledge Base Path", + "质量与风格默认值": "Quality and Style Defaults", + "包含了用于文本切分的函数": "Contains Functions for Text Segmentation", + "请你给出围绕“{subject}”的逻辑关系图": "Please Provide a Logic Diagram Surrounding '{subject}'", + "官方Pro服务器🧪": "Official Pro Server", + "不支持同时处理多个pdf文件": "Does Not Support Processing Multiple PDF Files Simultaneously", + "查询5天历史事件": "Query 5-Day Historical Events", + "你是经验丰富的翻译": "You Are an Experienced Translator", + "html输入": "HTML Input", + "输入文件不存在": "Input File Does Not Exist", + "很多人生来就会莫名其妙地迷上一样东西": "Many People Are Born with an Unexplained Attraction to Something", + "默认值为 0.7": "Default Value is 0.7", + "值越大": "The Larger the Value", + "以下文件未能成功加载": "The Following Files Failed to Load", + "在线模型": "Online Model", + "切割输入": "Cut Input", + "修改docker-compose.yml等价于修改容器内部的环境变量": "Modifying docker-compose.yml is Equivalent to Modifying the Internal Environment Variables of the Container", + "以换行符分割": "Split by Line Break", + "修复中文乱码的问题": "Fix Chinese Character Encoding Issues", + "zhipuai 是glm-4的别名": "zhipuai is an alias for glm-4", + "保证其在允许范围内": "Ensure it is within the permissible range", + "段尾如果有多余的\\n就去掉它": "Remove any extra \\n at the end of the paragraph", + "是否流式输出": "Whether to stream output", + "1-流程图": "1-Flowchart", + "学术语料润色": "Academic text polishing", + "已经超过了模型的最大上下文或是模型格式错误": "Has exceeded the model's maximum context or there is a model format error", + "英文省略号": "English ellipsis", + "登录成功": "Login successful", + "随便切一下吧": "Just cut it randomly", + "PDF转换为tex项目失败": "PDF conversion to TeX project failed", + "的 max_token 配置不是整数": "The max_token configuration is not an integer", + "根据当前聊天历史或指定的路径文件": "According to the current chat history or specified path file", + "你必须利用以下文档中包含的信息回答这个问题": "You must use the information contained in the following document to answer this question", + "对话、日志记录": "Dialogue, logging", + "内容至知识库": "Content to knowledge base", + "在银河系的中心": "At the center of the Milky Way", + "检查PDF是否被重复上传": "Check if the PDF has been uploaded multiple times", + "取最后 max_prompt_tokens 个 token 输入模型": "Take the last max_prompt_tokens tokens as input to the model", + "请输入图类型对应的数字": "Please enter the corresponding number for the graph type", + "插件主程序3 =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=": "Plugin main program 3 -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=", + "正在tex项目将翻译为中文": "The TeX project is being translated into Chinese", + "适配润色区域": "Adapter polishing area", + "首先你从历史记录中提取摘要": "First, you extract an abstract from the history", + "讯飞星火认知大模型 -=-=-=-=-=-=-": "iFLYTEK Spark Cognitive Model -=-=-=-=-=-=-=-=-=-", + "包含了用于构建和管理向量数据库的函数和类包含了用于构建和管理向量数据库的函数和类包含了用于构建和管理向量数据库的函数和类": "Contains functions and classes for building and managing vector databases", + "另外": "Additionally", + "内部调优参数": "Internal tuning parameters", + "输出格式例如": "Example of Output Format", + "当回复图像时": "When Responding with an Image", + "越权访问!": "Unauthorized Access!", + "如果给出的 prompt 的 token 长度超过此限制": "If the Given Prompt's Token Length Exceeds This Limit", + "因此你每次写的故事段落应少于300字": "Therefore, Each Story Paragraph You Write Should Be Less Than 300 Words", + "尽量短": "As Concise as Possible", + "中文提示词就不显示了": "Chinese Keywords Will Not Be Displayed", + "请在前文的基础上": "Please Based on the Previous Text", + "20张": "20 Sheets", + "文件内容优先": "File Content Takes Priority", + "状态图": "State Diagram", + "开始查找合适切分点的偏移": "Start Looking for the Offset of an Appropriate Split Point", + "已知信息": "Known Information", + "文心一言大模型": "Wenxin Yanyan Large Model", + "传递进来一些奇怪的东西": "Passing in Some Weird Things", + "很多规则中会考虑分号": "Many Rules Consider the Semicolon", + "请配置YUNQUE_SECRET_KEY": "Please Configure YUNQUE_SECRET_KEY", + "6-状态图": "6-State Diagram", + "输出文本的最小tokens限制": "Minimum Tokens Limit for Output Text", + "服务节点": "Service Node", + "云雀大模型": "Lark Large Model", + "请配置 GEMINI_API_KEY": "Please Configure GEMINI_API_KEY", + "可以让软件运行在 http": "Can Run the Software Over HTTP", + "基于当前对话或文件GenerateMultipleMermaidCharts": "Generate Multiple Mermaid Charts Based on the Current Conversation or File", + "剧情收尾": "Plot Conclusion", + "请开始提问": "Please Begin Your Question", + "第一页内容/摘要": "First Page Content/Summary", + "无法判断则返回image/jpeg": "Return image/jpeg If Unable to Determine", + "仅需要输出单个不带任何标点符号的数字": "Single digit without any punctuation", + "以下是每类图表的PROMPT": "Here are the PROMPTS for each type of chart", + "状态码": "Status code", + "TopP值越大输出的tokens类型越丰富": "The larger the TopP value, the richer the types of output tokens", + "files_filter_handler 根据type过滤文件": "files_filter_handler filters files by type", + "比较每一页的内容是否相同": "Compare whether each page's content is the same", + "前往": "Go to", + "请输入剧情走向": "Please enter the plot direction", + "故事收尾": "Story ending", + "必须说明正在回复哪张图像": "Must specify which image is being replied to", + "历史文件继续上传": "Continue uploading historical files", + "因此禁用": "Therefore disabled", + "使用lru缓存": "Use LRU caching", + "该装饰器是大多数功能调用的入口": "This decorator is the entry point for most function calls", + "如果需要开启": "If needed to enable", + "使用 json 解析库进行处理": "Process using JSON parsing library", + "将PDF转换为Latex项目": "Convert PDF to LaTeX project", + "7-实体关系图": "7-Entity relationship diagram", + "根据用户的提示": "According to the user's prompt", + "当前用户的请求信息": "Current user's request information", + "配置关联关系说明": "Configuration relationship description", + "这段代码是使用Python编程语言中的re模块": "This code uses the re module in the Python programming language", + "link_mtime_to_md 文件增加本地时间参数": "link_mtime_to_md adds local time parameter to the file", + "从当前对话或路径": "From the current conversation or path", + "一起写故事": "Write a story together", + "前端开发": "Front-end development", + "开区间": "Open interval", + "如插件参数不正确则使用对话模型判断": "If the plugin parameters are incorrect, use the dialogue model for judgment", + "对字符串进行处理": "Process the string", + "简洁和专业的来回答用户的问题": "Answer user questions concisely and professionally", + "如输入区不是文件则将输入区内容加入历史记录": "If the input area is not a file, add the content of the input area to the history", + "编写一个小说的第一幕": "Write the first act of a novel", + "更具创造性;": "More creative;", + "用于解析和翻译PDF文件的功能和相关辅助函数用于解析和翻译PDF文件的功能和相关辅助函数用于解析和翻译PDF文件的功能和相关辅助函数": "Functions and related auxiliary functions for parsing and translating PDF files", + "月之暗面 -=-=-=-=-=-=-": "The Dark Side of the Moon -=-=-=-=-=-=-", + "2. 后续剧情发展2": "2. Subsequent plot development 2", + "请先提供文本的更正版本": "Please provide the corrected version of the text first", + "修改环境变量": "Modify environment variables", + "读取之前的自定义按钮": "Read previous custom buttons", + "如果为0": "If it is 0", + "函数用于去除多行字符串的缩进": "Function to remove indentation from multiline strings", + "请绘制有关“": "Please draw something about \"", + "给出4种不同的后续剧情发展方向": "Provide 4 different directions for subsequent plot development", + "新调优版本GPT-4🔥": "Newly tuned version GPT-4🔥", + "已弃用": "Deprecated", + "参考 https": "Refer to https", + "发现重复上传": "Duplicate upload detected", + "本项目的所有配置都集中在config.py中": "All configurations for this project are centralized in config.py", + "默认值为 0.95": "Default value is 0.95", + "请查阅": "Please refer to", + "此选项已废弃": "This option is deprecated", + "找到了.doc文件": ".doc file found", + "他们的目的地是南极": "Their destination is Antarctica", + "lang_reference这段文字是": "The lang_reference text is", + "正在尝试生成对比PDF": "Attempting to generate a comparative PDF", + "input_encode_handler 提取input中的文件": "input_encode_handler Extracts files from input", + "使用中文": "Use Chinese", + "一些垃圾第三方接口会出现这样的错误": "Some crappy third-party interfaces may produce such errors", + "例如将空格转换为 ": "For example, converting spaces to  ", + "请你给出围绕“{subject}”的类图": "Please provide a class diagram around '{subject}'", + "是插件的内部参数": "Is an internal parameter of the plugin", + "网络波动时可选其他": "Alternative options when network fluctuates", + "非Cohere官方接口的出现这样的报错": "Such errors occur in non-Cohere official interfaces", + "是前缀": "Is a prefix", + "默认 None": "Default None", + "如果几天后能顺利到达那里": "If we can smoothly arrive there in a few days", + "输出1": "Output 1", + "3-类图": "3-Class Diagram", + "如需绘制思维导图请使用参数调用": "Please use parameters to call if you need to draw a mind map", + "正在将PDF转换为tex项目": "Converting PDF to TeX project", + "列出10个经典名著": "List 10 classic masterpieces", + "? 在这里用作非贪婪匹配": "? Used here as a non-greedy match", + "左上角更换模型菜单中可切换openai": "Switch to OpenAI in the model change menu in the top left corner", + "原样返回": "Return as is", + "请配置 MATHPIX_APPID 和 MATHPIX_APPKEY": "Please configure MATHPIX_APPID and MATHPIX_APPKEY", + "概括上述段落的内容以及内在逻辑关系": "Summarize the content of the above paragraph and its inherent logical relationship", + "cookie相关工具函数": "Cookie-related utility functions", + "请你给出围绕“{subject}”的饼图": "Please provide a pie chart around '{subject}'", + "原型设计": "Prototype design", + "必须为正数": "Must be a positive number", + "又一阵剧痛从肝部袭来": "Another wave of severe pain strikes from the liver", + "智谱AI": "Zhipu AI", + "基础功能区按钮的附加功能": "Additional functions of the basic functional area buttons", + "one-api 对齐支持 -=-=-=-=-=-=-": "one-api alignment support -=-=-=-=-=-=-", + "5 甘特图": "5 Gantt chart", + "用于初始化包的属性和导入模块是一个包的初始化文件": "The file used for initializing package properties and importing modules is an initialization file for the package", + "创建并修改config_private.py": "Create and modify config_private.py", + "会使输出更随机": "Would make the output more random", + "已添加": "Added", + "估计一个切分点": "Estimate a split point", + "\\n\\n1. 临时解决方案": "\\n\\n1. Temporary solution", + "没有回答": "No answer", + "尝试重新翻译PDF": "Try to retranslate the PDF", + "被这个解码给耍了": "Fooled by this decoding", + "再在后端清除history": "Clear history on the backend again", + "根据情况选择flowchart LR": "Choose flowchart LR based on the situation", + "幻方-深度求索大模型 -=-=-=-=-=-=-": "Deep Seek Large Model -=-=-=-=-=-=-", + "即使它们在历史记录中被提及": "Even if they are mentioned in the history", + "此处需要进一步优化逻辑": "Further logic optimization is needed here", + "借鉴自同目录下的bridge_ChatGPT.py": "Derived from the bridge_ChatGPT.py in the same directory", + "正是这样": "That's exactly right", + "您也可以给出您心中的其他故事走向": "You can also provide other story directions in your mind", + "文本预处理": "Text preprocessing", + "请登录": "Please log in", + "请修改docker-compose": "Please modify docker-compose", + "运行一些异步任务": "Run some asynchronous tasks", + "5-甘特图": "5-Gantt chart", + "3 类图": "3-Class diagram", + "因为你接下来将会与用户互动续写下面的情节": "Because you will interact with the user to continue writing the plot below", + "避免把同一个文件添加多次": "Avoid adding the same file multiple times", + "可挑选精度": "Selectable precision", + "调皮一下": "Play a joke", + "并解析": "And parse", + "您可以在输入框中输入一些关键词": "You can enter some keywords in the input box", + "文件加载失败": "File loading failed", + "请你给出围绕“{subject}”的甘特图": "Please provide a Gantt chart around \"{subject}\"", + "上传PDF": "Upload PDF", + "请判断适合使用的流程图类型": "Please determine the suitable flowchart type", + "错误码": "Error code", + "非markdown输入": "Non-markdown input", + "所以只能通过提示词对第几张图片进行定位": "So can only locate the image by the prompt", + "避免下载到缓存文件": "Avoid downloading cached files", + "没有思维导图!!!测试发现模型始终会优先选择思维导图": "No mind map!!! Testing found that the model always prioritizes mind maps", + "请登录Cohere查看详情 https": "Please log in to Cohere for details https", + "检查历史上传的文件是否与新上传的文件相同": "Check if the previously uploaded file is the same as the newly uploaded file", + "加载主题相关的工具函数": "Load theme-related utility functions", + "图表类型由模型判断": "Chart type is determined by the model", + "⭐ 多线程方法": "Multi-threading method", + "获取 max_token 的值": "Get the value of max_token", + "空白的输入栏": "Blank input field", + "根据整理的摘要选择图表类型": "Select chart type based on the organized summary", + "返回 True": "Return True", + "这里为了区分中英文情景搞复杂了一点": "Here it's a bit complicated to distinguish between Chinese and English contexts", + "ZHIPUAI_MODEL 配置项选项已经弃用": "ZHIPUAI_MODEL configuration option is deprecated", + "但是这里我把它忽略不计": "But here I ignore it", + "非必要": "Not necessary", + "思维导图": "Mind map", + "插件」": "Plugin", + "重复文件路径": "Duplicate file path", + "之间不要存在空格": "No spaces between fields", + "破折号、英文双引号等同样忽略": "Ignore dashes, English quotes, etc.", + "填写 VOLC_ACCESSKEY": "Enter VOLC_ACCESSKEY", + "称为核取样": "Called nuclear sampling", + "Incorrect API key. 请确保API key有效": "Incorrect API key. Please ensure the API key is valid", + "如输入区内容为文件则清空历史记录": "If the input area content is a file, clear the history", + "并处理精度问题": "And handle precision issues", + "并给出修改的理由": "And provide reasons for the changes", + "至此已经超出了正常接口应该进入的范围": "This has exceeded the scope that a normal interface should enter", + "并已加载知识库": "And the knowledge base has been loaded", + "file_manifest_filter_html 根据type过滤文件": "file_manifest_filter_html filters files by type", + "participant B as 系统": "participant B as System", + "要留出足够的互动空间": "Leave enough interaction space", + "请你给出围绕“{subject}”的实体关系图": "Please provide an entity relationship diagram around '{subject}'", + "答案请使用中文": "Please answer in Chinese", + "输出会更加稳定或确定": "The output will be more stable or certain", + "是一个包的初始化文件": "Is an initialization file for a package", + "用于加载和分割文件中的文本的通用文件加载器用于加载和分割文件中的文本的通用文件加载器用于加载和分割文件中的文本的通用文件加载器": "A universal file loader for loading and splitting text in files", + "围绕我选定的剧情情节": "Around the plot I have chosen", + "Mathpix 拥有执行PDF的OCR功能": "Mathpix has OCR functionality for PDFs", + "是否允许暴力切分": "Whether to allow violent segmentation", + "清空 txt_tmp 对应的位置方便下次搜索": "Clear the location corresponding to txt_tmp for easier next search", + "编写小说的最后一幕": "Write the last scene of the novel", + "可能是一个模块的初始化文件根据位置和名称": "May be an initialization file for a module based on position and name", + "更新新的自定义按钮": "Update new custom button", + "把分句符\\n放到双引号后": "Put the sentence separator \\n after the double quotes", + "序列图": "Sequence diagram", + "兼容非markdown输入": "Compatible with non-markdown input", + "那么就切": "Then cut", + "4-饼图": "4-Pie chart", + "结束剧情": "End of the plot", + "字数要求": "Word count requirement", + "以下是对以上文本的总结": "Below is a summary of the above text", + "但不要同时调整两个参数": "But do not adjust two parameters at the same time", + "📌省略": "Omit", + "请查看message": "Please check the message", + "如果所有页的内容都相同": "If all pages have the same content", + "我将在这4个选择中": "I will choose from these 4 options", + "请设置为True": "Please set to True", + "当 remain_txt_to_cut": "When remain_txt_to_cut", + "后续输出被截断": "Subsequent output is truncated", + "检查API_KEY": "Check API_KEY", + "阿里云实时语音识别 配置难度较高": "Alibaba Cloud real-time speech recognition has a higher configuration difficulty", + "图像生成提示为空白": "Image generation prompt is blank", + "由于实体关系图用到了{}符号": "Because the entity relationship diagram uses the {} symbol", + "系统繁忙": "System busy", + "月之暗面 API KEY": "Dark side of the moon API KEY", + "编写小说的下一幕": "Write the next scene of the novel", + "选择一种": "Choose one", + "或者flowchart TD": "Or flowchart TD", + "请把以下学术文章段落翻译成中文": "Please translate the following academic article paragraph into Chinese", + "7 实体关系图": "7 Entity relationship diagram", + "处理游戏的主体逻辑": "Handle the main logic of the game", + "请以“{headstart}”为开头": "Please start with \"{headstart}\"", + "匹配后单段上下文长度": "Length of single segment context after matching", + "先行者知道": "The pioneer knows", + "以及处理PDF文件的示例代码包含了用于文本切分的函数": "Example code for processing PDF files includes functions for text segmentation", + "未发现重复上传": "No duplicate uploads found", + "那么就不用切了": "Then there's no need to split", + "目前来说": "Currently", + "请在LLM_MODEL中配置": "Please configure in LLM_MODEL", + "是否启用上下文关联": "Whether to enable context association", + "为了加速计算": "To speed up calculations", + "登录请求": "Login request", + "这里解释一下正则表达式中的几个特殊字符": "Explanation of some special characters in regular expressions", + "其中数字对应关系为": "The corresponding relationship of the numbers is", + "修改配置有三种方法": "There are three ways to modify the configuration", + "请前往arxiv打开此论文下载页面": "Please go to arXiv and open the paper download page", + "然后download source手动下载latex源码包": "Then manually download the LaTeX source package by downloading the source", + "功能单元": "Functional unit", + "你需要翻译的文本如下": "The text you need to translate is as follows", + "以便于后续快速的匹配和查找操作": "To facilitate rapid matching and search operations later", + "文本内容": "Text content", + "自动更新、打开浏览器页面、预热tiktoken模块": "Auto-update, open browser page, warm up tiktoken module", + "原样传递": "Pass through as is", + "但是该文件格式不被支持": "But the file format is not supported", + "他现在是全宇宙中唯一的一个人了": "He is now the only person in the entire universe", + "取值范围0~1": "Value range 0~1", + "搜索匹配score阈值": "Search match score threshold", + "当字符串中有掩码tag时": "When there is a mask tag in the string", + "错误的不纳入对话": "Errors are not included in the conversation", + "英语": "English", + "象限提示图": "Quadrant prompt diagram", + "由于不管提供文本是什么": "Because regardless of what the provided text is", + "确定后续剧情的发展": "Determine the development of the subsequent plot", + "处理空输入导致报错的问题 https": "Handle the error caused by empty input", + "第 3 部分": "Part 3", + "不能等于 0 或 1": "Cannot be equal to 0 or 1", + "同时过大的图表可能需要复制到在线编辑器中进行渲染": "Large charts may need to be copied to an online editor for rendering", + "装饰器函数ArgsGeneralWrapper": "Decorator function ArgsGeneralWrapper", + "写个函数移除所有的换行符": "Write a function to remove all line breaks", + "默认为False": "Default is False", + "实例化BaiduSpider": "Instantiate BaiduSpider", + "9-思维导图": "Mind Map 9", + "是否开启跨域": "Whether to enable cross-domain", + "随机InteractiveMiniGame": "Random InteractiveMiniGame", + "用于构建HTML报告的类和方法用于构建HTML报告的类和方法用于构建HTML报告的类和方法": "Classes and methods for building HTML reports", + "这里填一个提示词字符串就行了": "Just fill in a prompt string here", + "文本切分": "Text segmentation", + "用于在生成mermaid图表时隐藏代码块": "Used to hide code blocks when generating mermaid charts", + "如果剩余文本的token数小于限制": "If the number of tokens in the remaining text is less than the limit", + "未能在规定时间内完成任务": "Failed to complete the task within the specified time", + "API key has been deactivated. Cohere以账户失效为由": "API key has been deactivated. Cohere cited account expiration as the reason", + "正在使用讯飞图片理解API": "Using the Xunfei Image Understanding API", + "如果您使用docker-compose部署": "If you deploy using docker-compose", + "最大输入 token 数": "Maximum input token count", + "遇到了控制请求速率限制": "Encountered control request rate limit", + "数值范围约为0-1100": "The numerical range is approximately 0-1100", + "几乎使他晕厥过去": "Almost made him faint", + "识图模型GPT-4V": "Image recognition model GPT-4V", + "零一万物模型 -=-=-=-=-=-=-": "Zero-One Universe Model", + "所有对话记录将自动保存在本地目录": "All conversation records will be saved automatically in the local directory", + "饼图": "Pie Chart", + "添加Live2D": "Add Live2D", + "⭐ 单线程方法": "Single-threaded Method", + "配图": "Illustration", + "根据上述已知信息": "Based on the Above Known Information", + "1. 后续剧情发展1": "1. Subsequent Plot Development 1", + "2-序列图": "Sequence Diagram", + "流程图": "Flowchart", + "需求分析": "Requirement Analysis", + "我认为更合理的是": "I Think a More Reasonable Approach Is", + "claude家族": "Claude Family", + "”的逻辑关系图": "Logic Relationship Diagram", + "给出人物的名字": "Provide the Names of Characters", + "无法自动下载该论文的Latex源码": "Unable to Automatically Download the LaTeX Source Code of the Paper", + "需要用户手动处理的信息": "Information That Requires Manual Processing by Users", + "点击展开“文件下载区”": "Click to Expand 'File Download Area'", + "生成长度过长": "Excessive Length Generated", + "\\n\\n2. 长效解决方案": "2. Long-term Solution", + "=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= 插件主程序2 =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=": "=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= Plugin Main Program 2 =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=", + "title 项目开发流程": "Title Project Development Process", + "如果您希望剧情立即收尾": "If You Want the Plot to End Immediately", + "空格转换为 ": "Space Converted to  ", + "图片数量超过api上限": "Number of Images Exceeds API Limit", + "他知道": "He Knows", + "在这里输入自定义参数「分辨率-质量": "Enter Custom Parameters Here 'Resolution-Quality", + "例如ChatGLM&gpt-3.5-turbo&gpt-4": "For example ChatGLM, gpt-3.5-turbo, and gpt-4", + "账户管理": "Account Management", + "正在将翻译好的项目tex项目编译为PDF": "Compiling the Translated Project .tex Project into PDF", + "我们把 _max 后的文字转存至 remain_txt_to_cut_storage": "We save the text after _max to the remain_txt_to_cut_storage", + "标签之前停止匹配": "Stop matching before the label", + "例子": "Example", + "遍历检查是否有额外参数": "Iterate to check for extra parameters", + "文本分句长度": "Length of text segmentation", + "请你给出围绕“{subject}”的状态图": "Please provide a state diagram surrounding \"{subject}\"", + "用stream的方法避免中途网线被掐": "Use the stream method to avoid the cable being disconnected midway", + "然后在markdown表格中列出修改的内容": "Then list the changes in a Markdown table", + "以上是从文章中提取的摘要": "The above is an abstract extracted from the article", + "但是无法找到相关文件": "But unable to find the relevant file", + "上海AI-LAB书生大模型 -=-=-=-=-=-=-": "Shanghai AI-LAB Shu Sheng Large Model -=-=-=-=-=-=-", + "遇到第一个": "Meet the first", + "存储在名为const_extract_exp的变量中": "Stored in a variable named const_extract_exp", + "括号在正则表达式中表示捕获组": "Parentheses represent capture groups in regular expressions", + "那里的太空中渐渐隐现出一个方形区域": "A square area gradually appears in the space there", + "智谱GLM4超级模型🔥": "Zhipu GLM4 Super Model🔥", + "故事开头": "Beginning of the story", + "请检查文件格式是否正确": "Please check if the file format is correct", + "这个模式被编译成一个正则表达式对象": "This pattern is compiled into a regular expression object", + "单字符断句符": "Single character sentence break", + "看后续支持吧": "Let's see the follow-up support", + "markdown输入": "Markdown input", + "系统": "System", + "80字以内": "Within 80 characters", + "一个测试mermaid绘制图表的功能": "A function to test the Mermaid chart drawing", + "输入部分": "Input section", + "移除右侧逗号": "Remove the comma on the right", + "因此思维导图仅能通过参数调用": "Therefore, the mind map can only be invoked through parameters", + "6 状态图": "State Diagram", + "类图": "Class Diagram", + "不要重复前文": "Do not repeat the previous text", + "但内部": "But internally", + "小说的下一幕字数少于300字": "The next scene of the novel has fewer than 300 words", + "每个发展方向都精明扼要地用一句话说明": "Each development direction is concisely described in one sentence", + "充分考虑其之间的逻辑": "Fully consider the logic between them", + "兼顾前端状态的功能": "Take into account the functionality of the frontend state", + "1 流程图": "Flowchart", + "用户QQ群925365219": "User QQ Group 925365219", + "通义-本地模型 -=-=-=-=-=-=-": "Tongyi - Local Model", + "取值范围0-1000": "Value range 0-1000", + "但不是^*.开始": "But not ^*. Start", + "他们将钻出地壳去看诗云": "They will emerge from the crust to see the poetry cloud", + "我们正在互相讨论": "We are discussing with each other", + "值越小": "The smaller the value", + "请在以下几种故事走向中": "Please choose from the following story directions", + "请先把模型切换至gpt-*": "Please switch the model to gpt-* first", + "不再需要填写": "No longer needs to be filled out", + "深夜": "Late at night", + "小说的前文回顾": "Review of the previous text of the novel", + "项目文件树": "Project file tree", + "如果双引号前有终止符": "If there is a terminator before the double quotes", + "participant A as 用户": "Participant A as User", + "处理游戏初始化等特殊情况": "Handle special cases like game initialization", + "然后使用mermaid+llm绘制图表": "Then use mermaid+llm to draw charts", + "0表示不生效": "0 means not effective", + "在以下的剧情发展中": "In the following plot development", + "模型考虑具有 top_p 概率质量 tokens 的结果": "Model considering results with top_p probability quality tokens", + "根据字符串要给谁看": "Depending on who is intended to view the string", + "没有设置YIMODEL_API_KEY选项": "YIMODEL_API_KEY option is not set", + "换行符转换为": "Convert line breaks to", + "-风格": "-style", + "默认情况下并发量极低": "Default to a very low level of concurrency", + "为字符串加上上面定义的前缀和后缀": "Add the defined prefix and suffix to the string", + "先切换模型到gpt-*": "Switch the model to gpt-* first", + "它确保我们匹配的任意文本是尽可能短的": "It ensures that any text we match is as short as possible", + "积极地运用环境描写、人物描写等手法": "Actively use techniques such as environmental and character descriptions", + "零一万物": "Zero One Universe", + "html_local_file 本地文件取相对路径": "html_local_file takes the relative path of the local file", + "伊依一行三人乘坐一艘游艇在南太平洋上做吟诗航行": "Yi Yi and three others set sail on a yacht to recite poetry in the South Pacific", + "移除左边通配符": "Remove left wildcard characters", + "随后绘制图表": "Draw a chart subsequently", + "输入2": "Input 2", + "所以用最没有意义的一个点代替": "Therefore, replace it with the most meaningless point", + "等": "etc.", + "是本地文件": "Is a local file", + "正在文本切分": "Text segmentation in progress", + "等价于修改容器内部的环境变量": "Equivalent to modifying the environment variables inside the container", + "cohere等请求源": "Cohere and other request sources", + "我们再把 remain_txt_to_cut_storage 中的部分文字取出": "Then we extract part of the text from remain_txt_to_cut_storage", + "生成带掩码tag的字符串": "Generate a string with masked tags", + "智谱 -=-=-=-=-=-=-": "ZhiPu -=-=-=-=-=-=-", + "前缀字符串": "Prefix string", + "Temperature值越大随机性越大": "The larger the Temperature value, the greater the randomness", + "借用PDF切割中的函数对文本进行切割": "Use functions from PDF cutting to segment the text", + "挑选一种剧情发展": "Choose a plot development", + "将换行符转换为": "Convert line breaks to", + "0.1 意味着模型解码器只考虑从前 10% 的概率的候选集中取 tokens": "0.1 means the model decoder only considers taking tokens from the top 10% probability candidates", + "确定故事的下一步": "Determine the next step of the story", + "个文件的显示": "Display of a file", + "用于控制输出tokens的多样性": "Used to control the diversity of output tokens", + "导入BaiduSpider": "Import BaiduSpider", + "不输入则为模型自行判断": "If not entered, the model will judge on its own", + "准备下一次迭代": "Prepare for the next iteration", + "包含一些用于文本处理和模型微调的函数和装饰器包含一些用于文本处理和模型微调的函数和装饰器包含一些用于文本处理和模型微调的函数和装饰器": "Contains functions and decorators for text processing and model fine-tuning", + "由于没有单独的参数保存包含图片的历史": "Since there is no separate parameter to save the history with images", + "section 开发": "section development", + "注意这里没有掩码tag": "Note that there is no mask tag here", + "section 设计": "section design", + "对话|编程|学术|智能体": "Dialogue | Programming | Academic | Intelligent Agent", + "您只需要选择其中一种即可": "You only need to choose one of them", + "添加Live2D形象": "Add Live2D image", + "请用以下命令安装": "Please install with the following command", + "触发了Google的安全访问策略": "Triggered Google's safe access policy", + "参数示例「1024x1024-hd-vivid」 || 分辨率支持 「1024x1024」": "Parameter example '1024x1024-hd-vivid' || Resolution support '1024x1024'", + "结局除外": "Excluding the ending", + "subgraph 函数调用": "subgraph function call", + "项目示意图": "Project diagram", + "实体关系图": "Entity relationship diagram", + "计算机把他的代号定为M102": "The computer named his code M102", + "首先尝试用双空行": "Try using double empty lines first", + "接下来将判断适合的图表类型": "Next, determine the appropriate chart type", + "注意前面的几句都小心保留了双引号": "Note that the previous sentences have carefully preserved double quotes", + "您正在调用插件": "You are calling a plugin", + "从上到下": "From top to bottom", + "请配置HUOSHAN_API_KEY": "Please configure HUOSHAN_API_KEY", + "知识检索内容相关度 Score": "Knowledge retrieval content relevance score", + "所以不会被处理": "So it will not be processed", + "设置10秒即可": "Set to 10 seconds", + "以空格分割": "Separated by space", + "根据位置和名称": "According to position and name", + "一些垃圾第三方接口出现这样的错误": "Some crappy third-party interfaces have this error", + "////////////////////// 输入清除键 ///////////////////////////": "////////////////////// Input Clear Key ///////////////////////////", + "并解析为html or md 文本": "And parse as HTML or MD text", + "匹配单段内容的连接上下文长度": "Matching single section content connection context length", + "控制输出的随机性": "Control the randomness of output", + "是模型名": "Is model name", + "请检查配置文件": "Please check the configuration file", + "如何使用one-api快速接入": "How to quickly access using one-api", + "请求失败": "Request failed", + "追加列表": "Append list", + "////////////////////// 函数插件区 ///////////////////////////": "////////////////////// Function Plugin Area ///////////////////////////", + "你是WPSAi": "You are WPSAi", + "第五部分 一些文件处理方法": "Part Five Some file processing methods", + "圆圆迷上了肥皂泡": "Yuan Yuan is fascinated by soap bubbles", + "可选参数": "Optional parameters", + "one-api模型": "one-api model", + "port/gpt_academic/ 下": "Under port/gpt_academic/", + "下一段故事": "Next part of the story", + "* 表示前一个字符可以出现0次或多次": "* means the previous character can appear 0 or more times", + "向后兼容配置": "Backward compatible configuration", + "输出部分": "Output section", + "稍后": "Later", + "比如比喻、拟人、排比、对偶、夸张等等": "For example, similes, personification, parallelism, antithesis, hyperbole, etc.", + "是自定义按钮": "Is a custom button", + "你需要根据用户给出的小说段落": "You need to based on the novel paragraph given by the user", + "以mermaid flowchart的形式展示": "Display in the form of a mermaid flowchart", + "最后一幕的字数少于1000字": "The last scene has fewer than 1000 words", + "如没出错则保持为空": "Keep it empty if there are no errors", + "建议您根据应用场景调整 top_p 或 temperature 参数": "It is recommended to adjust the top_p or temperature parameters according to the application scenario", + "仿佛他的出生就是要和这东西约会似的": "As if his birth was meant to date this thing", + "处理特殊的渲染问题": "Handle special rendering issues", + "我认为最合理的故事结局是": "I think the most reasonable ending for the story is", + "请给出上方内容的思维导图": "Please provide a mind map of the content above", + "点other Formats": "Click on other Formats", + "文件加载完毕": "File loaded", + "Your account is not active. Cohere以账户失效为由": "Your account is not active. Cohere cites the account's inactivation as the reason", + "找不到任何.pdf文件": "Cannot find any .pdf files", + "请根据判断结果绘制相应的图表": "Please draw the corresponding chart based on the judgment result", + "积极地运用修辞手法": "Actively use rhetorical devices", + "工具函数 =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-": "Utility function -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=", + "=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= 插件主程序1 =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=": "=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= Plugin Main Program 1 =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=", + "在": "In", + "即正则表达式库": "That is, the regular expression library", + "////////////////////// 基础功能区 ///////////////////////////": "////////////////////// Basic Function Area ///////////////////////////", + "并重新编译PDF | 输入参数为路径": "And recompile PDF | Input parameter is the path", + "甘特图": "Gantt Chart", + "但是需要注册账号": "But registration is required", + "获取完整的从Cohere返回的报错": "Get the complete error message returned from Cohere", + "合并摘要": "Merge Summary", + "这最后一课要提前讲了": "The last lesson will be taught ahead of schedule", + "大模型": "Large Model", + "查找输入区内容中的文件": "Find files in the input area content", + "预处理参数": "Preprocessing Parameters", + "这段代码定义了一个名为ProxyNetworkActivate的空上下文管理器": "This code defines an empty context manager named ProxyNetworkActivate", + "对话错误": "Dialogue Error", + "确定故事的结局": "Determine the ending of the story", + "第 1 部分": "Part 1", + "直到遇到括号外部最近的限定符": "Until the nearest qualifier outside the parentheses is encountered", + "负责向用户前端展示对话": "Responsible for displaying dialogue to the user frontend", + "查询内容": "Query Content", + "匹配结果更精准": "More accurate matching results", + "根据选择的图表类型绘制图表": "Draw a chart based on the selected chart type", + "空格、换行、空字符串都会报错": "Spaces, line breaks, and empty strings will all result in errors", + "请尝试削减单次输入的文本量": "Please try to reduce the amount of text in a single input", + "上传到路径": "Upload to path", + "中": "In", + "后缀字符串": "Suffix string", + "您还可以在接入one-api时": "You can also when accessing one-api", + "请说 “根据已知信息无法回答该问题” 或 “没有提供足够的相关信息”": "Please say 'Cannot answer the question based on available information' or 'Not enough relevant information is provided'", + "Cohere和API2D不会走这里": "Cohere and API2D will not go here", + "节点名字使用引号包裹": "Node names should be enclosed in quotes", + "这次的故事开头是": "The beginning of this story is", + "你是一个想象力丰富的杰出作家": "You are a brilliant writer with a rich imagination", + "正在与你的朋友互动": "Interacting with your friends", + "/「-hd」 || 风格支持 「-vivid」": "/ '-hd' || Style supports '-vivid'", + "如输入区无内容则直接解析历史记录": "If the input area is empty, parse the history directly", + "根据以上的情节": "Based on the above plot", + "将图表类型参数赋值为插件参数": "Set the chart type parameter to the plugin parameter", + "根据图片类型返回image/jpeg": "Return image/jpeg based on image type", + "如果lang_reference是英文": "If lang_reference is English", + "示意图": "Schematic diagram", + "完整参数列表": "Complete parameter list", + "仿佛灿烂的群星的背景被剪出一个方口": "As if the brilliant background of stars has been cut out into a square", + "如果没有找到合适的切分点": "If no suitable splitting point is found", + "获取数据": "Get data", + "内嵌的javascript代码": "Embedded JavaScript code", + "绘制多种mermaid图表": "Draw various mermaid charts", + "无效": "Invalid", + "查找pdf/md/word并获取文本内容并返回状态以及文本": "Search for pdf/md/word, retrieve text content, and return status and text", + "总结绘制脑图": "Summarize mind mapping", + "禁止杜撰不符合我选择的剧情": "Prohibit making up plots that do not match my choice", + "正在生成向量库": "Generating vector library", + "是LLM的内部调优参数": "Is an internal tuning parameter of LLM", + "请你选择一个合适的图表类型": "Please choose an appropriate chart type", + "请在“输入区”输入图像生成提示": "Please enter image generation prompts in the 'input area'", + "经测试设置为小于500时": "After testing, set it to less than 500", + "当然": "Certainly", + "必要": "Necessary", + "从左到右": "From left to right", + "接下来调用本地Latex翻译插件即可": "Next, call the local Latex translation plugin", + "如果相同则返回": "If the same, return", + "根据语言": "According to the language", + "使用mermaid语法": "Use mermaid syntax", + "这是游戏的第一步": "This is the first step of the game", + "构建后续剧情引导": "Building subsequent plot guidance", + "以满足 token 限制": "To meet the token limit", + "也就是说": "That is to say", + "mermaid语法举例": "Mermaid syntax example", + "发送": "Send", + "那么就只显示英文提示词": "Then only display English prompts", + "正在检查": "Checking", + "返回处理后的字符串": "Return the processed string", + "2 序列图": "Sequence diagram 2", + "yi-34b-chat-0205只有4k上下文": "yi-34b-chat-0205 has only 4k context", + "请检查配置": "Please check the configuration", + "请你给出围绕“{subject}”的象限图": "Please provide a quadrant diagram around '{subject}'", + "故事该结束了": "The story should end", + "修复缩进": "Fix indentation", + "请描述给出的图片": "Please describe the given image", + "启用插件热加载": "Enable plugin hot reload", + "通义-在线模型 -=-=-=-=-=-=-": "Tongyi - Online Model", + "比较页数是否相同": "Compare if the number of pages is the same", + "正式开始服务": "Officially start the service", + "使用mermaid flowchart对以上文本进行总结": "Summarize the above text using a mermaid flowchart", + "不是vision 才处理history": "Not only vision but also handle history", + "来定义了一个正则表达式模式": "Defined a regular expression pattern", + "IP地址等": "IP addresses, etc.", + "那么双引号才是句子的终点": "Then the double quotes mark the end of the sentence", + "输入1": "Input 1", + "/「1792x1024」/「1024x1792」 || 质量支持 「-standard」": "/'1792x1024'/ '1024x1792' || Quality support '-standard'", + "为了避免索引错误将其更改为大写": "To avoid indexing errors, change it to uppercase", + "搜索网页": "Search the web", + "用于控制生成文本的随机性和创造性": "Used to control the randomness and creativity of generated text", + "不能等于 0": "Cannot equal 0", + "在距地球五万光年的远方": "At a distance of fifty thousand light-years from Earth", + ". 表示任意单一字符": ". represents any single character", + "选择预测值最大的k个token进行采样": "Select the k tokens with the largest predicted values for sampling", + "输出2": "Output 2", + "函数示意图": "Function Diagram", + "You are associated with a deactivated account. Cohere以账户失效为由": "You are associated with a deactivated account. Cohere due to account deactivation", + "3. 后续剧情发展3": "3. Subsequent Plot Development", + "并以“剧情收尾”四个字提示程序": "And use the four characters 'Plot Conclusion' as a prompt for the program", + "中文省略号": "Chinese Ellipsis", + "则不生效": "Will not take effect", + "目前是两位小数": "Currently is two decimal places", + "Incorrect API key. Cohere以提供了不正确的API_KEY为由": "Incorrect API key. Cohere reports an incorrect API_KEY." +} \ No newline at end of file diff --git a/main.py b/main.py index 08ec61b81..23c02d370 100644 --- a/main.py +++ b/main.py @@ -13,6 +13,17 @@

如何语音对话: 请阅读Wiki

如何临时更换API_KEY: 在输入区输入临时API_KEY后提交(网页刷新后失效)""" +def enable_log(PATH_LOGGING): + import logging, uuid + admin_log_path = os.path.join(PATH_LOGGING, "admin") + os.makedirs(admin_log_path, exist_ok=True) + log_dir = os.path.join(admin_log_path, "chat_secrets.log") + try:logging.basicConfig(filename=log_dir, level=logging.INFO, encoding="utf-8", format="%(asctime)s %(levelname)-8s %(message)s", datefmt="%Y-%m-%d %H:%M:%S") + except:logging.basicConfig(filename=log_dir, level=logging.INFO, format="%(asctime)s %(levelname)-8s %(message)s", datefmt="%Y-%m-%d %H:%M:%S") + # Disable logging output from the 'httpx' logger + logging.getLogger("httpx").setLevel(logging.WARNING) + print(f"所有对话记录将自动保存在本地目录{log_dir}, 请注意自我隐私保护哦!") + def main(): import gradio as gr if gr.__version__ not in ['3.32.9']: @@ -31,18 +42,11 @@ def main(): from check_proxy import get_current_version from themes.theme import adjust_theme, advanced_css, theme_declaration, js_code_clear, js_code_reset, js_code_show_or_hide, js_code_show_or_hide_group2 from themes.theme import js_code_for_css_changing, js_code_for_toggle_darkmode, js_code_for_persistent_cookie_init - from themes.theme import load_dynamic_theme, to_cookie_str, from_cookie_str, init_cookie + from themes.theme import load_dynamic_theme, to_cookie_str, from_cookie_str, assign_user_uuid title_html = f"

GPT 学术优化 {get_current_version()}

{theme_declaration}" - # 对话记录, python 版本建议3.9+(越新越好) - import logging, uuid - os.makedirs(PATH_LOGGING, exist_ok=True) - chat_secrets_log = os.path.join(PATH_LOGGING, "chat_secrets.log") - try:logging.basicConfig(filename=chat_secrets_log, level=logging.INFO, encoding="utf-8", format="%(asctime)s %(levelname)-8s %(message)s", datefmt="%Y-%m-%d %H:%M:%S") - except:logging.basicConfig(filename=chat_secrets_log, level=logging.INFO, format="%(asctime)s %(levelname)-8s %(message)s", datefmt="%Y-%m-%d %H:%M:%S") - # Disable logging output from the 'httpx' logger - logging.getLogger("httpx").setLevel(logging.WARNING) - print(f"所有对话记录将自动保存在本地目录 {chat_secrets_log}, 请注意自我隐私保护哦!") + # 对话、日志记录 + enable_log(PATH_LOGGING) # 一些普通功能模块 from core_functional import get_core_functions @@ -75,9 +79,9 @@ def main(): cancel_handles = [] customize_btns = {} predefined_btns = {} - with gr.Blocks(title="GPT 学术优化", theme=set_theme, analytics_enabled=False, css=advanced_css) as demo: + with gr.Blocks(title="GPT 学术优化", theme=set_theme, analytics_enabled=False, css=advanced_css) as app_block: gr.HTML(title_html) - secret_css, py_pickle_cookie = gr.Textbox(visible=False), gr.Textbox(visible=False) + secret_css, web_cookie_cache = gr.Textbox(visible=False), gr.Textbox(visible=False) cookies = gr.State(load_chat_cookies()) with gr_L1(): with gr_L2(scale=2, elem_id="gpt-chat"): @@ -199,64 +203,19 @@ def main(): with gr.Column(scale=1, min_width=70): basic_fn_confirm = gr.Button("确认并保存", variant="primary"); basic_fn_confirm.style(size="sm") basic_fn_clean = gr.Button("恢复默认", variant="primary"); basic_fn_clean.style(size="sm") - def assign_btn(persistent_cookie_, cookies_, basic_btn_dropdown_, basic_fn_title, basic_fn_prefix, basic_fn_suffix, clean_up=False): - ret = {} - # 读取之前的自定义按钮 - customize_fn_overwrite_ = cookies_['customize_fn_overwrite'] - # 更新新的自定义按钮 - customize_fn_overwrite_.update({ - basic_btn_dropdown_: - { - "Title":basic_fn_title, - "Prefix":basic_fn_prefix, - "Suffix":basic_fn_suffix, - } - } - ) - if clean_up: - customize_fn_overwrite_ = {} - cookies_.update(customize_fn_overwrite_) # 更新cookie - visible = (not clean_up) and (basic_fn_title != "") - if basic_btn_dropdown_ in customize_btns: - # 是自定义按钮,不是预定义按钮 - ret.update({customize_btns[basic_btn_dropdown_]: gr.update(visible=visible, value=basic_fn_title)}) - else: - # 是预定义按钮 - ret.update({predefined_btns[basic_btn_dropdown_]: gr.update(visible=visible, value=basic_fn_title)}) - ret.update({cookies: cookies_}) - try: persistent_cookie_ = from_cookie_str(persistent_cookie_) # persistent cookie to dict - except: persistent_cookie_ = {} - persistent_cookie_["custom_bnt"] = customize_fn_overwrite_ # dict update new value - persistent_cookie_ = to_cookie_str(persistent_cookie_) # persistent cookie to dict - ret.update({py_pickle_cookie: persistent_cookie_}) # write persistent cookie - return ret + from shared_utils.cookie_manager import assign_btn__fn_builder + assign_btn = assign_btn__fn_builder(customize_btns, predefined_btns, cookies, web_cookie_cache) # update btn - h = basic_fn_confirm.click(assign_btn, [py_pickle_cookie, cookies, basic_btn_dropdown, basic_fn_title, basic_fn_prefix, basic_fn_suffix], - [py_pickle_cookie, cookies, *customize_btns.values(), *predefined_btns.values()]) - h.then(None, [py_pickle_cookie], None, _js="""(py_pickle_cookie)=>{setCookie("py_pickle_cookie", py_pickle_cookie, 365);}""") + h = basic_fn_confirm.click(assign_btn, [web_cookie_cache, cookies, basic_btn_dropdown, basic_fn_title, basic_fn_prefix, basic_fn_suffix], + [web_cookie_cache, cookies, *customize_btns.values(), *predefined_btns.values()]) + h.then(None, [web_cookie_cache], None, _js="""(web_cookie_cache)=>{setCookie("web_cookie_cache", web_cookie_cache, 365);}""") # clean up btn - h2 = basic_fn_clean.click(assign_btn, [py_pickle_cookie, cookies, basic_btn_dropdown, basic_fn_title, basic_fn_prefix, basic_fn_suffix, gr.State(True)], - [py_pickle_cookie, cookies, *customize_btns.values(), *predefined_btns.values()]) - h2.then(None, [py_pickle_cookie], None, _js="""(py_pickle_cookie)=>{setCookie("py_pickle_cookie", py_pickle_cookie, 365);}""") + h2 = basic_fn_clean.click(assign_btn, [web_cookie_cache, cookies, basic_btn_dropdown, basic_fn_title, basic_fn_prefix, basic_fn_suffix, gr.State(True)], + [web_cookie_cache, cookies, *customize_btns.values(), *predefined_btns.values()]) + h2.then(None, [web_cookie_cache], None, _js="""(web_cookie_cache)=>{setCookie("web_cookie_cache", web_cookie_cache, 365);}""") - def persistent_cookie_reload(persistent_cookie_, cookies_): - ret = {} - for k in customize_btns: - ret.update({customize_btns[k]: gr.update(visible=False, value="")}) - try: persistent_cookie_ = from_cookie_str(persistent_cookie_) # persistent cookie to dict - except: return ret - - customize_fn_overwrite_ = persistent_cookie_.get("custom_bnt", {}) - cookies_['customize_fn_overwrite'] = customize_fn_overwrite_ - ret.update({cookies: cookies_}) - - for k,v in persistent_cookie_["custom_bnt"].items(): - if v['Title'] == "": continue - if k in customize_btns: ret.update({customize_btns[k]: gr.update(visible=True, value=v['Title'])}) - else: ret.update({predefined_btns[k]: gr.update(visible=True, value=v['Title'])}) - return ret # 功能区显示开关与功能区的互动 def fn_area_visibility(a): @@ -376,11 +335,14 @@ def deal_audio(audio, cookies): audio_mic.stream(deal_audio, inputs=[audio_mic, cookies]) - demo.load(init_cookie, inputs=[cookies], outputs=[cookies]) - demo.load(persistent_cookie_reload, inputs = [py_pickle_cookie, cookies], - outputs = [py_pickle_cookie, cookies, *customize_btns.values(), *predefined_btns.values()], _js=js_code_for_persistent_cookie_init) - demo.load(None, inputs=[], outputs=None, _js=f"""()=>init_frontend_with_cookies("{DARK_MODE}","{INIT_SYS_PROMPT}","{ADD_WAIFU}")""") # 配置暗色主题或亮色主题 - demo.load(None, inputs=[gr.Textbox(LAYOUT, visible=False)], outputs=None, _js='(LAYOUT)=>{GptAcademicJavaScriptInit(LAYOUT);}') + app_block.load(assign_user_uuid, inputs=[cookies], outputs=[cookies]) + + from shared_utils.cookie_manager import load_web_cookie_cache__fn_builder + load_web_cookie_cache = load_web_cookie_cache__fn_builder(customize_btns, cookies, predefined_btns) + app_block.load(load_web_cookie_cache, inputs = [web_cookie_cache, cookies], + outputs = [web_cookie_cache, cookies, *customize_btns.values(), *predefined_btns.values()], _js=js_code_for_persistent_cookie_init) + + app_block.load(None, inputs=[], outputs=None, _js=f"""()=>GptAcademicJavaScriptInit("{DARK_MODE}","{INIT_SYS_PROMPT}","{ADD_WAIFU}","{LAYOUT}")""") # 配置暗色主题或亮色主题 # gradio的inbrowser触发不太稳定,回滚代码到原始的浏览器打开函数 def run_delayed_tasks(): @@ -395,19 +357,15 @@ def warm_up_mods(): time.sleep(6); warm_up_modules() threading.Thread(target=auto_updates, name="self-upgrade", daemon=True).start() # 查看自动更新 threading.Thread(target=open_browser, name="open-browser", daemon=True).start() # 打开浏览器页面 - threading.Thread(target=warm_up_mods, name="warm-up", daemon=True).start() # 预热tiktoken模块 + threading.Thread(target=warm_up_mods, name="warm-up", daemon=True).start() # 预热tiktoken模块 + # 运行一些异步任务:自动更新、打开浏览器页面、预热tiktoken模块 run_delayed_tasks() - demo.queue(concurrency_count=CONCURRENT_COUNT).launch( - quiet=True, - server_name="0.0.0.0", - ssl_keyfile=None if SSL_KEYFILE == "" else SSL_KEYFILE, - ssl_certfile=None if SSL_CERTFILE == "" else SSL_CERTFILE, - ssl_verify=False, - server_port=PORT, - favicon_path=os.path.join(os.path.dirname(__file__), "docs/logo.png"), - auth=AUTHENTICATION if len(AUTHENTICATION) != 0 else None, - blocked_paths=["config.py","__pycache__","config_private.py","docker-compose.yml","Dockerfile",f"{PATH_LOGGING}/admin", chat_secrets_log]) + + # 最后,正式开始服务 + from shared_utils.fastapi_server import start_app + start_app(app_block, CONCURRENT_COUNT, AUTHENTICATION, PORT, SSL_KEYFILE, SSL_CERTFILE) + if __name__ == "__main__": main() diff --git a/request_llms/bridge_all.py b/request_llms/bridge_all.py index 9b2ac3c61..033a8d92a 100644 --- a/request_llms/bridge_all.py +++ b/request_llms/bridge_all.py @@ -34,6 +34,9 @@ from .bridge_zhipu import predict_no_ui_long_connection as zhipu_noui from .bridge_zhipu import predict as zhipu_ui +from .bridge_cohere import predict as cohere_ui +from .bridge_cohere import predict_no_ui_long_connection as cohere_noui + colors = ['#FF00FF', '#00FFFF', '#FF0000', '#990099', '#009999', '#990044'] class LazyloadTiktoken(object): @@ -64,6 +67,7 @@ def decode(self, *args, **kwargs): gemini_endpoint = "https://generativelanguage.googleapis.com/v1beta/models" claude_endpoint = "https://api.anthropic.com/v1/messages" yimodel_endpoint = "https://api.lingyiwanwu.com/v1/chat/completions" +cohere_endpoint = 'https://api.cohere.ai/v1/chat' if not AZURE_ENDPOINT.endswith('/'): AZURE_ENDPOINT += '/' azure_endpoint = AZURE_ENDPOINT + f'openai/deployments/{AZURE_ENGINE}/chat/completions?api-version=2023-05-15' @@ -82,6 +86,7 @@ def decode(self, *args, **kwargs): if gemini_endpoint in API_URL_REDIRECT: gemini_endpoint = API_URL_REDIRECT[gemini_endpoint] if claude_endpoint in API_URL_REDIRECT: claude_endpoint = API_URL_REDIRECT[claude_endpoint] if yimodel_endpoint in API_URL_REDIRECT: yimodel_endpoint = API_URL_REDIRECT[yimodel_endpoint] +if cohere_endpoint in API_URL_REDIRECT: cohere_endpoint = API_URL_REDIRECT[cohere_endpoint] # 获取tokenizer tokenizer_gpt35 = LazyloadTiktoken("gpt-3.5-turbo") @@ -351,6 +356,18 @@ def decode(self, *args, **kwargs): "tokenizer": tokenizer_gpt35, "token_cnt": get_token_num_gpt35, }, + + # cohere + "cohere-command-r-plus": { + "fn_with_ui": cohere_ui, + "fn_without_ui": cohere_noui, + "can_multi_thread": True, + "endpoint": cohere_endpoint, + "max_token": 1024 * 4, + "tokenizer": tokenizer_gpt35, + "token_cnt": get_token_num_gpt35, + }, + } # -=-=-=-=-=-=- 月之暗面 -=-=-=-=-=-=- from request_llms.bridge_moonshot import predict as moonshot_ui @@ -400,7 +417,7 @@ def decode(self, *args, **kwargs): # -=-=-=-=-=-=- 以下部分是新加入的模型,可能附带额外依赖 -=-=-=-=-=-=- # claude家族 -claude_models = ["claude-instant-1.2","claude-2.0","claude-2.1","claude-3-sonnet-20240229","claude-3-opus-20240229"] +claude_models = ["claude-instant-1.2","claude-2.0","claude-2.1","claude-3-haiku-20240307","claude-3-sonnet-20240229","claude-3-opus-20240229"] if any(item in claude_models for item in AVAIL_LLM_MODELS): from .bridge_claude import predict_no_ui_long_connection as claude_noui from .bridge_claude import predict as claude_ui @@ -434,6 +451,16 @@ def decode(self, *args, **kwargs): "token_cnt": get_token_num_gpt35, }, }) + model_info.update({ + "claude-3-haiku-20240307": { + "fn_with_ui": claude_ui, + "fn_without_ui": claude_noui, + "endpoint": claude_endpoint, + "max_token": 200000, + "tokenizer": tokenizer_gpt35, + "token_cnt": get_token_num_gpt35, + }, + }) model_info.update({ "claude-3-sonnet-20240229": { "fn_with_ui": claude_ui, @@ -830,7 +857,7 @@ def LLM_CATCH_EXCEPTION(f): """ 装饰器函数,将错误显示出来 """ - def decorated(inputs, llm_kwargs, history, sys_prompt, observe_window, console_slience): + def decorated(inputs:str, llm_kwargs:dict, history:list, sys_prompt:str, observe_window:list, console_slience:bool): try: return f(inputs, llm_kwargs, history, sys_prompt, observe_window, console_slience) except Exception as e: @@ -840,9 +867,9 @@ def decorated(inputs, llm_kwargs, history, sys_prompt, observe_window, console_s return decorated -def predict_no_ui_long_connection(inputs, llm_kwargs, history, sys_prompt, observe_window=[], console_slience=False): +def predict_no_ui_long_connection(inputs:str, llm_kwargs:dict, history:list, sys_prompt:str, observe_window:list=[], console_slience:bool=False): """ - 发送至LLM,等待回复,一次性完成,不显示中间过程。但内部用stream的方法避免中途网线被掐。 + 发送至LLM,等待回复,一次性完成,不显示中间过程。但内部(尽可能地)用stream的方法避免中途网线被掐。 inputs: 是本次问询的输入 sys_prompt: @@ -860,7 +887,6 @@ def predict_no_ui_long_connection(inputs, llm_kwargs, history, sys_prompt, obser model = llm_kwargs['llm_model'] n_model = 1 if '&' not in model: - assert not model.startswith("tgui"), "TGUI不支持函数插件的实现" # 如果只询问1个大语言模型: method = model_info[model]["fn_without_ui"] @@ -921,15 +947,22 @@ def mutex_manager(window_mutex, observe_window): return res -def predict(inputs, llm_kwargs, *args, **kwargs): +def predict(inputs:str, llm_kwargs:dict, *args, **kwargs): """ 发送至LLM,流式获取输出。 用于基础的对话功能。 - inputs 是本次问询的输入 - top_p, temperature是LLM的内部调优参数 - history 是之前的对话列表(注意无论是inputs还是history,内容太长了都会触发token数量溢出的错误) - chatbot 为WebUI中显示的对话列表,修改它,然后yeild出去,可以直接修改对话界面内容 - additional_fn代表点击的哪个按钮,按钮见functional.py + + 完整参数列表: + predict( + inputs:str, # 是本次问询的输入 + llm_kwargs:dict, # 是LLM的内部调优参数 + plugin_kwargs:dict, # 是插件的内部参数 + chatbot:ChatBotWithCookies, # 原样传递,负责向用户前端展示对话,兼顾前端状态的功能 + history:list=[], # 是之前的对话列表 + system_prompt:str='', # 系统静默prompt + stream:bool=True, # 是否流式输出(已弃用) + additional_fn:str=None # 基础功能区按钮的附加功能 + ): """ inputs = apply_gpt_academic_string_mask(inputs, mode="show_llm") diff --git a/request_llms/bridge_chatglmft.py b/request_llms/bridge_chatglmft.py index 84f1426b6..394a33877 100644 --- a/request_llms/bridge_chatglmft.py +++ b/request_llms/bridge_chatglmft.py @@ -137,7 +137,8 @@ def stream_chat(self, **kwargs): global glmft_handle glmft_handle = None ################################################################################# -def predict_no_ui_long_connection(inputs, llm_kwargs, history=[], sys_prompt="", observe_window=[], console_slience=False): +def predict_no_ui_long_connection(inputs:str, llm_kwargs:dict, history:list=[], sys_prompt:str="", + observe_window:list=[], console_slience:bool=False): """ 多线程方法 函数的说明请见 request_llms/bridge_all.py diff --git a/request_llms/bridge_chatgpt.py b/request_llms/bridge_chatgpt.py index 3b1aec662..1be5d4321 100644 --- a/request_llms/bridge_chatgpt.py +++ b/request_llms/bridge_chatgpt.py @@ -23,6 +23,7 @@ # 读取时首先看是否存在私密的config_private配置文件(不受git管控),如果有,则覆盖原config文件 from toolbox import get_conf, update_ui, is_any_api_key, select_api_key, what_keys, clip_history from toolbox import trimmed_format_exc, is_the_upload_folder, read_one_api_model_name, log_chat +from toolbox import ChatBotWithCookies proxies, TIMEOUT_SECONDS, MAX_RETRY, API_ORG, AZURE_CFG_ARRAY = \ get_conf('proxies', 'TIMEOUT_SECONDS', 'MAX_RETRY', 'API_ORG', 'AZURE_CFG_ARRAY') @@ -69,7 +70,7 @@ def verify_endpoint(endpoint): raise ValueError("Endpoint不正确, 请检查AZURE_ENDPOINT的配置! 当前的Endpoint为:" + endpoint) return endpoint -def predict_no_ui_long_connection(inputs, llm_kwargs, history=[], sys_prompt="", observe_window=None, console_slience=False): +def predict_no_ui_long_connection(inputs:str, llm_kwargs:dict, history:list=[], sys_prompt:str="", observe_window:list=None, console_slience:bool=False): """ 发送至chatGPT,等待回复,一次性完成,不显示中间过程。但内部用stream的方法避免中途网线被掐。 inputs: @@ -147,7 +148,8 @@ def predict_no_ui_long_connection(inputs, llm_kwargs, history=[], sys_prompt="", return result -def predict(inputs, llm_kwargs, plugin_kwargs, chatbot, history=[], system_prompt='', stream = True, additional_fn=None): +def predict(inputs:str, llm_kwargs:dict, plugin_kwargs:dict, chatbot:ChatBotWithCookies, + history:list=[], system_prompt:str='', stream:bool=True, additional_fn:str=None): """ 发送至chatGPT,流式获取输出。 用于基础的对话功能。 diff --git a/request_llms/bridge_claude.py b/request_llms/bridge_claude.py index 6eb0a89b2..fd6b5afd7 100644 --- a/request_llms/bridge_claude.py +++ b/request_llms/bridge_claude.py @@ -13,11 +13,11 @@ import os import time import traceback -from toolbox import get_conf, update_ui, trimmed_format_exc, encode_image, every_image_file_in_path import json import requests +from toolbox import get_conf, update_ui, trimmed_format_exc, encode_image, every_image_file_in_path, log_chat picture_system_prompt = "\n当回复图像时,必须说明正在回复哪张图像。所有图像仅在最后一个问题中提供,即使它们在历史记录中被提及。请使用'这是第X张图像:'的格式来指明您正在描述的是哪张图像。" -Claude_3_Models = ["claude-3-sonnet-20240229", "claude-3-opus-20240229"] +Claude_3_Models = ["claude-3-haiku-20240307", "claude-3-sonnet-20240229", "claude-3-opus-20240229"] # config_private.py放自己的秘密如API和代理网址 # 读取时首先看是否存在私密的config_private配置文件(不受git管控),如果有,则覆盖原config文件 @@ -95,7 +95,7 @@ def predict_no_ui_long_connection(inputs, llm_kwargs, history=[], sys_prompt="", # make a POST request to the API endpoint, stream=False from .bridge_all import model_info endpoint = model_info[llm_kwargs['llm_model']]['endpoint'] - response = requests.post(endpoint, headers=headers, json=message, + response = requests.post(endpoint, headers=headers, json=message, proxies=proxies, stream=True, timeout=TIMEOUT_SECONDS);break except requests.exceptions.ReadTimeout as e: retry += 1 @@ -116,7 +116,7 @@ def predict_no_ui_long_connection(inputs, llm_kwargs, history=[], sys_prompt="", if need_to_pass: pass elif is_last_chunk: - logging.info(f'[response] {result}') + # logging.info(f'[response] {result}') break else: if chunkjson and chunkjson['type'] == 'content_block_delta': @@ -194,7 +194,7 @@ def predict(inputs, llm_kwargs, plugin_kwargs, chatbot, history=[], system_promp # make a POST request to the API endpoint, stream=True from .bridge_all import model_info endpoint = model_info[llm_kwargs['llm_model']]['endpoint'] - response = requests.post(endpoint, headers=headers, json=message, + response = requests.post(endpoint, headers=headers, json=message, proxies=proxies, stream=True, timeout=TIMEOUT_SECONDS);break except requests.exceptions.ReadTimeout as e: retry += 1 @@ -216,7 +216,8 @@ def predict(inputs, llm_kwargs, plugin_kwargs, chatbot, history=[], system_promp if need_to_pass: pass elif is_last_chunk: - logging.info(f'[response] {gpt_replying_buffer}') + log_chat(llm_model=llm_kwargs["llm_model"], input_str=inputs, output_str=gpt_replying_buffer) + # logging.info(f'[response] {gpt_replying_buffer}') break else: if chunkjson and chunkjson['type'] == 'content_block_delta': @@ -305,4 +306,4 @@ def generate_payload(inputs, llm_kwargs, history, system_prompt, image_paths): 'stream': True, 'system': system_prompt } - return headers, payload \ No newline at end of file + return headers, payload diff --git a/request_llms/bridge_cohere.py b/request_llms/bridge_cohere.py new file mode 100644 index 000000000..5ce5846c9 --- /dev/null +++ b/request_llms/bridge_cohere.py @@ -0,0 +1,328 @@ +# 借鉴了 https://github.com/GaiZhenbiao/ChuanhuChatGPT 项目 + +""" + 该文件中主要包含三个函数 + + 不具备多线程能力的函数: + 1. predict: 正常对话时使用,具备完备的交互功能,不可多线程 + + 具备多线程调用能力的函数 + 2. predict_no_ui_long_connection:支持多线程 +""" + +import json +import time +import gradio as gr +import logging +import traceback +import requests +import importlib +import random + +# config_private.py放自己的秘密如API和代理网址 +# 读取时首先看是否存在私密的config_private配置文件(不受git管控),如果有,则覆盖原config文件 +from toolbox import get_conf, update_ui, is_any_api_key, select_api_key, what_keys, clip_history +from toolbox import trimmed_format_exc, is_the_upload_folder, read_one_api_model_name, log_chat +from toolbox import ChatBotWithCookies +proxies, TIMEOUT_SECONDS, MAX_RETRY, API_ORG, AZURE_CFG_ARRAY = \ + get_conf('proxies', 'TIMEOUT_SECONDS', 'MAX_RETRY', 'API_ORG', 'AZURE_CFG_ARRAY') + +timeout_bot_msg = '[Local Message] Request timeout. Network error. Please check proxy settings in config.py.' + \ + '网络错误,检查代理服务器是否可用,以及代理设置的格式是否正确,格式须是[协议]://[地址]:[端口],缺一不可。' + +def get_full_error(chunk, stream_response): + """ + 获取完整的从Cohere返回的报错 + """ + while True: + try: + chunk += next(stream_response) + except: + break + return chunk + +def decode_chunk(chunk): + # 提前读取一些信息 (用于判断异常) + chunk_decoded = chunk.decode() + chunkjson = None + has_choices = False + choice_valid = False + has_content = False + has_role = False + try: + chunkjson = json.loads(chunk_decoded) + has_choices = 'choices' in chunkjson + if has_choices: choice_valid = (len(chunkjson['choices']) > 0) + if has_choices and choice_valid: has_content = ("content" in chunkjson['choices'][0]["delta"]) + if has_content: has_content = (chunkjson['choices'][0]["delta"]["content"] is not None) + if has_choices and choice_valid: has_role = "role" in chunkjson['choices'][0]["delta"] + except: + pass + return chunk_decoded, chunkjson, has_choices, choice_valid, has_content, has_role + +from functools import lru_cache +@lru_cache(maxsize=32) +def verify_endpoint(endpoint): + """ + 检查endpoint是否可用 + """ + if "你亲手写的api名称" in endpoint: + raise ValueError("Endpoint不正确, 请检查AZURE_ENDPOINT的配置! 当前的Endpoint为:" + endpoint) + return endpoint + +def predict_no_ui_long_connection(inputs:str, llm_kwargs:dict, history:list=[], sys_prompt:str="", observe_window:list=None, console_slience:bool=False): + """ + 发送,等待回复,一次性完成,不显示中间过程。但内部用stream的方法避免中途网线被掐。 + inputs: + 是本次问询的输入 + sys_prompt: + 系统静默prompt + llm_kwargs: + 内部调优参数 + history: + 是之前的对话列表 + observe_window = None: + 用于负责跨越线程传递已经输出的部分,大部分时候仅仅为了fancy的视觉效果,留空即可。observe_window[0]:观测窗。observe_window[1]:看门狗 + """ + watch_dog_patience = 5 # 看门狗的耐心, 设置5秒即可 + headers, payload = generate_payload(inputs, llm_kwargs, history, system_prompt=sys_prompt, stream=True) + retry = 0 + while True: + try: + # make a POST request to the API endpoint, stream=False + from .bridge_all import model_info + endpoint = verify_endpoint(model_info[llm_kwargs['llm_model']]['endpoint']) + response = requests.post(endpoint, headers=headers, proxies=proxies, + json=payload, stream=True, timeout=TIMEOUT_SECONDS); break + except requests.exceptions.ReadTimeout as e: + retry += 1 + traceback.print_exc() + if retry > MAX_RETRY: raise TimeoutError + if MAX_RETRY!=0: print(f'请求超时,正在重试 ({retry}/{MAX_RETRY}) ……') + + stream_response = response.iter_lines() + result = '' + json_data = None + while True: + try: chunk = next(stream_response) + except StopIteration: + break + except requests.exceptions.ConnectionError: + chunk = next(stream_response) # 失败了,重试一次?再失败就没办法了。 + chunk_decoded, chunkjson, has_choices, choice_valid, has_content, has_role = decode_chunk(chunk) + if chunkjson['event_type'] == 'stream-start': continue + if chunkjson['event_type'] == 'text-generation': + result += chunkjson["text"] + if not console_slience: print(chunkjson["text"], end='') + if observe_window is not None: + # 观测窗,把已经获取的数据显示出去 + if len(observe_window) >= 1: + observe_window[0] += chunkjson["text"] + # 看门狗,如果超过期限没有喂狗,则终止 + if len(observe_window) >= 2: + if (time.time()-observe_window[1]) > watch_dog_patience: + raise RuntimeError("用户取消了程序。") + if chunkjson['event_type'] == 'stream-end': break + return result + + +def predict(inputs:str, llm_kwargs:dict, plugin_kwargs:dict, chatbot:ChatBotWithCookies, + history:list=[], system_prompt:str='', stream:bool=True, additional_fn:str=None): + """ + 发送至chatGPT,流式获取输出。 + 用于基础的对话功能。 + inputs 是本次问询的输入 + top_p, temperature是chatGPT的内部调优参数 + history 是之前的对话列表(注意无论是inputs还是history,内容太长了都会触发token数量溢出的错误) + chatbot 为WebUI中显示的对话列表,修改它,然后yeild出去,可以直接修改对话界面内容 + additional_fn代表点击的哪个按钮,按钮见functional.py + """ + # if is_any_api_key(inputs): + # chatbot._cookies['api_key'] = inputs + # chatbot.append(("输入已识别为Cohere的api_key", what_keys(inputs))) + # yield from update_ui(chatbot=chatbot, history=history, msg="api_key已导入") # 刷新界面 + # return + # elif not is_any_api_key(chatbot._cookies['api_key']): + # chatbot.append((inputs, "缺少api_key。\n\n1. 临时解决方案:直接在输入区键入api_key,然后回车提交。\n\n2. 长效解决方案:在config.py中配置。")) + # yield from update_ui(chatbot=chatbot, history=history, msg="缺少api_key") # 刷新界面 + # return + + user_input = inputs + if additional_fn is not None: + from core_functional import handle_core_functionality + inputs, history = handle_core_functionality(additional_fn, inputs, history, chatbot) + + raw_input = inputs + # logging.info(f'[raw_input] {raw_input}') + chatbot.append((inputs, "")) + yield from update_ui(chatbot=chatbot, history=history, msg="等待响应") # 刷新界面 + + # check mis-behavior + if is_the_upload_folder(user_input): + chatbot[-1] = (inputs, f"[Local Message] 检测到操作错误!当您上传文档之后,需点击“**函数插件区**”按钮进行处理,请勿点击“提交”按钮或者“基础功能区”按钮。") + yield from update_ui(chatbot=chatbot, history=history, msg="正常") # 刷新界面 + time.sleep(2) + + try: + headers, payload = generate_payload(inputs, llm_kwargs, history, system_prompt, stream) + except RuntimeError as e: + chatbot[-1] = (inputs, f"您提供的api-key不满足要求,不包含任何可用于{llm_kwargs['llm_model']}的api-key。您可能选择了错误的模型或请求源。") + yield from update_ui(chatbot=chatbot, history=history, msg="api-key不满足要求") # 刷新界面 + return + + # 检查endpoint是否合法 + try: + from .bridge_all import model_info + endpoint = verify_endpoint(model_info[llm_kwargs['llm_model']]['endpoint']) + except: + tb_str = '```\n' + trimmed_format_exc() + '```' + chatbot[-1] = (inputs, tb_str) + yield from update_ui(chatbot=chatbot, history=history, msg="Endpoint不满足要求") # 刷新界面 + return + + history.append(inputs); history.append("") + + retry = 0 + while True: + try: + # make a POST request to the API endpoint, stream=True + response = requests.post(endpoint, headers=headers, proxies=proxies, + json=payload, stream=True, timeout=TIMEOUT_SECONDS);break + except: + retry += 1 + chatbot[-1] = ((chatbot[-1][0], timeout_bot_msg)) + retry_msg = f",正在重试 ({retry}/{MAX_RETRY}) ……" if MAX_RETRY > 0 else "" + yield from update_ui(chatbot=chatbot, history=history, msg="请求超时"+retry_msg) # 刷新界面 + if retry > MAX_RETRY: raise TimeoutError + + gpt_replying_buffer = "" + + is_head_of_the_stream = True + if stream: + stream_response = response.iter_lines() + while True: + try: + chunk = next(stream_response) + except StopIteration: + # 非Cohere官方接口的出现这样的报错,Cohere和API2D不会走这里 + chunk_decoded = chunk.decode() + error_msg = chunk_decoded + # 其他情况,直接返回报错 + chatbot, history = handle_error(inputs, llm_kwargs, chatbot, history, chunk_decoded, error_msg) + yield from update_ui(chatbot=chatbot, history=history, msg="非Cohere官方接口返回了错误:" + chunk.decode()) # 刷新界面 + return + + # 提前读取一些信息 (用于判断异常) + chunk_decoded, chunkjson, has_choices, choice_valid, has_content, has_role = decode_chunk(chunk) + + if chunkjson: + try: + if chunkjson['event_type'] == 'stream-start': + continue + if chunkjson['event_type'] == 'text-generation': + gpt_replying_buffer = gpt_replying_buffer + chunkjson["text"] + history[-1] = gpt_replying_buffer + chatbot[-1] = (history[-2], history[-1]) + yield from update_ui(chatbot=chatbot, history=history, msg="正常") # 刷新界面 + if chunkjson['event_type'] == 'stream-end': + log_chat(llm_model=llm_kwargs["llm_model"], input_str=inputs, output_str=gpt_replying_buffer) + history[-1] = gpt_replying_buffer + chatbot[-1] = (history[-2], history[-1]) + yield from update_ui(chatbot=chatbot, history=history, msg="正常") # 刷新界面 + break + except Exception as e: + yield from update_ui(chatbot=chatbot, history=history, msg="Json解析不合常规") # 刷新界面 + chunk = get_full_error(chunk, stream_response) + chunk_decoded = chunk.decode() + error_msg = chunk_decoded + chatbot, history = handle_error(inputs, llm_kwargs, chatbot, history, chunk_decoded, error_msg) + yield from update_ui(chatbot=chatbot, history=history, msg="Json异常" + error_msg) # 刷新界面 + print(error_msg) + return + +def handle_error(inputs, llm_kwargs, chatbot, history, chunk_decoded, error_msg): + from .bridge_all import model_info + Cohere_website = ' 请登录Cohere查看详情 https://platform.Cohere.com/signup' + if "reduce the length" in error_msg: + if len(history) >= 2: history[-1] = ""; history[-2] = "" # 清除当前溢出的输入:history[-2] 是本次输入, history[-1] 是本次输出 + history = clip_history(inputs=inputs, history=history, tokenizer=model_info[llm_kwargs['llm_model']]['tokenizer'], + max_token_limit=(model_info[llm_kwargs['llm_model']]['max_token'])) # history至少释放二分之一 + chatbot[-1] = (chatbot[-1][0], "[Local Message] Reduce the length. 本次输入过长, 或历史数据过长. 历史缓存数据已部分释放, 您可以请再次尝试. (若再次失败则更可能是因为输入过长.)") + elif "does not exist" in error_msg: + chatbot[-1] = (chatbot[-1][0], f"[Local Message] Model {llm_kwargs['llm_model']} does not exist. 模型不存在, 或者您没有获得体验资格.") + elif "Incorrect API key" in error_msg: + chatbot[-1] = (chatbot[-1][0], "[Local Message] Incorrect API key. Cohere以提供了不正确的API_KEY为由, 拒绝服务. " + Cohere_website) + elif "exceeded your current quota" in error_msg: + chatbot[-1] = (chatbot[-1][0], "[Local Message] You exceeded your current quota. Cohere以账户额度不足为由, 拒绝服务." + Cohere_website) + elif "account is not active" in error_msg: + chatbot[-1] = (chatbot[-1][0], "[Local Message] Your account is not active. Cohere以账户失效为由, 拒绝服务." + Cohere_website) + elif "associated with a deactivated account" in error_msg: + chatbot[-1] = (chatbot[-1][0], "[Local Message] You are associated with a deactivated account. Cohere以账户失效为由, 拒绝服务." + Cohere_website) + elif "API key has been deactivated" in error_msg: + chatbot[-1] = (chatbot[-1][0], "[Local Message] API key has been deactivated. Cohere以账户失效为由, 拒绝服务." + Cohere_website) + elif "bad forward key" in error_msg: + chatbot[-1] = (chatbot[-1][0], "[Local Message] Bad forward key. API2D账户额度不足.") + elif "Not enough point" in error_msg: + chatbot[-1] = (chatbot[-1][0], "[Local Message] Not enough point. API2D账户点数不足.") + else: + from toolbox import regular_txt_to_markdown + tb_str = '```\n' + trimmed_format_exc() + '```' + chatbot[-1] = (chatbot[-1][0], f"[Local Message] 异常 \n\n{tb_str} \n\n{regular_txt_to_markdown(chunk_decoded)}") + return chatbot, history + +def generate_payload(inputs, llm_kwargs, history, system_prompt, stream): + """ + 整合所有信息,选择LLM模型,生成http请求,为发送请求做准备 + """ + # if not is_any_api_key(llm_kwargs['api_key']): + # raise AssertionError("你提供了错误的API_KEY。\n\n1. 临时解决方案:直接在输入区键入api_key,然后回车提交。\n\n2. 长效解决方案:在config.py中配置。") + + api_key = select_api_key(llm_kwargs['api_key'], llm_kwargs['llm_model']) + + headers = { + "Content-Type": "application/json", + "Authorization": f"Bearer {api_key}" + } + if API_ORG.startswith('org-'): headers.update({"Cohere-Organization": API_ORG}) + if llm_kwargs['llm_model'].startswith('azure-'): + headers.update({"api-key": api_key}) + if llm_kwargs['llm_model'] in AZURE_CFG_ARRAY.keys(): + azure_api_key_unshared = AZURE_CFG_ARRAY[llm_kwargs['llm_model']]["AZURE_API_KEY"] + headers.update({"api-key": azure_api_key_unshared}) + + conversation_cnt = len(history) // 2 + + messages = [{"role": "SYSTEM", "message": system_prompt}] + if conversation_cnt: + for index in range(0, 2*conversation_cnt, 2): + what_i_have_asked = {} + what_i_have_asked["role"] = "USER" + what_i_have_asked["message"] = history[index] + what_gpt_answer = {} + what_gpt_answer["role"] = "CHATBOT" + what_gpt_answer["message"] = history[index+1] + if what_i_have_asked["message"] != "": + if what_gpt_answer["message"] == "": continue + if what_gpt_answer["message"] == timeout_bot_msg: continue + messages.append(what_i_have_asked) + messages.append(what_gpt_answer) + else: + messages[-1]['message'] = what_gpt_answer['message'] + + model = llm_kwargs['llm_model'] + if model.startswith('cohere-'): model = model[len('cohere-'):] + payload = { + "model": model, + "message": inputs, + "chat_history": messages, + "temperature": llm_kwargs['temperature'], # 1.0, + "top_p": llm_kwargs['top_p'], # 1.0, + "n": 1, + "stream": stream, + "presence_penalty": 0, + "frequency_penalty": 0, + } + + return headers,payload + + diff --git a/request_llms/bridge_google_gemini.py b/request_llms/bridge_google_gemini.py index 5cf3be9f1..129f0683d 100644 --- a/request_llms/bridge_google_gemini.py +++ b/request_llms/bridge_google_gemini.py @@ -7,6 +7,7 @@ import os import time from request_llms.com_google import GoogleChatInit +from toolbox import ChatBotWithCookies from toolbox import get_conf, update_ui, update_ui_lastest_msg, have_any_recent_upload_image_files, trimmed_format_exc proxies, TIMEOUT_SECONDS, MAX_RETRY = get_conf('proxies', 'TIMEOUT_SECONDS', 'MAX_RETRY') @@ -44,7 +45,8 @@ def predict_no_ui_long_connection(inputs, llm_kwargs, history=[], sys_prompt="", return gpt_replying_buffer -def predict(inputs, llm_kwargs, plugin_kwargs, chatbot, history=[], system_prompt='', stream=True, additional_fn=None): +def predict(inputs:str, llm_kwargs:dict, plugin_kwargs:dict, chatbot:ChatBotWithCookies, + history:list=[], system_prompt:str='', stream:bool=True, additional_fn:str=None): # 检查API_KEY if get_conf("GEMINI_API_KEY") == "": yield from update_ui_lastest_msg(f"请配置 GEMINI_API_KEY。", chatbot=chatbot, history=history, delay=0) diff --git a/request_llms/bridge_jittorllms_llama.py b/request_llms/bridge_jittorllms_llama.py index 25dbb42aa..9587fc354 100644 --- a/request_llms/bridge_jittorllms_llama.py +++ b/request_llms/bridge_jittorllms_llama.py @@ -1,10 +1,10 @@ -from transformers import AutoModel, AutoTokenizer import time import threading import importlib from toolbox import update_ui, get_conf from multiprocessing import Process, Pipe +from transformers import AutoModel, AutoTokenizer load_message = "jittorllms尚未加载,加载需要一段时间。注意,请避免混用多种jittor模型,否则可能导致显存溢出而造成卡顿,取决于`config.py`的配置,jittorllms消耗大量的内存(CPU)或显存(GPU),也许会导致低配计算机卡死 ……" @@ -106,7 +106,8 @@ def stream_chat(self, **kwargs): global llama_glm_handle llama_glm_handle = None ################################################################################# -def predict_no_ui_long_connection(inputs, llm_kwargs, history=[], sys_prompt="", observe_window=[], console_slience=False): +def predict_no_ui_long_connection(inputs:str, llm_kwargs:dict, history:list=[], sys_prompt:str="", + observe_window:list=[], console_slience:bool=False): """ 多线程方法 函数的说明请见 request_llms/bridge_all.py diff --git a/request_llms/bridge_jittorllms_pangualpha.py b/request_llms/bridge_jittorllms_pangualpha.py index 2681157ae..325c87b49 100644 --- a/request_llms/bridge_jittorllms_pangualpha.py +++ b/request_llms/bridge_jittorllms_pangualpha.py @@ -1,10 +1,10 @@ -from transformers import AutoModel, AutoTokenizer import time import threading import importlib from toolbox import update_ui, get_conf from multiprocessing import Process, Pipe +from transformers import AutoModel, AutoTokenizer load_message = "jittorllms尚未加载,加载需要一段时间。注意,请避免混用多种jittor模型,否则可能导致显存溢出而造成卡顿,取决于`config.py`的配置,jittorllms消耗大量的内存(CPU)或显存(GPU),也许会导致低配计算机卡死 ……" @@ -106,7 +106,8 @@ def stream_chat(self, **kwargs): global pangu_glm_handle pangu_glm_handle = None ################################################################################# -def predict_no_ui_long_connection(inputs, llm_kwargs, history=[], sys_prompt="", observe_window=[], console_slience=False): +def predict_no_ui_long_connection(inputs:str, llm_kwargs:dict, history:list=[], sys_prompt:str="", + observe_window:list=[], console_slience:bool=False): """ 多线程方法 函数的说明请见 request_llms/bridge_all.py diff --git a/request_llms/bridge_jittorllms_rwkv.py b/request_llms/bridge_jittorllms_rwkv.py index 28893d4b6..11f64c021 100644 --- a/request_llms/bridge_jittorllms_rwkv.py +++ b/request_llms/bridge_jittorllms_rwkv.py @@ -106,7 +106,8 @@ def stream_chat(self, **kwargs): global rwkv_glm_handle rwkv_glm_handle = None ################################################################################# -def predict_no_ui_long_connection(inputs, llm_kwargs, history=[], sys_prompt="", observe_window=[], console_slience=False): +def predict_no_ui_long_connection(inputs:str, llm_kwargs:dict, history:list=[], sys_prompt:str="", + observe_window:list=[], console_slience:bool=False): """ 多线程方法 函数的说明请见 request_llms/bridge_all.py diff --git a/request_llms/bridge_moonshot.py b/request_llms/bridge_moonshot.py index 645326e19..1f73bd504 100644 --- a/request_llms/bridge_moonshot.py +++ b/request_llms/bridge_moonshot.py @@ -8,6 +8,7 @@ import logging from toolbox import get_conf, update_ui, log_chat +from toolbox import ChatBotWithCookies import requests @@ -146,7 +147,8 @@ def msg_handle_error(llm_kwargs, chunk_decoded): return error_msg -def predict(inputs, llm_kwargs, plugin_kwargs, chatbot, history=[], system_prompt='', stream=True, additional_fn=None): +def predict(inputs:str, llm_kwargs:dict, plugin_kwargs:dict, chatbot:ChatBotWithCookies, + history:list=[], system_prompt:str='', stream:bool=True, additional_fn:str=None): chatbot.append([inputs, ""]) if additional_fn is not None: diff --git a/request_llms/bridge_moss.py b/request_llms/bridge_moss.py index 967f7239b..a7e75d203 100644 --- a/request_llms/bridge_moss.py +++ b/request_llms/bridge_moss.py @@ -171,7 +171,8 @@ def stream_chat(self, **kwargs): # 主进程执行 global moss_handle moss_handle = None ################################################################################# -def predict_no_ui_long_connection(inputs, llm_kwargs, history=[], sys_prompt="", observe_window=[], console_slience=False): +def predict_no_ui_long_connection(inputs:str, llm_kwargs:dict, history:list=[], sys_prompt:str="", + observe_window:list=[], console_slience:bool=False): """ 多线程方法 函数的说明请见 request_llms/bridge_all.py diff --git a/request_llms/bridge_qianfan.py b/request_llms/bridge_qianfan.py index ab3235c9c..76cea3c24 100644 --- a/request_llms/bridge_qianfan.py +++ b/request_llms/bridge_qianfan.py @@ -117,7 +117,8 @@ def generate_from_baidu_qianfan(inputs, llm_kwargs, history, system_prompt): raise RuntimeError(dec['error_msg']) -def predict_no_ui_long_connection(inputs, llm_kwargs, history=[], sys_prompt="", observe_window=[], console_slience=False): +def predict_no_ui_long_connection(inputs:str, llm_kwargs:dict, history:list=[], sys_prompt:str="", + observe_window:list=[], console_slience:bool=False): """ ⭐多线程方法 函数的说明请见 request_llms/bridge_all.py diff --git a/request_llms/bridge_qwen.py b/request_llms/bridge_qwen.py index 808c2c75c..2b1eeed27 100644 --- a/request_llms/bridge_qwen.py +++ b/request_llms/bridge_qwen.py @@ -5,7 +5,8 @@ model_name = 'Qwen' -def predict_no_ui_long_connection(inputs, llm_kwargs, history=[], sys_prompt="", observe_window=[], console_slience=False): +def predict_no_ui_long_connection(inputs:str, llm_kwargs:dict, history:list=[], sys_prompt:str="", + observe_window:list=[], console_slience:bool=False): """ ⭐多线程方法 函数的说明请见 request_llms/bridge_all.py @@ -47,6 +48,8 @@ def predict(inputs, llm_kwargs, plugin_kwargs, chatbot, history=[], system_promp if additional_fn is not None: from core_functional import handle_core_functionality inputs, history = handle_core_functionality(additional_fn, inputs, history, chatbot) + chatbot[-1] = (inputs, "") + yield from update_ui(chatbot=chatbot, history=history) # 开始接收回复 from .com_qwenapi import QwenRequestInstance diff --git a/request_llms/bridge_skylark2.py b/request_llms/bridge_skylark2.py index 1a8edcbca..37d6cc185 100644 --- a/request_llms/bridge_skylark2.py +++ b/request_llms/bridge_skylark2.py @@ -9,7 +9,8 @@ def validate_key(): if YUNQUE_SECRET_KEY == '': return False return True -def predict_no_ui_long_connection(inputs, llm_kwargs, history=[], sys_prompt="", observe_window=[], console_slience=False): +def predict_no_ui_long_connection(inputs:str, llm_kwargs:dict, history:list=[], sys_prompt:str="", + observe_window:list=[], console_slience:bool=False): """ ⭐ 多线程方法 函数的说明请见 request_llms/bridge_all.py diff --git a/request_llms/bridge_spark.py b/request_llms/bridge_spark.py index 8449494c1..4fc43518e 100644 --- a/request_llms/bridge_spark.py +++ b/request_llms/bridge_spark.py @@ -13,7 +13,8 @@ def validate_key(): return False return True -def predict_no_ui_long_connection(inputs, llm_kwargs, history=[], sys_prompt="", observe_window=[], console_slience=False): +def predict_no_ui_long_connection(inputs:str, llm_kwargs:dict, history:list=[], sys_prompt:str="", + observe_window:list=[], console_slience:bool=False): """ ⭐多线程方法 函数的说明请见 request_llms/bridge_all.py diff --git a/request_llms/bridge_zhipu.py b/request_llms/bridge_zhipu.py index ecb3b7550..f1db2e205 100644 --- a/request_llms/bridge_zhipu.py +++ b/request_llms/bridge_zhipu.py @@ -1,7 +1,8 @@ import time import os -from toolbox import update_ui, get_conf, update_ui_lastest_msg +from toolbox import update_ui, get_conf, update_ui_lastest_msg, log_chat from toolbox import check_packages, report_exception, have_any_recent_upload_image_files +from toolbox import ChatBotWithCookies model_name = '智谱AI大模型' zhipuai_default_model = 'glm-4' @@ -16,7 +17,8 @@ def make_media_input(inputs, image_paths): inputs = inputs + f'

' return inputs -def predict_no_ui_long_connection(inputs, llm_kwargs, history=[], sys_prompt="", observe_window=[], console_slience=False): +def predict_no_ui_long_connection(inputs:str, llm_kwargs:dict, history:list=[], sys_prompt:str="", + observe_window:list=[], console_slience:bool=False): """ ⭐多线程方法 函数的说明请见 request_llms/bridge_all.py @@ -42,7 +44,8 @@ def predict_no_ui_long_connection(inputs, llm_kwargs, history=[], sys_prompt="", return response -def predict(inputs, llm_kwargs, plugin_kwargs, chatbot, history=[], system_prompt='', stream=True, additional_fn=None): +def predict(inputs:str, llm_kwargs:dict, plugin_kwargs:dict, chatbot:ChatBotWithCookies, + history:list=[], system_prompt:str='', stream:bool=True, additional_fn:str=None): """ ⭐单线程方法 函数的说明请见 request_llms/bridge_all.py @@ -90,4 +93,5 @@ def predict(inputs, llm_kwargs, plugin_kwargs, chatbot, history=[], system_promp chatbot[-1] = [inputs, response] yield from update_ui(chatbot=chatbot, history=history) history.extend([inputs, response]) + log_chat(llm_model=llm_kwargs["llm_model"], input_str=inputs, output_str=response) yield from update_ui(chatbot=chatbot, history=history) \ No newline at end of file diff --git a/request_llms/com_zhipuglm.py b/request_llms/com_zhipuglm.py index b7bed2f04..d0326cfde 100644 --- a/request_llms/com_zhipuglm.py +++ b/request_llms/com_zhipuglm.py @@ -55,6 +55,21 @@ def __conversation_history(self, history:list, llm_kwargs:dict): messages.append(what_gpt_answer) return messages + @staticmethod + def preprocess_param(param, default=0.95, min_val=0.01, max_val=0.99): + """预处理参数,保证其在允许范围内,并处理精度问题""" + try: + param = float(param) + except ValueError: + return default + + if param <= min_val: + return min_val + elif param >= max_val: + return max_val + else: + return round(param, 2) # 可挑选精度,目前是两位小数 + def __conversation_message_payload(self, inputs:str, llm_kwargs:dict, history:list, system_prompt:str): messages = [] if system_prompt: @@ -64,11 +79,39 @@ def __conversation_message_payload(self, inputs:str, llm_kwargs:dict, history:li if inputs.strip() == "": # 处理空输入导致报错的问题 https://github.com/binary-husky/gpt_academic/issues/1640 提示 {"error":{"code":"1214","message":"messages[1]:content和tool_calls 字段不能同时为空"} inputs = "." # 空格、换行、空字符串都会报错,所以用最没有意义的一个点代替 messages.append(self.__conversation_user(inputs, llm_kwargs)) # 处理用户对话 + """ + 采样温度,控制输出的随机性,必须为正数 + 取值范围是:(0.0, 1.0),不能等于 0,默认值为 0.95, + 值越大,会使输出更随机,更具创造性; + 值越小,输出会更加稳定或确定 + 建议您根据应用场景调整 top_p 或 temperature 参数,但不要同时调整两个参数 + """ + temperature = self.preprocess_param( + param=llm_kwargs.get('temperature', 0.95), + default=0.95, + min_val=0.01, + max_val=0.99 + ) + """ + 用温度取样的另一种方法,称为核取样 + 取值范围是:(0.0, 1.0) 开区间, + 不能等于 0 或 1,默认值为 0.7 + 模型考虑具有 top_p 概率质量 tokens 的结果 + 例如:0.1 意味着模型解码器只考虑从前 10% 的概率的候选集中取 tokens + 建议您根据应用场景调整 top_p 或 temperature 参数, + 但不要同时调整两个参数 + """ + top_p = self.preprocess_param( + param=llm_kwargs.get('top_p', 0.70), + default=0.70, + min_val=0.01, + max_val=0.99 + ) response = self.zhipu_bro.chat.completions.create( model=self.model, messages=messages, stream=True, - temperature=llm_kwargs.get('temperature', 0.95) * 0.95, # 只能传默认的 temperature 和 top_p - top_p=llm_kwargs.get('top_p', 0.7) * 0.7, - max_tokens=llm_kwargs.get('max_tokens', 1024 * 4), # 最大输出模型的一半 + temperature=temperature, + top_p=top_p, + max_tokens=llm_kwargs.get('max_tokens', 1024 * 4), ) return response diff --git a/request_llms/local_llm_class.py b/request_llms/local_llm_class.py index 47af9e357..75dd17d1a 100644 --- a/request_llms/local_llm_class.py +++ b/request_llms/local_llm_class.py @@ -1,6 +1,7 @@ import time import threading from toolbox import update_ui, Singleton +from toolbox import ChatBotWithCookies from multiprocessing import Process, Pipe from contextlib import redirect_stdout from request_llms.queued_pipe import create_queue_pipe @@ -214,7 +215,7 @@ def stream_chat(self, **kwargs): def get_local_llm_predict_fns(LLMSingletonClass, model_name, history_format='classic'): load_message = f"{model_name}尚未加载,加载需要一段时间。注意,取决于`config.py`的配置,{model_name}消耗大量的内存(CPU)或显存(GPU),也许会导致低配计算机卡死 ……" - def predict_no_ui_long_connection(inputs, llm_kwargs, history=[], sys_prompt="", observe_window=[], console_slience=False): + def predict_no_ui_long_connection(inputs:str, llm_kwargs:dict, history:list=[], sys_prompt:str="", observe_window:list=[], console_slience:bool=False): """ refer to request_llms/bridge_all.py """ @@ -260,7 +261,8 @@ def predict_no_ui_long_connection(inputs, llm_kwargs, history=[], sys_prompt="", raise RuntimeError("程序终止。") return response - def predict(inputs, llm_kwargs, plugin_kwargs, chatbot, history=[], system_prompt='', stream=True, additional_fn=None): + def predict(inputs:str, llm_kwargs:dict, plugin_kwargs:dict, chatbot:ChatBotWithCookies, + history:list=[], system_prompt:str='', stream:bool=True, additional_fn:str=None): """ refer to request_llms/bridge_all.py """ diff --git a/requirements.txt b/requirements.txt index 36090861e..bf83268a1 100644 --- a/requirements.txt +++ b/requirements.txt @@ -17,6 +17,7 @@ prompt_toolkit latex2mathml python-docx mdtex2html +dashscope pyautogen colorama Markdown @@ -25,4 +26,4 @@ pymupdf openai arxiv numpy -rich +rich \ No newline at end of file diff --git a/shared_utils/cookie_manager.py b/shared_utils/cookie_manager.py index 8b1378917..bdfdbd58c 100644 --- a/shared_utils/cookie_manager.py +++ b/shared_utils/cookie_manager.py @@ -1 +1,61 @@ +from typing import Callable +def load_web_cookie_cache__fn_builder(customize_btns, cookies, predefined_btns)->Callable: + def load_web_cookie_cache(persistent_cookie_, cookies_): + import gradio as gr + from themes.theme import load_dynamic_theme, to_cookie_str, from_cookie_str, assign_user_uuid + + ret = {} + for k in customize_btns: + ret.update({customize_btns[k]: gr.update(visible=False, value="")}) + + try: persistent_cookie_ = from_cookie_str(persistent_cookie_) # persistent cookie to dict + except: return ret + + customize_fn_overwrite_ = persistent_cookie_.get("custom_bnt", {}) + cookies_['customize_fn_overwrite'] = customize_fn_overwrite_ + ret.update({cookies: cookies_}) + + for k,v in persistent_cookie_["custom_bnt"].items(): + if v['Title'] == "": continue + if k in customize_btns: ret.update({customize_btns[k]: gr.update(visible=True, value=v['Title'])}) + else: ret.update({predefined_btns[k]: gr.update(visible=True, value=v['Title'])}) + return ret + return load_web_cookie_cache + + +def assign_btn__fn_builder(customize_btns, predefined_btns, cookies, web_cookie_cache)->Callable: + def assign_btn(persistent_cookie_, cookies_, basic_btn_dropdown_, basic_fn_title, basic_fn_prefix, basic_fn_suffix, clean_up=False): + import gradio as gr + from themes.theme import load_dynamic_theme, to_cookie_str, from_cookie_str, assign_user_uuid + ret = {} + # 读取之前的自定义按钮 + customize_fn_overwrite_ = cookies_['customize_fn_overwrite'] + # 更新新的自定义按钮 + customize_fn_overwrite_.update({ + basic_btn_dropdown_: + { + "Title":basic_fn_title, + "Prefix":basic_fn_prefix, + "Suffix":basic_fn_suffix, + } + } + ) + if clean_up: + customize_fn_overwrite_ = {} + cookies_.update(customize_fn_overwrite_) # 更新cookie + visible = (not clean_up) and (basic_fn_title != "") + if basic_btn_dropdown_ in customize_btns: + # 是自定义按钮,不是预定义按钮 + ret.update({customize_btns[basic_btn_dropdown_]: gr.update(visible=visible, value=basic_fn_title)}) + else: + # 是预定义按钮 + ret.update({predefined_btns[basic_btn_dropdown_]: gr.update(visible=visible, value=basic_fn_title)}) + ret.update({cookies: cookies_}) + try: persistent_cookie_ = from_cookie_str(persistent_cookie_) # persistent cookie to dict + except: persistent_cookie_ = {} + persistent_cookie_["custom_bnt"] = customize_fn_overwrite_ # dict update new value + persistent_cookie_ = to_cookie_str(persistent_cookie_) # persistent cookie to dict + ret.update({web_cookie_cache: persistent_cookie_}) # write persistent cookie + return ret + return assign_btn diff --git a/shared_utils/fastapi_server.py b/shared_utils/fastapi_server.py new file mode 100644 index 000000000..9d3334b9c --- /dev/null +++ b/shared_utils/fastapi_server.py @@ -0,0 +1,211 @@ +""" +Tests: + +- custom_path false / no user auth: + -- upload file(yes) + -- download file(yes) + -- websocket(yes) + -- block __pycache__ access(yes) + -- rel (yes) + -- abs (yes) + -- block user access(fail) http://localhost:45013/file=gpt_log/admin/chat_secrets.log + -- fix(commit f6bf05048c08f5cd84593f7fdc01e64dec1f584a)-> block successful + +- custom_path yes("/cc/gptac") / no user auth: + -- upload file(yes) + -- download file(yes) + -- websocket(yes) + -- block __pycache__ access(yes) + -- block user access(yes) + +- custom_path yes("/cc/gptac/") / no user auth: + -- upload file(yes) + -- download file(yes) + -- websocket(yes) + -- block user access(yes) + +- custom_path yes("/cc/gptac/") / + user auth: + -- upload file(yes) + -- download file(yes) + -- websocket(yes) + -- block user access(yes) + -- block user-wise access (yes) + +- custom_path no + user auth: + -- upload file(yes) + -- download file(yes) + -- websocket(yes) + -- block user access(yes) + -- block user-wise access (yes) + +queue cocurrent effectiveness + -- upload file(yes) + -- download file(yes) + -- websocket(yes) +""" + +import os, requests, threading, time +import uvicorn + +def _authorize_user(path_or_url, request, gradio_app): + from toolbox import get_conf, default_user_name + PATH_PRIVATE_UPLOAD, PATH_LOGGING = get_conf('PATH_PRIVATE_UPLOAD', 'PATH_LOGGING') + sensitive_path = None + path_or_url = os.path.relpath(path_or_url) + if path_or_url.startswith(PATH_LOGGING): + sensitive_path = PATH_LOGGING + if path_or_url.startswith(PATH_PRIVATE_UPLOAD): + sensitive_path = PATH_PRIVATE_UPLOAD + if sensitive_path: + token = request.cookies.get("access-token") or request.cookies.get("access-token-unsecure") + user = gradio_app.tokens.get(token) # get user + allowed_users = [user, 'autogen', default_user_name] # three user path that can be accessed + for user_allowed in allowed_users: + # exact match + if f"{os.sep}".join(path_or_url.split(os.sep)[:2]) == os.path.join(sensitive_path, user_allowed): + return True + return False # "越权访问!" + return True + + +class Server(uvicorn.Server): + # A server that runs in a separate thread + def install_signal_handlers(self): + pass + + def run_in_thread(self): + self.thread = threading.Thread(target=self.run, daemon=True) + self.thread.start() + while not self.started: + time.sleep(1e-3) + + def close(self): + self.should_exit = True + self.thread.join() + + +def start_app(app_block, CONCURRENT_COUNT, AUTHENTICATION, PORT, SSL_KEYFILE, SSL_CERTFILE): + import uvicorn + import fastapi + import gradio as gr + from fastapi import FastAPI + from gradio.routes import App + from toolbox import get_conf + CUSTOM_PATH, PATH_LOGGING = get_conf('CUSTOM_PATH', 'PATH_LOGGING') + + # --- --- configurate gradio app block --- --- + app_block:gr.Blocks + app_block.ssl_verify = False + app_block.auth_message = '请登录' + app_block.favicon_path = os.path.join(os.path.dirname(os.path.dirname(__file__)), "docs/logo.png") + app_block.auth = AUTHENTICATION if len(AUTHENTICATION) != 0 else None + app_block.blocked_paths = ["config.py", "__pycache__", "config_private.py", "docker-compose.yml", "Dockerfile", f"{PATH_LOGGING}/admin"] + app_block.dev_mode = False + app_block.config = app_block.get_config_file() + app_block.enable_queue = True + app_block.queue(concurrency_count=CONCURRENT_COUNT) + app_block.validate_queue_settings() + app_block.show_api = False + app_block.config = app_block.get_config_file() + max_threads = 40 + app_block.max_threads = max( + app_block._queue.max_thread_count if app_block.enable_queue else 0, max_threads + ) + app_block.is_colab = False + app_block.is_kaggle = False + app_block.is_sagemaker = False + + gradio_app = App.create_app(app_block) + + # --- --- replace gradio endpoint to forbid access to sensitive files --- --- + if len(AUTHENTICATION) > 0: + dependencies = [] + endpoint = None + for route in list(gradio_app.router.routes): + if route.path == "/file/{path:path}": + gradio_app.router.routes.remove(route) + if route.path == "/file={path_or_url:path}": + dependencies = route.dependencies + endpoint = route.endpoint + gradio_app.router.routes.remove(route) + @gradio_app.get("/file/{path:path}", dependencies=dependencies) + @gradio_app.head("/file={path_or_url:path}", dependencies=dependencies) + @gradio_app.get("/file={path_or_url:path}", dependencies=dependencies) + async def file(path_or_url: str, request: fastapi.Request): + if len(AUTHENTICATION) > 0: + if not _authorize_user(path_or_url, request, gradio_app): + return "越权访问!" + return await endpoint(path_or_url, request) + + # --- --- app_lifespan --- --- + from contextlib import asynccontextmanager + @asynccontextmanager + async def app_lifespan(app): + async def startup_gradio_app(): + if gradio_app.get_blocks().enable_queue: + gradio_app.get_blocks().startup_events() + async def shutdown_gradio_app(): + pass + await startup_gradio_app() # startup logic here + yield # The application will serve requests after this point + await shutdown_gradio_app() # cleanup/shutdown logic here + + # --- --- FastAPI --- --- + fastapi_app = FastAPI(lifespan=app_lifespan) + fastapi_app.mount(CUSTOM_PATH, gradio_app) + + # --- --- favicon --- --- + if CUSTOM_PATH != '/': + from fastapi.responses import FileResponse + @fastapi_app.get("/favicon.ico") + async def favicon(): + return FileResponse(app_block.favicon_path) + + # --- --- uvicorn.Config --- --- + ssl_keyfile = None if SSL_KEYFILE == "" else SSL_KEYFILE + ssl_certfile = None if SSL_CERTFILE == "" else SSL_CERTFILE + server_name = "0.0.0.0" + config = uvicorn.Config( + fastapi_app, + host=server_name, + port=PORT, + reload=False, + log_level="warning", + ssl_keyfile=ssl_keyfile, + ssl_certfile=ssl_certfile, + ) + server = Server(config) + url_host_name = "localhost" if server_name == "0.0.0.0" else server_name + if ssl_keyfile is not None: + if ssl_certfile is None: + raise ValueError( + "ssl_certfile must be provided if ssl_keyfile is provided." + ) + path_to_local_server = f"https://{url_host_name}:{PORT}/" + else: + path_to_local_server = f"http://{url_host_name}:{PORT}/" + if CUSTOM_PATH != '/': + path_to_local_server += CUSTOM_PATH.lstrip('/').rstrip('/') + '/' + # --- --- begin --- --- + server.run_in_thread() + + # --- --- after server launch --- --- + app_block.server = server + app_block.server_name = server_name + app_block.local_url = path_to_local_server + app_block.protocol = ( + "https" + if app_block.local_url.startswith("https") or app_block.is_colab + else "http" + ) + + if app_block.enable_queue: + app_block._queue.set_url(path_to_local_server) + + forbid_proxies = { + "http": "", + "https": "", + } + requests.get(f"{app_block.local_url}startup-events", verify=app_block.ssl_verify, proxies=forbid_proxies) + app_block.is_running = True + app_block.block_thread() diff --git a/shared_utils/key_pattern_manager.py b/shared_utils/key_pattern_manager.py index f8400e971..8d925115a 100644 --- a/shared_utils/key_pattern_manager.py +++ b/shared_utils/key_pattern_manager.py @@ -28,6 +28,11 @@ def is_api2d_key(key): return bool(API_MATCH_API2D) +def is_cohere_api_key(key): + API_MATCH_AZURE = re.match(r"[a-zA-Z0-9]{40}$", key) + return bool(API_MATCH_AZURE) + + def is_any_api_key(key): if ',' in key: keys = key.split(',') @@ -35,7 +40,7 @@ def is_any_api_key(key): if is_any_api_key(k): return True return False else: - return is_openai_api_key(key) or is_api2d_key(key) or is_azure_api_key(key) + return is_openai_api_key(key) or is_api2d_key(key) or is_azure_api_key(key) or is_cohere_api_key(key) def what_keys(keys): @@ -76,8 +81,12 @@ def select_api_key(keys, llm_model): for k in key_list: if is_azure_api_key(k): avail_key_list.append(k) + if llm_model.startswith('cohere-'): + for k in key_list: + if is_cohere_api_key(k): avail_key_list.append(k) + if len(avail_key_list) == 0: - raise RuntimeError(f"您提供的api-key不满足要求,不包含任何可用于{llm_model}的api-key。您可能选择了错误的模型或请求源(右下角更换模型菜单中可切换openai,azure,claude,api2d等请求源)。") + raise RuntimeError(f"您提供的api-key不满足要求,不包含任何可用于{llm_model}的api-key。您可能选择了错误的模型或请求源(左上角更换模型菜单中可切换openai,azure,claude,cohere等请求源)。") api_key = random.choice(avail_key_list) # 随机负载均衡 return api_key diff --git a/tests/test_llms.py b/tests/test_llms.py index 2307848f9..e4b06c1a0 100644 --- a/tests/test_llms.py +++ b/tests/test_llms.py @@ -11,28 +11,45 @@ def validate_path(): validate_path() # validate path so you can run from base directory -if __name__ == "__main__": - # from request_llms.bridge_newbingfree import predict_no_ui_long_connection - # from request_llms.bridge_moss import predict_no_ui_long_connection - # from request_llms.bridge_jittorllms_pangualpha import predict_no_ui_long_connection - # from request_llms.bridge_jittorllms_llama import predict_no_ui_long_connection - # from request_llms.bridge_claude import predict_no_ui_long_connection - # from request_llms.bridge_internlm import predict_no_ui_long_connection - # from request_llms.bridge_deepseekcoder import predict_no_ui_long_connection - # from request_llms.bridge_qwen_7B import predict_no_ui_long_connection - from request_llms.bridge_qwen_local import predict_no_ui_long_connection - - # from request_llms.bridge_spark import predict_no_ui_long_connection - # from request_llms.bridge_zhipu import predict_no_ui_long_connection - # from request_llms.bridge_chatglm3 import predict_no_ui_long_connection - - llm_kwargs = { - "max_length": 4096, - "top_p": 1, - "temperature": 1, - } - - result = predict_no_ui_long_connection( - inputs="请问什么是质子?", llm_kwargs=llm_kwargs, history=["你好", "我好!"], sys_prompt="" - ) - print("final result:", result) + +if "在线模型": + if __name__ == "__main__": + from request_llms.bridge_cohere import predict_no_ui_long_connection + # from request_llms.bridge_spark import predict_no_ui_long_connection + # from request_llms.bridge_zhipu import predict_no_ui_long_connection + # from request_llms.bridge_chatglm3 import predict_no_ui_long_connection + llm_kwargs = { + "llm_model": "command-r-plus", + "max_length": 4096, + "top_p": 1, + "temperature": 1, + } + + result = predict_no_ui_long_connection( + inputs="请问什么是质子?", llm_kwargs=llm_kwargs, history=["你好", "我好!"], sys_prompt="系统" + ) + print("final result:", result) + print("final result:", result) + + +if "本地模型": + if __name__ == "__main__": + # from request_llms.bridge_newbingfree import predict_no_ui_long_connection + # from request_llms.bridge_moss import predict_no_ui_long_connection + # from request_llms.bridge_jittorllms_pangualpha import predict_no_ui_long_connection + # from request_llms.bridge_jittorllms_llama import predict_no_ui_long_connection + # from request_llms.bridge_claude import predict_no_ui_long_connection + # from request_llms.bridge_internlm import predict_no_ui_long_connection + # from request_llms.bridge_deepseekcoder import predict_no_ui_long_connection + # from request_llms.bridge_qwen_7B import predict_no_ui_long_connection + # from request_llms.bridge_qwen_local import predict_no_ui_long_connection + llm_kwargs = { + "max_length": 4096, + "top_p": 1, + "temperature": 1, + } + result = predict_no_ui_long_connection( + inputs="请问什么是质子?", llm_kwargs=llm_kwargs, history=["你好", "我好!"], sys_prompt="" + ) + print("final result:", result) + diff --git a/themes/common.js b/themes/common.js index e3de453de..cccbcb947 100644 --- a/themes/common.js +++ b/themes/common.js @@ -2,15 +2,15 @@ // 第 1 部分: 工具函数 // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= -function push_data_to_gradio_component(DAT, ELEM_ID, TYPE){ +function push_data_to_gradio_component(DAT, ELEM_ID, TYPE) { // type, // type==="str" / type==="float" - if (TYPE=="str"){ + if (TYPE == "str") { // convert dat to string: do nothing } - else if (TYPE=="no_conversion"){ + else if (TYPE == "no_conversion") { // no nothing } - else if (TYPE=="float"){ + else if (TYPE == "float") { // convert dat to float DAT = parseFloat(DAT); } @@ -24,7 +24,7 @@ function push_data_to_gradio_component(DAT, ELEM_ID, TYPE){ } -async function get_gradio_component(ELEM_ID){ +async function get_gradio_component(ELEM_ID) { function waitFor(ELEM_ID) { return new Promise((resolve) => { const myEvent = new CustomEvent('gpt_academic_get_gradio_component_value', { @@ -41,14 +41,13 @@ async function get_gradio_component(ELEM_ID){ } -async function get_data_from_gradio_component(ELEM_ID){ +async function get_data_from_gradio_component(ELEM_ID) { let comp = await get_gradio_component(ELEM_ID); return comp.props.value; } -function update_array(arr, item, mode) { - // let p = ["基础功能区", "输入清除键", "函数插件区"]; +function update_array(arr, item, mode) { // // Remove "输入清除键" // p = updateArray(p, "输入清除键", "remove"); // console.log(p); // Should log: ["基础功能区", "函数插件区"] @@ -60,13 +59,13 @@ function update_array(arr, item, mode) { const index = arr.indexOf(item); if (mode === "remove") { if (index !== -1) { - // Item found, remove it - arr.splice(index, 1); + // Item found, remove it + arr.splice(index, 1); } } else if (mode === "add") { if (index === -1) { - // Item not found, add it - arr.push(item); + // Item not found, add it + arr.push(item); } } return arr; @@ -85,6 +84,7 @@ function gradioApp() { return elem.shadowRoot ? elem.shadowRoot : elem; } + function setCookie(name, value, days) { var expires = ""; @@ -97,6 +97,7 @@ function setCookie(name, value, days) { document.cookie = name + "=" + value + expires + "; path=/"; } + function getCookie(name) { var decodedCookie = decodeURIComponent(document.cookie); var cookies = decodedCookie.split(';'); @@ -112,6 +113,7 @@ function getCookie(name) { return null; } + let toastCount = 0; function toast_push(msg, duration) { duration = isNaN(duration) ? 3000 : duration; @@ -134,6 +136,7 @@ function toast_push(msg, duration) { toastCount++; } + function toast_up(msg) { var m = document.getElementById('toast_up'); if (m) { @@ -146,6 +149,7 @@ function toast_up(msg) { document.body.appendChild(m); } + function toast_down() { var m = document.getElementById('toast_up'); if (m) { @@ -153,6 +157,7 @@ function toast_down() { } } + function begin_loading_status() { // Create the loader div and add styling var loader = document.createElement('div'); @@ -327,6 +332,7 @@ function do_something_but_not_too_frequently(min_interval, func) { } } + function chatbotContentChanged(attempt = 1, force = false) { // https://github.com/GaiZhenbiao/ChuanhuChatGPT/tree/main/web_assets/javascript for (var i = 0; i < attempt; i++) { @@ -343,7 +349,6 @@ function chatbotContentChanged(attempt = 1, force = false) { // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= // 第 3 部分: chatbot动态高度调整 // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= - function chatbotAutoHeight() { // 自动调整高度:立即 function update_height() { @@ -375,6 +380,7 @@ function chatbotAutoHeight() { setInterval(function () { update_height_slow() }, 50); // 每50毫秒执行一次 } + swapped = false; function swap_input_area() { // Get the elements to be swapped @@ -394,6 +400,7 @@ function swap_input_area() { else { swapped = true; } } + function get_elements(consider_state_panel = false) { var chatbot = document.querySelector('#gpt-chatbot > div.wrap.svelte-18telvq'); if (!chatbot) { @@ -491,6 +498,7 @@ async function upload_files(files) { } } + function register_func_paste(input) { let paste_files = []; if (input) { @@ -517,6 +525,7 @@ function register_func_paste(input) { } } + function register_func_drag(elem) { if (elem) { const dragEvents = ["dragover"]; @@ -553,6 +562,7 @@ function register_func_drag(elem) { } } + function elem_upload_component_pop_message(elem) { if (elem) { const dragEvents = ["dragover"]; @@ -582,6 +592,7 @@ function elem_upload_component_pop_message(elem) { } } + function register_upload_event() { locate_upload_elems(); if (elem_upload_float) { @@ -604,6 +615,7 @@ function register_upload_event() { } } + function monitoring_input_box() { register_upload_event(); @@ -637,7 +649,6 @@ window.addEventListener("DOMContentLoaded", function () { // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= // 第 5 部分: 音频按钮样式变化 // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= - function audio_fn_init() { let audio_component = document.getElementById('elem_audio'); if (audio_component) { @@ -674,6 +685,7 @@ function audio_fn_init() { } } + function minor_ui_adjustment() { let cbsc_area = document.getElementById('cbsc'); cbsc_area.style.paddingTop = '15px'; @@ -766,21 +778,6 @@ function limit_scroll_position() { // 第 7 部分: JS初始化函数 // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= -function GptAcademicJavaScriptInit(LAYOUT = "LEFT-RIGHT") { - audio_fn_init(); - minor_ui_adjustment(); - chatbotIndicator = gradioApp().querySelector('#gpt-chatbot > div.wrap'); - var chatbotObserver = new MutationObserver(() => { - chatbotContentChanged(1); - }); - chatbotObserver.observe(chatbotIndicator, { attributes: true, childList: true, subtree: true }); - if (LAYOUT === "LEFT-RIGHT") { chatbotAutoHeight(); } - if (LAYOUT === "LEFT-RIGHT") { limit_scroll_position(); } - // setInterval(function () { uml("mermaid") }, 5000); // 每50毫秒执行一次 - -} - - function loadLive2D() { try { $("").attr({ href: "file=themes/waifu_plugin/waifu.css", rel: "stylesheet", type: "text/css" }).appendTo('head'); @@ -802,12 +799,12 @@ function loadLive2D() { live2d_settings['canTakeScreenshot'] = false; live2d_settings['canTurnToHomePage'] = false; live2d_settings['canTurnToAboutPage'] = false; - live2d_settings['showHitokoto'] = false; // 显示一言 + live2d_settings['showHitokoto'] = false; // 显示一言 live2d_settings['showF12Status'] = false; // 显示加载状态 live2d_settings['showF12Message'] = false; // 显示看板娘消息 - live2d_settings['showF12OpenMsg'] = false; // 显示控制台打开提示 - live2d_settings['showCopyMessage'] = false; // 显示 复制内容 提示 - live2d_settings['showWelcomeMessage'] = true; // 显示进入面页欢迎词 + live2d_settings['showF12OpenMsg'] = false; // 显示控制台打开提示 + live2d_settings['showCopyMessage'] = false; // 显示 复制内容 提示 + live2d_settings['showWelcomeMessage'] = true; // 显示进入面页欢迎词 /* 在 initModel 前添加 */ initModel("file=themes/waifu_plugin/waifu-tips.json"); } @@ -817,7 +814,8 @@ function loadLive2D() { } catch (err) { console.log("[Error] JQuery is not defined.") } } -function get_checkbox_selected_items(elem_id){ + +function get_checkbox_selected_items(elem_id) { display_panel_arr = []; document.getElementById(elem_id).querySelector('[data-testid="checkbox-group"]').querySelectorAll('label').forEach(label => { // Get the span text @@ -831,62 +829,24 @@ function get_checkbox_selected_items(elem_id){ return display_panel_arr; } -function set_checkbox(key, bool, set_twice=false) { - set_success = false; - elem_ids = ["cbsc", "cbs"] - elem_ids.forEach(id => { - document.getElementById(id).querySelector('[data-testid="checkbox-group"]').querySelectorAll('label').forEach(label => { - // Get the span text - const spanText = label.querySelector('span').textContent; - if (spanText === key) { - if (bool){ - label.classList.add('selected'); - } else { - if (label.classList.contains('selected')) { - label.classList.remove('selected'); - } - } - if (set_twice){ - setTimeout(() => { - if (bool){ - label.classList.add('selected'); - } else { - if (label.classList.contains('selected')) { - label.classList.remove('selected'); - } - } - }, 5000); - } - - label.querySelector('input').checked = bool; - set_success = true; - return - } - }); - }); - - if (!set_success){ - console.log("设置checkbox失败,没有找到对应的key") - } -} function gpt_academic_gradio_saveload( - save_or_load, // save_or_load==="save" / save_or_load==="load" - elem_id, // element id - cookie_key, // cookie key - save_value="", // save value - load_type = "str", // type==="str" / type==="float" - load_default=false, // load default value - load_default_value="" - ) { + save_or_load, // save_or_load==="save" / save_or_load==="load" + elem_id, // element id + cookie_key, // cookie key + save_value = "", // save value + load_type = "str", // type==="str" / type==="float" + load_default = false, // load default value + load_default_value = "" +) { if (save_or_load === "load") { let value = getCookie(cookie_key); if (value) { console.log('加载cookie', elem_id, value) push_data_to_gradio_component(value, elem_id, load_type); } - else{ - if (load_default){ + else { + if (load_default) { console.log('加载cookie的默认值', elem_id, load_default_value) push_data_to_gradio_component(load_default_value, elem_id, load_type); } @@ -897,11 +857,24 @@ function gpt_academic_gradio_saveload( } } -async function init_frontend_with_cookies(dark, prompt, live2d) { - let searchString = "输入清除键"; - let bool_value = "False"; - ////////////////// darkmode /////////////////// +async function GptAcademicJavaScriptInit(dark, prompt, live2d, layout) { + // 第一部分,布局初始化 + audio_fn_init(); + minor_ui_adjustment(); + chatbotIndicator = gradioApp().querySelector('#gpt-chatbot > div.wrap'); + var chatbotObserver = new MutationObserver(() => { + chatbotContentChanged(1); + }); + chatbotObserver.observe(chatbotIndicator, { attributes: true, childList: true, subtree: true }); + if (layout === "LEFT-RIGHT") { chatbotAutoHeight(); } + if (layout === "LEFT-RIGHT") { limit_scroll_position(); } + + // 第二部分,读取Cookie,初始话界面 + let searchString = ""; + let bool_value = ""; + + // darkmode 深色模式 if (getCookie("js_darkmode_cookie")) { dark = getCookie("js_darkmode_cookie") } @@ -916,12 +889,13 @@ async function init_frontend_with_cookies(dark, prompt, live2d) { } } - ////////////////////// SysPrompt /////////////////////////// + // SysPrompt 系统静默提示词 gpt_academic_gradio_saveload("load", "elem_prompt", "js_system_prompt_cookie", null, "str"); - ////////////////////// Temperature /////////////////////////// + + // Temperature 大模型温度参数 gpt_academic_gradio_saveload("load", "elem_temperature", "js_temperature_cookie", null, "float"); - ////////////////////// clearButton /////////////////////////// + // clearButton 自动清除按钮 if (getCookie("js_clearbtn_show_cookie")) { // have cookie bool_value = getCookie("js_clearbtn_show_cookie") @@ -949,7 +923,7 @@ async function init_frontend_with_cookies(dark, prompt, live2d) { } } - ////////////////////// live2d /////////////////////////// + // live2d 显示 if (getCookie("js_live2d_show_cookie")) { // have cookie searchString = "添加Live2D形象"; diff --git a/themes/theme.py b/themes/theme.py index c3476f9df..6ccf36b45 100644 --- a/themes/theme.py +++ b/themes/theme.py @@ -48,7 +48,7 @@ def load_dynamic_theme(THEME): cookie相关工具函数 -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- """ -def init_cookie(cookies): +def assign_user_uuid(cookies): # 为每一位访问的用户赋予一个独一无二的uuid编码 cookies.update({"uuid": uuid.uuid4()}) return cookies @@ -106,8 +106,8 @@ def from_cookie_str(c): }""" -js_code_for_persistent_cookie_init = """(py_pickle_cookie, cookie) => { - return [getCookie("py_pickle_cookie"), cookie]; +js_code_for_persistent_cookie_init = """(web_cookie_cache, cookie) => { + return [getCookie("web_cookie_cache"), cookie]; } """ diff --git a/toolbox.py b/toolbox.py index 127821659..b25984dee 100644 --- a/toolbox.py +++ b/toolbox.py @@ -535,17 +535,13 @@ def on_file_uploaded( def on_report_generated(cookies:dict, files:List[str], chatbot:ChatBotWithCookies): - # from toolbox import find_recent_files - # PATH_LOGGING = get_conf('PATH_LOGGING') if "files_to_promote" in cookies: report_files = cookies["files_to_promote"] cookies.pop("files_to_promote") else: report_files = [] - # report_files = find_recent_files(PATH_LOGGING) if len(report_files) == 0: return cookies, None, chatbot - # files.extend(report_files) file_links = "" for f in report_files: file_links += ( @@ -1009,10 +1005,13 @@ def check_repeat_upload(new_pdf_path, pdf_hash): return False, None def log_chat(llm_model: str, input_str: str, output_str: str): - if output_str and input_str and llm_model: - uid = str(uuid.uuid4().hex) - logging.info(f"[Model({uid})] {llm_model}") - input_str = input_str.rstrip('\n') - logging.info(f"[Query({uid})]\n{input_str}") - output_str = output_str.rstrip('\n') - logging.info(f"[Response({uid})]\n{output_str}\n\n") + try: + if output_str and input_str and llm_model: + uid = str(uuid.uuid4().hex) + logging.info(f"[Model({uid})] {llm_model}") + input_str = input_str.rstrip('\n') + logging.info(f"[Query({uid})]\n{input_str}") + output_str = output_str.rstrip('\n') + logging.info(f"[Response({uid})]\n{output_str}\n\n") + except: + print(trimmed_format_exc()) diff --git a/version b/version index ed934e2eb..5d450de57 100644 --- a/version +++ b/version @@ -1,5 +1,5 @@ { - "version": 3.73, + "version": 3.74, "show_feature": true, - "new_feature": "优化oneapi接入方法 <-> 接入月之暗面模型 <-> 支持切换多个智谱ai模型 <-> 用绘图功能增强部分插件 <-> 基础功能区支持自动切换中英提示词 <-> 支持Mermaid绘图库(让大模型绘制脑图)" + "new_feature": "增加多用户文件鉴权验证提高安全性 <-> 优化oneapi接入方法 <-> 接入Cohere和月之暗面模型 <-> 简化挂载二级目录的步骤 <-> 支持Mermaid绘图库(让大模型绘制脑图)" }