Spaces:
Running
Running
adding newest pages
Browse files- .DS_Store +0 -0
- pages/chat.py +282 -0
- pages/tableau.py +18 -0
.DS_Store
CHANGED
Binary files a/.DS_Store and b/.DS_Store differ
|
|
pages/chat.py
ADDED
@@ -0,0 +1,282 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from openai import OpenAI
|
2 |
+
import streamlit as st
|
3 |
+
from langchain_openai import ChatOpenAI
|
4 |
+
from langchain_openai.embeddings import OpenAIEmbeddings
|
5 |
+
from langchain_text_splitters import RecursiveCharacterTextSplitter
|
6 |
+
import markdown
|
7 |
+
from operator import itemgetter
|
8 |
+
from langchain.schema.runnable import RunnablePassthrough
|
9 |
+
from langchain_core.prompts import ChatPromptTemplate
|
10 |
+
from langchain.schema import Document
|
11 |
+
from dotenv import load_dotenv
|
12 |
+
from langchain_community.vectorstores import Qdrant
|
13 |
+
# from langchain_qdrant import Qdrant
|
14 |
+
import os
|
15 |
+
import pandas as pd
|
16 |
+
import numpy as np
|
17 |
+
|
18 |
+
st.set_page_config(
|
19 |
+
page_title="Narrativ 🧠",
|
20 |
+
layout="wide",
|
21 |
+
initial_sidebar_state="expanded",
|
22 |
+
page_icon="🧠",
|
23 |
+
)
|
24 |
+
|
25 |
+
# Custom CSS for enhanced styling
|
26 |
+
st.markdown("""
|
27 |
+
<style>
|
28 |
+
.circular-image {
|
29 |
+
width: 200px;
|
30 |
+
height: 200px;
|
31 |
+
border-radius: 50%;
|
32 |
+
object-fit: cover;
|
33 |
+
display: block;
|
34 |
+
margin: 20px auto;
|
35 |
+
box-shadow: 0 4px 8px rgba(0,0,0,0.1);
|
36 |
+
}
|
37 |
+
|
38 |
+
/* Container for search section */
|
39 |
+
.search-container {
|
40 |
+
background: white;
|
41 |
+
padding: 20px;
|
42 |
+
border-radius: 10px;
|
43 |
+
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
|
44 |
+
margin: 20px 0;
|
45 |
+
}
|
46 |
+
|
47 |
+
/* Combined search input styling */
|
48 |
+
.combined-search {
|
49 |
+
display: flex;
|
50 |
+
gap: 10px;
|
51 |
+
align-items: center;
|
52 |
+
margin-bottom: 20px;
|
53 |
+
}
|
54 |
+
</style>
|
55 |
+
""", unsafe_allow_html=True)
|
56 |
+
|
57 |
+
load_dotenv()
|
58 |
+
OPENAI_API_KEY = os.environ["OPENAI_API_KEY"]
|
59 |
+
base_llm = ChatOpenAI(model="gpt-4o")
|
60 |
+
embedding_model = OpenAIEmbeddings(model="text-embedding-3-small")
|
61 |
+
|
62 |
+
#========== APP
|
63 |
+
|
64 |
+
from PIL import Image, ImageEnhance
|
65 |
+
|
66 |
+
image = Image.open('./data/Sentiment_index_traffic.png')
|
67 |
+
enhancer = ImageEnhance.Brightness(image)
|
68 |
+
darker_image = enhancer.enhance(0.5) # Adjust the brightness factor as needed
|
69 |
+
st.image(darker_image, use_container_width=True, output_format="PNG", clamp=True)
|
70 |
+
|
71 |
+
st.title("Narrativ 📰")
|
72 |
+
|
73 |
+
# Add a button to navigate to search page
|
74 |
+
if st.button("Go to Search 🔍", use_container_width=False):
|
75 |
+
st.switch_page("pages/search.py")
|
76 |
+
|
77 |
+
#check1 = st.button("Submit", key="submit_button")
|
78 |
+
prompt='I-495'
|
79 |
+
|
80 |
+
prompt=st.session_state.prompt
|
81 |
+
date=st.session_state.date
|
82 |
+
# Change the sidebar background with enhanced gradient and text styling
|
83 |
+
# sideb.markdown(
|
84 |
+
|
85 |
+
if 'messages' not in st.session_state:
|
86 |
+
st.session_state.messages = []
|
87 |
+
|
88 |
+
st.session_state.messages.append({"role": "assistant", "content": f'{date} {prompt}'})
|
89 |
+
|
90 |
+
if prompt:
|
91 |
+
if date:
|
92 |
+
try:
|
93 |
+
data=pd.read_csv('./data/sentiment_index_traffic_index_final1.csv',
|
94 |
+
index_col='index',
|
95 |
+
parse_dates=True,
|
96 |
+
infer_datetime_format=True
|
97 |
+
)
|
98 |
+
|
99 |
+
data = data.loc[data.index == date]
|
100 |
+
filtered_data = data[data.apply(lambda row: row.astype(str).str.contains(prompt, na=False).any(), axis=1)]
|
101 |
+
data_all = filtered_data.values.flatten()
|
102 |
+
docs = data_all
|
103 |
+
if len(docs)<1:
|
104 |
+
st.warning("No articles found that contain the prompt string.")
|
105 |
+
|
106 |
+
# Create markdown formatted text from the matching articles.
|
107 |
+
# docs_text = "\n".join([f"- {article}" for article in data_prompt if article])
|
108 |
+
# docs = [Document(page_content=docs_text)]
|
109 |
+
except Exception as e:
|
110 |
+
st.error(f"Error processing date: {e}")
|
111 |
+
else:
|
112 |
+
try:
|
113 |
+
data = pd.read_csv(
|
114 |
+
'./data/sentiment_index_traffic_index_final1.csv',
|
115 |
+
index_col='index',
|
116 |
+
parse_dates=True,
|
117 |
+
infer_datetime_format=True
|
118 |
+
)
|
119 |
+
|
120 |
+
filtered_data = data[data.apply(lambda row: row.astype(str).str.contains(prompt, na=False).any(), axis=1)]
|
121 |
+
data_all = filtered_data.values.flatten()
|
122 |
+
docs = data_all
|
123 |
+
if len(docs)<1:
|
124 |
+
st.warning("No articles found that contain the prompt string.")
|
125 |
+
|
126 |
+
#data_all = data.values.flatten()
|
127 |
+
#docs = data_all
|
128 |
+
# with open(f'./data/sentiment_index_traffic_index_final1.md', "w", encoding="utf-8") as file:
|
129 |
+
# file.write(str(data_all))
|
130 |
+
# with open(f'./data/sentiment_index_traffic_index_final1.md', "r", encoding="utf-8") as file_content:
|
131 |
+
# docs = file_content.read()
|
132 |
+
except Exception as e:
|
133 |
+
st.error(f"Error loading data: {e}")
|
134 |
+
|
135 |
+
docs_text = "\n".join([f"- {value}" for value in data_all if not pd.isna(value)])
|
136 |
+
docs = [Document(page_content=docs_text)]
|
137 |
+
st.write(data)
|
138 |
+
|
139 |
+
# Remove the markdown.markdown() since we've already formatted the text
|
140 |
+
docs = [Document(page_content=docs_text)]
|
141 |
+
#docs = [Document(page_content=markdown.markdown(docs))]
|
142 |
+
print(docs)
|
143 |
+
split_documents = RecursiveCharacterTextSplitter.from_tiktoken_encoder(
|
144 |
+
chunk_size=1000,
|
145 |
+
chunk_overlap=20
|
146 |
+
).split_documents(docs)
|
147 |
+
|
148 |
+
vectorstore = Qdrant.from_documents(
|
149 |
+
split_documents,
|
150 |
+
embedding_model,
|
151 |
+
location=":memory:",
|
152 |
+
collection_name="langchainblogs"
|
153 |
+
)
|
154 |
+
|
155 |
+
retriever = vectorstore.as_retriever()
|
156 |
+
|
157 |
+
print("Loaded Vectorstore")
|
158 |
+
|
159 |
+
# Add user message to chat history
|
160 |
+
st.session_state.messages.append({"role": "user", "content": prompt})
|
161 |
+
# Display user message in chat message container
|
162 |
+
with st.chat_message("user"):
|
163 |
+
st.markdown(prompt)
|
164 |
+
|
165 |
+
# Generate summarized message rationalize dominant sentiment
|
166 |
+
RAG_PROMPT = """# Traffic Analyst - Transurban Prompt
|
167 |
+
|
168 |
+
You are a Transurban traffic consultant focusing on the I-495 and I-95 express lanes in the Greater Washington area (GWA). Your task is to analyze news articles provided by a client on a specific topic. You will receive the full text of the relevant articles for the assigned topic, along with key data points.
|
169 |
+
You analyze articles and explain phenomenon for the traffic on the date.
|
170 |
+
## Your Tasks:
|
171 |
+
|
172 |
+
### 1. Summarize Opinions:
|
173 |
+
- Extract the key opinions and perspectives from the provided news articles.
|
174 |
+
- The news articles will include: title, URL, date, text, article source, sentiment index created by Transurban, sentiment index using HF (Hugging Face) model, and confidence for the HF index.
|
175 |
+
- Highlight any significant patterns, agreements, or disagreements across the sources.
|
176 |
+
|
177 |
+
### 2. Analyze Sentiment:
|
178 |
+
- Determine the overall sentiment (positive, negative, neutral) about the topic based on the extracted opinions.
|
179 |
+
- Provide a clear explanation of your sentiment conclusion, referencing specific points or trends from the articles.
|
180 |
+
|
181 |
+
### 3. Provide Chain-of-Thought Reasoning:
|
182 |
+
- Detail your reasoning process step by step. Explain how you interpreted the articles, derived insights, and reached your sentiment conclusion.
|
183 |
+
- Ensure the reasoning is logical, transparent, and grounded in the content provided.
|
184 |
+
|
185 |
+
### 4. Collect URL Sources:
|
186 |
+
- From the provided context, select 5 critical and recent URL sources related to the topic.
|
187 |
+
|
188 |
+
## Output Format:
|
189 |
+
|
190 |
+
- **Summary of Opinions:** [Concise summary of key opinions]
|
191 |
+
- **Sentiment Analysis:**
|
192 |
+
- Sentiment: [Positive/Negative/Neutral]
|
193 |
+
- Reasoning: [Detailed explanation here]
|
194 |
+
- **Chain-of-Thought Reasoning:** [Step-by-step explanation]
|
195 |
+
- **Sources:** [URLs for 5 most critical and recent articles on this topic]
|
196 |
+
|
197 |
+
## Guidelines:
|
198 |
+
- Maintain objectivity and precision in your analysis.
|
199 |
+
- Focus on the context specific to the Greater Washington Area.
|
200 |
+
- Use professional and analytical language suitable for client reports.
|
201 |
+
- Respond in the language of the article (mostly English).
|
202 |
+
|
203 |
+
CONTEXT:
|
204 |
+
{context}
|
205 |
+
|
206 |
+
QUERY:
|
207 |
+
{question}
|
208 |
+
Use the provided context to answer the provided user question. Only use the provided context to answer the question. If you do not know the answer, respond with "I don't know"
|
209 |
+
"""
|
210 |
+
rag_prompt = ChatPromptTemplate.from_template(RAG_PROMPT)
|
211 |
+
# RAG CHAIN
|
212 |
+
lcel_rag_chain = (
|
213 |
+
{"context": itemgetter("question") | retriever, "question": itemgetter("question")}
|
214 |
+
| RunnablePassthrough.assign(context=itemgetter("context"))
|
215 |
+
| {"response": rag_prompt | base_llm, "context": itemgetter("context")}
|
216 |
+
)
|
217 |
+
|
218 |
+
try:
|
219 |
+
summary = lcel_rag_chain.invoke({"question": prompt})
|
220 |
+
print(summary)
|
221 |
+
st.chat_message("assistant").write((summary['response'].content))
|
222 |
+
st.session_state.messages.append({"role": "assistant", "content": summary['response'].content})
|
223 |
+
except Exception as e:
|
224 |
+
st.error(f"Error generating summary: {e}")
|
225 |
+
|
226 |
+
if date:
|
227 |
+
with open('./data/sentiment_index_traffic_index_final_date.md', 'w') as file:
|
228 |
+
file.write(str(data_all))
|
229 |
+
else:
|
230 |
+
with open('./data/sentiment_index_traffic_index_final1.md', 'w') as file:
|
231 |
+
file.write(str(data_all))
|
232 |
+
|
233 |
+
|
234 |
+
client = OpenAI(api_key=OPENAI_API_KEY)
|
235 |
+
|
236 |
+
if "openai_model" not in st.session_state:
|
237 |
+
st.session_state["openai_model"] = "gpt-4o"
|
238 |
+
|
239 |
+
prompt1 = st.chat_input("Type your additional questions here...")
|
240 |
+
|
241 |
+
# Suggested keywords with enhanced styling
|
242 |
+
suggested_keywords = ["Summarize results", f"Explain the traffic drop", f"Explain the traffic growth"]
|
243 |
+
st.markdown("**Suggested Keywords:**")
|
244 |
+
cols = st.columns(len(suggested_keywords))
|
245 |
+
for idx, keyword in enumerate(suggested_keywords):
|
246 |
+
if cols[idx].button(keyword, key=keyword):
|
247 |
+
prompt1 = keyword
|
248 |
+
|
249 |
+
if prompt1:
|
250 |
+
|
251 |
+
if date:
|
252 |
+
file_path = f'./data/sentiment_index_traffic_index_final_date.md'
|
253 |
+
else:
|
254 |
+
file_path = f'./data/sentiment_index_traffic_index_final1.md'
|
255 |
+
|
256 |
+
try:
|
257 |
+
with open(file_path, "r", encoding="utf-8") as file_content:
|
258 |
+
docs = file_content.read()
|
259 |
+
except Exception as e:
|
260 |
+
st.error(f"Error loading context: {e}")
|
261 |
+
docs = ""
|
262 |
+
|
263 |
+
# Add user message to chat history
|
264 |
+
st.session_state.messages.append({"role": "user", "content": f'You are a data analyst, that answer questions: {prompt1} using context from {docs}'})
|
265 |
+
# Display user message in chat message container
|
266 |
+
with st.chat_message("user"):
|
267 |
+
st.markdown(prompt1)
|
268 |
+
# Display assistant response in chat message container
|
269 |
+
with st.chat_message("assistant"):
|
270 |
+
try:
|
271 |
+
stream = client.chat.completions.create(
|
272 |
+
model=st.session_state["openai_model"],
|
273 |
+
messages=[
|
274 |
+
{"role": m["role"], "content": m["content"]}
|
275 |
+
for m in st.session_state.messages
|
276 |
+
],
|
277 |
+
stream=True,
|
278 |
+
)
|
279 |
+
response = st.write_stream(stream)
|
280 |
+
st.session_state.messages.append({"role": "assistant", "content": response})
|
281 |
+
except Exception as e:
|
282 |
+
st.error(f"Error generating response: {e}")
|
pages/tableau.py
ADDED
@@ -0,0 +1,18 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
|
2 |
+
import streamlit as st
|
3 |
+
|
4 |
+
st.set_page_config(
|
5 |
+
page_title="Narrativ 🧠",
|
6 |
+
layout="wide",
|
7 |
+
initial_sidebar_state="expanded",
|
8 |
+
page_icon="🧠",
|
9 |
+
)
|
10 |
+
|
11 |
+
from PIL import Image, ImageEnhance
|
12 |
+
|
13 |
+
st.title("Narrativ 📰")
|
14 |
+
image = Image.open('./data/tableau.png')
|
15 |
+
enhancer = ImageEnhance.Brightness(image)
|
16 |
+
darker_image = enhancer.enhance(0.5) # Adjust the brightness factor as needed
|
17 |
+
st.image(darker_image, use_container_width=True, output_format="PNG", clamp=True)
|
18 |
+
|