NeonSamurai commited on
Commit
a8533b8
·
verified ·
1 Parent(s): 3d16623

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +178 -63
app.py CHANGED
@@ -1,63 +1,178 @@
1
- import streamlit as st
2
-
3
- from getpass import getpass
4
- GOOGLE_API_KEY = getpass("AIzaSyCL5TCEbUCfidn-f6cMSa7Lb6P9IyyLGUw")
5
-
6
- st.title("ITC Financial Analyzer")
7
-
8
- st.text_area(placeholder="Enter your query...")
9
-
10
- # Calling a Gemini LLM
11
- from langchain_google_genai import ChatGoogleGenerativeAI
12
-
13
- llm = ChatGoogleGenerativeAI(api_key = GOOGLE_API_KEY, model = "gemini-2.0-flash-exp")
14
-
15
-
16
- # Chat Prompt Template with MessagesPlaceholder
17
- from langchain_core.prompts import ChatMessagePromptTemplate, MessagesPlaceholder
18
-
19
- chat_prompt = ChatPromptTemplate.from_messages([
20
- ("system",
21
- """You are a domain-specific AI financial analyst focused on company-level performance evaluation.
22
-
23
- Your task is to analyze and respond to user financial queries *strictly based on the provided transcript data*: {context}.
24
-
25
- *Rules:*
26
- 1. ONLY extract facts, figures, and insights that are explicitly available in the transcript.
27
- 2. If data is *missing or partially available*, clearly state: "The required data is not available in the current transcript." Then provide a generic but relevant explanation based on standard financial principles.
28
- 3. Maintain numerical accuracy and avoid interpretation beyond data boundaries.
29
- 4. Prioritize answers relevant to *ITC Ltd.*, but keep response format adaptable to other firms and fiscal years.
30
- 5. Clearly present year-wise or metric-wise insights using bullet points or structured formats if applicable.
31
-
32
- *Your goals:*
33
- - Ensure 100% fidelity to source transcript.
34
- - Do not assume or hallucinate missing numbers.
35
- - Use clear, reproducible reasoning steps (e.g., show which line items support your conclusion).
36
- - Output should be modular enough to scale across other companies and time periods.
37
-
38
- Respond only to this question from the user."""),
39
- MessagesPlaceholder(variable_name = "chat_history"),
40
-
41
- ("human", "{question}")
42
- ])
43
-
44
-
45
- # String Output Parser
46
- from langchain_core.output_parsers import StrOutputParser
47
- parser = StrOutputParser()
48
-
49
- # Introducing Memory using Runnables
50
- from langchain_core.runnables import RunnableLambda, RunnableParallel, RunnablePassthrough
51
-
52
- memory_dict = {"history" : []}
53
-
54
- def get_history(input):
55
- return memory_dict['history']
56
-
57
- runnable_memory = RunnableLambda(get_history)
58
-
59
-
60
- # Chaining with History
61
- chain = RunnablePassthrough.assign(chat_history = runnable_memory) |
62
-
63
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import streamlit as st
2
+ import zipfile
3
+
4
+ from sentence_transformers import SentenceTransformer
5
+ from langchain_community.embeddings import HuggingFaceEmbeddings
6
+ from langchain_community.vectorstores import Chroma
7
+
8
+ from langchain_google_genai import ChatGoogleGenerativeAI
9
+ from langchain.schema.runnable import RunnableLambda, RunnablePassthrough
10
+ from langchain.prompts.chat import ChatPromptTemplate, MessagesPlaceholder
11
+ from langchain_core.messages import HumanMessage, AIMessage
12
+ from langchain.schema.output_parser import StrOutputParser
13
+
14
+ import base64
15
+
16
+ st.set_page_config(page_title="ITC Financial Analysis with AI Scraping & LLM Integration", layout="centered")
17
+
18
+ def set_background(local_image_path):
19
+ with open(local_image_path, "rb") as image_file:
20
+ encoded_string = base64.b64encode(image_file.read()).decode()
21
+
22
+ bg_image_style = f"""
23
+ <style>
24
+ .stApp {{
25
+ background-image: url(data:image/{"png"};base64,{encoded_string});
26
+ background-size: cover;
27
+ background-repeat: no-repeat;
28
+ background-attachment: fixed;
29
+ }}
30
+ </style>
31
+ """
32
+ st.markdown(bg_image_style, unsafe_allow_html=True)
33
+
34
+ set_background(r"Images/bkg2.jpg")
35
+
36
+ # API key
37
+ API_key = "AIzaSyCoFe_UHz_9zQzmB1KQgFp2A3G7m3KCe20"
38
+
39
+
40
+ st.title("📊 ITC Financial Analysis with AI Scraping & LLM Integration")
41
+
42
+ # Memory buffer for chat history
43
+ memory_buffer = {"chat_history": []}
44
+
45
+ # Minimalistic and background-matching style for the End Chat button
46
+ end_chat_button = """
47
+ <style>
48
+ .stButton>button {
49
+ background-color: rgba(255, 255, 255, 0.3); /* Semi-transparent white */
50
+ color: white;
51
+ font-size: 16px;
52
+ border: 1px solid rgba(255, 255, 255, 0.5);
53
+ border-radius: 20px;
54
+ padding: 12px 24px;
55
+ cursor: pointer;
56
+ transition: background-color 0.3s ease, transform 0.2s ease;
57
+ }
58
+ .stButton>button:hover {
59
+ background-color: rgba(255, 255, 255, 0.6); /* Lighter on hover */
60
+ transform: scale(1.05); /* Subtle scaling effect */
61
+ }
62
+ .stButton>button:active {
63
+ transform: scale(0.98); /* Slight shrink on click */
64
+ }
65
+ </style>
66
+ """
67
+ st.markdown(end_chat_button, unsafe_allow_html=True)
68
+
69
+
70
+ # End chat button
71
+ if st.button("End Chat 🛑"):
72
+ memory_buffer["chat_history"] = []
73
+
74
+ # Load Chroma vector DB from zip
75
+ with zipfile.ZipFile('chroma_db_32_backup.zip', 'r') as zip_ref:
76
+ zip_ref.extractall('chroma_db')
77
+
78
+ # Embeddings and vector store
79
+ embedding = HuggingFaceEmbeddings(model_name='all-MiniLM-L6-v2')
80
+ vectorstore = Chroma(persist_directory='chroma_db', embedding_function=embedding)
81
+ mmr_retriever = vectorstore.as_retriever(search_type="mmr", search_kwargs={"k": 3, "lambda_mult": 1})
82
+
83
+ # Helper functions
84
+ def format_docs(docs):
85
+ return "\n\n".join(doc.page_content for doc in docs)
86
+
87
+ def get_docs_and_context(question):
88
+ docs = mmr_retriever.get_relevant_documents(question)
89
+ return {"question": question, "docs": docs, "context": format_docs(docs)}
90
+
91
+ # Chain parts
92
+ parallel_chain = RunnableLambda(lambda x: {
93
+ "question": x["input"],
94
+ **get_docs_and_context(x["input"])
95
+ })
96
+
97
+ chat_prompt = ChatPromptTemplate.from_messages([
98
+ ("system",
99
+ """
100
+ You are a domain-specific AI financial analyst focused on company-level performance evaluation.
101
+
102
+ Your task is to analyze and respond to user financial queries *strictly based on the provided transcript data*: {context}.
103
+
104
+ Rules:
105
+ 1. ONLY extract facts, figures, and insights that are explicitly available in the transcript.
106
+ 2. If data is *missing or partially available*, clearly state: "The required data is not available in the current transcript." Then provide a generic but relevant explanation based on standard financial principles.
107
+ 3. Maintain numerical accuracy and avoid interpretation beyond data boundaries.
108
+ 4. Prioritize answers relevant to *ITC Ltd.*, but keep response format adaptable to other firms and fiscal years.
109
+ 5. Clearly present year-wise or metric-wise insights using bullet points or structured formats if applicable.
110
+
111
+ Your goals:
112
+ - Ensure 100% fidelity to source transcript.
113
+ - Do not assume or hallucinate missing numbers.
114
+ - Use clear, reproducible reasoning steps (e.g., show which line items support your conclusion).
115
+ - Output should be modular enough to scale across other companies and time periods.
116
+
117
+ Respond only to this question from the user.
118
+ """),
119
+ MessagesPlaceholder(variable_name="chat_history", optional=True),
120
+ ("human", "{input}")
121
+ ])
122
+
123
+ llm = ChatGoogleGenerativeAI(api_key=API_key, model="gemini-2.0-flash-exp", temperature=1)
124
+ parser = StrOutputParser()
125
+
126
+ # Chat memory logic
127
+ def get_history_from_buffer(_):
128
+ return memory_buffer['chat_history']
129
+
130
+ runnable_get_history_from_buffer = RunnableLambda(get_history_from_buffer)
131
+
132
+ main_chain = (
133
+ parallel_chain |
134
+ RunnableLambda(lambda x: {
135
+ "llm_input": {"input": x["question"], "context": x["context"]},
136
+ "docs": x["docs"]
137
+ }) |
138
+ RunnableLambda(lambda x: {
139
+ "result": (chat_prompt | llm | parser).invoke(x["llm_input"]),
140
+ "source_documents": x["docs"]
141
+ })
142
+ )
143
+
144
+ chain = RunnablePassthrough.assign(chat_history=runnable_get_history_from_buffer) | main_chain
145
+
146
+ # Display previous chat messages
147
+ for msg in memory_buffer["chat_history"]:
148
+ role = "user" if isinstance(msg, HumanMessage) else "assistant"
149
+ with st.chat_message(role):
150
+ st.markdown(msg.content)
151
+
152
+ # Chat input
153
+ user_input = st.chat_input("Ask a question about ITC's financials...")
154
+
155
+ if user_input:
156
+ # Show user message
157
+ with st.chat_message("user"):
158
+ st.markdown(user_input)
159
+
160
+ # Add user input to memory
161
+ memory_buffer["chat_history"].append(HumanMessage(content=user_input))
162
+
163
+ # Call the chain
164
+ output = chain.invoke({"input": user_input})
165
+ ai_response = output["result"]
166
+
167
+ # Add AI response to memory
168
+ memory_buffer["chat_history"].append(AIMessage(content=ai_response))
169
+
170
+ # Show AI response
171
+ with st.chat_message("assistant"):
172
+ st.markdown(ai_response)
173
+
174
+ # Show sources
175
+ if output.get("source_documents"):
176
+ st.markdown("**Sources:**")
177
+ for doc in output["source_documents"]:
178
+ st.markdown(f"- {doc.metadata.get('source', 'Unknown document')}")