IAMTFRMZA commited on
Commit
930629f
Β·
verified Β·
1 Parent(s): 2e0eb4d

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +55 -180
app.py CHANGED
@@ -1,180 +1,43 @@
1
  import streamlit as st
2
  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
9
  from openai import OpenAI
10
 
11
- # ------------------ App Configuration ------------------
12
- st.set_page_config(page_title="Schlaeger Forrestdale DocAIA", 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 IDs ------------------
17
  OPENAI_API_KEY = os.environ.get("OPENAI_API_KEY")
18
- CONTRACT_ASSISTANT_ID = os.environ.get("ASSISTANT_ID") # Contract assistant
19
- TECH_ASSISTANT_ID = "asst_DjvuWBc7tCvMbAhY7n1em4BZ" # Technical drawings assistant
20
 
21
- if not OPENAI_API_KEY or not CONTRACT_ASSISTANT_ID:
22
- st.error("❌ Missing secrets. Please set OPENAI_API_KEY and ASSISTANT_ID in Hugging Face Space secrets.")
23
  st.stop()
24
 
25
  client = OpenAI(api_key=OPENAI_API_KEY)
26
 
27
- # ------------------ Tabs ------------------
28
- tab1, tab2 = st.tabs(["πŸ“„ Contract Assistant", "πŸ“ Technical Drawings Assistant"])
 
29
 
30
- # ------------------ Tab 1: Contract Assistant ------------------
31
- with tab1:
32
- if "messages" not in st.session_state:
33
- st.session_state.messages = []
34
- if "thread_id" not in st.session_state:
35
- st.session_state.thread_id = None
36
- if "image_url" not in st.session_state:
37
- st.session_state.image_url = None
38
- if "image_updated" not in st.session_state:
39
- st.session_state.image_updated = False
40
- if "pending_prompt" not in st.session_state:
41
- st.session_state.pending_prompt = None
42
 
43
- show_image = st.sidebar.toggle("πŸ“‘ Show Page Image", value=True)
 
 
 
44
 
45
- st.sidebar.subheader("πŸ“˜ Document Tools")
46
- keyword = st.sidebar.text_input("Search by Keyword", placeholder="e.g. defects, WHS, delay")
47
- if st.sidebar.button("πŸ”Ž Search Keyword") and keyword:
48
- st.session_state.pending_prompt = f"Find clauses or references related to: {keyword}"
49
 
50
- section_options = [
51
- "Select a section...",
52
- "1. Formal Instrument of Contract",
53
- "2. Offer and Acceptance",
54
- "3. Key Personnel",
55
- "4. Contract Pricing",
56
- "5. Specifications",
57
- "6. WHS Policies",
58
- "7. Penalties and Delays",
59
- "8. Dispute Resolution",
60
- "9. Principal Obligations"
61
- ]
62
- section_select = st.sidebar.selectbox("πŸ“„ Jump to Section", section_options)
63
- if section_select != section_options[0]:
64
- st.session_state.pending_prompt = f"Summarize or list key points from section: {section_select}"
65
-
66
- actions = [
67
- "Select an action...",
68
- "List all contractual obligations",
69
- "Summarize payment terms",
70
- "List WHS responsibilities",
71
- "Find delay-related penalties",
72
- "Extract dispute resolution steps"
73
- ]
74
- action_select = st.sidebar.selectbox("βš™οΈ Common Contract Queries", actions)
75
- if action_select != actions[0]:
76
- st.session_state.pending_prompt = action_select
77
-
78
- chat_col, image_col = st.columns([2, 1])
79
-
80
- with chat_col:
81
- st.markdown("### 🧠 Ask a Document-Specific Question")
82
- user_prompt = st.chat_input("Example: What is the defects liability period?")
83
-
84
- if user_prompt:
85
- st.session_state.messages.append({"role": "user", "content": user_prompt})
86
- elif st.session_state.pending_prompt:
87
- st.session_state.messages.append({"role": "user", "content": st.session_state.pending_prompt})
88
- st.session_state.pending_prompt = None
89
-
90
- if st.session_state.messages and st.session_state.messages[-1]["role"] == "user":
91
- try:
92
- if st.session_state.thread_id is None:
93
- thread = client.beta.threads.create()
94
- st.session_state.thread_id = thread.id
95
-
96
- client.beta.threads.messages.create(
97
- thread_id=st.session_state.thread_id,
98
- role="user",
99
- content=st.session_state.messages[-1]["content"]
100
- )
101
-
102
- run = client.beta.threads.runs.create(
103
- thread_id=st.session_state.thread_id,
104
- assistant_id=CONTRACT_ASSISTANT_ID
105
- )
106
-
107
- with st.spinner("πŸ€– Parsing and responding with referenced content..."):
108
- while True:
109
- run_status = client.beta.threads.runs.retrieve(
110
- thread_id=st.session_state.thread_id,
111
- run_id=run.id
112
- )
113
- if run_status.status in ("completed", "failed", "cancelled"):
114
- break
115
- time.sleep(1)
116
-
117
- if run_status.status != "completed":
118
- st.error(f"⚠️ Assistant failed: {run_status.status}")
119
- else:
120
- messages = client.beta.threads.messages.list(thread_id=st.session_state.thread_id)
121
- for message in reversed(messages.data):
122
- if message.role == "assistant":
123
- assistant_reply = message.content[0].text.value
124
- st.session_state.messages.append({"role": "assistant", "content": assistant_reply})
125
-
126
- match = re.search(r'Document Reference:\s*(.*?),\s*Page\s*(\d+)', assistant_reply)
127
- if match:
128
- doc_name = match.group(1).strip()
129
- page = int(match.group(2))
130
- page_str = f"{page:04d}"
131
- folder = quote(doc_name)
132
- image_url = (
133
- f"https://raw.githubusercontent.com/AndrewLORTech/c2ozschlaegerforrestdale/main/"
134
- f"{folder}/{folder}_page_{page_str}.png"
135
- )
136
- st.session_state.image_url = image_url
137
- st.session_state.image_updated = True
138
- break
139
-
140
- st.rerun()
141
- except Exception as e:
142
- st.error(f"❌ Error: {e}")
143
-
144
- for msg in st.session_state.messages:
145
- with st.chat_message(msg["role"]):
146
- st.markdown(msg["content"], unsafe_allow_html=True)
147
-
148
- with image_col:
149
- if show_image and st.session_state.image_url:
150
- with st.spinner("Loading document preview..."):
151
- try:
152
- response = requests.get(st.session_state.image_url)
153
- response.raise_for_status()
154
- img = Image.open(BytesIO(response.content))
155
- st.image(img, caption="πŸ“„ OCR Page Image", use_container_width=True)
156
- st.session_state.image_updated = False
157
- except Exception as e:
158
- st.error(f"❗ Failed to load image: {e}")
159
-
160
- # ------------------ Tab 2: Technical Drawing Assistant ------------------
161
- with tab2:
162
- if "tech_messages" not in st.session_state:
163
- st.session_state.tech_messages = []
164
- st.session_state.tech_thread_id = None
165
-
166
- st.markdown("### πŸ—οΈ Ask a Question About Drawings or Diagrams")
167
- tech_prompt = st.chat_input("Example: Show me all architectural drawings")
168
-
169
- if tech_prompt:
170
- st.session_state.tech_messages.append({"role": "user", "content": tech_prompt})
171
-
172
- if st.session_state.tech_messages and st.session_state.tech_messages[-1]["role"] == "user":
173
  try:
174
- if st.session_state.tech_thread_id is None:
175
- thread = client.beta.threads.create()
176
- st.session_state.tech_thread_id = thread.id
177
-
178
  client.beta.threads.messages.create(
179
  thread_id=st.session_state.tech_thread_id,
180
  role="user",
@@ -183,33 +46,45 @@ with tab2:
183
 
184
  run = client.beta.threads.runs.create(
185
  thread_id=st.session_state.tech_thread_id,
186
- assistant_id=TECH_ASSISTANT_ID
187
  )
188
 
189
- with st.spinner("πŸ” Querying Technical Drawing Assistant..."):
190
- while True:
191
- run_status = client.beta.threads.runs.retrieve(
192
- thread_id=st.session_state.tech_thread_id,
193
- run_id=run.id
194
- )
195
- if run_status.status in ("completed", "failed", "cancelled"):
196
- break
197
- time.sleep(1)
198
 
199
  if run_status.status != "completed":
200
- st.error(f"⚠️ Assistant failed: {run_status.status}")
201
  else:
202
  messages = client.beta.threads.messages.list(thread_id=st.session_state.tech_thread_id)
203
  for message in reversed(messages.data):
204
  if message.role == "assistant":
205
- reply = message.content[0].text.value
206
- st.session_state.tech_messages.append({"role": "assistant", "content": reply})
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
207
  break
208
-
209
- st.rerun()
210
  except Exception as e:
211
- st.error(f"❌ Error: {e}")
212
-
213
- for msg in st.session_state.tech_messages:
214
- with st.chat_message(msg["role"]):
215
- st.markdown(msg["content"], unsafe_allow_html=True)
 
1
  import streamlit as st
2
  import os
3
  import time
4
+ import json
 
 
 
 
5
  from openai import OpenAI
6
 
7
+ # Configuration
8
+ st.set_page_config(page_title="Forrestdale Drawing Viewer", layout="wide")
9
+ st.title("πŸ“ Forrestdale Technical Drawing Assistant")
 
10
 
 
11
  OPENAI_API_KEY = os.environ.get("OPENAI_API_KEY")
12
+ ASSISTANT_ID = "asst_DjvuWBc7tCvMbAhY7n1em4BZ"
 
13
 
14
+ if not OPENAI_API_KEY:
15
+ st.error("❌ Missing OPENAI_API_KEY.")
16
  st.stop()
17
 
18
  client = OpenAI(api_key=OPENAI_API_KEY)
19
 
20
+ if "tech_thread_id" not in st.session_state:
21
+ thread = client.beta.threads.create()
22
+ st.session_state.tech_thread_id = thread.id
23
 
24
+ if "tech_messages" not in st.session_state:
25
+ st.session_state.tech_messages = []
 
 
 
 
 
 
 
 
 
 
26
 
27
+ # Prompt input
28
+ prompt = st.chat_input("Ask about plans, drawings or components (e.g. Show me all electrical plans)")
29
+ if prompt:
30
+ st.session_state.tech_messages.append({"role": "user", "content": prompt})
31
 
32
+ # Display assistant messages
33
+ for msg in st.session_state.tech_messages:
34
+ with st.chat_message(msg["role"]):
35
+ st.markdown(msg["content"])
36
 
37
+ # Trigger assistant
38
+ if st.session_state.tech_messages and st.session_state.tech_messages[-1]["role"] == "user":
39
+ with st.spinner("⏳ Fetching results from assistant..."):
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
40
  try:
 
 
 
 
41
  client.beta.threads.messages.create(
42
  thread_id=st.session_state.tech_thread_id,
43
  role="user",
 
46
 
47
  run = client.beta.threads.runs.create(
48
  thread_id=st.session_state.tech_thread_id,
49
+ assistant_id=ASSISTANT_ID
50
  )
51
 
52
+ while True:
53
+ run_status = client.beta.threads.runs.retrieve(
54
+ thread_id=st.session_state.tech_thread_id,
55
+ run_id=run.id
56
+ )
57
+ if run_status.status in ["completed", "failed", "cancelled"]:
58
+ break
59
+ time.sleep(1)
 
60
 
61
  if run_status.status != "completed":
62
+ st.error("⚠️ Assistant run failed.")
63
  else:
64
  messages = client.beta.threads.messages.list(thread_id=st.session_state.tech_thread_id)
65
  for message in reversed(messages.data):
66
  if message.role == "assistant":
67
+ reply_content = message.content[0].text.value.strip()
68
+ st.session_state.tech_messages.append({"role": "assistant", "content": reply_content})
69
+
70
+ # Try to parse response as JSON
71
+ try:
72
+ results = json.loads(reply_content)
73
+ if isinstance(results, list):
74
+ for item in results:
75
+ st.markdown(f"### πŸ“„ {item.get('drawing_number')} ({item.get('discipline')})")
76
+ st.markdown(f"**Summary:** {item.get('summary')}")
77
+
78
+ # Single image (keyword match)
79
+ if "image" in item:
80
+ st.image(item["image"], use_column_width=True)
81
+
82
+ # Multiple image pages
83
+ elif "images" in item:
84
+ for img in item["images"]:
85
+ st.image(img, use_column_width=True)
86
+ except Exception as parse_error:
87
+ st.warning("🟑 Could not parse assistant response as JSON.")
88
  break
 
 
89
  except Exception as e:
90
+ st.error(f"❌ Error occurred: {e}")