IAMTFRMZA commited on
Commit
80e3a1e
Β·
verified Β·
1 Parent(s): 4a71975

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +65 -57
app.py CHANGED
@@ -1,95 +1,103 @@
 
 
1
  import os
2
  import json
3
- import time
4
  import requests
5
- import streamlit as st
6
- from openai import OpenAI
7
-
8
- # -------------------- CONFIG --------------------
9
- OPENAI_API_KEY = os.environ.get("OPENAI_API_KEY")
10
- ASSISTANT_ID = os.environ.get("ASSISTANT_ID")
11
 
 
12
  st.set_page_config(page_title="Forrestdale Technical Drawing Assistant", layout="wide")
13
- st.title("🧱 Forrestdale Technical Drawing Assistant")
 
 
 
 
 
 
 
14
 
15
- # -------------------- ERROR CHECK --------------------
16
  if not OPENAI_API_KEY or not ASSISTANT_ID:
17
- st.error("❌ Missing API credentials. Please set OPENAI_API_KEY and ASSISTANT_ID as environment variables.")
18
  st.stop()
19
 
20
- client = OpenAI(api_key=OPENAI_API_KEY)
 
 
 
 
 
 
 
 
 
 
 
 
21
 
22
- # -------------------- CHAT SESSION --------------------
23
- if "messages" not in st.session_state:
24
- st.session_state.messages = []
25
- if "thread_id" not in st.session_state:
26
- st.session_state.thread_id = None
 
 
 
27
 
28
- query = st.text_input("Ask about plans, drawings or components", placeholder="e.g. Show me all electrical plans")
 
 
 
 
 
 
 
 
 
 
 
 
29
 
30
  if query:
31
- with st.spinner("Querying assistant..."):
32
  try:
33
- # Create thread if needed
34
- if not st.session_state.thread_id:
35
  thread = client.beta.threads.create()
36
  st.session_state.thread_id = thread.id
37
 
38
- # Submit message
39
  client.beta.threads.messages.create(
40
  thread_id=st.session_state.thread_id,
41
  role="user",
42
  content=query
43
  )
44
 
45
- # Run assistant
46
  run = client.beta.threads.runs.create(
47
  thread_id=st.session_state.thread_id,
48
  assistant_id=ASSISTANT_ID
49
  )
50
 
51
- # Poll for result
52
  while True:
53
  run_status = client.beta.threads.runs.retrieve(
54
  thread_id=st.session_state.thread_id,
55
  run_id=run.id
56
  )
57
- if run_status.status == "completed":
58
  break
59
- elif run_status.status in ("failed", "cancelled"):
60
- raise Exception(f"Assistant failed: {run_status.status}")
61
  time.sleep(1)
62
 
63
- # Fetch assistant message
64
- messages = client.beta.threads.messages.list(thread_id=st.session_state.thread_id)
65
- for message in reversed(messages.data):
66
- if message.role == "assistant":
67
- content = message.content[0].text.value.strip()
68
- if content.startswith("```json") and content.endswith("```"):
69
- json_block = content.strip("```json\n").strip("```")
70
- parsed = json.loads(json_block)
71
- st.session_state.messages.append(parsed)
72
- else:
73
- st.error("⚠️ Could not parse assistant response as JSON.")
74
- break
75
 
76
  except Exception as e:
77
- st.error(f"❌ Error: {e}")
78
-
79
- # -------------------- DISPLAY RESULTS --------------------
80
- if st.session_state.messages:
81
- drawings = st.session_state.messages[-1]
82
- if isinstance(drawings, list):
83
- cols = st.columns(4)
84
- for idx, item in enumerate(drawings):
85
- with cols[idx % 4]:
86
- st.subheader(f"πŸ“˜ {item['drawing_number']}")
87
- st.caption(f"Discipline: {item['discipline']}")
88
- st.write(item.get("summary", "No summary available."))
89
- if "images" in item:
90
- for img in item["images"][:1]:
91
- st.image(img, use_column_width=True)
92
- elif "image" in item:
93
- st.image(item["image"], use_column_width=True)
94
- if "question" in item:
95
- st.markdown(f"**Related Question:** {item['question']}")
 
1
+ import streamlit as st
2
+ import openai
3
  import os
4
  import json
5
+ import re
6
  import requests
7
+ from PIL import Image
8
+ from io import BytesIO
9
+ from urllib.parse import quote
 
 
 
10
 
11
+ # ------------------ Configuration ------------------
12
  st.set_page_config(page_title="Forrestdale Technical Drawing Assistant", layout="wide")
13
+ st.markdown("""
14
+ <h1 style='font-size: 2.5rem;'>πŸͺ Forrestdale Technical Drawing Assistant</h1>
15
+ <p style='font-size: 1rem;'>Ask about plans, drawings or components</p>
16
+ """, unsafe_allow_html=True)
17
+
18
+ # ------------------ Environment ------------------
19
+ OPENAI_API_KEY = os.getenv("OPENAI_API_KEY")
20
+ ASSISTANT_ID = os.getenv("ASSISTANT_ID")
21
 
 
22
  if not OPENAI_API_KEY or not ASSISTANT_ID:
23
+ st.error("❌ Missing environment variables: OPENAI_API_KEY or ASSISTANT_ID.")
24
  st.stop()
25
 
26
+ client = openai.OpenAI(api_key=OPENAI_API_KEY)
27
+
28
+ # ------------------ Helper Functions ------------------
29
+ def extract_json_from_response(response_text):
30
+ try:
31
+ match = re.search(r"```json\s*([\s\S]+?)```", response_text.strip())
32
+ if not match:
33
+ raise ValueError("No valid JSON block found.")
34
+ json_str = match.group(1).strip()
35
+ return json.loads(json_str)
36
+ except Exception as e:
37
+ st.error("⚠️ Could not parse assistant response as JSON.")
38
+ st.stop()
39
 
40
+ def display_card(item):
41
+ st.markdown("""
42
+ <div style="border: 1px solid #333; border-radius: 12px; padding: 16px; margin: 10px; background-color: #111;">
43
+ <h3>πŸ“ {} ({})</h3>
44
+ <p><b>Discipline:</b> {}</p>
45
+ <p><b>Summary:</b> {}</p>
46
+ <div style="display: flex; flex-wrap: wrap; gap: 10px;">
47
+ """.format(item["drawing_number"], item.get("drawing_type", ""), item["discipline"], item["summary"]), unsafe_allow_html=True)
48
 
49
+ for img in item.get("images", []):
50
+ try:
51
+ response = requests.get(img)
52
+ if response.status_code == 200:
53
+ image = Image.open(BytesIO(response.content))
54
+ st.image(image, caption=os.path.basename(img), width=200)
55
+ except:
56
+ st.warning(f"Image failed to load: {img}")
57
+
58
+ st.markdown("</div></div>", unsafe_allow_html=True)
59
+
60
+ # ------------------ Input ------------------
61
+ query = st.text_input("Ask about plans, drawings or components", placeholder="Show me all architectural plans")
62
 
63
  if query:
64
+ with st.spinner("πŸ” Querying assistant..."):
65
  try:
66
+ if "thread_id" not in st.session_state:
 
67
  thread = client.beta.threads.create()
68
  st.session_state.thread_id = thread.id
69
 
 
70
  client.beta.threads.messages.create(
71
  thread_id=st.session_state.thread_id,
72
  role="user",
73
  content=query
74
  )
75
 
 
76
  run = client.beta.threads.runs.create(
77
  thread_id=st.session_state.thread_id,
78
  assistant_id=ASSISTANT_ID
79
  )
80
 
 
81
  while True:
82
  run_status = client.beta.threads.runs.retrieve(
83
  thread_id=st.session_state.thread_id,
84
  run_id=run.id
85
  )
86
+ if run_status.status in ["completed", "failed", "cancelled"]:
87
  break
 
 
88
  time.sleep(1)
89
 
90
+ if run_status.status != "completed":
91
+ st.error(f"❌ Assistant run failed: {run_status.status}")
92
+ else:
93
+ messages = client.beta.threads.messages.list(thread_id=st.session_state.thread_id)
94
+ for message in reversed(messages.data):
95
+ if message.role == "assistant":
96
+ response_text = message.content[0].text.value
97
+ data = extract_json_from_response(response_text)
98
+ for item in data:
99
+ display_card(item)
100
+ break
 
101
 
102
  except Exception as e:
103
+ st.error(f"❌ Error during assistant call: {e}")