IAMTFRMZA commited on
Commit
18e25a2
Β·
verified Β·
1 Parent(s): a68bccd

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +80 -127
app.py CHANGED
@@ -3,6 +3,7 @@ import os
3
  import time
4
  import re
5
  import requests
 
6
  from PIL import Image
7
  from io import BytesIO
8
  from urllib.parse import quote
@@ -11,7 +12,7 @@ from openai import OpenAI
11
  # ------------------ App Configuration ------------------
12
  st.set_page_config(page_title="Schlaeger Forrestdale TechDocAIA", layout="wide", initial_sidebar_state="collapsed")
13
  st.title("πŸ“„ Schlaeger Forrestdale Document Assistant")
14
- st.caption("Explore City of Armadale construction documents using AI + OCR 🧠")
15
 
16
  # ------------------ Load API Key and Assistant ID ------------------
17
  OPENAI_API_KEY = os.environ.get("OPENAI_API_KEY")
@@ -28,143 +29,95 @@ if "messages" not in st.session_state:
28
  st.session_state.messages = []
29
  if "thread_id" not in st.session_state:
30
  st.session_state.thread_id = None
31
- if "image_url" not in st.session_state:
32
- st.session_state.image_url = None
33
- if "image_updated" not in st.session_state:
34
- st.session_state.image_updated = False
35
  if "pending_prompt" not in st.session_state:
36
  st.session_state.pending_prompt = None
 
 
37
 
38
  # ------------------ Sidebar ------------------
39
  st.sidebar.header("ℹ️ Information")
40
  if st.sidebar.button("🧹 Clear Chat"):
41
  st.session_state.messages = []
42
  st.session_state.thread_id = None
43
- st.session_state.image_url = None
44
- st.session_state.image_updated = False
45
  st.session_state.pending_prompt = None
 
46
  st.rerun()
47
 
48
- show_image = st.sidebar.toggle("πŸ“‘ Show Page Image", value=True)
49
-
50
- st.sidebar.subheader("πŸ“˜ Document Tools")
51
- st.sidebar.markdown("Use the tools below to locate relevant clauses and actions:")
52
-
53
- keyword = st.sidebar.text_input("Search by Keyword", placeholder="e.g. defects, WHS, delay")
54
- if st.sidebar.button("πŸ”Ž Search Keyword") and keyword:
55
- st.session_state.pending_prompt = f"Find clauses or references related to: {keyword}"
56
-
57
- section_options = [
58
- "Select a section...",
59
- "1. Formal Instrument of Contract",
60
- "2. Offer and Acceptance",
61
- "3. Key Personnel",
62
- "4. Contract Pricing",
63
- "5. Specifications",
64
- "6. WHS Policies",
65
- "7. Penalties and Delays",
66
- "8. Dispute Resolution",
67
- "9. Principal Obligations"
68
- ]
69
- section_select = st.sidebar.selectbox("πŸ“„ Jump to Section", section_options)
70
- if section_select != section_options[0]:
71
- st.session_state.pending_prompt = f"Summarize or list key points from section: {section_select}"
72
-
73
- actions = [
74
- "Select an action...",
75
- "List all contractual obligations",
76
- "Summarize payment terms",
77
- "List WHS responsibilities",
78
- "Find delay-related penalties",
79
- "Extract dispute resolution steps"
80
- ]
81
- action_select = st.sidebar.selectbox("βš™οΈ Common Contract Queries", actions)
82
- if action_select != actions[0]:
83
- st.session_state.pending_prompt = action_select
84
-
85
- # ------------------ Layout: Chat + Image ------------------
86
- chat_col, image_col = st.columns([2, 1])
87
-
88
- # ------------------ Chat Interface ------------------
89
- with chat_col:
90
- st.markdown("### 🧠 Ask a Document-Specific Question")
91
- user_prompt = st.chat_input("Example: What is the defects liability period?")
92
-
93
- # Use pending prompt from sidebar if no new chat prompt
94
- if user_prompt:
95
- st.session_state.messages.append({"role": "user", "content": user_prompt})
96
- elif st.session_state.pending_prompt:
97
- st.session_state.messages.append({"role": "user", "content": st.session_state.pending_prompt})
98
- st.session_state.pending_prompt = None
99
-
100
- if st.session_state.messages and st.session_state.messages[-1]["role"] == "user":
101
- try:
102
- if st.session_state.thread_id is None:
103
- thread = client.beta.threads.create()
104
- st.session_state.thread_id = thread.id
105
-
106
- client.beta.threads.messages.create(
107
- thread_id=st.session_state.thread_id,
108
- role="user",
109
- content=st.session_state.messages[-1]["content"]
110
- )
111
-
112
- run = client.beta.threads.runs.create(
113
- thread_id=st.session_state.thread_id,
114
- assistant_id=ASSISTANT_ID
115
- )
116
-
117
- with st.spinner("πŸ€– Parsing and responding with referenced content..."):
118
- while True:
119
- run_status = client.beta.threads.runs.retrieve(
120
- thread_id=st.session_state.thread_id,
121
- run_id=run.id
122
- )
123
- if run_status.status in ("completed", "failed", "cancelled"):
124
- break
125
- time.sleep(1)
126
-
127
- if run_status.status != "completed":
128
- st.error(f"⚠️ Assistant failed: {run_status.status}")
129
- else:
130
- messages = client.beta.threads.messages.list(thread_id=st.session_state.thread_id)
131
- for message in reversed(messages.data):
132
- if message.role == "assistant":
133
- assistant_reply = message.content[0].text.value
134
- st.session_state.messages.append({"role": "assistant", "content": assistant_reply})
135
-
136
- # Parse Document Reference and Page, then construct image URL with encoding
137
- match = re.search(r'Document Reference:\s*(.*?),\s*Page\s*(\d+)', assistant_reply)
138
- if match:
139
- doc_name = match.group(1).strip()
140
- page = int(match.group(2))
141
- page_str = f"{page:04d}"
142
- folder = quote(doc_name)
143
- image_url = (
144
- f"https://raw.githubusercontent.com/AndrewLORTech/c2ozschlaegerforrestdale/main/"
145
- f"{folder}/{folder}_page_{page_str}.png"
146
- )
147
- st.session_state.image_url = image_url
148
- st.session_state.image_updated = True
149
- break
150
-
151
- st.rerun()
152
- except Exception as e:
153
- st.error(f"❌ Error: {e}")
154
-
155
  for msg in st.session_state.messages:
156
  with st.chat_message(msg["role"]):
157
  st.markdown(msg["content"], unsafe_allow_html=True)
158
-
159
- # ------------------ Image Display ------------------
160
- with image_col:
161
- if show_image and st.session_state.image_url:
162
- with st.spinner("Loading document preview..."):
163
- try:
164
- response = requests.get(st.session_state.image_url)
165
- response.raise_for_status()
166
- img = Image.open(BytesIO(response.content))
167
- st.image(img, caption="πŸ“„ OCR Page Image", use_container_width=True)
168
- st.session_state.image_updated = False
169
- except Exception as e:
170
- st.error(f"❗ Failed to load image: {e}")
 
3
  import time
4
  import re
5
  import requests
6
+ import json
7
  from PIL import Image
8
  from io import BytesIO
9
  from urllib.parse import quote
 
12
  # ------------------ App Configuration ------------------
13
  st.set_page_config(page_title="Schlaeger Forrestdale TechDocAIA", layout="wide", initial_sidebar_state="collapsed")
14
  st.title("πŸ“„ Schlaeger Forrestdale Document Assistant")
15
+ st.caption("Explore City of Armadale construction documents using AI + OCR 🧐")
16
 
17
  # ------------------ Load API Key and Assistant ID ------------------
18
  OPENAI_API_KEY = os.environ.get("OPENAI_API_KEY")
 
29
  st.session_state.messages = []
30
  if "thread_id" not in st.session_state:
31
  st.session_state.thread_id = None
 
 
 
 
32
  if "pending_prompt" not in st.session_state:
33
  st.session_state.pending_prompt = None
34
+ if "results" not in st.session_state:
35
+ st.session_state.results = []
36
 
37
  # ------------------ Sidebar ------------------
38
  st.sidebar.header("ℹ️ Information")
39
  if st.sidebar.button("🧹 Clear Chat"):
40
  st.session_state.messages = []
41
  st.session_state.thread_id = None
 
 
42
  st.session_state.pending_prompt = None
43
+ st.session_state.results = []
44
  st.rerun()
45
 
46
+ # ------------------ Chat Input ------------------
47
+ user_prompt = st.chat_input("Ask about plans, drawings or components")
48
+ if user_prompt:
49
+ st.session_state.messages.append({"role": "user", "content": user_prompt})
50
+
51
+ # ------------------ Assistant Query ------------------
52
+ if st.session_state.messages and st.session_state.messages[-1]["role"] == "user":
53
+ try:
54
+ if st.session_state.thread_id is None:
55
+ thread = client.beta.threads.create()
56
+ st.session_state.thread_id = thread.id
57
+
58
+ client.beta.threads.messages.create(
59
+ thread_id=st.session_state.thread_id,
60
+ role="user",
61
+ content=st.session_state.messages[-1]["content"]
62
+ )
63
+
64
+ run = client.beta.threads.runs.create(
65
+ thread_id=st.session_state.thread_id,
66
+ assistant_id=ASSISTANT_ID
67
+ )
68
+
69
+ with st.spinner("πŸ€– Parsing and responding..."):
70
+ while True:
71
+ run_status = client.beta.threads.runs.retrieve(
72
+ thread_id=st.session_state.thread_id,
73
+ run_id=run.id
74
+ )
75
+ if run_status.status in ("completed", "failed", "cancelled"):
76
+ break
77
+ time.sleep(1)
78
+
79
+ if run_status.status != "completed":
80
+ st.error(f"⚠️ Assistant failed: {run_status.status}")
81
+ else:
82
+ messages = client.beta.threads.messages.list(thread_id=st.session_state.thread_id)
83
+ for message in reversed(messages.data):
84
+ if message.role == "assistant":
85
+ assistant_reply = message.content[0].text.value
86
+ st.session_state.messages.append({"role": "assistant", "content": assistant_reply})
87
+ try:
88
+ json_data = json.loads(assistant_reply.strip("`json "))
89
+ st.session_state.results = json_data
90
+ except:
91
+ st.session_state.results = []
92
+ break
93
+ st.rerun()
94
+ except Exception as e:
95
+ st.error(f"❌ Error: {e}")
96
+
97
+ # ------------------ Sorting and Filters ------------------
98
+ if st.session_state.results:
99
+ disciplines = sorted(set(d.get("discipline", "") for d in st.session_state.results))
100
+ selected_discipline = st.selectbox("🌍 Filter by discipline", ["All"] + disciplines)
101
+ page_size = 8
102
+ page_num = st.number_input("Page", min_value=1, step=1, value=1)
103
+
104
+ filtered_results = [r for r in st.session_state.results if selected_discipline == "All" or r.get("discipline") == selected_discipline]
105
+ paged = filtered_results[(page_num - 1) * page_size : page_num * page_size]
106
+
107
+ st.markdown("---")
108
+ st.subheader("πŸ“‚ Drawing Results")
109
+ cols = st.columns(4)
110
+
111
+ for i, item in enumerate(paged):
112
+ with cols[i % 4]:
113
+ st.markdown(f"**{item['drawing_number']}**")
114
+ st.markdown(f"_Discipline: {item['discipline']}_")
115
+ st.caption(item.get("summary", ""))
116
+ for url in item.get("images", [])[:1]:
117
+ if st.button("πŸ–ΌοΈ View Image", key=f"view_{i}"):
118
+ st.image(url, use_column_width=True)
119
+
120
+ else:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
121
  for msg in st.session_state.messages:
122
  with st.chat_message(msg["role"]):
123
  st.markdown(msg["content"], unsafe_allow_html=True)