wwwillchen commited on
Commit
bb4138d
·
1 Parent(s): d7640ce

Completed - part 3

Browse files
Files changed (3) hide show
  1. data_model.py +36 -0
  2. dialog.py +46 -0
  3. main.py +96 -15
data_model.py ADDED
@@ -0,0 +1,36 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from dataclasses import dataclass, field
2
+ from typing import Literal
3
+ from enum import Enum
4
+
5
+ import mesop as me
6
+
7
+ Role = Literal["user", "model"]
8
+
9
+ @dataclass(kw_only=True)
10
+ class ChatMessage:
11
+ role: Role = "user"
12
+ content: str = ""
13
+ in_progress: bool = False
14
+
15
+ class Models(Enum):
16
+ GEMINI_1_5_FLASH = "Gemini 1.5 Flash"
17
+ GEMINI_1_5_PRO = "Gemini 1.5 Pro"
18
+ CLAUDE_3_5_SONNET = "Claude 3.5 Sonnet"
19
+
20
+ @dataclass
21
+ class Conversation:
22
+ model: str = ""
23
+ messages: list[ChatMessage] = field(default_factory=list)
24
+
25
+ @me.stateclass
26
+ class State:
27
+ is_model_picker_dialog_open: bool = False
28
+ input: str = ""
29
+ conversations: list[Conversation] = field(default_factory=list)
30
+ models: list[str] = field(default_factory=list)
31
+ gemini_api_key: str = ""
32
+ claude_api_key: str = ""
33
+
34
+ @me.stateclass
35
+ class ModelDialogState:
36
+ selected_models: list[str] = field(default_factory=list)
dialog.py ADDED
@@ -0,0 +1,46 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import mesop as me
2
+
3
+ @me.content_component
4
+ def dialog(is_open: bool):
5
+ with me.box(
6
+ style=me.Style(
7
+ background="rgba(0,0,0,0.4)",
8
+ display="block" if is_open else "none",
9
+ height="100%",
10
+ overflow_x="auto",
11
+ overflow_y="auto",
12
+ position="fixed",
13
+ width="100%",
14
+ z_index=1000,
15
+ )
16
+ ):
17
+ with me.box(
18
+ style=me.Style(
19
+ align_items="center",
20
+ display="grid",
21
+ height="100vh",
22
+ justify_items="center",
23
+ )
24
+ ):
25
+ with me.box(
26
+ style=me.Style(
27
+ background="#fff",
28
+ border_radius=20,
29
+ box_sizing="content-box",
30
+ box_shadow=(
31
+ "0 3px 1px -2px #0003, 0 2px 2px #00000024, 0 1px 5px #0000001f"
32
+ ),
33
+ margin=me.Margin.symmetric(vertical="0", horizontal="auto"),
34
+ padding=me.Padding.all(20),
35
+ )
36
+ ):
37
+ me.slot()
38
+
39
+ @me.content_component
40
+ def dialog_actions():
41
+ with me.box(
42
+ style=me.Style(
43
+ display="flex", justify_content="end", margin=me.Margin(top=20)
44
+ )
45
+ ):
46
+ me.slot()
main.py CHANGED
@@ -1,4 +1,69 @@
1
  import mesop as me
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2
 
3
  ROOT_BOX_STYLE = me.Style(
4
  background="#e7f2ff",
@@ -15,23 +80,18 @@ ROOT_BOX_STYLE = me.Style(
15
  ],
16
  )
17
  def page():
 
18
  with me.box(style=ROOT_BOX_STYLE):
19
  header()
20
  with me.box(
21
  style=me.Style(
22
  width="min(680px, 100%)",
23
- margin=me.Margin.symmetric(
24
- horizontal="auto",
25
- vertical=36,
26
- ),
27
  )
28
  ):
29
  me.text(
30
  "Chat with multiple models at once",
31
- style=me.Style(
32
- font_size=20,
33
- margin=me.Margin(bottom=24),
34
- ),
35
  )
36
  chat_input()
37
 
@@ -51,13 +111,11 @@ def header():
51
  ),
52
  )
53
 
54
- @me.stateclass
55
- class State:
56
- input: str = ""
57
-
58
- def on_blur(e: me.InputBlurEvent):
59
  state = me.state(State)
60
- state.input = e.value
 
 
61
 
62
  def chat_input():
63
  state = me.state(State)
@@ -82,10 +140,33 @@ def chat_input():
82
  border=me.Border.all(me.BorderSide(style="none")),
83
  ),
84
  )
85
- with me.content_button(type="icon", on_click=send_prompt):
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
86
  me.icon("send")
87
 
 
 
 
 
88
  def send_prompt(e: me.ClickEvent):
89
  state = me.state(State)
90
  print(f"Sending prompt: {state.input}")
 
91
  state.input = ""
 
1
  import mesop as me
2
+ from data_model import State, Models, ModelDialogState
3
+ from dialog import dialog, dialog_actions
4
+
5
+ def change_model_option(e: me.CheckboxChangeEvent):
6
+ s = me.state(ModelDialogState)
7
+ if e.checked:
8
+ s.selected_models.append(e.key)
9
+ else:
10
+ s.selected_models.remove(e.key)
11
+
12
+ def set_gemini_api_key(e: me.InputBlurEvent):
13
+ me.state(State).gemini_api_key = e.value
14
+
15
+ def set_claude_api_key(e: me.InputBlurEvent):
16
+ me.state(State).claude_api_key = e.value
17
+
18
+ def model_picker_dialog():
19
+ state = me.state(State)
20
+ with dialog(state.is_model_picker_dialog_open):
21
+ with me.box(style=me.Style(display="flex", flex_direction="column", gap=12)):
22
+ me.text("API keys")
23
+ me.input(
24
+ label="Gemini API Key",
25
+ value=state.gemini_api_key,
26
+ on_blur=set_gemini_api_key,
27
+ )
28
+ me.input(
29
+ label="Claude API Key",
30
+ value=state.claude_api_key,
31
+ on_blur=set_claude_api_key,
32
+ )
33
+ me.text("Pick a model")
34
+ for model in Models:
35
+ if model.name.startswith("GEMINI"):
36
+ disabled = not state.gemini_api_key
37
+ elif model.name.startswith("CLAUDE"):
38
+ disabled = not state.claude_api_key
39
+ else:
40
+ disabled = False
41
+ me.checkbox(
42
+ key=model.value,
43
+ label=model.value,
44
+ checked=model.value in state.models,
45
+ disabled=disabled,
46
+ on_change=change_model_option,
47
+ style=me.Style(
48
+ display="flex",
49
+ flex_direction="column",
50
+ gap=4,
51
+ padding=me.Padding(top=12),
52
+ ),
53
+ )
54
+ with dialog_actions():
55
+ me.button("Cancel", on_click=close_model_picker_dialog)
56
+ me.button("Confirm", on_click=confirm_model_picker_dialog)
57
+
58
+ def close_model_picker_dialog(e: me.ClickEvent):
59
+ state = me.state(State)
60
+ state.is_model_picker_dialog_open = False
61
+
62
+ def confirm_model_picker_dialog(e: me.ClickEvent):
63
+ dialog_state = me.state(ModelDialogState)
64
+ state = me.state(State)
65
+ state.is_model_picker_dialog_open = False
66
+ state.models = dialog_state.selected_models
67
 
68
  ROOT_BOX_STYLE = me.Style(
69
  background="#e7f2ff",
 
80
  ],
81
  )
82
  def page():
83
+ model_picker_dialog()
84
  with me.box(style=ROOT_BOX_STYLE):
85
  header()
86
  with me.box(
87
  style=me.Style(
88
  width="min(680px, 100%)",
89
+ margin=me.Margin.symmetric(horizontal="auto", vertical=36),
 
 
 
90
  )
91
  ):
92
  me.text(
93
  "Chat with multiple models at once",
94
+ style=me.Style(font_size=20, margin=me.Margin(bottom=24)),
 
 
 
95
  )
96
  chat_input()
97
 
 
111
  ),
112
  )
113
 
114
+ def switch_model(e: me.ClickEvent):
 
 
 
 
115
  state = me.state(State)
116
+ state.is_model_picker_dialog_open = True
117
+ dialog_state = me.state(ModelDialogState)
118
+ dialog_state.selected_models = state.models[:]
119
 
120
  def chat_input():
121
  state = me.state(State)
 
140
  border=me.Border.all(me.BorderSide(style="none")),
141
  ),
142
  )
143
+ with me.box(
144
+ style=me.Style(
145
+ display="flex",
146
+ padding=me.Padding(left=12, bottom=12),
147
+ cursor="pointer",
148
+ ),
149
+ on_click=switch_model,
150
+ ):
151
+ me.text(
152
+ "Model:",
153
+ style=me.Style(font_weight=500, padding=me.Padding(right=6)),
154
+ )
155
+ if state.models:
156
+ me.text(", ".join(state.models))
157
+ else:
158
+ me.text("(no model selected)")
159
+ with me.content_button(
160
+ type="icon", on_click=send_prompt, disabled=not state.models
161
+ ):
162
  me.icon("send")
163
 
164
+ def on_blur(e: me.InputBlurEvent):
165
+ state = me.state(State)
166
+ state.input = e.value
167
+
168
  def send_prompt(e: me.ClickEvent):
169
  state = me.state(State)
170
  print(f"Sending prompt: {state.input}")
171
+ print(f"Selected models: {state.models}")
172
  state.input = ""