JohnTan38 commited on
Commit
a932ccf
1 Parent(s): 6c16e4c

Upload 6 files

Browse files
Files changed (6) hide show
  1. Dockerfile +22 -0
  2. README.MD +98 -0
  3. config.py +5 -0
  4. favicon.ico +0 -0
  5. main.py +187 -0
  6. requirements.txt +8 -0
Dockerfile ADDED
@@ -0,0 +1,22 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ FROM python:3.11-slim
2
+
3
+ WORKDIR /code
4
+
5
+ COPY requirements.txt ./
6
+
7
+ RUN pip install --no-cache-dir --upgrade -r /code/requirements.txt
8
+
9
+ RUN useradd -m -u 1000 user
10
+
11
+ USER user
12
+
13
+ ENV HOME=/home/user \
14
+ PATH=/home/user/.local/bin:$PATH
15
+
16
+ WORKDIR $HOME/app
17
+
18
+ COPY --chown=user . $HOME/app
19
+
20
+ COPY --chown=user config/config.toml $HOME/app/.streamlit/config.toml
21
+
22
+ CMD ["streamlit", "run", "main.py", "--server.port=7860", "--server.address=0.0.0.0"]
README.MD ADDED
@@ -0,0 +1,98 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Sparrow UI
2
+
3
+ ## Description
4
+
5
+ [Sparrow UI](https://katanaml-org-sparrow-ui.hf.space) module implements UI logic with Streamlit for document data annotation, model training/tuning and document data extraction.
6
+
7
+ #### Dashboard UI:
8
+
9
+ ![Sparrow Dashboard](https://github.com/katanaml/sparrow/blob/main/sparrow-ui/donut/assets/dashboard.png)
10
+
11
+ #### Annotation UI:
12
+
13
+ ![Sparrow Annotation](https://github.com/katanaml/sparrow/blob/main/sparrow-ui/donut/assets/annotation.png)
14
+
15
+ #### Inference UI:
16
+
17
+ ![Sparrow Inference](https://github.com/katanaml/sparrow/blob/main/sparrow-ui/donut/assets/inference.png)
18
+
19
+ #### Review UI:
20
+
21
+ ![Sparrow Review](https://github.com/katanaml/sparrow/blob/main/sparrow-ui/donut/assets/review.png)
22
+
23
+ #### Labels/Groups CRUD UI:
24
+
25
+ ![Sparrow CRUD](https://github.com/katanaml/sparrow/blob/main/sparrow-ui/donut/assets/crud.png)
26
+
27
+ ## Instructions
28
+
29
+ 1. Install
30
+
31
+ Streamlit docs:
32
+ https://docs.streamlit.io/library/get-started/installation
33
+
34
+ ```
35
+ pip install -r requirements.txt
36
+ ```
37
+
38
+ 2. Run
39
+
40
+ ```
41
+ streamlit run main.py
42
+ ```
43
+
44
+ After annotating files, click Export Labels button to produce JSON mapping with key/value pairs
45
+
46
+ ## Run in Docker container
47
+
48
+ 1. Build Docker image
49
+
50
+ ```
51
+ docker build --tag katanaml/sparrow-ui .
52
+ ```
53
+
54
+ 2. Run Docker container
55
+
56
+ ```
57
+ docker run -it --name sparrow-ui -p 7860:7860 katanaml/sparrow-ui:latest
58
+ ```
59
+
60
+ ## Deploy to Hugging Face Spaces
61
+
62
+ 1. Create new Space - https://huggingface.co/spaces
63
+
64
+ 2. Clone Space repo and init Git LFS. Copy Sparrow UI files. We are using config.toml from config folder, when deploying Docker container on Hugging Face Spaces, it can't read from standard .streamlit folder
65
+
66
+ ```
67
+ git lfs install
68
+ ```
69
+
70
+ 3. Add these files to LFS config
71
+
72
+ ```
73
+ git lfs track "assets/ab.png"
74
+ git lfs track "docs/image/receipt_00001.png"
75
+ git lfs track "docs/image/receipt_00002.png"
76
+ git lfs track "docs/image/receipt_00003.png"
77
+ git lfs track "docs/image/w_invoice1.png"
78
+ ```
79
+
80
+ 4. Commit and push code to Hugging Face Space, follow Space instructions. Docker container will be deployed automatically. Space example:
81
+
82
+ ```
83
+ https://huggingface.co/spaces/katanaml-org/sparrow-ui
84
+ ```
85
+
86
+ 5. Sparrow UI will be accessible by URL, you can get it from Hugging Face Space info. For example:
87
+
88
+ ```
89
+ https://katanaml-org-sparrow-ui.hf.space
90
+ ```
91
+
92
+ ## Author
93
+
94
+ [Katana ML](https://katanaml.io), [Andrej Baranovskij](https://github.com/abaranovskis-redsamurai)
95
+
96
+ ## License
97
+
98
+ Licensed under the Apache License, Version 2.0. Copyright 2020-2023 Katana ML, Andrej Baranovskij. [Copy of the license](https://github.com/katanaml/sparrow/blob/main/LICENSE).
config.py ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ class Settings():
2
+ sparrow_key = ""
3
+
4
+
5
+ settings = Settings()
favicon.ico ADDED
main.py ADDED
@@ -0,0 +1,187 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import streamlit as st
2
+ from streamlit_option_menu import option_menu
3
+ from tools.utilities import load_css
4
+ import json
5
+
6
+ from views.dashboard import Dashboard
7
+ from views.data_annotation import DataAnnotation
8
+ from views.model_training import ModelTraining
9
+ from views.model_tuning import ModelTuning
10
+ from views.data_inference import DataInference
11
+ from views.setup import Setup
12
+ from views.data_review import DataReview
13
+ from views.about import About
14
+
15
+ import streamlit_javascript as st_js
16
+
17
+ st.set_page_config(
18
+ page_title="Sparrow",
19
+ page_icon="favicon.ico",
20
+ layout="wide"
21
+ )
22
+
23
+ load_css()
24
+
25
+
26
+ class Model:
27
+ menuTitle = "Sparrow"
28
+ option1 = "Dashboard"
29
+ option2 = "Data Annotation"
30
+ option3 = "Model Training"
31
+ option4 = "Model Tuning"
32
+ option5 = "Inference"
33
+ option6 = "Data Review"
34
+ option7 = "Setup"
35
+ option8 = "About"
36
+
37
+ menuIcon = "menu-up"
38
+ icon1 = "speedometer"
39
+ icon2 = "activity"
40
+ icon3 = "motherboard"
41
+ icon4 = "graph-up-arrow"
42
+ icon5 = "journal-arrow-down"
43
+ icon6 = "droplet"
44
+ icon7 = "clipboard-data"
45
+ icon8 = "chat"
46
+
47
+
48
+ def view(model):
49
+ with st.sidebar:
50
+ menuItem = option_menu(model.menuTitle,
51
+ [model.option1, model.option2, model.option5, model.option6, model.option7, model.option8],
52
+ icons=[model.icon1, model.icon2, model.icon5, model.icon6, model.icon7, model.icon8],
53
+ menu_icon=model.menuIcon,
54
+ default_index=0,
55
+ styles={
56
+ "container": {"padding": "5!important", "background-color": "#fafafa"},
57
+ "icon": {"color": "black", "font-size": "25px"},
58
+ "nav-link": {"font-size": "16px", "text-align": "left", "margin": "0px",
59
+ "--hover-color": "#eee"},
60
+ "nav-link-selected": {"background-color": "#037ffc"},
61
+ })
62
+
63
+ if menuItem == model.option1:
64
+ Dashboard().view(Dashboard.Model())
65
+ logout_widget()
66
+
67
+ if menuItem == model.option2:
68
+ if 'ui_width' not in st.session_state or 'device_type' not in st.session_state or 'device_width' not in st.session_state:
69
+ # Get UI width
70
+ ui_width = st_js.st_javascript("window.innerWidth", key="ui_width_comp")
71
+ device_width = st_js.st_javascript("window.screen.width", key="device_width_comp")
72
+
73
+ if ui_width > 0 and device_width > 0:
74
+ # Add 20% of current screen width to compensate for the sidebar
75
+ ui_width = round(ui_width + (20 * ui_width / 100))
76
+
77
+ if device_width > 768:
78
+ device_type = 'desktop'
79
+ else:
80
+ device_type = 'mobile'
81
+
82
+ st.session_state['ui_width'] = ui_width
83
+ st.session_state['device_type'] = device_type
84
+ st.session_state['device_width'] = device_width
85
+
86
+ st.experimental_rerun()
87
+ else:
88
+ DataAnnotation().view(DataAnnotation.Model(), st.session_state['ui_width'], st.session_state['device_type'],
89
+ st.session_state['device_width'])
90
+ logout_widget()
91
+
92
+ if menuItem == model.option3:
93
+ ModelTraining().view(ModelTraining.Model())
94
+ logout_widget()
95
+
96
+ if menuItem == model.option4:
97
+ ModelTuning().view(ModelTuning.Model())
98
+ logout_widget()
99
+
100
+ if menuItem == model.option5:
101
+ if 'ui_width' not in st.session_state or 'device_type' not in st.session_state or 'device_width' not in st.session_state:
102
+ # Get UI width
103
+ ui_width = st_js.st_javascript("window.innerWidth", key="ui_width_comp")
104
+ device_width = st_js.st_javascript("window.screen.width", key="device_width_comp")
105
+
106
+ if ui_width > 0 and device_width > 0:
107
+ # Add 20% of current screen width to compensate for the sidebar
108
+ ui_width = round(ui_width + (20 * ui_width / 100))
109
+
110
+ if device_width > 768:
111
+ device_type = 'desktop'
112
+ else:
113
+ device_type = 'mobile'
114
+
115
+ st.session_state['ui_width'] = ui_width
116
+ st.session_state['device_type'] = device_type
117
+ st.session_state['device_width'] = device_width
118
+
119
+ st.experimental_rerun()
120
+ else:
121
+ DataInference().view(DataInference.Model(), st.session_state['ui_width'], st.session_state['device_type'],
122
+ st.session_state['device_width'])
123
+
124
+ logout_widget()
125
+
126
+ if menuItem == model.option6:
127
+ if 'ui_width' not in st.session_state or 'device_type' not in st.session_state or 'device_width' not in st.session_state:
128
+ # Get UI width
129
+ ui_width = st_js.st_javascript("window.innerWidth", key="ui_width_comp")
130
+ device_width = st_js.st_javascript("window.screen.width", key="device_width_comp")
131
+
132
+ if ui_width > 0 and device_width > 0:
133
+ # Add 20% of current screen width to compensate for the sidebar
134
+ ui_width = round(ui_width + (20 * ui_width / 100))
135
+
136
+ if device_width > 768:
137
+ device_type = 'desktop'
138
+ else:
139
+ device_type = 'mobile'
140
+
141
+ st.session_state['ui_width'] = ui_width
142
+ st.session_state['device_type'] = device_type
143
+ st.session_state['device_width'] = device_width
144
+
145
+ st.experimental_rerun()
146
+ else:
147
+ DataReview().view(DataReview.Model(), st.session_state['ui_width'], st.session_state['device_type'],
148
+ st.session_state['device_width'])
149
+
150
+ logout_widget()
151
+
152
+ if menuItem == model.option7:
153
+ Setup().view(Setup.Model())
154
+ logout_widget()
155
+
156
+ if menuItem == model.option8:
157
+ About().view(About.Model())
158
+ logout_widget()
159
+
160
+
161
+ def logout_widget():
162
+ with st.sidebar:
163
+ st.markdown("---")
164
+ # st.write("User:", "John Doe")
165
+ st.write("Version:", "2.0.0")
166
+ # st.button("Logout")
167
+ # st.markdown("---")
168
+
169
+ if 'visitors' not in st.session_state:
170
+ with open("docs/visitors.json", "r") as f:
171
+ visitors_json = json.load(f)
172
+ visitors = visitors_json["meta"]["visitors"]
173
+
174
+ visitors += 1
175
+ visitors_json["meta"]["visitors"] = visitors
176
+
177
+ with open("docs/visitors.json", "w") as f:
178
+ json.dump(visitors_json, f)
179
+
180
+ st.session_state['visitors'] = visitors
181
+ else:
182
+ visitors = st.session_state['visitors']
183
+
184
+ st.write("Counter:", visitors)
185
+
186
+
187
+ view(Model())
requirements.txt ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
 
1
+ streamlit==1.22.0
2
+ streamlit_option_menu
3
+ streamlit-sparrow-labeling==0.1.1
4
+ streamlit_nested_layout
5
+ streamlit-javascript
6
+ natsort
7
+ streamlit-aggrid==0.3.3
8
+ pandas<2.0