File size: 8,620 Bytes
3c0c2d6
 
d5350ac
3c0c2d6
 
 
 
 
 
 
 
 
cc26fab
 
3c0c2d6
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5585dcf
 
3c0c2d6
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
d5350ac
 
 
 
 
 
 
 
 
84bd3e9
3c0c2d6
 
 
 
d5350ac
 
 
5585dcf
3c0c2d6
 
84bd3e9
3c0c2d6
5585dcf
3c0c2d6
 
5585dcf
d26f874
5585dcf
d26f874
 
cc26fab
5585dcf
d26f874
 
 
 
9f0f462
 
d5350ac
9f0f462
 
84bd3e9
d5350ac
9f0f462
 
 
 
 
d26f874
5585dcf
d26f874
 
 
 
 
3c0c2d6
5585dcf
 
d5350ac
5585dcf
d5350ac
 
 
 
 
 
 
 
 
 
d26f874
d5350ac
 
 
 
 
 
cc26fab
d5350ac
d26f874
84bd3e9
 
 
 
 
 
9253b94
 
84bd3e9
9253b94
cc26fab
84bd3e9
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3c0c2d6
5585dcf
3c0c2d6
 
5585dcf
3c0c2d6
 
 
 
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
import streamlit as st
import pandas as pd
import numpy as np
from azure.core.credentials import AzureKeyCredential
from azure.ai.formrecognizer import DocumentAnalysisClient
import time
from dotenv import load_dotenv
import os

load_dotenv()

# Azure Form Recognizer credentials
endpoint = os.environ["endpoint"]
key = os.environ["key"]

# Initialize DocumentAnalysisClient
document_analysis_client = DocumentAnalysisClient(
    endpoint=endpoint, credential=AzureKeyCredential(key)
)

# Sidebar for document type selection
document_type = st.sidebar.selectbox(
    "Select Document Type", ["Invoice", "Receipt", "Identity Document"]
)

# Center area for file upload
uploaded_file = st.file_uploader(f"Choose or drag an {document_type} file", type=["pdf", "png", "jpg", "jpeg"])

# Initialize session state for processing results
if "processed" not in st.session_state:
    st.session_state.processed = False
    st.session_state.tables = []
    st.session_state.kv_df = pd.DataFrame()

# Process the uploaded file if the button is clicked
if uploaded_file is not None:
    if st.button("Upload and Process"):
        with st.spinner("Processing..."):
            time.sleep(1)  # Simulate some delay to show the spinner

            # Analyze the document
            poller = document_analysis_client.begin_analyze_document(
                "prebuilt-document", document=uploaded_file
            )
            result = poller.result()

            # Extract key-value pairs and store them in a dictionary
            kv_dict = {}
            for kv_pair in result.key_value_pairs:
                if kv_pair.key and kv_pair.value:  # Ensure both key and value exist
                    clean_key = kv_pair.key.content.rstrip(':')
                    kv_dict[clean_key] = kv_pair.value.content
            kv_df = pd.DataFrame(list(kv_dict.items()), columns=["Key", "Value"]).T

            # Set the first row as the header
            header = kv_df.iloc[0]

            # Create a new DataFrame with the header and the remaining rows
            kv_df = kv_df[1:].reset_index(drop=True)

            # Insert the new header row
            header_df = pd.DataFrame([header], columns=range(len(header)))

            # Concatenate the header row DataFrame with the original DataFrame
            kv_df = pd.concat([header_df, kv_df], ignore_index=True)

            st.session_state.kv_df = kv_df
            st.session_state.tables = []

            if result.tables:
                for table in result.tables:
                    data = []
                    for cell in table.cells:
                        data.append([cell.row_index, cell.column_index, cell.content])

                    table_df = pd.DataFrame(data, columns=["row_index", "column_index", "content"])
                    table_df = table_df.pivot(index="row_index", columns="column_index", values="content")
                    # Reset the column index
                    table_df.reset_index(drop=True, inplace=True)

                    # Set the first row as header
                    table_df.columns = table_df.iloc[0]  # Take the first row as column names
                    table_df = table_df.drop(table_df.index[0])  # Remove the first row after setting it as headers

                    # Optionally reset the index if required
                    table_df.reset_index(drop=True, inplace=True)

                    st.session_state.tables.append(table_df)

            st.session_state.processed = True

# Predefine default columns in the selected table
default_columns = ['Invoice No', 'Invoice Date', 'Customer Name']

# Sidebar for table and key-value pair selection
if st.session_state.processed:
    if not st.session_state.kv_df.empty:
        st.sidebar.write("Key-Value Pairs found.")
    else:
        st.sidebar.write("No Key-Value Pairs found in document.")

    if st.session_state.tables:
        # Display available tables for selection in the sidebar
        table_options = ["Select"] + [f"Table {i + 1}" for i in range(len(st.session_state.tables))]
        selected_table_option = st.sidebar.selectbox(
            "Select table to join key-value pairs:", table_options, index=0
        )

        # Proceed only if a table is selected
        if selected_table_option != "Select":
            selected_table_index = table_options.index(selected_table_option) - 1  # Adjust for "None"
            selected_table_df = st.session_state.tables[selected_table_index]

           
             # Add default columns to the left side of the table with NaN values initially
            for col in default_columns:
                if col not in selected_table_df.columns:
                    selected_table_df[col] = np.nan

            # Move default columns to the left
            # We include only those columns that exist in the table
            existing_columns = [col for col in default_columns if col in selected_table_df.columns]
            remaining_columns = [col for col in selected_table_df.columns if col not in existing_columns]
            selected_table_df = selected_table_df[[*existing_columns, *remaining_columns]]
            
            if not st.session_state.kv_df.empty:
                # Allow the user to select multiple columns using checkboxes
                first_row_values = st.session_state.kv_df.iloc[0].values
                second_row_values = st.session_state.kv_df.iloc[1].values
                key_value_options = [
                    f"{key}: {value}" for key, value in zip(first_row_values, second_row_values)
                ]
                
                selected_columns = []
                
                st.sidebar.write("Select key-value pairs to the default columns:")

                # Create draggable interface for each key-value pair
                for i, option in enumerate(key_value_options):
                    selected_column_option = st.sidebar.selectbox(
                        f"Insert {option} to the column:",
                        ["Select"] + default_columns,
                        key=f"col_select_{i}"
                    )
                    
                    if selected_column_option != "Select":
                        selected_columns.append((i, selected_column_option))

                # Insert selected key-value pairs into the appropriate columns
                for idx, selected_column in selected_columns:
                    st.session_state.kv_df[selected_column] = second_row_values[idx]
                    
                    # Fill the column in the table with the selected key-value pair
                    selected_table_df[selected_column] = st.session_state.kv_df.iloc[1, idx]

                st.write(f"Selected Table {selected_table_index + 1} with Key-Value Pairs Added:")

            # st.dataframe(selected_table_df)

            # Allow row and column selection for deletion
            st.sidebar.subheader("Manage Table")
            # Delete columns
            if st.sidebar.checkbox("Delete Columns"):
                col = list(selected_table_df.columns)
                col = col[3:]
                cols_to_delete = st.sidebar.multiselect(
                    "Select Columns to Delete", col
                )
                if st.sidebar.button("Remove Columns"):
                    st.session_state.tables[selected_table_index].drop(columns=cols_to_delete, inplace=True)

            # Delete rows
            if st.sidebar.checkbox("Delete Rows"):
                row_indices = st.sidebar.multiselect(
                    "Select Rows to Delete", selected_table_df.index.tolist()
                )
                if st.sidebar.button("Remove Rows"):
                    st.session_state.tables[selected_table_index].drop(index=row_indices, inplace=True)

            # Show the updated table
            # st.write(f"Updated Table {selected_table_index + 1}:")
            st.dataframe(selected_table_df)

            # Download updated table
            st.download_button(
                label=f"Download Updated Table {selected_table_index + 1} as CSV",
                data=selected_table_df.to_csv(index=False).encode('utf-8'),
                file_name=f"updated_table_{selected_table_index + 1}.csv",
                mime='text/csv',
            )
    else:
        st.sidebar.write("No tables found in the document.")

# Option to remove the file and clear the session
if st.session_state.processed and st.sidebar.button("Remove File"):
    st.session_state.processed = False
    st.session_state.tables = []
    st.session_state.kv_df = pd.DataFrame()
    st.rerun()