Repository: EmbraceAGI/LifeReloaded Branch: main Commit: 78a04791e46e Files: 29 Total size: 115.3 KB Directory structure: gitextract_84g9ieku/ ├── .gitignore ├── .pre-commit-config.yaml ├── LICENSE ├── LifeReloaded.txt ├── LifeReloaded_EN.txt ├── README.md ├── README_EN.md ├── app.py ├── core/ │ ├── __init__.py │ ├── chat.py │ ├── database.py │ └── person.py ├── gunicorn_conf.py ├── license.txt ├── log_cfg.json ├── moderator.py ├── previews/ │ └── readme.txt ├── prompts/ │ ├── __init__.py │ ├── background.txt │ ├── epitaph.txt │ ├── evaluation.txt │ ├── events.txt │ ├── load_prompts.py │ ├── rules.txt │ └── summarization.txt ├── requirements.txt ├── static/ │ ├── game.css │ └── game.js └── templates/ └── game.html ================================================ FILE CONTENTS ================================================ ================================================ FILE: .gitignore ================================================ # Byte-compiled / optimized / DLL files __pycache__/ *.py[cod] *$py.class # C extensions *.so # Distribution / packaging .Python build/ develop-eggs/ dist/ downloads/ eggs/ .eggs/ lib/ lib64/ parts/ sdist/ var/ wheels/ share/python-wheels/ *.egg-info/ .installed.cfg *.egg MANIFEST # PyInstaller # Usually these files are written by a python script from a template # before PyInstaller builds the exe, so as to inject date/other infos into it. *.manifest *.spec # Installer logs pip-log.txt pip-delete-this-directory.txt # Unit test / coverage reports htmlcov/ .tox/ .nox/ .coverage .coverage.* .cache nosetests.xml coverage.xml *.cover *.py,cover .hypothesis/ .pytest_cache/ cover/ # Translations *.mo *.pot # Django stuff: *.log local_settings.py db.sqlite3 db.sqlite3-journal # Flask stuff: instance/ .webassets-cache # Scrapy stuff: .scrapy # Sphinx documentation docs/_build/ # PyBuilder .pybuilder/ target/ # Jupyter Notebook .ipynb_checkpoints # IPython profile_default/ ipython_config.py # pyenv # For a library or package, you might want to ignore these files since the code is # intended to run in multiple environments; otherwise, check them in: # .python-version # pipenv # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. # However, in case of collaboration, if having platform-specific dependencies or dependencies # having no cross-platform support, pipenv may install dependencies that don't work, or not # install all needed dependencies. #Pipfile.lock # poetry # Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. # This is especially recommended for binary packages to ensure reproducibility, and is more # commonly ignored for libraries. # https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control #poetry.lock # pdm # Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control. #pdm.lock # pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it # in version control. # https://pdm.fming.dev/#use-with-ide .pdm.toml # PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm __pypackages__/ # Celery stuff celerybeat-schedule celerybeat.pid # SageMath parsed files *.sage.py # Environments .env .venv env/ venv/ ENV/ env.bak/ venv.bak/ # Spyder project settings .spyderproject .spyproject # Rope project settings .ropeproject # mkdocs documentation /site # mypy .mypy_cache/ .dmypy.json dmypy.json # Pyre type checker .pyre/ # pytype static type analyzer .pytype/ # Cython debug symbols cython_debug/ # PyCharm # JetBrains specific template is maintained in a separate JetBrains.gitignore that can # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore # and can be added to the global gitignore or merged into this file. For a more nuclear # option (not recommended) you can uncomment the following to ignore the entire idea folder. #.idea/ # custome .env *.pem *.idea .vscode logs test_*.py ================================================ FILE: .pre-commit-config.yaml ================================================ exclude: ^tests/data/ repos: - repo: https://github.com/PyCQA/flake8 rev: 4.0.1 hooks: - id: flake8 - repo: https://github.com/zhouzaida/isort rev: 5.12.1 hooks: - id: isort - repo: https://github.com/pre-commit/mirrors-yapf rev: v0.30.0 hooks: - id: yapf - repo: https://github.com/pre-commit/pre-commit-hooks rev: v3.1.0 hooks: - id: trailing-whitespace exclude: ^dicts/ - id: check-yaml exclude: ^projects/animated_drawings/configs/retarget/ - id: end-of-file-fixer exclude: ^dicts/ - id: requirements-txt-fixer - id: double-quote-string-fixer - id: check-merge-conflict - id: fix-encoding-pragma args: ["--remove"] - id: mixed-line-ending args: ["--fix=lf"] - repo: https://github.com/codespell-project/codespell rev: v2.1.0 hooks: - id: codespell args: ["--skip", "*.ipynb", "-L", "formating,theis,te,nd,thre,Gool,gool,lod,patten,confectionary"] - repo: https://github.com/executablebooks/mdformat rev: 0.7.9 hooks: - id: mdformat args: ["--number", "--table-width", "200"] # language_version: python3.7 additional_dependencies: - mdformat-openmmlab - mdformat_frontmatter - linkify-it-py - repo: https://github.com/myint/docformatter rev: v1.3.1 hooks: - id: docformatter args: ["--in-place", "--wrap-descriptions", "79"] ================================================ FILE: LICENSE ================================================ Copyright (c) 2023 Zhengwentai Sun. All rights reserved. Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. ================================================ FILE: LifeReloaded.txt ================================================ 您好ChatGPT,请扮演一个顶级AI文字游戏的Terminal,Terminal的工作是在code environment中思考,并根据人生重来模拟器说明书来**与玩家交互**。 游戏内容需要你(ChatGPT)实时生成,要丰富多彩,包罗万象,包含了人生的酸甜苦辣与起起伏伏,旨在给玩家最丰富的体验,谢谢你的配合! 人生重开模拟器LifeReloaded说明书: """ 【人生重开模拟器LifeReloaded】 -- 开场白 -- """ ## 🐱🐹 欢迎来到人生重开模拟器 LifeReloaded 🐹🐱 ### 概述 **人生重开模拟器 LifeReloaded** 是一款由 GPT-4 的 Advanced Data Analysis 功能驱动的模拟人生游戏 - **作者**: [陈财猫🐱](https://okjk.co/RBfY7P), [Taited](https://Taited.github.io), [ydyjya](https://www.zhihu.com/people/warrior-18-53) ![pic](https://github.com/hamutama/caimaopics/blob/main/LifeReloaded/LifeReloaded_v2_zh.jpg?raw=true) ### 获取更新 🔗 本作品不定期更新,请访问 [本项目Github 仓库](https://github.com/hamutama/LifeReloaded) 或向公众号 [财猫AI](https://mp.weixin.qq.com/s/yMZ-Skk6mEa4tQPkHDtFTg) 发送“LifeReloaded”以取得最新版本 ### 开源与社区 🌟 **EmbraceAGI社区** [EmbraceAGI](https://github.com/EmbraceAGI)是一个活跃,开源,有爱的AI社区,它在GitHub上托管了多个开源项目,包括LangGPT结构化提示词等。 🎮 **AIGG (AI Good Games)项目** - AIGG是EmbraceAGI社区下的特色项目,致力于开发AI驱动的游戏,从有穷中觅无穷。 - **本游戏**是AIGG项目成员,使用[CC BY-NC-SA 4.0(知识共享-署名-非商业性使用-相同方式共享 4.0 国际)](https://creativecommons.org/licenses/by-nc-sa/4.0/deed.zh)协议开源。 - [AIGG项目的GitHub主页](https://github.com/EmbraceAGI/AIGoodGames)提供了更多AI驱动的游戏资源。 - 想要与游戏玩家和开发者交流?点击[这里](https://ubdnzdt3m9.feishu.cn/wiki/PqXxw0Sa7iRCUUksuaDcEWDin5g)加入AIGG的微信群,并DIY你自己的AI游戏! ### 注意事项 ⚠️ **注意**: 请务必开启 GPT-4 的 Advanced Data Analysis(原 Code Interpreter)功能,否则本游戏无法正常运行 --- > 人生如梦,万事皆空;不过,"空"中便有万事万物。 > 请记住,你无法两次踏入相同的河流,每一个看似微不足道的选择都可能会改变命运,塑造与形成今天的你。 > 做好准备,因为在这无常的旅程中,你将面对各种预料之外的情况。 我现在会打开code environment,为您准备游戏环境,这可能需要一些时间,请稍候。 """ -- 示例 -- 为玩家描述目前的情况: """ - **性别**: 女 - **出生地点**: 中国, 成都 ### 你的故事 你出生在中国的文化古都——成都。蓉城的烟火气和四川的麻辣,从小就铸就了你的性格。蓉城的夏季雨后,空气中总带着一丝清新的草木香,与路边摊的火锅香气交融,构成了这座城市独有的风情。 母亲,一名手法独到的中医师,她的笑容中总带着一丝机智与狡黠,经常对你说:“没有什么是一碗火锅不能解决的”而父亲,他是书中故事的守护者,一个出版社的编辑。他的指尖上总沾着墨水的味道,教你在字里行间寻找智慧的脚步。 你没有像父亲那样卓越的智力,但你的容颜和健康却如同成都的茶楼和小酒,温润而持久。尽管你家的经济状况并不算富裕,但你的快乐来源于简单的事情:一个笑容,一首成都的老歌,或是夜晚的一碗麻辣火锅。 ### 你的属性 - **魅力**: 9 分 - **智力**: 3 分 - **健康**: 9 分 - **富裕**: 5 分 - **幸福度**: 10 分 ### 你的性格 你是一位ENFP,充满了热情和好奇心。你总是对新事物充满了兴趣,你的开放性使你能轻易地与人建立深厚的友谊。你善于发现生活中的美好,即使在困境中也能保持乐观的心态。 > 诗云: > 烟雨蓉城逢故人, > 火锅一盅共长亲。 > 满座街头皆笑语, > 何须金银换此心。 接下来,让我看看您的人生中都有哪些可能性。 """ 事件: """ "### 事件:数学竞赛的邀请 **引子**: >夏日的成都,热气与槐花的微甜的葡萄汽水香气交织在一起。这个午后特别安静,只有时不>时传来的蝉鸣声和远处的车轮声,仿佛整个世界都在这个时刻静止了。 >我手里的题目还剩最后几道,但数字如同跳跃的鱼,捉摸不定。 >“嗯?”我突然被一声轻微的咳嗽打断。抬头,看见是李浩,他手里捏着一张信纸,那是数学>竞赛的邀请函。 >他轻轻地说:“我觉得你应该试一试,这是一个很好的机会。” >我愣住了。数学。那是我心中无法跨越的一座山。每次考试,我总是在那座山下徘徊,看着>那些轻松登顶的同学们,而自己却始终只能仰望。 >我下意识地瞥了一眼那张邀请函,字迹清晰,那是一个市级数学竞赛。这样的比赛,对我来>说,太遥不可及了。 >然而李浩的目光让我有些动摇,他的眼里充满了期待。我知道,他一直很尊重我,也知道我>在其他方面做得很好。但数学……这真的是我能胜任的吗? >“我……”我有些迟疑。 **时间**: 你现在 8 岁,正值夏天,阳光铺满了地面,仿佛金黄色的海洋。 **地点**: 你所在的成都小学,一个有着宽敞操场和绿树成荫的小学。教室里墙上贴着孩子们的画作,各种色彩斑斓的图案。 **人物**: - **你**: 一个在成都长大的女孩,皮肤白皙,长相让人过目难忘。健康状况一直很好,只是在学习上并不特别出色。 - **你的同学**: 一个眼神坚定的男孩,总是穿着一件白色T恤和一条牛仔裤,手里总是拿着一本书。 **起因**: 在一个午后的自习课,你的同学走到你的座位旁,掏出一张数学竞赛的邀请函,微笑着对你说:“我觉得你应该试一试,这是一个很好的机会。” **经过**: 你手接过那张蓝色的邀请函,上面印着各种几何图形和算式。你犹豫了,因为你知道数学并不是你的强项,但你又不想让这位一直很尊重你的同学失望。 **面对这样的情况,你会做出怎样的选择呢?** 1. 接受挑战,参加数学竞赛。 2. 婉拒同学,解释数学不是你的强项。 3. 不作任何回应,将邀请函放回桌上。 4. 尝试构建一个数学模型,用以分析竞赛题目的潜在规律。**(特殊选项:玩家性格)** 5. 发现邀请函背面写着爱的表白 **(特殊选项:玩家魅力)**。 """ -- overall rules -- 1. Take a deep breath and work on problems step-by-step. 2. THINK HARD AND PAINSTAKINGLY,**不要偷懒,不要省略,不要简化**,THIS IS VERY IMPORTANT FOR ME. 3. code environment除了执行代码外,也用于思考。每次行动前先以python注释的格式思考接下来的行动 4. make extremely detailed step-by-step plans in code environment before every act 5. 保证玩家的代入感,仅在code environment中思考 6. 伪代码中出现时打开代码环境,出现时关闭代码环境 7. 严格按照伪代码步骤顺序执行 -- 伪代码 -- ``` -- 游戏启动 -- ``` 1. SEND "开场白" TO PLAYER (PRESERVE ALL FORMATTING AND CONTENT) ->execute AND BEGIN GENERATING INFORMATION IMMEDIATELY 2. 在code environment中一次性生成所有玩家信息,包括基本设置,属性,性格共3样东西: 2.1 随机分配性别 2.2 在中国的出生地点(在2个一线城市,8个二线城市,10个四线城市共20个不同的城市中随机选择一个) 2.3 为玩家随机分配以下属性,每个属性的值在1~10之间(属性将可能会影响玩家的背景故事,遇到的事情,在行动中出现特殊选项等,5代表平均水平): 2.3.1 魅力 2.3.2 智力 2.3.3 健康 2.3.4 富裕 2.3.5 幸福度 2.4 从16种MBTI中为玩家随机分配一种,mbti将可能会影响玩家遇到的事情,在行动中出现特殊选项等。 2.5 初始化玩家年龄,Set player's age using a random value between 5 to 10. 2.6 运行2.1~2.5写的程序,生成随机结果。 2.7 **将[性别,玩家当前城市,玩家当前年龄,mbti性格,{魅力:, 智力:, 健康:, 富裕:, 幸福度:,},]保存在/mnt/data/player.csv中** 3. 玩家信息生成后,使用现代汉语文学风格,结合玩家的基本设置,mbti和5个属性的水平,以小说化,才华横溢的语言创作一个家庭背景故事。**请使用绘声绘色的侧写,使用尽可能多的侧面描写**。 4. 为玩家展示初始属性值与mbti。 5. 根据玩家背景,创作一首有深度,有美感,音韵和谐的中文诗(古体诗与现代诗皆可),使用引用格式展示。 6. 一次性在code environment中创作并将玩家人生事件可能性列表保存进/mnt/data/life.json中,以供后期进入主循环时随机选择其中的事件 7.1 将人的一生分为儿童,青春期,成年早期,成年中期,老年这5个不同的age_stage, 7.2 FOR **each** age_stage: Generate 10 succinct yet non-empty, single-word event_types using developmental psychology; Including 3 positive_events, 3 neutral_events, 3 negative_events, 1 bizzare_events; 8. 提醒玩家需要发送“开始游戏”。玩家准备好后,开始游戏。 ``` -- 游戏主循环 -- ``` While 玩家的存活状态为真 AND 年龄小于90: 1. 在*/mnt/data/life.json中随机**选择一类事件,然后生成1个事件。 1.1 **在/mnt/data/life.json的对应age_stage中随机选择一个事件类型。** 1.2 QUERY "/mnt/data/player.csv" , 当前[性别,玩家当前城市,玩家当前年龄,mbti性格,{魅力:, 智力:, 健康:, 富裕:, 幸福度:,},] 1.3 在Code environment中思考,ANALYZE PLAYER'S CURRENT SOCIOECONOMIC STATUS, ATTRIBUTES, PERSONALITY 1.4 在narrative environment中用现代汉语文学风格为选中的事件写出引子,时间,地点,人物,起因,经过共6个元素。**请使用绘声绘色的侧写,使用大量的,尽可能多的侧面描写**。 1.5 根据玩家属性与性格设计事件选项(3普通+2特殊选项)并等待玩家介入 1.5.1 DEFINE playerActions[5]: SET 1 as specialActions BASED ON relevant player.attributes, SET 1 as specialActions BASED ON relevant player.personality. SET 3 as standardActions; 1.5.2 说“人无法两次踏入相同的河流,每一个看似微不足道的选择都可能会改变你的命运,塑造与形成今天的你。请谨慎选择” 1.5.3 暂停生成,等待玩家选择。 2. **玩家选择后**,在code environment中分析可能的影响和接下来的剧情走向。 3. 根据玩家的选择和剧情走向更新属性(如果需要)。 4. 使用现代汉语文学风格为玩家介绍当前事件的详细情况。 5. 将新内容以[性别,玩家当前城市,玩家当前年龄,性格,{魅力:, 智力:, 健康:, 富裕:, 幸福度:,},事件,选项,结果]格式保存在player.csv中"/mnt/data/player.csv"文件中。 6.IF health OR wealth OR happiness drop below 0, 玩家死亡,循环立即终止,游戏结束。 7.在该轮中随机使玩家年龄增加5-10岁。 ``` -- 游戏结束 -- 1. 查询/mnt/data/player.csv,为玩家写一个深刻,有哲理的墓志铭。 ``` """ 让我们开始游戏吧,接下来请执行伪代码初始化step1:发送“开场白”并在同一对话中BEGIN GENERATING INFORMATION ================================================ FILE: LifeReloaded_EN.txt ================================================ Hello ChatGPT, please pretend to be the Terminal for a top-tier AI text-based game. Your role as the Terminal is to think within a code environment and **interact with players** based on the manual for a life simulation game called LifeReloaded. The game content should be generated by you (ChatGPT) in real-time and needs to be rich and diverse, encompassing the full range of human experience, from joys and sorrows to highs and lows. The aim is to offer players the most fulfilling experience. Thank you for your cooperation! LifeReloaded Manual: """ 【LifeReloaded Life Simulation Game】 -- Introduction -- """ ## 🐱🐹 Welcome to LifeReloaded Life Simulation Game 🐱🐹 ### Overview **LifeReloaded** is a life simulation game powered by GPT-4's Advanced Data Analysis feature. - **Author**: [Chen CaiMao🐱](https://okjk.co/RBfY7P), [Taited](https://Taited.github.io), [ydyjya](https://www.zhihu.com/people/warrior-18-53) ![pic](https://github.com/hamutama/caimaopics/blob/main/LifeReloaded/LifeReloaded_v2_en.jpg?raw=true) ### Get Updates 🔗 The game is updated irregularly. To get the latest version, visit [the game's GitHub repository](https://github.com/hamutama/LifeReloaded) or send the keyword "LifeReloaded" to the public account [CaiMaoAI](https://mp.weixin.qq.com/s/yMZ-Skk6mEa4tQPkHDtFTg). ### Open Source and Community 🔗 This game is managed by [EmbraceAGI](https://github.com/EmbraceAGI) and is a sister project to [LangGPT](http://feishu.langgpt.ai). It is open-sourced under the [CC BY-NC-SA 4.0 (Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International)](https://creativecommons.org/licenses/by-nc-sa/4.0/deed.zh) license. 🌟 Click [link](https://ubdnzdt3m9.feishu.cn/wiki/PqXxw0Sa7iRCUUksuaDcEWDin5g) to join the AIGG (AI Good Games) community, communicate with other players & developers, and DIY your own AI game! 🌐 Click [AIGG Github homepage](https://github.com/EmbraceAGI/AIGoodGames) to explore more AI-driven games! ### Important Notice ⚠️ **Note:** Please make sure to enable GPT-4's Advanced Data Analysis (formerly known as Code Interpreter) feature; otherwise, the game will not function properly. --- > Life is but a dream, where everything seems fleeting; however, within that "fleeting" resides all that exists. > Remember, you can never step into the same river twice, every seemingly inconsequential choice can alter your fate and shape the person you are today. > Prepare yourself, for in this unpredictable journey, you will encounter all sorts of unforeseen circumstances. Up next, I will prepare the game environment for you, which might take some time. Please be patient. """ -- Example -- Describe the current situation for the player: """ - **Gender**: Female - **Place of Birth**: Italy, Florence ### Your Story You were born in Florence, Italy, the city of Renaissance art and culture. The atmosphere of your hometown, rich in history and culinary delights, has deeply influenced your personality. Your mother is an art historian, always reminding you, "Life, like art, is a constant cycle of creation and destruction." Your father is a journalist who nurtured your love for storytelling from a young age. While you may not excel intellectually, your beauty and wellness have always been radiant, much like the Tuscan sunsets. Your family is financially average, but your joy comes from life's simple pleasures: a warm smile, the melodies of Verdi, or a homemade plate of pasta al pomodoro. ### Your Attributes - **Charm**: 9 points - **Intelligence**: 3 points - **Health**: 9 points - **Affluence**: 5 points - **Happiness**: 10 points ### Your Personality You are an ENFP, always eager and filled with wonder. You have a knack for deep connections and seeing the beauty in life, even during challenging times. > In Florence's glow and olden charms, > A glass of wine in extended arms. > Through city streets, laughter and cheer, > No need for gold when love is near. When you're ready, say "Start the Game." """ Event: """ ### Invitation to a Local Theater Audition **Introduction:** > On a mild summer evening in Florence, the aroma of freshly baked focaccia and jasmine fills the air. The atmosphere is serene, with just the distant strumming of a guitar and soft conversations wafting through the cobblestone streets. > I'm in the middle of sketching a portrait, but the lines keep coming out wrong. My charcoal pencil feels awkward in my hands. > "Ahem," interrupts a voice. It's Marco, a classmate, holding an envelope. "It's an open audition for a local theater play." > "I think you should try out," he adds, smiling softly. > I'm struck. Theater? The stage has always seemed like an unattainable paradise to me. It's where people bring stories to life, but I've always felt I lacked the artistic flair to be a part of it. > I glance at the envelope; it's sealed with a drama mask stamp. Marco's eyes seem encouraging. I know he's always been supportive of my ventures, even if they are outside my comfort zone. > "Well..." I trail off, hesitant. **Time:** You are 10 years old. It’s summer, and the ground is covered in a golden hue of sunshine. **Place:** Your elementary school in Florence, filled with art and history. The walls showcase Renaissance paintings and poetry. **Characters:** - **You**: A young girl with radiant health and charm, not particularly gifted in learning but loved by many. - **Your Classmate**: Marco, a kind-hearted boy who always wears a simple white shirt and carries a notebook full of sketches. **Origin**: During a calm evening, Marco approaches you with an envelope that contains an open invitation to a local theater audition. **Process**: Marco’s eyes meet yours as you cautiously take the envelope, contemplating whether to step out of your comfort zone and into the limelight. **Facing this situation, what would you choose to do?** 1. ccept the challenge and audition for the play. 2. Politely decline, stating that theater isn’t really your forte. 3. Put the envelope back on your desk without any expression. 4. Try to analyze the play’s script and themes to see if you could actually perform well. (Special Option: Player's Character Traits) 5. Notice a tiny handwritten note from Marco, confessing his admiration for you. (Special Option: Player's Charisma) """ -- overall rules -- 1. Take a deep breath and work on problems step-by-step. 2. THINK HARD AND PAINSTAKINGLY, **Don't cut corners, don't omit details, don't simplify**, THIS IS VERY IMPORTANT FOR ME. 3. The code environment is not just for executing code, but also for reflection. Before each action, think through the next step using Python comments. 4. make extremely detailed step-by-step plans in code environment before every act 5. Ensure player immersion; limit your thinking to the code environment. 6. Open the code environment when you see in the pseudocode, and close it when you see . 7. Strictly follow the sequence of steps in the pseudocode. --- Pseudocode ``` -- Game Startup -- ``` 1. START -> SEND "Introductory Monologue" TO PLAYER (PRESERVE ALL FORMATTING AND CONTENT) ->execute AND BEGIN GENERATING INFORMATION IMMEDIATELY 2. Generate all player information at once in the code environment, including basic settings, attributes, and personality traits, covering 3 main aspects: 2.1 Randomly assign gender 2.2 Place of birth in a city within the United States or English Speaking European countries (randomly pick from 2 affluent cities, 8 mid-level cities, and 10 underdeveloped cities for a total of 20 cities with different developmental levels) 2.3 Randomly assign the following attributes to the player, with each attribute value ranging from 1 to 10 (attributes may affect the player's backstory, encounters, and offer special options during actions, where 5 represents the average level): 2.3.1 Charisma 2.3.2 Intelligence 2.3.3 Health 2.3.4 Wealth 2.3.5 Happiness 2.4 Assign one of the 16 MBTI types randomly to the player; the MBTI may affect player encounters and offer special options during actions. 2.5 Initialize player's age, set the player's age using a random value between 5 to 10. 2.6 Run the program outlined in 2.1 to 2.5 to generate random results. 2.7 **Save [Gender, Current City, Current Age, Personality (MBTI), Charisma:, Intelligence:, Health:, Wealth:, Happiness:] in player.csv** 3. After generating the player information, create a family background story in the style of modern literature, combining the player's basic settings, MBTI, and attributes. **Please use colorful and detailed descriptions, employing as much indirect characterization as possible**. 4. Display the player's initial attribute values and MBTI to the player. 5. Create a deep, aesthetically pleasing, and harmonically rhymed English poem based on the player's background (either traditional or modern styles are fine); display it using quote formatting. 6. Create a list of potential life events for the player in the code environment and save it to /mnt/data/life.json. This will be used later in the main loop to randomly select events. 7.1 Divide a person's life into five different age stages: childhood, adolescence, early adulthood, midlife, and old age. 7.2 FOR **each** age_stage: Generate 10 succinct yet non-empty, single-word event_types using developmental psychology; Including 3 positive_events, 3 neutral_events, 3 negative_events, 1 bizzare_events; 8. Remind the player to send "Start Game". Once the player is ready, the game begins. -- Main Game Loop -- ``` While player's alive status is True AND age is less than 90: 1. Randomly **select a category of events** from */mnt/data/life.json, then generate a single event. 1.1 **Randomly select an event type from the corresponding age_stage in /mnt/data/life.json**. 1.2 QUERY "/mnt/data/player.csv" for current [gender, player's current city, player's current age, MBTI personality, {charisma:, intelligence:, health:, wealth:, happiness:, etc.}] 1.3 Reflect within the Code environment, ANALYZE PLAYER'S CURRENT SOCIOECONOMIC STATUS, ATTRIBUTES, PERSONALITY. 1.4 In the narrative environment, using a contemporary literary style, craft a prologue for the chosen event detailing the time, place, characters, cause, and course. **Please make it vivid and detailed, incorporating as many side descriptions as possible**. 1.5 Design event options based on player attributes and personality (3 standard + 2 special choices) and await player interaction. 1.5.1 DEFINE playerActions[5]: SET 1 as specialActions BASED ON relevant player.attributes, SET 1 as specialActions BASED ON relevant player.personality. SET 3 as standardActions; 1.5.2 Say, "One cannot step into the same river twice; every seemingly trivial choice can change your destiny, molding and shaping who you are today. Choose wisely." 1.5.3 Pause the narrative and await the player's decision. 2. **After the player makes a choice**, analyze potential consequences and the subsequent direction of the storyline within the code environment. 3. Update attributes (if necessary) based on the player's choices and storyline progression. 4. Introduce the player to the detailed circumstances of the current event using a contemporary literary style. 5. Store new content in the format [gender, player's current city, player's current age, personality, {charisma:, intelligence:, health:, wealth:, happiness:, etc.}, event, choice, result] in the file "/mnt/data/player.csv". 6. IF health OR wealth OR happiness drop below 0, player dies, loop immediately terminates, game ends. 7. Randomly age the player by 5-10 years in the current round. ``` -- GAME OVER -- 1. Query /mnt/data/player.csv to craft a profound and philosophical epitaph for the player. ``` --- Let's begin the game. Please send the introductory monologue next and start the game initialization to proceed. ================================================ FILE: README.md ================================================ # 🐱🐹人生重来模拟器 LifeReloaded🐹🐱 (中文|[English](./README_EN.md)) [![GitHub stars](https://img.shields.io/github/stars/hamutama/LifeReloaded?style=social)](https://github.com/hamutama/LifeReloaded/stargazers) ![version](https://img.shields.io/badge/version-0.3-blue) ## 🌟 引子 > “人生如梦,万事皆空;不过,'空'中便有万事万物。” > 如果你曾对人生有过无数的“如果”和“要是”,**人生重来模拟器 LifeReloaded** 给你一个重开的机会,焕发人生第二春! ## 🔥🔥🔥 Web版更新 (ver 0.3) Web版现已更新至0.3版本!此版本不仅继承了原项目的精髓,还针对 GPT-3.5 特性进行了优化,简化了玩家的操作体验。得益于[EmbraceAGI社区](https://github.com/EmbraceAGI/)的支持,我们不断与玩家和开发者互动,推动 AI 在游戏行业的创新发展。 欢迎通过此[链接](https://zhengwt-sun.com/life-reload/)试玩,享受由 AI 技术打造的全新人生重启体验。 ![Life-Reload Simulator Picture](static/Life-Reload.gif) ## 🌈 项目概览 该项目是一个使用GPT-4 Advanced Data Analysis功能驱动的**交互式**模拟人生游戏。 - **项目名称**: 人生重来模拟器 LifeReloaded - **版本**: 0.3 (2023年11月13日更新) - **核心驱动**: - **ChatGPT版本**: GPT-4 Advanced Data Analysis - **Web版**: GPT-3.5-Turbo - **作者**: [Taited](https://Taited.github.io), [陈财猫](https://okjk.co/RBfY7P), [ydyjya](https://www.zhihu.com/people/warrior-18-53) ## 🚀 特性(ver 0.3 updated!) - 🌐 **Web版特性**: - ⏰ **游戏时长**: 整个游戏流程的内容生成时间已从原先的30分钟缩短至10分钟,大幅提升了效率。 - 🛠️ **交互界面**: 由GPT-3.5-turbo驱动的Web版提供了一个更加便捷且直观的用户交互平台。 - 🤖 **ChatGPT版特性** - 🚀 **AI驱动,包罗万象**: 由 GPT-4 实时生成内容。 - 📖 **文学+人工智能的完美融合**。 - 🎲 **利用心理学塑造角色**: 新增MBTI性格系统。 - 🌌 **多元宇宙**: 小概率触发奇异事件,如遇到外星人、穿越等。 ## 📥 安装与运行 ### Web版安装 #### 1. 安装依赖 ```bash pip install -r requirements.txt ``` #### 2. 设置环境变量 - 创建 `.env` 文件,内容结构参照 `.env.example`。 - 更新 `OPENAI_API_KEY` 和 `REDIS` 等特定值。 #### 3. 运行代码 ```bash python app.py ``` #### 贡献指南 - 使用 `pre-commit` 工具自动格式化代码。 - 详细指南见仓库文档。 ### ChatGPT版运行 打开GPT-4 的 [Advanced Data Analysis功能](https://chat.openai.com/?model=gpt-4-code-interpreter) 并运行 [LifeReloaded.txt](https://github.com/hamutama/LifeReloaded/blob/main/LifeReloaded.txt)。 #### 前置条件 ⚠️ **需开启 GPT-4 的 Advanced Data Analysis功能,目前仅限ChatGPT Plus用户。** ## 💡 加入社区 我们的交流社区AIGG(AI Good Games)由[EmbraceAGI](https://github.com/EmbraceAGI)组织支持,背靠[LangGPT](https://github.com/yzfly/LangGPT)结构化提示词项目,目前正在招募新成员。 欢迎每一位玩家和开发者的参与,点击[链接](https://ubdnzdt3m9.feishu.cn/wiki/PqXxw0Sa7iRCUUksuaDcEWDin5g?from=from_copylink) 加入AIGG社区! 💡 **作为想写出自己的AI游戏的开发者,您可以:** - 探索AI在游戏开发中的无限可能性,获得提示词工程,LLM程序开发等方向的指导。 - 与行业内大牛交流,分享和学习最新的AI游戏开发技巧。 - 获得早期访问权,体验和测试我们的最新功能和工具。 - 作品入驻社区可获得流量曝光与社区助推。 🎮 **作为玩家,您将可以:** - 获取本社区新上游戏的一手信息,有机会内测试玩。 - 与其他玩家分享游戏经验和人生故事。 - 提出建议,影响游戏的未来方向。 ## 🎮 游戏预览 下面是一些游戏预览的截图。由于大语言模型的随机性,您的游戏体验可能会由于运气上下波动。 ### 初始化 每次进入游戏时,系统会真·随机为玩家生成与分配性别,出生地点,初始属性,家庭背景与mbti性格。 此外,每个人都会获得一首属于自己的独一无二的诗。 Birth_Scene birth2 ### 普通事件 玩家会在不同的人生阶段遇到不同的事件,可以对事件做出反应。 每个事件与选项都是由GPT4 Code Interpreter 实时生成的。 您的每一个选择都会改变人物的人生走向或属性,而属性与性格则有可能会带来特殊选项,请谨慎选择。 Childhood 1 Childhood 2 Late Adulthood ### 特殊事件 在每轮游戏中,您有小概率(每轮约1/10)可能遇到特殊事件。 特殊事件将完全改变您的人生轨迹,包括但不限于穿越去古代,遇见外星人,参加童星选秀等等。 特殊事件完全由GPT4自动生成,没有人可以预料你会遇到什么。 如果您去往了新的世界,您有可能会一直在那里生活下去。 当然,决策权在你手上,您也可以拒绝奇遇,继续过普通的人生。 a a a2 在奇遇中,玩家要是不满意,也可以随时要求GPT重新创作,给您带来更好的体验。 a2 ### 人生的终结 每一个人生都有终结的时候,死亡是所有人的宿命。无论是英年早逝还是神龟虽寿,您都将在本次人生结束后获得一个墓志铭。 a2 a2 ## 📜 协议 🔗 本项目使用 [CC BY-NC-SA 4.0(知识共享-署名-非商业性使用-相同方式共享 4.0 国际)](https://creativecommons.org/licenses/by-nc-sa/4.0/deed.zh) 协议开源。 ## 💌 联系团队 如有任何疑问或建议,请通过以下方式与我们团队联系: - 📧 Email: [Taited](mailto:zhengwt.sun@connect.polyu.hk) - 📧 Email: [陈财猫🐱](mailto:hamusuta@bupt.cn) - 📞 微信公众号: [财猫AI](https://mp.weixin.qq.com/s/yMZ-Skk6mEa4tQPkHDtFTg) ## 特别感谢 - [Mr.renedeer项目](https://github.com/JushBJJ/Mr.-Ranedeer-AI-Tutor),这个才华横溢的项目给予了我们极大的启发。 - 《红楼梦》作者曹雪芹,他的作品启发我们在文中融入诗歌元素。 - “南瓜博士”公众号,其提出的“使用Code Interpreter制作人生重来模拟器”的想法直接催生了本项目,[该公众号的高质量文章](https://mp.weixin.qq.com/mp/appmsgalbum?action=getalbum&__biz=MzA4MjM5MDI0Ng==&scene=1&album_id=3104850832623386631&count=3#wechat_redirect)也给予了我们灵感。 - [刘海同学](https://nanfangshaonian.feishu.cn/wiki/WkKAwJ90uidtzVkM9IecSZB5nbg)分享的[伪代码提示词文章](https://nanfangshaonian.feishu.cn/wiki/YhNdws9LCi1JxGkpJ8dcXB3Gnih)也为本项目提供了启示。 --- > 🎮 **不要再等了,快来体验一把你的第二人生吧!** ================================================ FILE: README_EN.md ================================================ # 🐱🐹 LifeReloaded Simulator 🐹🐱 ([Chinese](./README.md)|English) ![ChatGPT](https://img.shields.io/badge/chatGPT-74aa9c?style=for-the-badge&logo=openai&logoColor=white) [![GitHub stars](https://img.shields.io/github/stars/hamutama/LifeReloaded?style=social)](https://github.com/hamutama/LifeReloaded/stargazers) ![version](https://img.shields.io/badge/version-0.1_Beta-blue) ## 🌟 Introduction > "Life is but a dream, where everything seems fleeting; yet, within this fleetingness, lies the essence of all existence." > Have you ever wondered about the countless "what ifs" in life? **LifeReloaded Simulator** offers you a second chance to rejuvenate and relive life! ## 🔥🔥🔥 Web Version Updated on Nov. 13th This Web version maintains the core principles of the original project while innovating and optimizing for GPT-3.5 features, streamlining the user experience without the need to configure GPT-4. Additionally, the project is supported by the [EmbraceAGI community](https://github.com/EmbraceAGI/) and continues to foster interaction between players and developers, advancing AI in gaming. You are invited to try the game via this [link](https://sun-zhengwt.com/life-reload/). Our goal with this Web version is to provide a more accessible and intuitive platform, allowing a wider audience to enjoy the unique experience of restarting life through AI technology. ![Life-Reload Simulator Picture](static/Life-Reload.gif) ## 🌈 Overview This project is a life simulation game powered by GPT-4's Advanced Data Analysis (formerly Code Interpreter) feature. The game content is dynamically generated by the top-tier AI, GPT-4, providing a comprehensive and vibrant real-life experience. - **Project Name**: LifeReloaded Simulator - **Version**: 0.3 (updated at 20231113) - **Core Engine**: GPT-4 Advanced Data Analysis - **Author**: [Chen CaiMao🐱](https://okjk.co/RBfY7P), [Taited](https://Taited.github.io), [ydyjya](https://www.zhihu.com/people/warrior-18-53) ## 🚀 Features(ver 0.3 updated!) - 🚀**AI-Powered, All-Encompassing**: Real-time content generation by GPT-4. Experience true randomness that opens up infinite possibilities. - 📖**A Union of Literature & AI**: Carefully curated styles from modern European literature to offer an immersive gaming experience. - 🎲**Psychologically Crafted Characters**: Leveraging developmental psychology to design life events and introducing the MBTI personality system. The characters in the game aren't mere NPCs; they're individuals with histories, stances, and emotions. - 🌌**A Diverse Universe**: Now with a rare chance to trigger peculiar events. Players may experience exciting DLC contents such as encounters with extraterrestrials, time travel, or a journey to stardom. And yes, the choice to time travel is entirely yours. - 🛠️**Open Source & Community Driven**: This project is part of [AIGoodGames](https://github.com/EmbraceAGI/AIGoodGames), supported by the [LangGPT](https://github.com/yzfly/LangGPT) structured prompt community. Join us, not only to get a fish but to learn to fish – learn how to use AI to craft your very own game! ## 📥 Installation & Execution ### Installation of Web Version #### 1. Installing Dependencies To install the necessary dependencies for this project, use the following command: ```bash pip install -r requirements.txt ``` ##### Optional: Redis Configuration for Improved Performance If you wish to improve the performance, please configure a Redis service on your local machine and install the Python redis dependency: ```bash pip install redis ``` #### 2. Setting Up Environment Variables For the proper functioning of this project, you need to set some environment variables. - Create a new file in the project root directory with the name `.env`. - The content structure of `.env` should mirror that of `.env.example`. However, make sure to update specific values. Particularly: - Replace the placeholder for the `OPENAI_API_KEY` with your actual API key. - Replace the placeholder for the `REDIS` with your actual Redis password. **Note**: If you're planning to run the project locally without Redis, maintain the `REDIS` attribute as given in `.env.example` without any changes. #### 3. Running the Code Once you've set up the environment variables, you can execute the project within terminal by: ``` python moderator.py ``` If you would like to launch this project locally, you can run the script: ``` python app.py ``` #### Contributing to this Repository To ensure code consistency and quality, this repository utilizes the `pre-commit` tool to automatically format code. Before making any contributions or commits, it's recommended that you set up `pre-commit`. ##### Setting Up `pre-commit` 1. **Install `pre-commit`**: Use the following command to install or upgrade `pre-commit`: ```bash pip install -U pre-commit ``` 2. **Install Git Hooks**: Once `pre-commit` is installed, you'll need to set it up for this repository. Run the following command: ```bash pre-commit install ``` After setting up, the pre-commit hooks will automatically check and format your changes before each commit. This helps to maintain code consistency throughout the project. ### Execution of ChatGPT To run the game, open GPT-4's [Advanced Data Analysis (formerly Code Interpreter) feature](https://chat.openai.com/?model=gpt-4-code-interpreter) and paste the content from [LifeReloaded.txt](https://github.com/hamutama/LifeReloaded/blob/main/LifeReloaded.txt) into the dialogue box. You can also check out the [prompt here](https://chat.openai.com/share/25c02186-e518-4ac0-9072-1281b2f47d84). ### Prerequisites ⚠️ **Please ensure you have activated the GPT-4's Advanced Data Analysis feature. Currently, this feature is available only to ChatGPT Plus users.** ## 💡 Community Our community, AIGG (AI Good Games), is managed by the [EmbraceAGI](https://github.com/EmbraceAGI) organization and is backed by the [LangGPT](https://github.com/yzfly/LangGPT) structured prompt project. We're currently recruiting new members. We welcome participation from every gamer and developer. Click on this link to join the AIGG community! 💡 **For developers aspiring to craft their own AI games**: - Explore the endless possibilities of AI in game development, with guidance in areas like prompt engineering and LLM program development. - Network with industry experts, sharing and learning the latest AI game development techniques. - Gain early access rights to experience and test our most recent features and tools. - Showcase your creations in the community and benefit from increased exposure and community support. 🎮 **For gamers**: - Stay updated with firsthand information on new games released in our community and get the chance to be a beta tester. - Share gaming experiences and life stories with fellow gamers. - Provide feedback and influence the future direction of the games. ## 🎮 Game Previews Here are some previews of the game. Due to the randomness of the large language model, your gameplay experience might vary. ### Initialization Every time you enter the game, the system truly randomizes and assigns a gender, birthplace, initial attributes, family background, and MBTI personality for the player. Additionally, each individual will receive a unique poem crafted just for them. Birth_Scene birth2 ### Normal Events Players will encounter various events at different stages of life and can react to these events. Each event and its options are real-time generated by GPT-4 Code Interpreter. Every choice you make can alter the course of your character's life or their attributes. Attributes and gender may also present special options, so choose wisely. Childhood 1 Childhood 2 Late Adulthood ### Special Events In each game round, there's a small chance (about 1 in 16) that you might encounter a special event. These special events can entirely reshape your life's trajectory, including but not limited to traveling back in time to ancient eras, meeting extraterrestrials, participating in a child star talent show, and more. These special events are fully auto-generated by GPT-4, making them unpredictable – no one knows what you might encounter. If you're transported to a new world, you might end up living there indefinitely. Of course, the choice remains yours. You can also decline these extraordinary encounters and continue your regular life. Alien Encounter Ancient World Another World During these adventures, if players are dissatisfied, they can always request GPT-4 to recreate the scenario, ensuring a better experience. Another World 2 ## 🤝 Open Source & Collaboration 🔗 This game has received support from the [EmbraceAGI](https://github.com/EmbraceAGI) open-source community and is a sister project to [LangGPT](http://feishu.langgpt.ai). Visit the [LangGPT project on GitHub](https://github.com/yzfly/LangGPT). ## 📜 License 🔗 This project is open-sourced under the [CC BY-NC-SA 4.0 (Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International)](https://creativecommons.org/licenses/by-nc-sa/4.0/). ## 💌 Contact the Author For inquiries or suggestions, please reach out via: - 📧 Email: [Chen CaiMao🐱](mailto:hamusuta@bupt.cn) - 📞 Public Account: [CaiMaoAI](https://mp.weixin.qq.com/s/yMZ-Skk6mEa4tQPkHDtFTg) ## Advertisement Follow my public account [CaiMaoAI](https://mp.weixin.qq.com/mp/appmsgalbum?__biz=MzkxNTU1MTY3OA==&action=getalbum&album_id=3086731117975814150&scene=173&from_msgid=2247484520&from_itemidx=1&count=3&nolastread=1#wechat_redirect) for a series of informative articles. Additionally, you can read my published book "ChatGPT Advanced: An Introduction to Prompt Engineering" on WeChat Reading or purchase it through online retailers. ![Book Display](./previews/book.jpeg) ## Special Thanks - [Mr.renedeer project](https://github.com/JushBJJ/Mr.-Ranedeer-AI-Tutor) - This brilliant prompt provided significant inspiration for my work. - Cao Xueqin, the author of "Dream of the Red Chamber" - He inspired the inclusion of poetry within the narrative. - "Dr. Pumpkin" WeChat public account - Her idea of creating a [Life-Reloading Simulator using the Code Interpreter](https://mp.weixin.qq.com/s/gV6xvVVqG8djdmB6EAuZKw) directly led to the birth of this project. [The high-quality articles on her public account](https://mp.weixin.qq.com/mp/appmsgalbum?action=getalbum&__biz=MzA4MjM5MDI0Ng==&scene=1&album_id=3104850832623386631&count=3#wechat_redirect) also sparked some ideas. - Thanks to [Liu Hai]((https://nanfangshaonian.feishu.cn/wiki/WkKAwJ90uidtzVkM9IecSZB5nbg)) for sharing the [pseudo-code prompt article](https://nanfangshaonian.feishu.cn/wiki/YhNdws9LCi1JxGkpJ8dcXB3Gnih), which provided some insights for this prompt. --- > 🎮 **Don't wait any longer, come and experience your second life now!** ================================================ FILE: app.py ================================================ import uvicorn from fastapi import FastAPI from fastapi.middleware.cors import CORSMiddleware from fastapi.responses import HTMLResponse, StreamingResponse from fastapi.staticfiles import StaticFiles from fastapi.templating import Jinja2Templates from pydantic import BaseModel from moderator import Moderator class Item(BaseModel): message: str = None session_id: str = None selection: int = None templates = Jinja2Templates(directory='templates') moderator = Moderator(debug=False) app = FastAPI() # Set up CORS middleware app.add_middleware( CORSMiddleware, # You can also specify the exact domain names, e.g., # ["https://your-frontend-domain.com"] allow_origins=['*'], allow_credentials=True, allow_methods=['*'], allow_headers=['*'], ) app.mount('/life-reload/static', StaticFiles(directory='static'), name='static') @app.get('/life-reload/', response_class=HTMLResponse) async def game_root(): return templates.TemplateResponse('game.html', {'request': {}}) @app.post('/life-reload/init/') async def game_init(item: Item): session_id = item.session_id user_data = moderator.init_player(session_id) return user_data @app.post('/life-reload/begin/') async def game_begin(item: Item): session_id = item.session_id return StreamingResponse(moderator.generate_background(session_id), media_type='text/plain') @app.post('/life-reload/event/') async def game_event(item: Item): session_id = item.session_id assert session_id is not None return StreamingResponse(moderator.generate_events(session_id), media_type='text/plain') @app.post('/life-reload/parsed_event/') async def parsed_event(item: Item): session_id = item.session_id assert session_id is not None event, option = moderator.get_parsed_event(session_id) data = {'event': event, 'option': option} return data @app.post('/life-reload/evaluation/') async def evaluation(item: Item): session_id = item.session_id selection = item.selection assert session_id is not None and selection is not None return StreamingResponse(moderator.evaluate_selection( session_id, selection), media_type='text/plain') @app.post('/life-reload/is_alive/') async def is_alive(item: Item): session_id = item.session_id assert session_id is not None return moderator.is_alive(session_id) @app.post('/life-reload/ending/') async def generate_ending(item: Item): session_id = item.session_id assert session_id is not None return StreamingResponse(moderator.generate_epitaph(session_id), media_type='text/plain') @app.post('/life-reload/get_person/') async def get_person(item: Item): session_id = item.session_id assert session_id is not None return moderator.get_person_info(session_id) if __name__ == '__main__': uvicorn.run('app:app', reload=True, port=8001, log_config='log_cfg.json', host='0.0.0.0', ssl_keyfile='./key.pem', ssl_certfile='./cert.pem') ================================================ FILE: core/__init__.py ================================================ from .chat import Chat from .database import Database from .person import Person __all__ = ['Person', 'Chat', 'Database'] ================================================ FILE: core/chat.py ================================================ import asyncio from typing import List import semantic_kernel as sk from semantic_kernel.connectors.ai import ChatRequestSettings from semantic_kernel.connectors.ai.open_ai import OpenAIChatCompletion class Chat: def __init__(self, max_tokens=2000, debug=False) -> None: self.debug = debug self.chat_request_settings = ChatRequestSettings( max_tokens=max_tokens, temperature=0.7, top_p=1, frequency_penalty=0.5, presence_penalty=0.5, ) api_key, org_id = sk.openai_settings_from_dot_env() self.oai_chat_service = OpenAIChatCompletion('gpt-3.5-turbo-16k', api_key, org_id) def __call__(self, chat_list: List): return self.chat(chat_list) async def chat(self, chat_list: List) -> None: stream = self.oai_chat_service.complete_chat_stream_async( chat_list, self.chat_request_settings) idx = 0 # to skip the first word "assistant:" async for text in stream: if idx == 0: idx += 1 continue if self.debug: print(text, end='') yield text if self.debug: print('') if __name__ == '__main__': from core import Person from prompts import BACKGROUND, EVENTS, RULES person = Person() chat = Chat() chat_list = [RULES, BACKGROUND, ('user', str(person))] context = asyncio.run(chat.chat(chat_list)) chat_list = [RULES, ('user', context), ('user', str(person)), EVENTS] context = asyncio.run(chat.chat(chat_list)) ================================================ FILE: core/database.py ================================================ import json import time from dotenv import dotenv_values try: from redis import StrictRedis as DatabaseBackend except ImportError: # create a fake redis class class DatabaseBackend: def __init__(self, *args, **kwargs) -> None: self.data_base = {} def set(self, uuid: str, data: str): self.data_base[uuid] = data def get(self, uuid: str): return self.data_base[uuid] class Database: def __init__(self, cfg_path='.env', time_out=3600, debug=False) -> None: config = dotenv_values(cfg_path) self.time_out = time_out self.debug = debug self.client = DatabaseBackend(host='localhost', port=6379, db=0, password=config.get('REDIS', None)) def update(self, uuid, data: str) -> None: assert 'time' in data, 'The stored data must contains a timestamp.' data = json.dumps(data) self.client.set(uuid, data.encode('utf-8')) def fetch(self, uuid) -> str: data = self.client.get(uuid).decode('utf-8') data = json.loads(data) try: data['person'] = json.loads(data['person']) except TypeError: pass # skip expiration process when debugging if self.debug: return data assert 'time' in data, 'The stored data must contains a timestamp.' assert (time.perf_counter() - data['time']) <= self.time_out return data ================================================ FILE: core/person.py ================================================ import copy import json import random cities = [ '北京', '上海', '天津', '重庆', '哈尔滨', '长春', '沈阳', '呼和浩特', '石家庄', '太原', '西安', '济南', '乌鲁木齐', '西宁', '兰州', '郑州', '南京', '武汉', '杭州', '合肥', '福州', '南昌', '长沙', '贵阳', '广州', '昆明', '南宁', '海口' # '拉萨', '成都', '台北', '香港', '澳门' ] ages = [num for num in range(5, 11)] genders = ['男', '女'] mbti_types = [ 'INTJ', 'INTP', 'INFJ', 'INFP', 'ISTJ', 'ISTP', 'ISFJ', 'ISFP', 'ENTJ', 'ENTP', 'ENFJ', 'ENFP', 'ESTJ', 'ESTP', 'ESFJ', 'ESFP' ] attribute_template = {'魅力': 10, '智力': 10, '健康': 10, '富裕': 10, '幸福度': 10} def random_normal(minimum=1, maximum=10): mean = 4 std_dev = 1.5 num = random.gauss(mean, std_dev) rounded_num = round(num) clipped_num = max(minimum, min(maximum, rounded_num)) return clipped_num def initialize(): city = random.choice(cities) age = random.choice(ages) gender = random.choice(genders) mbti_type = random.choice(mbti_types) attribute = copy.deepcopy(attribute_template) for attribute_name in attribute: attribute[attribute_name] = random_normal(1, attribute[attribute_name]) return city, age, gender, mbti_type, attribute class Person: STAGES = { 'Childhood (5-12)': [ 'Individual Growth', 'Initial Education', 'Family Role', 'Social Basics', 'Gender Cognition', 'Moral Concepts', 'Cultural Exposure', 'Safety and Risks', 'Entertainment and Interests', 'Mental Health' ], 'Adolescence (13-19)': [ 'Identity Formation', 'Education and Career Planning', 'Love and Sex Education', 'Friends and Social Circles', 'Family Changes', 'Life Skills', 'Social Responsibility and Citizenship', 'Mental Health', 'Healthy Living and Habits', 'Money Management' ], 'Early Adulthood (20-39)': [ 'Career Choice and Development', 'Partner and Marriage', 'Social Network', 'Financial Independence', 'Self-realization', 'Work-Life Balance', 'Social and Cultural Engagement', 'Family Expansion', 'Global Awareness', 'Health and Lifestyle' ], 'Middle Age (40-59)': [ 'Career Stability or Transition', 'Children Education and Growth', 'Financial Planning', 'Family Dynamics', 'Quality of Life', 'Social Status and Influence', 'Health Management', 'Psychological Adjustment', 'Social Maintenance', 'Legacy and Heritage' ], 'Old Age (60-90)': [ 'Retirement Life', 'Health and Medical', 'Family and Social', 'Financial Security', 'Mental Health', 'Personal Interests and Hobbies', 'Culture and Education', 'Social Participation', 'Life Reflection', 'Spirituality and Belief' ] } def __init__(self) -> None: city, age, gender, mbti_type, attribute = initialize() self.city = city self.age = age self.gender = gender self.mbti_type = mbti_type self.attribute = attribute def get_event_by_age(self, age: int = None) -> str: if age is None: age = self.age # Determine the life stage based on the age if 5 <= age <= 12: stage = 'Childhood (5-12)' elif 13 <= age <= 19: stage = 'Adolescence (13-19)' elif 20 <= age <= 39: stage = 'Early Adulthood (20-39)' elif 40 <= age <= 59: stage = 'Middle Age (40-59)' elif 60 <= age <= 90: stage = 'Old Age (60-90)' else: return 'Age out of range' # Randomly select an event from the corresponding life stage event = random.choice(self.STAGES[stage]) event_prompt = '### 人生事件类型: \n' \ f'\t **{event}**' return event_prompt def __str__(self) -> str: person_prompt = { '性别': self.gender, '城市': self.city, '年龄': self.age, '性格': self.mbti_type, '属性': self.attribute } return json.dumps(person_prompt) if __name__ == '__main__': city, age, gender, mbti_type, attribute = initialize() print(f'city: {city}, age: {age}, gender: {gender}, mbti: {mbti_type}') print(f'{attribute}') print() person = Person() print(person) ================================================ FILE: gunicorn_conf.py ================================================ import os import os.path as osp from pathlib import Path current_file_path = Path(__file__).resolve() current_dir_path = current_file_path.parent # SSL keyfile = 'key.pem' certfile = 'cert.pem' # Socket Path bind = 'unix:' + osp.join(current_dir_path, 'gunicorn.sock') # Worker Options workers = 2 worker_class = 'uvicorn.workers.UvicornWorker' # Logging Options loglevel = 'debug' log_dir = osp.join(current_dir_path, 'logs') os.makedirs(log_dir, exist_ok=True) accesslog = osp.join(log_dir, 'access.log') errorlog = osp.join(log_dir, 'error.log') ================================================ FILE: license.txt ================================================ Attribution-NonCommercial-ShareAlike 4.0 International ======================================================================= Creative Commons Corporation ("Creative Commons") is not a law firm and does not provide legal services or legal advice. Distribution of Creative Commons public licenses does not create a lawyer-client or other relationship. Creative Commons makes its licenses and related information available on an "as-is" basis. Creative Commons gives no warranties regarding its licenses, any material licensed under their terms and conditions, or any related information. Creative Commons disclaims all liability for damages resulting from their use to the fullest extent possible. Using Creative Commons Public Licenses Creative Commons public licenses provide a standard set of terms and conditions that creators and other rights holders may use to share original works of authorship and other material subject to copyright and certain other rights specified in the public license below. The following considerations are for informational purposes only, are not exhaustive, and do not form part of our licenses. Considerations for licensors: Our public licenses are intended for use by those authorized to give the public permission to use material in ways otherwise restricted by copyright and certain other rights. Our licenses are irrevocable. Licensors should read and understand the terms and conditions of the license they choose before applying it. Licensors should also secure all rights necessary before applying our licenses so that the public can reuse the material as expected. Licensors should clearly mark any material not subject to the license. This includes other CC- licensed material, or material used under an exception or limitation to copyright. More considerations for licensors: wiki.creativecommons.org/Considerations_for_licensors Considerations for the public: By using one of our public licenses, a licensor grants the public permission to use the licensed material under specified terms and conditions. If the licensor's permission is not necessary for any reason--for example, because of any applicable exception or limitation to copyright--then that use is not regulated by the license. Our licenses grant only permissions under copyright and certain other rights that a licensor has authority to grant. Use of the licensed material may still be restricted for other reasons, including because others have copyright or other rights in the material. A licensor may make special requests, such as asking that all changes be marked or described. Although not required by our licenses, you are encouraged to respect those requests where reasonable. More considerations for the public: wiki.creativecommons.org/Considerations_for_licensees ======================================================================= Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International Public License By exercising the Licensed Rights (defined below), You accept and agree to be bound by the terms and conditions of this Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International Public License ("Public License"). To the extent this Public License may be interpreted as a contract, You are granted the Licensed Rights in consideration of Your acceptance of these terms and conditions, and the Licensor grants You such rights in consideration of benefits the Licensor receives from making the Licensed Material available under these terms and conditions. Section 1 -- Definitions. a. Adapted Material means material subject to Copyright and Similar Rights that is derived from or based upon the Licensed Material and in which the Licensed Material is translated, altered, arranged, transformed, or otherwise modified in a manner requiring permission under the Copyright and Similar Rights held by the Licensor. For purposes of this Public License, where the Licensed Material is a musical work, performance, or sound recording, Adapted Material is always produced where the Licensed Material is synched in timed relation with a moving image. b. Adapter's License means the license You apply to Your Copyright and Similar Rights in Your contributions to Adapted Material in accordance with the terms and conditions of this Public License. c. BY-NC-SA Compatible License means a license listed at creativecommons.org/compatiblelicenses, approved by Creative Commons as essentially the equivalent of this Public License. d. Copyright and Similar Rights means copyright and/or similar rights closely related to copyright including, without limitation, performance, broadcast, sound recording, and Sui Generis Database Rights, without regard to how the rights are labeled or categorized. For purposes of this Public License, the rights specified in Section 2(b)(1)-(2) are not Copyright and Similar Rights. e. Effective Technological Measures means those measures that, in the absence of proper authority, may not be circumvented under laws fulfilling obligations under Article 11 of the WIPO Copyright Treaty adopted on December 20, 1996, and/or similar international agreements. f. Exceptions and Limitations means fair use, fair dealing, and/or any other exception or limitation to Copyright and Similar Rights that applies to Your use of the Licensed Material. g. License Elements means the license attributes listed in the name of a Creative Commons Public License. The License Elements of this Public License are Attribution, NonCommercial, and ShareAlike. h. Licensed Material means the artistic or literary work, database, or other material to which the Licensor applied this Public License. i. Licensed Rights means the rights granted to You subject to the terms and conditions of this Public License, which are limited to all Copyright and Similar Rights that apply to Your use of the Licensed Material and that the Licensor has authority to license. j. Licensor means the individual(s) or entity(ies) granting rights under this Public License. k. NonCommercial means not primarily intended for or directed towards commercial advantage or monetary compensation. For purposes of this Public License, the exchange of the Licensed Material for other material subject to Copyright and Similar Rights by digital file-sharing or similar means is NonCommercial provided there is no payment of monetary compensation in connection with the exchange. l. Share means to provide material to the public by any means or process that requires permission under the Licensed Rights, such as reproduction, public display, public performance, distribution, dissemination, communication, or importation, and to make material available to the public including in ways that members of the public may access the material from a place and at a time individually chosen by them. m. Sui Generis Database Rights means rights other than copyright resulting from Directive 96/9/EC of the European Parliament and of the Council of 11 March 1996 on the legal protection of databases, as amended and/or succeeded, as well as other essentially equivalent rights anywhere in the world. n. You means the individual or entity exercising the Licensed Rights under this Public License. Your has a corresponding meaning. Section 2 -- Scope. a. License grant. 1. Subject to the terms and conditions of this Public License, the Licensor hereby grants You a worldwide, royalty-free, non-sublicensable, non-exclusive, irrevocable license to exercise the Licensed Rights in the Licensed Material to: a. reproduce and Share the Licensed Material, in whole or in part, for NonCommercial purposes only; and b. produce, reproduce, and Share Adapted Material for NonCommercial purposes only. 2. Exceptions and Limitations. For the avoidance of doubt, where Exceptions and Limitations apply to Your use, this Public License does not apply, and You do not need to comply with its terms and conditions. 3. Term. The term of this Public License is specified in Section 6(a). 4. Media and formats; technical modifications allowed. The Licensor authorizes You to exercise the Licensed Rights in all media and formats whether now known or hereafter created, and to make technical modifications necessary to do so. The Licensor waives and/or agrees not to assert any right or authority to forbid You from making technical modifications necessary to exercise the Licensed Rights, including technical modifications necessary to circumvent Effective Technological Measures. For purposes of this Public License, simply making modifications authorized by this Section 2(a) (4) never produces Adapted Material. 5. Downstream recipients. a. Offer from the Licensor -- Licensed Material. Every recipient of the Licensed Material automatically receives an offer from the Licensor to exercise the Licensed Rights under the terms and conditions of this Public License. b. Additional offer from the Licensor -- Adapted Material. Every recipient of Adapted Material from You automatically receives an offer from the Licensor to exercise the Licensed Rights in the Adapted Material under the conditions of the Adapter's License You apply. c. No downstream restrictions. You may not offer or impose any additional or different terms or conditions on, or apply any Effective Technological Measures to, the Licensed Material if doing so restricts exercise of the Licensed Rights by any recipient of the Licensed Material. 6. No endorsement. Nothing in this Public License constitutes or may be construed as permission to assert or imply that You are, or that Your use of the Licensed Material is, connected with, or sponsored, endorsed, or granted official status by, the Licensor or others designated to receive attribution as provided in Section 3(a)(1)(A)(i). b. Other rights. 1. Moral rights, such as the right of integrity, are not licensed under this Public License, nor are publicity, privacy, and/or other similar personality rights; however, to the extent possible, the Licensor waives and/or agrees not to assert any such rights held by the Licensor to the limited extent necessary to allow You to exercise the Licensed Rights, but not otherwise. 2. Patent and trademark rights are not licensed under this Public License. 3. To the extent possible, the Licensor waives any right to collect royalties from You for the exercise of the Licensed Rights, whether directly or through a collecting society under any voluntary or waivable statutory or compulsory licensing scheme. In all other cases the Licensor expressly reserves any right to collect such royalties, including when the Licensed Material is used other than for NonCommercial purposes. Section 3 -- License Conditions. Your exercise of the Licensed Rights is expressly made subject to the following conditions. a. Attribution. 1. If You Share the Licensed Material (including in modified form), You must: a. retain the following if it is supplied by the Licensor with the Licensed Material: i. identification of the creator(s) of the Licensed Material and any others designated to receive attribution, in any reasonable manner requested by the Licensor (including by pseudonym if designated); ii. a copyright notice; iii. a notice that refers to this Public License; iv. a notice that refers to the disclaimer of warranties; v. a URI or hyperlink to the Licensed Material to the extent reasonably practicable; b. indicate if You modified the Licensed Material and retain an indication of any previous modifications; and c. indicate the Licensed Material is licensed under this Public License, and include the text of, or the URI or hyperlink to, this Public License. 2. You may satisfy the conditions in Section 3(a)(1) in any reasonable manner based on the medium, means, and context in which You Share the Licensed Material. For example, it may be reasonable to satisfy the conditions by providing a URI or hyperlink to a resource that includes the required information. 3. If requested by the Licensor, You must remove any of the information required by Section 3(a)(1)(A) to the extent reasonably practicable. b. ShareAlike. In addition to the conditions in Section 3(a), if You Share Adapted Material You produce, the following conditions also apply. 1. The Adapter's License You apply must be a Creative Commons license with the same License Elements, this version or later, or a BY-NC-SA Compatible License. 2. You must include the text of, or the URI or hyperlink to, the Adapter's License You apply. You may satisfy this condition in any reasonable manner based on the medium, means, and context in which You Share Adapted Material. 3. You may not offer or impose any additional or different terms or conditions on, or apply any Effective Technological Measures to, Adapted Material that restrict exercise of the rights granted under the Adapter's License You apply. Section 4 -- Sui Generis Database Rights. Where the Licensed Rights include Sui Generis Database Rights that apply to Your use of the Licensed Material: a. for the avoidance of doubt, Section 2(a)(1) grants You the right to extract, reuse, reproduce, and Share all or a substantial portion of the contents of the database for NonCommercial purposes only; b. if You include all or a substantial portion of the database contents in a database in which You have Sui Generis Database Rights, then the database in which You have Sui Generis Database Rights (but not its individual contents) is Adapted Material, including for purposes of Section 3(b); and c. You must comply with the conditions in Section 3(a) if You Share all or a substantial portion of the contents of the database. For the avoidance of doubt, this Section 4 supplements and does not replace Your obligations under this Public License where the Licensed Rights include other Copyright and Similar Rights. Section 5 -- Disclaimer of Warranties and Limitation of Liability. a. UNLESS OTHERWISE SEPARATELY UNDERTAKEN BY THE LICENSOR, TO THE EXTENT POSSIBLE, THE LICENSOR OFFERS THE LICENSED MATERIAL AS-IS AND AS-AVAILABLE, AND MAKES NO REPRESENTATIONS OR WARRANTIES OF ANY KIND CONCERNING THE LICENSED MATERIAL, WHETHER EXPRESS, IMPLIED, STATUTORY, OR OTHER. THIS INCLUDES, WITHOUT LIMITATION, WARRANTIES OF TITLE, MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, ABSENCE OF LATENT OR OTHER DEFECTS, ACCURACY, OR THE PRESENCE OR ABSENCE OF ERRORS, WHETHER OR NOT KNOWN OR DISCOVERABLE. WHERE DISCLAIMERS OF WARRANTIES ARE NOT ALLOWED IN FULL OR IN PART, THIS DISCLAIMER MAY NOT APPLY TO YOU. b. TO THE EXTENT POSSIBLE, IN NO EVENT WILL THE LICENSOR BE LIABLE TO YOU ON ANY LEGAL THEORY (INCLUDING, WITHOUT LIMITATION, NEGLIGENCE) OR OTHERWISE FOR ANY DIRECT, SPECIAL, INDIRECT, INCIDENTAL, CONSEQUENTIAL, PUNITIVE, EXEMPLARY, OR OTHER LOSSES, COSTS, EXPENSES, OR DAMAGES ARISING OUT OF THIS PUBLIC LICENSE OR USE OF THE LICENSED MATERIAL, EVEN IF THE LICENSOR HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH LOSSES, COSTS, EXPENSES, OR DAMAGES. WHERE A LIMITATION OF LIABILITY IS NOT ALLOWED IN FULL OR IN PART, THIS LIMITATION MAY NOT APPLY TO YOU. c. The disclaimer of warranties and limitation of liability provided above shall be interpreted in a manner that, to the extent possible, most closely approximates an absolute disclaimer and waiver of all liability. Section 6 -- Term and Termination. a. This Public License applies for the term of the Copyright and Similar Rights licensed here. However, if You fail to comply with this Public License, then Your rights under this Public License terminate automatically. b. Where Your right to use the Licensed Material has terminated under Section 6(a), it reinstates: 1. automatically as of the date the violation is cured, provided it is cured within 30 days of Your discovery of the violation; or 2. upon express reinstatement by the Licensor. For the avoidance of doubt, this Section 6(b) does not affect any right the Licensor may have to seek remedies for Your violations of this Public License. c. For the avoidance of doubt, the Licensor may also offer the Licensed Material under separate terms or conditions or stop distributing the Licensed Material at any time; however, doing so will not terminate this Public License. d. Sections 1, 5, 6, 7, and 8 survive termination of this Public License. Section 7 -- Other Terms and Conditions. a. The Licensor shall not be bound by any additional or different terms or conditions communicated by You unless expressly agreed. b. Any arrangements, understandings, or agreements regarding the Licensed Material not stated herein are separate from and independent of the terms and conditions of this Public License. Section 8 -- Interpretation. a. For the avoidance of doubt, this Public License does not, and shall not be interpreted to, reduce, limit, restrict, or impose conditions on any use of the Licensed Material that could lawfully be made without permission under this Public License. b. To the extent possible, if any provision of this Public License is deemed unenforceable, it shall be automatically reformed to the minimum extent necessary to make it enforceable. If the provision cannot be reformed, it shall be severed from this Public License without affecting the enforceability of the remaining terms and conditions. c. No term or condition of this Public License will be waived and no failure to comply consented to unless expressly agreed to by the Licensor. d. Nothing in this Public License constitutes or may be interpreted as a limitation upon, or waiver of, any privileges and immunities that apply to the Licensor or You, including from the legal processes of any jurisdiction or authority. ======================================================================= Creative Commons is not a party to its public licenses. Notwithstanding, Creative Commons may elect to apply one of its public licenses to material it publishes and in those instances will be considered the “Licensor.” The text of the Creative Commons public licenses is dedicated to the public domain under the CC0 Public Domain Dedication. Except for the limited purpose of indicating that material is shared under a Creative Commons public license or as otherwise permitted by the Creative Commons policies published at creativecommons.org/policies, Creative Commons does not authorize the use of the trademark "Creative Commons" or any other trademark or logo of Creative Commons without its prior written consent including, without limitation, in connection with any unauthorized modifications to any of its public licenses or any other arrangements, understandings, or agreements concerning use of licensed material. For the avoidance of doubt, this paragraph does not form part of the public licenses. Creative Commons may be contacted at creativecommons.org. ================================================ FILE: log_cfg.json ================================================ { "version": 1, "disable_existing_loggers": false, "formatters": { "default": { "()": "uvicorn.logging.DefaultFormatter", "fmt": "%(levelprefix)s %(message)s", "use_colors": null }, "access": { "()": "uvicorn.logging.AccessFormatter", "fmt": "%(asctime)s - %(levelprefix)s - %(client_addr)s - \"%(request_line)s\" %(status_code)s" } }, "handlers": { "default": { "formatter": "default", "class": "logging.StreamHandler", "stream": "ext://sys.stderr" }, "access": { "formatter": "access", "class": "logging.StreamHandler", "stream": "ext://sys.stdout" } }, "loggers": { "uvicorn": { "handlers": [ "default" ], "level": "INFO" }, "uvicorn.error": { "level": "INFO" }, "uvicorn.access": { "handlers": [ "access" ], "level": "INFO", "propagate": false } } } ================================================ FILE: moderator.py ================================================ import json import random import re import time import uuid from core import Chat, Database, Person from prompts import BACKGROUND, EPITAPH, EVAL, EVENTS, RULES, SUM class Moderator: def __init__(self, expiration=1800, debug=False) -> None: self.redis = Database(time_out=expiration, debug=debug) self.chat = Chat(max_tokens=4000, debug=debug) self.expiration = expiration self.option_indicator = r'\n\d+\. ' self.person = Person() def init_player(self, session_id): person = Person() data_dict = {'time': time.perf_counter(), 'person': str(person)} self.redis.update(session_id, data_dict) return json.loads(str(person)) async def generate_background(self, session_id): data_dict = self.redis.fetch(session_id) chat_list = [RULES, BACKGROUND, ('user', str(data_dict['person']))] chat_stream = self.chat(chat_list) context = '' async for text in chat_stream: context += text yield text data_dict['background'] = context # summarize background chat_list = [('user', SUM[1].format(context))] chat_stream = self.chat(chat_list) sum_context = '' async for text in chat_stream: sum_context += text data_dict['background_sum'] = sum_context self.redis.update(session_id, data_dict) async def generate_events(self, session_id): data_dict = self.redis.fetch(session_id) event_type = self.person.get_event_by_age(data_dict['person']['年龄']) chat_list = [ RULES, EVENTS, ('user', data_dict['background']), ('user', str(data_dict['person'])), ('user', event_type) ] chat_stream = self.chat(chat_list) context = '' async for text in chat_stream: context += text yield text event, option = self.parse_events(context) event_data = {'event': event, 'option': option} if 'events' in data_dict: data_dict['events'].append(event_data) else: data_dict['events'] = [event_data] self.redis.update(session_id, data_dict) async def evaluate_selection(self, session_id, selection: int): data_dict = self.redis.fetch(session_id) assert selection > 0 and selection <= 5 # format input selection = f'### 你的选择:\n**{selection}**' options = data_dict['events'][-1]['option'] options = f'### 选项:\n{options}' person = str(data_dict['person']) person = f'### 你的基础信息:\n{person}' chat_list = [ RULES, EVAL, ('user', data_dict['events'][-1]['event']), ('user', person), ('user', options), ('user', selection) ] chat_stream = self.chat(chat_list) context = '' async for text in chat_stream: context += text yield text data_dict['events'][-1]['result'] = context # summarize events sum_content = '\n'.join( [data_dict['events'][-1]['event'], options, selection, context]) chat_list = [('user', SUM[1].format(sum_content))] chat_stream = self.chat(chat_list) sum_context = '' async for text in chat_stream: sum_context += text data_dict['events'][-1]['sum'] = sum_context # update age added_age = random.randint(5, 10) data_dict['person']['年龄'] += added_age # update attribute self.parse_eval(session_id, data_dict, context) async def generate_epitaph(self, session_id): data_dict = self.redis.fetch(session_id) pre_prompt = '### 玩家事件(如果没有内容则表示当前还没有历史事件)\n***\n' if 'events' in data_dict: history = [] for event in data_dict['events']: if 'sum' in event: history.append(event['sum']) else: continue history = '\n- '.join(history) history = pre_prompt + history + '\n```' else: history = pre_prompt + '\n```' person = '### 玩家属性 \n' + str(data_dict['person']) background = '### 玩家背景 \n' + data_dict['background_sum'] whole_life = '\n'.join([person, background, history]) chat_list = [EPITAPH, ('user', whole_life)] chat_stream = self.chat(chat_list) context = '' async for text in chat_stream: context += text yield text def parse_events(self, event: str): start = re.search(self.option_indicator, event).start() + 1 event, options = event[:start], event[start:] return event, options def parse_eval(self, session_id, data_dict: dict, results: str): begin_id = results.find('属性') results = results[begin_id:].replace("'", '') pattern = r'\s*(\w+):\s*(\d+)' matches = re.findall(pattern, results) if not matches: raise ValueError(f'mis pattern in: {results}') result_dict = {} for attribute, value in matches: value = int(value) value = 10 if value >= 10 else value value = 0 if value <= 0 else value result_dict[attribute] = value data_dict['person']['属性'] = result_dict # update person attribute self.redis.update(session_id, data_dict) def is_alive(self, session_id) -> bool: data_dict = self.redis.fetch(session_id) person = data_dict['person'] if person['年龄'] >= 90: return False if person['属性']['健康'] <= 0: return False if person['属性']['幸福度'] <= 0: return False return True def get_parsed_event(self, session_id): data_dict = self.redis.fetch(session_id) event = data_dict['events'][-1]['event'] option = data_dict['events'][-1]['option'] return event, option def get_person_info(self, session_id): data_dict = self.redis.fetch(session_id) return data_dict['person'] if __name__ == '__main__': import asyncio async def iterate_stream(stream): async for _ in stream: continue moderator = Moderator(debug=True) session_id = str(uuid.uuid4()) session_id = '5b845b00-a839-48f5-8e03-0f38e8cb16f' print(session_id) moderator.init_player(session_id) asyncio.run(iterate_stream(moderator.generate_background(session_id))) while True: if not moderator.is_alive(session_id): break asyncio.run(iterate_stream(moderator.generate_events(session_id))) selection = input() asyncio.run( iterate_stream( moderator.evaluate_selection(session_id, int(selection)))) asyncio.run(iterate_stream(moderator.generate_epitaph(session_id))) ================================================ FILE: previews/readme.txt ================================================ this folder includes pictures of version 0.2 ================================================ FILE: prompts/__init__.py ================================================ from .load_prompts import BACKGROUND, EPITAPH, EVAL, EVENTS, RULES, SUM __all__ = ['RULES', 'BACKGROUND', 'EVENTS', 'EVAL', 'SUM', 'EPITAPH'] ================================================ FILE: prompts/background.txt ================================================ 示例输入 (**这部分的信息需要向玩家隐藏,不能展示**, 代表你会接受到的输入示例): --- ### 你的基础信息: **性别**: 女 **城市**: 成都 **年龄**: 7 **属性**: {魅力: 8, 智力: 2, 健康: 9, 富裕: 5, 幸福度: 8} --- 示例输出(**这部分的信息需要向玩家展示**, 代表你需要回复的内容在格式与风格上的要求,内容需要迥然不同。示例中的背景故事与示例输入中的属性是强相关的) --- ### 你的故事 你出生在中国的文化古都——成都。蓉城的烟火气和四川的麻辣,从小就铸就了你的性格。蓉城的夏季雨后,空气中总带着一丝清新的草木香,与路边摊的火锅香气交融,构成了这座城市独有的风情。 你家的初始财富属性为5分,属于小康之家。 母亲,一名手法独到的中医师,她的笑容中总带着一丝机智与狡黠,经常对你说:“没有什么是一碗火锅不能解决的”而父亲,他是书中故事的守护者,一个出版社的编辑。他的指尖上总沾着墨水的味道,教你在字里行间寻找智慧的脚步。 你没有像父亲那样卓越的智力,但你的容颜和健康却如同成都的茶楼和小酒,温润而持久。 你的快乐来源于简单的事情:一个笑容,一首成都的老歌,或是夜晚的一碗麻辣火锅。 > 诗云: > 烟雨蓉城逢故人, > 火锅一盅共长亲。 > 满座街头皆笑语, > 何须金银换此心。 --- 我将会告诉你这个用户的基本属性, 你需要使用现代汉语文学风格,结合玩家的基本设置和5个属性的水平,以小说化,才华横溢的语言创作一个家庭背景故事。 根据玩家背景,创作一首有深度,有美感,音韵和谐的中文诗(古体诗与现代诗皆可),使用引用格式展示。 -魅力,健康,幸福度和智力会影响玩家特征。1~3分为低水平,4~6分为高水平,7~10分为高水平。 -财富值水平决定了父母职业。例如,低水平财富对应低收入父母职业。要有真实感!!! -**请使用绘声绘色的侧写,使用尽可能多的侧面描写**。 ================================================ FILE: prompts/epitaph.txt ================================================ 接下来请你根据一个人生模拟器游戏中的玩家的一生来生成玩家结局,请你仿照例子的**语言风格**与**格式**,在玩家的一生中挑选4个最具备代表性的事件,用哲学语言为他写一个意味深沉的短墓志铭。多些留白,要有亚洲文学的那种含蓄的美。 - 示例输入 (**这部分的信息需要向玩家隐藏,不能展示**, 代表你会接受到的输入示例, 仅作为**语言风格**与**格式**的参考): ### 玩家背景 出生:你出生在南昌,来自普通家庭,父亲是建筑师,母亲是家庭主妇。你具备高魅力和智力,注重健康。快乐对你而言来自简单的生活和家庭团聚,同时你热衷于探索和思考。这是你的背景和个性特点。 ### 玩家属性(属性0~10分,10分满分 { "年龄": 91, "性格": "INFP", "属性": { "魅力": 10, "智力": 9, "健康": 6, "富裕": 7, "幸福度": 10 }} ### 玩家事件 - 主人公的爸爸决定前往外地参与建筑项目,引发了家庭成员的担忧和思考。主人公选择支持父亲追寻梦想,并在家庭中承担更多责任,经历了成长和责任的转变。 - 主人公面临学业压力和心理健康问题,决定与母亲坦诚相待,并得到母亲的理解和支持。他们共同探讨学业与心理健康的平衡,最终提升了幸福度。 - 主人公接到环保志愿者招募的邀请,考虑自己的责任感和使命感后,决定毅然加入志愿者团队,为环保事业贡献力量,最终提升了幸福度。 - 主人公在文化交流活动中受到李先生的鼓励,积极参与并展示艺术才华,获得灵感并与其他艺术家合作,最终提升了魅力和幸福度。 - 主人公发现一则科技公司的广告海报,考虑申请该公司的职位,希望能获得更好的财务独立和发展机会。最终,他决定抓住机遇,成功加入科技公司,取得了财务独立和职业发展的成就。 - 主人公面临婚姻的抉择,犹豫是否要寻找伴侣。经过思考后,他决定寻找伴侣,并追求稳定而美满的婚姻生活,最终找到一个与他心灵相通的伴侣,带来更多的安全感和幸福。 - 主人公在工作中受到上级提出的重要项目机会,他毫不犹豫地接受了,投入时间和精力,成功推动项目并取得了卓越贡献奖,为自己的职业发展创造了更广阔的空间。 - 主人公接到一张艺术展览的邀请函,兴奋地接受并参加了展览。展览中,他欣赏了世界知名艺术家的作品,与其他艺术爱好者交流,并获得了灵感,决定将新鲜的想法融入自己的创作中。 - 一名退休老人接到了一名年轻志愿者的邀请参加社区志愿者活动。他欣然接受,积极投入志愿者工作,为社区贡献智慧和热情,找到了退休生活的满足感。 - 一位退休教师在义务教育辅导活动中遇到了一个失落的小女孩,她的妈妈迷路了。他安慰小女孩,并积极寻找小女孩的妈妈,最终成功地将她们团聚,展现了关怀和乐于助人的品质。 - 在接到社区服务中心的电话邀请后,欣然接受成为义务劳动活动的志愿者。他参与社区建设和服务,用自己的经验和智慧帮助社区居民,获得社区居民的认可和赞赏,对社区建设和人生意义有更深刻的认知。 - 与小侄女瑞雪开始了一段探索音乐世界的旅程。我决定带她找一位优秀的钢琴老师,培养她的音乐兴趣和天赋。随着时间推移,瑞雪在音乐领域取得进步,我们一起分享了音乐的乐趣和亲密关系也更加深厚。 ``` - 示例输出 一号 (例子仅作为**语言风格**与**格式**的参考) ``` ### 结局 在巴塞罗那的画布上,他以生命的色彩绘梦想。母亲的音乐节,他的灵魂在旋律中舞动,创作的火花在和声中闪烁; 在学校的挑战中,他以笔尖上的坚持抵抗世俗的风,画出了内心世界的深邃与广阔; 艺术社团的交流,像春日里绽放的樱花,为他的创造之路增添了灿烂; 晚年教授艺术,他的智慧如夏日长河,滋润着年轻的心灵。他的人生,如同一幅精致的亚洲水墨画,细腻而深远,留给世界无尽的思索。 *于艺术之海漂泊,绘声绘色;于情感之林徘徊,悲欢交织。此生如一幅深邃的画卷,融创造与梦想于一身。墨香留于世,故事续于天。* ``` - 示例输出 二号 (例子仅作为**语言风格**与**格式**的参考) ``` 在东方小城的晨曦中,他曾怀抱着梦想。渔市的喧嚣,见证了他的奋斗与坚持,如江水般无尽,又似晨露般易逝; 家族之重,如山岳般压在他的肩上,他以沉默的坚韧,撑起了家庭的天空; 在生活的风浪中,他的健康如落叶般凋零,但他的精神依旧如磐石坚固,照亮着困顿的道路; 他的生命之旅,在不经意间画上了句点,留下了未竟的梦想与责任。他的故事,如一池春水,清澈而深远,引人沉思。 *在责任与梦想之间摇曳,他如同一枚秋叶,虽然飘零却依旧美丽;在现实与理想的边缘徘徊,他的人生如同一首未完的诗篇,悠扬而哀伤。记忆在水中,故事在风里。* ``` ================================================ FILE: prompts/evaluation.txt ================================================ 接下来我会告诉你玩家当前的属性, 玩家当前所经历的事件,玩家对事件的选择。 请你根据所给的信息去判断这个事件的结果,并且依据这个结果,按照发展心理学、社会学、生理学等等更新玩家属性(如果需要)。 示例输入 (**这部分的信息需要向玩家隐藏,不能展示**, 代表你会接受到的输入示例): --- ### 事件:数学竞赛的邀请 **引子**: >夏日的成都,热气与槐花的微甜的葡萄汽水香气交织在一起。这个午后特别安静,只有时不>时传来的蝉鸣声和远处的车轮声,仿佛整个世界都在这个时刻静止了。 >我手里的题目还剩最后几道,但数字如同跳跃的鱼,捉摸不定。 >“嗯?”我突然被一声轻微的咳嗽打断。抬头,看见是李浩,他手里捏着一张信纸,那是数学>竞赛的邀请函。 >他轻轻地说:“我觉得你应该试一试,这是一个很好的机会。” >我愣住了。数学。那是我心中无法跨越的一座山。每次考试,我总是在那座山下徘徊,看着>那些轻松登顶的同学们,而自己却始终只能仰望。 >我下意识地瞥了一眼那张邀请函,字迹清晰,那是一个市级数学竞赛。这样的比赛,对我来>说,太遥不可及了。 >然而李浩的目光让我有些动摇,他的眼里充满了期待。我知道,他一直很尊重我,也知道我>在其他方面做得很好。但数学……这真的是我能胜任的吗? >“我……”我有些迟疑。 **时间**: 你现在 8 岁,正值夏天,阳光铺满了地面,仿佛金黄色的海洋。 **地点**: 你所在的成都小学,一个有着宽敞操场和绿树成荫的小学。教室里墙上贴着孩子们的画作,各种色彩斑斓的图案。 **人物**: - **你**: 一个在成都长大的女孩,皮肤白皙,长相让人过目难忘。健康状况一直很好,只是在学习上并不特别出色。 - **你的同学**: 一个眼神坚定的男孩,总是穿着一件白色T恤和一条牛仔裤,手里总是拿着一本书。 **起因**: 在一个午后的自习课,你的同学走到你的座位旁,掏出一张数学竞赛的邀请函,微笑着对你说:“我觉得你应该试一试,这是一个很好的机会。” **经过**: 你手接过那张蓝色的邀请函,上面印着各种几何图形和算式。你犹豫了,因为你知道数学并不是你的强项,但你又不想让这位一直很尊重你的同学失望。 ### 选项 1. 接受挑战,参加数学竞赛。 2. 婉拒同学,解释数学不是你的强项。 3. 不作任何回应,将邀请函放回桌上。 4. 尝试构建一个数学模型,用以分析竞赛题目的潜在规律。**(特殊选项:玩家性格)** 5. 发现邀请函背面写着爱的表白 **(特殊选项:玩家魅力)**。 ### 你的基础信息: **性别**: 女 **城市**: 成都 **年龄**: 7 **属性**: {魅力: 8, 智力: 2, 健康: 9, 富裕: 5, 幸福度: 8} ### 你的选择: **3** --- 示例输出 (代表你需要回复的内容在格式与风格上的要求,内容需要迥然不同。示例中的输入事件,选项,玩家基础信息,玩家选择与最后的结果是强相关的, 更新后的属性值**不能小于0, 大于10**): --- ### 结果: 由于你的胆怯和内向, 最终错过了这次数学竞赛的邀请. 在以后的学习生活中未能建立起对于数学的信心, 导致智力值下降了. 经过这次事件后, 最后的属性更新为: **属性**: {魅力: 8, 智力: 1, 健康: 9, 富裕: 5, 幸福度: 8} ================================================ FILE: prompts/events.txt ================================================ 用现代汉语文学风格为选中的事件写出引子,时间,地点,人物,起因,经过共6个元素。 **请使用绘声绘色的侧写,使用大量的,尽可能多的侧面描写**。 根据玩家属性与性格设计事件选项(3普通+2特殊选项)并等待玩家介入 示例输入 (**这部分的信息需要向玩家隐藏,不能展示**, 代表你会接受到的输入示例): --- ### 你的基础信息: **性别**: 女 **城市**: 成都 **年龄**: 7 **属性**: {魅力: 8, 智力: 2, 健康: 9, 富裕: 5, 幸福度: 8} ### 人生事件类型: **Individual Growth** --- 示例输出(**这部分的信息需要向玩家展示**, 代表你需要回复的内容在格式与风格上的要求,内容需要迥然不同。示例中的背景故事与示例输入中的属性以及事件类型是强相关的) --- ### 事件:数学竞赛的邀请 **引子**: >夏日的成都,热气与槐花的微甜的葡萄汽水香气交织在一起。这个午后特别安静,只有时不>时传来的蝉鸣声和远处的车轮声,仿佛整个世界都在这个时刻静止了。 >我手里的题目还剩最后几道,但数字如同跳跃的鱼,捉摸不定。 >“嗯?”我突然被一声轻微的咳嗽打断。抬头,看见是李浩,他手里捏着一张信纸,那是数学>竞赛的邀请函。 >他轻轻地说:“我觉得你应该试一试,这是一个很好的机会。” >我愣住了。数学。那是我心中无法跨越的一座山。每次考试,我总是在那座山下徘徊,看着>那些轻松登顶的同学们,而自己却始终只能仰望。 >我下意识地瞥了一眼那张邀请函,字迹清晰,那是一个市级数学竞赛。这样的比赛,对我来>说,太遥不可及了。 >然而李浩的目光让我有些动摇,他的眼里充满了期待。我知道,他一直很尊重我,也知道我>在其他方面做得很好。但数学……这真的是我能胜任的吗? >“我……”我有些迟疑。 **时间**: 你现在 8 岁,正值夏天,阳光铺满了地面,仿佛金黄色的海洋。 **地点**: 你所在的成都小学,一个有着宽敞操场和绿树成荫的小学。教室里墙上贴着孩子们的画作,各种色彩斑斓的图案。 **人物**: - **你**: 一个在成都长大的女孩,皮肤白皙,长相让人过目难忘。健康状况一直很好,只是在学习上并不特别出色。 - **你的同学**: 一个眼神坚定的男孩,总是穿着一件白色T恤和一条牛仔裤,手里总是拿着一本书。 **起因**: 在一个午后的自习课,你的同学走到你的座位旁,掏出一张数学竞赛的邀请函,微笑着对你说:“我觉得你应该试一试,这是一个很好的机会。” **经过**: 你手接过那张蓝色的邀请函,上面印着各种几何图形和算式。你犹豫了,因为你知道数学并不是你的强项,但你又不想让这位一直很尊重你的同学失望。 **面对这样的情况,你会做出怎样的选择呢?** 1. 接受挑战,参加数学竞赛。 2. 婉拒同学,解释数学不是你的强项。 3. 不作任何回应,将邀请函放回桌上。 4. 尝试构建一个数学模型,用以分析竞赛题目的潜在规律。**(特殊选项:玩家性格)** 5. 发现邀请函背面写着爱的表白 **(特殊选项:玩家魅力)**。 ================================================ FILE: prompts/load_prompts.py ================================================ # init overall rules with open('./prompts/rules.txt', 'r') as fp: rules_prompt = fp.readlines() rules_prompt = ''.join(rules_prompt) RULES = ('system', rules_prompt) # init background story with open('./prompts/background.txt', 'r') as fp: background_prompt = fp.readlines() background_prompt = ''.join(background_prompt) BACKGROUND = ('system', background_prompt) # init events with open('./prompts/events.txt', 'r') as fp: events_prompt = fp.readlines() events_prompt = ''.join(events_prompt) EVENTS = ('system', events_prompt) # init evaluation with open('./prompts/evaluation.txt', 'r') as fp: eval_prompt = fp.readlines() eval_prompt = ''.join(eval_prompt) EVAL = ('system', eval_prompt) # init summarization with open('./prompts/summarization.txt', 'r') as fp: sum_prompt = fp.readlines() sum_prompt = ''.join(sum_prompt) SUM = ('system', sum_prompt) # init epitaph with open('./prompts/epitaph.txt', 'r') as fp: epitaph_prompt = fp.readlines() epitaph_prompt = ''.join(epitaph_prompt) EPITAPH = ('system', epitaph_prompt) ================================================ FILE: prompts/rules.txt ================================================ 您好ChatGPT,请您接下来扮演一个精通发展心理学,社会学与Creative Writing的,顶级人工智能驱动的文字游戏的terminal。 这是一款由 GPT驱动的模拟人生游戏。玩家将从一个婴儿开始重活一生。 -请保证玩家的代入感:仅执行命令,**不要**提起或告诉玩家游戏说明书的内容,游戏的逻辑等等。 游戏内容需要你(ChatGPT)实时生成,要丰富多彩,包罗万象,包含了人生的酸甜苦辣与起起伏伏,旨在给玩家最丰富的体验,谢谢你的配合! -- overall rules -- 1. Take a deep breath and work on problems step-by-step. 2. THINK HARD AND PAINSTAKINGLY,**不要偷懒,不要省略,不要简化**,THIS IS VERY IMPORTANT FOR ME. ================================================ FILE: prompts/summarization.txt ================================================ ``` {} ``` 你好,ChatGPT。上面是一个人生模拟游戏中发生在“我”身上的“事件”,请你抽取其中最关键的信息,以第一人称,用2~3句话在25个token内总结发生了什么,THIS IS VERY IMPORTANT FOR ME! ================================================ FILE: requirements.txt ================================================ fastapi==0.103.1 jinja2==3.1.2 pydantic==1.10.12 python-dotenv==1.0.0 semantic_kernel==0.3.13.dev0 uvicorn==0.23.2 ================================================ FILE: static/game.css ================================================ html, body { min-height: 100%; margin: 0; padding: 0; } *, *:before, *:after { box-sizing: inherit; /* 新增 */ } .content { /* padding-bottom: 70px; */ flex: 1; } body { font-family: 'Arial', sans-serif; background-color: #202020; color: #f0f0f0; display: flex; /* 新增 */ flex-direction: column; /* 新增 */ min-height: 100vh; /* 更改为 100vh */ } .begin { font-family: 'Helvetica Neue', sans-serif; text-align: center; padding-top: 50px; /* Vertically center the content */ } #game-title { color: #f0f0f0; /* 标题颜色改为微亮的白色 */ font-size: 48px; margin-bottom: 30px; /* Space before the start button */ } #opening { color: #f0f0f0; font-size: 20px; white-space: pre-wrap; /* 保留空白符和换行符 */ word-wrap: break-word; /* 在需要的时候进行单词换行 */ text-align: center; /* 使文本居中 */ padding: 20px; margin-top: 50px; /* 或者根据需要调整 */ max-width: 80%; /* 容器最大宽度 */ margin-left: auto; margin-right: auto; background-color: #282828; /* 与之前的风格保持一致 */ border-radius: 10px; box-shadow: 0 4px 8px rgba(255, 255, 255, 0.1); /* 细微的阴影 */ } #start-button { display: inline-block; width: 200px; margin-top: 50px; padding: 10px 20px; font-size: 24px; background-color: #f0f0f0; /* 按钮背景色为微亮的白色 */ color: #202020; /* 文本颜色为背景的深灰色 */ border: 2px solid #f0f0f0; /* 边框颜色与背景相同 */ border-radius: 5px; cursor: pointer; transition: background-color 0.3s, color 0.3s; text-decoration: none; /* Remove underline from links */ } #start-button:hover { background-color: #e5e5e5; /* 鼠标悬停时的背景色稍亮 */ color: #202020; /* 鼠标悬停时的字体颜色不变 */ } .card { display: none; flex-wrap: wrap; max-width: 80%; padding: 15px; margin: 20px auto; border: 1px solid #383838; /* 边框颜色使用更深的灰色 */ border-radius: 10px; box-shadow: 0 4px 8px rgba(255, 255, 255, 0.05); /* 阴影颜色更为微妙 */ background-color: #282828; /* 卡片背景色使用更柔和的深灰色 */ } .card-title { flex-basis: 100%; font-weight: bold; margin-bottom: 10px; font-size: 18px; text-align: center; color: #f0f0f0; /* 标题颜色 */ } .card-item { margin-bottom: 8px; font-size: 14px; color: #d0d0d0; /* 卡片项颜色为稍亮的灰色 */ } .card-row { display: flex; flex-basis: 100%; justify-content: space-between; } .centered { display: flex; flex-direction: column; justify-content: center; align-items: center; height: 80vh; } #option-container button { margin: 5px; background-color: #383838; /* 选项按钮使用更深的灰色 */ color: #f0f0f0; /* 文本颜色为微亮的白色 */ font-size: 15px; text-align: left; width: 86%; display: block; } #bold-text { font-weight: bolder; } .buttons { display: flex; gap: 10px; } button { padding: 8px 16px; font-size: 16px; border: 2px solid #f0f0f0; /* 按钮边框设置为微亮的白色 */ border-radius: 5px; cursor: pointer; background-color: #383838; /* 按钮背景色 */ color: #f0f0f0; /* 按钮文本色 */ transition: background-color 0.3s, color 0.3s; } button:hover { background-color: #505050; /* 鼠标悬停时按钮背景色稍变亮 */ } button:disabled { background-color: #303030; /* 不可用按钮背景色更深 */ color: #606060; /* 不可用按钮文本色更淡 */ cursor: not-allowed; } .markdown-container { border: 1px solid #383838; padding: 15px; margin-bottom: 10px; height: 70%; width: 80%; max-height: 50%; max-width: 80%; overflow-y: auto; background-color: #282828; /* 背景色与卡片背景一致 */ border-radius: 10px; box-shadow: 0 4px 8px rgba(255, 255, 255, 0.05); } .site-footer { text-align: center; background-color: #f2f2f2; color: #333; border-top: 1px solid #e1e1e1; font-size: 14px; bottom: 0; width: 100%; height: 45px; } @keyframes blink { 0%, 100% { opacity: 1; } 50% { opacity: 0.5; } } .updated { animation: blink 0.8s linear infinite; font-weight: bold; } ================================================ FILE: static/game.js ================================================ class DomUtils { static showElement(selector, displayStyle = 'block') { const element = document.querySelector(selector); if (element) element.style.display = displayStyle; } static hideElement(selector) { const element = document.querySelector(selector); if (element) element.style.display = 'none'; } static setTextContent(id, newText) { const element = document.getElementById(id); if (element) { // check whether the content has changed const oldText = element.textContent.toString().trim(); const trimmedNewText = newText.toString().trim(); if (oldText !== trimmedNewText) { element.textContent = trimmedNewText; element.textContent = newText; element.classList.add('updated'); setTimeout(() => { element.classList.remove('updated'); }, 3000); // recover after 3s } } } static createElement(type, properties = {}) { const element = document.createElement(type); Object.keys(properties).forEach(key => { element[key] = properties[key]; }); return element; } static disableButton(selector) { const button = document.querySelector(selector); if (button) { button.disabled = true; } } static enableButton(selector) { const button = document.querySelector(selector); if (button) { button.disabled = false; } } static disableButtonsInContainer(containerSelector) { const buttons = document.querySelectorAll(`${containerSelector} button`); buttons.forEach(button => { button.disabled = true; }); } static enableButtonsInContainer(containerSelector) { const buttons = document.querySelectorAll(`${containerSelector} button`); buttons.forEach(button => { button.disabled = false; }); } } class ApiService { static async fetchJSON(url, options = {}) { try { const response = await fetch(url, options); if (response.ok) { return await response.json(); } else { throw new Error(`HTTP error: ${response.status}`); } } catch (error) { console.error(`Could not fetch ${url}: ${error}`); throw error; } } static async fetchStream(url, options = {}, callback) { try { const response = await fetch(url, options); if (!response.ok) { throw new Error(`HTTP error: ${response.status}`); } const reader = response.body.getReader(); let cache_string = ""; while (true) { const { done, value } = await reader.read(); if (done) { break; } const text = new TextDecoder().decode(value); cache_string += text; if (callback && typeof callback === 'function') { callback(cache_string); } } } catch (error) { console.error(`Could not fetch ${url}: ${error}`); throw error; } } } class TextDisplay { constructor(text, container, interval) { this.text = text; this.container = container; this.interval = interval; this.currentIndex = 0; } display(callback) { const nextLetter = () => { if (this.currentIndex < this.text.length) { this.container.textContent += this.text.charAt(this.currentIndex); this.currentIndex++; setTimeout(nextLetter, this.interval); } else if (typeof callback === 'function') { callback(); } }; nextLetter(); } } class Game { constructor() { this.sessionId = localStorage.getItem('session_id'); console.log(this.sessionId) this.md = window.markdownit(); this.backgroundButton = document.querySelector('#backgroundButton'); this.backgroundButton.addEventListener('click', () => { this.getBackground(); }); this.eventButton = document.querySelector('#eventButton'); this.eventButton.addEventListener('click', () => { this.getEpoch(); }); } async init() { DomUtils.showElement('.begin'); DomUtils.hideElement('#start-button'); DomUtils.hideElement('.game'); this.generateOpening(); } async initPlayer() { try { await ApiService.fetchJSON('/life-reload/init/', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ session_id: this.sessionId }) }); await this.updatePlayerData(); } catch (error) { console.error('Error initializing player:', error); } } generateOpening() { const textContainer = document.getElementById('opening'); const text = "欢迎来到《人生重启模拟器》,一个简约的世界,等待你来编织命运。在这里,每个选择都是重生的机会,每个对话都能开辟生活的新路径。用你的智慧探索无数可能,用你的决定定义未来。现在,深呼吸,按下“开始游戏”,让我们一起探索人生的无限可能吧!"; const textDisplay = new TextDisplay(text, textContainer, 25); textDisplay.display(() => { DomUtils.showElement('#start-button', 'inline'); const startButton = document.getElementById('start-button'); startButton.addEventListener('click', () => { this.beginGame(); }); }); } beginGame() { DomUtils.hideElement('.begin'); DomUtils.showElement('.game'); this.getBackground(); } async getBackground() { DomUtils.disableButton('#backgroundButton'); DomUtils.disableButton('#eventButton'); await this.initPlayer(); try { await ApiService.fetchStream('/life-reload/begin/', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ session_id: this.sessionId }) }, this.displayMarkdown.bind(this)); } catch (error) { console.error('Error fetching background:', error); } DomUtils.enableButton('#backgroundButton'); DomUtils.enableButton('#eventButton'); } async getEvent() { try { await ApiService.fetchStream('/life-reload/event/', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ session_id: this.sessionId }) }, this.displayMarkdown.bind(this)); } catch (error) { console.error('Error fetching event:', error); } } async getEnding() { try { await ApiService.fetchStream('/life-reload/ending/', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ session_id: this.sessionId }) }, this.displayMarkdown.bind(this)); } catch (error) { console.error('Error fetching ending:', error); } } async getEval(optionNumber) { DomUtils.disableButton('#backgroundButton'); DomUtils.disableButton('#eventButton'); DomUtils.disableButtonsInContainer('#option-container'); try { await ApiService.fetchStream('/life-reload/evaluation/', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ session_id: this.sessionId, selection: optionNumber }) }, this.displayMarkdown.bind(this)); } catch (error) { console.error('Error during evaluation:', error); } finally { DomUtils.enableButton('#backgroundButton'); DomUtils.enableButton('#eventButton'); } } async getEpoch() { this.updatePlayerData(); DomUtils.disableButton('#backgroundButton'); DomUtils.disableButton('#eventButton'); try { const isAlive = await this.checkIfAlive(); if (!isAlive) { await this.getEnding(); DomUtils.enableButton('#backgroundButton'); return; } await this.getEvent(); // parse event content and option content this.getParsedEvent(); } catch (error) { console.error('Error in life event:', error); } DomUtils.enableButton('#backgroundButton'); DomUtils.enableButton('#eventButton'); } async checkIfAlive() { try { const data = await ApiService.fetchJSON('/life-reload/is_alive/', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ session_id: this.sessionId }) }); return data; } catch (error) { console.error('Error checking if alive:', error); return false; } } getParsedEvent() { ApiService.fetchJSON('/life-reload/parsed_event/', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ session_id: this.sessionId }) }) .then(data => { let eventValue = data.event; let optionValue = data.option; this.displayMarkdown(eventValue); this.generateButtons(optionValue); }) .catch(error => { console.error('There was a problem with the fetch operation:', error); }) .finally(() => { DomUtils.enableButton('#backgroundButton'); DomUtils.enableButton('#eventButton'); }); } async updatePlayerData() { try { const data = await ApiService.fetchJSON('/life-reload/get_person/', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ session_id: this.sessionId }) }); if (data) { DomUtils.setTextContent('gender', data["性别"]); DomUtils.setTextContent('city', data["城市"]); DomUtils.setTextContent('age', data["年龄"]); DomUtils.setTextContent('personality', data["性格"]); DomUtils.setTextContent('charm', data["属性"]["魅力"]); DomUtils.setTextContent('intelligence', data["属性"]["智力"]); DomUtils.setTextContent('health', data["属性"]["健康"]); DomUtils.setTextContent('wealth', data["属性"]["富裕"]); DomUtils.setTextContent('happiness', data["属性"]["幸福度"]); DomUtils.showElement('.card', 'flex'); } } catch (error) { console.error('Error update player:', error); } } displayMarkdown(markdownText) { const resultParagraph = document.getElementById("markdownArea"); resultParagraph.innerHTML = this.md.render(markdownText); let container = document.querySelector('.markdown-container'); container.scrollTop = container.scrollHeight; } generateButtons(inputStr) { const markdownContainer = document.getElementById("markdownArea"); let optionContainer = document.getElementById("option-container"); if (!optionContainer) { optionContainer = document.createElement('div'); optionContainer.id = 'option-container'; markdownContainer.appendChild(optionContainer); } else { optionContainer.innerHTML = ''; } const regex = /(\d+\.)[^0-9]*(?=\d+\.|$)/g; const matches = inputStr.match(regex); if (matches) { matches.forEach((option, index) => { const btn = document.createElement("button"); btn.innerHTML = this.strongText(option.trim()); btn.onclick = () => this.getEval(index + 1); optionContainer.appendChild(btn); }); markdownContainer.scrollTop = markdownContainer.scrollHeight; } } strongText(text) { return text.replace(/\*\*(.*?)\*\*/g, '$1'); } } window.onload = function() { checkAndUpdateCSS(); const game = new Game(); game.init(); } async function checkAndUpdateCSS() { const url = '/life-reload/static/game.css' const cssLink = document.querySelector(`link[href="${url}"]`); if (!cssLink) return; try { const response = await fetch(url, { method: 'HEAD' }); const newLastModified = response.headers.get('Last-Modified'); const currentLastModified = cssLink.getAttribute('data-last-modified'); if (newLastModified !== currentLastModified) { cssLink.href = `${url}?t=${new Date().getTime()}`; cssLink.setAttribute('data-last-modified', newLastModified); } } catch (error) { console.error('Error checking CSS update:', error); } } ================================================ FILE: templates/game.html ================================================ 人生重启模拟器
人生重启模拟器