songweig radames commited on
Commit
d019488
1 Parent(s): 8f96b94

rich-text-gradio (#3)

Browse files

- add custom gradio component (785da46cbf712c609b5836e295fee5648ab60d15)


Co-authored-by: Radamés Ajna <[email protected]>

.gitignore ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ venv
2
+ __pycache__/
3
+ *.pyc
app.py CHANGED
@@ -26,6 +26,24 @@ If you are encountering an error or not achieving your desired outcome, here are
26
  4. Consider using a different seed.
27
  """
28
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
29
 
30
  def main():
31
  device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
@@ -40,12 +58,14 @@ def main():
40
  steps: int,
41
  guidance_weight: float,
42
  color_guidance_weight: float,
 
43
  ):
44
  run_dir = 'results/'
45
  # Load region diffusion model.
46
  steps = 41 if not steps else steps
47
  guidance_weight = 8.5 if not guidance_weight else guidance_weight
48
-
 
49
  # parse json to span attributes
50
  base_text_prompt, style_text_prompts, footnote_text_prompts, footnote_target_tokens,\
51
  color_text_prompts, color_names, color_rgbs, size_text_prompts_and_sizes, use_grad_guidance = parse_json(
@@ -99,11 +119,14 @@ def main():
99
  return [plain_img[0], rich_img[0], token_maps]
100
 
101
  with gr.Blocks() as demo:
 
102
  gr.HTML("""<h1 style="font-weight: 900; margin-bottom: 7px;">Expressive Text-to-Image Generation with Rich Text</h1>
103
  <p> Visit our <a href="https://rich-text-to-image.github.io/rich-text-to-json.html">rich-text-to-json interface</a> to generate rich-text JSON input.<p/>
104
  <p> <a href="https://rich-text-to-image.github.io">[Website]</a> | <a href="https://github.com/SongweiGe/rich-text-to-image">[Code]</a> <p/> """)
105
  with gr.Row():
106
  with gr.Column():
 
 
107
  text_input = gr.Textbox(
108
  label='Rich-text JSON Input',
109
  max_lines=1,
@@ -164,6 +187,7 @@ def main():
164
  512,
165
  6,
166
  1,
 
167
  ],
168
  [
169
  '{"ops":[{"attributes":{"link":"the awe-inspiring sky and ocean in the style of J.M.W. Turner"},"insert":"the awe-inspiring sky and sea"},{"insert":" by "},{"attributes":{"font":"mirza"},"insert":"a coast with flowers and grasses in spring"}]}',
@@ -172,6 +196,7 @@ def main():
172
  512,
173
  9,
174
  1,
 
175
  ],
176
  [
177
  '{"ops":[{"insert":"a Gothic "},{"attributes":{"color":"#b26b00"},"insert":"church"},{"insert":" in a the sunset with a beautiful landscape in the background."}]}',
@@ -180,6 +205,7 @@ def main():
180
  512,
181
  6,
182
  1,
 
183
  ],
184
  [
185
  '{"ops": [{"insert": "A pizza with "}, {"attributes": {"size": "50px"}, "insert": "pineapples"}, {"insert": ", pepperonis, and mushrooms on the top, 4k, photorealistic"}]}',
@@ -188,6 +214,7 @@ def main():
188
  896,
189
  6,
190
  1,
 
191
  ],
192
  [
193
  '{"ops":[{"insert":"a "},{"attributes":{"font":"mirza"},"insert":"beautiful garden"},{"insert":" with a "},{"attributes":{"font":"roboto"},"insert":"snow mountain in the background"},{"insert":""}]}',
@@ -196,6 +223,7 @@ def main():
196
  512,
197
  3,
198
  1,
 
199
  ],
200
  [
201
  '{"ops":[{"insert":"A close-up 4k dslr photo of a "},{"attributes":{"link":"A cat wearing sunglasses and a bandana around its neck."},"insert":"cat"},{"insert":" riding a scooter. Palm trees in the background."}]}',
@@ -204,6 +232,7 @@ def main():
204
  512,
205
  6,
206
  1,
 
207
  ],
208
  ]
209
  gr.Examples(examples=examples,
@@ -214,6 +243,7 @@ def main():
214
  width,
215
  seed,
216
  color_guidance_weight,
 
217
  ],
218
  outputs=[
219
  plaintext_result,
@@ -235,10 +265,11 @@ def main():
235
  steps,
236
  guidance_weight,
237
  color_guidance_weight,
 
238
  ],
239
  outputs=[plaintext_result, richtext_result, token_map],
 
240
  )
241
-
242
  demo.queue(concurrency_count=1)
243
  demo.launch(share=False)
244
 
 
26
  4. Consider using a different seed.
27
  """
28
 
29
+ canvas_html = """<rich-text-editor id="rich-text-root"></rich-text-editor>"""
30
+ load_js = """
31
+ async () => {
32
+ const scripts = ["https://cdn.quilljs.com/1.3.6/quill.min.js","file=rich-text-to-json.js"]
33
+ scripts.forEach(src => {
34
+ const script = document.createElement('script');
35
+ script.src = src;
36
+ document.head.appendChild(script);
37
+ })
38
+ }
39
+ """
40
+ get_js_data = """
41
+ async (text_input, negative_prompt, height, width, seed, steps, guidance_weight, color_guidance_weight, rich_text_input) => {
42
+ const richEl = document.getElementById("rich-text-root");
43
+ const data = richEl? richEl._data : {};
44
+ return [text_input, negative_prompt, height, width, seed, steps, guidance_weight, color_guidance_weight, JSON.stringify(data)];
45
+ }
46
+ """
47
 
48
  def main():
49
  device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
 
58
  steps: int,
59
  guidance_weight: float,
60
  color_guidance_weight: float,
61
+ rich_text_input: str
62
  ):
63
  run_dir = 'results/'
64
  # Load region diffusion model.
65
  steps = 41 if not steps else steps
66
  guidance_weight = 8.5 if not guidance_weight else guidance_weight
67
+ text_input = text_input if text_input != '' else rich_text_input
68
+ print('text_input', text_input)
69
  # parse json to span attributes
70
  base_text_prompt, style_text_prompts, footnote_text_prompts, footnote_target_tokens,\
71
  color_text_prompts, color_names, color_rgbs, size_text_prompts_and_sizes, use_grad_guidance = parse_json(
 
119
  return [plain_img[0], rich_img[0], token_maps]
120
 
121
  with gr.Blocks() as demo:
122
+ demo.load(None, None, None, _js=load_js)
123
  gr.HTML("""<h1 style="font-weight: 900; margin-bottom: 7px;">Expressive Text-to-Image Generation with Rich Text</h1>
124
  <p> Visit our <a href="https://rich-text-to-image.github.io/rich-text-to-json.html">rich-text-to-json interface</a> to generate rich-text JSON input.<p/>
125
  <p> <a href="https://rich-text-to-image.github.io">[Website]</a> | <a href="https://github.com/SongweiGe/rich-text-to-image">[Code]</a> <p/> """)
126
  with gr.Row():
127
  with gr.Column():
128
+ rich_text_el = gr.HTML(canvas_html,elem_id="canvas_html")
129
+ rich_text_input = gr.Textbox(value="", visible=False)
130
  text_input = gr.Textbox(
131
  label='Rich-text JSON Input',
132
  max_lines=1,
 
187
  512,
188
  6,
189
  1,
190
+ None
191
  ],
192
  [
193
  '{"ops":[{"attributes":{"link":"the awe-inspiring sky and ocean in the style of J.M.W. Turner"},"insert":"the awe-inspiring sky and sea"},{"insert":" by "},{"attributes":{"font":"mirza"},"insert":"a coast with flowers and grasses in spring"}]}',
 
196
  512,
197
  9,
198
  1,
199
+ None
200
  ],
201
  [
202
  '{"ops":[{"insert":"a Gothic "},{"attributes":{"color":"#b26b00"},"insert":"church"},{"insert":" in a the sunset with a beautiful landscape in the background."}]}',
 
205
  512,
206
  6,
207
  1,
208
+ None
209
  ],
210
  [
211
  '{"ops": [{"insert": "A pizza with "}, {"attributes": {"size": "50px"}, "insert": "pineapples"}, {"insert": ", pepperonis, and mushrooms on the top, 4k, photorealistic"}]}',
 
214
  896,
215
  6,
216
  1,
217
+ None
218
  ],
219
  [
220
  '{"ops":[{"insert":"a "},{"attributes":{"font":"mirza"},"insert":"beautiful garden"},{"insert":" with a "},{"attributes":{"font":"roboto"},"insert":"snow mountain in the background"},{"insert":""}]}',
 
223
  512,
224
  3,
225
  1,
226
+ None
227
  ],
228
  [
229
  '{"ops":[{"insert":"A close-up 4k dslr photo of a "},{"attributes":{"link":"A cat wearing sunglasses and a bandana around its neck."},"insert":"cat"},{"insert":" riding a scooter. Palm trees in the background."}]}',
 
232
  512,
233
  6,
234
  1,
235
+ None
236
  ],
237
  ]
238
  gr.Examples(examples=examples,
 
243
  width,
244
  seed,
245
  color_guidance_weight,
246
+ rich_text_input,
247
  ],
248
  outputs=[
249
  plaintext_result,
 
265
  steps,
266
  guidance_weight,
267
  color_guidance_weight,
268
+ rich_text_input
269
  ],
270
  outputs=[plaintext_result, richtext_result, token_map],
271
+ _js=get_js_data
272
  )
 
273
  demo.queue(concurrency_count=1)
274
  demo.launch(share=False)
275
 
models/__pycache__/attention.cpython-38.pyc DELETED
Binary file (28.7 kB)
 
models/__pycache__/region_diffusion.cpython-38.pyc DELETED
Binary file (7.89 kB)
 
models/__pycache__/unet_2d_blocks.cpython-38.pyc DELETED
Binary file (27.8 kB)
 
models/__pycache__/unet_2d_condition.cpython-38.pyc DELETED
Binary file (11.4 kB)
 
requirements.txt CHANGED
@@ -4,4 +4,5 @@ torchvision==0.12.0
4
  diffusers==0.12.1
5
  transformers==4.25.1
6
  numpy==1.24.2
7
- seaborn==0.12.2
 
 
4
  diffusers==0.12.1
5
  transformers==4.25.1
6
  numpy==1.24.2
7
+ seaborn==0.12.2
8
+ accelerate==0.18.0
rich-text-to-json.js ADDED
@@ -0,0 +1,349 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ class RichTextEditor extends HTMLElement {
2
+ constructor() {
3
+ super();
4
+ this.loadExternalScripts();
5
+ this.attachShadow({ mode: 'open' });
6
+ this.shadowRoot.innerHTML = `
7
+ ${RichTextEditor.header()}
8
+ ${RichTextEditor.template()}
9
+ `;
10
+ }
11
+ connectedCallback() {
12
+ this.myQuill = this.mountQuill();
13
+ }
14
+ loadExternalScripts() {
15
+ const links = ["https://cdn.quilljs.com/1.3.6/quill.snow.css", "https://cdn.jsdelivr.net/npm/[email protected]/css/bulma.min.css", "https://fonts.googleapis.com/css?family=Mirza|Roboto|Slabo+27px|Sofia|Inconsolata|Ubuntu|Akronim|Monoton&display=swap"]
16
+ links.forEach(link => {
17
+ const css = document.createElement("link");
18
+ css.href = link;
19
+ css.rel = "stylesheet"
20
+ document.head.appendChild(css);
21
+ })
22
+
23
+ }
24
+ static template() {
25
+ return `
26
+ <div id="standalone-container">
27
+ <div id="toolbar-container">
28
+ <span class="ql-formats">
29
+ <select class="ql-font">
30
+ <option selected>Base</option>
31
+ <option value="mirza">Claude Monet</option>
32
+ <option value="roboto">Ukiyoe</option>
33
+ <option value="cursive">Cyber Punk</option>
34
+ <option value="sofia">Pop Art</option>
35
+ <option value="slabo">Van Gogh</option>
36
+ <option value="inconsolata">Pixel Art</option>
37
+ <option value="ubuntu">Rembrandt</option>
38
+ <option value="Akronim">Cubism</option>
39
+ <option value="Monoton">Neon Art</option>
40
+ </select>
41
+ <select class="ql-size">
42
+ <option value="18px">Small</option>
43
+ <option selected>Normal</option>
44
+ <option value="32px">Large</option>
45
+ <option value="50px">Huge</option>
46
+ </select>
47
+ </span>
48
+ <span class="ql-formats">
49
+ <button class="ql-strike"></button>
50
+ </span>
51
+ <!-- <span class="ql-formats">
52
+ <button class="ql-bold"></button>
53
+ <button class="ql-italic"></button>
54
+ <button class="ql-underline"></button>
55
+ </span> -->
56
+ <span class="ql-formats">
57
+ <select class="ql-color"></select>
58
+ <!-- <select class="ql-background"></select> -->
59
+ </span>
60
+ <!-- <span class="ql-formats">
61
+ <button class="ql-script" value="sub"></button>
62
+ <button class="ql-script" value="super"></button>
63
+ </span>
64
+ <span class="ql-formats">
65
+ <button class="ql-header" value="1"></button>
66
+ <button class="ql-header" value="2"></button>
67
+ <button class="ql-blockquote"></button>
68
+ <button class="ql-code-block"></button>
69
+ </span>
70
+ <span class="ql-formats">
71
+ <button class="ql-list" value="ordered"></button>
72
+ <button class="ql-list" value="bullet"></button>
73
+ <button class="ql-indent" value="-1"></button>
74
+ <button class="ql-indent" value="+1"></button>
75
+ </span>
76
+ <span class="ql-formats">
77
+ <button class="ql-direction" value="rtl"></button>
78
+ <select class="ql-align"></select>
79
+ </span>
80
+ <span class="ql-formats">
81
+ <button class="ql-link"></button>
82
+ <button class="ql-image"></button>
83
+ <button class="ql-video"></button>
84
+ <button class="ql-formula"></button>
85
+ </span> -->
86
+ <span class="ql-formats">
87
+ <button class="ql-link"></button>
88
+ </span>
89
+ <span class="ql-formats">
90
+ <button class="ql-clean"></button>
91
+ </span>
92
+ </div>
93
+ <div id="editor-container"></div>
94
+ </div>
95
+ `;
96
+ }
97
+
98
+ static header() {
99
+ return `
100
+ <link rel="stylesheet" href="https://cdn.quilljs.com/1.3.6/quill.snow.css">
101
+ <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/css/bulma.min.css">
102
+ <style>
103
+ /* Set default font-family */
104
+ .ql-snow .ql-tooltip::before {
105
+ content: "Footnote";
106
+ line-height: 26px;
107
+ margin-right: 8px;
108
+ }
109
+
110
+ .ql-snow .ql-tooltip[data-mode=link]::before {
111
+ content: "Enter footnote:";
112
+ }
113
+
114
+ .row {
115
+ margin-top: 15px;
116
+ margin-left: 0px;
117
+ margin-bottom: 15px;
118
+ }
119
+
120
+ .btn-primary {
121
+ color: #ffffff;
122
+ background-color: #2780e3;
123
+ border-color: #2780e3;
124
+ }
125
+
126
+ .btn-primary:hover {
127
+ color: #ffffff;
128
+ background-color: #1967be;
129
+ border-color: #1862b5;
130
+ }
131
+
132
+ .btn {
133
+ display: inline-block;
134
+ margin-bottom: 0;
135
+ font-weight: normal;
136
+ text-align: center;
137
+ vertical-align: middle;
138
+ touch-action: manipulation;
139
+ cursor: pointer;
140
+ background-image: none;
141
+ border: 1px solid transparent;
142
+ white-space: nowrap;
143
+ padding: 10px 18px;
144
+ font-size: 15px;
145
+ line-height: 1.42857143;
146
+ border-radius: 0;
147
+ user-select: none;
148
+ }
149
+
150
+ #standalone-container {
151
+ position: relative;
152
+ max-width: 720px;
153
+ background-color: #ffffff;
154
+ color: black !important;
155
+ z-index: 1000;
156
+ }
157
+
158
+ #editor-container {
159
+ font-family: "Aref Ruqaa";
160
+ font-size: 18px;
161
+ height: 250px;
162
+ }
163
+
164
+ #toolbar-container {
165
+ font-family: "Aref Ruqaa";
166
+ display: flex;
167
+ flex-wrap: wrap;
168
+ }
169
+
170
+ #json-container {
171
+ max-width: 720px;
172
+ }
173
+
174
+ /* Set dropdown font-families */
175
+ #toolbar-container .ql-font span[data-label="Base"]::before {
176
+ font-family: "Aref Ruqaa";
177
+ }
178
+
179
+ #toolbar-container .ql-font span[data-label="Claude Monet"]::before {
180
+ font-family: "Mirza";
181
+ }
182
+
183
+ #toolbar-container .ql-font span[data-label="Ukiyoe"]::before {
184
+ font-family: "Roboto";
185
+ }
186
+
187
+ #toolbar-container .ql-font span[data-label="Cyber Punk"]::before {
188
+ font-family: "Comic Sans MS";
189
+ }
190
+
191
+ #toolbar-container .ql-font span[data-label="Pop Art"]::before {
192
+ font-family: "sofia";
193
+ }
194
+
195
+ #toolbar-container .ql-font span[data-label="Van Gogh"]::before {
196
+ font-family: "slabo 27px";
197
+ }
198
+
199
+ #toolbar-container .ql-font span[data-label="Pixel Art"]::before {
200
+ font-family: "inconsolata";
201
+ }
202
+
203
+ #toolbar-container .ql-font span[data-label="Rembrandt"]::before {
204
+ font-family: "ubuntu";
205
+ }
206
+
207
+ #toolbar-container .ql-font span[data-label="Cubism"]::before {
208
+ font-family: "Akronim";
209
+ }
210
+
211
+ #toolbar-container .ql-font span[data-label="Neon Art"]::before {
212
+ font-family: "Monoton";
213
+ }
214
+
215
+ /* Set content font-families */
216
+ .ql-font-mirza {
217
+ font-family: "Mirza";
218
+ }
219
+
220
+ .ql-font-roboto {
221
+ font-family: "Roboto";
222
+ }
223
+
224
+ .ql-font-cursive {
225
+ font-family: "Comic Sans MS";
226
+ }
227
+
228
+ .ql-font-sofia {
229
+ font-family: "sofia";
230
+ }
231
+
232
+ .ql-font-slabo {
233
+ font-family: "slabo 27px";
234
+ }
235
+
236
+ .ql-font-inconsolata {
237
+ font-family: "inconsolata";
238
+ }
239
+
240
+ .ql-font-ubuntu {
241
+ font-family: "ubuntu";
242
+ }
243
+
244
+ .ql-font-Akronim {
245
+ font-family: "Akronim";
246
+ }
247
+
248
+ .ql-font-Monoton {
249
+ font-family: "Monoton";
250
+ }
251
+ </style>
252
+ `;
253
+ }
254
+ async mountQuill() {
255
+ // Register the customs format with Quill
256
+ const lib = await import("https://cdn.jsdelivr.net/npm/shadow-selection-polyfill");
257
+ const getRange = lib.getRange;
258
+
259
+ const Font = Quill.import('formats/font');
260
+ Font.whitelist = ['mirza', 'roboto', 'sofia', 'slabo', 'inconsolata', 'ubuntu', 'cursive', 'Akronim', 'Monoton'];
261
+ const Link = Quill.import('formats/link');
262
+ Link.sanitize = function (url) {
263
+ // modify url if desired
264
+ return url;
265
+ }
266
+ const SizeStyle = Quill.import('attributors/style/size');
267
+ SizeStyle.whitelist = ['10px', '18px', '32px', '50px', '64px'];
268
+ Quill.register(SizeStyle, true);
269
+ Quill.register(Link, true);
270
+ Quill.register(Font, true);
271
+ const icons = Quill.import('ui/icons');
272
+ const icon = `<svg xmlns="http://www.w3.org/2000/svg" width="17" viewBox="0 0 512 512" xml:space="preserve"><path fill="#010101" d="M276.75 1c4.51 3.23 9.2 6.04 12.97 9.77 29.7 29.45 59.15 59.14 88.85 88.6 4.98 4.93 7.13 10.37 7.12 17.32-.1 125.8-.09 251.6-.01 377.4 0 7.94-1.96 14.46-9.62 18.57-121.41.34-242.77.34-364.76.05A288.3 288.3 0 0 1 1 502c0-163.02 0-326.04.34-489.62C3.84 6.53 8.04 3.38 13 1c23.35 0 46.7 0 70.82.3 2.07.43 3.38.68 4.69.68h127.98c18.44.01 36.41.04 54.39-.03 1.7 0 3.41-.62 5.12-.95h.75M33.03 122.5v359.05h320.22V129.18h-76.18c-14.22-.01-19.8-5.68-19.8-20.09V33.31H33.02v89.19m256.29-27.36c.72.66 1.44 1.9 2.17 1.9 12.73.12 25.46.08 37.55.08L289.3 57.45v37.7z"/><path fill="#020202" d="M513 375.53c-4.68 7.99-11.52 10.51-20.21 10.25-13.15-.4-26.32-.1-39.48-.1h-5.58c5.49 8.28 10.7 15.74 15.46 23.47 6.06 9.82 1.14 21.65-9.96 24.27-6.7 1.59-12.45-.64-16.23-6.15a2608.6 2608.6 0 0 1-32.97-49.36c-3.57-5.48-3.39-11.54.17-16.98a3122.5 3122.5 0 0 1 32.39-48.56c5.22-7.65 14.67-9.35 21.95-4.45 7.63 5.12 9.6 14.26 4.5 22.33-4.75 7.54-9.8 14.9-15.11 22.95h33.64V225.19h-5.24c-19.49 0-38.97.11-58.46-.05-12.74-.1-20.12-13.15-13.84-24.14 3.12-5.46 8.14-7.71 14.18-7.73 26.15-.06 52.3-.04 78.45 0 7.1 0 12.47 3.05 16.01 9.64.33 57.44.33 114.8.33 172.62z"/><path fill="#111" d="M216.03 1.97C173.52 1.98 131 2 88.5 1.98a16 16 0 0 1-4.22-.68c43.4-.3 87.09-.3 131.24-.06.48.25.5.73.5.73z"/><path fill="#232323" d="M216.5 1.98c-.47 0-.5-.5-.5-.74C235.7 1 255.38 1 275.53 1c-1.24.33-2.94.95-4.65.95-17.98.07-35.95.04-54.39.03z"/><path fill="#040404" d="M148 321.42h153.5c14.25 0 19.96 5.71 19.96 19.97.01 19.17.03 38.33 0 57.5-.03 12.6-6.16 18.78-18.66 18.78H99.81c-12.42 0-18.75-6.34-18.76-18.73-.01-19.83-.02-39.66 0-59.5.02-11.47 6.4-17.93 17.95-18 16.17-.08 32.33-.02 49-.02m40.5 32.15h-75.16v31.84h175.7v-31.84H188.5z"/><path fill="#030303" d="m110 225.33 178.89-.03c11.98 0 19.25 9.95 15.74 21.44-2.05 6.71-7.5 10.57-15.14 10.57-63.63 0-127.25-.01-190.88-.07-12.03-.02-19.17-8.62-16.7-19.84 1.6-7.21 7.17-11.74 15.1-12.04 4.17-.16 8.33-.03 13-.03zm-24.12-36.19c-5.28-6.2-6.3-12.76-2.85-19.73 3.22-6.49 9.13-8.24 15.86-8.24 25.64.01 51.27-.06 76.91.04 13.07.04 20.66 10.44 16.33 22.08-2.25 6.06-6.63 9.76-13.08 9.8-27.97.18-55.94.2-83.9-.07-3.01-.03-6-2.36-9.27-3.88z"/></svg>`
273
+ icons['link'] = icon;
274
+ const editorContainer = this.shadowRoot.querySelector('#editor-container')
275
+ const toolbarContainer = this.shadowRoot.querySelector('#toolbar-container')
276
+ const myQuill = new Quill(editorContainer, {
277
+ modules: {
278
+ toolbar: {
279
+ container: toolbarContainer,
280
+ },
281
+ },
282
+ theme: 'snow'
283
+ });
284
+ const normalizeNative = (nativeRange) => {
285
+
286
+ if (nativeRange) {
287
+ const range = nativeRange;
288
+
289
+ if (range.baseNode) {
290
+ range.startContainer = nativeRange.baseNode;
291
+ range.endContainer = nativeRange.focusNode;
292
+ range.startOffset = nativeRange.baseOffset;
293
+ range.endOffset = nativeRange.focusOffset;
294
+
295
+ if (range.endOffset < range.startOffset) {
296
+ range.startContainer = nativeRange.focusNode;
297
+ range.endContainer = nativeRange.baseNode;
298
+ range.startOffset = nativeRange.focusOffset;
299
+ range.endOffset = nativeRange.baseOffset;
300
+ }
301
+ }
302
+
303
+ if (range.startContainer) {
304
+ return {
305
+ start: { node: range.startContainer, offset: range.startOffset },
306
+ end: { node: range.endContainer, offset: range.endOffset },
307
+ native: range
308
+ };
309
+ }
310
+ }
311
+
312
+ return null
313
+ };
314
+
315
+ myQuill.selection.getNativeRange = () => {
316
+
317
+ const dom = myQuill.root.getRootNode();
318
+ const selection = getRange(dom);
319
+ const range = normalizeNative(selection);
320
+
321
+ return range;
322
+ };
323
+ let fromEditor = false;
324
+ editorContainer.addEventListener("pointerup", (e) => {
325
+ fromEditor = false;
326
+ });
327
+ editorContainer.addEventListener("pointerout", (e) => {
328
+ fromEditor = false;
329
+ });
330
+ editorContainer.addEventListener("pointerdown", (e) => {
331
+ fromEditor = true;
332
+ });
333
+
334
+ document.addEventListener("selectionchange", () => {
335
+ if (fromEditor) {
336
+ myQuill.selection.update()
337
+ }
338
+ });
339
+
340
+
341
+ myQuill.on('text-change', () => {
342
+ // keep qull data inside _data to communicate with Gradio
343
+ document.querySelector("#rich-text-root")._data = myQuill.getContents()
344
+ })
345
+ return myQuill
346
+ }
347
+ }
348
+
349
+ customElements.define('rich-text-editor', RichTextEditor);
utils/__pycache__/attention_utils.cpython-38.pyc DELETED
Binary file (5.27 kB)
 
utils/__pycache__/richtext_utils.cpython-38.pyc DELETED
Binary file (6.57 kB)