demo_streamlit.py 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222
  1. """
  2. Layout Inference Web Application
  3. A Streamlit-based layout inference tool that supports image uploads and multiple backend inference engines.
  4. """
  5. import streamlit as st
  6. import json
  7. import os
  8. import io
  9. import tempfile
  10. from PIL import Image
  11. import requests
  12. # Local utility imports
  13. # from utils import infer
  14. from dots_ocr.utils import dict_promptmode_to_prompt
  15. from dots_ocr.utils.format_transformer import layoutjson2md
  16. from dots_ocr.utils.layout_utils import draw_layout_on_image, post_process_cells
  17. from dots_ocr.utils.image_utils import get_input_dimensions, get_image_by_fitz_doc
  18. from dots_ocr.model.inference import inference_with_vllm
  19. from dots_ocr.utils.consts import MIN_PIXELS, MAX_PIXELS
  20. import os
  21. from PIL import Image
  22. from dots_ocr.utils.demo_utils.display import read_image
  23. # ==================== Configuration ====================
  24. DEFAULT_CONFIG = {
  25. 'ip': "127.0.0.1",
  26. 'port_vllm': 8000,
  27. 'min_pixels': MIN_PIXELS,
  28. 'max_pixels': MAX_PIXELS,
  29. 'test_images_dir': "./assets/showcase_origin",
  30. }
  31. # ==================== Utility Functions ====================
  32. @st.cache_resource
  33. def read_image_v2(img: str):
  34. if img.startswith(("http://", "https://")):
  35. with requests.get(img, stream=True) as response:
  36. response.raise_for_status()
  37. img = Image.open(io.BytesIO(response.content))
  38. if isinstance(img, str):
  39. # img = transform_image_path(img)
  40. img, _, _ = read_image(img, use_native=True)
  41. elif isinstance(img, Image.Image):
  42. pass
  43. else:
  44. raise ValueError(f"Invalid image type: {type(img)}")
  45. return img
  46. # ==================== UI Components ====================
  47. def create_config_sidebar():
  48. """Create configuration sidebar"""
  49. st.sidebar.header("Configuration Parameters")
  50. config = {}
  51. config['prompt_key'] = st.sidebar.selectbox("Prompt Mode", list(dict_promptmode_to_prompt.keys()))
  52. config['ip'] = st.sidebar.text_input("Server IP", DEFAULT_CONFIG['ip'])
  53. config['port'] = st.sidebar.number_input("Port", min_value=1000, max_value=9999, value=DEFAULT_CONFIG['port_vllm'])
  54. # config['eos_word'] = st.sidebar.text_input("EOS Word", DEFAULT_CONFIG['eos_word'])
  55. # Image configuration
  56. st.sidebar.subheader("Image Configuration")
  57. config['min_pixels'] = st.sidebar.number_input("Min Pixels", value=DEFAULT_CONFIG['min_pixels'])
  58. config['max_pixels'] = st.sidebar.number_input("Max Pixels", value=DEFAULT_CONFIG['max_pixels'])
  59. return config
  60. def get_image_input():
  61. """Get image input"""
  62. st.markdown("#### Image Input")
  63. input_mode = st.pills(label="Select input method", options=["Upload Image", "Enter Image URL/Path", "Select Test Image"], key="input_mode", label_visibility="collapsed")
  64. if input_mode == "Upload Image":
  65. # File uploader
  66. uploaded_file = st.file_uploader("Upload Image", type=["png", "jpg", "jpeg"])
  67. if uploaded_file is not None:
  68. with tempfile.NamedTemporaryFile(delete=False, suffix='.png') as tmp_file:
  69. tmp_file.write(uploaded_file.getvalue())
  70. return tmp_file.name
  71. elif input_mode == 'Enter Image URL/Path':
  72. # URL input
  73. img_url_input = st.text_input("Enter Image URL/Path")
  74. return img_url_input
  75. elif input_mode == 'Select Test Image':
  76. # Test image selection
  77. test_images = []
  78. test_dir = DEFAULT_CONFIG['test_images_dir']
  79. if os.path.exists(test_dir):
  80. test_images = [os.path.join(test_dir, name) for name in os.listdir(test_dir)]
  81. img_url_test = st.selectbox("Select Test Image", [""] + test_images)
  82. return img_url_test
  83. else:
  84. raise ValueError(f"Invalid input mode: {input_mode}")
  85. return None
  86. def process_and_display_results(output: str, image: Image.Image, config: dict):
  87. """Process and display inference results"""
  88. prompt, response = output['prompt'], output['response']
  89. try:
  90. col1, col2 = st.columns(2)
  91. # st.markdown('---')
  92. cells = json.loads(response)
  93. # image = Image.open(img_url)
  94. # Post-processing
  95. cells = post_process_cells(
  96. image, cells,
  97. image.width, image.height,
  98. min_pixels=config['min_pixels'],
  99. max_pixels=config['max_pixels']
  100. )
  101. # Calculate input dimensions
  102. input_width, input_height = get_input_dimensions(
  103. image,
  104. min_pixels=config['min_pixels'],
  105. max_pixels=config['max_pixels']
  106. )
  107. st.markdown('---')
  108. st.write(f'Input Dimensions: {input_width} x {input_height}')
  109. # st.write(f'Prompt: {prompt}')
  110. # st.markdown(f'模型原始输出: <span style="color:blue">{result}</span>', unsafe_allow_html=True)
  111. # st.write('模型原始输出:')
  112. # st.write(response)
  113. # st.write('后处理结果:', str(cells))
  114. st.text_area('Original Model Output', response, height=200)
  115. st.text_area('Post-processed Result', str(cells), height=200)
  116. # 显示结果
  117. # st.title("Layout推理结果")
  118. with col1:
  119. # st.markdown("##### 可视化结果")
  120. new_image = draw_layout_on_image(
  121. image, cells,
  122. resized_height=None, resized_width=None,
  123. # text_key='text',
  124. fill_bbox=True, draw_bbox=True
  125. )
  126. st.markdown('##### Visualization Result')
  127. st.image(new_image, width=new_image.width)
  128. # st.write(f"尺寸: {new_image.width} x {new_image.height}")
  129. with col2:
  130. # st.markdown("##### Markdown格式")
  131. md_code = layoutjson2md(image, cells, text_key='text')
  132. # md_code = fix_streamlit_formula(md_code)
  133. st.markdown('##### Markdown Format')
  134. st.markdown(md_code, unsafe_allow_html=True)
  135. except json.JSONDecodeError:
  136. st.error("Model output is not a valid JSON format")
  137. except Exception as e:
  138. st.error(f"Error processing results: {e}")
  139. # ==================== Main Application ====================
  140. def main():
  141. """Main application function"""
  142. st.set_page_config(page_title="Layout Inference Tool", layout="wide")
  143. st.title("🔍 Layout Inference Tool")
  144. # Configuration
  145. config = create_config_sidebar()
  146. prompt = dict_promptmode_to_prompt[config['prompt_key']]
  147. st.sidebar.info(f"Current Prompt: {prompt}")
  148. # Image input
  149. img_url = get_image_input()
  150. start_button = st.button('🚀 Start Inference', type="primary")
  151. if img_url is not None and img_url.strip() != "":
  152. try:
  153. # processed_image = read_image_v2(img_url)
  154. origin_image = read_image_v2(img_url)
  155. st.write(f"Original Dimensions: {origin_image.width} x {origin_image.height}")
  156. # processed_image = get_image_by_fitz_doc(origin_image, target_dpi=200)
  157. processed_image = origin_image
  158. except Exception as e:
  159. st.error(f"Failed to read image: {e}")
  160. return
  161. else:
  162. st.info("Please enter an image URL/path or upload an image")
  163. return
  164. output = None
  165. # Inference button
  166. if start_button:
  167. with st.spinner(f"Inferring... Server: {config['ip']}:{config['port']}"):
  168. response = inference_with_vllm(
  169. processed_image, prompt, config['ip'], config['port'],
  170. # config['min_pixels'], config['max_pixels']
  171. )
  172. output = {
  173. 'prompt': prompt,
  174. 'response': response,
  175. }
  176. else:
  177. st.image(processed_image, width=500)
  178. # Process results
  179. if output:
  180. process_and_display_results(output, processed_image, config)
  181. if __name__ == "__main__":
  182. main()