返回提交历史
Modified
g4f/gui/client/index.html
+215
-222
Modified
g4f/gui/client/static/css/style.css
+1
-86
Modified
g4f/gui/client/static/js/chat.v1.js
+0
-110
Modified
g4f/gui/server/backend.py
+2
-22
XFEstudio/gpt4free
Update (g4f/gui/*)
d7d1db83
代码差异
4 个文件
+218
-440
@@ -1,222 +1,227 @@
1
1
<!DOCTYPE html>
2
2
<html lang="en" data-framework="javascript">
3
<head>
4
<meta charset="UTF-8">
5
<meta http-equiv="X-UA-Compatible" content="IE=edge">
6
<meta name="viewport" content="width=device-width, initial-scale=1.0 maximum-scale=1.0">
7
<meta name="description" content="A conversational AI system that listens, learns, and challenges">
8
<meta property="og:title" content="ChatGPT">
9
<meta property="og:image" content="https://openai.com/content/images/2022/11/ChatGPT.jpg">
10
<meta property="og:description" content="A conversational AI system that listens, learns, and challenges">
11
<meta property="og:url" content="https://g4f.ai">
12
<link rel="stylesheet" href="/static/css/style.css">
13
<link rel="apple-touch-icon" sizes="180x180" href="/static/img/apple-touch-icon.png">
14
<link rel="icon" type="image/png" sizes="32x32" href="/static/img/favicon-32x32.png">
15
<link rel="icon" type="image/png" sizes="16x16" href="/static/img/favicon-16x16.png">
16
<link rel="manifest" href="/static/img/site.webmanifest">
17
<script src="/static/js/icons.js"></script>
18
<script src="/static/js/highlightjs-copy.min.js"></script>
19
<script src="/static/js/chat.v1.js" defer></script>
20
<script src="https://cdn.jsdelivr.net/npm/markdown-it@13.0.1/dist/markdown-it.min.js"></script>
21
<link rel="stylesheet" href="/static/css/dracula.min.css">
22
<script>
23
MathJax = {
24
chtml: {
25
scale: 1,
26
displayAlign: 'left'
27
}
28
};
29
</script>
30
<script id="MathJax-script" src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js" async></script>
31
<script type="module" src="https://cdn.jsdelivr.net/npm/mistral-tokenizer-js" async>
32
import mistralTokenizer from "mistral-tokenizer-js"
33
</script>
34
<script type="module" src="https://cdn.jsdelivr.net/gh/belladoreai/llama-tokenizer-js@master/llama-tokenizer.js" async>
35
import llamaTokenizer from "llama-tokenizer-js"
36
</script>
37
<script src="https://cdn.jsdelivr.net/npm/gpt-tokenizer/dist/cl100k_base.js" async></script>
38
<script src="/static/js/text_to_speech/index.js" async></script>
39
<!--
40
<script src="/static/js/whisper-web/index.js" async></script>
41
-->
42
<script>
43
const user_image = '<img src="/static/img/user.png" alt="your avatar">';
44
const gpt_image = '<img src="/static/img/gpt.png" alt="your avatar">';
45
</script>
46
<script src="/static/js/highlight.min.js"></script>
47
<script>window.conversation_id = "{{chat_id}}"</script>
48
<title>g4f - gui</title>
49
</head>
50
<body>
51
<div class="gradient"></div>
52
<div class="row">
53
<div class="box conversations">
3
4
<head>
5
<meta charset="UTF-8">
6
<meta http-equiv="X-UA-Compatible" content="IE=edge">
7
<meta name="viewport" content="width=device-width, initial-scale=1.0 maximum-scale=1.0">
8
<meta name="description" content="A conversational AI system that listens, learns, and challenges">
9
<meta property="og:title" content="ChatGPT">
10
<meta property="og:image" content="https://openai.com/content/images/2022/11/ChatGPT.jpg">
11
<meta property="og:description" content="A conversational AI system that listens, learns, and challenges">
12
<meta property="og:url" content="https://g4f.ai">
13
<link rel="stylesheet" href="/static/css/style.css">
14
<link rel="apple-touch-icon" sizes="180x180" href="/static/img/apple-touch-icon.png">
15
<link rel="icon" type="image/png" sizes="32x32" href="/static/img/favicon-32x32.png">
16
<link rel="icon" type="image/png" sizes="16x16" href="/static/img/favicon-16x16.png">
17
<link rel="manifest" href="/static/img/site.webmanifest">
18
<script src="/static/js/icons.js"></script>
19
<script src="/static/js/highlightjs-copy.min.js"></script>
20
<script src="/static/js/chat.v1.js" defer></script>
21
<script src="https://cdn.jsdelivr.net/npm/markdown-it@13.0.1/dist/markdown-it.min.js"></script>
22
<link rel="stylesheet" href="/static/css/dracula.min.css">
23
<script>
24
MathJax = {
25
chtml: {
26
scale: 1,
27
displayAlign: 'left'
28
}
29
};
30
</script>
31
<script id="MathJax-script" src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js" async></script>
32
<script type="module" src="https://cdn.jsdelivr.net/npm/mistral-tokenizer-js" async>
33
import mistralTokenizer from "mistral-tokenizer-js"
34
</script>
35
<script type="module" src="https://cdn.jsdelivr.net/gh/belladoreai/llama-tokenizer-js@master/llama-tokenizer.js" async>
36
import llamaTokenizer from "llama-tokenizer-js"
37
</script>
38
<script src="https://cdn.jsdelivr.net/npm/gpt-tokenizer/dist/cl100k_base.js" async></script>
39
<script src="/static/js/text_to_speech/index.js" async></script>
40
<!--
41
<script src="/static/js/whisper-web/index.js" async></script>
42
-->
43
<script>
44
const user_image = '<img src="/static/img/user.png" alt="your avatar">';
45
const gpt_image = '<img src="/static/img/gpt.png" alt="your avatar">';
46
</script>
47
<script src="/static/js/highlight.min.js"></script>
48
<script>window.conversation_id = "{{chat_id}}"</script>
49
<title>g4f - gui</title>
50
</head>
51
52
<body>
53
<div class="gradient"></div>
54
<div class="row">
55
<div class="box conversations">
54
56
<div class="top">
55
<button class="new_convo" onclick="new_conversation()">
56
<i class="fa-regular fa-plus"></i>
57
<span>New Conversation</span>
58
</button>
57
<button class="new_convo" onclick="new_conversation()">
58
<i class="fa-regular fa-plus"></i>
59
<span>New Conversation</span>
60
</button>
59
61
</div>
60
62
<div class="bottom_buttons">
61
<button onclick="open_album();">
62
<i class="fa-solid fa-toolbox"></i>
63
<span>Images Album</span>
64
</button>
65
<button onclick="open_settings();">
66
<i class="fa-solid fa-toolbox"></i>
67
<span>Open Settings</span>
68
</button>
69
<div class="info">
70
<i class="fa-brands fa-discord"></i>
71
<span class="convo-title">discord ~ <a href="https://discord.gg/XfybzPXPH5">discord.gg/XfybzPXPH5</a>
72
</span>
73
</div>
74
<div class="info">
75
<i class="fa-brands fa-github"></i>
76
<span class="convo-title">github ~ <a href="https://github.com/xtekky/gpt4free">@xtekky/gpt4free</a>
77
</span>
78
</div>
79
<div class="info">
80
<i class="fa-solid fa-star"></i>
81
<span id="version_text" class="convo-title"></span>
82
</div>
63
<!--
64
<button onclick="open_album();">
65
<i class="fa-solid fa-toolbox"></i>
66
<span>Images Album</span>
67
</button>
68
-->
69
<button onclick="open_settings();">
70
<i class="fa-solid fa-toolbox"></i>
71
<span>Open Settings</span>
72
</button>
73
<div class="info">
74
<i class="fa-brands fa-discord"></i>
75
<span class="convo-title">discord ~ <a href="https://discord.gg/XfybzPXPH5">discord.gg/XfybzPXPH5</a>
76
</span>
77
</div>
78
<div class="info">
79
<i class="fa-brands fa-github"></i>
80
<span class="convo-title">github ~ <a href="https://github.com/xtekky/gpt4free">@xtekky/gpt4free</a>
81
</span>
82
</div>
83
<div class="info">
84
<i class="fa-solid fa-star"></i>
85
<span id="version_text" class="convo-title"></span>
86
</div>
83
87
</div>
84
</div>
85
<div class="images hidden">
86
</div>
87
<div class="settings hidden">
88
</div>
89
<div class="images hidden">
90
91
</div>
92
<div class="settings hidden">
88
93
<div class="paper">
89
<h3>Settings</h3>
90
<div class="field">
91
<span class="label">Enable Dark Mode</span>
92
<input type="checkbox" id="darkMode" checked />
93
<label for="darkMode" class="toogle" title=""></label>
94
</div>
95
<div class="field">
96
<span class="label">Web Access with DuckDuckGo</span>
97
<input type="checkbox" id="switch" />
98
<label for="switch" class="toogle" title="Add the pages of the first 5 search results to the query."></label>
99
</div>
100
<div class="field">
101
<span class="label">Disable Conversation History</span>
102
<input type="checkbox" id="history" />
103
<label for="history" class="toogle" title="To improve the reaction time or if you have trouble with large conversations."></label>
104
</div>
105
<div class="field">
106
<span class="label">Hide System-prompt</span>
107
<input type="checkbox" id="hide-systemPrompt" />
108
<label for="hide-systemPrompt" class="toogle" title="For more space on phones"></label>
109
</div>
110
<div class="field">
111
<span class="label">Auto continue in ChatGPT</span>
112
<input id="auto_continue" type="checkbox" name="auto_continue" checked/>
113
<label for="auto_continue" class="toogle" title="Continue large responses in OpenaiChat"></label>
114
</div>
115
<div class="field box">
116
<label for="message-input-height" class="label" title="">Input max. height</label>
117
<input type="number" id="message-input-height" value="200"/>
118
</div>
119
<div class="field box">
120
<label for="recognition-language" class="label" title="">Speech recognition lang</label>
121
<input type="text" id="recognition-language" value="" placeholder="navigator.language"/>
122
</div>
123
<div class="field box">
124
<label for="BingCreateImages-api_key" class="label" title="">Microsoft Designer in Bing:</label>
125
<textarea id="BingCreateImages-api_key" name="BingCreateImages[api_key]" placeholder=""_U" cookie"></textarea>
126
</div>
127
<div class="field box">
128
<label for="DeepInfra-api_key" class="label" title="">DeepInfra:</label>
129
<textarea id="DeepInfra-api_key" name="DeepInfra[api_key]" class="DeepInfraImage-api_key" placeholder="api_key"></textarea>
130
</div>
131
<div class="field box">
132
<label for="GeminiPro-api_key" class="label" title="">Gemini API:</label>
133
<textarea id="GeminiPro-api_key" name="GeminiPro[api_key]" placeholder="api_key"></textarea>
134
</div>
135
<div class="field box">
136
<label for="Groq-api_key" class="label" title="">Groq:</label>
137
<textarea id="Groq-api_key" name="Groq[api_key]" placeholder="api_key"></textarea>
138
</div>
139
<div class="field box">
140
<label for="HuggingFace-api_key" class="label" title="">HuggingFace:</label>
141
<textarea id="HuggingFace-api_key" name="HuggingFace[api_key]" placeholder="api_key"></textarea>
142
</div>
143
<div class="field box">
144
<label for="Openai-api_key" class="label" title="">OpenAI API:</label>
145
<textarea id="Openai-api_key" name="Openai[api_key]" placeholder="api_key"></textarea>
146
</div>
147
<div class="field box">
148
<label for="OpenRouter-api_key" class="label" title="">OpenRouter:</label>
149
<textarea id="OpenRouter-api_key" name="OpenRouter[api_key]" placeholder="api_key"></textarea>
150
</div>
151
<div class="field box">
152
<label for="PerplexityApi-api_key" class="label" title="">Perplexity API:</label>
153
<textarea id="PerplexityApi-api_key" name="PerplexityApi[api_key]" placeholder="api_key"></textarea>
154
</div>
155
<div class="field box">
156
<label for="Replicate-api_key" class="label" title="">Replicate:</label>
157
<textarea id="Replicate-api_key" name="Replicate[api_key]" class="ReplicateImage-api_key" placeholder="api_key"></textarea>
158
</div>
94
<h3>Settings</h3>
95
<div class="field">
96
<span class="label">Enable Dark Mode</span>
97
<input type="checkbox" id="darkMode" checked />
98
<label for="darkMode" class="toogle" title=""></label>
99
</div>
100
<div class="field">
101
<span class="label">Web Access with DuckDuckGo</span>
102
<input type="checkbox" id="switch" />
103
<label for="switch" class="toogle" title="Add the pages of the first 5 search results to the query."></label>
104
</div>
105
<div class="field">
106
<span class="label">Disable Conversation History</span>
107
<input type="checkbox" id="history" />
108
<label for="history" class="toogle" title="To improve the reaction time or if you have trouble with large conversations."></label>
109
</div>
110
<div class="field">
111
<span class="label">Hide System-prompt</span>
112
<input type="checkbox" id="hide-systemPrompt" />
113
<label for="hide-systemPrompt" class="toogle" title="For more space on phones"></label>
114
</div>
115
<div class="field">
116
<span class="label">Auto continue in ChatGPT</span>
117
<input id="auto_continue" type="checkbox" name="auto_continue" checked/>
118
<label for="auto_continue" class="toogle" title="Continue large responses in OpenaiChat"></label>
119
</div>
120
<div class="field box">
121
<label for="message-input-height" class="label" title="">Input max. height</label>
122
<input type="number" id="message-input-height" value="200"/>
123
</div>
124
<div class="field box">
125
<label for="recognition-language" class="label" title="">Speech recognition lang</label>
126
<input type="text" id="recognition-language" value="" placeholder="navigator.language"/>
127
</div>
128
<div class="field box">
129
<label for="BingCreateImages-api_key" class="label" title="">Microsoft Designer in Bing:</label>
130
<textarea id="BingCreateImages-api_key" name="BingCreateImages[api_key]" placeholder=""_U" cookie"></textarea>
131
</div>
132
<div class="field box">
133
<label for="DeepInfra-api_key" class="label" title="">DeepInfra:</label>
134
<textarea id="DeepInfra-api_key" name="DeepInfra[api_key]" class="DeepInfraImage-api_key" placeholder="api_key"></textarea>
135
</div>
136
<div class="field box">
137
<label for="GeminiPro-api_key" class="label" title="">Gemini API:</label>
138
<textarea id="GeminiPro-api_key" name="GeminiPro[api_key]" placeholder="api_key"></textarea>
139
</div>
140
<div class="field box">
141
<label for="Groq-api_key" class="label" title="">Groq:</label>
142
<textarea id="Groq-api_key" name="Groq[api_key]" placeholder="api_key"></textarea>
143
</div>
144
<div class="field box">
145
<label for="HuggingFace-api_key" class="label" title="">HuggingFace:</label>
146
<textarea id="HuggingFace-api_key" name="HuggingFace[api_key]" placeholder="api_key"></textarea>
147
</div>
148
<div class="field box">
149
<label for="Openai-api_key" class="label" title="">OpenAI API:</label>
150
<textarea id="Openai-api_key" name="Openai[api_key]" placeholder="api_key"></textarea>
151
</div>
152
<div class="field box">
153
<label for="OpenRouter-api_key" class="label" title="">OpenRouter:</label>
154
<textarea id="OpenRouter-api_key" name="OpenRouter[api_key]" placeholder="api_key"></textarea>
155
</div>
156
<div class="field box">
157
<label for="PerplexityApi-api_key" class="label" title="">Perplexity API:</label>
158
<textarea id="PerplexityApi-api_key" name="PerplexityApi[api_key]" placeholder="api_key"></textarea>
159
</div>
160
<div class="field box">
161
<label for="Replicate-api_key" class="label" title="">Replicate:</label>
162
<textarea id="Replicate-api_key" name="Replicate[api_key]" class="ReplicateImage-api_key" placeholder="api_key"></textarea>
163
</div>
159
164
</div>
160
165
<div class="bottom_buttons">
161
<button onclick="delete_conversations()">
162
<i class="fa-regular fa-trash"></i>
163
<span>Clear Conversations</span>
164
</button>
165
<button onclick="save_storage()">
166
<i class="fa-solid fa-download"></i>
167
<a href="" onclick="return false;">Export Conversations</a>
168
</button>
166
<button onclick="delete_conversations()">
167
<i class="fa-regular fa-trash"></i>
168
<span>Clear Conversations</span>
169
</button>
170
<button onclick="save_storage()">
171
<i class="fa-solid fa-download"></i>
172
<a href="" onclick="return false;">Export Conversations</a>
173
</button>
169
174
</div>
170
</div>
171
<div class="conversation">
175
</div>
176
<div class="conversation">
172
177
<textarea id="systemPrompt" class="box" placeholder="System prompt"></textarea>
173
178
<div id="messages" class="box"></div>
174
179
<button class="slide-systemPrompt">
175
<i class="fa-solid fa-angles-up"></i>
180
<i class="fa-solid fa-angles-up"></i>
176
181
</button>
177
182
<div class="toolbar">
178
<div id="input-count" class="">
179
<button class="hide-input">
180
<i class="fa-solid fa-angles-down"></i>
181
</button>
182
<span class="text"></span>
183
</div>
184
<div class="stop_generating stop_generating-hidden">
185
<button id="cancelButton">
186
<span>Stop Generating</span>
187
<i class="fa-regular fa-stop"></i>
188
</button>
189
</div>
190
<div class="regenerate regenerate-hidden">
191
<button id="regenerateButton">
192
<span>Regenerate</span>
193
<i class="fa-solid fa-rotate"></i>
194
</button>
195
</div>
183
<div id="input-count" class="">
184
<button class="hide-input">
185
<i class="fa-solid fa-angles-down"></i>
186
</button>
187
<span class="text"></span>
188
</div>
189
<div class="stop_generating stop_generating-hidden">
190
<button id="cancelButton">
191
<span>Stop Generating</span>
192
<i class="fa-regular fa-stop"></i>
193
</button>
194
</div>
195
<div class="regenerate regenerate-hidden">
196
<button id="regenerateButton">
197
<span>Regenerate</span>
198
<i class="fa-solid fa-rotate"></i>
199
</button>
200
</div>
196
201
</div>
197
202
<div class="user-input">
198
<div class="box input-box">
199
<textarea id="message-input" placeholder="Ask a question" cols="30" rows="10"
200
style="white-space: pre-wrap;resize: none;"></textarea>
201
<label class="file-label image-label" for="image" title="Works with Bing, Gemini, OpenaiChat and You">
202
<input type="file" id="image" name="image" accept="image/*" required/>
203
<i class="fa-regular fa-image"></i>
204
</label>
205
<label class="file-label image-label" for="camera">
206
<input type="file" id="camera" name="camera" accept="image/*" capture="camera" required/>
207
<i class="fa-solid fa-camera"></i>
208
</label>
209
<label class="file-label" for="file">
210
<input type="file" id="file" name="file" accept="text/plain, text/html, text/xml, application/json, text/javascript, .sh, .py, .php, .css, .yaml, .sql, .log, .csv, .twig, .md" required/>
211
<i class="fa-solid fa-paperclip"></i>
212
</label>
213
<label class="micro-label" for="micro">
214
<i class="fa-solid fa-microphone-slash"></i>
215
</label>
216
<div id="send-button">
217
<i class="fa-solid fa-paper-plane-top"></i>
218
</div>
219
</div>
203
<div class="box input-box">
204
<textarea id="message-input" placeholder="Ask a question" cols="30" rows="10"
205
style="white-space: pre-wrap;resize: none;"></textarea>
206
<label class="file-label image-label" for="image" title="Works with Bing, Gemini, OpenaiChat and You">
207
<input type="file" id="image" name="image" accept="image/*" required/>
208
<i class="fa-regular fa-image"></i>
209
</label>
210
<label class="file-label image-label" for="camera">
211
<input type="file" id="camera" name="camera" accept="image/*" capture="camera" required/>
212
<i class="fa-solid fa-camera"></i>
213
</label>
214
<label class="file-label" for="file">
215
<input type="file" id="file" name="file" accept="text/plain, text/html, text/xml, application/json, text/javascript, .sh, .py, .php, .css, .yaml, .sql, .log, .csv, .twig, .md" required/>
216
<i class="fa-solid fa-paperclip"></i>
217
</label>
218
<label class="micro-label" for="micro">
219
<i class="fa-solid fa-microphone-slash"></i>
220
</label>
221
<div id="send-button">
222
<i class="fa-solid fa-paper-plane-top"></i>
223
</div>
224
</div>
220
225
</div>
221
226
<div class="buttons">
222
227
<div class="field">
@@ -243,30 +248,18 @@
243
248
<option value="Gemini">Gemini</option>
244
249
<option value="MetaAI">Meta AI</option>
245
250
<option value="DeepInfraChat">DeepInfraChat</option>
246
<option value="ReplicateHome">ReplicateHome</option>
247
251
<option value="Blackbox">Blackbox</option>
248
252
<option value="HuggingChat">HuggingChat</option>
249
253
<option value="DDG">DDG</option>
250
254
<option value="Pizzagpt">Pizzagpt</option>
251
255
<option value="">----</option>
252
</select>
253
</div>
256
</select>
257
</div>
254
258
</div>
255
</div>
256
</div>
257
<div id="imageModal" class="modal hidden">
258
<span class="close">×</span>
259
<img class="modal-content" id="img01">
260
<div id="caption"></div>
261
<div class="navigation-controls">
262
<button id="prevImage" class="nav-button left">❮</button>
263
<span id="imageCounter" class="image-counter"></span>
264
<button id="nextImage" class="nav-button right">❯</button>
265
</div>
266
</div>
267
<div class="mobile-sidebar">
268
<i class="fa-solid fa-bars"></i>
269
</div>
270
</body>
259
</div>
260
</div>
261
<div class="mobile-sidebar">
262
<i class="fa-solid fa-bars"></i>
263
</div>
264
</body>
271
265
</html>
272
@@ -474,6 +474,7 @@ body {
474
474
475
475
.stop_generating, .toolbar .regenerate {
476
476
position: absolute;
477
z-index: 1000000;
477
478
top: 0;
478
479
right: 0;
479
480
}
@@ -1117,92 +1118,6 @@ a:-webkit-any-link {
1117
1118
display: none;
1118
1119
}
1119
1120
1120
.album-image {
1121
width: 100px;
1122
height: auto;
1123
margin: 5px;
1124
display: inline-block;
1125
}
1126
1127
.modal {
1128
display: none;
1129
position: fixed;
1130
z-index: 1;
1131
left: 0;
1132
top: 0;
1133
width: 100%;
1134
height: 100%;
1135
overflow: hidden;
1136
background-color: rgba(0,0,0,0.9);
1137
}
1138
1139
.modal-content {
1140
margin: auto;
1141
display: block;
1142
max-width: 80%;
1143
max-height: 80%;
1144
transition: transform 0.2s;
1145
}
1146
1147
.close {
1148
position: absolute;
1149
top: 15px;
1150
right: 35px;
1151
color: #f1f1f1;
1152
font-size: 40px;
1153
font-weight: bold;
1154
transition: 0.3s;
1155
}
1156
1157
.close:hover,
1158
.close:focus {
1159
color: #bbb;
1160
text-decoration: none;
1161
cursor: pointer;
1162
}
1163
1164
1165
.image-counter {
1166
color: #fff;
1167
font-size: 18px;
1168
margin: auto 10px;
1169
user-select: none;
1170
}
1171
1172
.nav-button {
1173
background-color: #555;
1174
color: #fff;
1175
border: none;
1176
padding: 10px;
1177
font-size: 20px;
1178
cursor: pointer;
1179
}
1180
1181
.nav-button:hover {
1182
background-color: #777;
1183
}
1184
1185
.nav-button {
1186
position: relative;
1187
}
1188
1189
.nav-button.left {
1190
left: 0;
1191
}
1192
1193
.nav-button.right {
1194
right: 0;
1195
}
1196
1197
.navigation-controls {
1198
position: absolute;
1199
bottom: 20px;
1200
left: 50%;
1201
transform: translateX(-50%);
1202
display: flex;
1203
gap: 10px;
1204
}
1205
1206
1121
.blink {
1207
1122
animation: blinker 1s step-start infinite;
1208
1123
}
@@ -936,127 +936,17 @@ function open_settings() {
936
936
}
937
937
}
938
938
939
async function loadImages() {
940
try {
941
const response = await fetch('/images');
942
const images = await response.json();
943
console.log(images);
944
displayImages(images);
945
} catch (error) {
946
console.error('Error fetching images:', error);
947
}
948
}
949
950
function displayImages(images) {
951
const album = document.querySelector('.images');
952
album.innerHTML = '';
953
images.forEach(image => {
954
const imgElement = document.createElement('img');
955
imgElement.src = image;
956
imgElement.alt = 'Generated Image';
957
imgElement.classList.add('album-image');
958
album.appendChild(imgElement);
959
});
960
}
961
962
document.addEventListener('DOMContentLoaded', () => {
963
loadImages();
964
});
965
966
939
function open_album() {
967
const album = document.querySelector('.images');
968
940
if (album.classList.contains("hidden")) {
969
941
sidebar.classList.remove("shown");
970
942
settings.classList.add("hidden");
971
943
album.classList.remove("hidden");
972
944
history.pushState({}, null, "/images/");
973
loadImages();
974
945
} else {
975
946
album.classList.add("hidden");
976
947
}
977
948
}
978
949
979
let currentScale = 1;
980
let currentImageIndex = 0;
981
let imagesList = [];
982
983
function displayImages(images) {
984
imagesList = images;
985
const album = document.querySelector('.images');
986
album.innerHTML = '';
987
images.forEach((image, index) => {
988
const imgElement = document.createElement('img');
989
imgElement.src = image;
990
imgElement.alt = 'Generated Image';
991
imgElement.classList.add('album-image');
992
imgElement.style.cursor = 'pointer';
993
imgElement.addEventListener('click', () => openImageModal(index));
994
album.appendChild(imgElement);
995
});
996
}
997
998
function openImageModal(index) {
999
currentImageIndex = index;
1000
const modal = document.getElementById('imageModal');
1001
const modalImg = document.getElementById('img01');
1002
const imageCounter = document.getElementById('imageCounter');
1003
modal.style.display = 'block';
1004
modalImg.src = imagesList[index];
1005
currentScale = 1;
1006
modalImg.style.transform = `scale(${currentScale})`;
1007
imageCounter.textContent = `${index + 1} / ${imagesList.length}`;
1008
}
1009
1010
const modal = document.getElementById('imageModal');
1011
const span = document.getElementsByClassName('close')[0];
1012
const prevImageButton = document.getElementById('prevImage');
1013
const nextImageButton = document.getElementById('nextImage');
1014
1015
span.onclick = function() {
1016
modal.style.display = 'none';
1017
}
1018
1019
window.onclick = function(event) {
1020
if (event.target == modal) {
1021
modal.style.display = 'none';
1022
}
1023
}
1024
1025
document.getElementById('img01').addEventListener('wheel', function(event) {
1026
event.preventDefault();
1027
if (event.deltaY < 0) {
1028
currentScale += 0.1;
1029
} else if (currentScale > 0.1) {
1030
currentScale -= 0.1;
1031
}
1032
document.getElementById('img01').style.transform = `scale(${currentScale})`;
1033
});
1034
1035
prevImageButton.onclick = function() {
1036
if (currentImageIndex > 0) {
1037
currentImageIndex--;
1038
openImageModal(currentImageIndex);
1039
}
1040
}
1041
1042
nextImageButton.onclick = function() {
1043
if (currentImageIndex < imagesList.length - 1) {
1044
currentImageIndex++;
1045
openImageModal(currentImageIndex);
1046
}
1047
}
1048
1049
document.addEventListener('keydown', function(event) {
1050
if (modal.style.display === 'block') {
1051
if (event.key === 'ArrowLeft') {
1052
prevImageButton.click();
1053
} else if (event.key === 'ArrowRight') {
1054
nextImageButton.click();
1055
}
1056
}
1057
});
1058
1059
1060
950
const register_settings_storage = async () => {
1061
951
optionElements.forEach((element) => {
1062
952
if (element.type == "textarea") {
@@ -1,6 +1,5 @@
1
1
import json
2
import os
3
from flask import request, Flask, jsonify, send_from_directory
2
from flask import request, Flask
4
3
from g4f.image import is_allowed_extension, to_image
5
4
from .api import Api
6
5
@@ -55,10 +54,6 @@ class Backend_Api(Api):
55
54
'/images/<path:name>': {
56
55
'function': self.serve_images,
57
56
'methods': ['GET']
58
},
59
'/images': {
60
'function': self.get_images,
61
'methods': ['GET']
62
57
}
63
58
}
64
59
@@ -115,19 +110,4 @@ class Backend_Api(Api):
115
110
Returns:
116
111
str: A JSON formatted string.
117
112
"""
118
return json.dumps(super()._format_json(response_type, content)) + "\n"
119
120
@staticmethod
121
def get_images():
122
images_dir = "./generated_images"
123
try:
124
images = [f for f in os.listdir(images_dir) if os.path.isfile(os.path.join(images_dir, f))]
125
images = [f"/images/{image}" for image in images if image.lower().endswith(('.png', '.jpg', '.jpeg', '.gif', '.webp'))]
126
return jsonify(images)
127
except Exception as e:
128
return str(e), 500
129
130
@staticmethod
131
def serve_images(name):
132
images_dir = "./generated_images"
133
return send_from_directory(os.path.abspath(images_dir), name)
113
return json.dumps(super()._format_json(response_type, content)) + "\n"