linjieccc commited on
Commit
2623e99
1 Parent(s): cce9bdf
Files changed (11) hide show
  1. .gitattributes +3 -0
  2. README.md +5 -5
  3. app.py +424 -0
  4. business_card.png +3 -0
  5. custom.jpeg +3 -0
  6. footer.html +4 -0
  7. header.html +31 -0
  8. invoice.jpeg +3 -0
  9. license.jpeg +3 -0
  10. requirements.txt +4 -0
  11. resume.png +3 -0
.gitattributes CHANGED
@@ -32,3 +32,6 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
32
  *.zip filter=lfs diff=lfs merge=lfs -text
33
  *.zst filter=lfs diff=lfs merge=lfs -text
34
  *tfevents* filter=lfs diff=lfs merge=lfs -text
 
 
 
32
  *.zip filter=lfs diff=lfs merge=lfs -text
33
  *.zst filter=lfs diff=lfs merge=lfs -text
34
  *tfevents* filter=lfs diff=lfs merge=lfs -text
35
+ *.psd filter=lfs diff=lfs merge=lfs -text
36
+ *.png filter=lfs diff=lfs merge=lfs -text
37
+ *.jpeg filter=lfs diff=lfs merge=lfs -text
README.md CHANGED
@@ -1,10 +1,10 @@
1
  ---
2
- title: UIE X
3
- emoji: 🐠
4
- colorFrom: blue
5
- colorTo: purple
6
  sdk: gradio
7
- sdk_version: 3.13.0
8
  app_file: app.py
9
  pinned: false
10
  license: apache-2.0
1
  ---
2
+ title: UIE-X
3
+ emoji: 🧾
4
+ colorFrom: gray
5
+ colorTo: pink
6
  sdk: gradio
7
+ sdk_version: 3.4.1
8
  app_file: app.py
9
  pinned: false
10
  license: apache-2.0
app.py ADDED
@@ -0,0 +1,424 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #-*- coding: UTF-8 -*-
2
+ # Copyright 2022 The Impira Team and the HuggingFace Team.
3
+ # Copyright (c) 2022 PaddlePaddle Authors. All Rights Reserved.
4
+ #
5
+ # Licensed under the Apache License, Version 2.0 (the "License");
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS,
13
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ # See the License for the specific language governing permissions and
15
+ # limitations under the License.
16
+
17
+ import os
18
+ import json
19
+ import base64
20
+ from io import BytesIO
21
+ from PIL import Image
22
+ import traceback
23
+
24
+ import requests
25
+ import numpy as np
26
+ import gradio as gr
27
+ import cv2
28
+
29
+ from paddlenlp.utils.doc_parser import DocParser
30
+
31
+ doc_parser = DocParser()
32
+
33
+ examples = [
34
+ [
35
+ "business_card.png",
36
+ "Name;Title;Web Link;Email;Address",
37
+ ],
38
+ [
39
+ "license.jpeg",
40
+ "Name;DOB;ISS;EXP",
41
+ ],
42
+ [
43
+ "invoice.jpeg",
44
+ "名称;纳税人识别号;开票日期",
45
+ ],
46
+ [
47
+ "custom.jpeg",
48
+ "收发货人;进口口岸;进口日期;运输方式;征免性质;境内目的地;运输工具名称;包装种类;件数;合同协议号"
49
+ ],
50
+ [
51
+ "resume.png",
52
+ "职位;年龄;学校|时间;学校|专业",
53
+ ],
54
+ ]
55
+
56
+ example_files = {
57
+ "Name;Title;Web Link;Email;Address": "business_card.png",
58
+ "Name;DOB;ISS;EXP": "license.jpeg",
59
+ "职位;年龄;学校|时间;学校|专业": "resume.png",
60
+ "收发货人;进口口岸;进口日期;运输方式;征免性质;境内目的地;运输工具名称;包装种类;件数;合同协议号": "custom.jpeg",
61
+ "名称;纳税人识别号;开票日期": "invoice.jpeg",
62
+ }
63
+
64
+ lang_map = {
65
+ "resume.png": "ch-no",
66
+ "custom.jpeg": "ch-no",
67
+ "business_card.png": "en-no",
68
+ "invoice.jpeg": "ch-no",
69
+ "license.jpeg": "en-no",
70
+ }
71
+
72
+ def dbc2sbc(s):
73
+ rs = ""
74
+ for char in s:
75
+ code = ord(char)
76
+ if code == 0x3000:
77
+ code = 0x0020
78
+ else:
79
+ code -= 0xfee0
80
+ if not (0x0021 <= code and code <= 0x7e):
81
+ rs += char
82
+ continue
83
+ rs += chr(code)
84
+ return rs
85
+
86
+
87
+ def process_path(path):
88
+ error = None
89
+ if path:
90
+ try:
91
+ images_list = [doc_parser.read_image(path)]
92
+ return (
93
+ path,
94
+ gr.update(visible=True, value=images_list),
95
+ gr.update(visible=True),
96
+ gr.update(visible=False, value=None),
97
+ gr.update(visible=False, value=None),
98
+ None,
99
+ )
100
+ except Exception as e:
101
+ traceback.print_exc()
102
+ error = str(e)
103
+ return (
104
+ None,
105
+ gr.update(visible=False, value=None),
106
+ gr.update(visible=False),
107
+ gr.update(visible=False, value=None),
108
+ gr.update(visible=False, value=None),
109
+ gr.update(visible=True, value=error) if error is not None else None,
110
+ None,
111
+ )
112
+
113
+
114
+ def process_upload(file):
115
+ if file:
116
+ return process_path(file.name)
117
+ else:
118
+ return (
119
+ None,
120
+ gr.update(visible=False, value=None),
121
+ gr.update(visible=False),
122
+ gr.update(visible=False, value=None),
123
+ gr.update(visible=False, value=None),
124
+ None,
125
+ )
126
+
127
+
128
+ def BGR2RGB(img):
129
+ pilimg = img.copy()
130
+ pilimg[:, :, 0] = img[:, :, 2]
131
+ pilimg[:, :, 2] = img[:, :, 0]
132
+ return pilimg
133
+
134
+
135
+ def np2base64(image_np):
136
+ image_np = BGR2RGB(image_np)
137
+ image = cv2.imencode('.jpg', image_np)[1]
138
+ base64_str = str(base64.b64encode(image))[2:-1]
139
+ return base64_str
140
+
141
+
142
+ def process_doc(document, schema, ocr_lang, layout_analysis):
143
+ if not schema:
144
+ schema = '时间;组织机构;人物'
145
+ if document is None:
146
+ return None, None
147
+
148
+ option = ocr_lang + "-" + layout_analysis
149
+
150
+ schema = dbc2sbc(schema)
151
+
152
+ access_token = os.environ['token']
153
+ url = f"https://aip.baidubce.com/rpc/2.0/nlp-itec/poc/ie?access_token={access_token}"
154
+
155
+ base64_str = np2base64(doc_parser.read_image(document))
156
+
157
+ r = requests.post(url, json={"doc": base64_str, "schema": schema, "option": option})
158
+ response = r.json()
159
+ print(response)
160
+ predictions = response['result']
161
+
162
+ img_show = doc_parser.write_image_with_results(
163
+ base64_str,
164
+ result=predictions,
165
+ max_size=2000,
166
+ return_image=True)
167
+ img_list = [img_show]
168
+
169
+ return (
170
+ gr.update(visible=True, value=img_list),
171
+ gr.update(visible=True, value=predictions),
172
+ )
173
+
174
+
175
+ def load_example_document(img, schema, ocr_lang, layout_analysis):
176
+ if img is not None:
177
+ document = example_files[schema]
178
+ ocr_lang, layout_analysis = lang_map[document].split("-")
179
+ preview, answer = process_doc(document, schema, ocr_lang, layout_analysis)
180
+ return document, schema, preview, gr.update(visible=True), answer
181
+ else:
182
+ return None, None, None, gr.update(visible=False), None
183
+
184
+
185
+ def read_content(file_path: str) -> str:
186
+ """read the content of target file
187
+ """
188
+ with open(file_path, 'r', encoding='utf-8') as f:
189
+ content = f.read()
190
+
191
+ return content
192
+
193
+
194
+ CSS = """
195
+ #prompt input {
196
+ font-size: 16px;
197
+ }
198
+ #url-textbox {
199
+ padding: 0 !important;
200
+ }
201
+ #short-upload-box .w-full {
202
+ min-height: 10rem !important;
203
+ }
204
+ /* I think something like this can be used to re-shape
205
+ * the table
206
+ */
207
+ /*
208
+ .gr-samples-table tr {
209
+ display: inline;
210
+ }
211
+ .gr-samples-table .p-2 {
212
+ width: 100px;
213
+ }
214
+ */
215
+ #select-a-file {
216
+ width: 100%;
217
+ }
218
+ #file-clear {
219
+ padding-top: 2px !important;
220
+ padding-bottom: 2px !important;
221
+ padding-left: 8px !important;
222
+ padding-right: 8px !important;
223
+ margin-top: 10px;
224
+ }
225
+ .gradio-container .gr-button-primary {
226
+ background: linear-gradient(180deg, #CDF9BE 0%, #AFF497 100%);
227
+ border: 1px solid #B0DCCC;
228
+ border-radius: 8px;
229
+ color: #1B8700;
230
+ }
231
+ .gradio-container.dark button#submit-button {
232
+ background: linear-gradient(180deg, #CDF9BE 0%, #AFF497 100%);
233
+ border: 1px solid #B0DCCC;
234
+ border-radius: 8px;
235
+ color: #1B8700
236
+ }
237
+ table.gr-samples-table tr td {
238
+ border: none;
239
+ outline: none;
240
+ }
241
+ table.gr-samples-table tr td:first-of-type {
242
+ width: 0%;
243
+ }
244
+ div#short-upload-box div.absolute {
245
+ display: none !important;
246
+ }
247
+ gradio-app > div > div > div > div.w-full > div, .gradio-app > div > div > div > div.w-full > div {
248
+ gap: 0px 2%;
249
+ }
250
+ gradio-app div div div div.w-full, .gradio-app div div div div.w-full {
251
+ gap: 0px;
252
+ }
253
+ gradio-app h2, .gradio-app h2 {
254
+ padding-top: 10px;
255
+ }
256
+ #answer {
257
+ overflow-y: scroll;
258
+ color: white;
259
+ background: #666;
260
+ border-color: #666;
261
+ font-size: 20px;
262
+ font-weight: bold;
263
+ }
264
+ #answer span {
265
+ color: white;
266
+ }
267
+ #answer textarea {
268
+ color:white;
269
+ background: #777;
270
+ border-color: #777;
271
+ font-size: 18px;
272
+ }
273
+ #url-error input {
274
+ color: red;
275
+ }
276
+ """
277
+
278
+ with gr.Blocks(css=CSS) as demo:
279
+ gr.HTML(read_content("header.html"))
280
+ gr.Markdown(
281
+ "**UIE-X 🧾 🎓** is a universal information extraction engine which supports both document and text inputs. It is powered by BAIDU and released on PaddleNLP. "
282
+ "Our extraction target(schema) can be set in natural language without limitation, and it also supports most extraction tasks. "
283
+ "The model performs well on zero-shot and few-shot settings. Moreover, on PaddleNLP, we provide a comprehensive and easy-to-use fine-tuning customization workflow."
284
+ "For more details, please visit the [GitHub](https://github.com/PaddlePaddle/PaddleNLP/tree/develop/applications/information_extraction)"
285
+ )
286
+
287
+ document = gr.Variable()
288
+ is_text = gr.Variable()
289
+ example_schema = gr.Textbox(visible=False)
290
+ example_image = gr.Image(visible=False)
291
+ with gr.Row(equal_height=True):
292
+ with gr.Column():
293
+ with gr.Row():
294
+ gr.Markdown("## 1. 选择文件 / Select a file 📄", elem_id="select-a-file")
295
+ img_clear_button = gr.Button(
296
+ "Clear", variant="secondary", elem_id="file-clear", visible=False
297
+ )
298
+ image = gr.Gallery(visible=False)
299
+ with gr.Row(equal_height=True):
300
+ with gr.Column():
301
+ with gr.Row():
302
+ url = gr.Textbox(
303
+ show_label=False,
304
+ placeholder="URL",
305
+ lines=1,
306
+ max_lines=1,
307
+ elem_id="url-textbox",
308
+ )
309
+ submit = gr.Button("Get")
310
+ url_error = gr.Textbox(
311
+ visible=False,
312
+ elem_id="url-error",
313
+ max_lines=1,
314
+ interactive=False,
315
+ label="Error",
316
+ )
317
+ gr.Markdown("— or —")
318
+ upload = gr.File(label=None, interactive=True, elem_id="short-upload-box")
319
+ gr.Examples(
320
+ examples=examples,
321
+ inputs=[example_image, example_schema],
322
+ )
323
+
324
+ with gr.Column():
325
+ gr.Markdown("## 2. 信息抽取 / Information extraction ℹ️ ")
326
+ gr.Markdown("### 👉 设置schema")
327
+ gr.Markdown("实体抽取:实体类别之间以';'分割,例如 **人物;组织机构**")
328
+ gr.Markdown("关系抽取:需配置主体和关系类别,中间以'|'分割,例如 **人物|出生时间;人物|邮箱**")
329
+ gr.Markdown("### 👉 Set a schema")
330
+ gr.Markdown("Entity extraction: entity label should be separated by ';', e.g. **Person;Organization**")
331
+ gr.Markdown("Relation extraction: set the subject and relation type, separated by '|', e.g. **Person|Date;Person|Email**")
332
+ gr.Markdown("### 💪 模型定制 / Model customization")
333
+ gr.Markdown("我们建议通过[数据标注+微调](https://github.com/PaddlePaddle/PaddleNLP/tree/develop/applications/information_extraction/document)的流程进一步增强模型在特定场景的效果")
334
+ gr.Markdown("We recommend to further improve the extraction performance in specific domain through the process of [data annotation & fine-tuning](https://github.com/PaddlePaddle/PaddleNLP/tree/develop/applications/information_extraction/document)")
335
+
336
+ schema = gr.Textbox(
337
+ label="Schema",
338
+ placeholder="e.g. Name|Company;Name|Position;Email;Phone Number",
339
+ lines=1,
340
+ max_lines=1,
341
+ )
342
+
343
+ ocr_lang = gr.Radio(
344
+ choices=["ch", "en"],
345
+ value="en",
346
+ label="OCR语言 / OCR Language (Please choose ch for Chinese images.)",
347
+ )
348
+
349
+ layout_analysis = gr.Radio(
350
+ choices=["yes", "no"],
351
+ value="no",
352
+ label="版面分析 / Layout analysis (Better extraction for multi-line text)",
353
+ )
354
+
355
+ with gr.Row():
356
+ clear_button = gr.Button("Clear", variant="secondary")
357
+ submit_button = gr.Button(
358
+ "Submit", variant="primary", elem_id="submit-button"
359
+ )
360
+ with gr.Column():
361
+ output = gr.JSON(label="Output", visible=False)
362
+
363
+ for cb in [img_clear_button, clear_button]:
364
+ cb.click(
365
+ lambda _: (
366
+ gr.update(visible=False, value=None),
367
+ None,
368
+ gr.update(visible=False, value=None),
369
+ gr.update(visible=False),
370
+ None,
371
+ None,
372
+ None,
373
+ gr.update(visible=False, value=None),
374
+ None,
375
+ ),
376
+ inputs=clear_button,
377
+ outputs=[
378
+ image,
379
+ document,
380
+ output,
381
+ img_clear_button,
382
+ example_image,
383
+ upload,
384
+ url,
385
+ url_error,
386
+ schema,
387
+ ],
388
+ )
389
+
390
+ upload.change(
391
+ fn=process_upload,
392
+ inputs=[upload],
393
+ outputs=[document, image, img_clear_button, output, url_error],
394
+ )
395
+ submit.click(
396
+ fn=process_path,
397
+ inputs=[url],
398
+ outputs=[document, image, img_clear_button, output, url_error],
399
+ )
400
+
401
+ schema.submit(
402
+ fn=process_doc,
403
+ inputs=[document, schema, ocr_lang, layout_analysis],
404
+ outputs=[image, output],
405
+ )
406
+
407
+ submit_button.click(
408
+ fn=process_doc,
409
+ inputs=[document, schema, ocr_lang, layout_analysis],
410
+ outputs=[image, output],
411
+ )
412
+
413
+ example_image.change(
414
+ fn=load_example_document,
415
+ inputs=[example_image, example_schema, ocr_lang, layout_analysis],
416
+ outputs=[document, schema, image, img_clear_button, output],
417
+ )
418
+
419
+ gr.Markdown("[![Stargazers repo roster for @PaddlePaddle/PaddleNLP](https://reporoster.com/stars/PaddlePaddle/PaddleNLP)](https://github.com/PaddlePaddle/PaddleNLP)")
420
+ gr.HTML(read_content("footer.html"))
421
+
422
+
423
+ if __name__ == "__main__":
424
+ demo.launch(enable_queue=False)
business_card.png ADDED

Git LFS Details

  • SHA256: 68aa93a2b4122a517fac752507a4c65218fbaccbf16385afec02dbac0ecdbbdc
  • Pointer size: 131 Bytes
  • Size of remote file: 313 kB
custom.jpeg ADDED

Git LFS Details

  • SHA256: b0d83ab6cac4747e00192474a2e8636285bddfcab884c4083ad30c6284f13b10
  • Pointer size: 131 Bytes
  • Size of remote file: 520 kB
footer.html ADDED
@@ -0,0 +1,4 @@
 
 
 
 
1
+ <div class="footer">
2
+ <p>Model by <a href="https://github.com/PaddlePaddle/PaddleNLP" style="text-decoration: underline;" target="_blank">PaddleNLP</a> - Gradio Demo by 🤗 Hugging Face
3
+ </p>
4
+ </div>
header.html ADDED
@@ -0,0 +1,31 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <div style="text-align: center; max-width: 650px; margin: 0 auto;">
2
+ <div
3
+ style="
4
+ display: inline-flex;
5
+ gap: 0.8rem;
6
+ font-size: 1.75rem;
7
+ margin-bottom: 10px;
8
+ margin-left: 220px;
9
+ justify-content: center;
10
+ "
11
+ >
12
+ <a href="https://github.com/PaddlePaddle/PaddleNLP"><img src="https://user-images.githubusercontent.com/1371212/175816733-8ec25eb0-9af3-4380-9218-27c154518258.png" alt="PaddleNLP" width="60%"></a>
13
+ </div>
14
+ <div
15
+ style="
16
+ display: inline-flex;
17
+ align-items: center;
18
+ gap: 0.8rem;
19
+ font-size: 1.75rem;
20
+ margin-bottom: 10px;
21
+ justify-content: center;
22
+ ">
23
+ <a href="https://github.com/PaddlePaddle/PaddleNLP/tree/develop/model_zoo/ernie-layout"><h1 style="font-weight: 900; align-items: center; margin-bottom: 7px;">
24
+ UIE-X 📰
25
+ </h1></a>
26
+ </div>
27
+ <!-- <p style="margin-bottom: 10px; font-size: 94%">
28
+ DocPrompt🔖 is a Document Prompt Engine using [ERNIE-Layout](https://github.com/PaddlePaddle/PaddleNLP/tree/develop/model_zoo/ernie-layout) as the backbone model. The engine is powered by BAIDU WenXin Document Intelligence Team and has the ability for multilingual documents information extraction and question ansering.
29
+ </p> -->
30
+ <a href="https://github.com/PaddlePaddle/PaddleNLP"><img src="https://user-images.githubusercontent.com/40840292/195516769-c4452d7c-3f9e-446f-8f9d-882b99052a5b.png" width="100%"></a>
31
+ </div>
invoice.jpeg ADDED

Git LFS Details

  • SHA256: a3afad8c016954d8f5b1e79cc9209ca54318c860e0228a812d3e75805cd50f4b
  • Pointer size: 132 Bytes
  • Size of remote file: 2.83 MB
license.jpeg ADDED

Git LFS Details

  • SHA256: 3fd243446a474f8c7de06b92da796e6a36d0604b4c83d7c30c027a8d3525a766
  • Pointer size: 131 Bytes
  • Size of remote file: 102 kB
requirements.txt ADDED
@@ -0,0 +1,4 @@
 
 
 
 
1
+ numpy
2
+ opencv-python
3
+ paddlenlp
4
+ requests
resume.png ADDED

Git LFS Details

  • SHA256: 7be8498397a59f6aedf3cbee96041aea96b5d8f1aa667cf1d3ac5e93a7716734
  • Pointer size: 131 Bytes
  • Size of remote file: 191 kB