From 8b248bb420fc3a5484b07be4ade8d65372ec0399 Mon Sep 17 00:00:00 2001 From: songw Date: Wed, 19 Apr 2023 11:50:34 +0800 Subject: [PATCH] add build.yaml Dockerfile app.py document.png requirements.txt --- .gitea/workflows/build.yaml | 47 ++++++++++++++++++++ Dockerfile | 18 ++++++++ app.py | 84 ++++++++++++++++++++++++++++++++++++ document.png | Bin 0 -> 22717 bytes requirements.txt | 8 ++++ 5 files changed, 157 insertions(+) create mode 100644 .gitea/workflows/build.yaml create mode 100644 Dockerfile create mode 100644 app.py create mode 100644 document.png create mode 100644 requirements.txt diff --git a/.gitea/workflows/build.yaml b/.gitea/workflows/build.yaml new file mode 100644 index 0000000..1966567 --- /dev/null +++ b/.gitea/workflows/build.yaml @@ -0,0 +1,47 @@ +name: Build +run-name: ${{ github.actor }} is upgrade release πŸš€ +on: [push] +env: + REPOSITORY: ${{ github.repository }} + COMMIT_ID: ${{ github.sha }} +jobs: + Build-Deploy-Actions: + runs-on: ubuntu-latest + steps: + - run: echo "πŸŽ‰ The job was automatically triggered by a ${{ github.event_name }} event." + - run: echo "🐧 This job is now running on a ${{ runner.os }} server hosted by Gitea!" + - run: echo "πŸ”Ž The name of your branch is ${{ github.ref }} and your repository is ${{ github.repository }}." + - name: Check out repository code + uses: actions/checkout@v3 + - + name: Setup Git LFS + run: | + git lfs install + git lfs fetch + git lfs checkout + - name: List files in the repository + run: | + ls ${{ github.workspace }} + - + name: Docker Image Info + id: image-info + run: | + echo "::set-output name=image_name::$(echo $REPOSITORY | tr '[:upper:]' '[:lower:]')" + echo "::set-output name=image_tag::${COMMIT_ID:0:10}" + - + name: Login to Docker Hub + uses: docker/login-action@v2 + with: + registry: artifacts.iflytek.com + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v2 + - + name: Build and push + run: | + docker version + docker buildx build -t artifacts.iflytek.com/docker-private/atp/${{ steps.image-info.outputs.image_name }}:${{ steps.image-info.outputs.image_tag }} . --file ${{ github.workspace }}/Dockerfile --load + docker push artifacts.iflytek.com/docker-private/atp/${{ steps.image-info.outputs.image_name }}:${{ steps.image-info.outputs.image_tag }} + docker rmi artifacts.iflytek.com/docker-private/atp/${{ steps.image-info.outputs.image_name }}:${{ steps.image-info.outputs.image_tag }} + - run: echo "🍏 This job's status is ${{ job.status }}." diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..199f4b3 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,18 @@ +FROM python:3.8.13 + +WORKDIR /app + +COPY . /app + +RUN pip config set global.index-url https://pypi.mirrors.ustc.edu.cn/simple + +ENV PYHTONUNBUFFERED=1 +RUN apt-get update && apt-get -y install tesseract-ocr + +RUN pip install pyyaml==5.1 + +RUN pip install -r requirements.txt + +RUN pip install 'git+https://ghproxy.com/https://github.com/facebookresearch/detectron2.git' + +CMD ["python", "app.py"] diff --git a/app.py b/app.py new file mode 100644 index 0000000..ec1d42f --- /dev/null +++ b/app.py @@ -0,0 +1,84 @@ +import gradio as gr +import numpy as np +from transformers import LayoutLMv2Processor, LayoutLMv2ForTokenClassification +from datasets import load_dataset +from PIL import Image, ImageDraw, ImageFont +from gradio.themes.utils import sizes + + +theme = gr.themes.Default(radius_size=sizes.radius_none).set( + block_label_text_color = '#4D63FF', + block_title_text_color = '#4D63FF', + button_primary_text_color = '#4D63FF', + button_primary_background_fill='#FFFFFF', + button_primary_border_color='#4D63FF', + button_primary_background_fill_hover='#EDEFFF', +) + +processor = LayoutLMv2Processor.from_pretrained("microsoft/layoutlmv2-base-uncased") +model = LayoutLMv2ForTokenClassification.from_pretrained("nielsr/layoutlmv2-finetuned-funsd") + +labels = ['O', 'B-HEADER', 'I-HEADER', 'B-QUESTION', 'I-QUESTION', 'B-ANSWER', 'I-ANSWER'] +id2label = {0: 'O', 1: 'B-HEADER', 2: 'I-HEADER', 3: 'B-QUESTION', 4: 'I-QUESTION', 5: 'B-ANSWER', 6: 'I-ANSWER'} +label2color = {'question':'blue', 'answer':'green', 'header':'orange', 'other':'violet'} + +def unnormalize_box(bbox, width, height): + return [ + width * (bbox[0] / 1000), + height * (bbox[1] / 1000), + width * (bbox[2] / 1000), + height * (bbox[3] / 1000), + ] + +def iob_to_label(label): + label = label[2:] + if not label: + return 'other' + return label + +def process_image(image): + width, height = image.size + + # encode + encoding = processor(image, truncation=True, return_offsets_mapping=True, return_tensors="pt") + offset_mapping = encoding.pop('offset_mapping') + + # forward pass + outputs = model(**encoding) + + # get predictions + predictions = outputs.logits.argmax(-1).squeeze().tolist() + token_boxes = encoding.bbox.squeeze().tolist() + + # only keep non-subword predictions + is_subword = np.array(offset_mapping.squeeze().tolist())[:,0] != 0 + true_predictions = [id2label[pred] for idx, pred in enumerate(predictions) if not is_subword[idx]] + true_boxes = [unnormalize_box(box, width, height) for idx, box in enumerate(token_boxes) if not is_subword[idx]] + + # draw predictions over the image + draw = ImageDraw.Draw(image) + font = ImageFont.load_default() + for prediction, box in zip(true_predictions, true_boxes): + predicted_label = iob_to_label(prediction).lower() + draw.rectangle(box, outline=label2color[predicted_label]) + draw.text((box[0]+10, box[1]-10), text=predicted_label, fill=label2color[predicted_label], font=font) + + return image + +with gr.Blocks(theme=theme, css="footer {visibility: hidden}") as demo: + gr.Markdown(""" +
ζ–‡ζ‘£η‰ˆι’εˆ†ζž
+ """) + with gr.Row(): + with gr.Column(): + image_input =gr.inputs.Image(type="pil", label="图片") + with gr.Row(): + button = gr.Button("提亀", variant="primary") + image_output = gr.Image(label="图片") + + button.click(fn=process_image, inputs=image_input, outputs=image_output) + examples = gr.Examples(examples=[['document.png']], inputs=[image_input], label="例子") + + +if __name__ == "__main__": + demo.queue(concurrency_count=3).launch(server_name = "0.0.0.0") diff --git a/document.png b/document.png new file mode 100644 index 0000000000000000000000000000000000000000..e161a39ab3019d89260af19ea91fc59e13149b92 GIT binary patch literal 22717 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