File size: 8,120 Bytes
b56e481
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
"""

Layout Inference Web Application



A Streamlit-based layout inference tool that supports image uploads and multiple backend inference engines.

"""

import streamlit as st
import json
import os
import io
import tempfile
from PIL import Image
import requests

# Local utility imports

# from utils import infer

from dots_ocr.utils import dict_promptmode_to_prompt
from dots_ocr.utils.format_transformer import layoutjson2md
from dots_ocr.utils.layout_utils import draw_layout_on_image, post_process_cells
from dots_ocr.utils.image_utils import get_input_dimensions, get_image_by_fitz_doc
from dots_ocr.model.inference import inference_with_vllm
from dots_ocr.utils.consts import MIN_PIXELS, MAX_PIXELS

import os
from PIL import Image
from dots_ocr.utils.demo_utils.display import read_image



# ==================== Configuration ====================
DEFAULT_CONFIG = {
    'ip': "127.0.0.1",
    'port_vllm': 8000,
    'min_pixels': MIN_PIXELS,
    'max_pixels': MAX_PIXELS,
    'test_images_dir': "./assets/showcase_origin",
}

# ==================== Utility Functions ====================


@st.cache_resource
def read_image_v2(img: str):
    if img.startswith(("http://", "https://")):
        with requests.get(img, stream=True) as response:
            response.raise_for_status()
            img = Image.open(io.BytesIO(response.content))

    if isinstance(img, str):
        # img = transform_image_path(img)
        img, _, _ = read_image(img, use_native=True)
    elif isinstance(img, Image.Image):
        pass
    else:
        raise ValueError(f"Invalid image type: {type(img)}")
    return img


# ==================== UI Components ====================
def create_config_sidebar():
    """Create configuration sidebar"""
    st.sidebar.header("Configuration Parameters")
    
    config = {}
    config['prompt_key'] = st.sidebar.selectbox("Prompt Mode", list(dict_promptmode_to_prompt.keys()))
    config['ip'] = st.sidebar.text_input("Server IP", DEFAULT_CONFIG['ip'])
    config['port'] = st.sidebar.number_input("Port", min_value=1000, max_value=9999, value=DEFAULT_CONFIG['port_vllm'])
    # config['eos_word'] = st.sidebar.text_input("EOS Word", DEFAULT_CONFIG['eos_word'])
    
    # Image configuration
    st.sidebar.subheader("Image Configuration")
    config['min_pixels'] = st.sidebar.number_input("Min Pixels", value=DEFAULT_CONFIG['min_pixels'])
    config['max_pixels'] = st.sidebar.number_input("Max Pixels", value=DEFAULT_CONFIG['max_pixels'])
    
    return config

def get_image_input():
    """Get image input"""
    st.markdown("#### Image Input")
    
    input_mode = st.pills(label="Select input method", options=["Upload Image", "Enter Image URL/Path", "Select Test Image"], key="input_mode", label_visibility="collapsed")

    if input_mode == "Upload Image":
        # File uploader
        uploaded_file = st.file_uploader("Upload Image", type=["png", "jpg", "jpeg"])
        if uploaded_file is not None:
            with tempfile.NamedTemporaryFile(delete=False, suffix='.png') as tmp_file:
                tmp_file.write(uploaded_file.getvalue())
                return tmp_file.name
    elif input_mode == 'Enter Image URL/Path':
        # URL input
        img_url_input = st.text_input("Enter Image URL/Path")
        return img_url_input

    elif input_mode == 'Select Test Image':
        # Test image selection
        test_images = []
        test_dir = DEFAULT_CONFIG['test_images_dir']
        if os.path.exists(test_dir):
            test_images = [os.path.join(test_dir, name) for name in os.listdir(test_dir)]
        img_url_test = st.selectbox("Select Test Image", [""] + test_images)
        return img_url_test
    else:
        raise ValueError(f"Invalid input mode: {input_mode}")

    return None



def process_and_display_results(output: str, image: Image.Image, config: dict):
    """Process and display inference results"""
    prompt, response = output['prompt'], output['response']
    
    try:
        col1, col2 = st.columns(2)
        # st.markdown('---')
        cells = json.loads(response)
        # image = Image.open(img_url)
        
        # Post-processing
        cells = post_process_cells(
            image, cells,
            image.width, image.height,
            min_pixels=config['min_pixels'],
            max_pixels=config['max_pixels']
        )
        
        # Calculate input dimensions
        input_width, input_height = get_input_dimensions(
            image,
            min_pixels=config['min_pixels'],
            max_pixels=config['max_pixels']
        )
        st.markdown('---')
        st.write(f'Input Dimensions: {input_width} x {input_height}')
        # st.write(f'Prompt: {prompt}')
        # st.markdown(f'模型原始输出: <span style="color:blue">{result}</span>', unsafe_allow_html=True)
        # st.write('模型原始输出:')
        # st.write(response)
        # st.write('后处理结果:', str(cells))
        st.text_area('Original Model Output', response, height=200)
        st.text_area('Post-processed Result', str(cells), height=200)
        # 显示结果
        # st.title("Layout推理结果")
        
        with col1:
            # st.markdown("##### 可视化结果")
            new_image = draw_layout_on_image(
                image, cells, 
                resized_height=None, resized_width=None,
                # text_key='text', 
                fill_bbox=True, draw_bbox=True
            )
            st.markdown('##### Visualization Result')
            st.image(new_image, width=new_image.width)
            # st.write(f"尺寸: {new_image.width} x {new_image.height}")
        
        with col2:
            # st.markdown("##### Markdown格式")
            md_code = layoutjson2md(image, cells, text_key='text')
            # md_code = fix_streamlit_formula(md_code)
            st.markdown('##### Markdown Format')
            st.markdown(md_code, unsafe_allow_html=True)
            
    except json.JSONDecodeError:
        st.error("Model output is not a valid JSON format")
    except Exception as e:
        st.error(f"Error processing results: {e}")

# ==================== Main Application ====================
def main():
    """Main application function"""
    st.set_page_config(page_title="Layout Inference Tool", layout="wide")
    st.title("🔍 Layout Inference Tool")
    
    # Configuration
    config = create_config_sidebar()
    prompt = dict_promptmode_to_prompt[config['prompt_key']]
    st.sidebar.info(f"Current Prompt: {prompt}")
    
    # Image input
    img_url = get_image_input()
    start_button = st.button('🚀 Start Inference', type="primary")
    
    if img_url is not None and img_url.strip() != "":
        try:
            # processed_image = read_image_v2(img_url)
            origin_image = read_image_v2(img_url)
            st.write(f"Original Dimensions: {origin_image.width} x {origin_image.height}")
            # processed_image = get_image_by_fitz_doc(origin_image, target_dpi=200)
            processed_image = origin_image
        except Exception as e:
            st.error(f"Failed to read image: {e}")
            return
    else:
        st.info("Please enter an image URL/path or upload an image")
        return

    output = None
    # Inference button
    if start_button:
        with st.spinner(f"Inferring... Server: {config['ip']}:{config['port']}"):
            
            response = inference_with_vllm(
                processed_image, prompt, config['ip'], config['port'],
                # config['min_pixels'], config['max_pixels']
            )
            output = {
                'prompt': prompt,
                'response': response,
            }
    else:
        st.image(processed_image, width=500)

    # Process results
    if output:
        process_and_display_results(output, processed_image, config)

if __name__ == "__main__":
    main()