IAMTFRMZA commited on
Commit
92001e7
Β·
verified Β·
1 Parent(s): 81240ab

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +75 -97
app.py CHANGED
@@ -2,132 +2,110 @@ import streamlit as st
2
  import os
3
  import time
4
  import re
5
- import requests
6
- import tempfile
7
- import wave
8
- import numpy as np
9
  from openai import OpenAI
10
- from streamlit_audio_recorder import audio_recorder
11
 
12
- # ------------------ Page Config ------------------
13
  st.set_page_config(page_title="Document AI Assistant", layout="wide")
14
  st.title("πŸ“„ Document AI Assistant")
15
  st.caption("Chat with an AI Assistant on your medical/pathology documents")
16
 
17
- # ------------------ Load Secrets ------------------
18
  OPENAI_API_KEY = os.environ.get("OPENAI_API_KEY")
19
  ASSISTANT_ID = os.environ.get("ASSISTANT_ID")
20
 
 
21
  if not OPENAI_API_KEY or not ASSISTANT_ID:
22
- st.error("❌ Missing secrets. Please set both OPENAI_API_KEY and ASSISTANT_ID in Hugging Face Space settings.")
23
  st.stop()
24
 
25
  client = OpenAI(api_key=OPENAI_API_KEY)
26
 
27
- # ------------------ Session State Init ------------------
28
- for key in ["messages", "thread_id", "image_url", "transcript"]:
29
- if key not in st.session_state:
30
- st.session_state[key] = [] if key == "messages" else None
31
-
32
- # ------------------ Whisper Transcription ------------------
33
- def transcribe_audio(file_path, api_key):
34
- with open(file_path, "rb") as f:
35
- response = requests.post(
36
- "https://api.openai.com/v1/audio/transcriptions",
37
- headers={"Authorization": f"Bearer {api_key}"},
38
- files={"file": f},
39
- data={"model": "whisper-1"}
40
- )
41
- return response.json().get("text", None)
42
-
43
- # ------------------ Sidebar & Layout ------------------
44
  st.sidebar.header("πŸ”§ Settings")
45
  if st.sidebar.button("πŸ”„ Clear Chat"):
46
  st.session_state.messages = []
47
  st.session_state.thread_id = None
48
  st.session_state.image_url = None
49
- st.session_state.transcript = None
50
  st.rerun()
51
 
52
  show_image = st.sidebar.checkbox("πŸ“– Show Document Image", value=True)
53
- col1, col2 = st.columns([1, 2])
54
 
55
- # ------------------ Image Panel ------------------
 
 
 
56
  with col1:
57
  if show_image and st.session_state.image_url:
58
  st.image(st.session_state.image_url, caption="πŸ“‘ Extracted Page", use_container_width=True)
59
 
60
- # ------------------ Chat + Mic Panel ------------------
61
  with col2:
62
  for message in st.session_state.messages:
63
- st.chat_message(message["role"]).write(message["content"])
64
-
65
- st.subheader("πŸŽ™οΈ Ask with Your Voice")
66
-
67
- audio_bytes = audio_recorder(pause_threshold=3.0, energy_threshold=-1.0, sample_rate=44100)
68
-
69
- if audio_bytes:
70
- # Save temporary WAV file
71
- with tempfile.NamedTemporaryFile(delete=False, suffix=".wav") as tmpfile:
72
- tmpfile.write(audio_bytes)
73
- tmp_path = tmpfile.name
74
-
75
- st.audio(tmp_path, format="audio/wav")
76
-
77
- with st.spinner("🧠 Transcribing..."):
78
- transcript = transcribe_audio(tmp_path, OPENAI_API_KEY)
79
-
80
- if transcript:
81
- st.success("πŸ“ Transcript: " + transcript)
82
- st.session_state.transcript = transcript
83
-
84
- # Submit Transcript to Assistant
85
- if st.session_state.transcript:
86
- if st.button("βœ… Send Transcript to Assistant"):
87
- user_input = st.session_state.transcript
88
- st.session_state.transcript = None # reset
89
-
90
- st.session_state.messages.append({"role": "user", "content": user_input})
91
- st.chat_message("user").write(user_input)
92
-
93
- try:
94
- if st.session_state.thread_id is None:
95
- thread = client.beta.threads.create()
96
- st.session_state.thread_id = thread.id
97
-
98
- thread_id = st.session_state.thread_id
99
- client.beta.threads.messages.create(thread_id=thread_id, role="user", content=user_input)
100
- run = client.beta.threads.runs.create(thread_id=thread_id, assistant_id=ASSISTANT_ID)
101
-
102
- with st.spinner("πŸ€– Assistant is thinking..."):
103
- while True:
104
- run_status = client.beta.threads.runs.retrieve(thread_id=thread_id, run_id=run.id)
105
- if run_status.status == "completed":
106
- break
107
- time.sleep(1)
108
-
109
- messages = client.beta.threads.messages.list(thread_id=thread_id)
110
- assistant_message = next(
111
- (m.content[0].text.value for m in reversed(messages.data) if m.role == "assistant"), None
112
- )
113
-
114
- st.chat_message("assistant").write(assistant_message)
115
- st.session_state.messages.append({"role": "assistant", "content": assistant_message})
116
-
117
- # Extract GitHub image if available
118
- image_match = re.search(
119
- r'https://raw\.githubusercontent\.com/AndrewLORTech/surgical-pathology-manual/main/[\w\-/]*\.png',
120
- assistant_message
121
- )
122
- if image_match:
123
- st.session_state.image_url = image_match.group(0)
124
-
125
- except Exception as e:
126
- st.error(f"❌ Error: {str(e)}")
127
-
128
- # Fallback text input
129
- if prompt := st.chat_input("πŸ’¬ Or type your question..."):
130
  st.session_state.messages.append({"role": "user", "content": prompt})
131
  st.chat_message("user").write(prompt)
132
- st.session_state.transcript = prompt # Treat like voice input for now
133
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2
  import os
3
  import time
4
  import re
 
 
 
 
5
  from openai import OpenAI
 
6
 
7
+ # ------------------ App Configuration ------------------
8
  st.set_page_config(page_title="Document AI Assistant", layout="wide")
9
  st.title("πŸ“„ Document AI Assistant")
10
  st.caption("Chat with an AI Assistant on your medical/pathology documents")
11
 
12
+ # ------------------ Load API Key and Assistant ID from Hugging Face Secrets ------------------
13
  OPENAI_API_KEY = os.environ.get("OPENAI_API_KEY")
14
  ASSISTANT_ID = os.environ.get("ASSISTANT_ID")
15
 
16
+ # ------------------ Error Handling for Missing Secrets ------------------
17
  if not OPENAI_API_KEY or not ASSISTANT_ID:
18
+ st.error("Missing secrets. Please ensure both OPENAI_API_KEY and ASSISTANT_ID are set in your Hugging Face Space secrets.")
19
  st.stop()
20
 
21
  client = OpenAI(api_key=OPENAI_API_KEY)
22
 
23
+ # ------------------ Session State Initialization ------------------
24
+ if "messages" not in st.session_state:
25
+ st.session_state.messages = []
26
+ if "thread_id" not in st.session_state:
27
+ st.session_state.thread_id = None
28
+ if "image_url" not in st.session_state:
29
+ st.session_state.image_url = None
30
+
31
+ # ------------------ Sidebar Controls ------------------
 
 
 
 
 
 
 
 
32
  st.sidebar.header("πŸ”§ Settings")
33
  if st.sidebar.button("πŸ”„ Clear Chat"):
34
  st.session_state.messages = []
35
  st.session_state.thread_id = None
36
  st.session_state.image_url = None
 
37
  st.rerun()
38
 
39
  show_image = st.sidebar.checkbox("πŸ“– Show Document Image", value=True)
 
40
 
41
+ # ------------------ Split Layout ------------------
42
+ col1, col2 = st.columns([1, 2]) # Adjust ratio as needed
43
+
44
+ # ------------------ Image Panel (Left) ------------------
45
  with col1:
46
  if show_image and st.session_state.image_url:
47
  st.image(st.session_state.image_url, caption="πŸ“‘ Extracted Page", use_container_width=True)
48
 
49
+ # ------------------ Chat Panel (Right) ------------------
50
  with col2:
51
  for message in st.session_state.messages:
52
+ role, content = message["role"], message["content"]
53
+ st.chat_message(role).write(content)
54
+
55
+ if prompt := st.chat_input("Type your question about the document..."):
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
56
  st.session_state.messages.append({"role": "user", "content": prompt})
57
  st.chat_message("user").write(prompt)
 
58
 
59
+ try:
60
+ # Initialize thread if needed
61
+ if st.session_state.thread_id is None:
62
+ thread = client.beta.threads.create()
63
+ st.session_state.thread_id = thread.id
64
+
65
+ thread_id = st.session_state.thread_id
66
+
67
+ # Send message to assistant
68
+ client.beta.threads.messages.create(
69
+ thread_id=thread_id,
70
+ role="user",
71
+ content=prompt
72
+ )
73
+
74
+ # Run assistant
75
+ run = client.beta.threads.runs.create(
76
+ thread_id=thread_id,
77
+ assistant_id=ASSISTANT_ID
78
+ )
79
+
80
+ # Wait for assistant response
81
+ with st.spinner("Assistant is thinking..."):
82
+ while True:
83
+ run_status = client.beta.threads.runs.retrieve(
84
+ thread_id=thread_id,
85
+ run_id=run.id
86
+ )
87
+ if run_status.status == "completed":
88
+ break
89
+ time.sleep(1)
90
+
91
+ # Get assistant response
92
+ messages = client.beta.threads.messages.list(thread_id=thread_id)
93
+ assistant_message = None
94
+ for message in reversed(messages.data):
95
+ if message.role == "assistant":
96
+ assistant_message = message.content[0].text.value
97
+ break
98
+
99
+ st.chat_message("assistant").write(assistant_message)
100
+ st.session_state.messages.append({"role": "assistant", "content": assistant_message})
101
+
102
+ # Extract GitHub image from response if available
103
+ image_match = re.search(
104
+ r'https://raw\.githubusercontent\.com/AndrewLORTech/surgical-pathology-manual/main/[\w\-/]*\.png',
105
+ assistant_message
106
+ )
107
+ if image_match:
108
+ st.session_state.image_url = image_match.group(0)
109
+
110
+ except Exception as e:
111
+ st.error(f"❌ Error: {str(e)}")