@@ -5,6 +5,9 @@ use chrono::{DateTime, Utc};
5
5
use dioxus:: prelude:: * ;
6
6
use dioxus_desktop:: tao:: window:: Icon ;
7
7
use dioxus_desktop:: { Config , WindowBuilder } ;
8
+ use dioxus_free_icons:: Icon ;
9
+ use dioxus_free_icons:: icons:: bs_icons:: { BsGear , BsArrowDownShort , BsArrowUpShort } ;
10
+ use dioxus_free_icons:: icons:: fa_brands_icons:: FaGithub ;
8
11
use serde:: de:: DeserializeOwned ;
9
12
use serde:: { Deserialize , Serialize } ;
10
13
use serde_json:: json;
@@ -66,11 +69,7 @@ fn app(cx: Scope) -> Element {
66
69
target: "_blank" ,
67
70
href: "https://github.com/fairjm/dioxus-openai-qa-gui" ,
68
71
span { class: "icon is-small" ,
69
- svg {
70
- "xmlns" : "http://www.w3.org/2000/svg" ,
71
- "viewBox" : "0 0 24 24" ,
72
- path { "d" : "M12,2A10,10 0 0,0 2,12C2,16.42 4.87,20.17 8.84,21.5C9.34,21.58 9.5,21.27 9.5,21C9.5,20.77 9.5,20.14 9.5,19.31C6.73,19.91 6.14,17.97 6.14,17.97C5.68,16.81 5.03,16.5 5.03,16.5C4.12,15.88 5.1,15.9 5.1,15.9C6.1,15.97 6.63,16.93 6.63,16.93C7.5,18.45 8.97,18 9.54,17.76C9.63,17.11 9.89,16.67 10.17,16.42C7.95,16.17 5.62,15.31 5.62,11.5C5.62,10.39 6,9.5 6.65,8.79C6.55,8.54 6.2,7.5 6.75,6.15C6.75,6.15 7.59,5.88 9.5,7.17C10.29,6.95 11.15,6.84 12,6.84C12.85,6.84 13.71,6.95 14.5,7.17C16.41,5.88 17.25,6.15 17.25,6.15C17.8,7.5 17.45,8.54 17.35,8.79C18,9.5 18.38,10.39 18.38,11.5C18.38,15.32 16.04,16.16 13.81,16.41C14.17,16.72 14.5,17.33 14.5,18.26C14.5,19.6 14.5,20.68 14.5,21C14.5,21.27 14.66,21.59 15.17,21.5C19.14,20.16 22,16.42 22,12A10,10 0 0,0 12,2Z" }
73
- }
72
+ Icon { width: 24 , height: 24 , fill: "#6e7781" , icon: FaGithub }
74
73
}
75
74
span { "GitHub" }
76
75
}
@@ -89,9 +88,7 @@ fn app(cx: Scope) -> Element {
89
88
}
90
89
} ,
91
90
span { class: "icon has-text-light" ,
92
- svg { "xmlns" : "http://www.w3.org/2000/svg" , "viewBox" : "0 0 24 24" ,
93
- path { "d" : "M12,15.5A3.5,3.5 0 0,1 8.5,12A3.5,3.5 0 0,1 12,8.5A3.5,3.5 0 0,1 15.5,12A3.5,3.5 0 0,1 12,15.5M19.43,12.97C19.47,12.65 19.5,12.33 19.5,12C19.5,11.67 19.47,11.34 19.43,11L21.54,9.37C21.73,9.22 21.78,8.95 21.66,8.73L19.66,5.27C19.54,5.05 19.27,4.96 19.05,5.05L16.56,6.05C16.04,5.66 15.5,5.32 14.87,5.07L14.5,2.42C14.46,2.18 14.25,2 14,2H10C9.75,2 9.54,2.18 9.5,2.42L9.13,5.07C8.5,5.32 7.96,5.66 7.44,6.05L4.95,5.05C4.73,4.96 4.46,5.05 4.34,5.27L2.34,8.73C2.21,8.95 2.27,9.22 2.46,9.37L4.57,11C4.53,11.34 4.5,11.67 4.5,12C4.5,12.33 4.53,12.65 4.57,12.97L2.46,14.63C2.27,14.78 2.21,15.05 2.34,15.27L4.34,18.73C4.46,18.95 4.73,19.03 4.95,18.95L7.44,17.94C7.96,18.34 8.5,18.68 9.13,18.93L9.5,21.58C9.54,21.82 9.75,22 10,22H14C14.25,22 14.46,21.82 14.5,21.58L14.87,18.93C15.5,18.67 16.04,18.34 16.56,17.94L19.05,18.95C19.27,19.03 19.54,18.95 19.66,18.73L21.66,15.27C21.78,15.05 21.73,14.78 21.54,14.63L19.43,12.97Z" }
94
- }
91
+ Icon { width: 24 , height: 24 , fill: "#6e7781" , icon: BsGear }
95
92
}
96
93
span { "设置" }
97
94
}
@@ -129,93 +126,110 @@ fn app(cx: Scope) -> Element {
129
126
}
130
127
}
131
128
}
129
+
132
130
div { class: "columns" ,
133
- div { class: "column" ,
131
+ div { class: "column pb-1 " ,
134
132
nav { class: "level mb-1" ,
135
133
div { class: "level-left" ,
136
134
div { class: "level-item" , p { class: "has-text-grey-light" , "系统prompt" } }
137
- }
138
- }
139
- div { class: "block mb-1" ,
140
- div { class: "dropdown {system_prompt_dropdown}" ,
141
- div { class: "dropdown-trigger" ,
142
- button {
143
- class: "button" ,
144
- "aria-haspopup" : true ,
145
- "aria-controls" : "dropdown-menu" ,
146
- onclick: move |_| {
147
- if system_prompt_dropdown. current( ) . is_empty( ) {
148
- system_prompt_dropdown. set( "is-active" ) ;
149
- } else {
150
- system_prompt_dropdown. set( "" ) ;
151
- }
152
- } ,
153
- span { "prompt列表" }
154
- span { class: "icon is-small" ,
155
- svg {
156
- xmlns: "http://www.w3.org/2000/svg" ,
157
- "viewBox" : "0 0 24 24" ,
158
- path { d: "M7,10L12,15L17,10H7Z" }
135
+ div { class: "level-item" ,
136
+ div { class: "dropdown {system_prompt_dropdown}" ,
137
+ div { class: "dropdown-trigger" ,
138
+ button {
139
+ class: "button is-small" ,
140
+ "aria-haspopup" : true ,
141
+ "aria-controls" : "dropdown-menu" ,
142
+ onclick: move |_| {
143
+ if system_prompt_dropdown. current( ) . is_empty( ) {
144
+ system_prompt_dropdown. set( "is-active" ) ;
145
+ } else {
146
+ system_prompt_dropdown. set( "" ) ;
147
+ }
148
+ } ,
149
+ span { "prompt列表" }
150
+ span { class: "icon is-small" ,
151
+ if system_prompt_dropdown. is_empty( ) {
152
+ rsx!(
153
+ Icon { width: 24 , height: 24 , fill: "#6e7781" , icon: BsArrowDownShort }
154
+ )
155
+ } else {
156
+ rsx!(
157
+ Icon { width: 24 , height: 24 , fill: "#6e7781" , icon: BsArrowUpShort }
158
+ )
159
+ }
160
+ }
159
161
}
160
162
}
161
- }
162
- }
163
163
164
- div { class: "dropdown-menu" , id: "dropdown-menu" , role: "menu" ,
165
- div { class: "dropdown-content" ,
166
- a {
167
- class: "dropdown-item py-0" ,
168
- onclick: move |_| {
169
- system_prompt_dropdown. set( "" ) ;
170
- } ,
171
- "关闭"
172
- }
173
- hr { class: "dropdown-divider" }
174
- if system_prompts. is_empty( ) {
175
- rsx! {
176
- div { class: "dropdown-item" ,
177
- p {
178
- "没有system prompts"
179
- }
164
+ div {
165
+
166
+ class: "dropdown-menu" ,
167
+
168
+ id: "dropdown-menu" ,
169
+
170
+ role: "menu" ,
171
+ div { class: "dropdown-content" ,
172
+ a {
173
+ class: "dropdown-item py-0" ,
174
+ onclick: move |_| {
175
+ system_prompt_dropdown. set( "" ) ;
176
+ } ,
177
+ "关闭"
180
178
}
179
+ hr { class: "dropdown-divider" }
180
+ if system_prompts. is_empty( ) {
181
+ rsx! {
182
+ div { class: "dropdown-item" ,
183
+ p {
184
+ "没有system prompts"
181
185
}
182
186
}
183
- div { class: "dropdown-item" ,
184
- div { class: "columns is-multiline" ,
185
- system_prompts. iter( ) . map( |e| {
186
- rsx!(
187
- div { class: "column" ,
188
- span { class: "tag is-primary is-light" ,
189
- onclick: move |_| {
190
- system_prompt_name. set( e. name. clone( ) ) ;
191
- system_prompt. set( e. content. clone( ) ) ;
192
- system_prompt_dropdown. set( "" ) ;
193
- } ,
194
- "{e.name}"
195
-
196
- button { class: "delete is-small" ,
197
- onclick: move |_| {
198
- system_prompts. with_mut( |v| {
199
- if let Some ( p) = v. iter( ) . position( |value| value. name. eq( & e. name) ) {
200
- v. remove( p) ;
201
- }
202
- } ) ;
203
- save_system_prompts( & * system_prompts. current( ) . clone( ) ) ;
187
+ }
188
+ }
189
+ div { class: "dropdown-item" ,
190
+ div { class: "columns is-multiline" ,
191
+ system_prompts. iter( ) . map( |e| {
192
+ rsx!(
193
+ div { class: "column" ,
194
+ span { class: "tag is-primary is-light" ,
195
+ onclick: move |_| {
196
+ system_prompt_name. set( e. name. clone( ) ) ;
197
+ system_prompt. set( e. content. clone( ) ) ;
198
+ system_prompt_dropdown. set( "" ) ;
199
+ } ,
200
+ "{e.name}"
201
+
202
+ button { class: "delete is-small" ,
203
+ onclick: move |_| {
204
+ system_prompts. with_mut( |v| {
205
+ if let Some ( p) = v. iter( ) . position( |value| value. name. eq( & e. name) ) {
206
+ v. remove( p) ;
204
207
}
205
- }
208
+ } ) ;
209
+ save_system_prompts( & * system_prompts. current( ) . clone( ) ) ;
206
210
}
207
- } )
208
- } )
211
+ }
212
+ }
213
+ } )
214
+ } )
215
+ }
216
+ }
209
217
}
210
218
}
211
219
}
212
220
}
213
221
}
214
222
}
223
+ }
224
+
225
+ div { class: "column pb-1" , p { class: "has-text-grey-light" , "用户prompt" } }
226
+ }
227
+
228
+ div { class: "columns" ,
229
+ div { class: "column pt-1" ,
215
230
p { class: "control" ,
216
231
textarea {
217
232
class: "textarea" ,
218
- rows: 2 ,
219
233
value: "{system_prompt}" ,
220
234
oninput: move |evt| {
221
235
system_prompt. set( evt. value. clone( ) ) ;
@@ -259,10 +273,7 @@ fn app(cx: Scope) -> Element {
259
273
}
260
274
}
261
275
}
262
- }
263
- div { class: "columns" ,
264
- div { class: "column" ,
265
- p { class: "has-text-grey-light" , "用户prompt" }
276
+ div { class: "column pt-1" ,
266
277
p { class: "control {loading}" ,
267
278
textarea {
268
279
class: "textarea" ,
@@ -280,33 +291,32 @@ fn app(cx: Scope) -> Element {
280
291
class: "button is-primary my-1 {loading}" ,
281
292
disabled: "{request_button_disable(configuration, system_prompt, prompt)}" ,
282
293
onclick: move |_| {
283
- cx
284
- . spawn( {
285
- let loading = loading. clone( ) ;
286
- loading. set( "is-loading" . to_string( ) ) ;
287
- let configuration = configuration. clone( ) ;
288
- let system_prompt = system_prompt. clone( ) ;
289
- let prompt = prompt. clone( ) ;
290
- let response = response. clone( ) ;
291
- let error_msg = error_msg. clone( ) ;
292
- async move {
293
- let result = request(
294
- configuration. current( ) . url_prefix. clone( ) ,
295
- configuration. current( ) . secret. clone( ) ,
296
- system_prompt. current( ) . to_string( ) ,
297
- prompt. current( ) . to_string( ) ,
298
- )
299
- . await ;
300
- match result {
301
- Ok ( res) => {
302
- error_msg. set( "" . to_string( ) ) ;
303
- response. set( res) ;
304
- }
305
- Err ( e) => error_msg. set( e. to_string( ) ) ,
294
+ cx. spawn( {
295
+ let loading = loading. clone( ) ;
296
+ loading. set( "is-loading" . to_string( ) ) ;
297
+ let configuration = configuration. clone( ) ;
298
+ let system_prompt = system_prompt. clone( ) ;
299
+ let prompt = prompt. clone( ) ;
300
+ let response = response. clone( ) ;
301
+ let error_msg = error_msg. clone( ) ;
302
+ async move {
303
+ let result = request(
304
+ configuration. current( ) . url_prefix. clone( ) ,
305
+ configuration. current( ) . secret. clone( ) ,
306
+ system_prompt. current( ) . to_string( ) ,
307
+ prompt. current( ) . to_string( ) ,
308
+ )
309
+ . await ;
310
+ match result {
311
+ Ok ( res) => {
312
+ error_msg. set( "" . to_string( ) ) ;
313
+ response. set( res) ;
306
314
}
307
- loading . set( "" . to_string( ) ) ;
315
+ Err ( e ) => error_msg . set( e . to_string( ) ) ,
308
316
}
309
- } )
317
+ loading. set( "" . to_string( ) ) ;
318
+ }
319
+ } )
310
320
} ,
311
321
"提交"
312
322
}
0 commit comments