diff --git a/examples/game/app.py b/examples/game/app.py index a174cafda..d015c2fea 100644 --- a/examples/game/app.py +++ b/examples/game/app.py @@ -24,6 +24,36 @@ glb_history_chat = [] MAX_NUM_DISPLAY_MSG = 20 +import base64 +# 图片本地路径转换为 base64 格式 +def covert_image_to_base64(image_path): + # 获得文件后缀名 + ext = image_path.split('.')[-1] + if ext not in ['gif', 'jpeg', 'png']: + ext = 'jpeg' + + with open(image_path, 'rb') as image_file: + # Read the file + encoded_string = base64.b64encode(image_file.read()) + + # Convert bytes to string + base64_data = encoded_string.decode('utf-8') + + # 生成base64编码的地址 + base64_url = f'data:image/{ext};base64,{base64_data}' + return base64_url + +def format_cover_html(config: dict, bot_avatar_path='assets/bg.png'): + image_src = covert_image_to_base64(bot_avatar_path) + return f""" +
+
+ +
+
{config.get("name", "经营餐厅")}
+
{config.get("description", "快来经营你的餐厅吧")}
+
+""" def export_chat_history(): timestamp = datetime.datetime.now().strftime("%Y-%m-%d_%H-%M-%S") @@ -74,11 +104,26 @@ def start_game(): except ResetException: print("重置成功") - with gr.Blocks() as demo: + with gr.Blocks(css='assets/app.css') as demo: # Users can select the interested exp + welcome = { + "name": "饮食男女", + "description": "这是一款模拟餐馆经营的文字冒险游戏, 快来开始吧😊" + } + + user_chat_bot_cover = gr.HTML(format_cover_html(welcome)) + chatbot = GroupChat(label="Dialog", show_label=False, height=600, visible=False) + with gr.Row(): - chatbot = GroupChat(label="Dialog", show_label=False, height=600) + with gr.Column(): + new_button = gr.Button( + value="🚀新的探险", + ) + with gr.Column(): + resume_button = gr.Button( + value="🔥续写情缘", + ) with gr.Row(): with gr.Column(): @@ -87,13 +132,14 @@ def start_game(): placeholder="想说点什么", show_label=False, interactive=True, + visible=False, ) user_chat_bot_suggest = gr.Dataset( label="选择一个", components=[user_chat_input], samples=[], - visible=True, + visible=False, ) user_chat_bot_suggest.select( @@ -104,17 +150,21 @@ def start_game(): with gr.Column(): send_button = gr.Button( - value="发送", + value="📣发送", + visible=False ) - with gr.Accordion("导出选项", open=False): + export = gr.Accordion("导出选项", open=False, visible=False) + with export: with gr.Column(): export_button = gr.Button("导出完整游戏记录") export_output = gr.File(label="下载完整游戏记录", visible=False) - reset_button = gr.Button( - value="重置", - ) + return_welcome_button = gr.Button( + value="↩️返回首页", + visible=False, + ) + def send_message(msg): send_player_input(msg) send_chat_msg(msg, "你") @@ -143,14 +193,60 @@ def update_suggest(): visible=True, ) - outputs = [chatbot, user_chat_bot_suggest] + def game_ui(): + visible = True + invisible = False + return {chatbot:GroupChat(visible=visible), + user_chat_input: gr.Text(visible=visible), + send_button: gr.Button(visible=visible), + new_button: gr.Button(visible=invisible), + resume_button: gr.Button(visible=invisible), + return_welcome_button: gr.Button(visible=visible), + user_chat_bot_suggest: gr.Dataset( + components=[user_chat_input], + visible=visible, + ), + export: gr.Accordion(visible=visible), + user_chat_bot_cover:gr.HTML(visible=invisible)} + + def welcome_ui(): + visible = True + invisible = False + return {chatbot:GroupChat(visible=invisible), + user_chat_input: gr.Text(visible=invisible), + send_button: gr.Button(visible=invisible), + new_button: gr.Button(visible=visible), + resume_button: gr.Button(visible=visible), + return_welcome_button: gr.Button(visible=invisible), + user_chat_bot_suggest: gr.Dataset( + components=[user_chat_input], + visible=invisible, + ), + export: gr.Accordion(visible=invisible), + user_chat_bot_cover:gr.HTML(visible=visible)} + + outputs = [chatbot, user_chat_input, send_button, new_button, resume_button,return_welcome_button, user_chat_bot_suggest, export, user_chat_bot_cover] + + # submit message send_button.click(send_message, user_chat_input, user_chat_input) - reset_button.click(send_reset_message) - export_button.click(export_chat_history, [], export_output) user_chat_input.submit(send_message, user_chat_input, user_chat_input) - demo.load(get_chat, inputs=None, outputs=chatbot, every=0.5) + + # change ui + new_button.click(game_ui, outputs=outputs) + resume_button.click(game_ui, outputs=outputs) + return_welcome_button.click(welcome_ui, outputs=outputs) + + # start game + new_button.click(send_reset_message) + new_button.click(start_game) + resume_button.click(start_game) + + # export + export_button.click(export_chat_history, [], export_output) + + # update chat history + demo.load(get_chat, outputs=chatbot, every=0.5) demo.load(update_suggest, outputs=user_chat_bot_suggest, every=0.5) - demo.load(start_game) demo.queue() demo.launch() diff --git a/examples/game/assets/app.css b/examples/game/assets/app.css new file mode 100644 index 000000000..93b031c74 --- /dev/null +++ b/examples/game/assets/app.css @@ -0,0 +1,147 @@ +/* code highlight: https://python-markdown.github.io/extensions/code_hilite/ */ +.codehilite .hll { background-color: #ffffcc } +.codehilite { background: #f8f8f8; } +.codehilite .c { color: #408080; font-style: italic } /* Comment */ +.codehilite .err { border: 1px solid #FF0000 } /* Error */ +.codehilite .k { color: #008000; font-weight: bold } /* Keyword */ +.codehilite .o { color: #666666 } /* Operator */ +.codehilite .ch { color: #408080; font-style: italic } /* Comment.Hashbang */ +.codehilite .cm { color: #408080; font-style: italic } /* Comment.Multiline */ +.codehilite .cp { color: #BC7A00 } /* Comment.Preproc */ +.codehilite .cpf { color: #408080; font-style: italic } /* Comment.PreprocFile */ +.codehilite .c1 { color: #408080; font-style: italic } /* Comment.Single */ +.codehilite .cs { color: #408080; font-style: italic } /* Comment.Special */ +.codehilite .gd { color: #A00000 } /* Generic.Deleted */ +.codehilite .ge { font-style: italic } /* Generic.Emph */ +.codehilite .gr { color: #FF0000 } /* Generic.Error */ +.codehilite .gh { color: #000080; font-weight: bold } /* Generic.Heading */ +.codehilite .gi { color: #00A000 } /* Generic.Inserted */ +.codehilite .go { color: #888888 } /* Generic.Output */ +.codehilite .gp { color: #000080; font-weight: bold } /* Generic.Prompt */ +.codehilite .gs { font-weight: bold } /* Generic.Strong */ +.codehilite .gu { color: #800080; font-weight: bold } /* Generic.Subheading */ +.codehilite .gt { color: #0044DD } /* Generic.Traceback */ +.codehilite .kc { color: #008000; font-weight: bold } /* Keyword.Constant */ +.codehilite .kd { color: #008000; font-weight: bold } /* Keyword.Declaration */ +.codehilite .kn { color: #008000; font-weight: bold } /* Keyword.Namespace */ +.codehilite .kp { color: #008000 } /* Keyword.Pseudo */ +.codehilite .kr { color: #008000; font-weight: bold } /* Keyword.Reserved */ +.codehilite .kt { color: #B00040 } /* Keyword.Type */ +.codehilite .m { color: #666666 } /* Literal.Number */ +.codehilite .s { color: #BA2121 } /* Literal.String */ +.codehilite .na { color: #7D9029 } /* Name.Attribute */ +.codehilite .nb { color: #008000 } /* Name.Builtin */ +.codehilite .nc { color: #0000FF; font-weight: bold } /* Name.Class */ +.codehilite .no { color: #880000 } /* Name.Constant */ +.codehilite .nd { color: #AA22FF } /* Name.Decorator */ +.codehilite .ni { color: #999999; font-weight: bold } /* Name.Entity */ +.codehilite .ne { color: #D2413A; font-weight: bold } /* Name.Exception */ +.codehilite .nf { color: #0000FF } /* Name.Function */ +.codehilite .nl { color: #A0A000 } /* Name.Label */ +.codehilite .nn { color: #0000FF; font-weight: bold } /* Name.Namespace */ +.codehilite .nt { color: #008000; font-weight: bold } /* Name.Tag */ +.codehilite .nv { color: #19177C } /* Name.Variable */ +.codehilite .ow { color: #AA22FF; font-weight: bold } /* Operator.Word */ +.codehilite .w { color: #bbbbbb } /* Text.Whitespace */ +.codehilite .mb { color: #666666 } /* Literal.Number.Bin */ +.codehilite .mf { color: #666666 } /* Literal.Number.Float */ +.codehilite .mh { color: #666666 } /* Literal.Number.Hex */ +.codehilite .mi { color: #666666 } /* Literal.Number.Integer */ +.codehilite .mo { color: #666666 } /* Literal.Number.Oct */ +.codehilite .sa { color: #BA2121 } /* Literal.String.Affix */ +.codehilite .sb { color: #BA2121 } /* Literal.String.Backtick */ +.codehilite .sc { color: #BA2121 } /* Literal.String.Char */ +.codehilite .dl { color: #BA2121 } /* Literal.String.Delimiter */ +.codehilite .sd { color: #BA2121; font-style: italic } /* Literal.String.Doc */ +.codehilite .s2 { color: #BA2121 } /* Literal.String.Double */ +.codehilite .se { color: #BB6622; font-weight: bold } /* Literal.String.Escape */ +.codehilite .sh { color: #BA2121 } /* Literal.String.Heredoc */ +.codehilite .si { color: #BB6688; font-weight: bold } /* Literal.String.Interpol */ +.codehilite .sx { color: #008000 } /* Literal.String.Other */ +.codehilite .sr { color: #BB6688 } /* Literal.String.Regex */ +.codehilite .s1 { color: #BA2121 } /* Literal.String.Single */ +.codehilite .ss { color: #19177C } /* Literal.String.Symbol */ +.codehilite .bp { color: #008000 } /* Name.Builtin.Pseudo */ +.codehilite .fm { color: #0000FF } /* Name.Function.Magic */ +.codehilite .vc { color: #19177C } /* Name.Variable.Class */ +.codehilite .vg { color: #19177C } /* Name.Variable.Global */ +.codehilite .vi { color: #19177C } /* Name.Variable.Instance */ +.codehilite .vm { color: #19177C } /* Name.Variable.Magic */ +.codehilite .il { color: #666666 } /* Literal.Number.Integer.Long */ + +.preview_header { + font-size: 18px; + font-weight: 500; + text-align: center; + margin-bottom: -12px; +} + +.bot_cover { + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + min-height: 650px; + border: 1px solid rgb(229, 231, 235); + border-radius: 8px; + padding: 20px 40px; +} + +.bot_avatar { + width: 100px; + height: 100px; + border-radius: 50%; + overflow: hidden; +} + +.bot_avatar img { + width: 150px; + height: 150px; +} + +.bot_name { + font-size: 36px; + margin-top: 10px; +} + +.bot_desc { + color: #ddd; +} + +.publish_link_container > a { + display: block; + border-radius: var(--button-large-radius); + padding: var(--button-large-padding); + font-weight: var(--button-large-text-weight); + font-size: var(--button-large-text-size); + border: var(--button-border-width) solid var(--button-secondary-border-color); + background: var(--button-secondary-background-fill); + color: var(--button-secondary-text-color) !important; + cursor: pointer; + text-decoration: none !important; + text-align: center; +} + +.publish_link_container > .disabled { + cursor: not-allowed; + opacity: .5; + filter: grayscale(30%); +} + +.markdown-body .message { + white-space: pre-wrap; +} + +.markdown-body details { + white-space: nowrap; +} +.markdown-body .bot details:not(:last-child) { + margin-bottom: 1px; +} +.markdown-body summary { + background-color: #4b5563; + color: #eee; + padding: 0 4px; + border-radius: 4px; + font-size: 0.9em; +} diff --git a/examples/game/assets/bg.png b/examples/game/assets/bg.png new file mode 100644 index 000000000..ffb0ca21e Binary files /dev/null and b/examples/game/assets/bg.png differ