Skip to content

Commit 555d941

Browse files
authored
Merge pull request #1704 from oracle-devrel/aliottoman-patch-2-smart-invoice
Update SmartInvoiceExtraction.py
2 parents 389e693 + dcc8056 commit 555d941

File tree

1 file changed

+94
-57
lines changed

1 file changed

+94
-57
lines changed

ai/generative-ai-service/smart-invoice-extraction/SmartInvoiceExtraction.py

Lines changed: 94 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -70,116 +70,153 @@ def extractor(image_list):
7070
# Main Streamlit app function
7171
def invoiceAnalysisPlus():
7272
st.title("Invoice Data Extraction")
73-
73+
7474
with st.sidebar:
7575
st.title("Parameters")
76-
# Replace with your own compartment ID
77-
compID = "<YOUR_COMPARTMENT_OCID_HERE>"
76+
# User prompt input
7877
user_prompt = st.text_input("Input the elements you are looking to extract here")
7978
st.caption("Our AI assistant has extracted the following key elements from the invoice. Please select the elements you wish to extract.")
8079

80+
8181
uploaded_file = st.file_uploader("Upload your invoices here:", type=["pdf"])
82-
82+
8383
if uploaded_file is not None:
8484
with st.spinner("Processing..."):
85-
# Convert PDF to image list
8685
if uploaded_file.type == "application/pdf":
8786
images = convert_from_bytes(uploaded_file.read(), fmt="jpeg")
8887
else:
8988
images = [convert_from_bytes(uploaded_file.read(), fmt="jpeg")[0]]
90-
91-
# Save as byte streams
92-
image_list = save_images(images)
93-
94-
# Load both image-based and text-based LLMs
89+
90+
image_list = save_images(images) # Convert to byte arrays
91+
9592
llm = ChatOCIGenAI(
96-
model_id="meta.llama-3.2-90b-vision-instruct", # Replace with your model ID
97-
compartment_id=compID,
93+
model_id="meta.llama-3.2-90b-vision-instruct",
94+
compartment_id="", #TO-DO: Add your compartment ID here
9895
model_kwargs={"max_tokens": 2000, "temperature": 0}
9996
)
10097
llm_for_prompts = ChatOCIGenAI(
101-
model_id="cohere.command-r-plus-08-2024", # Replace with your model ID
102-
compartment_id=compID,
98+
model_id="cohere.command-r-plus-08-2024",
99+
compartment_id="",#TO-DO: Add your compartment ID here
103100
model_kwargs={"max_tokens": 2000, "temperature": 0}
104101
)
105-
106-
# Select box UI for user to pick elements and their data types
107-
data_types = ["Text", "Number", "Percentage", "Date"]
102+
103+
# Options for data types
104+
data_types = [ "Text", "Number", "Percentage", "Date"]
105+
106+
# Lists to store names and their types
108107
elements = []
109-
110108
if "availables" not in st.session_state:
111109
st.session_state.availables = extractor(image_list)
112-
113-
for i in range(3): # Max 3 fields
114-
col1, col2 = st.columns([2, 1])
115-
with col1:
110+
for i in range(3): # Adjust 'n' for the maximum number of selections
111+
col1, col2 = st.columns([2, 1]) # Adjust width ratio if needed
112+
113+
with col1:
114+
# Preserve user selection across reruns
116115
name = st.selectbox(f"Select an element {i+1}", st.session_state.availables, key=f"name_{i}", index=i)
117116
with col2:
118117
data_type = st.selectbox(f"Type {i+1}", data_types, key=f"type_{i}")
119118
elements.append((name, data_type))
120119

121-
# Generate appropriate prompt based on selected or input fields
122-
if elements:
120+
if elements is not None:
123121
system_message_cohere = SystemMessage(
124-
content=f"""
125-
Based on the following set of elements {elements}, with their respective types, extract their values and respond only in valid JSON format (no explanation):
126-
{', '.join([f'- {e[0]}' for e in elements])}
127-
For example:
128-
{{
129-
{elements[0][0]}: "296969",
130-
{elements[1][0]}: "296969",
131-
{elements[2][0]}: "296969"
132-
}}
133-
"""
134-
)
122+
content=f"""
123+
Based on the following set of elements {elements}, with their respective types ({elements[0][1]}, {elements[1][1]}, {elements[2][1]}), Extract the following details and provide the response only in valid JSON format (no extra explanation or text):
124+
- {elements[0][0]}
125+
- {elements[1][0]}
126+
- {elements[2][0]}
127+
Ensure the extracted data is formatted correctly as JSON and include nothing else at all in the response, not even a greeting or closing.
128+
For example:
129+
{{
130+
{elements[0][0]}: "296969",
131+
{elements[1][0]}: "296969",
132+
{elements[2][0]}: "296969",
133+
}}
134+
""")
135135
ai_response_cohere = system_message_cohere
136136
else:
137+
# Cohere section for generating the prompt
137138
system_message_cohere = SystemMessage(
138-
content=f"""
139-
Generate a system prompt to extract fields based on user-defined elements: {user_prompt}.
140-
Output should be JSON only. No other text.
141-
"""
142-
)
139+
content=f"""
140+
Based on the following system prompt, create a new prompt accordingly based on the elements specified in the user prompt here ({user_prompt}).
141+
142+
This is the system prompt template:
143+
"
144+
Extract the following details and provide the response only in valid JSON format (no extra explanation or text):
145+
- **Debit / Credit Note No.**
146+
- **Policy Period**
147+
- **Insured**
148+
- **Vessel Name**
149+
- **Details**
150+
- **Currency**
151+
- **Gross Premium 100%**
152+
- **OIMSL Share**
153+
- **Total Deductions**
154+
- **Net Premium**
155+
- **Premium Schedule**
156+
- **Installment Amount**
157+
158+
Ensure the extracted data is formatted correctly as JSON and include nothing else at all in the response, not even a greeting or closing.
159+
160+
For example:
161+
162+
"Debit / Credit Note No.": "296969",
163+
"Policy Period": "Feb 20, 2024 to Jul 15, 2025",
164+
"Insured": "Stealth Maritime Corp. S.A.",
165+
"Vessel Name": "SUPRA DUKE - HULL & MACHINERY", (Make sure this is the entire vessel name only)
166+
"Details": "SUPRA DUKE - Original Premium",
167+
"Currency": "USD",
168+
"Gross Premium 100%": 56973.63,
169+
"OIMSL Share": 4557.89,
170+
"Total Deductions": 979.92,
171+
"Net Premium": 3577.97,
172+
"Premium Schedule": ["Apr 20, 2024", "Jun 14, 2024", "Sep 13, 2024", "Dec 14, 2024", "Mar 16, 2025", "Jun 14, 2025"],
173+
"Installment Amount": [372.87, 641.02, 641.02, 641.02, 641.02, 641.02]
174+
175+
)" ensure your response is a system prompt format with an example of what the ouput should look like. Also ensure to mention in your gernerated prompt that no other content whatsover should appear except the JSON
176+
""")
143177
ai_response_cohere = llm_for_prompts.invoke(input=[system_message_cohere])
178+
print(ai_response_cohere)
144179

145-
# Extracted data list
146180
extracted_data = []
147-
181+
148182
with st.spinner("Analyzing invoice..."):
149183
for idx, img_byte_arr in enumerate(image_list):
150184
try:
185+
# Convert the image to base64 directly from memory
151186
encoded_frame = base64.b64encode(img_byte_arr.getvalue()).decode("utf-8")
152-
153-
if elements:
187+
if elements is not None:
154188
system_message = ai_response_cohere
155189
else:
156-
system_message = SystemMessage(content=ai_response_cohere.content)
157-
190+
system_message = SystemMessage(
191+
content=ai_response_cohere.content)
158192
human_message = HumanMessage(
159193
content=[
160194
{"type": "text", "text": "This is my invoice"},
161195
{"type": "image_url", "image_url": {"url": f"data:image/jpeg;base64,{encoded_frame}"}},
162196
]
163197
)
164-
165198
ai_response = llm.invoke(input=[human_message, system_message])
166-
json_start = ai_response.content.find('{')
167-
json_end = ai_response.content.find('}', json_start)
168-
json_data = ai_response.content[json_start:json_end + 1]
169-
170-
response_dict = json.loads(json_data)
199+
print(ai_response.content)
200+
index = ai_response.content.find('{')
201+
index2 = ai_response.content.find('}')
202+
x = ai_response.content[index:]
203+
x2 = x[:index2+1]
204+
print(x2)
205+
response_dict = json.loads(x2)
206+
207+
# Add metadata for tracking
171208
response_dict["File Name"] = uploaded_file.name
172-
response_dict["Page Number"] = idx + 1
209+
response_dict["Page Number"] = idx + 1
210+
173211
extracted_data.append(response_dict)
174212

175213
except Exception as e:
176214
st.error(f"Error processing page {idx+1}: {str(e)}")
177-
178-
# Display and save results
215+
179216
if extracted_data:
180217
save_to_csv(extracted_data)
181218
st.dataframe(pd.DataFrame(extracted_data))
182219

183-
# Run the app
220+
# Run the chatbot function
184221
if __name__ == "__main__":
185-
invoiceAnalysisPlus()
222+
invoiceAnalysisPlus()

0 commit comments

Comments
 (0)