[
  {
    "path": ".github/ISSUE_TEMPLATE/issue模板.md",
    "content": "---\nname: issue模板\nabout: 任何问题请使用这个模板创建\ntitle: \"\"\nlabels: ''\nassignees: ''\n\n---\n\n请您认真填写以下信息。\n\n### 任务\n\n- [ ] 我已严格按照文档中的步骤操作\n- [ ] 我已经搜索了相关的issue\n\n### 预期/正在使用的逆向库\n\n我要使用的逆向库是：（例如：New Bing）\n\n### 期望情况\n\n我希望的情况是：\n\n### 实际情况\n\n实际情况是：\n"
  },
  {
    "path": ".github/dependabot.yml",
    "content": "# To get started with Dependabot version updates, you'll need to specify which\n# package ecosystems to update and where the package manifests are located.\n# Please see the documentation for all configuration options:\n# https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates\n\nversion: 2\nupdates:\n  - package-ecosystem: \"pip\" # See documentation for possible values\n    directory: \"/\" # Location of package manifests\n    schedule:\n      interval: \"daily\"\n    allow:\n      - dependency-name: \"revChatGPT\"\n      - dependency-name: \"EdgeGPT\"\n"
  },
  {
    "path": ".gitignore",
    "content": "__pycache__/"
  },
  {
    "path": "README.md",
    "content": "# RevLib Support for QChatGPT\n\n> 2023/8/29 现已支持`gpt4free`，请查看下方的使用方法  \n> 2023/8/14 现已支持`Claude`和`Bard`，请查看下方的使用方法  \n> 2023/8/03 逆向库现已支持`函数调用`, 配置方法同[主程序配置方法](https://github.com/RockChinQ/QChatGPT/wiki/%E6%8F%92%E4%BB%B6%E4%BD%BF%E7%94%A8-%E5%86%85%E5%AE%B9%E5%87%BD%E6%95%B0)  \n\n\n得益于[QChatGPT项目](https://github.com/RockChinQ/QChatGPT)的插件功能，此插件将允许接入`ChatGPT网页版`用以替换原项目主线的GPT-3模型接口，提升回复质量。  \n[官方接口与ChatGPT网页版的区别？](https://github.com/RockChinQ/QChatGPT/wiki/%E5%AE%98%E6%96%B9%E6%8E%A5%E5%8F%A3%E4%B8%8EChatGPT%E7%BD%91%E9%A1%B5%E7%89%88)\n\n## 安装方式\n\n> 若您未安装QChatGPT程序，请先查看原仓库[文档](https://github.com/RockChinQ/QChatGPT)  \n\n使用管理员账号私聊机器人发送指令:\n\n```\n!plugin https://github.com/RockChinQ/revLibs\n```\n\n若无法访问GitHub，可以使用Gitee镜像\n\n```\n!plugin https://gitee.com/RockChin/revLibs\n```\n\n等待程序获取源码，并解决依赖，这可能需要数分钟的时间。  \n安装完毕后，请发送:\n```\n!reload\n```\n重载插件，生成配置文件，**关闭主程序**。  \n到`QChatGPT`程序目录编辑`revcfg.py`文件，根据注释修改必填配置项。  \n配置完成后重新启动主程序以使用。\n\n## Cookies获取方法\n\n大部分逆向库基于Cookies登录，因此需要获取Cookies。这里讲解了获取一个网站的Cookies的详细步骤，您可以先查看下方选择逆向库的步骤，到需要的网站使用以下方式获取Cookies。\n\n1. 安装适用于[Chrome/Edge](https://chrome.google.com/webstore/detail/cookie-editor/hlkenndednhfkekhgcdicdfddnkalmdm) 或 [Firefox](https://addons.mozilla.org/en-US/firefox/addon/cookie-editor/) 的Cookies编辑器插件\n2. 访问 目标网站\n3. 打开这个插件\n4. 点击 `Export` 按钮, 复制JSON格式的Cookies\n5. 将`Cookies`保存到指定的文件中\n\n## 选择逆向库\n\n目前支持的逆向库及使用方式如下, 下方所述文件保存位置均为主程序`config.py`同目录，若无此文件，请自行创建：\n\n<details>\n<summary>ChatGPT网页版</summary>\n\n本插件默认使用的逆向库，使用方法请参考配置文件注释。\n使用的是 [acheong08/ChatGPT](https://github.com/acheong08/ChatGPT)  \n\n> **WARNING**  \n> 必须配置反向代理才能使用，默认的是作者自建的，不一定能用，建议自己搭建。  \n> 可以参考：[另外一个项目的文档，仅参考 ChatGPT 反向代理搭建方式](https://free-one-api.rockchin.top/#/zh-CN/Adapters?id=%e5%8f%8d%e5%90%91%e4%bb%a3%e7%90%86)\n\n</details>\n\n<details>\n<summary>New Bing(暂不可用)</summary>\n\n使用的是 [acheong08/EdgeGPT](https://github.com/acheong08/EdgeGPT)  \n\n - 修改`revcfg.py`中的`reverse_lib`的值为`acheong08/EdgeGPT`\n - 获取[NewBing](https://bing.com/chat)的Cookies，保存到`cookies.json`中\n\n#### 配置\n\n- new bing逆向库默认输出参考资料, 若不需要, 请在`revcfg.py`中设置:\n\n```python\noutput_references = False\n```\n\n- 设置New Bing的风格\n\n查看revcfg.py中的`new_bing_style`字段，按照说明更改。在运行期间可以通过指令`!style <风格（创意、平衡、精确）>`来更改风格。\n\n</details>\n\n<details>\n<summary>HuggingChat</summary>\n\n1. 在`revcfg.py`中修改`reverse_lib`的值为`Soulter/hugging-chat-api`\n2. 获取[HuggingChat](https://huggingface.co/chat/)的Cookies，保存到`hugchat.json`中\n\n</details>\n\n<details>\n<summary>Claude</summary>\n\n1. 在`revcfg.py`中修改`reverse_lib`的值为`KoushikNavuluri/Claude-API`\n2. 获取[Claude](https://claude.ai/chats)的Cookies，保存到`claude.json`中\n\n</details>\n\n<details>\n\n<summary>Google Bard</summary>\n\n1. 在`revcfg.py`中修改`reverse_lib`的值为`dsdanielpark/Bard-API`\n2. 获取[Bard](https://bard.google.com/)的Cookies，保存到`bard.json`中\n\n</details>\n\n<details>\n<summary>gpt4free</summary>\n\n接入[xtekky/gpt4free](https://github.com/xtekky/gpt4free)自动从数个平台选择可用的 GPT-4，**无需鉴权**，但很不稳定，仅需要在`revcfg.py`中修改`reverse_lib`的值为`xtekky/gpt4free`即可。\n\n#### 配置\n\n- gpt4free 提供了多个渠道，默认情况下程序会自动测试并选择可用的渠道，可以在 `revcfg.py` 中指定要使用的渠道和要排除的渠道\n- 向机器人发送 `!provider ls` 来查看所有支持设置的渠道, 发送 `!provider` 查看当前使用的渠道\n\n</details>\n\n<br/>\n\n### 🚫请勿修改`revcfg-template.py`的内容，配置项请在主程序`config.py`同目录的`revcfg.py`中修改🚫\n\n## 特别感谢\n\n> 向所有致力于人工智能民主化的开发者致敬。  \n> Salute to all developers committed to the democratization of artificial intelligence.  \n> 인공지능 민주화에 힘쓴 모든 개발자들에게 경의를 표합니다.  \n> 人工知能の民主化に取り組むすべての開発者に敬意を表します。\n"
  },
  {
    "path": "__init__.py",
    "content": ""
  },
  {
    "path": "main.py",
    "content": "import traceback\n\nfrom pkg.plugin.models import *\nfrom pkg.plugin.host import EventContext, PluginHost, emit\n\nimport time\nimport os\n\nfrom revChatGPT.V1 import Chatbot\n\nimport plugins.revLibs.pkg.process.revss as revss\nimport plugins.revLibs.pkg.process.procmsg as procmsg\nimport plugins.revLibs.pkg.process.proccmd as proccmd\nfrom EdgeGPT.EdgeGPT import ConversationStyle\n\n\ndef check_config():\n    this_file = __file__\n\n    template_file = os.path.join(os.path.dirname(this_file), \"revcfg-template.py\")\n\n    # 检查revlib.py是否存在\n    if not os.path.exists(\"revcfg.py\"):\n        # 不存在则使用本模块同目录的revcfg-template.py复制创建\n        with open(template_file, \"r\", encoding=\"utf-8\") as f:\n            template = f.read()\n\n        with open(\"revcfg.py\", \"w\", encoding=\"utf-8\") as f:\n            f.write(template)\n\n        return False\n\n    return True\n\n\n# 注册插件\n@register(name=\"revLibs\", description=\"接入acheong08/ChatGPT、Claude、Bard等逆向库\", version=\"0.9.1\", author=\"RockChinQ\")\nclass RevLibsPlugin(Plugin):\n\n    chatbot: Chatbot = None\n\n    # 插件加载时触发\n    def __init__(self, plugin_host: PluginHost):\n        # 执行依赖库更新\n        # try:\n        #     import plugins.revLibs.pkg.utils as utils\n        #     # utils.upgrade_revlibs()\n        # except:\n        #     traceback.print_exc()\n        #     logging.warn(\"[rev] 依赖库更新失败，不能确保逆向库正常运行\")\n\n        if not check_config():\n            logging.error(\"[rev] 已生成配置文件(revcfg.py)，请按照其中注释填写配置文件后重启程序\")\n            # plugin_host.notify_admin(\"[rev] 已生成配置文件(revcfg.py)，请按照其中注释填写配置文件后重启程序\")\n            return\n\n        import revcfg\n\n        if not hasattr(revcfg, \"new_bing_style\"):\n            setattr(revcfg, \"new_bing_style\", ConversationStyle.balanced)\n\n        try:\n\n            from plugins.revLibs.pkg.process.impls import v1impl, edgegpt, hugchat, claude, bard, gpt4free\n\n            reverse_lib_mapping = {\n                \"acheong08/ChatGPT.V1\": v1impl.RevChatGPTV1,\n                \"acheong08/EdgeGPT\": edgegpt.EdgeGPTImpl,\n                \"Soulter/hugging-chat-api\": hugchat.HugChatImpl,\n                \"KoushikNavuluri/Claude-API\": claude.ClaudeImpl,\n                \"dsdanielpark/Bard-API\": bard.BardImpl,\n                \"xtekky/gpt4free\": gpt4free.GPT4FreeImpl,\n            }\n\n            import plugins.revLibs.pkg.process.revss as revss\n\n            if hasattr(revcfg, \"reverse_lib\") and revcfg.reverse_lib in reverse_lib_mapping:\n                revss.__rev_interface_impl_class__ = reverse_lib_mapping[revcfg.reverse_lib]\n                logging.info(\"[rev] 已加载逆向库{}, 使用接口实现类: {}\".format(revcfg.reverse_lib, str(reverse_lib_mapping[revcfg.reverse_lib])))\n            else:\n                logging.error(\"[rev] 未知的逆向库: \" + revcfg.reverse_lib + \", 请检查配置文件是否填写正确或尝试更新逆向库插件\")\n                time.sleep(5)\n                return\n        except:\n            # 输出完整的错误信息\n            # plugin_host.notify_admin(\"[rev] 逆向库初始化失败，请检查配置文件(revcfg.py)是否正确\")\n            logging.error(\"[rev] 逆向库初始化失败，请检查配置文件(revcfg.py)是否正确\")\n            logging.error(\"[rev] \" + traceback.format_exc())\n            return\n\n        import config\n\n        revcfg.process_message_timeout = config.process_message_timeout\n        config.process_message_timeout = 10*60\n        logging.info(\"[rev] 已将主程序消息处理超时时间设置为10分钟\")\n\n        @on(PersonNormalMessageReceived)\n        @on(GroupNormalMessageReceived)\n        def normal_message_received(inst, event: EventContext, **kwargs):\n            event.prevent_default()\n            event.prevent_postorder()\n\n            reply = []\n\n            try:\n\n                prefix = revcfg.reply_prefix\n                reply_message = \"\"\n                reply_message = procmsg.process_message(session_name=kwargs['launcher_type']+\"_\"+str(kwargs['launcher_id']),\n                                                        prompt=kwargs['text_message'], **kwargs)\n\n                logging.debug(\"[rev] \" + reply_message)\n\n                reply_message = reply_message\n\n                # 触发NormalMessageResponded事件\n                args = {\n                    \"launcher_type\": kwargs['launcher_type'],\n                    \"launcher_id\": kwargs['launcher_id'],\n                    \"sender_id\": kwargs['sender_id'],\n                    \"session\": None,\n                    \"prefix\": prefix,\n                    \"response_text\": reply_message,\n                    \"finish_reason\": \"revLibs.\"+revcfg.reverse_lib+\".finish\",\n                }\n\n                inter_event: EventContext = emit(NormalMessageResponded, **args)\n\n                reply = []\n\n                if inter_event.get_return_value(\"prefix\") is not None:\n                    prefix = inter_event.get_return_value(\"prefix\")\n                \n                if inter_event.get_return_value(\"reply\") is not None:\n                    reply = inter_event.get_return_value(\"reply\")\n                \n                if not inter_event.is_prevented_default():\n                    reply = [prefix + reply_message]\n\n            except Exception as e:\n                logging.error(\"[rev] \" + traceback.format_exc())\n                import config\n                if config.hide_exce_info_to_user:\n                    reply_message = ''\n                    try:\n                        import tips\n                        reply_message = tips.alter_tip_message\n                    except:\n                        if hasattr(config, \"alter_tip_message\"):\n                            reply_message = config.alter_tip_message\n                        else:\n                            reply_message = \"处理消息时出现错误，请联系管理员\"\n\n                    kwargs['host'].notify_admin(\"[rev] 处理消息时出现错误:\\n\"+traceback.format_exc())\n                else:\n                    reply_message = \"处理消息时出现错误，请联系管理员\"+\"\\n\"+traceback.format_exc()\n                \n                reply = [revcfg.reply_prefix+reply_message]\n\n            if reply_message != \"\":\n                event.add_return(\n                    \"reply\",\n                    reply,\n                )\n\n        @on(PersonCommandSent)\n        @on(GroupCommandSent)\n        def command_send(inst, event: EventContext, **kwargs):\n            reply_message = \"\"\n            try:\n                reply_message = proccmd.process_command(session_name=kwargs['launcher_type']+\"_\"+str(kwargs['launcher_id']),\n                                                        **kwargs)\n\n                logging.debug(\"[rev] \" + reply_message)\n            except Exception as e:\n                logging.error(\"[rev] \" + traceback.format_exc())\n                reply_message = \"处理命令时出现错误，请联系管理员\"+\"\\n\"+traceback.format_exc()\n            \n            if reply_message.strip() != \"\":\n                event.add_return(\n                    \"reply\",\n                    [\"{}(cmd)\".format(revcfg.reply_prefix)+reply_message],\n                )\n                event.prevent_default()\n                event.prevent_postorder()\n\n    def make_reply(self, prompt, **kwargs) -> dict:\n        reply_gen = self.chatbot.ask(prompt, **kwargs)\n        reply = {}\n\n        for r in reply_gen:\n            reply = r\n\n        return reply\n\n    # 插件卸载时触发\n    def __del__(self):\n        pass\n"
  },
  {
    "path": "pkg/__init__.py",
    "content": ""
  },
  {
    "path": "pkg/accounts/accmgr.py",
    "content": "import time\n\n\ndef get_account_list():\n    import revcfg\n    if type(revcfg.openai_account) is dict:\n        revcfg.openai_account = [revcfg.openai_account]\n    return revcfg.openai_account\n\n\ndef get_account_brief_name(account: dict):\n    if 'email' in account:\n        return account['email']\n    elif 'session_token' in account:\n        return \"sessionToken: \"+account['session_token'][:8]\n    elif 'access_token' in account:\n        return \"accessToken: \"+account['access_token'][:8]\n    else:\n        return \"未知账户\"\n\n\ndef move_account_to_end(account: dict):\n    # 将账户移动到末尾\n    import revcfg\n\n    account_list = get_account_list()\n    account_list.remove(account)\n    account_list.append(account)\n    revcfg.openai_account = account_list\n\n\ndef delete_invalid_attr(account: dict):\n    temp_dict = dict(account)\n    if 'invalid_at' in temp_dict:\n        del temp_dict['invalid_at']\n    return temp_dict\n\n\ndef use_account() -> tuple[bool, dict]:\n    # 计算并返回下一个账户\n    import revcfg\n\n    account_resume_interval = revcfg.openai_account_resume_interval if hasattr(revcfg, 'openai_account_resume_interval') else 60\n    \n    now = int(time.time())\n    for account in get_account_list():\n        if 'invalid_at' in account:\n            if account['invalid_at'] < now - account_resume_interval * 60:\n                move_account_to_end(account)\n                return True, delete_invalid_attr(account)\n\n        if 'invalid_at' not in account:\n            move_account_to_end(account)\n            return True, delete_invalid_attr(account)\n    \n    move_account_to_end(get_account_list()[0])\n    return False, delete_invalid_attr(get_account_list()[0])\n    \n\ndef report_invalidation(account: dict):\n    # 报告账户失效\n\n    for acc in get_account_list():\n        if 'email' in acc and 'email' in account and acc['email'] == account['email']:\n            acc['invalid_at'] = int(time.time())\n            return\n        elif 'session_token' in acc and 'session_token' in account and acc['session_token'] == account['session_token']:\n            acc['invalid_at'] = int(time.time())\n            return\n        elif 'access_token' in acc and 'access_token' in account and acc['access_token'] == account['access_token']:\n            acc['invalid_at'] = int(time.time())\n            return\n    \n    \n\n\n"
  },
  {
    "path": "pkg/models/forward.py",
    "content": "from mirai.models.message import MessageComponent\nfrom mirai.models.message import ForwardMessageNode\nfrom mirai.models.base import MiraiBaseModel\nfrom typing import List, Optional\n\n\nclass ForwardMessageDiaplay(MiraiBaseModel):\n    title: str = \"群聊的聊天记录\"\n    brief: str = \"[聊天记录]\"\n    source: str = \"聊天记录\"\n    preview: List[str] = []\n    summary: str = \"查看x条转发消息\"\n\n\nclass Forward(MessageComponent):\n    \"\"\"合并转发。\"\"\"\n    type: str = \"Forward\"\n    \"\"\"消息组件类型。\"\"\"\n    display: ForwardMessageDiaplay\n    \"\"\"显示信息\"\"\"\n    node_list: List[ForwardMessageNode]\n    \"\"\"转发消息节点列表。\"\"\"\n    def __init__(self, *args, **kwargs):\n        if len(args) == 1:\n            self.node_list = args[0]\n            super().__init__(**kwargs)\n        super().__init__(*args, **kwargs)\n\n    def __str__(self):\n        return '[聊天记录]'\n"
  },
  {
    "path": "pkg/models/interface.py",
    "content": "from typing import Tuple\n\n\nclass RevLibInterface:\n    \"\"\"逆向库接口\"\"\"\n\n    @staticmethod\n    def create_instance() -> tuple[\"RevLibInterface\", bool, dict]:\n        raise NotImplementedError\n\n    def get_rev_lib_inst(self):\n        raise NotImplementedError\n\n    def get_reply(self, prompt: str, **kwargs) -> Tuple[str, dict]:\n        raise NotImplementedError\n\n    def reset_chat(self, **kwargs):\n        raise NotImplementedError\n\n    def rollback(self):\n        raise NotImplementedError\n"
  },
  {
    "path": "pkg/process/__init__.py",
    "content": ""
  },
  {
    "path": "pkg/process/impls/__init__.py",
    "content": ""
  },
  {
    "path": "pkg/process/impls/bard.py",
    "content": "from typing import Tuple\nimport logging\n\nfrom plugins.revLibs.pkg.models.interface import RevLibInterface\n\nfrom bardapi import Bard\n\nimport os\nimport json\n\n\nclass BardImpl(RevLibInterface):\n\n    chatbot: Bard = None\n\n    token: str = None\n\n    @staticmethod\n    def create_instance() -> tuple[RevLibInterface, bool, dict]:\n        import revcfg\n        # 检查bard的cookies是否存在\n        if not os.path.exists(\"bard.json\"):\n            logging.error(\"Bard cookies不存在\")\n            raise Exception(\"Bard cookies不存在, 请根据文档进行配置: https://github.com/RockChinQ/revLibs\")\n\n        cookies_list = []\n        with open(\"bard.json\", \"r\", encoding=\"utf-8\") as f:\n            cookies_list = json.load(f)\n\n        return BardImpl(cookies_list), True, cookies_list\n\n    def __init__(self, cookies: str = None):\n\n        __Secure_1PSID = \"\"\n\n        for cookie in cookies:\n            if cookie[\"name\"] == \"__Secure-1PSID\":\n                __Secure_1PSID = cookie[\"value\"]\n                break\n\n        if __Secure_1PSID == \"\":\n            raise Exception(\"Bard cookies中不含有所需的__Secure-1PSID字段, 请尝试重新获取.\")\n\n        self.token = __Secure_1PSID\n\n        self.chatbot = Bard(token=__Secure_1PSID)\n\n    def get_rev_lib_inst(self):\n        return self.chatbot\n\n    def get_reply(self, prompt: str, **kwargs) -> Tuple[str, dict]:\n        logging.debug(\"[rev] 请求bard回复: {}\".format(prompt))\n\n        resp = self.chatbot.get_answer(prompt)\n\n        yield resp['content'], resp\n\n    def reset_chat(self):\n        self.chatbot = Bard(token=self.token)\n\n    def rollback(self):\n        pass\n"
  },
  {
    "path": "pkg/process/impls/claude.py",
    "content": "from typing import Tuple\nimport logging\n\nfrom plugins.revLibs.pkg.models.interface import RevLibInterface\n\nfrom claude_api import Client\n\nimport os\nimport json\n\n\nclass ClaudeImpl(RevLibInterface):\n\n    chatbot: Client = None\n\n    conversation_id: str = None\n\n    @staticmethod\n    def create_instance() -> tuple[RevLibInterface, bool, dict]:\n        import revcfg\n        # 检查claude的cookies是否存在\n        if not os.path.exists(\"claude.json\"):\n            logging.error(\"Claude cookies不存在\")\n            raise Exception(\"Claude cookies不存在, 请根据文档进行配置: https://github.com/RockChinQ/revLibs\")\n        \n        cookies_list = []\n        with open(\"claude.json\", \"r\", encoding=\"utf-8\") as f:\n            cookies_list = json.load(f)\n        \n        # 把cookies转换为字符串\n        cookies = \"\"\n\n        for cookie in cookies_list:\n            cookies += cookie[\"name\"] + \"=\" + cookie[\"value\"] + \";\"\n\n        return ClaudeImpl(cookies), True, cookies_list\n\n    def __init__(self, cookies: str = None):\n        self.chatbot = Client(cookies)\n\n    def get_rev_lib_inst(self):\n        return self.chatbot\n\n    def get_reply(self, prompt: str, **kwargs) -> Tuple[str, dict]:\n        logging.debug(\"[rev] 请求claude回复: {}\".format(prompt))\n\n        if self.conversation_id is None:\n            self.conversation_id = self.chatbot.create_new_chat()['uuid']\n\n        resp = self.chatbot.send_message(prompt, self.conversation_id)\n\n        yield resp, {}\n    \n    def reset_chat(self):\n        self.conversation_id = None\n\n    def rollback(self):\n        pass\n"
  },
  {
    "path": "pkg/process/impls/edgegpt.py",
    "content": "\"\"\"接入acheone08/EdgeGPT\n\"\"\"\nimport os\nimport logging\nimport json\nimport asyncio\n\nfrom plugins.revLibs.pkg.models.interface import RevLibInterface\nfrom EdgeGPT.EdgeGPT import Chatbot, ConversationStyle\n\n\nref_num_loop = ['¹', '²', '³', '⁴', '⁵', '⁶', '⁷', '⁸', '⁹', '¹⁰', '¹¹', '¹²', '¹³', '¹⁴', '¹⁵', '¹⁶', '¹⁷', '¹⁸', '¹⁹', '²⁰']\n\n\nclass EdgeGPTImpl(RevLibInterface):\n    \"\"\"使用acheong08/EdgeGPT接入new bing\n    \"\"\"\n    chatbot: Chatbot = None\n\n    style = ConversationStyle.balanced\n\n    inst_name: str\n\n    wss_link: str = \"wss://sydney.bing.com/sydney/ChatHub\"\n\n    @staticmethod\n    def create_instance() -> tuple[RevLibInterface, bool]:\n        import revcfg\n\n        return EdgeGPTImpl(revcfg.new_bing_style if hasattr(revcfg, \"new_bing_style\") else ConversationStyle.balanced), True\n\n    def __init__(self, style):\n        # logging.debug(\"[rev] 初始化接口实现，使用账户cookies: {}\".format(str(cookies)[:30]))\n        logging.debug(\"[rev] 初始化New Bing接口实现\")\n        import revcfg\n\n        params = {}\n\n        if hasattr(revcfg, \"new_bing_proxy\"):\n            params[\"proxy\"] = revcfg.new_bing_proxy\n            logging.info(\"[rev] 初始化NewBing使用代理: {}\".format(revcfg.new_bing_proxy))\n\n        if hasattr(revcfg, \"new_bing_reverse_proxy\") and revcfg.new_bing_reverse_proxy != \"\":\n            self.wss_link = revcfg.new_bing_reverse_proxy\n            logging.info(\"[rev] 初始化NewBing使用反向代理: {}\".format(revcfg.new_bing_reverse_proxy))\n\n        if os.path.exists(\"cookies.json\"):\n            with open(\"cookies.json\", \"r\") as f:\n                cookies_list = json.load(f)\n            params[\"cookies\"] = cookies_list\n            logging.info(\"[rev] 初始化NewBing具有Cookies\")\n\n        self.chatbot = Chatbot(**params)\n\n        self.style = style\n        # 随机一个uuid作为实例名\n        import uuid\n        self.inst_name = str(uuid.uuid4())\n    \n    def get_rev_lib_inst(self):\n        return self.chatbot\n\n    def get_reply(self, prompt: str, **kwargs) -> tuple[str, dict]:\n        \"\"\"获取回复\"\"\"\n        logging.debug(\"[rev] 请求bing回复: {}\".format(prompt))\n        task = self.chatbot.ask(prompt, conversation_style=self.style, wss_link=self.wss_link)\n        resp = asyncio.run(task)\n        logging.debug(json.dumps(resp, indent=4, ensure_ascii=False))\n\n        reply_obj = resp[\"item\"][\"messages\"][-1] if 'messageType' not in resp[\"item\"][\"messages\"][-1] else resp[\"item\"][\"messages\"][-2]\n        body = reply_obj[\"text\"] if \"text\" in reply_obj else (\n            reply_obj['hiddenText'] if \"hiddenText\" in reply_obj else (\n                reply_obj['spokenText'] if \"spokenText\" in reply_obj else \"\"\n            )\n        )\n\n        if \"sourceAttributions\" in reply_obj:\n            refs_str = \"参考资料: \\n\"\n            index = 1\n            for ref in reply_obj[\"sourceAttributions\"]:\n                refs_str += \"{}\".format(ref_num_loop[index-1]) + \" \" + ref['providerDisplayName'] + \" | \" + ref['seeMoreUrl'] + \"\\n\"\n                index += 1\n\n            throttling = resp[\"item\"][\"throttling\"]\n\n            throttling_str = \"本次对话: {}/{}\".format(throttling[\"numUserMessagesInConversation\"], throttling[\"maxNumUserMessagesInConversation\"])\n            \n            import revcfg\n            if hasattr(revcfg, \"output_references\") and not revcfg.output_references:\n                # 把正文的[^n^]替换成空\n                import re\n                body = re.sub(r\"\\[\\^[0-9]+\\^\\]\", \"\", body)\n            else:\n                # 把正文的[^n^]替换成对应的序号\n                for i in range(index):\n                    body = body.replace(\"[^\"+str(i+1)+\"^]\", ref_num_loop[i])\n\n            # if throttling[\"numUserMessagesInConversation\"] == 3:\n            if throttling[\"numUserMessagesInConversation\"] == throttling[\"maxNumUserMessagesInConversation\"]:\n                self.reset_chat()\n                throttling_str += \"(已达最大次数，下一回合将开启新对话)\"\n\n            reply_str = body + \"\\n\\n\" + ((refs_str + \"\\n\\n\") if index != 1 and (not hasattr(revcfg, \"output_references\") or revcfg.output_references) else \"\") + throttling_str\n            \n            yield reply_str, resp\n        else:\n            self.reset_chat()\n            yield \"err: 可能由于内容不当，对话已被接口拒绝，下一回合将开启新的会话。\", resp\n\n    def reset_chat(self):\n        asyncio.run(self.chatbot.reset())\n\n    def rollback(self):\n        pass"
  },
  {
    "path": "pkg/process/impls/fproxy.py",
    "content": "class Proxy:\n\n    funcs: list\n\n\n    def __init__(self, funcs: list):\n        self.funcs = funcs\n\n    def prompt(self, user_prompt: str):\n        if len(self.funcs) == 0:\n            return user_prompt\n        \n        raw = \\\n\"\"\"\n# You now have access to the following functions:\n\n```yaml\n{functions}```\n\n# P.S.\n- `required` means the arguments are required.\n\n# If user's input matches the description of a certain function, please output with following format to call the function:\n\n```json\n{{\"name\": \"function_name\", \"args\": {{\"arg_name\": \"arg_value\", ...}}}}\n```\n\n# If not, you can reply in your own way.\n\n# User's input:\n{user_prompt}\n\n# Rules\n\n- You can only call one function at a time.\n\n# Your output:\n\"\"\".strip()\n        funcs = \"\"\n        for i in range(len(self.funcs)):\n            # - name: func_name\n            #   description: func_description\n            #   args:\n            #     - name: arg_name\n            #       description: arg_description\n            #       type: int\n            #     - name: arg_name\n            #       description: arg_description\n            #       type: str\n            #   required: [arg_name, ...]\n            #   return: return_type\n            func = self.funcs[i]\n\n            func_desc = func['description'].replace(\"\\n\", \"\")\n\n            args = \"\"\n\n            for arg in func['parameters']['properties']:\n                args += \\\nf\"\"\"    - name: {arg}\n      description: {func['parameters']['properties'][arg]['description']}\n      type: {func['parameters']['properties'][arg]['type']}\n\"\"\"\n            if args.endswith(\"\\n\"):\n                args = args[:-1]\n\n            func_str = \\\nf\"\"\"- name: {func['name']}\n  description: {func_desc}\n  args:\n{args}\n  required: {str(func['parameters']['required'])}\n\"\"\"\n            funcs += func_str\n        return raw.format(functions=funcs, user_prompt=user_prompt)\n\n    def call(self, func_name: str, args: dict) -> tuple[bool, str, any]:\n        for func in self.funcs:\n            if func['name'] == func_name:\n                return func['function'](**args)\n        return \"error: no such function\"\n    \n    def extra_function_call(self, text: str):\n        \"\"\"Extra function call request from text\n        \n        ```json\n{\n  \"name\": \"access_web\",\n  \"args\": {\n    \"link\": \"https://www.example.com/search?q=RockChinQ\"\n  }\n}\n```\n        \"\"\"\n        import re\n        import json\n\n        # 用正则提取json数据\n        # 直接找大括号包围的, 匹配全文，不限于一行内\n        json_strs = re.findall(r\"\\{.*\\}\", text, re.S)\n\n        func_name = None\n        args = None\n\n        found = False\n\n        # 逐个检查json数据是否符合格式\n        for json_str in json_strs:\n            try:\n                # 删除所有// xxx\n                json_str = re.sub(r\",\\s*//.*\", \"\", json_str)\n\n                json_data = json.loads(json_str)\n                func_name = json_data['name']\n                args = json_data['args']\n                found = True\n                break\n            except:\n                continue\n          \n        if not found:\n            return False, None, None\n\n        return True, func_name, args"
  },
  {
    "path": "pkg/process/impls/gpt4free.py",
    "content": "from typing import Tuple\nimport logging\n\nfrom plugins.revLibs.pkg.models.interface import RevLibInterface\n\nimport g4f\nfrom g4f import models\n\n\nclass GPT4FreeImpl(RevLibInterface):\n\n    messages: list[dict]\n\n    use_model: models.Model = models.gpt_4\n\n    use_provider: g4f.Provider.BaseProvider = None\n\n    @staticmethod\n    def create_instance() -> tuple[RevLibInterface, bool, dict]:\n        return GPT4FreeImpl(), True, {}\n\n    @classmethod\n    def select_provider(cls):\n        logging.info(\"[rev] 测试并选择provider，如果某个provider测试过久，可以在revcfg.py中将其排除\")\n\n        from g4f.Provider import __all__ as providers\n\n        providers = providers.copy()\n\n        exclude = [\n            'Acytoo'\n        ]\n\n        import revcfg\n        \n        if hasattr(revcfg, 'g4f_use_adapters') and len(revcfg.g4f_use_adapters) > 0:\n            providers = revcfg.g4f_use_adapters\n            logging.debug(\"[rev] 已指定provider列表: {}\".format(providers))\n\n        if hasattr(revcfg, 'g4f_exclude_adapters') and len(revcfg.g4f_exclude_adapters) > 0:\n            exclude = revcfg.g4f_exclude_adapters\n            logging.debug(\"[rev] 已指定排除provider列表: {}\".format(exclude))\n\n        for provider in providers:\n\n            if provider in exclude:\n                continue\n\n            logging.info(\"[rev] 测试provider: {}\".format(provider))\n            provider = getattr(g4f.Provider, provider)\n            try:\n                response = g4f.ChatCompletion.create(\n                    model=cls.use_model,\n                    messages=[\n                        {\n                            \"role\": \"user\",\n                            \"content\": \"hi\"\n                        }\n                    ],\n                    provider=provider\n                )\n\n                logging.debug(\"[rev] 测试provider: {} 成功: {}\".format(provider, response))\n                cls.use_provider = provider\n                break\n            except Exception as e:\n                continue\n\n    def __init__(self):\n        self.messages = []\n\n        if GPT4FreeImpl.use_provider is None:\n            # 测试可用模型\n            self.select_provider()\n\n    def get_rev_lib_inst(self):\n        return None\n\n    def get_reply(self, prompt: str, **kwargs) -> Tuple[str, dict]:\n        logging.debug(\"[rev] 请求gpt4free: {} 回复: {}\".format(GPT4FreeImpl.use_provider, prompt))\n\n        retry = 0\n        while True:\n            try:\n                resp = g4f.ChatCompletion.create(\n                    model=GPT4FreeImpl.use_model,\n                    messages=self.messages+[\n                        {\n                            \"role\": \"user\",\n                            \"content\": prompt\n                        }\n                    ],\n                    provider=GPT4FreeImpl.use_provider,\n                )\n                \n                self.messages.append(\n                    {\n                        \"role\": \"user\",\n                        \"content\": prompt\n                    }\n                )\n                self.messages.append(\n                    {\n                        \"role\": \"assistant\",\n                        \"content\": resp\n                    }\n                )\n\n                yield resp, {}\n                break\n            except Exception as e:\n                retry += 1\n\n                if retry >= 3:\n                    raise e\n                \n                GPT4FreeImpl.select_provider()\n\n    def reset_chat(self):\n        self.messages = []\n\n    def rollback(self):\n\n        if len(self.messages) < 2:\n            return\n\n        self.messages.pop()\n        self.messages.pop()"
  },
  {
    "path": "pkg/process/impls/hugchat.py",
    "content": "from typing import Tuple\nimport logging\n\nfrom plugins.revLibs.pkg.models.interface import RevLibInterface\n\nfrom hugchat import hugchat\n\nimport os\nimport json\n\n\nclass HugChatImpl(RevLibInterface):\n\n    chatbot: hugchat.ChatBot = None\n\n    @staticmethod\n    def create_instance() -> tuple[RevLibInterface, bool, dict]:\n        import revcfg\n        # 检查hugging chat的cookies是否存在\n        if not os.path.exists(\"hugchat.json\"):\n            logging.error(\"HuggingChat cookies不存在\")\n            raise Exception(\"HuggingChat cookies不存在, 请根据文档进行配置: https://github.com/RockChinQ/revLibs\")\n        \n        cookies_dict = {}\n        with open(\"hugchat.json\", \"r\", encoding=\"utf-8\") as f:\n            cookies_dict = json.load(f)\n        return HugChatImpl(cookies_dict), True, cookies_dict\n\n    def __init__(self, cookies_dict: dict = None):\n        self.chatbot = hugchat.ChatBot(cookies=cookies_dict)\n\n    def get_rev_lib_inst(self):\n        return self.chatbot\n\n    def get_reply(self, prompt: str, **kwargs) -> Tuple[str, dict]:\n        logging.debug(\"[rev] 请求hugchat回复: {}\".format(prompt))\n\n        resp = self.chatbot.chat(prompt)\n\n        yield resp, {}\n\n    def reset_chat(self):\n        self.chatbot.new_conversation()\n\n    def rollback(self):\n        pass\n\n"
  },
  {
    "path": "pkg/process/impls/v1impl.py",
    "content": "from typing import Tuple\nfrom plugins.revLibs.pkg.models.interface import RevLibInterface\n\nfrom revChatGPT.V1 import Chatbot\n\nimport threading\n\n__thr_locks__ = {}\n\n\ndef get_lock(key: str):\n    if key not in __thr_locks__:\n        __thr_locks__[key] = threading.Lock()\n    return __thr_locks__[key]\n\n\nimport logging\n\n\nclass RevChatGPTV1(RevLibInterface):\n    \"\"\"acheong08/ChatGPT的逆向库接口 V1\"\"\"\n    chatbot: Chatbot = None\n\n    inst_name: str\n\n    @staticmethod\n    def create_instance() -> tuple[RevLibInterface, bool, dict]:\n        import plugins.revLibs.pkg.accounts.accmgr as accmgr\n        valid_acc, acc = accmgr.use_account()\n        return RevChatGPTV1(acc), valid_acc, acc\n\n    def __init__(self, cfg):\n        logging.debug(\"[rev] 初始化接口实现，使用账户配置: {}\".format(cfg))\n\n        import revcfg\n\n        if hasattr(revcfg, \"revchatgpt_reverse_proxy\") and revcfg.revchatgpt_reverse_proxy != \"\":\n            import revChatGPT.V1 as revcgpt\n            revcgpt.BASE_URL = revcfg.revchatgpt_reverse_proxy\n            logging.info(\"[rev] 已指定revchatgpt的反向代理: {}\".format(revcfg.revchatgpt_reverse_proxy))\n            \n        self.chatbot = Chatbot(\n            config=cfg,\n        )\n\n        self.inst_name = str(cfg)\n\n    def get_rev_lib_inst(self):\n        return self.chatbot\n\n    def get_reply(self, prompt: str, **kwargs) -> Tuple[str, dict]:\n        import revcfg\n        logging.debug(\"[rev] 请求ChatGPT回复: {}\".format(prompt))\n\n        # 构建函数代理\n        funcs = []\n\n        import pkg.plugin.models as models\n        import pkg.plugin.host as plugin_host\n        import pkg.openai.funcmgr as funcmgr\n        if hasattr(models, \"require_ver\"):\n            funcs = funcmgr.get_func_schema_list()\n            for func in funcs:\n                func['function'] = plugin_host.__function_inst_map__[func['name']]\n        \n        from .fproxy import Proxy\n\n        fp = Proxy(funcs)\n\n        try:\n            get_lock(self.inst_name).acquire()\n            if self.chatbot is None:\n                raise Exception(\"acheong08/ChatGPT.V1 逆向接口未初始化\")\n\n            prompt = fp.prompt(prompt)\n            \n            reply_gen = self.chatbot.ask(prompt, **kwargs)\n            already_reply_msg = \"\"\n            reply = {}\n\n            first_received = False\n            for r in reply_gen:\n                if not first_received:\n                    first_received = True\n                    logging.debug(\"已响应，正在接收...\")\n                reply = r\n\n                if \"message\" in reply:\n                    assert isinstance(reply['message'], str)\n                    reply['message'] = reply['message'].replace(already_reply_msg, \"\")\n\n            logging.debug(\"接收完毕: {}\".format(reply))\n\n            # 检查是否有JSON函数调用\n            is_func_call, func_name, args = fp.extra_function_call(reply['message'])\n\n            while is_func_call:\n                logging.info(\"[REV] 执行函数调用: {} {}\".format(func_name, args))\n                \n                result = \"\"\n\n                try:\n                    result = fp.call(func_name, args)\n                    logging.debug(\"func result: {}\".format(result))\n                    logging.info(\"[REV] 函数调用完成。\")\n                except Exception as e:\n                    logging.info(\"[REV] 函数调用失败。\")\n                    result = \"error: failed to call function: \"+str(e)\n                \n                reply = {}\n\n                prompt = f\"\"\"## Function call result: \n\n```\n{result}\n```\n\n## Rules\n\n- If you haven't done completely, you can call function again.\n- Please reply in the user's language.\"\"\"\n\n                for data in self.chatbot.ask(\n                    prompt=prompt,\n                ):\n                    try:\n                        assert 'message' in data\n                        reply = data\n                    except:\n                        continue\n\n                logging.debug(\"ChatGPT's output: {}\".format(reply['message']))\n\n                is_func_call, func_name, args = fp.extra_function_call(reply['message'])\n\n            yield reply['message'], reply\n        except Exception as e:\n            raise e\n        finally:\n            get_lock(self.inst_name).release()\n\n    def reset_chat(self):\n        self.chatbot.reset_chat()\n\n    def rollback(self):\n        self.chatbot.rollback_conversation()\n\n\n    \n"
  },
  {
    "path": "pkg/process/proccmd.py",
    "content": "import plugins.revLibs.pkg.process.revss as revss\nimport plugins.revLibs.pkg.process.impls.v1impl as v1impl\nimport plugins.revLibs.pkg.process.impls.edgegpt as edgegpt\nimport plugins.revLibs.pkg.process.impls.gpt4free as gpt4free\n\n\ndef process_command(session_name: str, **kwargs) -> str:\n    \"\"\"处理命令\"\"\"\n\n    cmd = kwargs['command']\n    params = kwargs['params']\n\n    reply_message = \"\"\n\n    if cmd == 'reset':\n        session: revss.RevSession = revss.get_session(session_name)\n        if len(params) >= 1:\n            prompt_whole_name = session.reset(params[0])\n            reply_message = \"已重置会话，使用情景预设: {}\".format(prompt_whole_name)\n        else:\n            session.reset()\n            reply_message = \"已重置会话\"\n    elif cmd == 'list':\n        session: revss.RevSession = revss.get_session(session_name)\n        page = 1\n        if len(params)>=1:\n            page = int(params[0])\n        \n        cbinst = session.get_rev_lib_inst()\n        from revChatGPT.V1 import Chatbot\n        assert isinstance(cbinst, Chatbot)\n\n        conversations = cbinst.get_conversations((page-1)*10, 10)\n\n        reply_message = \"会话列表 (第{}页) 本页{}个会话:\\n\".format(page, len(conversations))\n        for conversation in conversations:\n            reply_message += \"#{}: {}\\n\".format(conversation['id'], conversation['create_time'])\n\n    elif cmd == 'prompt':\n        # cbinst = session.get_rev_lib_inst()\n        # from revChatGPT.V1 import Chatbot\n        # assert isinstance(cbinst, Chatbot)\n        # reply_message = str(cbinst.get_msg_history(session.conversation_id))\n        reply_message = \"正在使用逆向库，暂不支持查看历史消息\"\n    elif cmd == \"last\":\n        reply_message = \"正在使用逆向库，暂不支持切换到前一次会话\"\n    elif cmd == \"next\":\n        reply_message = \"正在使用逆向库，暂不支持切换到后一次会话\"\n    elif cmd == \"resend\":\n        session: revss.RevSession = revss.get_session(session_name)\n        if session.__ls_prompt__ == \"\":\n            reply_message = \"没有上一条成功回复的消息\"\n        else:\n            reply_message = session.resend()\n    elif cmd == \"accs\":\n        \"\"\"查看每个账户的使用情况\"\"\"\n        import plugins.revLibs.pkg.accounts.accmgr as accmgr\n\n        if revss.__rev_interface_impl_class__ == v1impl.RevInterfaceImplV1:\n\n            reply_message = \"账户列表:\\n\"\n\n            for account in accmgr.get_account_list():\n                \"\"\"\n                    - 账户名称\n                \"\"\"\n                reply_message += \"账户: {}\\n  - \".format(accmgr.get_account_brief_name(account))\n\n                using = False\n                for k in revss.__sessions__:\n                    v: revss.RevSession = revss.__sessions__[k]\n                    if accmgr.get_account_brief_name(v.using_account) == accmgr.get_account_brief_name(account):\n                        reply_message += v.name + \", \"\n                        using = True\n                if not using:\n                    reply_message += \"未使用\"\n                else:\n                    reply_message = reply_message[:-2]\n\n                reply_message += \"\\n\\n\"\n            reply_message = reply_message[:-1]\n        else:\n            reply_message = \"仅当使用ChatGPT逆向库时可查看账户负载情况\"\n    elif cmd == \"style\":\n        if revss.__rev_interface_impl_class__ == edgegpt.EdgeGPTImpl:\n            import revcfg\n            from EdgeGPT import ConversationStyle\n            if len(params) >= 1:\n\n                mapping = {\n                    \"创意\": ConversationStyle.creative,\n                    \"平衡\": ConversationStyle.balanced,\n                    \"精确\": ConversationStyle.precise,\n                }\n\n                if params[0] not in mapping:\n                    reply_message = \"风格参数错误，可选参数: 创意, 平衡, 精确\"\n                    return reply_message\n\n                setattr(revcfg, \"new_bing_style\", mapping[params[0]])\n\n                reply_message = \"已切换到{}风格，重置会话后生效\".format(params[0])\n            else:\n                current = \"创意\"\n                if getattr(revcfg, \"new_bing_style\") == ConversationStyle.balanced:\n                    current = \"平衡\"\n                elif getattr(revcfg, \"new_bing_style\") == ConversationStyle.precise:\n                    current = \"精确\"\n                reply_message = \"当前风格为: {}，可选参数: 创意, 平衡, 精确\\n例如: !style 创意\".format(current)\n        else:\n            reply_message = \"仅当使用New Bing逆向库时可切换风格\"\n\n    elif cmd == \"provider\":\n        if revss.__rev_interface_impl_class__ == gpt4free.GPT4FreeImpl:\n            if len(params) >= 1:\n                if params[0] == 'ls':\n                    from g4f.Provider import __all__ as providers\n                    providers = providers.copy()\n                    reply_message = \"适配器列表:\\n\"\n                    for adapter in providers:\n                        reply_message += \"  - {}\\n\".format(adapter)\n                    reply_message = reply_message[:-1]\n            else:\n                if gpt4free.GPT4FreeImpl.use_provider is None:\n                    reply_message = \"当前未选择适配器，第一次对话时将测试并选择适配器\"\n                else:\n                    reply_message = \"当前使用的适配器: {}\".format(gpt4free.GPT4FreeImpl.use_provider)\n        else:\n            reply_message = \"仅当使用gpt4free逆向库时可查看适配器\"\n\n    return reply_message\n"
  },
  {
    "path": "pkg/process/procmsg.py",
    "content": "import time\nimport plugins.revLibs.pkg.process.revss as revss\nfrom pkg.plugin.host import PluginHost\nimport logging\nfrom mirai import MessageChain\nfrom mirai.models.message import ForwardMessageNode\nfrom plugins.revLibs.pkg.models.forward import Forward, ForwardMessageDiaplay\nimport traceback\nimport pkg.utils.context as context\nimport pkg.qqbot.manager as qqmgr\n\n__host__: PluginHost = None\n\n\ndef process_message(session_name: str, prompt: str, host: PluginHost, **kwargs) -> str:\n    \"\"\"处理消息\"\"\"\n    global __host__\n\n    logging.info(\"[rev] 收到{}消息: {}\".format(session_name, prompt))\n\n    if __host__ is None:\n        __host__ = host\n    if host is None:\n        host = __host__\n\n    import revcfg\n\n    # 重试循环\n    fail_times = 0\n    reply_message = \"\"\n    while True:\n        session: revss.RevSession = revss.get_session(session_name)\n        try:\n            if hasattr(revcfg, \"blog_msg_strategy\"):\n                logging.warning(\"[rev] 逆向库不再进行长消息处理，请使用主程序的长消息处理功能，详情请查看主程序的config-template.py\")\n            \n            all_reply = \"\"\n\n            for section in session.get_reply(prompt):\n                all_reply += section\n\n            reply_message = all_reply\n\n            # 发送使用量信息\n            from pkg.utils.context import get_openai_manager\n\n            openai_mgr = get_openai_manager()\n            openai_mgr.audit_mgr.report_to_server(\n                revcfg.reverse_lib,\n                len(reply_message)\n            )\n\n            break\n        except Exception as e:\n            traceback.print_exc()\n            if str(e).__contains__(\"Too many requests in 1 hour\"):\n                session.__init__(session_name)\n                logging.warn(\"超过一小时限次，切换会话账户\")\n                continue\n\n            if fail_times < revcfg.retry_when_fail:\n                fail_times += 1\n                logging.error(traceback.format_exc())\n                logging.warn(\"失败，重试({}/{})...\".format(fail_times, revcfg.retry_when_fail))\n                time.sleep(2)\n                continue\n            else:\n                raise e\n\n    return reply_message\n"
  },
  {
    "path": "pkg/process/revss.py",
    "content": "# 逆向库的session\nfrom plugins.revLibs.pkg.models.interface import RevLibInterface\nfrom plugins.revLibs.pkg.process.impls.v1impl import RevChatGPTV1\nfrom plugins.revLibs.pkg.process.impls.edgegpt import EdgeGPTImpl\nfrom plugins.revLibs.pkg.process.impls.hugchat import HugChatImpl\nfrom plugins.revLibs.pkg.process.impls.claude import ClaudeImpl\nfrom plugins.revLibs.pkg.process.impls.bard import BardImpl\n\nimport pkg.openai.dprompt as dprompt\nimport uuid\nimport time\n\nimport logging\nimport threading\n\nimport config\n\n__sessions__ = {}\n\"\"\"所有session\"\"\"\n\n__rev_interface_impl_class__: RevLibInterface = None\n\nclass RevSession:\n    name: str\n\n    conversation_id: str = None\n    \"\"\"会话id，第一次获取到回复时生成\"\"\"\n\n    parent_id: str = None\n    \"\"\"父会话id\"\"\"\n\n    __rev_interface_impl__: RevLibInterface = None\n\n    __ls_prompt__: str = \"\"\n\n    __set_prompt__: str = \"\"\n\n    using_account: dict = None\n\n    last_interaction_time: int = 0\n    \"\"\"最后一次交互时间\"\"\"\n\n    getting_reply: bool = False\n\n    def __init__(self, name: str):\n        self.name = name\n\n        logging.debug(\"[rev] 逆向库接口实现为 {}\".format(__rev_interface_impl_class__))\n        self.__rev_interface_impl__, valid, acc = __rev_interface_impl_class__.create_instance()\n        self.using_account = acc\n        self.reset()\n\n        # if __rev_interface_impl_class__ is RevChatGPTV1:\n        #     logging.debug(\"[rev] 逆向接口实现为RevChatGPTV1\")\n        #     self.__rev_interface_impl__, valid, acc = __rev_interface_impl_class__.create_instance()\n        #     self.using_account = acc\n        #     self.reset()\n        # elif __rev_interface_impl_class__ is EdgeGPTImpl:\n        #     logging.debug(\"[rev] 逆向接口实现为EdgeGPTImpl\")\n        #     self.__rev_interface_impl__,_ = __rev_interface_impl_class__.create_instance()\n        #     self.reset()\n        # elif __rev_interface_impl_class__ is HugChatImpl:\n        #     logging.debug(\"[rev] 逆向接口实现为HugChatImpl\")\n        #     self.__rev_interface_impl__,_,_ = __rev_interface_impl_class__.create_instance()\n        #     self.reset()\n        # elif __rev_interface_impl_class__ is ClaudeImpl:\n        #     logging.debug(\"[rev] 逆向接口实现为ClaudeImpl\")\n        #     self.__rev_interface_impl__,_,_ = __rev_interface_impl_class__.create_instance()\n        #     self.reset()\n        # elif __rev_interface_impl_class__ is BardImpl:\n        #     logging.debug(\"[rev] 逆向接口实现为BardImpl\")\n        #     self.__rev_interface_impl__,_,_ = __rev_interface_impl_class__.create_instance()\n        #     self.reset()\n\n        threading.Thread(target=self.check_expire_loop, daemon=True).start()\n\n    def check_expire_loop(self):\n        while True:\n            time.sleep(60)\n            if self not in __sessions__.values():\n                break\n            if self.last_interaction_time < int(time.time()) - config.session_expire_time and not self.getting_reply:\n                # 删除此session\n                logging.info(\"[rev] 会话 {} 已过期，自动重置\".format(self.name))\n                del __sessions__[self.name]\n                break\n\n    def get_rev_lib_inst(self):\n        return self.__rev_interface_impl__.get_rev_lib_inst()\n\n    def get_reply(self, prompt: str, **kwargs) -> str:\n        \"\"\"获取回复\"\"\"\n        self.getting_reply = True\n\n        if self.__rev_interface_impl__ is None:\n            raise Exception(\"逆向接口未初始化\")\n\n        self.last_interaction_time = int(time.time())\n        \n        self.__ls_prompt__ = prompt\n        if self.conversation_id is not None:\n            kwargs['conversation_id'] = self.conversation_id\n        \n        using_name = dprompt.mode_inst().get_using_name()\n        dprompt_, _ = dprompt.mode_inst().get_prompt(using_name)\n        if self.__set_prompt__ != \"\":\n            dprompt_ = self.__set_prompt__\n            self.__set_prompt__ = \"\"\n            \n        if dprompt_ != \"\" and self.conversation_id is None and __rev_interface_impl_class__ is not EdgeGPTImpl:  # new bing不使用情景预设\n            if type(dprompt_) == list:\n                dprompt_ = dprompt_[0]['content']\n            # prompt = dprompt_ +\" \\n\"+ prompt\n            prompt = f\"{dprompt_} \\n{prompt}\"\n            logging.info(\"[rev] 使用情景预设: {}\".format(dprompt_))\n\n        # 改成迭代器以支持回复分节\n        for reply_period_msg, reply_period_dict in self.__rev_interface_impl__.get_reply(prompt, **kwargs):\n            if __rev_interface_impl_class__ is RevChatGPTV1:\n                self.conversation_id = reply_period_dict['conversation_id']\n            else:\n                self.conversation_id = uuid.uuid4().hex\n                \n            yield reply_period_msg\n        \n        self.getting_reply = False\n\n    def reset(self, using_prompt_name: str = None) -> str:\n        \"\"\"重置会话\"\"\"\n        self.conversation_id = None\n        self.parent_id = None\n        self.__ls_prompt__ = \"\"\n        self.__rev_interface_impl__.reset_chat()\n        if using_prompt_name is not None:\n            for key in dprompt.mode_inst().list():\n                if key.startswith(using_prompt_name):\n                    using_prompt_name = key\n                    break\n            self.__set_prompt__ = dprompt.mode_inst().get_prompt(using_prompt_name)\n            return using_prompt_name\n\n    def resend(self):\n        \"\"\"重新发送上一条消息\"\"\"\n        self.__rev_interface_impl__.rollback()\n        import plugins.revLibs.pkg.process.procmsg as procmsg  # 不优雅的解决办法\n        return procmsg.process_message(self.name, self.__ls_prompt__, None, launcher_type=self.name.split(\"_\")[0], launcher_id=int(self.name.split(\"_\")[1]))\n        \n    \n    \ndef get_session(name: str) -> RevSession:\n    \"\"\"获取session\"\"\"\n    if name not in __sessions__:\n        # 创建session\n        __sessions__[name] = RevSession(name)\n    return __sessions__[name]\n"
  },
  {
    "path": "pkg/utils.py",
    "content": "from pip._internal import main as pipmain\n\ndef upgrade_revlibs():\n    \"\"\"更新逆向库\"\"\"\n    pipmain(['install', '--upgrade', 'revChatGPT', '--quiet'])\n    import main\n    main.reset_logging()"
  },
  {
    "path": "requirements.txt",
    "content": "revChatGPT~=6.8.6\nEdgeGPT~=0.13.2\nhugchat\nrequests\nclaude-api\nbardapi\ng4f==0.1.9.3\nPyExecJS\n"
  },
  {
    "path": "revcfg-template.py",
    "content": "from EdgeGPT.EdgeGPT import ConversationStyle\n# 选择使用的逆向库\n# 目前支持以下库：\n# - \"acheong08/ChatGPT.V1\": acheong08/ChatGPT库的V1版本\n# - \"acheong08/EdgeGPT\": acheong08/EdgeGPT库，接入new bing\n# - \"Soulter/hugging-chat-api\": Soulter/hugging-chat-api库，接入hugging chat\n# - \"KoushikNavuluri/Claude-API\": KoushikNavuluri/Claude-API库，接入Claude\n# - \"dsdanielpark/Bard-API\": dsdanielpark/Bard-API库，接入Bard\n# - \"xtekky/gpt4free\": xtekky/gpt4free库，接入多个平台的免费的 GPT-4，无需鉴权\nreverse_lib = \"acheong08/ChatGPT.V1\"\n\n# [必填][❗此说明很重要，请您认真阅读❗] OpenAI账户信息\n# *仅使用acheong08/ChatGPT.V1时填写\n# 目前支持三种登录方式：\n# - 账号密码登录(仅支持ChatGPT Plus账号)\n# - SessionToken登录(仅Microsoft、Google账号注册的账号)\n# - accessToken登录(普通账号请使用此方法登录)\n#\n# *账号密码登录方式，例如：\n# openai_account = {\n#   \"email\": \"your email\",\n#   \"password\": \"your password\"\n# }\n#\n# *若要使用SessionToken登录方式，请删掉email和password参数，添加session_token参数：\n# 例如：\n# openai_account = {\n#   \"session_token\": \"your session token\"\n# }\n#\n# *若要使用accessToken登录方式，请删掉email和password参数，添加access_token参数：\n# 你可以在 https://chat.openai.com/api/auth/session 返回的数据中找到你的accessToken，记得先登录再获取\n# 例如：\n# openai_account = {\n#   \"access_token\": \"your access token\"\n# }\n#\n# 除了登录信息，还支持以下可选参数：\n#  - proxy: 代理服务器地址，格式为\"protocol:ip:port\"，例如\"https://localhost:1080\"\n#  - paid: 是否订阅了ChatGPT Plus服务，若为True则使用ChatGPT Plus服务\n#  - model: 使用的模型, 若要使用GPT-4, 可以添加此参数并设置为\"gpt-4\"\n# 可选参数填写格式示例:\n# openai_account = [\n#   {\n#     \"access_token\": \"your access_token\",\n#     \"proxy\": \"https://localhost:1080\",\n#     \"paid\": True,\n#     \"model\": \"gpt-4\"\n#   }\n# ]\n#\n# **若要使用多个账户均衡负载，可以以列表的形式添加多个账户信息，例如：\n# openai_account = [\n#   {\n#     \"access_token\": \"your access_token\",\n#   },\n#   {\n#     \"access_token\": \"your access_token\",\n#   }\n# ]\n# 其中每个账户的格式符合前文所述的格式\nopenai_account = [\n    {\n        \"access_token\": \"your access_token\",\n    }\n]\n\n# 账号重新恢复使用的时间间隔\n# 以分钟为单位\nopenai_account_resume_interval = 60\n\n# New Bing的代理地址\n# 参考config.py中openai的代理地址\n# 若为None则不使用代理\nnew_bing_proxy = None\n\n# New Bing的Style\n# 请将此值设置为以下之一：\n# ConversationStyle.creative     有创意\n# ConversationStyle.balanced     平衡\n# ConversationStyle.precise      精确\nnew_bing_style = ConversationStyle.balanced\n\n# 使用New Bing时是否显示参考资料\noutput_references = True\n\n# 使用 revChatGPT 时使用的反向代理\n# 现在不用反向代理基本没法用了吧，可以自己上github找一下\n# 用来搭建 ChatGPT 反向代理的项目\n# 或者到 QChatGPT 主页找到社区群加进去有公用的反向代理\n# 这里默认的是作者的反向代理，但是不保证一直可用\nrevchatgpt_reverse_proxy = \"https://chatproxy.rockchin.top/api/\"\n\n# 使用 New Bing (EdgeGPT) 时使用的反向代理\n# 参考 revchatgpt_reverse_proxy，但是你需要的是 New Bing 的反向代理\n# 需要不同的项目，社区群里也有公用的\nnew_bing_reverse_proxy = \"\"\n\n# 消息回复前缀\n# 建议保留此前缀，以便区分GPT-3和此插件的回复\nreply_prefix = \"[REV]\"\n\n# 获取回复失败时的重试次数\n# 若为0则不重试\nretry_when_fail = 3\n\n# 使用 gpt4free 时，仅使用的适配器名称列表\n# 程序将在这些适配器中选择一个可用的适配器\n# 例如：\n# g4f_use_adapters = ['Acytoo', 'FakeGpt']\n# \n# 若为 空列表 则会测试所有适配器并自动选择\n# 所有适配器列表可以在\n# https://github.com/xtekky/gpt4free/blob/main/g4f/Provider/__init__.py\n# 中找到\n# 也可以再启动机器人之后，发送命令 `!provider ls` 列出所有适配器\n#\n# 注意：设置此字段可能会影响可用性，请确认指定的适配器可用\ng4f_use_adapters = []\n\n# 使用 gpt4free 时，排除的适配器名称\n# 此字段优先级高于 g4f_use_adapters\ng4f_exclude_adapters = []\n"
  }
]