Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
@@ -1,92 +1,85 @@
|
|
1 |
-
import
|
2 |
-
import openai
|
3 |
import os
|
4 |
import json
|
|
|
|
|
|
|
5 |
|
6 |
-
#
|
7 |
-
|
8 |
-
|
9 |
-
VECTOR_STORE_ID = "vs_68199dddd40c8191973e8a6d1b136cd3"
|
10 |
-
|
11 |
-
# === Chat Function ===
|
12 |
-
def search_drawings(user_query):
|
13 |
-
try:
|
14 |
-
thread = openai.beta.threads.create()
|
15 |
-
openai.beta.threads.messages.create(
|
16 |
-
thread_id=thread.id,
|
17 |
-
role="user",
|
18 |
-
content=user_query
|
19 |
-
)
|
20 |
|
21 |
-
|
22 |
-
|
23 |
-
|
24 |
-
tool_choice="auto",
|
25 |
-
vector_store_ids=[VECTOR_STORE_ID]
|
26 |
-
)
|
27 |
-
|
28 |
-
# Wait for completion
|
29 |
-
while True:
|
30 |
-
run_status = openai.beta.threads.runs.retrieve(thread_id=thread.id, run_id=run.id)
|
31 |
-
if run_status.status in ["completed", "failed", "cancelled"]:
|
32 |
-
break
|
33 |
-
|
34 |
-
if run_status.status != "completed":
|
35 |
-
return gr.update(visible=True), f"❌ Assistant failed: {run_status.status}", []
|
36 |
|
37 |
-
|
38 |
-
|
39 |
-
|
40 |
-
raw = m.content[0].text.value
|
41 |
-
try:
|
42 |
-
result = json.loads(raw)
|
43 |
-
cards = []
|
44 |
-
for entry in result.get("drawings", []):
|
45 |
-
img_tag = f'<img src="{entry["image_url"]}" style="width:100%; border-radius:12px"/>'
|
46 |
-
page_caption = f"{entry['drawing_number']} – Page {entry['page_number']}"
|
47 |
-
summary = f"<b>Summary:</b> {entry['summary']}"
|
48 |
|
49 |
-
|
50 |
-
cards.append(gr.HTML(f"""
|
51 |
-
<div style='background:#1a1a1a; border:1px solid #333; border-radius:14px; padding:16px; height:100%'>
|
52 |
-
{img_tag}<br>
|
53 |
-
<p style='margin-top:8px; font-weight:bold;'>{page_caption}</p>
|
54 |
-
<p style='font-size:14px'>{summary}</p>
|
55 |
-
</div>
|
56 |
-
"""))
|
57 |
-
return gr.update(visible=False), "", cards
|
58 |
-
except Exception as e:
|
59 |
-
return gr.update(visible=True), "⚠️ Could not parse assistant response as JSON.", []
|
60 |
-
return gr.update(visible=True), "⚠️ No assistant response found.", []
|
61 |
|
62 |
-
|
63 |
-
|
|
|
|
|
|
|
64 |
|
65 |
-
#
|
66 |
-
|
67 |
-
description = "Ask for plans by discipline, components or tags (e.g. \"Show all architectural plans\")"
|
68 |
|
69 |
-
|
70 |
-
|
71 |
-
|
72 |
-
|
73 |
-
<p style='color:#aaa; font-size:16px'>{description}</p>
|
74 |
-
""")
|
75 |
|
76 |
-
|
77 |
-
|
78 |
-
|
|
|
|
|
79 |
|
80 |
-
|
81 |
-
|
|
|
|
|
82 |
|
83 |
-
|
84 |
-
|
85 |
-
|
86 |
-
|
87 |
-
|
|
|
|
|
|
|
|
|
88 |
|
89 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
90 |
|
91 |
-
|
92 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import streamlit as st
|
|
|
2 |
import os
|
3 |
import json
|
4 |
+
import time
|
5 |
+
import requests
|
6 |
+
from openai import OpenAI
|
7 |
|
8 |
+
# ------------------ App Configuration ------------------
|
9 |
+
st.set_page_config(page_title="Forrestdale Drawing Assistant", layout="wide")
|
10 |
+
st.title("📐 Forrestdale Technical Drawing Assistant")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
11 |
|
12 |
+
# ------------------ Load API Key and Assistant ID ------------------
|
13 |
+
OPENAI_API_KEY = os.environ.get("OPENAI_API_KEY")
|
14 |
+
ASSISTANT_ID = os.environ.get("ASSISTANT_ID")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
15 |
|
16 |
+
if not OPENAI_API_KEY or not ASSISTANT_ID:
|
17 |
+
st.error("❌ Missing secrets. Please set OPENAI_API_KEY and ASSISTANT_ID in secrets.")
|
18 |
+
st.stop()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
19 |
|
20 |
+
client = OpenAI(api_key=OPENAI_API_KEY)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
21 |
|
22 |
+
# ------------------ Session State Init ------------------
|
23 |
+
if "thread_id" not in st.session_state:
|
24 |
+
st.session_state.thread_id = None
|
25 |
+
if "results" not in st.session_state:
|
26 |
+
st.session_state.results = []
|
27 |
|
28 |
+
# ------------------ Query Bar ------------------
|
29 |
+
prompt = st.text_input("Ask about plans, drawings or components", placeholder="e.g. Show me all electrical plans")
|
|
|
30 |
|
31 |
+
if prompt:
|
32 |
+
if st.session_state.thread_id is None:
|
33 |
+
thread = client.beta.threads.create()
|
34 |
+
st.session_state.thread_id = thread.id
|
|
|
|
|
35 |
|
36 |
+
client.beta.threads.messages.create(
|
37 |
+
thread_id=st.session_state.thread_id,
|
38 |
+
role="user",
|
39 |
+
content=prompt
|
40 |
+
)
|
41 |
|
42 |
+
run = client.beta.threads.runs.create(
|
43 |
+
thread_id=st.session_state.thread_id,
|
44 |
+
assistant_id=ASSISTANT_ID
|
45 |
+
)
|
46 |
|
47 |
+
with st.spinner("Thinking..."):
|
48 |
+
while True:
|
49 |
+
run_status = client.beta.threads.runs.retrieve(
|
50 |
+
thread_id=st.session_state.thread_id,
|
51 |
+
run_id=run.id
|
52 |
+
)
|
53 |
+
if run_status.status in ("completed", "failed", "cancelled"):
|
54 |
+
break
|
55 |
+
time.sleep(1)
|
56 |
|
57 |
+
if run_status.status == "completed":
|
58 |
+
messages = client.beta.threads.messages.list(thread_id=st.session_state.thread_id)
|
59 |
+
for message in reversed(messages.data):
|
60 |
+
if message.role == "assistant":
|
61 |
+
try:
|
62 |
+
json_data = json.loads(message.content[0].text.value)
|
63 |
+
st.session_state.results = json_data["results"]
|
64 |
+
except Exception as e:
|
65 |
+
st.error("⚠️ Could not parse assistant response as JSON.")
|
66 |
+
break
|
67 |
+
else:
|
68 |
+
st.error(f"⚠️ Assistant failed: {run_status.status}")
|
69 |
|
70 |
+
# ------------------ Display Results as Cards ------------------
|
71 |
+
if st.session_state.results:
|
72 |
+
cols = st.columns(4)
|
73 |
+
for i, result in enumerate(st.session_state.results):
|
74 |
+
with cols[i % 4]:
|
75 |
+
st.markdown("""
|
76 |
+
<div style='border:1px solid #444; padding:10px; border-radius:10px; background:#111;'>
|
77 |
+
<h5 style='color:#fdd;'>📁 {drawing_number}</h5>
|
78 |
+
<b>Summary:</b> {summary}<br>
|
79 |
+
<img src="{image_url}" style="width:100%; margin-top:10px; border-radius:6px;">
|
80 |
+
</div>
|
81 |
+
""".format(
|
82 |
+
drawing_number=result.get("drawing_number", "Untitled"),
|
83 |
+
summary=result.get("summary", "No summary available."),
|
84 |
+
image_url=result.get("image_url", "")
|
85 |
+
), unsafe_allow_html=True)
|