Spaces:
Sleeping
Sleeping
Code files added
Browse files- Finance-RAG/.gitattributes +2 -0
- Finance-RAG/.gitignore +160 -0
- Finance-RAG/.streamlit/secrets.toml +2 -0
- Finance-RAG/AI finance .xlsx +0 -0
- Finance-RAG/Home.py +82 -0
- Finance-RAG/Login.py +81 -0
- Finance-RAG/README.md +133 -0
- Finance-RAG/Test.ipynb +623 -0
- Finance-RAG/WhatsApp Chat with Jashan Cu.txt +0 -0
- Finance-RAG/app.py +953 -0
- Finance-RAG/artifacts/Chat.txt +0 -0
- Finance-RAG/artifacts/bm25_values.json +1 -0
- Finance-RAG/artifacts/client_secret_330901082226-f5jag2m50pripvslninfng7ej0c05kqd.apps.googleusercontent.com.json +1 -0
- Finance-RAG/artifacts/report.html +0 -0
- Finance-RAG/artifacts/sample_financial_analysis_data.xlsx +0 -0
- Finance-RAG/pages/Chat_With_Data.py +355 -0
- Finance-RAG/pages/Excel_Processing_And_Analysis.py +130 -0
- Finance-RAG/pages/NDA_Creation.py +189 -0
- Finance-RAG/pages/Upload_Chat.py +0 -0
- Finance-RAG/requirements.txt +30 -0
- Finance-RAG/sample_balance_sheet.xlsx +0 -0
- Finance-RAG/sample_financial_data.xlsx +0 -0
- Finance-RAG/setup.py +37 -0
- Finance-RAG/src/__init__.py +0 -0
- Finance-RAG/src/exception.py +41 -0
- Finance-RAG/src/logger.py +17 -0
Finance-RAG/.gitattributes
ADDED
@@ -0,0 +1,2 @@
|
|
|
|
|
|
|
1 |
+
# Auto detect text files and perform LF normalization
|
2 |
+
* text=auto
|
Finance-RAG/.gitignore
ADDED
@@ -0,0 +1,160 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# Byte-compiled / optimized / DLL files
|
2 |
+
__pycache__/
|
3 |
+
*.py[cod]
|
4 |
+
*$py.class
|
5 |
+
|
6 |
+
# C extensions
|
7 |
+
*.so
|
8 |
+
|
9 |
+
# Distribution / packaging
|
10 |
+
.Python
|
11 |
+
build/
|
12 |
+
develop-eggs/
|
13 |
+
dist/
|
14 |
+
downloads/
|
15 |
+
eggs/
|
16 |
+
.eggs/
|
17 |
+
lib/
|
18 |
+
lib64/
|
19 |
+
parts/
|
20 |
+
sdist/
|
21 |
+
var/
|
22 |
+
wheels/
|
23 |
+
share/python-wheels/
|
24 |
+
*.egg-info/
|
25 |
+
.installed.cfg
|
26 |
+
*.egg
|
27 |
+
MANIFEST
|
28 |
+
firebase_cred/
|
29 |
+
# PyInstaller
|
30 |
+
# Usually these files are written by a python script from a template
|
31 |
+
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
32 |
+
*.manifest
|
33 |
+
*.spec
|
34 |
+
|
35 |
+
# Installer logs
|
36 |
+
pip-log.txt
|
37 |
+
pip-delete-this-directory.txt
|
38 |
+
|
39 |
+
# Unit test / coverage reports
|
40 |
+
htmlcov/
|
41 |
+
.tox/
|
42 |
+
.nox/
|
43 |
+
.coverage
|
44 |
+
.coverage.*
|
45 |
+
.cache
|
46 |
+
nosetests.xml
|
47 |
+
coverage.xml
|
48 |
+
*.cover
|
49 |
+
*.py,cover
|
50 |
+
.hypothesis/
|
51 |
+
.pytest_cache/
|
52 |
+
cover/
|
53 |
+
|
54 |
+
# Translations
|
55 |
+
*.mo
|
56 |
+
*.pot
|
57 |
+
|
58 |
+
# Django stuff:
|
59 |
+
*.log
|
60 |
+
local_settings.py
|
61 |
+
db.sqlite3
|
62 |
+
db.sqlite3-journal
|
63 |
+
|
64 |
+
# Flask stuff:
|
65 |
+
instance/
|
66 |
+
.webassets-cache
|
67 |
+
|
68 |
+
# Scrapy stuff:
|
69 |
+
.scrapy
|
70 |
+
|
71 |
+
# Sphinx documentation
|
72 |
+
docs/_build/
|
73 |
+
|
74 |
+
# PyBuilder
|
75 |
+
.pybuilder/
|
76 |
+
target/
|
77 |
+
|
78 |
+
# Jupyter Notebook
|
79 |
+
.ipynb_checkpoints
|
80 |
+
|
81 |
+
# IPython
|
82 |
+
profile_default/
|
83 |
+
ipython_config.py
|
84 |
+
|
85 |
+
# pyenv
|
86 |
+
# For a library or package, you might want to ignore these files since the code is
|
87 |
+
# intended to run in multiple environments; otherwise, check them in:
|
88 |
+
# .python-version
|
89 |
+
|
90 |
+
# pipenv
|
91 |
+
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
|
92 |
+
# However, in case of collaboration, if having platform-specific dependencies or dependencies
|
93 |
+
# having no cross-platform support, pipenv may install dependencies that don't work, or not
|
94 |
+
# install all needed dependencies.
|
95 |
+
#Pipfile.lock
|
96 |
+
|
97 |
+
# poetry
|
98 |
+
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
|
99 |
+
# This is especially recommended for binary packages to ensure reproducibility, and is more
|
100 |
+
# commonly ignored for libraries.
|
101 |
+
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
|
102 |
+
#poetry.lock
|
103 |
+
|
104 |
+
# pdm
|
105 |
+
# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
|
106 |
+
#pdm.lock
|
107 |
+
# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
|
108 |
+
# in version control.
|
109 |
+
# https://pdm.fming.dev/#use-with-ide
|
110 |
+
.pdm.toml
|
111 |
+
|
112 |
+
# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
|
113 |
+
__pypackages__/
|
114 |
+
|
115 |
+
# Celery stuff
|
116 |
+
celerybeat-schedule
|
117 |
+
celerybeat.pid
|
118 |
+
|
119 |
+
# SageMath parsed files
|
120 |
+
*.sage.py
|
121 |
+
|
122 |
+
# Environments
|
123 |
+
.env
|
124 |
+
.venv
|
125 |
+
env/
|
126 |
+
venv/
|
127 |
+
ENV/
|
128 |
+
env.bak/
|
129 |
+
venv.bak/
|
130 |
+
|
131 |
+
# Spyder project settings
|
132 |
+
.spyderproject
|
133 |
+
.spyproject
|
134 |
+
|
135 |
+
# Rope project settings
|
136 |
+
.ropeproject
|
137 |
+
|
138 |
+
# mkdocs documentation
|
139 |
+
/site
|
140 |
+
|
141 |
+
# mypy
|
142 |
+
.mypy_cache/
|
143 |
+
.dmypy.json
|
144 |
+
dmypy.json
|
145 |
+
|
146 |
+
# Pyre type checker
|
147 |
+
.pyre/
|
148 |
+
|
149 |
+
# pytype static type analyzer
|
150 |
+
.pytype/
|
151 |
+
|
152 |
+
# Cython debug symbols
|
153 |
+
cython_debug/
|
154 |
+
|
155 |
+
# PyCharm
|
156 |
+
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
|
157 |
+
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
|
158 |
+
# and can be added to the global gitignore or merged into this file. For a more nuclear
|
159 |
+
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
|
160 |
+
#.idea/
|
Finance-RAG/.streamlit/secrets.toml
ADDED
@@ -0,0 +1,2 @@
|
|
|
|
|
|
|
1 |
+
client_id="330901082226-f5jag2m50pripvslninfng7ej0c05kqd.apps.googleusercontent.com"
|
2 |
+
client_secret="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"
|
Finance-RAG/AI finance .xlsx
ADDED
Binary file (73.8 kB). View file
|
|
Finance-RAG/Home.py
ADDED
@@ -0,0 +1,82 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import streamlit as st
|
2 |
+
import firebase_admin
|
3 |
+
from firebase_admin import auth, exceptions, credentials, initialize_app
|
4 |
+
import asyncio
|
5 |
+
from httpx_oauth.clients.google import GoogleOAuth2
|
6 |
+
|
7 |
+
|
8 |
+
# Initialize Firebase app
|
9 |
+
cred = credentials.Certificate(r"firebase_cred\fin-rag-firebase-adminsdk-un38r-81d28e871c.json")
|
10 |
+
try:
|
11 |
+
firebase_admin.get_app()
|
12 |
+
except ValueError as e:
|
13 |
+
initialize_app(cred)
|
14 |
+
|
15 |
+
# Initialize Google OAuth2 client
|
16 |
+
client_id = st.secrets["client_id"]
|
17 |
+
client_secret = st.secrets["client_secret"]
|
18 |
+
redirect_url = "http://localhost:8501/" # Your redirect URL
|
19 |
+
|
20 |
+
client = GoogleOAuth2(client_id=client_id, client_secret=client_secret)
|
21 |
+
|
22 |
+
|
23 |
+
st.session_state.email = ''
|
24 |
+
|
25 |
+
|
26 |
+
|
27 |
+
async def get_access_token(client: GoogleOAuth2, redirect_url: str, code: str):
|
28 |
+
return await client.get_access_token(code, redirect_url)
|
29 |
+
|
30 |
+
async def get_email(client: GoogleOAuth2, token: str):
|
31 |
+
user_id, user_email = await client.get_id_email(token)
|
32 |
+
return user_id, user_email
|
33 |
+
|
34 |
+
def get_logged_in_user_email():
|
35 |
+
try:
|
36 |
+
query_params = st.query_params
|
37 |
+
code = query_params.get('code')
|
38 |
+
if code:
|
39 |
+
token = asyncio.run(get_access_token(client, redirect_url, code))
|
40 |
+
st.experimental_set_query_params()
|
41 |
+
|
42 |
+
if token:
|
43 |
+
user_id, user_email = asyncio.run(get_email(client, token['access_token']))
|
44 |
+
if user_email:
|
45 |
+
try:
|
46 |
+
user = auth.get_user_by_email(user_email)
|
47 |
+
except exceptions.FirebaseError:
|
48 |
+
user = auth.create_user(email=user_email)
|
49 |
+
st.session_state.email = user.email
|
50 |
+
return user.email
|
51 |
+
return None
|
52 |
+
except:
|
53 |
+
pass
|
54 |
+
|
55 |
+
|
56 |
+
def show_login_button():
|
57 |
+
authorization_url = asyncio.run(client.get_authorization_url(
|
58 |
+
redirect_url,
|
59 |
+
scope=["email", "profile"],
|
60 |
+
extras_params={"access_type": "offline"},
|
61 |
+
))
|
62 |
+
st.markdown(f'<a href="{authorization_url}" target="_self">Login</a>', unsafe_allow_html=True)
|
63 |
+
get_logged_in_user_email()
|
64 |
+
|
65 |
+
|
66 |
+
|
67 |
+
|
68 |
+
def app():
|
69 |
+
st.title('Welcome!')
|
70 |
+
if not st.session_state.email:
|
71 |
+
get_logged_in_user_email()
|
72 |
+
if not st.session_state.email:
|
73 |
+
|
74 |
+
show_login_button()
|
75 |
+
|
76 |
+
if st.session_state.email:
|
77 |
+
st.write(st.session_state.email)
|
78 |
+
if st.button("Logout", type="primary", key="logout_non_required"):
|
79 |
+
st.session_state.email = ''
|
80 |
+
st.rerun()
|
81 |
+
|
82 |
+
app()
|
Finance-RAG/Login.py
ADDED
@@ -0,0 +1,81 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import streamlit as st
|
2 |
+
import firebase_admin
|
3 |
+
from firebase_admin import auth, exceptions, credentials, initialize_app
|
4 |
+
import asyncio
|
5 |
+
from httpx_oauth.clients.google import GoogleOAuth2
|
6 |
+
|
7 |
+
|
8 |
+
# Initialize Firebase app
|
9 |
+
cred = credentials.Certificate(r"artifacts\client_secret_330901082226-f5jag2m50pripvslninfng7ej0c05kqd.apps.googleusercontent.com.json")
|
10 |
+
firebase_admin.get_app()
|
11 |
+
except ValueError as e:
|
12 |
+
initialize_app(cred)
|
13 |
+
|
14 |
+
# Initialize Google OAuth2 client
|
15 |
+
client_id = st.secrets["client_id"]
|
16 |
+
client_secret = st.secrets["client_secret"]
|
17 |
+
redirect_url = "http://localhost:8501/" # Your redirect URL
|
18 |
+
|
19 |
+
client = GoogleOAuth2(client_id=client_id, client_secret=client_secret)
|
20 |
+
|
21 |
+
|
22 |
+
st.session_state.email = ''
|
23 |
+
|
24 |
+
|
25 |
+
|
26 |
+
async def get_access_token(client: GoogleOAuth2, redirect_url: str, code: str):
|
27 |
+
return await client.get_access_token(code, redirect_url)
|
28 |
+
|
29 |
+
async def get_email(client: GoogleOAuth2, token: str):
|
30 |
+
user_id, user_email = await client.get_id_email(token)
|
31 |
+
return user_id, user_email
|
32 |
+
|
33 |
+
def get_logged_in_user_email():
|
34 |
+
try:
|
35 |
+
query_params = st.query_params
|
36 |
+
code = query_params.get('code')
|
37 |
+
if code:
|
38 |
+
token = asyncio.run(get_access_token(client, redirect_url, code))
|
39 |
+
st.experimental_set_query_params()
|
40 |
+
|
41 |
+
if token:
|
42 |
+
user_id, user_email = asyncio.run(get_email(client, token['access_token']))
|
43 |
+
if user_email:
|
44 |
+
try:
|
45 |
+
user = auth.get_user_by_email(user_email)
|
46 |
+
except exceptions.FirebaseError:
|
47 |
+
user = auth.create_user(email=user_email)
|
48 |
+
st.session_state.email = user.email
|
49 |
+
return user.email
|
50 |
+
return None
|
51 |
+
except:
|
52 |
+
pass
|
53 |
+
|
54 |
+
|
55 |
+
def show_login_button():
|
56 |
+
authorization_url = asyncio.run(client.get_authorization_url(
|
57 |
+
redirect_url,
|
58 |
+
scope=["email", "profile"],
|
59 |
+
extras_params={"access_type": "offline"},
|
60 |
+
))
|
61 |
+
st.markdown(f'<a href="{authorization_url}" target="_self">Login</a>', unsafe_allow_html=True)
|
62 |
+
get_logged_in_user_email()
|
63 |
+
|
64 |
+
|
65 |
+
|
66 |
+
|
67 |
+
def app():
|
68 |
+
st.title('Welcome!')
|
69 |
+
if not st.session_state.email:
|
70 |
+
get_logged_in_user_email()
|
71 |
+
if not st.session_state.email:
|
72 |
+
|
73 |
+
show_login_button()
|
74 |
+
|
75 |
+
if st.session_state.email:
|
76 |
+
st.write(st.session_state.email)
|
77 |
+
if st.button("Logout", type="primary", key="logout_non_required"):
|
78 |
+
st.session_state.email = ''
|
79 |
+
st.rerun()
|
80 |
+
|
81 |
+
app()
|
Finance-RAG/README.md
ADDED
@@ -0,0 +1,133 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
title: FinRAG
|
2 |
+
emoji: 🤖
|
3 |
+
colorFrom: blue
|
4 |
+
colorTo: gray
|
5 |
+
sdk: streamlit
|
6 |
+
sdk_version: 1.39.0
|
7 |
+
app_file: Home.py
|
8 |
+
pinned: false
|
9 |
+
license: mit
|
10 |
+
|
11 |
+
# Finance-RAG
|
12 |
+
|
13 |
+
This project is designed to help users streamline various business processes such as authentication, data extraction, automation, analysis, and reporting using cutting-edge technologies like Claude and OpenAI, integrated with APIs and other services. The repository contains all the code and instructions you need to get started with the platform.
|
14 |
+
|
15 |
+
<a name="readme-top"></a>
|
16 |
+
|
17 |
+
<!-- TABLE OF CONTENTS -->
|
18 |
+
<details>
|
19 |
+
<summary>Table of Contents</summary>
|
20 |
+
<ol>
|
21 |
+
<li><a href="#about-the-project">About The Project</a></li>
|
22 |
+
<li><a href="#core-objectives">Core Objectives</a></li>
|
23 |
+
<li><a href="#additional-features">Additional Features</a></li>
|
24 |
+
<li><a href="#built-with">Built With</a></li>
|
25 |
+
<li>
|
26 |
+
<a href="#getting-started">Getting Started</a>
|
27 |
+
<ul>
|
28 |
+
<li><a href="#prerequisites">Prerequisites</a></li>
|
29 |
+
<li><a href="#installation">Installation</a></li>
|
30 |
+
</ul>
|
31 |
+
</li>
|
32 |
+
<li><a href="#contributing">Contributing</a></li>
|
33 |
+
<li><a href="#license">License</a></li>
|
34 |
+
<li><a href="#contact">Contact</a></li>
|
35 |
+
<li><a href="#acknowledgments">Acknowledgments</a></li>
|
36 |
+
</ol>
|
37 |
+
</details>
|
38 |
+
|
39 |
+
<!-- ABOUT THE PROJECT -->
|
40 |
+
## About The Project
|
41 |
+
The **Advanced Data Processing & Analysis Platform** is an all-in-one solution for handling various data operations such as login authentication, data extraction, document automation, and financial reporting. With the ability to integrate external APIs and perform advanced data summarization, this platform is perfect for businesses looking to enhance productivity with minimal user input. The project leverages modern machine learning techniques and offers customizable options for end-users.
|
42 |
+
|
43 |
+
<!-- CORE OBJECTIVES -->
|
44 |
+
## Core Objectives
|
45 |
+
- **Authentication**: Implement login options using Google and LinkedIn.
|
46 |
+
- **Data Storage**: Utilize Google Drive for securely storing login information.
|
47 |
+
- **API Integration**: Fetch and process data from external APIs.
|
48 |
+
- **Customization**: Allow users to modify headings and provide custom explanations.
|
49 |
+
- **Automation**: Automatically generate NDAs and other types of agreements.
|
50 |
+
- **Single-Formula Creation**: Enable users to start new projects with a single formula.
|
51 |
+
- **Data Extraction**: Extract and summarize data from WhatsApp chats, YouTube, and other sources.
|
52 |
+
- **Claude Integration**: Integrate Claude as an alternative to OCR and OpenAI for document processing.
|
53 |
+
- **Data Summarization**: Provide options to summarize PDF data and download it in various formats (CSV, XML).
|
54 |
+
- **Analysis**: Perform detailed calculations and generate dynamic graphs.
|
55 |
+
- **Financial Reporting**: Automatically generate downloadable P&L statements, sales reports, and balance sheets.
|
56 |
+
|
57 |
+
<!-- ADDITIONAL FEATURES -->
|
58 |
+
## Additional Features
|
59 |
+
- **Chunking**: A new chunking technique for improved content retrieval and better coherence.
|
60 |
+
- **Hybrid Search**: Leverage hybrid search instead of semantic search to enhance factual accuracy.
|
61 |
+
- **WhatsApp Chat Module**: Input WhatsApp chat text files (including emoji encoding) for processing and analysis.
|
62 |
+
- **Pre-Calculated Entities**: Pre-calculated sales, balance sheet, and P&L data with accompanying graphs.
|
63 |
+
- **PDF Parsing**: Use a high-performance PDF parsing algorithm to handle complex tabular data.
|
64 |
+
- **Streamlit UI**: Updated UI using Streamlit for easier navigation and a seamless user experience.
|
65 |
+
- **Industry-Level Code**: Well-documented, scalable code adhering to industry-standard practices for future development.
|
66 |
+
|
67 |
+
<!-- BUILT WITH -->
|
68 |
+
## Built With
|
69 |
+
This project was developed using the following programming languages and frameworks:
|
70 |
+
- **Programming Language**: Python
|
71 |
+
- **Libraries & Tools**:
|
72 |
+
- PyTorch
|
73 |
+
- Transformers
|
74 |
+
- Streamlit
|
75 |
+
- Claude API
|
76 |
+
- OpenAI API
|
77 |
+
- Google Drive API
|
78 |
+
- Hybrid Search Techniques
|
79 |
+
- PDF Parsing Libraries
|
80 |
+
- Financial Data Visualization Libraries
|
81 |
+
|
82 |
+
<!-- GETTING STARTED -->
|
83 |
+
## Getting Started
|
84 |
+
Follow the instructions below to set up and run the project on your local machine.
|
85 |
+
|
86 |
+
### Prerequisites
|
87 |
+
- Python 3.8+
|
88 |
+
- Google API credentials for Drive integration
|
89 |
+
- Streamlit for UI
|
90 |
+
- Claude and OpenAI API keys
|
91 |
+
- Required Python libraries (see requirements.txt)
|
92 |
+
|
93 |
+
### Installation
|
94 |
+
1. Clone the repo:
|
95 |
+
```bash
|
96 |
+
git clone https://github.com/your-username/advanced-data-platform.git
|
97 |
+
```
|
98 |
+
2. Navigate to the project directory:
|
99 |
+
```bash
|
100 |
+
cd advanced-data-platform
|
101 |
+
```
|
102 |
+
3. Install required dependencies:
|
103 |
+
```bash
|
104 |
+
pip install -r requirements.txt
|
105 |
+
```
|
106 |
+
4. Run the application:
|
107 |
+
```bash
|
108 |
+
streamlit run app.py
|
109 |
+
```
|
110 |
+
|
111 |
+
<!-- CONTRIBUTING -->
|
112 |
+
## Contributing
|
113 |
+
We welcome contributions to improve the platform. For now this is a private project.
|
114 |
+
|
115 |
+
<!-- LICENSE -->
|
116 |
+
## License
|
117 |
+
Distributed under the MIT License. See `LICENSE.txt` for more information.
|
118 |
+
|
119 |
+
<!-- CONTACT -->
|
120 |
+
## Contact
|
121 |
+
For further inquiries, reach out via:
|
122 |
+
- **Email**: 686jashan@gmail.com
|
123 |
+
- **LinkedIn**: https://www.linkedin.com/in/jashan-preet-singh-badwal/
|
124 |
+
|
125 |
+
<!-- ACKNOWLEDGMENTS -->
|
126 |
+
## Acknowledgments
|
127 |
+
A special thanks to all the libraries and APIs that made this project possible:
|
128 |
+
- Streamlit
|
129 |
+
- PyTorch
|
130 |
+
- Claude AI
|
131 |
+
- OpenAI
|
132 |
+
- Google Drive API
|
133 |
+
- https://youtu.be/7DStwsEj7rA?si=Mpb1DgwWPVvnjtsJ
|
Finance-RAG/Test.ipynb
ADDED
@@ -0,0 +1,623 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
{
|
2 |
+
"cells": [
|
3 |
+
{
|
4 |
+
"cell_type": "code",
|
5 |
+
"execution_count": 1,
|
6 |
+
"metadata": {},
|
7 |
+
"outputs": [],
|
8 |
+
"source": [
|
9 |
+
"from dotenv import load_dotenv\n",
|
10 |
+
"import os\n",
|
11 |
+
"import pandas as pd\n",
|
12 |
+
"load_dotenv()\n",
|
13 |
+
"\n",
|
14 |
+
"from openai import OpenAI\n",
|
15 |
+
"from langchain_community.retrievers import PineconeHybridSearchRetriever\n",
|
16 |
+
"client = OpenAI(api_key=os.getenv('OPENAI_API_KEY'))\n",
|
17 |
+
"vd_api_key = os.environ[\"PINECONE_API_KEY\"]"
|
18 |
+
]
|
19 |
+
},
|
20 |
+
{
|
21 |
+
"cell_type": "code",
|
22 |
+
"execution_count": 4,
|
23 |
+
"metadata": {},
|
24 |
+
"outputs": [
|
25 |
+
{
|
26 |
+
"data": {
|
27 |
+
"text/html": [
|
28 |
+
"<div>\n",
|
29 |
+
"<style scoped>\n",
|
30 |
+
" .dataframe tbody tr th:only-of-type {\n",
|
31 |
+
" vertical-align: middle;\n",
|
32 |
+
" }\n",
|
33 |
+
"\n",
|
34 |
+
" .dataframe tbody tr th {\n",
|
35 |
+
" vertical-align: top;\n",
|
36 |
+
" }\n",
|
37 |
+
"\n",
|
38 |
+
" .dataframe thead th {\n",
|
39 |
+
" text-align: right;\n",
|
40 |
+
" }\n",
|
41 |
+
"</style>\n",
|
42 |
+
"<table border=\"1\" class=\"dataframe\">\n",
|
43 |
+
" <thead>\n",
|
44 |
+
" <tr style=\"text-align: right;\">\n",
|
45 |
+
" <th></th>\n",
|
46 |
+
" <th>Entry ID</th>\n",
|
47 |
+
" <th>Type</th>\n",
|
48 |
+
" <th>Description</th>\n",
|
49 |
+
" <th>Value</th>\n",
|
50 |
+
" <th>Date</th>\n",
|
51 |
+
" </tr>\n",
|
52 |
+
" </thead>\n",
|
53 |
+
" <tbody>\n",
|
54 |
+
" <tr>\n",
|
55 |
+
" <th>0</th>\n",
|
56 |
+
" <td>BS-00001</td>\n",
|
57 |
+
" <td>Asset</td>\n",
|
58 |
+
" <td>Inventory</td>\n",
|
59 |
+
" <td>57678.09</td>\n",
|
60 |
+
" <td>2023-10-14</td>\n",
|
61 |
+
" </tr>\n",
|
62 |
+
" <tr>\n",
|
63 |
+
" <th>1</th>\n",
|
64 |
+
" <td>BS-00002</td>\n",
|
65 |
+
" <td>Asset</td>\n",
|
66 |
+
" <td>Loan</td>\n",
|
67 |
+
" <td>76072.69</td>\n",
|
68 |
+
" <td>2023-03-09</td>\n",
|
69 |
+
" </tr>\n",
|
70 |
+
" <tr>\n",
|
71 |
+
" <th>2</th>\n",
|
72 |
+
" <td>BS-00003</td>\n",
|
73 |
+
" <td>Asset</td>\n",
|
74 |
+
" <td>Cash</td>\n",
|
75 |
+
" <td>21014.60</td>\n",
|
76 |
+
" <td>2023-08-07</td>\n",
|
77 |
+
" </tr>\n",
|
78 |
+
" <tr>\n",
|
79 |
+
" <th>3</th>\n",
|
80 |
+
" <td>BS-00004</td>\n",
|
81 |
+
" <td>Liability</td>\n",
|
82 |
+
" <td>Accounts Receivable</td>\n",
|
83 |
+
" <td>62154.55</td>\n",
|
84 |
+
" <td>2023-03-06</td>\n",
|
85 |
+
" </tr>\n",
|
86 |
+
" <tr>\n",
|
87 |
+
" <th>4</th>\n",
|
88 |
+
" <td>BS-00005</td>\n",
|
89 |
+
" <td>Liability</td>\n",
|
90 |
+
" <td>Inventory</td>\n",
|
91 |
+
" <td>50103.60</td>\n",
|
92 |
+
" <td>2023-04-13</td>\n",
|
93 |
+
" </tr>\n",
|
94 |
+
" </tbody>\n",
|
95 |
+
"</table>\n",
|
96 |
+
"</div>"
|
97 |
+
],
|
98 |
+
"text/plain": [
|
99 |
+
" Entry ID Type Description Value Date\n",
|
100 |
+
"0 BS-00001 Asset Inventory 57678.09 2023-10-14\n",
|
101 |
+
"1 BS-00002 Asset Loan 76072.69 2023-03-09\n",
|
102 |
+
"2 BS-00003 Asset Cash 21014.60 2023-08-07\n",
|
103 |
+
"3 BS-00004 Liability Accounts Receivable 62154.55 2023-03-06\n",
|
104 |
+
"4 BS-00005 Liability Inventory 50103.60 2023-04-13"
|
105 |
+
]
|
106 |
+
},
|
107 |
+
"execution_count": 4,
|
108 |
+
"metadata": {},
|
109 |
+
"output_type": "execute_result"
|
110 |
+
}
|
111 |
+
],
|
112 |
+
"source": [
|
113 |
+
"df = pd.read_excel(r\"sample_balance_sheet.xlsx\")\n",
|
114 |
+
"df.head(5)"
|
115 |
+
]
|
116 |
+
},
|
117 |
+
{
|
118 |
+
"cell_type": "code",
|
119 |
+
"execution_count": 8,
|
120 |
+
"metadata": {},
|
121 |
+
"outputs": [],
|
122 |
+
"source": [
|
123 |
+
"data = df.to_dict()\n"
|
124 |
+
]
|
125 |
+
},
|
126 |
+
{
|
127 |
+
"cell_type": "code",
|
128 |
+
"execution_count": 9,
|
129 |
+
"metadata": {},
|
130 |
+
"outputs": [],
|
131 |
+
"source": [
|
132 |
+
"def analyze_file(data_dict):\n",
|
133 |
+
" \"\"\"\n",
|
134 |
+
" This function takes a dictionary representation of a file and analyzes it thoroughly to provide a comprehensive analysis.\n",
|
135 |
+
" It uses the OpenAI API to generate a response that includes mathematical calculations, text answers, and graphical representations.\n",
|
136 |
+
" The analysis covers all aspects of the file, providing insights and visualizations to facilitate a deeper understanding of the data.\n",
|
137 |
+
"\n",
|
138 |
+
" Args:\n",
|
139 |
+
" data_dict (dict): The dictionary representation of the file to be analyzed.\n",
|
140 |
+
"\n",
|
141 |
+
" Returns:\n",
|
142 |
+
" str: The comprehensive analysis of the file, including mathematical calculations, text answers, and graphical representations.\n",
|
143 |
+
" \"\"\"\n",
|
144 |
+
"\n",
|
145 |
+
" # Define the prompt template for file analysis\n",
|
146 |
+
" prompt_template = f\"\"\"\n",
|
147 |
+
" ### Task Description:\n",
|
148 |
+
" You are an advanced data analyst tasked with performing a comprehensive analysis of a file represented as a dictionary.\n",
|
149 |
+
" Your task is to thoroughly analyze the file, providing insights through mathematical calculations, text answers, and graphical representations.\n",
|
150 |
+
" Ensure that your analysis covers all aspects of the file, offering a detailed understanding of the data.\n",
|
151 |
+
"\n",
|
152 |
+
" ### Instructions:\n",
|
153 |
+
" 1. Analyze the provided dictionary representation of the file.\n",
|
154 |
+
" 2. Perform mathematical calculations to extract meaningful insights from the data.\n",
|
155 |
+
" 3. Provide text answers to questions that can be derived from the analysis.\n",
|
156 |
+
" 4. Include graphical representations to visualize the data and facilitate understanding.\n",
|
157 |
+
"\n",
|
158 |
+
" ### Input:\n",
|
159 |
+
" File Data: {data_dict}\n",
|
160 |
+
"\n",
|
161 |
+
" ### Output:\n",
|
162 |
+
" Analysis:\n",
|
163 |
+
" \"\"\"\n",
|
164 |
+
"\n",
|
165 |
+
" # Call the OpenAI API to generate the response based on context and file data\n",
|
166 |
+
" response = client.chat.completions.create(\n",
|
167 |
+
" model=\"gpt-4o-mini\", # Replace this with the actual model if needed\n",
|
168 |
+
" messages=[\n",
|
169 |
+
" {\"role\": \"system\", \"content\": \"You are a helpful assistant.\"},\n",
|
170 |
+
" {\"role\": \"user\", \"content\": prompt_template}\n",
|
171 |
+
" ],\n",
|
172 |
+
" temperature=0.7,\n",
|
173 |
+
" top_p=1,\n",
|
174 |
+
" n=1\n",
|
175 |
+
" )\n",
|
176 |
+
" \n",
|
177 |
+
" # Extract the comprehensive analysis from the response\n",
|
178 |
+
" comprehensive_analysis = response.choices[0].message.content.strip()\n",
|
179 |
+
" return comprehensive_analysis"
|
180 |
+
]
|
181 |
+
},
|
182 |
+
{
|
183 |
+
"cell_type": "code",
|
184 |
+
"execution_count": null,
|
185 |
+
"metadata": {},
|
186 |
+
"outputs": [],
|
187 |
+
"source": []
|
188 |
+
},
|
189 |
+
{
|
190 |
+
"cell_type": "code",
|
191 |
+
"execution_count": 2,
|
192 |
+
"metadata": {},
|
193 |
+
"outputs": [
|
194 |
+
{
|
195 |
+
"name": "stderr",
|
196 |
+
"output_type": "stream",
|
197 |
+
"text": [
|
198 |
+
"c:\\Users\\yuvraj.s_maxval\\Desktop\\F_Projects\\Finance-RAG\\.venv\\Lib\\site-packages\\pinecone\\data\\index.py:1: TqdmWarning: IProgress not found. Please update jupyter and ipywidgets. See https://ipywidgets.readthedocs.io/en/stable/user_install.html\n",
|
199 |
+
" from tqdm.autonotebook import tqdm\n"
|
200 |
+
]
|
201 |
+
}
|
202 |
+
],
|
203 |
+
"source": [
|
204 |
+
"from pinecone import Pinecone, ServerlessSpec"
|
205 |
+
]
|
206 |
+
},
|
207 |
+
{
|
208 |
+
"cell_type": "code",
|
209 |
+
"execution_count": 25,
|
210 |
+
"metadata": {},
|
211 |
+
"outputs": [
|
212 |
+
{
|
213 |
+
"name": "stdout",
|
214 |
+
"output_type": "stream",
|
215 |
+
"text": [
|
216 |
+
"Creating\n"
|
217 |
+
]
|
218 |
+
}
|
219 |
+
],
|
220 |
+
"source": [
|
221 |
+
"index_name = \"testing\"\n",
|
222 |
+
"\n",
|
223 |
+
"# initialize Pinecone client\n",
|
224 |
+
"pc = Pinecone(api_key=vd_api_key)\n",
|
225 |
+
"\n",
|
226 |
+
"# create the index\n",
|
227 |
+
"if index_name not in pc.list_indexes().names():\n",
|
228 |
+
" print(\"Creating\")\n",
|
229 |
+
" pc.create_index(\n",
|
230 |
+
" name=index_name,\n",
|
231 |
+
" dimension=1536, # dimensionality of dense model\n",
|
232 |
+
" metric=\"dotproduct\", # sparse values supported only for dotproduct\n",
|
233 |
+
" spec=ServerlessSpec(cloud=\"aws\", region=\"us-east-1\"),\n",
|
234 |
+
" )"
|
235 |
+
]
|
236 |
+
},
|
237 |
+
{
|
238 |
+
"cell_type": "code",
|
239 |
+
"execution_count": 26,
|
240 |
+
"metadata": {},
|
241 |
+
"outputs": [],
|
242 |
+
"source": [
|
243 |
+
"index = pc.Index(index_name)"
|
244 |
+
]
|
245 |
+
},
|
246 |
+
{
|
247 |
+
"cell_type": "code",
|
248 |
+
"execution_count": 10,
|
249 |
+
"metadata": {},
|
250 |
+
"outputs": [],
|
251 |
+
"source": [
|
252 |
+
"from langchain_openai import OpenAIEmbeddings\n",
|
253 |
+
"\n",
|
254 |
+
"embeddings = OpenAIEmbeddings()"
|
255 |
+
]
|
256 |
+
},
|
257 |
+
{
|
258 |
+
"cell_type": "code",
|
259 |
+
"execution_count": 27,
|
260 |
+
"metadata": {},
|
261 |
+
"outputs": [],
|
262 |
+
"source": [
|
263 |
+
"from pinecone_text.sparse import BM25Encoder\n",
|
264 |
+
"\n",
|
265 |
+
"# or from pinecone_text.sparse import SpladeEncoder if you wish to work with SPLADE\n",
|
266 |
+
"\n",
|
267 |
+
"# use default tf-idf values\n",
|
268 |
+
"bm25_encoder = BM25Encoder().default()"
|
269 |
+
]
|
270 |
+
},
|
271 |
+
{
|
272 |
+
"cell_type": "code",
|
273 |
+
"execution_count": 28,
|
274 |
+
"metadata": {},
|
275 |
+
"outputs": [],
|
276 |
+
"source": [
|
277 |
+
"corpus = [\n",
|
278 |
+
" \"AIML Developer Intern\",\n",
|
279 |
+
" \"Remote\",\n",
|
280 |
+
" \"– Implemented YOLO V8 for Indian road traffic management, achieving a 8% improvement in vehicle number plate detection accuracy, thus increasing fine collections by 25%\",\n",
|
281 |
+
" \"Projects\",\n",
|
282 |
+
" \"• InterviewX (AI Tutor)\",\n",
|
283 |
+
" \"Developed an AI tutor app using GenAI, computer vision, NLP, and ML to boost job market success rates by 38%\",\n",
|
284 |
+
" \"Link.\",\n",
|
285 |
+
" \"– Engineered an AI-driven interview preparation application leveraging generative AI, large language models (LLM), and advanced machine learning models. Key functionalities include fake job posting detection (F1 score: 0.86), resume-content similarity analysis, posture evaluation through video analysis, text summarization module, and Omnichat retrieval-augmented generation with PDF and YouTube videos.\",\n",
|
286 |
+
" \"– Introduced personalized interview question generation and comprehensive posture analysis feedback, leveraging a high MAP value of 0.916; optimized resumes with detailed preparation, leading to a 10% improvement in interview success rates.\"\n",
|
287 |
+
"]"
|
288 |
+
]
|
289 |
+
},
|
290 |
+
{
|
291 |
+
"cell_type": "code",
|
292 |
+
"execution_count": 29,
|
293 |
+
"metadata": {},
|
294 |
+
"outputs": [
|
295 |
+
{
|
296 |
+
"name": "stderr",
|
297 |
+
"output_type": "stream",
|
298 |
+
"text": [
|
299 |
+
"100%|██████████| 9/9 [00:00<00:00, 2284.48it/s]\n"
|
300 |
+
]
|
301 |
+
}
|
302 |
+
],
|
303 |
+
"source": [
|
304 |
+
"# corpus = [\"foo\", \"bar\", \"world\", \"hello\"]\n",
|
305 |
+
"\n",
|
306 |
+
"# fit tf-idf values on your corpus\n",
|
307 |
+
"bm25_encoder.fit(corpus)\n",
|
308 |
+
"\n",
|
309 |
+
"# store the values to a json file\n",
|
310 |
+
"bm25_encoder.dump(\"bm25_values.json\")\n",
|
311 |
+
"\n",
|
312 |
+
"# load to your BM25Encoder object\n",
|
313 |
+
"bm25_encoder = BM25Encoder().load(\"bm25_values.json\")"
|
314 |
+
]
|
315 |
+
},
|
316 |
+
{
|
317 |
+
"cell_type": "code",
|
318 |
+
"execution_count": 31,
|
319 |
+
"metadata": {},
|
320 |
+
"outputs": [],
|
321 |
+
"source": [
|
322 |
+
"retriever = PineconeHybridSearchRetriever(\n",
|
323 |
+
" embeddings=embeddings, sparse_encoder=bm25_encoder, index=index\n",
|
324 |
+
")"
|
325 |
+
]
|
326 |
+
},
|
327 |
+
{
|
328 |
+
"cell_type": "code",
|
329 |
+
"execution_count": 32,
|
330 |
+
"metadata": {},
|
331 |
+
"outputs": [
|
332 |
+
{
|
333 |
+
"name": "stderr",
|
334 |
+
"output_type": "stream",
|
335 |
+
"text": [
|
336 |
+
"100%|██████████| 1/1 [00:05<00:00, 5.43s/it]\n"
|
337 |
+
]
|
338 |
+
}
|
339 |
+
],
|
340 |
+
"source": [
|
341 |
+
"retriever.add_texts(corpus)"
|
342 |
+
]
|
343 |
+
},
|
344 |
+
{
|
345 |
+
"cell_type": "code",
|
346 |
+
"execution_count": 33,
|
347 |
+
"metadata": {},
|
348 |
+
"outputs": [],
|
349 |
+
"source": [
|
350 |
+
"result = retriever.invoke(\"Give me information about personalized interview thing\")"
|
351 |
+
]
|
352 |
+
},
|
353 |
+
{
|
354 |
+
"cell_type": "code",
|
355 |
+
"execution_count": 34,
|
356 |
+
"metadata": {},
|
357 |
+
"outputs": [
|
358 |
+
{
|
359 |
+
"data": {
|
360 |
+
"text/plain": [
|
361 |
+
"[Document(metadata={'score': 0.483713746}, page_content='– Introduced personalized interview question generation and comprehensive posture analysis feedback, leveraging a high MAP value of 0.916; optimized resumes with detailed preparation, leading to a 10% improvement in interview success rates.'),\n",
|
362 |
+
" Document(metadata={'score': 0.416778952}, page_content='– Engineered an AI-driven interview preparation application leveraging generative AI, large language models (LLM), and advanced machine learning models. Key functionalities include fake job posting detection (F1 score: 0.86), resume-content similarity analysis, posture evaluation through video analysis, text summarization module, and Omnichat retrieval-augmented generation with PDF and YouTube videos.'),\n",
|
363 |
+
" Document(metadata={'score': 0.39953351}, page_content='• InterviewX (AI Tutor)'),\n",
|
364 |
+
" Document(metadata={'score': 0.383933604}, page_content='Projects')]"
|
365 |
+
]
|
366 |
+
},
|
367 |
+
"execution_count": 34,
|
368 |
+
"metadata": {},
|
369 |
+
"output_type": "execute_result"
|
370 |
+
}
|
371 |
+
],
|
372 |
+
"source": [
|
373 |
+
"result"
|
374 |
+
]
|
375 |
+
},
|
376 |
+
{
|
377 |
+
"cell_type": "code",
|
378 |
+
"execution_count": null,
|
379 |
+
"metadata": {},
|
380 |
+
"outputs": [],
|
381 |
+
"source": []
|
382 |
+
},
|
383 |
+
{
|
384 |
+
"cell_type": "code",
|
385 |
+
"execution_count": 16,
|
386 |
+
"metadata": {},
|
387 |
+
"outputs": [
|
388 |
+
{
|
389 |
+
"data": {
|
390 |
+
"text/html": [
|
391 |
+
"<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\"><span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">1536</span>\n",
|
392 |
+
"</pre>\n"
|
393 |
+
],
|
394 |
+
"text/plain": [
|
395 |
+
"\u001b[1;36m1536\u001b[0m\n"
|
396 |
+
]
|
397 |
+
},
|
398 |
+
"metadata": {},
|
399 |
+
"output_type": "display_data"
|
400 |
+
}
|
401 |
+
],
|
402 |
+
"source": [
|
403 |
+
"embedding = response.data[0].embedding\n",
|
404 |
+
"print(len(embedding))"
|
405 |
+
]
|
406 |
+
},
|
407 |
+
{
|
408 |
+
"cell_type": "code",
|
409 |
+
"execution_count": 20,
|
410 |
+
"metadata": {},
|
411 |
+
"outputs": [],
|
412 |
+
"source": [
|
413 |
+
"with open(r\"artifacts\\Chat.txt\",\"r\", encoding='utf-8') as f:\n",
|
414 |
+
" data = f.read()"
|
415 |
+
]
|
416 |
+
},
|
417 |
+
{
|
418 |
+
"cell_type": "code",
|
419 |
+
"execution_count": 23,
|
420 |
+
"metadata": {},
|
421 |
+
"outputs": [
|
422 |
+
{
|
423 |
+
"data": {
|
424 |
+
"text/html": [
|
425 |
+
"<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\">--- <span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">08</span>/<span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">01</span>/<span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">23</span> ---\n",
|
426 |
+
"</pre>\n"
|
427 |
+
],
|
428 |
+
"text/plain": [
|
429 |
+
"--- \u001b[1;36m08\u001b[0m/\u001b[1;36m01\u001b[0m/\u001b[1;36m23\u001b[0m ---\n"
|
430 |
+
]
|
431 |
+
},
|
432 |
+
"metadata": {},
|
433 |
+
"output_type": "display_data"
|
434 |
+
},
|
435 |
+
{
|
436 |
+
"data": {
|
437 |
+
"text/html": [
|
438 |
+
"<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\"><span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">08</span>/<span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">01</span>/<span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">23</span>, <span style=\"color: #00ff00; text-decoration-color: #00ff00; font-weight: bold\">10:16</span> pm - Messages to yourself are end-to-end encrypted<span style=\"color: #808000; text-decoration-color: #808000\">...</span>\n",
|
439 |
+
"</pre>\n"
|
440 |
+
],
|
441 |
+
"text/plain": [
|
442 |
+
"\u001b[1;36m08\u001b[0m/\u001b[1;36m01\u001b[0m/\u001b[1;36m23\u001b[0m, \u001b[1;92m10:16\u001b[0m pm - Messages to yourself are end-to-end encrypted\u001b[33m...\u001b[0m\n"
|
443 |
+
]
|
444 |
+
},
|
445 |
+
"metadata": {},
|
446 |
+
"output_type": "display_data"
|
447 |
+
},
|
448 |
+
{
|
449 |
+
"data": {
|
450 |
+
"text/html": [
|
451 |
+
"<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\"><span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">08</span>/<span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">01</span>/<span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">23</span>, <span style=\"color: #00ff00; text-decoration-color: #00ff00; font-weight: bold\">10:11</span> pm - Yuvraj: <span style=\"font-weight: bold\"><</span><span style=\"color: #ff00ff; text-decoration-color: #ff00ff; font-weight: bold\">Media</span><span style=\"color: #000000; text-decoration-color: #000000\"> omitted</span><span style=\"font-weight: bold\">></span>\n",
|
452 |
+
"</pre>\n"
|
453 |
+
],
|
454 |
+
"text/plain": [
|
455 |
+
"\u001b[1;36m08\u001b[0m/\u001b[1;36m01\u001b[0m/\u001b[1;36m23\u001b[0m, \u001b[1;92m10:11\u001b[0m pm - Yuvraj: \u001b[1m<\u001b[0m\u001b[1;95mMedia\u001b[0m\u001b[39m omitted\u001b[0m\u001b[1m>\u001b[0m\n"
|
456 |
+
]
|
457 |
+
},
|
458 |
+
"metadata": {},
|
459 |
+
"output_type": "display_data"
|
460 |
+
},
|
461 |
+
{
|
462 |
+
"data": {
|
463 |
+
"text/html": [
|
464 |
+
"<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\">\n",
|
465 |
+
"</pre>\n"
|
466 |
+
],
|
467 |
+
"text/plain": [
|
468 |
+
"\n"
|
469 |
+
]
|
470 |
+
},
|
471 |
+
"metadata": {},
|
472 |
+
"output_type": "display_data"
|
473 |
+
},
|
474 |
+
{
|
475 |
+
"data": {
|
476 |
+
"text/html": [
|
477 |
+
"<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\">--- <span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">09</span>/<span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">01</span>/<span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">23</span> ---\n",
|
478 |
+
"</pre>\n"
|
479 |
+
],
|
480 |
+
"text/plain": [
|
481 |
+
"--- \u001b[1;36m09\u001b[0m/\u001b[1;36m01\u001b[0m/\u001b[1;36m23\u001b[0m ---\n"
|
482 |
+
]
|
483 |
+
},
|
484 |
+
"metadata": {},
|
485 |
+
"output_type": "display_data"
|
486 |
+
},
|
487 |
+
{
|
488 |
+
"data": {
|
489 |
+
"text/html": [
|
490 |
+
"<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\"><span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">09</span>/<span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">01</span>/<span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">23</span>, <span style=\"color: #00ff00; text-decoration-color: #00ff00; font-weight: bold\">12:05</span> am - Yuvraj: <span style=\"color: #0000ff; text-decoration-color: #0000ff; text-decoration: underline\">https://www.sumly.ai/</span>\n",
|
491 |
+
"</pre>\n"
|
492 |
+
],
|
493 |
+
"text/plain": [
|
494 |
+
"\u001b[1;36m09\u001b[0m/\u001b[1;36m01\u001b[0m/\u001b[1;36m23\u001b[0m, \u001b[1;92m12:05\u001b[0m am - Yuvraj: \u001b[4;94mhttps://www.sumly.ai/\u001b[0m\n"
|
495 |
+
]
|
496 |
+
},
|
497 |
+
"metadata": {},
|
498 |
+
"output_type": "display_data"
|
499 |
+
},
|
500 |
+
{
|
501 |
+
"data": {
|
502 |
+
"text/html": [
|
503 |
+
"<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\">\n",
|
504 |
+
"</pre>\n"
|
505 |
+
],
|
506 |
+
"text/plain": [
|
507 |
+
"\n"
|
508 |
+
]
|
509 |
+
},
|
510 |
+
"metadata": {},
|
511 |
+
"output_type": "display_data"
|
512 |
+
},
|
513 |
+
{
|
514 |
+
"data": {
|
515 |
+
"text/html": [
|
516 |
+
"<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\">--- <span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">15</span>/<span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">01</span>/<span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">23</span> ---\n",
|
517 |
+
"</pre>\n"
|
518 |
+
],
|
519 |
+
"text/plain": [
|
520 |
+
"--- \u001b[1;36m15\u001b[0m/\u001b[1;36m01\u001b[0m/\u001b[1;36m23\u001b[0m ---\n"
|
521 |
+
]
|
522 |
+
},
|
523 |
+
"metadata": {},
|
524 |
+
"output_type": "display_data"
|
525 |
+
},
|
526 |
+
{
|
527 |
+
"data": {
|
528 |
+
"text/html": [
|
529 |
+
"<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\"><span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">15</span>/<span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">01</span>/<span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">23</span>, <span style=\"color: #00ff00; text-decoration-color: #00ff00; font-weight: bold\">2:17</span> pm - Yuvraj: <span style=\"color: #0000ff; text-decoration-color: #0000ff; text-decoration: underline\">https://youtube.com/shorts/GYxiuFRkS58?feature=share</span>\n",
|
530 |
+
"</pre>\n"
|
531 |
+
],
|
532 |
+
"text/plain": [
|
533 |
+
"\u001b[1;36m15\u001b[0m/\u001b[1;36m01\u001b[0m/\u001b[1;36m23\u001b[0m, \u001b[1;92m2:17\u001b[0m pm - Yuvraj: \u001b[4;94mhttps://youtube.com/shorts/GYxiuFRkS58?\u001b[0m\u001b[4;94mfeature\u001b[0m\u001b[4;94m=\u001b[0m\u001b[4;94mshare\u001b[0m\n"
|
534 |
+
]
|
535 |
+
},
|
536 |
+
"metadata": {},
|
537 |
+
"output_type": "display_data"
|
538 |
+
},
|
539 |
+
{
|
540 |
+
"data": {
|
541 |
+
"text/html": [
|
542 |
+
"<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\">\n",
|
543 |
+
"</pre>\n"
|
544 |
+
],
|
545 |
+
"text/plain": [
|
546 |
+
"\n"
|
547 |
+
]
|
548 |
+
},
|
549 |
+
"metadata": {},
|
550 |
+
"output_type": "display_data"
|
551 |
+
},
|
552 |
+
{
|
553 |
+
"data": {
|
554 |
+
"text/html": [
|
555 |
+
"<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\">--- <span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">17</span>/<span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">01</span>/<span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">23</span> ---\n",
|
556 |
+
"</pre>\n"
|
557 |
+
],
|
558 |
+
"text/plain": [
|
559 |
+
"--- \u001b[1;36m17\u001b[0m/\u001b[1;36m01\u001b[0m/\u001b[1;36m23\u001b[0m ---\n"
|
560 |
+
]
|
561 |
+
},
|
562 |
+
"metadata": {},
|
563 |
+
"output_type": "display_data"
|
564 |
+
},
|
565 |
+
{
|
566 |
+
"data": {
|
567 |
+
"text/html": [
|
568 |
+
"<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\"><span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">17</span>/<span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">01</span>/<span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">23</span>, <span style=\"color: #00ff00; text-decoration-color: #00ff00; font-weight: bold\">8:20</span> pm - Yuvraj: Dear Students<span style=\"color: #808000; text-decoration-color: #808000\">...</span>\n",
|
569 |
+
"</pre>\n"
|
570 |
+
],
|
571 |
+
"text/plain": [
|
572 |
+
"\u001b[1;36m17\u001b[0m/\u001b[1;36m01\u001b[0m/\u001b[1;36m23\u001b[0m, \u001b[1;92m8:20\u001b[0m pm - Yuvraj: Dear Students\u001b[33m...\u001b[0m\n"
|
573 |
+
]
|
574 |
+
},
|
575 |
+
"metadata": {},
|
576 |
+
"output_type": "display_data"
|
577 |
+
},
|
578 |
+
{
|
579 |
+
"data": {
|
580 |
+
"text/html": [
|
581 |
+
"<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\">\n",
|
582 |
+
"</pre>\n"
|
583 |
+
],
|
584 |
+
"text/plain": [
|
585 |
+
"\n"
|
586 |
+
]
|
587 |
+
},
|
588 |
+
"metadata": {},
|
589 |
+
"output_type": "display_data"
|
590 |
+
}
|
591 |
+
],
|
592 |
+
"source": []
|
593 |
+
},
|
594 |
+
{
|
595 |
+
"cell_type": "code",
|
596 |
+
"execution_count": null,
|
597 |
+
"metadata": {},
|
598 |
+
"outputs": [],
|
599 |
+
"source": []
|
600 |
+
}
|
601 |
+
],
|
602 |
+
"metadata": {
|
603 |
+
"kernelspec": {
|
604 |
+
"display_name": ".venv",
|
605 |
+
"language": "python",
|
606 |
+
"name": "python3"
|
607 |
+
},
|
608 |
+
"language_info": {
|
609 |
+
"codemirror_mode": {
|
610 |
+
"name": "ipython",
|
611 |
+
"version": 3
|
612 |
+
},
|
613 |
+
"file_extension": ".py",
|
614 |
+
"mimetype": "text/x-python",
|
615 |
+
"name": "python",
|
616 |
+
"nbconvert_exporter": "python",
|
617 |
+
"pygments_lexer": "ipython3",
|
618 |
+
"version": "3.12.6"
|
619 |
+
}
|
620 |
+
},
|
621 |
+
"nbformat": 4,
|
622 |
+
"nbformat_minor": 2
|
623 |
+
}
|
Finance-RAG/WhatsApp Chat with Jashan Cu.txt
ADDED
The diff for this file is too large to render.
See raw diff
|
|
Finance-RAG/app.py
ADDED
@@ -0,0 +1,953 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import os
|
2 |
+
import streamlit as st
|
3 |
+
from openai import OpenAI
|
4 |
+
from PyPDF2 import PdfReader
|
5 |
+
import requests
|
6 |
+
from youtube_transcript_api import YouTubeTranscriptApi, NoTranscriptFound, TranscriptsDisabled
|
7 |
+
from urllib.parse import urlparse, parse_qs
|
8 |
+
from pinecone import Pinecone
|
9 |
+
import uuid
|
10 |
+
from dotenv import load_dotenv
|
11 |
+
import time
|
12 |
+
from concurrent.futures import ThreadPoolExecutor, as_completed
|
13 |
+
from itertools import islice
|
14 |
+
import unicodedata
|
15 |
+
import re
|
16 |
+
from tiktoken import encoding_for_model
|
17 |
+
import json
|
18 |
+
import datetime
|
19 |
+
import tiktoken
|
20 |
+
import pandas as pd
|
21 |
+
import io
|
22 |
+
from fpdf import FPDF
|
23 |
+
import tempfile
|
24 |
+
from PyPDF2 import PdfReader
|
25 |
+
import base64
|
26 |
+
from pathlib import Path
|
27 |
+
import numpy as np
|
28 |
+
from pymongo import MongoClient
|
29 |
+
import traceback
|
30 |
+
from docx import Document
|
31 |
+
import pandas as pd
|
32 |
+
import io
|
33 |
+
import time
|
34 |
+
import traceback
|
35 |
+
|
36 |
+
load_dotenv()
|
37 |
+
|
38 |
+
# Set up OpenAI client
|
39 |
+
client = OpenAI(api_key=os.getenv("OPENAI_API_KEY"))
|
40 |
+
|
41 |
+
# Set up Pinecone
|
42 |
+
pc = Pinecone(api_key=os.getenv("PINECONE_API_KEY"))
|
43 |
+
|
44 |
+
# Get index name and URL from .env
|
45 |
+
index_name = os.getenv("PINECONE_INDEX_NAME")
|
46 |
+
index_url = os.getenv("PINECONE_INDEX_URL")
|
47 |
+
|
48 |
+
index = pc.Index(index_name, url=index_url)
|
49 |
+
|
50 |
+
# Set up MongoDB connection
|
51 |
+
mongo_client = MongoClient(os.getenv("MONGODB_URI"))
|
52 |
+
db = mongo_client.get_database("finance")
|
53 |
+
users_collection = db["users"]
|
54 |
+
|
55 |
+
def get_embedding(text):
|
56 |
+
response = client.embeddings.create(input=text, model="text-embedding-3-large")
|
57 |
+
return response.data[0].embedding
|
58 |
+
|
59 |
+
def chunk_text(text, content_type):
|
60 |
+
sanitized_text = sanitize_text(text)
|
61 |
+
if content_type == "YouTube":
|
62 |
+
chunk_size = 2000 # Adjust this value as needed
|
63 |
+
content_length = len(sanitized_text)
|
64 |
+
return [sanitized_text[i:i+chunk_size] for i in range(0, content_length, chunk_size)]
|
65 |
+
else: # Default for PDF and Web Link
|
66 |
+
chunk_size = 2000
|
67 |
+
content_length = len(sanitized_text)
|
68 |
+
return [sanitized_text[i:i+chunk_size] for i in range(0, content_length, chunk_size)]
|
69 |
+
|
70 |
+
def process_pdf(file):
|
71 |
+
reader = PdfReader(file)
|
72 |
+
text = []
|
73 |
+
for page in reader.pages:
|
74 |
+
text.append(page.extract_text())
|
75 |
+
return " ".join(text) # Join all pages into a single string
|
76 |
+
|
77 |
+
def process_web_link(url):
|
78 |
+
response = requests.get(url)
|
79 |
+
return chunk_text(response.text, "Web")
|
80 |
+
|
81 |
+
def process_youtube_link(url):
|
82 |
+
try:
|
83 |
+
video_id = extract_video_id(url)
|
84 |
+
transcript = YouTubeTranscriptApi.get_transcript(video_id)
|
85 |
+
full_text = " ".join([entry['text'] for entry in transcript])
|
86 |
+
print("Transcript obtained from YouTube API")
|
87 |
+
return chunk_text(full_text, "YouTube") # Use chunk_text function to split large transcripts
|
88 |
+
except NoTranscriptFound:
|
89 |
+
print("No transcript found for this YouTube video.")
|
90 |
+
return []
|
91 |
+
except TranscriptsDisabled:
|
92 |
+
print("Transcripts are disabled for this YouTube video.")
|
93 |
+
return []
|
94 |
+
except Exception as e:
|
95 |
+
print(f"An error occurred while processing the YouTube link: {str(e)}")
|
96 |
+
return []
|
97 |
+
|
98 |
+
def extract_video_id(url):
|
99 |
+
parsed_url = urlparse(url)
|
100 |
+
if parsed_url.hostname == 'youtu.be':
|
101 |
+
return parsed_url.path[1:]
|
102 |
+
if parsed_url.hostname in ('www.youtube.com', 'youtube.com'):
|
103 |
+
if parsed_url.path == '/watch':
|
104 |
+
return parse_qs(parsed_url.query)['v'][0]
|
105 |
+
if parsed_url.path[:7] == '/embed/':
|
106 |
+
return parsed_url.path.split('/')[2]
|
107 |
+
if parsed_url.path[:3] == '/v/':
|
108 |
+
return parsed_url.path.split('/')[2]
|
109 |
+
return None
|
110 |
+
|
111 |
+
def process_upload(upload_type, file_or_link, file_name=None):
|
112 |
+
print(f"Starting process_upload for {upload_type}")
|
113 |
+
doc_id = str(uuid.uuid4())
|
114 |
+
print(f"Generated doc_id: {doc_id}")
|
115 |
+
|
116 |
+
if upload_type == "PDF":
|
117 |
+
chunks = process_pdf(file_or_link)
|
118 |
+
doc_name = file_name or "Uploaded PDF"
|
119 |
+
elif upload_type == "Web Link":
|
120 |
+
chunks = process_web_link(file_or_link)
|
121 |
+
doc_name = file_or_link
|
122 |
+
elif upload_type == "YouTube Link":
|
123 |
+
chunks = process_youtube_link(file_or_link)
|
124 |
+
doc_name = f"YouTube: {file_or_link}"
|
125 |
+
else:
|
126 |
+
print("Invalid upload type")
|
127 |
+
return "Invalid upload type"
|
128 |
+
|
129 |
+
vectors = []
|
130 |
+
with ThreadPoolExecutor() as executor:
|
131 |
+
futures = [executor.submit(process_chunk, chunk, doc_id, i, upload_type, doc_name) for i, chunk in enumerate(chunks)]
|
132 |
+
|
133 |
+
for future in as_completed(futures):
|
134 |
+
vectors.append(future.result())
|
135 |
+
# Update progress
|
136 |
+
progress = len(vectors) / len(chunks)
|
137 |
+
st.session_state.upload_progress.progress(progress)
|
138 |
+
|
139 |
+
print(f"Generated {len(vectors)} vectors")
|
140 |
+
|
141 |
+
# Upsert vectors in batches
|
142 |
+
batch_size = 100 # Adjust this value as needed
|
143 |
+
for i in range(0, len(vectors), batch_size):
|
144 |
+
batch = list(islice(vectors, i, i + batch_size))
|
145 |
+
index.upsert(vectors=batch)
|
146 |
+
print(f"Upserted batch {i//batch_size + 1} of {len(vectors)//batch_size + 1}")
|
147 |
+
|
148 |
+
print("All vectors upserted to Pinecone")
|
149 |
+
|
150 |
+
return f"Processing complete for {upload_type}. Document Name: {doc_name}"
|
151 |
+
|
152 |
+
def process_chunk(chunk, doc_id, i, upload_type, doc_name):
|
153 |
+
# Sanitize the chunk text
|
154 |
+
sanitized_chunk = sanitize_text(chunk)
|
155 |
+
embedding = get_embedding(sanitized_chunk)
|
156 |
+
return (f"{doc_id}_{i}", embedding, {
|
157 |
+
"text": sanitized_chunk,
|
158 |
+
"type": upload_type,
|
159 |
+
"doc_id": doc_id,
|
160 |
+
"doc_name": doc_name,
|
161 |
+
"chunk_index": i
|
162 |
+
})
|
163 |
+
|
164 |
+
def sanitize_text(text):
|
165 |
+
# Remove control characters and normalize Unicode
|
166 |
+
return ''.join(ch for ch in unicodedata.normalize('NFKD', text) if unicodedata.category(ch)[0] != 'C')
|
167 |
+
|
168 |
+
def get_relevant_context(query, top_k=5):
|
169 |
+
print(f"Getting relevant context for query: {query}")
|
170 |
+
query_embedding = get_embedding(query)
|
171 |
+
|
172 |
+
search_results = index.query(vector=query_embedding, top_k=top_k, include_metadata=True)
|
173 |
+
print(f"Found {len(search_results['matches'])} relevant results")
|
174 |
+
|
175 |
+
# Sort results by similarity score (higher is better)
|
176 |
+
sorted_results = sorted(search_results['matches'], key=lambda x: x['score'], reverse=True)
|
177 |
+
|
178 |
+
context = "\n".join([result['metadata']['text'] for result in sorted_results])
|
179 |
+
return context, sorted_results
|
180 |
+
|
181 |
+
def truncate_context(context, max_tokens):
|
182 |
+
enc = encoding_for_model("gpt-4o-mini")
|
183 |
+
encoded = enc.encode(context)
|
184 |
+
if len(encoded) > max_tokens:
|
185 |
+
return enc.decode(encoded[:max_tokens])
|
186 |
+
return context
|
187 |
+
|
188 |
+
def chat_with_ai(message):
|
189 |
+
print(f"Chatting with AI, message: {message}")
|
190 |
+
context, results = get_relevant_context(message)
|
191 |
+
print(f"Retrieved context, length: {len(context)}")
|
192 |
+
|
193 |
+
# Truncate context if it's too long
|
194 |
+
max_tokens = 7000 # Leave some room for the system message and user query
|
195 |
+
context = truncate_context(context, max_tokens)
|
196 |
+
|
197 |
+
messages = [
|
198 |
+
{"role": "system", "content": "You are a helpful assistant. Use the following information to answer the user's question, but don't mention the context directly in your response. If the information isn't in the context, say you don't know."},
|
199 |
+
{"role": "system", "content": f"Context: {context}"},
|
200 |
+
{"role": "user", "content": message}
|
201 |
+
]
|
202 |
+
|
203 |
+
response = client.chat.completions.create(
|
204 |
+
model="gpt-4o-mini",
|
205 |
+
messages=messages
|
206 |
+
)
|
207 |
+
print("Received response from OpenAI")
|
208 |
+
|
209 |
+
ai_response = response.choices[0].message.content
|
210 |
+
|
211 |
+
# Prepare source information
|
212 |
+
sources = [
|
213 |
+
{
|
214 |
+
"doc_id": result['metadata']['doc_id'],
|
215 |
+
"doc_name": result['metadata']['doc_name'],
|
216 |
+
"chunk_index": result['metadata']['chunk_index'],
|
217 |
+
"text": result['metadata']['text'],
|
218 |
+
"type": result['metadata']['type'],
|
219 |
+
"score": result['score']
|
220 |
+
}
|
221 |
+
for result in results
|
222 |
+
]
|
223 |
+
|
224 |
+
return ai_response, sources
|
225 |
+
|
226 |
+
def process_youtube_links(links):
|
227 |
+
results = []
|
228 |
+
for link in links:
|
229 |
+
result = process_upload("YouTube Link", link.strip())
|
230 |
+
results.append(result)
|
231 |
+
return results
|
232 |
+
|
233 |
+
def process_excel(file):
|
234 |
+
dfs = pd.read_excel(file, sheet_name=None) # Read all sheets
|
235 |
+
for sheet_name, df in dfs.items():
|
236 |
+
df.columns = df.columns.astype(str)
|
237 |
+
# Remove any unnamed columns
|
238 |
+
df = df.loc[:, ~df.columns.str.contains('^Unnamed')]
|
239 |
+
return dfs
|
240 |
+
|
241 |
+
def analyze_and_generate_formulas(main_df, other_dfs):
|
242 |
+
# Focus on the 'DETAILS' column and the month columns
|
243 |
+
details_column = main_df.columns[0]
|
244 |
+
month_columns = main_df.columns[1:-1] # Exclude the 'Total' column
|
245 |
+
|
246 |
+
main_summary = f"DETAILS column data: {main_df[details_column].tolist()}\n"
|
247 |
+
for month in month_columns:
|
248 |
+
main_summary += f"{month} column data: {main_df[month].tolist()}\n"
|
249 |
+
|
250 |
+
other_sheets_summary = ""
|
251 |
+
for name, df in other_dfs.items():
|
252 |
+
if len(df.columns) > 0:
|
253 |
+
other_sheets_summary += f"\nSheet '{name}' structure:\n"
|
254 |
+
other_sheets_summary += f"Columns: {df.columns.tolist()}\n"
|
255 |
+
other_sheets_summary += f"First few rows:\n{df.head().to_string()}\n"
|
256 |
+
|
257 |
+
prompt = f"""Analyze the following Excel data and generate Python formulas to fill missing values:
|
258 |
+
|
259 |
+
Main Sheet Structure:
|
260 |
+
{main_summary}
|
261 |
+
|
262 |
+
Other Sheets:
|
263 |
+
{other_sheets_summary}
|
264 |
+
|
265 |
+
Provide Python formulas using pandas to fill missing values in the month columns of the main sheet.
|
266 |
+
Use pandas and numpy functions where appropriate. If a value cannot be determined, use None.
|
267 |
+
Return a dictionary with column names as keys and formulas as values.
|
268 |
+
Example of the expected format: {{'Apr'24': "df['Apr'24'].fillna(method='ffill')"}}
|
269 |
+
"""
|
270 |
+
|
271 |
+
try:
|
272 |
+
response = client.chat.completions.create(
|
273 |
+
model="gpt-4o-mini",
|
274 |
+
messages=[
|
275 |
+
{"role": "system", "content": "You are a data analysis expert skilled in creating concise formulas for data filling."},
|
276 |
+
{"role": "user", "content": prompt}
|
277 |
+
]
|
278 |
+
)
|
279 |
+
|
280 |
+
formulas = eval(response.choices[0].message.content.strip())
|
281 |
+
print(f"Generated formulas: {formulas}")
|
282 |
+
|
283 |
+
return formulas
|
284 |
+
|
285 |
+
except Exception as e:
|
286 |
+
print(f"Error in analyze_and_generate_formulas: {str(e)}")
|
287 |
+
print(traceback.format_exc())
|
288 |
+
return {}
|
289 |
+
|
290 |
+
def apply_formulas(main_df, other_dfs, formulas):
|
291 |
+
filled_df = main_df.copy()
|
292 |
+
|
293 |
+
for column, formula in formulas.items():
|
294 |
+
if column in filled_df.columns:
|
295 |
+
try:
|
296 |
+
print(f"Applying formula for column {column}: {formula}")
|
297 |
+
|
298 |
+
# Create a local namespace with all dataframes
|
299 |
+
namespace = {'df': filled_df, 'np': np, 'pd': pd}
|
300 |
+
|
301 |
+
# Execute the formula in the namespace
|
302 |
+
exec(f"result = {formula}", namespace)
|
303 |
+
|
304 |
+
# Apply the result to the column
|
305 |
+
filled_df[column] = namespace['result']
|
306 |
+
print(f"Successfully applied formula for column {column}")
|
307 |
+
except Exception as e:
|
308 |
+
print(f"Error applying formula for column {column}: {str(e)}")
|
309 |
+
print(traceback.format_exc())
|
310 |
+
|
311 |
+
return filled_df
|
312 |
+
|
313 |
+
def excel_to_pdf(df):
|
314 |
+
pdf = FPDF(orientation='L', unit='mm', format='A4')
|
315 |
+
pdf.add_page()
|
316 |
+
pdf.set_font("Arial", size=8)
|
317 |
+
|
318 |
+
# Calculate column widths
|
319 |
+
col_widths = [pdf.get_string_width(str(col)) + 6 for col in df.columns]
|
320 |
+
|
321 |
+
# Write header
|
322 |
+
for i, col in enumerate(df.columns):
|
323 |
+
pdf.cell(col_widths[i], 10, str(col), border=1)
|
324 |
+
pdf.ln()
|
325 |
+
|
326 |
+
# Write data
|
327 |
+
for _, row in df.iterrows():
|
328 |
+
for i, value in enumerate(row):
|
329 |
+
pdf.cell(col_widths[i], 10, str(value), border=1)
|
330 |
+
pdf.ln()
|
331 |
+
|
332 |
+
# Save to a temporary file
|
333 |
+
with tempfile.NamedTemporaryFile(delete=False, suffix=".pdf") as temp_file:
|
334 |
+
pdf.output(temp_file.name)
|
335 |
+
return temp_file.name
|
336 |
+
|
337 |
+
def pdf_to_text(pdf_path):
|
338 |
+
with open(pdf_path, 'rb') as file:
|
339 |
+
pdf = PdfReader(file)
|
340 |
+
text = []
|
341 |
+
for page in pdf.pages:
|
342 |
+
text.append(page.extract_text())
|
343 |
+
return text
|
344 |
+
|
345 |
+
def get_user_feedback(user_id):
|
346 |
+
user = users_collection.find_one({"_id": user_id})
|
347 |
+
return user.get("feedback", "") if user else ""
|
348 |
+
|
349 |
+
def get_category_reports():
|
350 |
+
return {
|
351 |
+
"Default": [], # Changed from "None" to "Default"
|
352 |
+
"Sales KPI": [
|
353 |
+
"Monthwise Sales Table", "Customer-wise Sales Table (top 10)", "Qty Sales",
|
354 |
+
"Customer-wise Churn", "Avg Sales per Customer", "Product-wise Sales Rate",
|
355 |
+
"Geography-wise", "Trend Analysis", "Graphs", "Month-wise Comparison"
|
356 |
+
],
|
357 |
+
"Expenses KPI": [
|
358 |
+
"Vendor-wise Comparison", "Year on Year Monthwise", "Division-wise"
|
359 |
+
],
|
360 |
+
"Purchase Register": [
|
361 |
+
"Vendor-wise Monthwise", "Monthwise", "Material-wise Purchase Rate Analysis"
|
362 |
+
],
|
363 |
+
"Balance Sheet": [
|
364 |
+
"Year on Year Comparison", "Ratios"
|
365 |
+
]
|
366 |
+
}
|
367 |
+
|
368 |
+
def analyze_excel_with_gpt(df, sheet_name, user_feedback, category, reports_needed, use_assistants_api=False):
|
369 |
+
if use_assistants_api:
|
370 |
+
return process_excel_with_assistant(df, category, reports_needed, user_feedback)
|
371 |
+
else:
|
372 |
+
# Existing OCR-based analysis code
|
373 |
+
prompt = f"""Analyze the following Excel data from sheet '{sheet_name}':
|
374 |
+
|
375 |
+
{df.to_string()}
|
376 |
+
|
377 |
+
User's previous feedback and insights:
|
378 |
+
{user_feedback}
|
379 |
+
|
380 |
+
"""
|
381 |
+
|
382 |
+
if category != "general":
|
383 |
+
prompt += f"""Please provide analysis and insights based on the following required reports for the category '{category}':
|
384 |
+
{', '.join(reports_needed)}
|
385 |
+
|
386 |
+
Please provide:
|
387 |
+
1. A comprehensive overview of the data focusing on the {category} category
|
388 |
+
2. Key observations and trends related to the required reports
|
389 |
+
3. Any anomalies, interesting patterns, or correlations relevant to the {category}
|
390 |
+
4. Suggestions for further analysis or visualization based on the required reports
|
391 |
+
5. Address any previous feedback or insights mentioned above, if applicable
|
392 |
+
|
393 |
+
Focus on providing a thorough analysis of all aspects of the data relevant to the {category} and the specified reports."""
|
394 |
+
else:
|
395 |
+
prompt += """Please provide a general analysis of the data, including:
|
396 |
+
1. A comprehensive overview of the data
|
397 |
+
2. Key observations and trends
|
398 |
+
3. Any anomalies, interesting patterns, or correlations
|
399 |
+
4. Suggestions for further analysis or visualization
|
400 |
+
5. Address any previous feedback or insights mentioned above, if applicable
|
401 |
+
|
402 |
+
Focus on providing a thorough analysis of all aspects of the data."""
|
403 |
+
|
404 |
+
response = client.chat.completions.create(
|
405 |
+
model="gpt-4o-mini",
|
406 |
+
messages=[
|
407 |
+
{"role": "system", "content": f"You are a data analyst expert in interpreting Excel data for {'general' if category == 'general' else category} analysis."},
|
408 |
+
{"role": "user", "content": prompt}
|
409 |
+
]
|
410 |
+
)
|
411 |
+
|
412 |
+
return response.choices[0].message.content
|
413 |
+
|
414 |
+
def analyze_document_with_gpt(document_content, user_feedback, category, reports_needed, use_assistants_api=False, file_id=None):
|
415 |
+
if use_assistants_api:
|
416 |
+
assistant = client.beta.assistants.create(
|
417 |
+
name="Document Analyzer",
|
418 |
+
instructions=f"You are a document analysis expert. Analyze the uploaded document and provide insights based on the category: {category}.",
|
419 |
+
model="gpt-4-1106-preview"
|
420 |
+
)
|
421 |
+
|
422 |
+
thread = client.beta.threads.create()
|
423 |
+
|
424 |
+
message = client.beta.threads.messages.create(
|
425 |
+
thread_id=thread.id,
|
426 |
+
role="user",
|
427 |
+
content=f"Analyze the document with file ID: {file_id}. Category: {category}. Required reports: {', '.join(reports_needed)}. User feedback: {user_feedback}",
|
428 |
+
file_ids=[file_id]
|
429 |
+
)
|
430 |
+
|
431 |
+
run = client.beta.threads.runs.create(
|
432 |
+
thread_id=thread.id,
|
433 |
+
assistant_id=assistant.id
|
434 |
+
)
|
435 |
+
|
436 |
+
while run.status != "completed":
|
437 |
+
run = client.beta.threads.runs.retrieve(thread_id=thread.id, run_id=run.id)
|
438 |
+
time.sleep(1)
|
439 |
+
|
440 |
+
messages = client.beta.threads.messages.list(thread_id=thread.id)
|
441 |
+
return messages.data[0].content[0].text.value
|
442 |
+
else:
|
443 |
+
# Existing OCR-based analysis code
|
444 |
+
prompt = f"""Analyze the following document content:
|
445 |
+
|
446 |
+
{document_content}
|
447 |
+
|
448 |
+
User's previous feedback and insights:
|
449 |
+
{user_feedback}
|
450 |
+
|
451 |
+
"""
|
452 |
+
|
453 |
+
if category != "general":
|
454 |
+
prompt += f"""Please provide analysis and insights based on the following required reports for the category '{category}':
|
455 |
+
{', '.join(reports_needed)}
|
456 |
+
|
457 |
+
Please provide:
|
458 |
+
1. A comprehensive overview of the content focusing on the {category} category
|
459 |
+
2. Key points and main ideas related to the required reports
|
460 |
+
3. Any interesting patterns or unique aspects relevant to the {category}
|
461 |
+
4. Suggestions for further analysis or insights based on the required reports
|
462 |
+
5. Any limitations of the analysis due to the document format or OCR process
|
463 |
+
6. Address any previous feedback or insights mentioned above, if applicable
|
464 |
+
|
465 |
+
Focus on providing a thorough analysis of all aspects of the content relevant to the {category} and the specified reports."""
|
466 |
+
else:
|
467 |
+
prompt += """Please provide a general analysis of the document content, including:
|
468 |
+
1. A comprehensive overview of the content
|
469 |
+
2. Key points and main ideas
|
470 |
+
3. Any interesting patterns or unique aspects
|
471 |
+
4. Suggestions for further analysis or insights
|
472 |
+
5. Any limitations of the analysis due to the document format or OCR process
|
473 |
+
6. Address any previous feedback or insights mentioned above, if applicable
|
474 |
+
|
475 |
+
Focus on providing a thorough analysis of all aspects of the content."""
|
476 |
+
|
477 |
+
response = client.chat.completions.create(
|
478 |
+
model="gpt-4o-mini",
|
479 |
+
messages=[
|
480 |
+
{"role": "system", "content": f"You are a data analyst expert in interpreting complex document content for {'general' if category == 'general' else category} analysis."},
|
481 |
+
{"role": "user", "content": prompt}
|
482 |
+
]
|
483 |
+
)
|
484 |
+
|
485 |
+
return response.choices[0].message.content
|
486 |
+
|
487 |
+
def process_uploaded_file(uploaded_file):
|
488 |
+
file_type = uploaded_file.type
|
489 |
+
if file_type in ["application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", "application/vnd.ms-excel"]:
|
490 |
+
# Process Excel file
|
491 |
+
dfs = process_excel(uploaded_file)
|
492 |
+
return "excel", dfs
|
493 |
+
elif file_type == "application/pdf":
|
494 |
+
# Process PDF file using PyPDF2
|
495 |
+
try:
|
496 |
+
pdf_reader = PdfReader(uploaded_file)
|
497 |
+
text = ""
|
498 |
+
for page in pdf_reader.pages:
|
499 |
+
text += page.extract_text()
|
500 |
+
return "text", text
|
501 |
+
except Exception as e:
|
502 |
+
st.error(f"Error processing PDF: {str(e)}")
|
503 |
+
print(f"Error processing PDF: {str(e)}")
|
504 |
+
print(traceback.format_exc())
|
505 |
+
return None, None
|
506 |
+
elif file_type in ["application/vnd.openxmlformats-officedocument.wordprocessingml.document", "application/msword"]:
|
507 |
+
# Process Word document
|
508 |
+
try:
|
509 |
+
doc = Document(io.BytesIO(uploaded_file.read()))
|
510 |
+
text = "\n".join([paragraph.text for paragraph in doc.paragraphs])
|
511 |
+
return "text", text
|
512 |
+
except Exception as e:
|
513 |
+
st.error(f"Error processing Word document: {str(e)}")
|
514 |
+
print(f"Error processing Word document: {str(e)}")
|
515 |
+
print(traceback.format_exc())
|
516 |
+
return None, None
|
517 |
+
else:
|
518 |
+
st.error(f"Unsupported file type: {file_type}. Please upload an Excel file, PDF, or Word document.")
|
519 |
+
return None, None
|
520 |
+
|
521 |
+
def chat_with_data(data, user_question, data_type):
|
522 |
+
if data_type == "excel":
|
523 |
+
df_string = data.to_string()
|
524 |
+
data_description = "Excel sheet data"
|
525 |
+
else: # PDF or Word document
|
526 |
+
df_string = data
|
527 |
+
data_description = "document content"
|
528 |
+
|
529 |
+
prompt = f"""You are an AI assistant specialized in analyzing {data_description}. You have access to the following data:
|
530 |
+
|
531 |
+
{df_string}
|
532 |
+
|
533 |
+
Based on this data, please answer the following question:
|
534 |
+
{user_question}
|
535 |
+
|
536 |
+
Provide a detailed and accurate answer based on the given data. If the answer cannot be directly inferred from the data, provide the best possible response based on the available information and your general knowledge about data analysis."""
|
537 |
+
|
538 |
+
response = client.chat.completions.create(
|
539 |
+
model="gpt-4o-mini",
|
540 |
+
messages=[
|
541 |
+
{"role": "system", "content": f"You are a data analysis expert skilled in interpreting {data_description}."},
|
542 |
+
{"role": "user", "content": prompt}
|
543 |
+
]
|
544 |
+
)
|
545 |
+
|
546 |
+
return response.choices[0].message.content
|
547 |
+
|
548 |
+
def extract_challan_data(pdf_text):
|
549 |
+
data = {}
|
550 |
+
patterns = {
|
551 |
+
'ITNS No.': r'ITNS No\.\s*:\s*(\d+)',
|
552 |
+
'TAN': r'TAN\s*:\s*(\w+)',
|
553 |
+
'Name': r'Name\s*:\s*(.+)',
|
554 |
+
'Assessment Year': r'Assessment Year\s*:\s*(\d{4}-\d{2})',
|
555 |
+
'Financial Year': r'Financial Year\s*:\s*(\d{4}-\d{2})',
|
556 |
+
'Amount': r'Amount \(in Rs\.\)\s*:\s*₹\s*([\d,]+)',
|
557 |
+
'CIN': r'CIN\s*:\s*(\w+)',
|
558 |
+
'Date of Deposit': r'Date of Deposit\s*:\s*(\d{2}-\w{3}-\d{4})',
|
559 |
+
'Challan No': r'Challan No\s*:\s*(\d+)',
|
560 |
+
}
|
561 |
+
|
562 |
+
for key, pattern in patterns.items():
|
563 |
+
match = re.search(pattern, pdf_text)
|
564 |
+
if match:
|
565 |
+
data[key] = match.group(1)
|
566 |
+
else:
|
567 |
+
data[key] = 'N/A'
|
568 |
+
|
569 |
+
return data
|
570 |
+
|
571 |
+
def process_challan_pdfs(pdf_files):
|
572 |
+
all_data = []
|
573 |
+
for pdf_file in pdf_files:
|
574 |
+
pdf_text = process_pdf(pdf_file)
|
575 |
+
challan_data = extract_challan_data(pdf_text)
|
576 |
+
all_data.append(challan_data)
|
577 |
+
|
578 |
+
df = pd.DataFrame(all_data)
|
579 |
+
return df
|
580 |
+
|
581 |
+
def process_file_with_assistant(file, file_type, category, reports_needed, user_feedback):
|
582 |
+
print(f"Starting {file_type} processing with Assistant")
|
583 |
+
try:
|
584 |
+
# Upload the file to OpenAI
|
585 |
+
uploaded_file = client.files.create(
|
586 |
+
file=file,
|
587 |
+
purpose='assistants'
|
588 |
+
)
|
589 |
+
print(f"File uploaded successfully. File ID: {uploaded_file.id}")
|
590 |
+
|
591 |
+
# Create an assistant
|
592 |
+
assistant = client.beta.assistants.create(
|
593 |
+
name=f"{file_type} Analyzer",
|
594 |
+
instructions=f"You are an expert in analyzing {file_type} files, focusing on {category}. Provide insights and summaries of the content based on the following reports: {', '.join(reports_needed)}. Consider the user's previous feedback: {user_feedback}",
|
595 |
+
model="gpt-4o",
|
596 |
+
tools=[{"type": "file_search"}]
|
597 |
+
)
|
598 |
+
print(f"Assistant created. Assistant ID: {assistant.id}")
|
599 |
+
|
600 |
+
# Create a thread
|
601 |
+
thread = client.beta.threads.create()
|
602 |
+
print(f"Thread created. Thread ID: {thread.id}")
|
603 |
+
|
604 |
+
# Add a message to the thread with the file attachment
|
605 |
+
message = client.beta.threads.messages.create(
|
606 |
+
thread_id=thread.id,
|
607 |
+
role="user",
|
608 |
+
content=f"Please analyze this file and provide insights for the {category} category, focusing on the following reports: {', '.join(reports_needed)}.",
|
609 |
+
attachments=[
|
610 |
+
{"file_id": uploaded_file.id, "tools": [{"type": "file_search"}]}
|
611 |
+
]
|
612 |
+
)
|
613 |
+
print(f"Message added to thread. Message ID: {message.id}")
|
614 |
+
|
615 |
+
# Run the assistant
|
616 |
+
run = client.beta.threads.runs.create(
|
617 |
+
thread_id=thread.id,
|
618 |
+
assistant_id=assistant.id
|
619 |
+
)
|
620 |
+
print(f"Run created. Run ID: {run.id}")
|
621 |
+
|
622 |
+
# Wait for the run to complete
|
623 |
+
while run.status != 'completed':
|
624 |
+
run = client.beta.threads.runs.retrieve(thread_id=thread.id, run_id=run.id)
|
625 |
+
print(f"Run status: {run.status}")
|
626 |
+
time.sleep(1)
|
627 |
+
|
628 |
+
# Retrieve the messages
|
629 |
+
messages = client.beta.threads.messages.list(thread_id=thread.id)
|
630 |
+
|
631 |
+
# Extract the assistant's response
|
632 |
+
analysis_result = next((msg.content[0].text.value for msg in messages if msg.role == 'assistant'), None)
|
633 |
+
|
634 |
+
print(f"{file_type} analysis completed successfully")
|
635 |
+
return analysis_result
|
636 |
+
|
637 |
+
except Exception as e:
|
638 |
+
print(f"Error in process_file_with_assistant: {str(e)}")
|
639 |
+
print(traceback.format_exc())
|
640 |
+
return None
|
641 |
+
|
642 |
+
# Streamlit UI
|
643 |
+
st.set_page_config(layout="wide")
|
644 |
+
st.title("Document Processing, Chat, Excel Filling, and Analysis")
|
645 |
+
|
646 |
+
# Add login/signup system
|
647 |
+
if "user" not in st.session_state:
|
648 |
+
st.session_state.user = None
|
649 |
+
|
650 |
+
def login(username, password):
|
651 |
+
user = users_collection.find_one({"username": username})
|
652 |
+
if user and user.get("password") == password:
|
653 |
+
return user
|
654 |
+
return None
|
655 |
+
|
656 |
+
def signup(username, password):
|
657 |
+
existing_user = users_collection.find_one({"username": username})
|
658 |
+
if existing_user:
|
659 |
+
return False
|
660 |
+
users_collection.insert_one({
|
661 |
+
"username": username,
|
662 |
+
"password": password,
|
663 |
+
"feedback": [] # Initialize an empty list for feedback
|
664 |
+
})
|
665 |
+
return True
|
666 |
+
|
667 |
+
def store_feedback(username, feedback):
|
668 |
+
users_collection.update_one(
|
669 |
+
{"username": username},
|
670 |
+
{"$push": {"feedback": feedback}},
|
671 |
+
upsert=True
|
672 |
+
)
|
673 |
+
|
674 |
+
# Login/Signup form
|
675 |
+
if not st.session_state.user:
|
676 |
+
tab1, tab2 = st.tabs(["Login", "Sign Up"])
|
677 |
+
|
678 |
+
with tab1:
|
679 |
+
st.subheader("Login")
|
680 |
+
login_username = st.text_input("Username", key="login_username")
|
681 |
+
login_password = st.text_input("Password", type="password", key="login_password")
|
682 |
+
if st.button("Login"):
|
683 |
+
user = login(login_username, login_password)
|
684 |
+
if user:
|
685 |
+
st.session_state.user = user
|
686 |
+
st.success("Logged in successfully!")
|
687 |
+
st.rerun()
|
688 |
+
else:
|
689 |
+
st.error("Invalid username or password")
|
690 |
+
|
691 |
+
with tab2:
|
692 |
+
st.subheader("Sign Up")
|
693 |
+
signup_username = st.text_input("Username", key="signup_username")
|
694 |
+
signup_password = st.text_input("Password", type="password", key="signup_password")
|
695 |
+
if st.button("Sign Up"):
|
696 |
+
if signup(signup_username, signup_password):
|
697 |
+
st.success("Account created successfully! Please log in.")
|
698 |
+
else:
|
699 |
+
st.error("Username already exists")
|
700 |
+
|
701 |
+
if st.session_state.user:
|
702 |
+
st.write(f"Welcome, {st.session_state.user['username']}!")
|
703 |
+
|
704 |
+
# Create four tabs
|
705 |
+
tab1, tab2, tab3, tab4 = st.tabs(["Upload, Chat, and Source", "Excel Processing", "Excel Analysis and Chat", "Challan Processing"])
|
706 |
+
|
707 |
+
with tab1:
|
708 |
+
st.subheader("Upload")
|
709 |
+
|
710 |
+
# PDF upload
|
711 |
+
uploaded_files = st.file_uploader("Choose one or more PDF files", type="pdf", accept_multiple_files=True)
|
712 |
+
|
713 |
+
# Web Link input
|
714 |
+
web_link = st.text_input("Enter a Web Link")
|
715 |
+
|
716 |
+
# YouTube Links input
|
717 |
+
youtube_links = st.text_area("Enter YouTube Links (one per line)")
|
718 |
+
|
719 |
+
if st.button("Process All"):
|
720 |
+
st.session_state.upload_progress = st.progress(0)
|
721 |
+
with st.spinner("Processing uploads..."):
|
722 |
+
results = []
|
723 |
+
if uploaded_files:
|
724 |
+
for file in uploaded_files:
|
725 |
+
pdf_result = process_upload("PDF", file, file.name)
|
726 |
+
results.append(pdf_result)
|
727 |
+
if web_link:
|
728 |
+
web_result = process_upload("Web Link", web_link)
|
729 |
+
results.append(web_result)
|
730 |
+
if youtube_links:
|
731 |
+
youtube_links_list = re.split(r'[\n\r]+', youtube_links.strip())
|
732 |
+
youtube_results = process_youtube_links(youtube_links_list)
|
733 |
+
results.extend(youtube_results)
|
734 |
+
|
735 |
+
if results:
|
736 |
+
for result in results:
|
737 |
+
st.success(result)
|
738 |
+
else:
|
739 |
+
st.warning("No content uploaded. Please provide at least one input.")
|
740 |
+
st.session_state.upload_progress.empty()
|
741 |
+
|
742 |
+
st.subheader("Chat")
|
743 |
+
user_input = st.text_input("Ask a question about the uploaded content:")
|
744 |
+
if st.button("Send"):
|
745 |
+
if user_input:
|
746 |
+
print(f"Sending user input: {user_input}")
|
747 |
+
st.session_state.chat_progress = st.progress(0)
|
748 |
+
response, sources = chat_with_ai(user_input)
|
749 |
+
st.session_state.chat_progress.progress(1.0)
|
750 |
+
st.markdown("**You:** " + user_input)
|
751 |
+
st.markdown("**AI:** " + response)
|
752 |
+
|
753 |
+
# Store sources in session state for display in the Source Chunks section
|
754 |
+
st.session_state.sources = sources
|
755 |
+
st.session_state.chat_progress.empty()
|
756 |
+
else:
|
757 |
+
print("Empty user input")
|
758 |
+
st.warning("Please enter a question.")
|
759 |
+
|
760 |
+
st.subheader("Source Chunks")
|
761 |
+
if 'sources' in st.session_state and st.session_state.sources:
|
762 |
+
for i, source in enumerate(st.session_state.sources, 1):
|
763 |
+
with st.expander(f"Source {i} - {source['type']} ({source['doc_name']}) - Score: {source['score']}"):
|
764 |
+
st.markdown(f"**Chunk Index:** {source['chunk_index']}")
|
765 |
+
st.text(source['text'])
|
766 |
+
else:
|
767 |
+
st.info("Ask a question to see source chunks here.")
|
768 |
+
|
769 |
+
with tab2:
|
770 |
+
st.subheader("Excel Processing")
|
771 |
+
uploaded_excel = st.file_uploader("Choose an Excel file", type=["xlsx", "xls"])
|
772 |
+
|
773 |
+
if uploaded_excel is not None:
|
774 |
+
dfs = process_excel(uploaded_excel)
|
775 |
+
|
776 |
+
# Display preview of each sheet
|
777 |
+
for sheet_name, df in dfs.items():
|
778 |
+
if not df.empty:
|
779 |
+
st.write(f"Preview of {sheet_name}:")
|
780 |
+
st.dataframe(df.head())
|
781 |
+
|
782 |
+
# Select the main sheet for processing
|
783 |
+
main_sheet = st.selectbox("Select the main sheet to fill", list(dfs.keys()))
|
784 |
+
main_df = dfs[main_sheet]
|
785 |
+
|
786 |
+
if st.button("Fill Missing Data"):
|
787 |
+
with st.spinner("Analyzing data and generating formulas..."):
|
788 |
+
other_dfs = {name: df for name, df in dfs.items() if name != main_sheet}
|
789 |
+
formulas = analyze_and_generate_formulas(main_df, other_dfs)
|
790 |
+
|
791 |
+
if formulas:
|
792 |
+
st.write("Generated Formulas:")
|
793 |
+
for column, formula in formulas.items():
|
794 |
+
st.code(f"{column}: {formula}")
|
795 |
+
|
796 |
+
filled_df = apply_formulas(main_df, other_dfs, formulas)
|
797 |
+
|
798 |
+
st.write("Filled Excel Data:")
|
799 |
+
st.dataframe(filled_df)
|
800 |
+
|
801 |
+
# Provide download link for the filled Excel file
|
802 |
+
buffer = io.BytesIO()
|
803 |
+
with pd.ExcelWriter(buffer, engine='xlsxwriter') as writer:
|
804 |
+
filled_df.to_excel(writer, index=False, sheet_name=main_sheet)
|
805 |
+
# Also save other sheets
|
806 |
+
for sheet_name, df in dfs.items():
|
807 |
+
if sheet_name != main_sheet:
|
808 |
+
df.to_excel(writer, index=False, sheet_name=sheet_name)
|
809 |
+
buffer.seek(0)
|
810 |
+
st.download_button(
|
811 |
+
label="Download Filled Excel",
|
812 |
+
data=buffer,
|
813 |
+
file_name="filled_excel.xlsx",
|
814 |
+
mime="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
|
815 |
+
)
|
816 |
+
else:
|
817 |
+
st.warning("No formulas were generated. The data might not have clear patterns for filling missing values.")
|
818 |
+
|
819 |
+
with tab3:
|
820 |
+
st.subheader("Excel and Document Analysis")
|
821 |
+
uploaded_file = st.file_uploader(
|
822 |
+
"Choose an Excel file, PDF, or Word document for analysis",
|
823 |
+
type=["xlsx", "xls", "pdf", "docx", "doc"],
|
824 |
+
key="excel_analysis_uploader"
|
825 |
+
)
|
826 |
+
|
827 |
+
if uploaded_file is not None:
|
828 |
+
file_type, content = process_uploaded_file(uploaded_file)
|
829 |
+
|
830 |
+
if file_type is not None and content is not None:
|
831 |
+
if file_type == "excel":
|
832 |
+
dfs = content
|
833 |
+
sheet_names = list(dfs.keys())
|
834 |
+
selected_sheet = st.selectbox("Select a sheet for analysis", sheet_names)
|
835 |
+
|
836 |
+
df_to_analyze = dfs[selected_sheet]
|
837 |
+
st.write(f"Preview of {selected_sheet}:")
|
838 |
+
st.dataframe(df_to_analyze.head())
|
839 |
+
|
840 |
+
st.session_state.analyzed_data = df_to_analyze
|
841 |
+
analysis_method = "OCR" # Default to OCR for Excel files
|
842 |
+
elif file_type == "text":
|
843 |
+
st.write("Document content preview:")
|
844 |
+
preview_text = content[:500] + "..."
|
845 |
+
st.text(preview_text) # Show first 500 characters
|
846 |
+
|
847 |
+
# Add option to choose between OCR and Assistants API for PDF/Word
|
848 |
+
analysis_method = st.radio("Choose analysis method:", ("OCR", "OpenAI Assistants API"))
|
849 |
+
|
850 |
+
st.session_state.analyzed_data = content
|
851 |
+
|
852 |
+
# Add category selection with "Default" option
|
853 |
+
categories = list(get_category_reports().keys())
|
854 |
+
if "Default" in categories:
|
855 |
+
categories.remove("Default")
|
856 |
+
categories = ["Default"] + categories
|
857 |
+
selected_category = st.selectbox("Select analysis category", categories)
|
858 |
+
|
859 |
+
if st.button("Analyze with GPT"):
|
860 |
+
with st.spinner("Analyzing data... This may take a while for large datasets."):
|
861 |
+
user_feedback = get_user_feedback(st.session_state.user["_id"])
|
862 |
+
reports_needed = get_category_reports().get(selected_category, [])
|
863 |
+
|
864 |
+
if file_type == "excel":
|
865 |
+
analysis_result = analyze_excel_with_gpt(st.session_state.analyzed_data, selected_sheet, user_feedback, selected_category, reports_needed)
|
866 |
+
else: # PDF or Word document
|
867 |
+
if analysis_method == "OpenAI Assistants API":
|
868 |
+
analysis_result = process_file_with_assistant(uploaded_file, "PDF", selected_category, reports_needed, user_feedback)
|
869 |
+
else:
|
870 |
+
analysis_result = analyze_document_with_gpt(st.session_state.analyzed_data, user_feedback, selected_category, reports_needed)
|
871 |
+
|
872 |
+
st.markdown("## Analysis Results")
|
873 |
+
st.markdown(analysis_result)
|
874 |
+
|
875 |
+
st.session_state.analysis_result = analysis_result
|
876 |
+
|
877 |
+
if file_type == "excel":
|
878 |
+
pdf_path = excel_to_pdf(st.session_state.analyzed_data)
|
879 |
+
with open(pdf_path, "rb") as pdf_file:
|
880 |
+
pdf_bytes = pdf_file.read()
|
881 |
+
st.download_button(
|
882 |
+
label="Download Excel PDF version",
|
883 |
+
data=pdf_bytes,
|
884 |
+
file_name="excel_data.pdf",
|
885 |
+
mime="application/pdf"
|
886 |
+
)
|
887 |
+
|
888 |
+
# Feedback section
|
889 |
+
st.markdown("## Feedback")
|
890 |
+
new_feedback = st.text_area("Provide feedback or additional insights about the analysis:")
|
891 |
+
if st.button("Submit Feedback"):
|
892 |
+
if new_feedback:
|
893 |
+
user = users_collection.find_one({"_id": st.session_state.user["_id"]})
|
894 |
+
existing_feedback = user.get("feedback", "")
|
895 |
+
|
896 |
+
updated_feedback = f"{existing_feedback}\n{new_feedback}" if existing_feedback else new_feedback
|
897 |
+
|
898 |
+
users_collection.update_one(
|
899 |
+
{"_id": st.session_state.user["_id"]},
|
900 |
+
{"$set": {"feedback": updated_feedback}}
|
901 |
+
)
|
902 |
+
st.success("Feedback submitted successfully!")
|
903 |
+
else:
|
904 |
+
st.warning("Please enter some feedback before submitting.")
|
905 |
+
|
906 |
+
# Chat with Data section
|
907 |
+
st.markdown("## Chat with Data")
|
908 |
+
with st.form(key='chat_form'):
|
909 |
+
user_question = st.text_input("Ask a question about the data:")
|
910 |
+
chat_submit_button = st.form_submit_button(label='Get Answer')
|
911 |
+
|
912 |
+
if chat_submit_button:
|
913 |
+
if user_question:
|
914 |
+
with st.spinner("Analyzing your question..."):
|
915 |
+
answer = chat_with_data(st.session_state.analyzed_data, user_question, file_type)
|
916 |
+
st.markdown("### Answer")
|
917 |
+
st.markdown(answer)
|
918 |
+
else:
|
919 |
+
st.warning("Please enter a question about the data.")
|
920 |
+
else:
|
921 |
+
st.error("Unable to process the uploaded file. Please check the file format and try again.")
|
922 |
+
|
923 |
+
with tab4:
|
924 |
+
st.subheader("Challan Processing")
|
925 |
+
|
926 |
+
challan_pdfs = st.file_uploader(
|
927 |
+
"Choose Challan PDF files",
|
928 |
+
type="pdf",
|
929 |
+
accept_multiple_files=True,
|
930 |
+
key="challan_processing_uploader"
|
931 |
+
)
|
932 |
+
|
933 |
+
if st.button("Process Challan PDFs"):
|
934 |
+
if challan_pdfs:
|
935 |
+
with st.spinner("Processing Challan PDFs..."):
|
936 |
+
challan_df = process_challan_pdfs(challan_pdfs)
|
937 |
+
st.write("Challan Data:")
|
938 |
+
st.dataframe(challan_df)
|
939 |
+
|
940 |
+
buffer = io.BytesIO()
|
941 |
+
with pd.ExcelWriter(buffer, engine='xlsxwriter') as writer:
|
942 |
+
challan_df.to_excel(writer, index=False, sheet_name='Challan Data')
|
943 |
+
buffer.seek(0)
|
944 |
+
st.download_button(
|
945 |
+
label="Download Challan Excel",
|
946 |
+
data=buffer,
|
947 |
+
file_name="challan_data.xlsx",
|
948 |
+
mime="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
|
949 |
+
)
|
950 |
+
|
951 |
+
st.success("Challan PDFs processed successfully")
|
952 |
+
else:
|
953 |
+
st.warning("No Challan PDFs uploaded. Please choose at least one PDF file.")
|
Finance-RAG/artifacts/Chat.txt
ADDED
The diff for this file is too large to render.
See raw diff
|
|
Finance-RAG/artifacts/bm25_values.json
ADDED
@@ -0,0 +1 @@
|
|
|
|
|
1 |
+
{"avgdl": 131.0, "n_docs": 125, "doc_freq": {"indices": [1021034567, 1454980414, 3662309742, 2217217400, 798390861, 2257684172, 364080503, 420652329, 2707362363, 2788967896, 3449948193, 751038381, 4022658749, 2650797237, 3184106641, 4256697198, 4214497192, 975958667, 2203845707, 3780320928, 4181762184, 1256513470, 923832745, 1577783582, 3515787133, 2970451732, 1762271436, 1368212003, 1235337510, 3614898122, 3623906278, 2313181365, 1866681274, 2442379174, 4293690404, 3173410128, 248496370, 483756523, 3137721469, 2288100307, 679161492, 963086208, 3501375171, 2857490624, 3442505729, 959934444, 2500277244, 395655728, 636328848, 3345976090, 2557402861, 1565814976, 3303976948, 4205125344, 2087117142, 3950786067, 3366506348, 2018632456, 3547277221, 1458901273, 1653055373, 1287706142, 2545146156, 1192017098, 403603410, 4051743857, 3819098157, 1884388439, 3634433397, 3454715413, 2510634953, 3988319771, 2741297702, 3441401522, 2997766306, 2560167400, 1117261085, 475514102, 318325784, 1935690415, 1072751960, 130713793, 2020981834, 3923295591, 536249406, 1903655411, 2771712084, 2689071136, 2073620283, 750243, 3764782562, 4064198169, 2913370233, 3295074444, 4115403471, 1114599853, 1996537235, 622767579, 837133632, 3382308661, 997012898, 4173428777, 1612531086, 712299080, 1696616304, 4238911163, 684970627, 2270570485, 4201747257, 2115811026, 3715594583, 939657615, 2490526110, 318895593, 4078099288, 3545686470, 1971192742, 1948686422, 1904930356, 4249627615, 2915038981, 996076929, 770173338, 4112104824, 2441571111, 3981855590, 4191199403, 567629540, 2094177973, 4206423020, 2924029937, 3904829042, 257116880, 2236453805, 2560286898, 1316065000, 3136791544, 2375493166, 840884889, 1878949369, 2755283679, 2189814888, 4233925054, 2541172146, 2030390818, 2452818717, 253954487, 47115911, 2908427063, 899802442, 3266778159, 1289314367, 232034543, 70273945, 3701159945, 3313706720, 185763488, 4246189485, 2152142946, 4060722683, 3800896210, 1091705843, 1081156857, 490211949, 596743439, 1739635433, 2679536720, 4193046578, 2571639767, 118212969, 1554880932, 3875167354, 611474860, 3886697187, 1773147772, 3314016017, 1296424812, 4179405343, 2301427609, 2352464484, 3159897040, 1444856033, 3751557719, 202421782, 3196595689, 2722362853, 1727035794, 2797379193, 1131637966, 2298747703, 2871232097, 3110868845, 155898861, 3919354315, 91223998, 752895054, 2920317225, 569047032, 3324292644, 1639487260, 705868017, 3941739082, 877304949, 664789781, 3490260866, 1257865791, 2428187528, 3726289458, 3160213544, 2671877867, 2670090644, 4158184310, 3717262626, 4106717676, 2348582311, 3851217254, 526344119, 1483407135, 1950663011, 388908256, 1112031443, 1096441908, 2295482173, 682117108, 1830646559, 1980985811, 1392430834, 2814226305, 1314458390, 3151107800, 3656056540, 2049222729, 344160443, 2589650044, 2799270951, 3780090702, 397049589, 3215337761, 2130627626, 1711579224, 2564673975, 3725200190, 3029698579, 2566038170, 2194983448, 2791622851, 3867649340, 4282028867, 2799203408, 2575682837, 26897902, 775368311, 4096764877, 3413443226, 175142257, 2268050145, 2646213291, 613153351, 327407896, 2287504240, 2945906318, 3015165939, 3402432764, 913078775, 3009698197, 2474874971, 2426593727, 1195989500, 1963234965, 2014097110, 1802985854, 832098838, 4269975048, 3812103426, 1334131551, 2991982070, 2529390902, 574566247, 2872949654, 2406802669, 3928038441, 270412435, 3194453705, 1117377358, 3483282318, 90030643, 133816045, 1162130333, 741510003, 2953989488, 2514321228, 548955463, 4232745734, 1558403699, 2895605406, 989116115, 1706052786, 958659146, 1034394088, 1745114270, 245221680, 640124220, 2856928418, 2838403054, 3178849318, 3583993711, 100532018, 2871008955, 206945987, 4240885550, 3555997862, 2531392473, 3401591458, 2830324691, 150695120, 2012898701, 2757029170, 2365106341, 2032101475, 3637875462, 2923042786, 499576795, 2764870452, 1786604015, 961319078, 1738701361, 4010165003, 348891404, 639288724, 4146944219, 1081392422, 95223715, 2348005584, 3086851070, 1350496995, 3913711300, 1240248262, 3284199863, 395793395, 3294113796, 3238020449, 2450617228, 4227221740, 806976768, 698625569, 1552620746, 4126600468, 1970079093, 2435212367, 497588539, 1832578980, 2016484071, 2030590383, 150282422, 2019031726, 2815972317, 2602715729, 2239134243, 2354296186, 3740340384, 4052413758, 3431164258, 1388280598, 182194458, 3988185726, 269160524, 262840313, 2566440236, 4060205056, 569308866, 3788552753, 537661565, 3631500069, 2484513939, 1372199004, 2940655442, 2458826739, 3609399819, 294778681, 558074401, 3566562695, 4094263556, 1551106550, 615978258, 3031056277, 4068491112, 1277427225, 1332474969, 1463633647, 61930844, 1088214061, 2115116630, 2002612373, 2836570682, 4032247756, 538856249, 2217145755, 122850963, 4259972761, 2717217932, 4173742222, 1853176582, 3525417812, 956992893, 839427432, 3734338810, 1272688357, 2263091519, 1090497704, 1236542976, 3209516291, 2206024373, 214084523, 1239368365, 3996785687, 3857356698, 989509788, 2542944140, 3313717465, 3538073998, 3476647774, 4146668087, 1104244167, 2541935877, 1762032986, 1690623792, 1623780900, 3488055477, 859229416, 2116029891, 380541707, 4126688549, 1079027559, 3915229131, 401258451, 2641612105, 4027543957, 1212879818, 997512866, 2892062428, 1578014742, 564731308, 2350854469, 2882792817, 664667393, 905234867, 3685696496, 4102578029, 2361787631, 54081900, 570245443, 2687174735, 4186256544, 907547314, 3255297991, 592326839, 2994235176, 4078800703, 987377478, 1319288094, 1790252449, 3437877431, 3520027802, 1685761084, 953824239, 2806668873, 1306918158, 836982580, 916214203, 758850910, 2876684594, 3066577729, 1563718956, 4286132664, 1021972251, 115441729, 2391722386, 2966842999, 1920135276, 1034183227, 3452949137, 2225624884, 1621337241, 2996671233, 3444258836, 3172858508, 2951258741, 3725872281, 2039377815, 4108725818, 3455813968, 3997133275, 1236385344, 2135986242, 14784032, 1827736854, 845321163, 691409538, 3525523449, 659326392, 2786666077, 2562495414, 1070064657, 4247117526, 3796074982, 254839692, 4218656810, 3578070748, 1678955722, 1457721415, 550510908, 2638548021, 709260326, 3741620795, 3438886076, 189262593, 3559232987, 4065007249, 3927490055, 1975257448, 2044745418, 2180406531, 422208903, 4018598106, 3469107893, 1612003016, 2573582857, 2167364491, 3669011020, 575755316, 1200518484, 822745112, 2516331022, 260499195, 1796529793, 1974594591, 3020339199, 2305334529, 2203090375, 1062750627, 638596201, 1706587157, 3119836432, 3660156378, 3695721515, 2150714867, 3047429373, 3973561477, 2768410132, 2794782940, 2220717165, 2237944795, 1308688855, 1571837593, 2599925349, 1333205585, 3739924922, 2228746633, 1793137844, 1714760135, 3658895392, 2175737161, 2797188186, 3197025135, 4273941665, 820773949, 73902273, 659280773, 1713488374, 4051235863, 620220149, 2845015760, 1318954659, 2516804095, 3876873682, 2509520141, 1542009946, 919171525, 2142141949, 997549709, 3471378517, 3774761357, 2351685495, 3440463439, 1097973018, 1837728678, 1967589093, 2999287691, 1337453135, 4210889658, 2405728333, 3923787185, 3377905009, 3286166600, 82883857, 1452127806, 2751533102, 3831243209, 2579408843, 3537839420, 4030145240, 2630770281, 1246703071, 1623850183, 253786804, 1111599271, 3557534174, 3247030105, 534752004, 1990448937, 2669074641, 1214231007, 997476635, 2487889501, 4063744503, 3058401716, 4094463266, 509621098, 4077251510, 2280702716, 2136544277, 437367475, 2310243035, 2409698815, 912854380, 1021187622, 1360733048, 3695069830, 337330324, 332723732, 1709343116, 2712920252, 3618358963, 1932972436, 47102758, 1311394734, 3614749990, 1044312602, 352293261, 1860783634, 1617655253, 459695680, 4272757276, 964745590, 300397944, 3887247451, 1228615861, 147691773, 3737300892, 3870245702, 2482114291, 1418759671, 34379837, 2408696830, 3689307051, 2901150436, 3176141921, 4291385346, 275574541, 802617321, 1553167345, 2930274378, 4081531861, 403938802, 1172383616, 3253279657, 2660310214, 2012469550, 662754433, 212438410, 2953188479, 683459885, 3190124294, 149060006, 4249943136, 3381074633, 2193283912, 842430915, 116350199, 1181836714, 3388075432, 614665414, 3959618709, 1318134775, 4272136130, 2736802367, 3514344499, 2999931892, 1666014760, 2232832807, 3639391104, 2231220596, 3035066612, 1804363299, 3180462103, 2139336747, 3881069374, 111228364, 2436057914, 1624942512, 702881754, 374114094, 2335032033, 1243829275, 1974987360, 853122056, 1404934148, 2136405083, 441260191, 1993503267, 846361587, 264741300, 75480261, 2598234228, 1522948780, 2308390441, 281319581, 3704047462, 699049568, 1748033122, 3813299610, 2719417954, 1098758338, 2608927722, 327841461, 4075116728, 744685125, 2753177719, 163714009, 519878365, 3211308883, 1853582658, 1794787556, 2852256900, 3324524666, 2260941283, 774734253, 1746254371, 4191350549, 3318719970, 2918366455, 3642524647, 31342119, 142031186, 1711044967, 445633476, 3867408905, 1182424816, 1244756286, 2545935929, 4273174761, 1509042925, 616351661, 3080486524, 2026541654, 1246280156, 1061809485, 3602582777, 2583006184, 4003766845, 4161811491, 468707856, 4261826499, 2866278071, 1853198146, 4064148579, 1955345431, 452255852, 301705055, 3741174264, 915439510, 440609716, 3289512026, 30706311, 906720305, 737178442, 631582644, 728165346, 1839695642, 2114385920, 1363043438, 1489370732, 486549773, 1940846275, 3334473096, 1137177623, 1561600913, 4229140433, 640681670, 4044349899, 3535910499, 2265006919, 613148321, 2139857658, 2540822849, 1536956927, 2874441055, 2998016548, 4129357894, 3553535066, 3796669908, 124635254, 2678802000, 3351982627, 580887246, 2066971792, 3242200208, 2645357763, 1463597126, 2465027848, 841855028, 1678348498, 1350591508, 4174045351, 1531474321, 2584450256, 163641640, 342691481, 904732330, 1219032011, 1026214564, 665136687, 2173101216, 1408770214, 902695515, 2733467792, 3578741850, 1695671356, 4151497484, 817323683, 3361040556, 616362826, 1458211656, 3576316214, 1973777711, 3186616370, 632299704, 778641487, 3956902843, 925649020, 3737317655, 4145867034, 180587303, 760898494, 418958690, 3089878517, 1975148541, 2668977447, 1947820556, 2497647768, 3507810899, 1800729743, 3131402060, 3494909076, 198527388, 2191644555, 1961024030, 4049115728, 1960712366, 2677164652, 2490533594, 877300803, 3414190804, 23272723, 2297364852, 1871677193, 3401175220, 1565218773, 1620321068, 4282911669, 214637379, 2787701381, 231857734, 2179962017, 754352942, 3791876903, 749129358, 1605216796, 3126390891, 2747335425, 2725713990, 543259558, 1844461674, 2371442522, 172652411, 1537230434, 4220128678, 1777733683, 887967055, 3682083305, 1545193637, 3838770754, 3411418812, 1707350732, 687335188, 3821917617, 2991656097, 414294961, 720173232, 3804538644, 440359455, 195324156, 920707857, 1962653560, 3352945215, 301030427, 372182521, 1364383302, 4004851965, 1964299612, 3725535981, 2037250279, 696515614, 2926691847, 3171114879, 3987277541, 4131135811, 3744277684, 1989892411, 1978398805, 3530670207, 2486746700, 1994063850, 3778137224, 1977109837, 4150915742, 930883039, 1028984916, 2935540726, 927153649, 1770506646, 121182782, 3061787125, 294264100, 4118380002, 2747057832, 1180690720, 166093682, 407983593, 193452503, 185526223, 1099042301, 2892675647, 3703325647, 2851137560, 4240559916, 3377652727, 1207234426, 1019838425, 1321762707, 3709388982, 1564465246, 1050319643, 4282621215, 3565335251, 1652275073, 1512720756, 2580097488, 974372365, 2045916435, 2840212248, 1786548735, 1424671076, 1096618103, 561261590, 1430125705, 1286856114, 3731741184, 662216322, 1717991430, 326127912, 935313282, 3196577431, 217630715, 1106799526, 2503164535, 3377004681, 2342175534, 2707757268, 1841156733, 1255637661, 1865476978, 113765032, 1050980247, 1865887525, 930102859, 449651267, 1312345749, 3806153820, 442064690, 2046658185, 3434143855, 497703773, 3112307346, 217369395, 3707530499, 2468374363, 2910905616, 2942131635, 3607577929, 2578007438, 2872668384, 888000370, 1808902238, 1376673955, 41435889, 4078964492, 614773986, 3277239078, 2995430201, 743435112, 2830370693, 4003108830, 4071218396, 3789471481, 107450748, 1423551419, 4286712296, 1271411175, 2905565758, 566624108, 2304255058, 1879610850, 3841429135, 3966249623, 994666259, 3797557799, 695926169, 573216872, 1372955919, 3688822001, 2539030805, 862607732, 1830401145, 1428662464, 2019785588, 123462699, 324964102, 1777960979, 3874518728, 3153294166, 1802853965, 1148177069, 1477105254, 3347247730, 2028044069, 3571741442, 4173216340, 1177748882, 223412490, 2976135297, 2148073227, 1976498608, 2253461213, 65094886, 2772066268, 1833938074, 2325784421, 2608702916, 3508911095, 677727288, 719013046, 309400477, 3786070417, 74256320, 1141099794, 1300596145, 2519853829, 3305235960, 4037162160, 1401966460, 1572399708, 1491351846, 703245684, 997052087, 446617493, 339478471, 1470654964, 3357039338, 1014127006, 1281345964, 1704311633, 3609117281, 1031674594, 1033723920, 1360744857, 1875908499, 1789703446, 1076181166, 2561703420, 1918041394, 1692322133, 4226592599, 3129005739, 2701992530, 3371595112, 205635131, 2868293341, 1990266732, 2674658271, 3056162231, 2819360576, 76290613, 2898225755, 3252314809, 1057239507, 1328615756, 3016213670, 4072206095, 1784538203, 192877707, 3905920373, 2912884399, 3040100084, 1002339664, 1939799981, 652598628, 2674921959, 3833758145, 2850407460, 1783685817, 2511134412, 2395279267, 753937198, 3281339372, 1357846105, 1473687757, 4146010875, 4290449415, 2819878408, 1035020093, 1123840555, 180277816, 3452862550, 3311132764, 642138030, 3684745362, 2255193489, 2443126305, 148207794, 1305218356, 2830437215, 1844405519, 2253515411, 2673623443, 3432864597, 3015825689, 1286780356, 1036492046, 3603372531, 1980837581, 3460335762, 2283442809, 4159542630, 1166735067, 1902488443, 3988684505, 434507211, 2137479269, 3076736765, 3882113197, 239161542, 648501015, 3871720206, 633257171, 3659522595, 3396792551, 2548657752, 3803256308, 1210960293, 698998408, 3781512643, 2335912917, 3667013003, 3423274687, 3627550890, 3420564022, 2783546920, 3743430521, 1928848833, 4038522636, 3027968034, 1472062936, 3586802366, 3967169986, 4220927227, 2233892242, 2386266869, 1063320047, 3286862687, 409164144, 3886694538, 777885454, 1761334405, 3130583748, 3706248294, 3433143304, 2967788773, 459411296, 16796957, 607995987, 2755408749, 1538063088, 3933780523, 1431673852, 1647276219, 872508948, 1203995548, 722292439, 1191532796, 2911130080, 1767664469, 2562849904, 3218613111, 1601978260, 267723541, 3058462535, 23953077, 670124293, 1817543370, 701455177, 3305296187, 1909158714, 1646843365, 553238108, 1695374030, 186140916, 703717300, 625320497, 563585672, 3354101492, 3544702269, 2919262346, 2557289334, 1472004420, 3206411579, 550479775, 3218699675, 795647784, 2762761413, 1958247819, 3823892088, 1475669757, 2050456347, 2825766026, 39125515, 1408781209, 1848020007, 1078932941, 3101395336, 1254533690, 11563538, 3908605802, 1921621272, 1296773219, 699514751, 1679626713, 570652574, 4258355225, 4173979793, 4124818257, 408571802, 3614296607, 744779191, 1906283416, 1402184228, 3345519630, 3158801439, 4018346279, 3677720983, 4263284158, 3474479854, 1789042031, 3934274063, 3492571379, 1407898508, 2712931676, 768679706, 1153915709, 3921302413, 3358769376, 4153030385, 319172129, 3844522144, 3402301762, 692052014, 2251441648, 3748190670, 929241871, 2102668976, 518350612, 70440145, 1247504452, 2145365533, 1279209997, 1914624459, 2601498684, 1837495628, 3107196980, 2419346358, 822928508, 972528270, 3324227653, 458859209, 2345472352, 4191300951, 2269372292, 2055651091, 1445111490, 4031722285, 4283304985, 3408016047, 3502599827, 3742645591, 2723609106, 3547447186, 2990989170, 4285449496, 451368094, 290488243, 367490092, 2338697976, 586932639, 1338150097, 3174900812, 3778205279, 3182414933, 3251030277, 2600560175, 3354233777, 185547507, 3881720473, 3985184762, 2087367745, 1673618911, 3773303764, 3284862352, 2035475614, 1644075694, 3096200065, 794129062, 1128198904, 3787580939, 3063946649, 116628897, 1257682525, 3153893987, 3872118918, 3234134341, 1877738838, 3760517632, 4145065484, 3798698373, 1267513490, 1039260564, 1388583211, 3918493313, 3222497275, 4183835765, 280406134, 2373257806, 600061284, 1489078915, 124135962, 4219882198, 4265793861, 3796886850, 2875043960, 1433963656, 1336311870, 1551120200, 436757074, 3269254465, 246483041, 2303613713, 3735040880, 3515377842, 1533210021, 288190977, 3984502342, 3775485520, 1229781636, 3833322559, 1042440291, 702051550, 2033276763, 2420473801, 2083496860, 3069135178, 1031761608, 2307408050, 3160626773, 4250350860, 2361271937, 3647400625, 3080064868, 3567372611, 1506837206, 3537398643, 717653329, 3891556496, 1214258741, 4153398174, 3955408424, 180554566, 3355129947, 2758708783, 1360027385, 1026658409, 746419308, 3652963089, 1871711020, 1570645513, 2349927858, 1615682969, 2950284285, 1622591063, 2043142394, 3036742391, 3057023774, 2063761311, 1971985367, 3623439247, 1000129002, 3232878242, 374821798, 1646279392, 2054338899, 2848315406, 2900069745, 2420477432, 871617278, 4095958457, 4204430930, 1994398860, 3486394129, 286434387, 2561757799, 1427920598, 2035926655, 1615792474, 2177509083, 3425508159, 387298284, 2424766425, 3355546462, 766710245, 1036792120, 1623065834, 3589630101, 520409122, 2165730276, 1997014908, 2253821162, 2260292620, 753595076, 849820344, 1765639896, 3170325535, 3534645922, 2067848296, 2815579477, 1058501323, 1946772953, 1319287133, 3778852250, 1704236722, 2965229515, 2194093370, 2557508704, 3133460940, 1504846510, 2740018081, 2046009338, 3368723024, 3601174169, 3896517288, 269548239, 4238889041, 51800208, 2135526316, 2291919351, 2443074361, 3143659061, 3117886515, 1523929128, 173740189, 851412213, 1401524087, 31598678, 2095749492, 1831365263, 412323527, 1075238684, 1688554989, 1277177331, 3932035137, 2352766506, 2583399238, 1464208094, 3378515508, 876558472, 540174517, 3962831319, 3104176421, 3753258952, 1598346136, 3639641146, 2799144837, 1335082830, 3448894474, 1971389377, 1280338847, 1678523307, 3979495055, 3977447151, 4197236110, 240152631, 2564056742, 4152503047, 2132027491, 613462886, 1905940299, 1914167390, 3071595071, 3641575855, 2504228319, 770899034, 1860802979, 857986413, 497334170, 4094582072, 389043458, 3356750231, 1037980684, 1366453392, 213109279, 2137544865, 3348058796, 1432619228, 2502307765, 598330921, 2058541321, 119240421, 3713535024, 3127628307, 742500863, 2455432819, 273066799, 3385369385, 3561349011, 1135884324, 1376864891, 1732333218, 2327135704, 4085630678, 446319932, 1065576971, 137449227, 804460016, 4294821288, 3588960392, 2622103353, 179297712, 1091666738, 19522071, 1885795795, 3110917931, 1540820345, 1936903680, 3019051052, 3233814315, 1822615852, 3770184132, 939215365, 2633291327, 2725039967, 3355664914, 3945249370, 3897916792, 2814817232, 1296924235, 2200505117, 412527760, 1997889251, 2072640357, 2571733327, 3285190086, 2853536884, 3006442335, 3609949799, 1677271114, 3729500624, 2903753601, 1810936627, 285545133, 1909934694, 3476027533, 1751750842, 1394226660, 2319518391, 3562189416, 3169584877, 3054746445, 3510466679, 2255946758, 894492446, 490703729, 295080233, 3404975881, 3278416349, 760114740, 3071363599, 1532660994, 1449130480, 2594120686, 2383099596, 3335033140, 2239148652, 2151929596, 1727802518, 3438322864, 4118507672, 999928592, 926656099, 2848976781, 1932842145, 3021282327, 2505986059, 4113113783, 2049931698, 1665574026, 3731321176, 2732930389, 2679676326, 1242265590, 4235816862, 380125944, 1591479349, 998481103, 252855587, 2523355832, 1187558402, 3131197321, 1679435792, 330588669, 1285987188, 2774366904, 192565064, 3330308343, 143180323, 1230427407, 1042626614, 3551371075, 3299470607, 4252551163, 2557905889, 2923427031, 3987085787, 446026292, 3695067108, 1456499511, 4112722992, 1587106584, 2829719777, 609543353, 3556558201, 718402331, 3292444331, 2859596431, 31637370, 2860097397, 3414469054, 3810338184, 270780933, 3753613260, 892595036, 2737580695, 3846175386, 1193012855, 1088068304, 3339587274, 1562672477, 3070518047, 3597663484, 2739426334, 3204952150, 2912995929, 2748506879, 3842003573, 2776412830, 1400058916, 2020054662, 2377036718, 4160846599, 2120095081, 3920878941, 309345261, 892248147, 1686411590, 1501357941, 3140419239, 2689448544, 1772193500, 755229721, 649863546, 146955813, 2565648513, 2900311104, 1258658466, 58671053, 778808748, 3674116194, 2098766047, 3130663065, 2317089509, 3975246870, 3321476405, 78204234, 3436785089, 3780779385, 2949139593, 3768912244, 286958595, 478470316, 4172060285, 3075297601, 109767259, 3381163159, 2608709722, 3905155331, 2852832732, 3921976414, 1537682830, 641072600, 1462097478, 1452705388, 2623795872, 3976333004, 936646829, 2383782296, 1005939606, 2763868573, 1057950572, 3062575565, 1546045229, 949844320, 1368371267, 1304629564, 1667947035, 948311561, 2030429570, 2546539268, 2253910877, 1961765842, 801446384, 2893567083, 2835976434, 1488739183, 1272204281, 3829527774, 1598227991, 669188700, 2755084886, 1021444792, 1865260546, 2609090726, 1897053132, 1442782985, 930117598, 2666567843, 529573622, 78109961, 373997120, 3086686431, 2577858874, 1201595649, 3153037067, 563445918, 310830179, 2678678093, 2099560782, 1031134330, 1144259690, 2131604341, 142798466, 3414297028, 28501148, 2428553208, 2064885619, 2347315390, 4248571992, 288152231, 1362116887, 3106554626, 599339349, 114473371, 1417694715, 1613012486, 1715992043, 3876231624, 3177874309, 4159912129, 3005552705, 2711286954, 1156362334, 1155714481, 2815345946, 1061267272, 121956570, 1611077114, 3460643800, 2703993611, 3071667970, 2485669278, 3801901636, 555641829, 378940769, 3373905023, 2588453077, 644716969, 1962582582, 1482532889, 2752320985, 3226812640, 602572328, 2932982433, 1459505690, 2551413073, 2256796665, 1160622526, 2768524694, 2604591768, 1632466115, 2425704271, 4192298249, 2453002763, 403459058, 3601806796, 1223115691, 3254747297, 1714055965, 4144206424, 556014141, 1656581065, 2333353026, 3471348524, 971649853, 3465648511, 3232879773, 1283235079, 3718907467, 499549952, 3915559234, 474595453, 3059829727, 3137757213, 3870371645, 1518475715, 1457106270, 3888873998, 1521078680, 2721828228, 4288054154, 3551900475, 2416607293, 447227821, 3611801353, 3536413079, 197807508, 4285011529, 2403650753, 1798202528, 813193091, 1437973278, 905570583, 1217738310, 2161547596, 111326364, 1987469716, 3384730322, 567742684, 3141019767, 2045682692, 3242818906, 555487219, 2197641947, 335067705, 749081176, 1173401727, 3773567876, 3842337238, 1202643662, 4194507451, 697769661, 782867788, 2941739973, 3538453554, 1075669042, 1755032060, 682051836, 3897031998, 3017658459, 4013423263, 2495093926, 1538753247, 1703796690, 93378247, 2977249687, 4227963854, 2202597035, 1611589041, 2364882964, 1517563190, 1551089265, 2266310605, 3689300074, 4166210063, 2501073735, 2991263183, 3194111925, 2330092162, 1267828134, 2724419853, 1342301861, 1983770811, 575623047, 3351576674, 2159116855, 1266491073, 985696441, 1591018592, 3766224004, 1520586419, 3145125624, 1626967645, 2625146438, 2854705516, 528823216, 1082867806, 2762398090, 878364773, 1635936542, 3440942345, 1346149903, 2181154949, 1018265636, 2207224827, 2616950127, 2900961420, 2293808668, 2456699241, 7592522, 2842383784, 3071630859, 443994268, 2045217175, 915649341, 324090866, 2904652459, 3464699359, 3396622905, 1833610515, 4235231428, 3325661774, 1867299791, 3609449684, 3151762376, 1585678078, 1856538418, 1366145224, 2212397824, 358389376, 2985250381, 2218326882, 3474293978, 1160490768, 111078402, 4206065286, 3714192957, 2436105438, 3327252652, 3485312465, 1590456296, 3774540135, 2274311278, 4054825975, 1807167981, 970171337, 3259841305, 3290144238, 3097970700, 2770872197, 214875146, 3002796927, 640494850, 2774602186, 696559717, 1083080571, 3089465468, 2784797390, 3637478094, 163191252, 1249588206, 4189389670, 289766105, 1497795724, 3264452507, 2514386435, 448220673, 4257564859, 1122754679, 3015039124, 1159070063, 938581893, 2022319180, 3920346031, 3907739185, 2893984058, 3591321705, 1362360658, 164142478, 3252995241, 3329748518, 1184145779, 171401187, 2371607528, 2758447546, 2464654755, 3804378595, 4051061832, 2945231165, 4277476277, 2691201840, 2988255621, 80000787, 134503379, 1732668052, 579409137, 4257507612, 1101351995, 1419210964, 1452984755, 4569815, 606805141, 3636593602, 3098044319, 2273487831, 3043789296, 1979060459, 3984842259, 2314336923, 4193995551, 524852419, 3241999938, 436714412, 25491271, 3944806654, 2598428456, 1438597426, 2884461260, 2086361453, 475566487, 4292998278, 831929033, 3176801710, 490104154, 863092022, 219988893, 3756629244, 2464532537, 4147915025, 1676178726, 3481465181, 961313688, 214165022, 2523456534, 998205717, 2163444944, 3607376721, 1315539196, 2661826722, 2344072812, 1498744802, 1747552497, 1214327234, 233516638, 1184071759, 2877471145, 488165615, 1435962775, 2665287668, 2730745409, 1982804121, 2287987552, 239454046, 796388130, 790629467, 2050180223, 3040371067, 3401063302, 1955147705, 3919195202, 959644756, 3219852384, 1509807134, 2184015671, 3589965190, 2691996638, 2301044897, 2722752205, 2530990704, 3683798579, 20559532, 3234527682, 3183232707, 3830345903, 3270687257, 3758910623, 151069542, 3419568627, 1308568161, 1684568639, 97837699, 2335895504, 2219664818, 652247842, 751565418, 3816697845, 4049392527, 3540170031, 2259394960, 2285491077, 2443146540, 4165255312, 40439745, 1189493976, 1655622172, 2411009640, 915699934, 1096710751, 3728911374, 1158809984, 231078435, 3823394050, 3113868906, 2537583726, 4015932122, 2205894006, 1267247386, 1370848696, 755629816, 3898348400, 220716774, 668561586, 2488133284, 3187347304, 618138163, 2405280684, 1154866484, 597902715, 2129513689, 2716473315, 3161307004, 3289207475, 3051348366, 3288097382, 1294453762, 903716339, 754658576, 3943832446, 1177690189, 2537206265, 2150507160, 2163381518, 2333687351, 3076548668, 500517981, 2298303075, 3570117707, 3307603441, 3824888676, 3469675055, 3443768752, 2409909436, 3341589273, 2148962626, 3370228692, 1809597582, 1162222997, 1449680995, 2448660655, 933587337, 2608684097, 6240828, 939747503, 2678223555, 3746152410, 30662561, 3218322022, 939821884, 3581262181, 2753121657, 281464262, 3094537120, 412397654, 3656364086, 151552333, 2502686460, 2298285389, 4124048943, 328175897, 479293612, 2906125292, 1065695588, 868916452, 1083986277, 1806662802, 1051991909, 492382656, 1462001628, 2216274387, 1726249646, 4178367202, 1110254181, 1660790781, 1444941599, 256717755, 200760985, 2073689645, 2242896094, 238922530, 545845867, 3180921756, 2153670215, 2405588645, 298452803, 1265399198, 1326171016, 3061206939, 2071993386, 511952431, 1351974733, 763765441, 2996030395, 297117344, 2435901668, 3746491031, 3062936733, 833399803, 3686012684, 491324539, 4056494058, 2062762926, 3379381198, 2611370628, 635940634, 3508828090, 1284918442, 2962748792, 2981465352, 1972103513, 1169667353, 2799559150, 894451947, 2548686881, 1356533036, 1536651520, 262962171, 2929822643, 3197744180, 1253056104, 2968762495, 14431766, 2377340160, 2306570033, 3991406849, 2452201001, 2026813501, 4186850749, 2709120681, 4115667283, 3834059575, 1189272019, 2790865605, 2836507239, 1399477598, 2269248484, 3027483899, 1701593959, 838001422, 3407333751, 3787757141, 325905840, 3730573684, 2858424231, 4220246447, 3522859922, 2338675945, 833850743, 320734856, 3864945679, 3396090028, 4059257716, 710131520, 1465733053, 405311467, 1933472352, 4087403127, 3375138435, 1944583244, 631829103, 2140899797, 972955555, 307750386, 142848066, 2626552127, 962346254, 60228289, 4045712778, 1491262280, 3254163991, 3197978882, 3076601470, 112018162, 2482451809, 4244853151, 503002883, 2549440027, 1241390259, 3845265510, 4114357701, 1515684580, 2710963736, 1723648133, 3036202627, 884471572, 638999228, 14407230, 2062157370, 2508170191, 33333397, 2292818691, 3168409804, 3882862057, 1379083633, 1930561013, 2459555504, 2923193138, 3778092958, 3877481447, 1165680771, 2565138539, 4049954587, 1497027039, 856182083, 818409348, 106161985, 2570541023, 1203615276, 4200702907, 2964158455, 3703677304, 1864233262, 3881590876, 578347006, 117657025, 1769930954, 2983044089, 2615686146, 228795499, 3355850606, 472780449, 3973386305, 571733310, 684456500, 2679533674, 1823526264, 3924448163, 2544441640, 695051243, 3571821581, 2451239118, 801792380, 2458301696, 3458143915, 1268372114, 2941339503, 1157923234, 2473453715, 1289061206, 351015433, 99212807, 830844771, 2642847889, 2989052340, 3312807167, 411865129, 1176489997, 3650067903, 4135765561, 221110814, 2357056077, 2827488450, 3479911421, 674474795, 573839151, 2071652480, 3461421941, 3585513829, 1796268431, 3241406128, 2297135129, 3051446912, 228092646, 3535943607, 698578001, 580832123, 3509337952, 634494300, 2548600401, 541083112, 3900105485, 2186825589, 3042342723, 416595260, 3833021324, 2206456735, 1548713000, 2534965306, 3579516917, 4142991232, 3031962306, 1935702058, 336939528, 2701455560, 2184495630, 1582919432, 3723050412, 322863405, 685441702, 1302857090, 1382617884, 3584054563, 990944040, 1865517296, 2063468477, 1302285368, 1902323900, 1127950196, 2359104239, 1687955600, 3311104859, 2233583495, 275223868, 2629452459, 2558713800, 4227943692, 2110489631, 3194724229, 2453876022, 136449178, 3770004194, 4284513131, 1142780901, 1132169263, 348236390, 3593504718, 1110658133, 4235829338, 3356284847, 2972288183, 3238527875, 3874735297, 1144049158, 264235129, 1183495594, 3969156806, 2214754386, 2366107210, 2234765425, 2305533893, 3251607392, 2756421348, 2917376729, 3707583023, 466206346, 1555456217, 2372035279, 2891294743, 2247240548, 460348150, 1275227312, 3955003342, 2102042989, 983281070, 1919436832, 835528348, 199587935, 1397373123, 1439002320, 4002894681, 3087468851, 3980891822, 2204558828, 1016023670, 4015842397, 1283344967, 1026809464, 1416085982, 3510989507, 2400035256, 976530312, 3988520219, 3593763647, 4216824957, 2629095760, 3965953819, 4106033356, 226335245, 2152691551, 882952242, 401514366, 3241470185, 4255107447, 2630719512, 318824902, 1943344364, 3595243007, 3018016476, 701444165, 366360165, 2339487469, 751175284, 3375857465, 3264007889, 860147700, 3108533835, 2860897558, 331247439, 2444840106, 3349217085, 2178838444, 1212082447, 2297125488, 587376043, 2704907732, 2136633260, 1014267077, 1759959872, 565517991, 2539044209, 2300136337, 1572011726, 418310737, 2926051694, 98601642, 799750855, 3778420796, 3100787782, 3112494906, 300413161, 3380305552, 1899872023, 2330971316, 1897798766, 4108766870, 4215890198, 3106094480, 668707053, 4267817053, 1630073110, 3110249996, 3498246210, 1112844949, 4196075087, 3634879226, 3679507997, 849849936, 1005783980, 1223861826, 4147124887, 3984585307, 1674748798, 1448801182, 1208535885, 1562878794, 728487644, 1200021954, 2857869476, 2548928201, 2416469360, 946828419, 3450118165, 2155166286, 2995206408, 3177173382, 1417203434, 272816502, 607422462, 2205706001, 950561027, 1309490094, 2631349032, 2447882044, 2877975267, 634305349, 1023719213, 751220503, 2138940374, 3628515739, 2575833127, 3133887861, 4126942014, 3611963450, 2557986934, 2274195844, 1181726436, 3316723612, 274093857, 1580062363, 1691351615, 2573338740, 767227209, 1306544165, 3448768122, 3274481934, 1875637301, 3376112789, 2405859532, 570705459, 4032966598, 1197528033, 585316057, 504851561, 2258913155, 3836883374, 480451243, 3361871542, 3857971353, 437624215, 737129019, 3211628980, 1034195237, 3899526027, 4185677449, 1203633856, 3125914747, 2487899854, 2995891856, 2405637697, 2996284697, 3887384832, 3504424698, 314056623, 3861640763, 1508140589, 4130454741, 2418334270, 3459599240, 3392364376, 4077927219, 2990352559, 2704342070, 1173707794, 2233567785, 824577393, 780056877, 1150095417, 566190526, 3191043472, 68163110, 2196765019, 3250766381, 3623338820, 4227877829, 2357515825, 3235437686, 771291085, 2078235127, 499389038, 635349764, 309612458, 3776750619, 1895704580, 523842517, 2609519727, 3929791324, 1624201192, 1417647348, 1104664740, 3877131356, 935794303, 3540353262, 1122593135, 2194727937, 1223236950, 917596265, 1624645031, 2754058700, 4091797469, 539240815, 126597464, 1979188071, 1041526299, 683845261, 1955939834, 2128274336, 1239512929, 3491502467, 3441048000, 4006988776, 3628416533, 2730760137, 41828683, 91759785, 3669147593, 2689951346, 3157974603, 2356746139, 489905694, 1904070401, 326989153, 2541964394, 2186117692, 582912023, 183856640, 2205678083, 1192383963, 57784291, 156667965, 1972778257, 2279582957, 600911161, 672804528, 2432223864, 3879537828, 3722058118, 352763954, 1813590533, 2407037767, 1004152995, 1985861895, 1039115649, 485905822, 3067320537, 3890285500, 4144230801, 1380609464, 4202216761, 3670689598, 1320800569, 3205955197, 1217855674, 3254437694, 41739140, 1073135560, 2568661738, 90684693, 2581147015, 4244404101, 1436364804, 436751995, 506947906, 2513919205, 4062987066, 2755458375, 3182046194, 1641820942, 3429725592, 924587953, 3201484753, 3024548359, 3748248736, 2895314706, 2510435025, 3042473135, 2693195525, 3157425058, 2926427120, 1606156817, 1376542356, 3329145363, 4217629790, 2511787101, 123506855, 4234978787, 799435471, 1858558137, 3677572089, 4177413491, 2284202143, 2334746477, 2692902225, 2856526389, 1460215059, 3955331890, 1454412800, 2616947411, 767786402, 2891706377, 3378992354, 2995021, 3448110918, 3720597946, 754506168, 3597416608, 1235209082, 3998989164, 2219475051, 1219429866, 2429569652, 2972414596, 1847147142, 3334851888, 3378557844, 3031275313, 767358319, 481754697, 995575256, 3123037339, 3184792628, 765718147, 1159720685, 1054824633, 709566417, 1822252788, 202708381, 3017643002, 1660628907, 780280564, 2394752843, 2346712442, 3483800966, 1647588258, 4283132451, 345312046, 3787978677, 2974885445, 3600633256, 2560416690, 3206177058, 2930643192, 1549025167, 4252809346, 85891315, 81911741, 2326660907, 2842073998, 528209143, 1014785212, 896517293, 3994255386, 1899370807, 734978415, 1842173370, 2676692258, 3642792593, 3328590970, 160213030, 2713070612, 949310718, 3973595413, 1941865885, 2648565580], "values": [2.0, 23.0, 18.0, 2.0, 1.0, 9.0, 1.0, 10.0, 3.0, 12.0, 8.0, 1.0, 3.0, 14.0, 105.0, 105.0, 2.0, 106.0, 7.0, 6.0, 1.0, 1.0, 56.0, 2.0, 11.0, 1.0, 13.0, 7.0, 1.0, 21.0, 1.0, 59.0, 2.0, 47.0, 1.0, 49.0, 5.0, 7.0, 6.0, 41.0, 1.0, 3.0, 1.0, 23.0, 2.0, 14.0, 28.0, 51.0, 1.0, 40.0, 1.0, 11.0, 9.0, 5.0, 1.0, 25.0, 3.0, 5.0, 43.0, 3.0, 13.0, 52.0, 14.0, 7.0, 9.0, 1.0, 37.0, 1.0, 31.0, 1.0, 5.0, 44.0, 2.0, 1.0, 1.0, 1.0, 20.0, 9.0, 8.0, 57.0, 2.0, 33.0, 26.0, 2.0, 5.0, 2.0, 14.0, 9.0, 2.0, 17.0, 3.0, 43.0, 2.0, 37.0, 6.0, 2.0, 2.0, 51.0, 1.0, 13.0, 5.0, 2.0, 6.0, 4.0, 7.0, 1.0, 8.0, 1.0, 65.0, 21.0, 2.0, 5.0, 1.0, 1.0, 5.0, 1.0, 1.0, 2.0, 9.0, 17.0, 3.0, 12.0, 24.0, 49.0, 41.0, 8.0, 6.0, 1.0, 2.0, 1.0, 1.0, 15.0, 1.0, 27.0, 3.0, 33.0, 1.0, 2.0, 7.0, 2.0, 4.0, 46.0, 2.0, 2.0, 19.0, 2.0, 2.0, 2.0, 6.0, 3.0, 8.0, 8.0, 4.0, 5.0, 40.0, 13.0, 7.0, 43.0, 1.0, 6.0, 46.0, 1.0, 3.0, 1.0, 1.0, 2.0, 1.0, 2.0, 1.0, 2.0, 9.0, 24.0, 9.0, 15.0, 14.0, 11.0, 3.0, 23.0, 1.0, 7.0, 5.0, 2.0, 8.0, 3.0, 7.0, 2.0, 64.0, 2.0, 2.0, 13.0, 2.0, 28.0, 10.0, 8.0, 2.0, 6.0, 7.0, 9.0, 11.0, 42.0, 2.0, 30.0, 2.0, 9.0, 24.0, 5.0, 5.0, 8.0, 16.0, 12.0, 1.0, 6.0, 1.0, 4.0, 1.0, 6.0, 1.0, 2.0, 17.0, 1.0, 1.0, 2.0, 4.0, 1.0, 14.0, 1.0, 12.0, 1.0, 1.0, 3.0, 2.0, 2.0, 2.0, 7.0, 31.0, 2.0, 10.0, 6.0, 2.0, 2.0, 2.0, 2.0, 2.0, 3.0, 7.0, 3.0, 1.0, 1.0, 14.0, 17.0, 4.0, 7.0, 10.0, 7.0, 4.0, 1.0, 2.0, 8.0, 6.0, 1.0, 1.0, 2.0, 22.0, 1.0, 5.0, 1.0, 10.0, 4.0, 7.0, 4.0, 9.0, 6.0, 2.0, 8.0, 5.0, 6.0, 16.0, 1.0, 1.0, 30.0, 27.0, 21.0, 1.0, 2.0, 2.0, 1.0, 16.0, 23.0, 1.0, 1.0, 4.0, 1.0, 6.0, 10.0, 10.0, 19.0, 1.0, 11.0, 2.0, 3.0, 4.0, 42.0, 1.0, 1.0, 2.0, 1.0, 2.0, 9.0, 1.0, 11.0, 20.0, 3.0, 1.0, 3.0, 16.0, 5.0, 2.0, 2.0, 7.0, 29.0, 2.0, 2.0, 5.0, 2.0, 2.0, 1.0, 1.0, 7.0, 5.0, 4.0, 21.0, 9.0, 4.0, 9.0, 3.0, 5.0, 3.0, 3.0, 26.0, 1.0, 2.0, 2.0, 2.0, 5.0, 1.0, 2.0, 3.0, 1.0, 6.0, 1.0, 5.0, 1.0, 2.0, 2.0, 5.0, 5.0, 5.0, 2.0, 8.0, 2.0, 3.0, 3.0, 4.0, 2.0, 10.0, 1.0, 1.0, 7.0, 19.0, 1.0, 1.0, 17.0, 7.0, 13.0, 7.0, 6.0, 6.0, 6.0, 1.0, 9.0, 2.0, 4.0, 1.0, 1.0, 6.0, 13.0, 6.0, 1.0, 4.0, 5.0, 25.0, 9.0, 5.0, 9.0, 2.0, 2.0, 2.0, 4.0, 13.0, 3.0, 1.0, 19.0, 6.0, 1.0, 22.0, 13.0, 2.0, 11.0, 1.0, 7.0, 4.0, 6.0, 2.0, 1.0, 1.0, 2.0, 3.0, 5.0, 7.0, 1.0, 5.0, 4.0, 1.0, 1.0, 1.0, 4.0, 1.0, 3.0, 4.0, 1.0, 4.0, 6.0, 1.0, 2.0, 1.0, 19.0, 1.0, 1.0, 4.0, 9.0, 1.0, 3.0, 3.0, 2.0, 1.0, 3.0, 10.0, 5.0, 4.0, 1.0, 9.0, 7.0, 10.0, 1.0, 1.0, 4.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 3.0, 2.0, 1.0, 1.0, 2.0, 2.0, 1.0, 5.0, 8.0, 16.0, 5.0, 2.0, 16.0, 1.0, 2.0, 3.0, 1.0, 1.0, 7.0, 1.0, 4.0, 6.0, 4.0, 1.0, 4.0, 7.0, 1.0, 5.0, 12.0, 2.0, 2.0, 3.0, 1.0, 2.0, 11.0, 17.0, 10.0, 6.0, 1.0, 3.0, 4.0, 1.0, 2.0, 1.0, 1.0, 1.0, 1.0, 2.0, 1.0, 1.0, 1.0, 3.0, 9.0, 1.0, 3.0, 5.0, 1.0, 3.0, 2.0, 7.0, 5.0, 3.0, 1.0, 9.0, 1.0, 3.0, 2.0, 1.0, 6.0, 2.0, 1.0, 1.0, 1.0, 1.0, 1.0, 11.0, 5.0, 1.0, 9.0, 1.0, 1.0, 1.0, 1.0, 1.0, 3.0, 1.0, 1.0, 1.0, 1.0, 4.0, 1.0, 2.0, 1.0, 1.0, 7.0, 2.0, 1.0, 1.0, 1.0, 1.0, 2.0, 1.0, 1.0, 1.0, 1.0, 1.0, 17.0, 2.0, 1.0, 1.0, 1.0, 1.0, 9.0, 1.0, 1.0, 1.0, 4.0, 5.0, 6.0, 1.0, 1.0, 2.0, 3.0, 3.0, 4.0, 1.0, 6.0, 1.0, 1.0, 11.0, 13.0, 2.0, 3.0, 1.0, 3.0, 1.0, 1.0, 2.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 2.0, 1.0, 11.0, 1.0, 1.0, 29.0, 7.0, 4.0, 2.0, 6.0, 5.0, 2.0, 2.0, 7.0, 2.0, 2.0, 2.0, 1.0, 1.0, 24.0, 1.0, 19.0, 6.0, 12.0, 6.0, 2.0, 3.0, 15.0, 2.0, 3.0, 5.0, 3.0, 1.0, 2.0, 1.0, 3.0, 1.0, 1.0, 6.0, 9.0, 2.0, 3.0, 2.0, 2.0, 3.0, 30.0, 6.0, 7.0, 15.0, 1.0, 3.0, 12.0, 6.0, 2.0, 4.0, 1.0, 1.0, 1.0, 4.0, 5.0, 4.0, 3.0, 3.0, 5.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 5.0, 2.0, 1.0, 1.0, 1.0, 5.0, 9.0, 4.0, 2.0, 1.0, 1.0, 1.0, 4.0, 1.0, 5.0, 1.0, 6.0, 5.0, 3.0, 6.0, 13.0, 3.0, 17.0, 1.0, 1.0, 1.0, 1.0, 1.0, 2.0, 30.0, 4.0, 2.0, 2.0, 2.0, 7.0, 2.0, 15.0, 2.0, 3.0, 3.0, 1.0, 14.0, 1.0, 3.0, 6.0, 1.0, 5.0, 4.0, 1.0, 1.0, 1.0, 1.0, 2.0, 2.0, 2.0, 1.0, 1.0, 1.0, 1.0, 2.0, 2.0, 2.0, 1.0, 1.0, 1.0, 1.0, 2.0, 1.0, 1.0, 1.0, 1.0, 2.0, 4.0, 1.0, 1.0, 5.0, 6.0, 9.0, 1.0, 2.0, 5.0, 1.0, 1.0, 4.0, 2.0, 2.0, 3.0, 3.0, 3.0, 2.0, 2.0, 15.0, 2.0, 9.0, 5.0, 2.0, 1.0, 1.0, 1.0, 20.0, 3.0, 4.0, 3.0, 2.0, 8.0, 1.0, 1.0, 11.0, 3.0, 1.0, 2.0, 9.0, 2.0, 5.0, 2.0, 5.0, 7.0, 6.0, 13.0, 1.0, 1.0, 1.0, 5.0, 4.0, 1.0, 4.0, 3.0, 1.0, 7.0, 3.0, 1.0, 1.0, 2.0, 1.0, 1.0, 2.0, 13.0, 2.0, 2.0, 10.0, 3.0, 2.0, 2.0, 2.0, 4.0, 5.0, 3.0, 1.0, 7.0, 1.0, 3.0, 8.0, 1.0, 2.0, 3.0, 1.0, 1.0, 8.0, 1.0, 3.0, 1.0, 1.0, 2.0, 1.0, 1.0, 1.0, 1.0, 6.0, 4.0, 1.0, 1.0, 5.0, 1.0, 7.0, 1.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 1.0, 1.0, 4.0, 3.0, 1.0, 3.0, 3.0, 1.0, 1.0, 2.0, 16.0, 4.0, 1.0, 4.0, 1.0, 2.0, 2.0, 2.0, 4.0, 2.0, 5.0, 2.0, 7.0, 1.0, 1.0, 3.0, 1.0, 2.0, 1.0, 3.0, 1.0, 1.0, 1.0, 1.0, 8.0, 2.0, 4.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 5.0, 4.0, 2.0, 1.0, 9.0, 2.0, 2.0, 9.0, 2.0, 8.0, 4.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 5.0, 3.0, 4.0, 7.0, 14.0, 1.0, 1.0, 1.0, 3.0, 2.0, 5.0, 3.0, 2.0, 1.0, 1.0, 1.0, 1.0, 1.0, 3.0, 1.0, 1.0, 2.0, 1.0, 1.0, 1.0, 8.0, 4.0, 10.0, 1.0, 4.0, 2.0, 5.0, 3.0, 3.0, 3.0, 3.0, 3.0, 3.0, 2.0, 6.0, 2.0, 1.0, 1.0, 1.0, 1.0, 2.0, 2.0, 1.0, 1.0, 7.0, 1.0, 1.0, 2.0, 1.0, 2.0, 6.0, 3.0, 2.0, 2.0, 4.0, 2.0, 2.0, 2.0, 8.0, 3.0, 2.0, 3.0, 2.0, 5.0, 2.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 4.0, 1.0, 7.0, 1.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 1.0, 1.0, 3.0, 3.0, 1.0, 2.0, 1.0, 1.0, 1.0, 1.0, 3.0, 2.0, 2.0, 1.0, 2.0, 1.0, 1.0, 11.0, 1.0, 1.0, 2.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 3.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 2.0, 3.0, 3.0, 3.0, 2.0, 2.0, 2.0, 2.0, 4.0, 2.0, 18.0, 4.0, 3.0, 6.0, 4.0, 1.0, 2.0, 1.0, 1.0, 1.0, 1.0, 1.0, 10.0, 1.0, 1.0, 2.0, 4.0, 1.0, 6.0, 4.0, 2.0, 1.0, 2.0, 3.0, 3.0, 4.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 7.0, 2.0, 2.0, 1.0, 1.0, 1.0, 3.0, 1.0, 1.0, 2.0, 4.0, 1.0, 1.0, 1.0, 1.0, 4.0, 7.0, 6.0, 5.0, 4.0, 2.0, 4.0, 4.0, 6.0, 2.0, 2.0, 4.0, 2.0, 2.0, 3.0, 2.0, 1.0, 4.0, 5.0, 1.0, 1.0, 1.0, 3.0, 1.0, 4.0, 2.0, 1.0, 5.0, 1.0, 4.0, 3.0, 4.0, 3.0, 1.0, 3.0, 1.0, 2.0, 5.0, 4.0, 1.0, 1.0, 2.0, 2.0, 1.0, 3.0, 3.0, 2.0, 2.0, 1.0, 7.0, 1.0, 1.0, 1.0, 5.0, 1.0, 1.0, 1.0, 8.0, 1.0, 1.0, 1.0, 2.0, 4.0, 8.0, 5.0, 2.0, 4.0, 3.0, 6.0, 2.0, 2.0, 1.0, 4.0, 6.0, 1.0, 1.0, 1.0, 2.0, 2.0, 1.0, 1.0, 11.0, 1.0, 1.0, 5.0, 4.0, 5.0, 1.0, 1.0, 4.0, 4.0, 3.0, 3.0, 3.0, 2.0, 5.0, 1.0, 1.0, 3.0, 1.0, 3.0, 1.0, 6.0, 3.0, 1.0, 1.0, 1.0, 1.0, 1.0, 9.0, 1.0, 1.0, 2.0, 1.0, 1.0, 1.0, 1.0, 2.0, 7.0, 2.0, 3.0, 3.0, 2.0, 1.0, 1.0, 6.0, 1.0, 1.0, 2.0, 5.0, 1.0, 1.0, 2.0, 1.0, 2.0, 1.0, 5.0, 1.0, 1.0, 2.0, 4.0, 2.0, 4.0, 2.0, 2.0, 2.0, 2.0, 1.0, 12.0, 1.0, 1.0, 1.0, 7.0, 1.0, 1.0, 1.0, 1.0, 2.0, 5.0, 5.0, 3.0, 1.0, 1.0, 1.0, 1.0, 1.0, 2.0, 1.0, 4.0, 2.0, 2.0, 2.0, 1.0, 1.0, 3.0, 2.0, 1.0, 1.0, 4.0, 1.0, 3.0, 1.0, 1.0, 1.0, 2.0, 6.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 3.0, 5.0, 3.0, 7.0, 2.0, 2.0, 1.0, 1.0, 2.0, 8.0, 6.0, 1.0, 2.0, 1.0, 2.0, 2.0, 8.0, 2.0, 2.0, 5.0, 7.0, 2.0, 13.0, 8.0, 9.0, 21.0, 13.0, 3.0, 1.0, 5.0, 2.0, 7.0, 3.0, 1.0, 1.0, 1.0, 1.0, 2.0, 3.0, 2.0, 2.0, 2.0, 2.0, 2.0, 19.0, 8.0, 1.0, 6.0, 1.0, 1.0, 1.0, 4.0, 2.0, 1.0, 8.0, 3.0, 2.0, 1.0, 9.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 2.0, 2.0, 2.0, 2.0, 2.0, 1.0, 12.0, 1.0, 1.0, 1.0, 1.0, 7.0, 2.0, 1.0, 1.0, 11.0, 5.0, 1.0, 1.0, 2.0, 3.0, 6.0, 2.0, 2.0, 2.0, 4.0, 1.0, 2.0, 2.0, 3.0, 5.0, 1.0, 4.0, 1.0, 3.0, 2.0, 2.0, 7.0, 2.0, 1.0, 4.0, 2.0, 4.0, 2.0, 2.0, 1.0, 1.0, 5.0, 4.0, 1.0, 3.0, 1.0, 1.0, 4.0, 2.0, 2.0, 2.0, 16.0, 4.0, 5.0, 10.0, 1.0, 2.0, 2.0, 1.0, 6.0, 3.0, 7.0, 1.0, 3.0, 6.0, 2.0, 1.0, 6.0, 3.0, 2.0, 2.0, 1.0, 2.0, 2.0, 3.0, 7.0, 2.0, 3.0, 1.0, 1.0, 11.0, 5.0, 4.0, 6.0, 1.0, 2.0, 1.0, 2.0, 2.0, 5.0, 2.0, 1.0, 2.0, 8.0, 1.0, 4.0, 4.0, 1.0, 5.0, 2.0, 3.0, 4.0, 1.0, 5.0, 4.0, 5.0, 2.0, 1.0, 1.0, 1.0, 1.0, 3.0, 2.0, 1.0, 1.0, 1.0, 1.0, 1.0, 4.0, 15.0, 1.0, 3.0, 1.0, 3.0, 1.0, 1.0, 2.0, 1.0, 1.0, 1.0, 2.0, 2.0, 1.0, 1.0, 1.0, 4.0, 1.0, 1.0, 3.0, 1.0, 3.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 2.0, 3.0, 1.0, 3.0, 3.0, 6.0, 2.0, 1.0, 2.0, 1.0, 1.0, 5.0, 4.0, 8.0, 5.0, 5.0, 1.0, 6.0, 3.0, 4.0, 1.0, 1.0, 1.0, 1.0, 5.0, 1.0, 1.0, 2.0, 6.0, 4.0, 1.0, 1.0, 1.0, 11.0, 1.0, 1.0, 3.0, 5.0, 1.0, 1.0, 1.0, 1.0, 3.0, 1.0, 1.0, 1.0, 1.0, 3.0, 1.0, 3.0, 2.0, 2.0, 2.0, 2.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 2.0, 4.0, 3.0, 4.0, 1.0, 2.0, 1.0, 3.0, 1.0, 1.0, 1.0, 4.0, 2.0, 2.0, 4.0, 2.0, 2.0, 1.0, 1.0, 1.0, 1.0, 2.0, 2.0, 2.0, 2.0, 1.0, 1.0, 2.0, 2.0, 2.0, 2.0, 2.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 4.0, 1.0, 2.0, 2.0, 4.0, 2.0, 2.0, 3.0, 1.0, 3.0, 3.0, 5.0, 1.0, 1.0, 4.0, 3.0, 2.0, 1.0, 3.0, 3.0, 1.0, 2.0, 1.0, 1.0, 4.0, 9.0, 2.0, 3.0, 4.0, 4.0, 3.0, 2.0, 2.0, 4.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 5.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 3.0, 3.0, 1.0, 1.0, 3.0, 5.0, 3.0, 1.0, 2.0, 3.0, 2.0, 3.0, 2.0, 2.0, 5.0, 2.0, 2.0, 2.0, 2.0, 1.0, 2.0, 3.0, 1.0, 1.0, 1.0, 1.0, 1.0, 3.0, 1.0, 1.0, 1.0, 8.0, 2.0, 4.0, 1.0, 4.0, 6.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 6.0, 1.0, 2.0, 4.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 3.0, 3.0, 1.0, 1.0, 2.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 2.0, 1.0, 2.0, 1.0, 1.0, 2.0, 4.0, 6.0, 4.0, 2.0, 1.0, 1.0, 4.0, 4.0, 1.0, 5.0, 1.0, 1.0, 2.0, 2.0, 3.0, 2.0, 7.0, 5.0, 2.0, 2.0, 2.0, 5.0, 1.0, 3.0, 1.0, 2.0, 1.0, 3.0, 13.0, 1.0, 1.0, 1.0, 1.0, 4.0, 3.0, 4.0, 2.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 4.0, 2.0, 1.0, 7.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 2.0, 3.0, 2.0, 3.0, 2.0, 2.0, 3.0, 1.0, 1.0, 2.0, 1.0, 1.0, 1.0, 19.0, 1.0, 2.0, 1.0, 5.0, 1.0, 1.0, 1.0, 2.0, 1.0, 2.0, 1.0, 1.0, 4.0, 2.0, 1.0, 1.0, 1.0, 1.0, 1.0, 2.0, 2.0, 2.0, 2.0, 2.0, 4.0, 2.0, 2.0, 2.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 2.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 4.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 1.0, 1.0, 1.0, 1.0, 3.0, 3.0, 3.0, 3.0, 1.0, 4.0, 1.0, 7.0, 6.0, 2.0, 2.0, 2.0, 2.0, 2.0, 1.0, 1.0, 1.0, 1.0, 1.0, 2.0, 1.0, 1.0, 1.0, 3.0, 2.0, 2.0, 2.0, 5.0, 4.0, 2.0, 3.0, 2.0, 2.0, 3.0, 3.0, 3.0, 3.0, 3.0, 2.0, 3.0, 5.0, 3.0, 2.0, 2.0, 2.0, 1.0, 1.0, 1.0, 1.0, 2.0, 1.0, 1.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 3.0, 2.0, 1.0, 3.0, 5.0, 1.0, 1.0, 1.0, 5.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 2.0, 3.0, 3.0, 3.0, 5.0, 2.0, 3.0, 2.0, 2.0, 2.0, 1.0, 3.0, 1.0, 2.0, 2.0, 2.0, 2.0, 2.0, 1.0, 2.0, 2.0, 2.0, 2.0, 2.0, 1.0, 1.0, 1.0, 1.0, 2.0, 1.0, 1.0, 2.0, 6.0, 2.0, 7.0, 2.0, 2.0, 3.0, 2.0, 2.0, 2.0, 1.0, 1.0, 1.0, 5.0, 1.0, 1.0, 2.0, 1.0, 1.0, 5.0, 1.0, 4.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 3.0, 1.0, 2.0, 3.0, 1.0, 2.0, 1.0, 1.0, 1.0, 1.0, 2.0, 1.0, 2.0, 1.0, 2.0, 2.0, 2.0, 2.0, 1.0, 1.0, 1.0, 2.0, 2.0, 1.0, 1.0, 3.0, 3.0, 1.0, 1.0, 1.0, 1.0, 2.0, 2.0, 1.0, 1.0, 1.0, 2.0, 2.0, 2.0, 2.0, 3.0, 1.0, 4.0, 2.0, 3.0, 1.0, 7.0, 2.0, 6.0, 2.0, 3.0, 1.0, 6.0, 2.0, 3.0, 2.0, 2.0, 2.0, 1.0, 4.0, 2.0, 2.0, 3.0, 2.0, 3.0, 2.0, 5.0, 1.0, 1.0, 1.0, 1.0, 1.0, 4.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 3.0, 2.0, 2.0, 2.0, 4.0, 4.0, 4.0, 3.0, 1.0, 2.0, 1.0, 1.0, 1.0, 1.0, 1.0, 6.0, 6.0, 2.0, 1.0, 1.0, 1.0, 1.0, 2.0, 2.0, 1.0, 1.0, 1.0, 1.0, 2.0, 1.0, 3.0, 2.0, 3.0, 1.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 6.0, 3.0, 1.0, 3.0, 1.0, 2.0, 1.0, 1.0, 1.0, 1.0, 1.0, 2.0, 4.0, 2.0, 1.0, 1.0, 1.0, 10.0, 1.0, 1.0, 2.0, 3.0, 6.0, 8.0, 3.0, 1.0, 1.0, 3.0, 1.0, 1.0, 3.0, 1.0, 1.0, 1.0, 3.0, 2.0, 2.0, 2.0, 2.0, 1.0, 3.0, 1.0, 5.0, 1.0, 2.0, 1.0, 2.0, 1.0, 1.0, 2.0, 2.0, 4.0, 1.0, 3.0, 1.0, 5.0, 1.0, 1.0, 1.0, 2.0, 2.0, 2.0, 2.0, 1.0, 1.0, 1.0, 3.0, 1.0, 1.0, 1.0, 5.0, 2.0, 3.0, 2.0, 5.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 2.0, 2.0, 2.0, 2.0, 1.0, 1.0, 1.0, 1.0, 1.0, 3.0, 2.0, 1.0, 1.0, 1.0, 1.0, 3.0, 1.0, 3.0, 2.0, 3.0, 1.0, 1.0, 1.0, 5.0, 4.0, 2.0, 2.0, 1.0, 2.0, 3.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 3.0, 1.0, 3.0, 2.0, 2.0, 2.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 2.0, 2.0, 2.0, 2.0, 4.0, 2.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 4.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 1.0, 9.0, 1.0, 1.0, 2.0, 2.0, 2.0, 2.0, 1.0, 1.0, 1.0, 1.0, 5.0, 3.0, 4.0, 6.0, 4.0, 4.0, 2.0, 2.0, 1.0, 1.0, 2.0, 1.0, 1.0, 1.0, 1.0, 1.0, 2.0, 1.0, 2.0, 2.0, 5.0, 5.0, 2.0, 4.0, 4.0, 1.0, 1.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 1.0, 2.0, 1.0, 2.0, 1.0, 2.0, 2.0, 2.0, 2.0, 2.0, 1.0, 3.0, 1.0, 1.0, 1.0, 3.0, 1.0, 1.0, 1.0, 1.0, 5.0, 5.0, 1.0, 3.0, 1.0, 2.0, 2.0, 2.0, 1.0, 3.0, 1.0, 3.0, 1.0, 1.0, 2.0, 3.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 5.0, 1.0, 3.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 2.0, 1.0, 3.0, 1.0, 1.0, 2.0, 2.0, 2.0, 2.0, 2.0, 1.0, 1.0, 1.0, 4.0, 3.0, 1.0, 1.0, 1.0, 2.0, 2.0, 2.0, 4.0, 2.0, 2.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 5.0, 1.0, 1.0, 2.0, 2.0, 1.0, 1.0, 1.0, 1.0, 1.0, 2.0, 2.0, 2.0, 3.0, 1.0, 1.0, 1.0, 1.0, 3.0, 1.0, 1.0, 1.0, 3.0, 1.0, 1.0, 2.0, 2.0, 3.0, 2.0, 2.0, 1.0, 1.0, 1.0, 1.0, 1.0, 2.0, 2.0, 1.0, 1.0, 1.0, 2.0, 1.0, 2.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 2.0, 3.0, 2.0, 2.0, 2.0, 2.0, 1.0, 1.0, 3.0, 2.0, 1.0, 3.0, 1.0, 1.0, 1.0, 1.0, 2.0, 2.0, 2.0, 3.0, 1.0, 1.0, 1.0, 1.0, 4.0, 3.0, 4.0, 4.0, 1.0, 2.0, 1.0, 1.0, 2.0, 2.0, 1.0, 3.0, 1.0, 2.0, 2.0, 1.0, 3.0, 3.0, 2.0, 3.0, 3.0, 3.0, 3.0, 2.0, 1.0, 2.0, 1.0, 1.0, 1.0, 2.0, 1.0, 2.0, 2.0, 1.0, 1.0, 1.0, 1.0, 2.0, 1.0, 2.0, 1.0, 2.0, 2.0, 4.0, 1.0, 2.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 2.0, 2.0, 2.0, 2.0, 1.0, 1.0, 8.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 3.0, 2.0, 2.0, 2.0, 3.0, 2.0, 2.0, 3.0, 2.0, 2.0, 2.0, 4.0, 1.0, 1.0, 4.0, 3.0, 1.0, 2.0, 1.0, 1.0, 2.0, 2.0, 1.0, 1.0, 1.0, 1.0, 1.0, 2.0, 4.0, 2.0, 2.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 2.0, 2.0, 2.0, 1.0, 1.0, 1.0, 1.0, 3.0, 2.0, 2.0, 2.0, 1.0, 1.0, 2.0, 2.0, 1.0, 1.0, 1.0, 2.0, 2.0, 4.0, 1.0, 1.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 1.0, 2.0, 1.0, 3.0, 3.0, 2.0, 2.0, 2.0, 2.0, 3.0, 2.0, 1.0, 2.0, 1.0, 1.0, 1.0, 1.0, 1.0, 2.0, 2.0, 2.0, 2.0, 1.0, 2.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 5.0, 4.0, 1.0, 2.0, 2.0, 2.0, 1.0, 1.0, 2.0, 2.0, 2.0, 2.0, 1.0, 1.0, 1.0, 1.0, 2.0, 1.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 1.0, 1.0, 1.0, 1.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 6.0, 3.0, 2.0, 2.0, 1.0, 1.0, 1.0, 1.0, 1.0, 2.0, 2.0, 1.0, 2.0, 1.0, 1.0, 1.0, 1.0, 2.0, 2.0, 1.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 1.0, 1.0, 1.0, 1.0, 2.0, 2.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 2.0, 2.0, 2.0, 2.0, 2.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 2.0, 2.0, 1.0, 1.0, 2.0, 1.0, 1.0, 2.0, 2.0, 2.0, 2.0]}, "b": 0.75, "k1": 1.2, "lower_case": true, "remove_punctuation": true, "remove_stopwords": true, "stem": true, "language": "english"}
|
Finance-RAG/artifacts/client_secret_330901082226-f5jag2m50pripvslninfng7ej0c05kqd.apps.googleusercontent.com.json
ADDED
@@ -0,0 +1 @@
|
|
|
|
|
1 |
+
{"web":{"client_id":"330901082226-f5jag2m50pripvslninfng7ej0c05kqd.apps.googleusercontent.com","project_id":"finance-rag-97b85","auth_uri":"https://accounts.google.com/o/oauth2/auth","token_uri":"https://oauth2.googleapis.com/token","auth_provider_x509_cert_url":"https://www.googleapis.com/oauth2/v1/certs","client_secret":"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","redirect_uris":["http://localhost:8501/"]}}
|
Finance-RAG/artifacts/report.html
ADDED
The diff for this file is too large to render.
See raw diff
|
|
Finance-RAG/artifacts/sample_financial_analysis_data.xlsx
ADDED
Binary file (148 kB). View file
|
|
Finance-RAG/pages/Chat_With_Data.py
ADDED
@@ -0,0 +1,355 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import streamlit as st
|
2 |
+
import re
|
3 |
+
import os
|
4 |
+
from langchain_text_splitters import RecursiveCharacterTextSplitter
|
5 |
+
from langchain_community.embeddings import HuggingFaceBgeEmbeddings
|
6 |
+
from openai import OpenAI
|
7 |
+
from langchain_openai import OpenAIEmbeddings
|
8 |
+
from langchain_community.retrievers import PineconeHybridSearchRetriever
|
9 |
+
from pinecone import Pinecone, ServerlessSpec # Use Pinecone class and ServerlessSpec
|
10 |
+
from pinecone_text.sparse import BM25Encoder
|
11 |
+
from dotenv import load_dotenv
|
12 |
+
from PyPDF2 import PdfReader
|
13 |
+
from langchain_community.document_loaders import PyMuPDFLoader
|
14 |
+
from youtube_transcript_api import YouTubeTranscriptApi
|
15 |
+
import tempfile
|
16 |
+
|
17 |
+
# For reranking
|
18 |
+
from langchain.retrievers import ContextualCompressionRetriever
|
19 |
+
from langchain.retrievers.document_compressors import CrossEncoderReranker
|
20 |
+
from langchain_community.cross_encoders import HuggingFaceCrossEncoder
|
21 |
+
|
22 |
+
# Load environment variables
|
23 |
+
load_dotenv()
|
24 |
+
|
25 |
+
st.markdown(
|
26 |
+
"""
|
27 |
+
<style>
|
28 |
+
.block-container {
|
29 |
+
padding-top: 1rem;
|
30 |
+
padding-bottom: 0rem;
|
31 |
+
# padding-left: 2rem;
|
32 |
+
# padding-right:2rem;
|
33 |
+
}
|
34 |
+
.top-margin{
|
35 |
+
margin-top: 4rem;
|
36 |
+
margin-bottom:2rem;
|
37 |
+
}
|
38 |
+
.block-button{
|
39 |
+
padding: 10px;
|
40 |
+
width: 100%;
|
41 |
+
background-color: #c4fcce;
|
42 |
+
}
|
43 |
+
</style>
|
44 |
+
""",
|
45 |
+
unsafe_allow_html=True,
|
46 |
+
)
|
47 |
+
|
48 |
+
class DataProcessing:
|
49 |
+
|
50 |
+
def __init__(self):
|
51 |
+
self.splitter = RecursiveCharacterTextSplitter(chunk_size=1000, chunk_overlap=250)
|
52 |
+
|
53 |
+
# Initialize BM25 Encoder and Pinecone in session state if not already done
|
54 |
+
if 'bm25' not in st.session_state:
|
55 |
+
st.session_state.bm25 = BM25Encoder().default()
|
56 |
+
|
57 |
+
# Initialize Pinecone client using the new class-based API
|
58 |
+
if 'pinecone_client' not in st.session_state:
|
59 |
+
st.session_state.pinecone_client = Pinecone(api_key=os.getenv('PINECONE_API_KEY'))
|
60 |
+
|
61 |
+
self.index_name = "rag-finance"
|
62 |
+
self.embedding_model = OpenAIEmbeddings(api_key=os.getenv('OPENAI_API_KEY'))
|
63 |
+
|
64 |
+
# Store the client of OpenAI in Streamlit session state
|
65 |
+
if 'openai_client' not in st.session_state:
|
66 |
+
st.session_state.openai_client = OpenAI(api_key=os.getenv('OPENAI_API_KEY'))
|
67 |
+
self.client = st.session_state.openai_client
|
68 |
+
|
69 |
+
# Check if the index exists before using it
|
70 |
+
if 'pinecone_index' not in st.session_state:
|
71 |
+
# Check if index exists; if not, create it
|
72 |
+
if self.index_name not in st.session_state.pinecone_client.list_indexes().names():
|
73 |
+
st.session_state.pinecone_client.create_index(
|
74 |
+
name=self.index_name,
|
75 |
+
dimension=1536, # Assuming vector dimension is 1536
|
76 |
+
metric='dotproduct',
|
77 |
+
spec=ServerlessSpec(cloud='aws', region='us-east-1')
|
78 |
+
)
|
79 |
+
st.session_state.pinecone_index = st.session_state.pinecone_client.Index(self.index_name)
|
80 |
+
|
81 |
+
self.index = st.session_state.pinecone_index
|
82 |
+
self.bm25 = st.session_state.bm25
|
83 |
+
|
84 |
+
# Initialize the reranker and retriever
|
85 |
+
self.model = HuggingFaceCrossEncoder(model_name="BAAI/bge-reranker-base")
|
86 |
+
self.compressor = CrossEncoderReranker(model=self.model, top_n=4)
|
87 |
+
|
88 |
+
# The retriever will be initialized later when the corpus is available
|
89 |
+
self.retriever = None
|
90 |
+
|
91 |
+
def initialize_compression_retriever(self):
|
92 |
+
"""Initialize compression retriever using the base retriever"""
|
93 |
+
self.compression_retriever = ContextualCompressionRetriever(
|
94 |
+
base_compressor=self.compressor, base_retriever=self.retriever
|
95 |
+
)
|
96 |
+
|
97 |
+
def get_youtube_id(self, url):
|
98 |
+
regex = (
|
99 |
+
r'(https?://)?(www\.)?(youtube|youtu|youtube-nocookie)\.(com|be)/(watch\?v=|embed/|v/|.+\?v=)?([^&=%\?]{11})')
|
100 |
+
match = re.match(regex, url)
|
101 |
+
return match.group(6) if match else None
|
102 |
+
|
103 |
+
def process_youtube(self, youtube_id, corpus):
|
104 |
+
try:
|
105 |
+
result = YouTubeTranscriptApi.get_transcript(youtube_id)
|
106 |
+
yt_captions = ""
|
107 |
+
for item in iter(result):
|
108 |
+
yt_captions += item['text'] + " "
|
109 |
+
except (YouTubeTranscriptApi.TranscriptsDisabled, YouTubeTranscriptApi.NoTranscriptFound):
|
110 |
+
st.error("Transcript is disabled or not found for this video.")
|
111 |
+
|
112 |
+
chunks = self.splitter.create_documents([yt_captions])
|
113 |
+
for chunk in chunks:
|
114 |
+
corpus.append(chunk.page_content)
|
115 |
+
|
116 |
+
def process_pdf(self, pdf_file, corpus):
|
117 |
+
if pdf_file is not None:
|
118 |
+
try:
|
119 |
+
with tempfile.NamedTemporaryFile(delete=False, suffix=".pdf") as tmp_file:
|
120 |
+
tmp_file.write(pdf_file.getvalue())
|
121 |
+
tmp_file_path = tmp_file.name
|
122 |
+
|
123 |
+
# Use PyMuPDFLoader to process the file
|
124 |
+
loader = PyMuPDFLoader(tmp_file_path)
|
125 |
+
data = loader.load()
|
126 |
+
|
127 |
+
os.unlink(tmp_file_path)
|
128 |
+
|
129 |
+
content = ""
|
130 |
+
for doc in data:
|
131 |
+
content += doc.page_content
|
132 |
+
chunks = self.splitter.create_documents([content])
|
133 |
+
for chunk in chunks:
|
134 |
+
corpus.append(chunk.page_content)
|
135 |
+
except Exception as e:
|
136 |
+
st.error(f"An error occurred while processing the PDF: {str(e)}")
|
137 |
+
|
138 |
+
def process_whatsapp(self, text, corpus):
|
139 |
+
"""
|
140 |
+
Process a conversation text by removing timestamps and '<Media omitted>' lines, then split the text into chunks and add them to the corpus.
|
141 |
+
|
142 |
+
Args:
|
143 |
+
text (str): The conversation text to process.
|
144 |
+
corpus (list): The list of documents to which the processed chunks will be added.
|
145 |
+
"""
|
146 |
+
# Regex to match the time only, keeping the date intact
|
147 |
+
pattern = r"(?<=^\d{2}/\d{2}/\d{2}), \d{1,2}:\d{2}(?:\u202f)?(?:am|pm) -"
|
148 |
+
|
149 |
+
# Process each line
|
150 |
+
processed_lines = []
|
151 |
+
for line in text.splitlines():
|
152 |
+
# Remove only the time from the beginning, keeping the date
|
153 |
+
cleaned_line = re.sub(pattern, '', line).strip()
|
154 |
+
|
155 |
+
# Remove any line containing '<Media omitted>'
|
156 |
+
if '<Media omitted>' not in cleaned_line and cleaned_line:
|
157 |
+
processed_lines.append(cleaned_line)
|
158 |
+
|
159 |
+
complete_text = "\n".join(processed_lines)
|
160 |
+
chunks = self.splitter.create_documents([complete_text])
|
161 |
+
for chunk in chunks:
|
162 |
+
corpus.append(chunk.page_content)
|
163 |
+
|
164 |
+
|
165 |
+
def improve_query(self, user_query):
|
166 |
+
"""
|
167 |
+
This function takes a user's raw query in Hinglish (Hindi + English) and improves it to make it clearer, more detailed, and optimal for document retrieval systems.
|
168 |
+
It uses the OpenAI API to generate a response based on the context and query, refining the query by adding clarity, removing ambiguity, and adding any missing context.
|
169 |
+
The intent of the question remains the same while enhancing its clarity.
|
170 |
+
|
171 |
+
Args:
|
172 |
+
user_query (str): The user's raw query in Hinglish (Hindi + English).
|
173 |
+
|
174 |
+
Returns:
|
175 |
+
str: The optimized query for document retrieval systems.
|
176 |
+
"""
|
177 |
+
|
178 |
+
# Define the prompt template with Hinglish support
|
179 |
+
prompt_template = f"""
|
180 |
+
### Task Description:
|
181 |
+
You are an assistant that specializes in improving user questions to make them clearer, more detailed, and optimal for document retrieval systems.
|
182 |
+
You will be provided with a user's raw query in Hinglish (Hindi + English). Your task is to rephrase the query by making it more specific, removing ambiguity, and adding any missing context that can help the system provide the best possible answer.
|
183 |
+
Make sure the intent of the question remains the same while enhancing its clarity.
|
184 |
+
|
185 |
+
### Instructions:
|
186 |
+
1. Take the user's raw query, which may be in Hinglish (Hindi + English).
|
187 |
+
2. If the query is vague, refine it by adding clarity and ensuring all parts of the question are meaningful.
|
188 |
+
3. Make the query as specific as possible without changing the original intent.
|
189 |
+
4. If necessary, add any additional context that could assist the retrieval system in providing the best response.
|
190 |
+
|
191 |
+
### Input:
|
192 |
+
User's Raw Query: "{user_query}"
|
193 |
+
|
194 |
+
### Output:
|
195 |
+
Query:
|
196 |
+
"""
|
197 |
+
|
198 |
+
# Call the OpenAI API to generate the response based on context and query
|
199 |
+
response = self.client.chat.completions.create(
|
200 |
+
model="gpt-4o-mini", # Replace this with the actual model if needed
|
201 |
+
messages=[
|
202 |
+
{"role": "system", "content": "You are a helpful assistant."},
|
203 |
+
{"role": "user", "content": prompt_template}
|
204 |
+
],
|
205 |
+
temperature=0.7,
|
206 |
+
top_p=1,
|
207 |
+
n=1
|
208 |
+
)
|
209 |
+
|
210 |
+
# Extract the optimized query from the response
|
211 |
+
optimized_query = response.choices[0].message.content.strip()
|
212 |
+
return optimized_query
|
213 |
+
|
214 |
+
def generate_response(self, context_data, query):
|
215 |
+
"""
|
216 |
+
Generate a prompt for the GPT-4-mini model to provide a clear, accurate, and well-structured response
|
217 |
+
based on the query and the given context data, with a heading "AI Response:".
|
218 |
+
|
219 |
+
Args:
|
220 |
+
context_data (str): The context data that serves as input for the model.
|
221 |
+
query (str): The specific query provided by the user.
|
222 |
+
|
223 |
+
Returns:
|
224 |
+
str: The generated response from GPT-4-mini.
|
225 |
+
"""
|
226 |
+
|
227 |
+
# Create a prompt that instructs the AI to respond with a heading "AI Response:" before the actual output
|
228 |
+
prompt_template = f"""
|
229 |
+
You are an intelligent assistant (GPT-4-mini) tasked with providing a detailed, accurate, and concise response
|
230 |
+
based on the following context and query:
|
231 |
+
|
232 |
+
Context:
|
233 |
+
\"{context_data}\"
|
234 |
+
|
235 |
+
Query:
|
236 |
+
\"{query}\"
|
237 |
+
|
238 |
+
Guidelines:
|
239 |
+
1. Begin your response with the heading: **AI Response:**
|
240 |
+
2. Carefully analyze both the context and the query to generate a comprehensive and relevant response.
|
241 |
+
3. Ensure that the response is well-structured, uses clear language, and is factually accurate.
|
242 |
+
4. If the context or query is unclear or ambiguous, politely ask the user for clarification or to rephrase the question.
|
243 |
+
|
244 |
+
Example response formats:
|
245 |
+
- "AI Response: Based on the context provided and your query, here is the relevant information..."
|
246 |
+
- "AI Response: The context and query provided are unclear. Could you please rephrase the question or provide more specific information?"
|
247 |
+
|
248 |
+
Please provide your response below.
|
249 |
+
"""
|
250 |
+
|
251 |
+
try:
|
252 |
+
# Call the OpenAI API to generate the response based on context and query
|
253 |
+
response = self.client.chat.completions.create(
|
254 |
+
model="gpt-4o-mini", # Replace this with the actual model if needed
|
255 |
+
messages=[
|
256 |
+
{"role": "system", "content": "You are a helpful assistant."},
|
257 |
+
{"role": "user", "content": prompt_template}
|
258 |
+
],
|
259 |
+
temperature=0.7,
|
260 |
+
top_p=1,
|
261 |
+
n=1
|
262 |
+
)
|
263 |
+
|
264 |
+
# Extract the generated response text
|
265 |
+
generated_response = response.choices[0].message.content.strip()
|
266 |
+
return generated_response
|
267 |
+
|
268 |
+
except Exception as e:
|
269 |
+
return f"An error occurred while generating the response: {str(e)}"
|
270 |
+
|
271 |
+
|
272 |
+
def chat_with_docs():
|
273 |
+
dp_obj = DataProcessing()
|
274 |
+
corpus = []
|
275 |
+
|
276 |
+
# File upload options for PDF, WhatsApp, and YouTube transcript
|
277 |
+
st.title("Chat with your Data")
|
278 |
+
st.write("**********")
|
279 |
+
pdf_tab, whatsapp_tab, youtube_tab = st.columns(spec=(1,1,1), gap="large")
|
280 |
+
with pdf_tab:
|
281 |
+
pdf_upload = st.file_uploader("Choose a PDF file", type="pdf", accept_multiple_files=False, key="pdf_upload")
|
282 |
+
if pdf_upload:
|
283 |
+
with st.spinner("Processing PDF..."):
|
284 |
+
dp_obj.process_pdf(pdf_upload, corpus)
|
285 |
+
st.success("PDF document uploaded and setup")
|
286 |
+
with whatsapp_tab:
|
287 |
+
chat_upload = st.file_uploader("Upload the Whatsapp chat text file", type="txt", accept_multiple_files=False, key="chat_upload")
|
288 |
+
if chat_upload is not None:
|
289 |
+
with st.spinner("Processing WhatsApp chat..."):
|
290 |
+
raw_text = chat_upload.read().decode("utf-8")
|
291 |
+
dp_obj.process_whatsapp(raw_text, corpus)
|
292 |
+
st.success("WhatsApp chat uploaded and setup")
|
293 |
+
with youtube_tab:
|
294 |
+
youtube_link = st.text_input("Enter a YouTube Link")
|
295 |
+
youtube_id = dp_obj.get_youtube_id(youtube_link)
|
296 |
+
if youtube_id:
|
297 |
+
with st.spinner("Processing YouTube transcript..."):
|
298 |
+
dp_obj.process_youtube(youtube_id, corpus)
|
299 |
+
st.success("YouTube transcript uploaded and setup")
|
300 |
+
|
301 |
+
if corpus:
|
302 |
+
|
303 |
+
dp_obj.bm25.fit(corpus)
|
304 |
+
dp_obj.bm25.dump(r"artifacts/bm25_values.json")
|
305 |
+
dp_obj.bm25 = BM25Encoder().load(r"artifacts/bm25_values.json")
|
306 |
+
dp_obj.retriever = PineconeHybridSearchRetriever(
|
307 |
+
embeddings=dp_obj.embedding_model,
|
308 |
+
sparse_encoder=dp_obj.bm25,
|
309 |
+
index=dp_obj.index,
|
310 |
+
top_k=5
|
311 |
+
)
|
312 |
+
|
313 |
+
# Add the corpus to the retriever and initialize the compression retriever
|
314 |
+
dp_obj.retriever.add_texts(corpus)
|
315 |
+
dp_obj.initialize_compression_retriever()
|
316 |
+
|
317 |
+
# Use st.chat_message for displaying messages
|
318 |
+
st.write("**********")
|
319 |
+
with st.chat_message("system"):
|
320 |
+
st.write("You can upload documents and ask questions based on the context.")
|
321 |
+
|
322 |
+
# Use st.chat_input to capture the user's query in a chat-like format
|
323 |
+
query_input = st.chat_input("Ask your query")
|
324 |
+
if query_input:
|
325 |
+
with st.spinner("Optimizing your query for the best response..."):
|
326 |
+
improved_query = dp_obj.improve_query(query_input)
|
327 |
+
with st.chat_message("user"):
|
328 |
+
st.write(f"User Query: {query_input}")
|
329 |
+
|
330 |
+
with st.chat_message("system"):
|
331 |
+
st.write(f"Improved Query: {improved_query}")
|
332 |
+
|
333 |
+
|
334 |
+
try:
|
335 |
+
sparse_vector = dp_obj.bm25.encode_queries([query_input])
|
336 |
+
if not sparse_vector[0]:
|
337 |
+
st.warning("The query resulted in an empty sparse vector. Try a different query.")
|
338 |
+
else:
|
339 |
+
# Use the compression retriever to get reranked documents
|
340 |
+
compressed_docs = dp_obj.compression_retriever.invoke(query_input)
|
341 |
+
context_data = ""
|
342 |
+
for doc in compressed_docs:
|
343 |
+
context_data += doc.page_content
|
344 |
+
|
345 |
+
with st.chat_message("system"):
|
346 |
+
with st.spinner("Generating response..."):
|
347 |
+
response = dp_obj.generate_response(query=improved_query, context_data=context_data)
|
348 |
+
st.write(response)
|
349 |
+
except Exception as e:
|
350 |
+
st.error(f"An error occurred while processing the query: {str(e)}")
|
351 |
+
else:
|
352 |
+
st.warning("No documents processed. Please upload or enter content to process.")
|
353 |
+
|
354 |
+
|
355 |
+
chat_with_docs()
|
Finance-RAG/pages/Excel_Processing_And_Analysis.py
ADDED
@@ -0,0 +1,130 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import streamlit as st
|
2 |
+
import pandas as pd
|
3 |
+
from openai import OpenAI
|
4 |
+
import os
|
5 |
+
from ydata_profiling import ProfileReport
|
6 |
+
|
7 |
+
st.markdown(
|
8 |
+
"""
|
9 |
+
<style>
|
10 |
+
.block-container {
|
11 |
+
padding-top: 1rem;
|
12 |
+
padding-bottom: 0rem;
|
13 |
+
# padding-left: 2rem;
|
14 |
+
# padding-right:2rem;
|
15 |
+
}
|
16 |
+
.top-margin{
|
17 |
+
margin-top: 4rem;
|
18 |
+
margin-bottom:2rem;
|
19 |
+
}
|
20 |
+
.block-button{
|
21 |
+
padding: 10px;
|
22 |
+
width: 100%;
|
23 |
+
background-color: #c4fcce;
|
24 |
+
}
|
25 |
+
</style>
|
26 |
+
""",
|
27 |
+
unsafe_allow_html=True,
|
28 |
+
)
|
29 |
+
|
30 |
+
client = OpenAI(api_key=os.getenv('OPENAI_API_KEY'))
|
31 |
+
|
32 |
+
def analyze_file(dataframe, output_path):
|
33 |
+
"""
|
34 |
+
Analyzes the given dataframe and generates a report using pandas profiling.
|
35 |
+
|
36 |
+
Parameters:
|
37 |
+
- dataframe (pd.DataFrame): The pandas dataframe to be analyzed.
|
38 |
+
- output_path (str): The directory path where the report will be saved.
|
39 |
+
|
40 |
+
Returns:
|
41 |
+
- str: The file path of the generated report.
|
42 |
+
"""
|
43 |
+
# Performing automatic EDA
|
44 |
+
profile = ProfileReport(dataframe, title="Pandas Profiling Report")
|
45 |
+
final_path = os.path.join(output_path,"report.html")
|
46 |
+
profile.to_file(final_path)
|
47 |
+
|
48 |
+
return final_path
|
49 |
+
|
50 |
+
def excel_processing_and_analysis():
|
51 |
+
"""
|
52 |
+
This function enables the user to upload an Excel file and perform various data processing and analysis tasks.
|
53 |
+
It provides an interface to select a sheet from the uploaded file, display a preview of the sheet, and initiate an analysis process.
|
54 |
+
The analysis process generates a report using pandas profiling, which is then made available for download.
|
55 |
+
|
56 |
+
This function is designed to facilitate data analysis and visualization for Excel files, particularly for financial data such as sales, expenses, COGS, and balance sheet data.
|
57 |
+
It aims to provide insights into the data, helping users make informed decisions and understand trends within their data.
|
58 |
+
"""
|
59 |
+
|
60 |
+
upload_tab, display_tab = st.columns(spec=(3,1), gap="large")
|
61 |
+
with upload_tab:
|
62 |
+
st.title("Excel Processing and Analysis")
|
63 |
+
st.write("This page allows you to upload an Excel file and perform various data processing and analysis tasks. With power of large language models and statistical techniques, this module will help you to perform a complete analysis of your Excel file, providing insights into your data and helping you make informed decisions. You will also get interactive graphs to visualize your data and trends.")
|
64 |
+
|
65 |
+
# File upload
|
66 |
+
uploaded_file = st.file_uploader("Choose an Excel file", type=["xlsx", "xls"])
|
67 |
+
|
68 |
+
if uploaded_file is not None:
|
69 |
+
with display_tab:
|
70 |
+
st.write("")
|
71 |
+
st.write("")
|
72 |
+
st.write("")
|
73 |
+
st.success(f"File {uploaded_file.name} uploaded successfully!")
|
74 |
+
|
75 |
+
if uploaded_file is not None:
|
76 |
+
file_path = uploaded_file
|
77 |
+
excel_file = pd.ExcelFile(file_path)
|
78 |
+
sheet_names = excel_file.sheet_names
|
79 |
+
|
80 |
+
# Display sheet names as markdown
|
81 |
+
st.markdown("#### Available Sheets📂")
|
82 |
+
selected_sheet = st.selectbox("Select a sheet to analyze", sheet_names)
|
83 |
+
|
84 |
+
start_analysis = False
|
85 |
+
if selected_sheet:
|
86 |
+
df = pd.read_excel(file_path, sheet_name=selected_sheet)
|
87 |
+
sheet_display, description = st.columns(spec=(1,1), gap="small")
|
88 |
+
with sheet_display:
|
89 |
+
st.dataframe(df.head(5))
|
90 |
+
with description:
|
91 |
+
if selected_sheet == 'Sales Data':
|
92 |
+
st.write("The Sales Data sheet is crucial for understanding the revenue streams of the business. It helps in analyzing total revenue, identifying key customers, understanding sales trends over different time periods, and evaluating the performance of different products. Insights from this sheet can be used to determine which products are high-performing, which customer segments are most profitable, and to monitor revenue growth. It also provides foundational data for the Profit & Loss (PnL) analysis.")
|
93 |
+
if st.button("Start Analysis", key="start_analysis_sales", use_container_width=True):
|
94 |
+
start_analysis = True
|
95 |
+
report_path = analyze_file(df,"artifacts")
|
96 |
+
|
97 |
+
elif selected_sheet == 'Expenses':
|
98 |
+
st.write("The Expenses sheet is essential for monitoring and controlling the costs of the business. Tracking expenses helps in understanding where money is being spent and identifying opportunities to reduce costs or improve efficiency. This sheet also provides input for calculating net profit, as it details all costs that need to be subtracted from gross revenue. Analyzing expenses also supports budgeting and helps identify areas that might need cost-cutting measures.")
|
99 |
+
if st.button("Start Analysis", key="start_analysis_expenses", use_container_width=True):
|
100 |
+
start_analysis = True
|
101 |
+
report_path = analyze_file(df,"artifacts")
|
102 |
+
|
103 |
+
elif selected_sheet == 'COGS':
|
104 |
+
st.write("The COGS sheet is vital for calculating the gross profit of the business. By understanding how much it costs to produce each product, a company can determine profitability at a product level. It helps in identifying the cost efficiency of production processes and in setting appropriate product pricing. Gross profit, calculated as revenue minus COGS, is a key metric to evaluate whether the business is covering its direct costs and how much margin is available to cover operating expenses.")
|
105 |
+
if st.button("Start Analysis", key="start_analysis_cogs", use_container_width=True):
|
106 |
+
start_analysis = True
|
107 |
+
report_path = analyze_file(df,"artifacts")
|
108 |
+
|
109 |
+
elif selected_sheet == 'Balance Sheet Data':
|
110 |
+
st.write("The Balance Sheet Data sheet is used to evaluate the overall financial health of the company. It shows what the company owns (assets), what it owes (liabilities), and the net worth (equity). This sheet is crucial for understanding liquidity, solvency, and the financial stability of the business. It helps in assessing whether the company has enough assets to cover its liabilities, understanding the capital structure, and calculating important financial ratios such as the current ratio and debt-to-equity ratio. The balance sheet data also helps stakeholders understand the long-term sustainability of the company.")
|
111 |
+
if st.button("Start Analysis", key="start_analysis_balance", use_container_width=True):
|
112 |
+
start_analysis = True
|
113 |
+
report_path = analyze_file(df,"artifacts")
|
114 |
+
else:
|
115 |
+
if st.button("Start Analysis", key="start_analysis_sales", use_container_width=True):
|
116 |
+
start_analysis = True
|
117 |
+
report_path = analyze_file(df,"artifacts")
|
118 |
+
|
119 |
+
|
120 |
+
if start_analysis:
|
121 |
+
st.success("Analysis Completed Successfully!")
|
122 |
+
st.download_button(
|
123 |
+
label="Download Analysis Report",
|
124 |
+
data=open(report_path, 'rb').read(),
|
125 |
+
file_name="analysis_report.html",
|
126 |
+
mime='text/html'
|
127 |
+
)
|
128 |
+
|
129 |
+
|
130 |
+
excel_processing_and_analysis()
|
Finance-RAG/pages/NDA_Creation.py
ADDED
@@ -0,0 +1,189 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import streamlit as st
|
2 |
+
from docx import Document
|
3 |
+
from docx.shared import Pt
|
4 |
+
from docx.oxml.ns import qn
|
5 |
+
from io import BytesIO
|
6 |
+
from src.logger import logging
|
7 |
+
import os
|
8 |
+
import subprocess
|
9 |
+
|
10 |
+
st.markdown(
|
11 |
+
"""
|
12 |
+
<style>
|
13 |
+
.block-container {
|
14 |
+
padding-top: 1rem;
|
15 |
+
padding-bottom: 0rem;
|
16 |
+
}
|
17 |
+
.top-margin{
|
18 |
+
margin-top: 4rem;
|
19 |
+
margin-bottom:2rem;
|
20 |
+
}
|
21 |
+
.block-button{
|
22 |
+
padding: 10px;
|
23 |
+
width: 100%;
|
24 |
+
background-color: #c4fcce;
|
25 |
+
}
|
26 |
+
</style>
|
27 |
+
""",
|
28 |
+
unsafe_allow_html=True,
|
29 |
+
)
|
30 |
+
|
31 |
+
def create_nda_response(company_party, service_provider_party, company_address, service_provider_address, dates, time_period, jurisdiction, item):
|
32 |
+
return f"""
|
33 |
+
# Non-Disclosure Agreement (NDA)
|
34 |
+
|
35 |
+
**This Agreement made on this {dates.day} day of {dates.strftime("%B")}, {dates.year}**
|
36 |
+
|
37 |
+
By and Between
|
38 |
+
|
39 |
+
**{company_party}**, a company incorporated under the Companies Act, 1956 and having its registered office at {company_address} (hereinafter referred to as “Company”, which expression shall unless repugnant to the context or meaning thereof, include its successors in interests and assigns) of the one part;
|
40 |
+
|
41 |
+
And
|
42 |
+
|
43 |
+
**{service_provider_party}**, a company incorporated under the Companies Act, 2013 and having its registered office at {service_provider_address} (hereinafter referred to as “Service Provider”, which expression shall, unless repugnant to the context or meaning thereof, be deemed to include its representatives and permitted assigns) of the other part;
|
44 |
+
|
45 |
+
**Company** and **Service Provider** shall hereinafter be referred to as such or collectively as “Parties” and individually as “Party”.
|
46 |
+
|
47 |
+
---
|
48 |
+
|
49 |
+
**WHEREAS** both the Parties herein wish to pursue discussions and negotiate with each other for the purpose of entering into a potential business arrangement in relation to {item} (“Proposed Transaction”);
|
50 |
+
|
51 |
+
**AND WHEREAS** the Parties contemplate that with respect to the Proposed Transaction, both the Parties may exchange certain information, material and documents relating to each other’s business, assets, financial condition, operations, plans and/or prospects of their businesses (hereinafter referred to as “Confidential Information”, more fully detailed in clause 1 herein below) that each Party regards as proprietary and confidential;
|
52 |
+
|
53 |
+
**AND WHEREAS**, each Party wishes to review such Confidential Information of the other for the sole purpose of determining their mutual interest in engaging in the Proposed Transaction;
|
54 |
+
|
55 |
+
---
|
56 |
+
|
57 |
+
IN CONNECTION WITH THE ABOVE, THE PARTIES HEREBY AGREE AS FOLLOWS:
|
58 |
+
|
59 |
+
1. “Confidential and/or proprietary Information” shall mean and include any information disclosed by one Party (Disclosing Party) to the other (Receiving Party) either directly or indirectly, in writing, orally, by inspection of tangible objects. Confidential information shall include, without limitation, any materials, trade secrets, network information, configurations, trademarks, brand name, know-how, business and marketing plans, financial and operational information, and all other non-public information, material or data relating to the current and/or future business and operations of the Disclosing Party.
|
60 |
+
|
61 |
+
2. The Receiving Party shall refrain from disclosing, reproducing, summarizing and/or distributing Confidential Information and confidential materials of the Disclosing Party except in connection with the Proposed Transaction.
|
62 |
+
|
63 |
+
3. The Parties shall protect the confidentiality of each other’s Confidential Information in the same manner as they protect the confidentiality of their own proprietary and confidential information of similar nature. Each Party, while acknowledging the confidential and proprietary nature of the Confidential Information agrees to take all reasonable measures at its own expense to restrain its representatives from prohibited or unauthorized disclosure or use of the Confidential Information.
|
64 |
+
|
65 |
+
4. Confidential Information shall at all times remain the property of the Disclosing Party and may not be copied or reproduced by the Receiving Party without the Disclosing Party’s prior written consent.
|
66 |
+
|
67 |
+
5. Within seven (7) days of a written request by the Disclosing Party, the Receiving Party shall return/destroy (as may be requested in writing by the Disclosing Party or upon expiry and or earlier termination) all originals, copies, reproductions and summaries of Confidential Information provided to the Receiving Party as Confidential Information. The Receiving Party shall certify to the Disclosing Party in writing that it has satisfied its obligations under this paragraph.
|
68 |
+
|
69 |
+
6. The Receiving Party may disclose the Confidential Information only to the Receiving Party's employees and consultants on a need-to-know basis. The Receiving Party shall have executed or shall execute appropriate written agreements with third parties, in a form and manner sufficient to enable the Receiving Party to enforce all the provisions of this Agreement.
|
70 |
+
|
71 |
+
7. Confidential Information, however, shall not include any information which the Receiving Party can show:
|
72 |
+
- i) is in or comes into the public domain otherwise than through a breach of this Agreement or the fault of the Receiving Party; or
|
73 |
+
- ii) was already in its possession free of any such restriction prior to receipt from the Disclosing Party; or
|
74 |
+
- iii) was independently developed by the Receiving Party without making use of the Confidential Information; or
|
75 |
+
- iv) has been approved for release or use (in either case without restriction) by written authorization of the Disclosing Party.
|
76 |
+
|
77 |
+
8. In the event either Party receives a summons or other validly issued administrative or judicial process requiring the disclosure of Confidential Information of the other Party, the Receiving Party shall promptly notify the Disclosing Party. The Receiving Party may disclose Confidential Information to the extent such disclosure is required by law, rule, regulation, or legal process; provided however, that, to the extent practicable, the Receiving Party shall give prompt written notice of any such request for such information to the Disclosing Party, and agrees to cooperate with the Disclosing Party, at the Disclosing Party’s expense, to the extent permissible and practicable, to challenge the request or limit the scope thereof, as the Disclosing Party may reasonably deem appropriate.
|
78 |
+
|
79 |
+
9. Neither Party shall use the other’s name, trademarks, proprietary words or symbols or disclose under this Agreement in any publication, press release, marketing material, or otherwise without the prior written approval of the other.
|
80 |
+
|
81 |
+
10. This Agreement shall be governed by the laws of India. Both parties irrevocably submit to the exclusive jurisdiction of the Courts in {jurisdiction}, for any action or proceeding regarding this Agreement.
|
82 |
+
|
83 |
+
---
|
84 |
+
|
85 |
+
**IN WITNESS WHEREOF**, the Parties hereto have executed this confidentiality agreement in duplicate by affixing the signature of the authorized representatives as of the date herein above mentioned.
|
86 |
+
|
87 |
+
Party 1: ______
|
88 |
+
Signature 1: ______
|
89 |
+
Name: ______
|
90 |
+
Designation: ______
|
91 |
+
Place: ______
|
92 |
+
Date: ______
|
93 |
+
|
94 |
+
Party 2: ______
|
95 |
+
Signature 2: ______
|
96 |
+
Name: ______
|
97 |
+
Designation: ______
|
98 |
+
Place: ______
|
99 |
+
Date: ______
|
100 |
+
"""
|
101 |
+
|
102 |
+
def create_docx(nda_response):
|
103 |
+
# Create a new Document
|
104 |
+
doc = Document()
|
105 |
+
|
106 |
+
# Set the default font style to Times New Roman, 11pt
|
107 |
+
style = doc.styles['Normal']
|
108 |
+
font = style.font
|
109 |
+
font.name = 'Times New Roman'
|
110 |
+
font.size = Pt(11)
|
111 |
+
|
112 |
+
# Add the NDA content
|
113 |
+
for paragraph in nda_response.split("\n"):
|
114 |
+
doc.add_paragraph(paragraph)
|
115 |
+
|
116 |
+
# Save the document in a BytesIO object for download
|
117 |
+
buffer = BytesIO()
|
118 |
+
doc.save(buffer)
|
119 |
+
buffer.seek(0)
|
120 |
+
|
121 |
+
return buffer
|
122 |
+
|
123 |
+
def create_docx(output_md_path, doc_content):
|
124 |
+
"""
|
125 |
+
Saves the extracted information to a Markdown file and converts it to a DOCX file.
|
126 |
+
|
127 |
+
This method ensures the directory for the output file exists, overwrites the file if it already exists, and writes the provided doc_content to the file. After saving the content in Markdown format, it initiates the conversion process to DOCX format using Pandoc. The converted DOCX file is saved in the same directory with a predefined name.
|
128 |
+
|
129 |
+
Parameters:
|
130 |
+
- output_path (str): The path where the Markdown file will be saved.
|
131 |
+
- doc_content (str): The content to be written to the Markdown file.
|
132 |
+
|
133 |
+
Returns:
|
134 |
+
- None: This method does not return any value. It logs the progress and outcome of the operations.
|
135 |
+
"""
|
136 |
+
# Ensure the directory exists
|
137 |
+
os.makedirs(os.path.dirname(output_md_path), exist_ok=True)
|
138 |
+
|
139 |
+
# Overwrite the file if it exists
|
140 |
+
with open(output_md_path, "w") as md_file:
|
141 |
+
md_file.write(doc_content)
|
142 |
+
|
143 |
+
logging.info("Saved the content into markdown format ")
|
144 |
+
logging.info("Initializing markdown to docx conversion ")
|
145 |
+
docx_file_path = (
|
146 |
+
"/".join(output_md_path.split("/")[:2]) + "/NDA_Agreement.docx"
|
147 |
+
)
|
148 |
+
subprocess.run(["pandoc", output_md_path, "-o", docx_file_path], check=True)
|
149 |
+
return docx_file_path
|
150 |
+
|
151 |
+
def nda_creation_form():
|
152 |
+
st.title("NDA Creation Form")
|
153 |
+
|
154 |
+
input_tab, output_tab = st.columns(spec=(1,1), gap="large")
|
155 |
+
create_nda = False
|
156 |
+
with input_tab:
|
157 |
+
st.markdown("<p style='font-size: 18px;'>This module is specifically designed to streamline the process of creating a comprehensive Non-Disclosure Agreement (NDA). It is essential to provide all the necessary information as outlined below to ensure the initiation of the agreement creation process. Please ensure that all details are accurate and complete to facilitate a smooth and efficient process.</p>", unsafe_allow_html=True)
|
158 |
+
# Input fields for the NDA parameters
|
159 |
+
company_party = st.text_input("Company Party")
|
160 |
+
service_provider_party = st.text_input("Service Provider Party")
|
161 |
+
company_address = st.text_input("Company Address")
|
162 |
+
service_provider_address = st.text_input("Service Provider Address")
|
163 |
+
dates = st.date_input("Effective Dates")
|
164 |
+
time_period = st.text_input("Duration of Agreement")
|
165 |
+
jurisdiction = st.text_input("Governing Jurisdiction")
|
166 |
+
item = st.text_input("Subject Matter")
|
167 |
+
# Submit button
|
168 |
+
if st.button("Create NDA", use_container_width=True):
|
169 |
+
st.success("NDA details submitted successfully!")
|
170 |
+
create_nda = True
|
171 |
+
|
172 |
+
with output_tab:
|
173 |
+
if create_nda:
|
174 |
+
with st.spinner("Generating response..."):
|
175 |
+
nda_response = create_nda_response(company_party, service_provider_party, company_address, service_provider_address, dates, time_period, jurisdiction, item)
|
176 |
+
st.markdown(nda_response, unsafe_allow_html=True)
|
177 |
+
|
178 |
+
# Create DOCX file
|
179 |
+
# buffer = create_docx("artifacts",nda_response)
|
180 |
+
|
181 |
+
# # Provide download button for the generated DOCX
|
182 |
+
# st.download_button(
|
183 |
+
# label="Download NDA as DOCX",
|
184 |
+
# data=buffer,
|
185 |
+
# file_name="NDA_Agreement.docx",
|
186 |
+
# mime="application/vnd.openxmlformats-officedocument.wordprocessingml.document"
|
187 |
+
# )
|
188 |
+
|
189 |
+
nda_creation_form()
|
Finance-RAG/pages/Upload_Chat.py
ADDED
File without changes
|
Finance-RAG/requirements.txt
ADDED
@@ -0,0 +1,30 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
streamlit
|
2 |
+
openai
|
3 |
+
PyPDF2
|
4 |
+
requests
|
5 |
+
youtube_transcript_api
|
6 |
+
pinecone-client
|
7 |
+
python-dotenv
|
8 |
+
tiktoken
|
9 |
+
pandas
|
10 |
+
fpdf
|
11 |
+
numpy
|
12 |
+
xlsxwriter
|
13 |
+
openpyxl
|
14 |
+
seaborn
|
15 |
+
pytesseract
|
16 |
+
Pillow
|
17 |
+
python-docx
|
18 |
+
pdf2image
|
19 |
+
pymongo
|
20 |
+
matplotlib
|
21 |
+
streamlit-google-auth
|
22 |
+
langchain
|
23 |
+
langchain_community
|
24 |
+
pymupdf
|
25 |
+
sentence_transformers
|
26 |
+
pinecone_text
|
27 |
+
langchain_openai
|
28 |
+
firebase-admin
|
29 |
+
httpx-oauth
|
30 |
+
ydata-profiling
|
Finance-RAG/sample_balance_sheet.xlsx
ADDED
Binary file (38.5 kB). View file
|
|
Finance-RAG/sample_financial_data.xlsx
ADDED
Binary file (144 kB). View file
|
|
Finance-RAG/setup.py
ADDED
@@ -0,0 +1,37 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from setuptools import find_packages,setup
|
2 |
+
from typing import List
|
3 |
+
|
4 |
+
HYPEN_E_DOT='-e .'
|
5 |
+
def get_requirements(file_path:str)->List[str]:
|
6 |
+
'''
|
7 |
+
Reads the requirements from a file and returns them as a list of strings.
|
8 |
+
This function is designed to handle the case where the file contains a line '-e .',
|
9 |
+
which is a common pattern in Python project requirements files to indicate
|
10 |
+
that the project itself should be installed in editable mode. This line is removed
|
11 |
+
from the list of requirements before returning.
|
12 |
+
|
13 |
+
Parameters:
|
14 |
+
file_path (str): The path to the file containing the requirements.
|
15 |
+
|
16 |
+
Returns:
|
17 |
+
List[str]: A list of strings, each representing a requirement.
|
18 |
+
'''
|
19 |
+
requirements=[]
|
20 |
+
with open(file_path) as file_obj:
|
21 |
+
requirements=file_obj.readlines()
|
22 |
+
requirements=[req.replace("\n","") for req in requirements]
|
23 |
+
|
24 |
+
if HYPEN_E_DOT in requirements:
|
25 |
+
requirements.remove(HYPEN_E_DOT)
|
26 |
+
|
27 |
+
return requirements
|
28 |
+
|
29 |
+
setup(
|
30 |
+
name='fin_Rag',
|
31 |
+
version='0.0.1',
|
32 |
+
author='Yuvraj Singh',
|
33 |
+
author_email='ys2002github@gmail.com',
|
34 |
+
packages=find_packages(),
|
35 |
+
install_requires=get_requirements('requirements.txt')
|
36 |
+
|
37 |
+
)
|
Finance-RAG/src/__init__.py
ADDED
File without changes
|
Finance-RAG/src/exception.py
ADDED
@@ -0,0 +1,41 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import sys
|
2 |
+
from src.logger import logging
|
3 |
+
|
4 |
+
def error_message_detail(error,error_detail:sys):
|
5 |
+
'''
|
6 |
+
This function generates a detailed error message.
|
7 |
+
|
8 |
+
Parameters:
|
9 |
+
error (Exception): The error that occurred.
|
10 |
+
error_detail (sys): The details of the error.
|
11 |
+
|
12 |
+
Returns:
|
13 |
+
str: A detailed error message.
|
14 |
+
'''
|
15 |
+
_,_,exc_tb=error_detail.exc_info()
|
16 |
+
file_name=exc_tb.tb_frame.f_code.co_filename
|
17 |
+
error_message="Error occured in python script name [{0}] line number [{1}] error message[{2}]".format(
|
18 |
+
file_name,exc_tb.tb_lineno,str(error))
|
19 |
+
|
20 |
+
return error_message
|
21 |
+
|
22 |
+
|
23 |
+
|
24 |
+
class CustomException(Exception):
|
25 |
+
'''
|
26 |
+
This is a custom exception class that extends the base Exception class.
|
27 |
+
It also generates a detailed error message.
|
28 |
+
|
29 |
+
Parameters:
|
30 |
+
error_message (str): The error message.
|
31 |
+
error_detail (sys): The details of the error.
|
32 |
+
'''
|
33 |
+
def __init__(self,error_message,error_detail:sys):
|
34 |
+
super().__init__(error_message)
|
35 |
+
self.error_message=error_message_detail(error_message,error_detail=error_detail)
|
36 |
+
|
37 |
+
def __str__(self):
|
38 |
+
return self.error_message
|
39 |
+
|
40 |
+
|
41 |
+
|
Finance-RAG/src/logger.py
ADDED
@@ -0,0 +1,17 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import logging
|
2 |
+
import os
|
3 |
+
from datetime import datetime
|
4 |
+
|
5 |
+
LOG_FILE=f"{datetime.now().strftime('%m_%d_%Y_%H_%M_%S')}.log"
|
6 |
+
logs_path=os.path.join(os.getcwd(),"logs",LOG_FILE)
|
7 |
+
os.makedirs(logs_path,exist_ok=True)
|
8 |
+
|
9 |
+
LOG_FILE_PATH=os.path.join(logs_path,LOG_FILE)
|
10 |
+
|
11 |
+
logging.basicConfig(
|
12 |
+
filename=LOG_FILE_PATH,
|
13 |
+
format="[ %(asctime)s ] %(lineno)d %(name)s - %(levelname)s - %(message)s",
|
14 |
+
level=logging.INFO,
|
15 |
+
|
16 |
+
|
17 |
+
)
|