AxelFritz1 commited on
Commit
7013379
Β·
1 Parent(s): e1571d6

first commit

Browse files
.gitattributes CHANGED
@@ -33,3 +33,5 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
 
 
 
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
36
+ data/index.faiss filter=lfs diff=lfs merge=lfs -text
37
+ data/ filter=lfs diff=lfs merge=lfs -text
.gitignore ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ __pycache__/
2
+ .vscode/
3
+ .chainlit/
4
+ .idea/
5
+
6
+ .env
7
+ env/
8
+ venv/
9
+
10
+ pdf_data*
11
+ reg_gpt_*
12
+ rma_gpt_v1/
13
+
14
+ app.log
Images/Reg-GPT.png ADDED
README.md CHANGED
@@ -1,3 +1,15 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
  ---
2
  title: CSRD GPT
3
  emoji: πŸ“Š
@@ -9,4 +21,152 @@ app_file: app.py
9
  pinned: false
10
  ---
11
 
12
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ title: RegGPT
3
+ emoji: πŸš€
4
+ colorFrom: indigo
5
+ colorTo: red
6
+ sdk: gradio
7
+ python_version: 3.10.0
8
+ sdk_version: 3.22.1
9
+ app_file: app.py
10
+ pinned: true
11
+ ---
12
+
13
  ---
14
  title: CSRD GPT
15
  emoji: πŸ“Š
 
21
  pinned: false
22
  ---
23
 
24
+ ## Introduction
25
+
26
+ Python Version used is: 3.10.0
27
+
28
+ ## Built With
29
+
30
+ - [Gradio](https://www.gradio.app/docs/interface) - Main server and interactive components
31
+ - [OpenAI API](https://platform.openai.com/docs/api-reference) - Main LLM engine used in the app
32
+ - [HuggingFace Sentence Transformers](https://huggingface.co/docs/hub/sentence-transformers) - Used as the default embedding model
33
+
34
+ ## Requirements
35
+
36
+ > **_NOTE:_** Before installing the requirements, rename the file `.env.example` to `.env` and put your OpenAI API key there !
37
+
38
+ We suggest you to create a separate virtual environment running Python 3 for this app, and install all of the required dependencies there. Run in Terminal/Command Prompt:
39
+
40
+ ```bash
41
+ git clone https://github.com/Nexialog/RegGPT.git
42
+ cd RegGPT/
43
+ python -m venv env
44
+ ```
45
+
46
+ In UNIX system:
47
+
48
+ ```bash
49
+ source venv/bin/activate
50
+ ```
51
+
52
+ In Windows:
53
+
54
+ ```bash
55
+ venv\Scripts\activate
56
+ ```
57
+
58
+ To install all of the required packages to this environment, simply run:
59
+
60
+ ```bash
61
+ pip install -r requirements.txt
62
+ ```
63
+
64
+ and all of the required `pip` packages will be installed, and the app will be able to run.
65
+
66
+ ## Usage of run_script.py
67
+
68
+ This script is used for processing PDF documents and generating text embeddings. You can specify different modes and parameters via command-line arguments.
69
+
70
+ ### Process Documents
71
+ To process PDF documents and extract paragraphs and metadata, use the following command:
72
+
73
+ ```bash
74
+ python run_script.py --type process_documents
75
+ ```
76
+
77
+ You can also use optional arguments to specify the folder containing PDFs, the output data folder, minimum paragraph length, and merge length.
78
+
79
+ ### Generate Embeddings
80
+ To generate text embeddings from the processed paragraphs, use the following command:
81
+
82
+ ```bash
83
+ python run_script.py --type generate_embeddings
84
+ ```
85
+
86
+ This command will use the default embedding model, but you can specify another model using the `--embedding_model` argument.
87
+
88
+ ### Process Documents and Generate Embeddings
89
+ To perform both document processing and embedding generation, use:
90
+
91
+ ```bash
92
+ python run_script.py --type all
93
+ ```
94
+
95
+ ### Command Line Arguments
96
+
97
+ - `--type`: Specifies the operation type. Choices are `all`, `process_documents`, or `generate_embeddings`. (required)
98
+ - `--pdf_folder`: Path to the folder containing PDF documents. Default is `pdf_data/`. (optional)
99
+ - `--data_folder`: Path to the folder where processed data and embeddings will be saved. Default is `data/`. (optional)
100
+ - `--embedding_model`: Specifies the model to be used for generating embeddings. Default is `sentence-transformers/multi-qa-mpnet-base-dot-v1`. (optional)
101
+ - `--device`: Specifies the device to be used (CPU or GPU). Choices are `cpu` or `cuda`. Default is `cpu`. (optional)
102
+ - `--min_length`: Specifies the minimum paragraph length for inclusion. Default is `300`. (optional)
103
+ - `--merge_length`: Specifies the merge length for paragraphs. Default is `700`. (optional)
104
+
105
+ ### Examples
106
+
107
+ ```bash
108
+ python run_script.py --type process_documents --pdf_folder my_pdf_folder/ --merge_length 800
109
+ ```
110
+
111
+ ```bash
112
+ python run_script.py --type generate_embeddings --device cuda
113
+ ```
114
+
115
+ ### How to use Colab's GPU
116
+
117
+ 1. Create your own [deploying key from github](https://github.com/Nexialog/RegGPT/settings/keys)
118
+ 2. Upload the key to Google Drive on the path : `drive/MyDrive/ssh_key_github/`
119
+ 3. Upload the notebook `notebooks/generate_embeddings.ipynb` into a colab session (or use this [link](https://colab.research.google.com/drive/1E7uHJF7gH_36O9ylIgWhiAjHpRJRyvnv?usp=sharing))
120
+ 4. Upload the pdf files on the same colab session on the path : `pdf_data/`
121
+ 5. Run the notebook on GPU mode and download the folder `data/` containing embeddings and chnukns
122
+
123
+ ## How to Configure a New BOT
124
+
125
+ 1. Put all pdf files in a folder at the same repository (We recommend using the folder name : 'pdf_data')
126
+ 2. Run the python sciprt 'run_script.py' as explained above. 3-Configure the BOT in config by following the steps bellow:
127
+
128
+ In order to configure the chatbot, you need to modify the config.py file that contains the CFG_APP class. Here's what each attribute in the class means:
129
+
130
+ ### Basic Settings
131
+
132
+ - `DEBUG`: Debugging mode
133
+ - `K_TOTAL`: The total number of retrieved docs
134
+ - `THRESHOLD`: Threshold of retrieval by embeddings
135
+ - `DEVICE`: Device for computation
136
+ - `BOT_NAME`: The name of the bot
137
+ - `MODEL_NAME`: The name of the model
138
+
139
+ ### Language and Data
140
+
141
+ - `DEFAULT_LANGUAGE`: Default language
142
+ - `DATA_FOLDER`: Path to the data folder
143
+ - `EMBEDDING_MODEL`: Embedding model
144
+
145
+ ### Tokens and Prompts
146
+
147
+ - `MAX_TOKENS_REF_QUESTION`: Maximum tokens in the reformulated question
148
+ - `MAX_TOKENS_ANSWER`: Maximum tokens in answers
149
+ - `INIT_PROMPT`: Initial prompt
150
+ - `SOURCES_PROMPT`: Sources prompt for responses
151
+
152
+ ### Default Questions
153
+
154
+ - `DEFAULT_QUESTIONS`: Tuple of default questions
155
+
156
+ ### Reformulation Prompt
157
+
158
+ - `REFORMULATION_PROMPT`: Prompt for reformulating questions
159
+
160
+ ### Metadata Path
161
+
162
+ - `DOC_METADATA_PATH`: Path to document metadata
163
+
164
+ ## How to Use This BOT
165
+
166
+ Run this app locally by:
167
+
168
+ ```bash
169
+ python app.py
170
+ ```
171
+
172
+ Open [http://127.0.0.1:7860](http://127.0.0.1:7860) in your browser, and you will see the bot.
app.py ADDED
@@ -0,0 +1,164 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import openai
3
+ import gradio as gr
4
+ from dotenv import load_dotenv
5
+ from utils import chat
6
+ from config import CFG_APP
7
+
8
+ # Load API KEY
9
+ try:
10
+ load_dotenv()
11
+ except Exception as e:
12
+ pass
13
+ openai.api_key = os.environ["OPENAI_API_KEY"]
14
+
15
+
16
+ # SYS Template
17
+ system_template = {
18
+ "role": "system",
19
+ "content": CFG_APP.INIT_PROMPT,
20
+ }
21
+
22
+ # APP
23
+ theme = gr.themes.Monochrome(
24
+ font=[gr.themes.GoogleFont("Kanit"), "sans-serif"],
25
+ )
26
+
27
+ with gr.Blocks(title=CFG_APP.BOT_NAME, css="assets/style.css", theme=theme) as demo:
28
+ gr.Markdown(f"<h1><center>{CFG_APP.BOT_NAME} πŸ€–</center></h1>")
29
+
30
+ with gr.Row():
31
+ with gr.Column(scale=2):
32
+ chatbot = gr.Chatbot(
33
+ elem_id="chatbot", label=f"{CFG_APP.BOT_NAME} chatbot", show_label=False
34
+ )
35
+ state = gr.State([system_template])
36
+
37
+
38
+ with gr.Row():
39
+ ask = gr.Textbox(
40
+ show_label=False,
41
+ placeholder="Ask here your question and press enter",
42
+ )
43
+
44
+ ask_examples_hidden = gr.Textbox(elem_id="hidden-message")
45
+
46
+ examples_questions = gr.Examples(
47
+ [*CFG_APP.DEFAULT_QUESTIONS],
48
+ [ask_examples_hidden],
49
+ examples_per_page=15,
50
+ )
51
+
52
+ with gr.Column(scale=1, variant="panel"):
53
+ sources_textbox = gr.Markdown(show_label=False)
54
+
55
+ ask.submit(
56
+ fn=chat,
57
+ inputs=[ask, state],
58
+ outputs=[chatbot, state, sources_textbox],
59
+ )
60
+ ask.submit(lambda x: gr.update(value=""), [], [ask])
61
+
62
+ ask_examples_hidden.change(
63
+ fn=chat,
64
+ inputs=[ask_examples_hidden, state],
65
+ outputs=[chatbot, state, sources_textbox],
66
+ )
67
+ demo.queue(concurrency_count=16)
68
+ gr.Markdown(
69
+ """
70
+
71
+ ### 🎯 Understanding CSRD_GPT's Purpose
72
+
73
+ In an era marked by growing emphasis on Environmental, Social, and Governance (ESG) considerations, staying well-informed about the intricate landscape of ESG and CSRD regulations can be a challenging endeavor. The evolving nature of these regulations and the wealth of information available can make it difficult to extract precise insights.
74
+
75
+
76
+ \n CSRD_GPT, a conversational tool related to a chatbot, offers an effective solution to this challenge. CSRD_GPT is specifically designed to address queries related to CSRD regulations. This tool draws its insights solely from documents published by official European regulatory sources, thus assuring the reliability and pertinence of its responses. By strictly focusing on these documents, CSRD_GPT ensures that it does not reference non-relevant sources, maintaining a high standard of precision in its responses. This novel tool harnesses the power of conversational AI to help users navigate the complex world of environmental's regulations, simplifying the task and promoting compliance efficiency.
77
+
78
+ """
79
+ )
80
+
81
+ gr.Markdown(
82
+ """
83
+
84
+ ### πŸ“ƒ Inputs and functionalities
85
+
86
+ In its initial release, Version 0, CSRD_GPT uses the subsequent 5 documents as the basis for its answers:
87
+ \n
88
+ |Document|Link|
89
+ |:----|:----|
90
+ |CSRD|https://eur-lex.europa.eu/legal-content/EN/TXT/PDF/?uri=CELEX:32022L2464|
91
+ |CSRD - Delegated Act|https://webgate.ec.europa.eu/regdel/web/delegatedActs/2111/documents/latest?lang=en|
92
+ |ESRS – CSRD DA annex1|https://ec.europa.eu/finance/docs/level-2-measures/csrd-delegated-act-2023-5303-annex-1_en.pdf|
93
+ |ESRS – CSRD DA annex2|https://ec.europa.eu/finance/docs/level-2-measures/csrd-delegated-act-2023-5303-annex-2_en.pdf|
94
+ |Q&A on the Adoption of European Sustainability Reporting Standards|https://ec.europa.eu/commission/presscorner/detail/en/qanda_23_4043|
95
+
96
+ """
97
+ )
98
+
99
+ gr.Markdown(
100
+ """
101
+
102
+ CSRD_GPT provides users with the opportunity to input queries using a dedicated prompt area, much like the one used in OpenAI's ChatGPT. If you're unsure of what to ask, examples of potential questions are displayed below the query bar. Simply click on one of these and the tool will generate corresponding responses.
103
+
104
+
105
+ \n When a query is submitted to the model, 10 sources are extracted from the previously mentioned documents to provide a comprehensive answer. These sources are quoted within the generated answer to ensure accuracy and reliability. For easy reference, exact passages can be quickly located by clicking on the link icon πŸ”— located beneath each excerpt, which will directly guide you to the relevant section within the document.
106
+
107
+ """
108
+ )
109
+
110
+ gr.Markdown(
111
+ """
112
+
113
+ ### πŸ’¬ Prompt Initialization
114
+
115
+ To limit the model's responses to only the 10 proposed sources, a set of prompts has been designed and will serve as instructions to the GPT API. This design decision ensures that the model's output is reliably grounded in the selected documents, contributing to the overall accuracy and reliability of the tool. The structured guidance provided by these prompts enables the GPT API to more effectively navigate the wealth of information contained within the ten sources, delivering highly relevant and concise responses to the users' queries.
116
+
117
+ <u>Prompts used to initialize CSRD_GPT: </u>
118
+
119
+ - "You are CSRD_GPT, an expert in CSRD regulations, an AI Assistant by Nexialog Consulting."
120
+ - "You are given a question and extracted parts of regulation reports."
121
+ - "Provide a clear and structured answer based only on the context provided."
122
+ - "When relevant, use bullet points and lists to structure your answers."
123
+ - "When relevant, use facts and numbers from the following documents in your answer."
124
+ - "Whenever you use information from a document, reference it at the end of the sentence (ex: [doc 2])."
125
+ - "You don't have to use all documents, only if it makes sense in the conversation."
126
+ - "Don't make up new sources and references that don't exist."
127
+ - "If no relevant information to answer the question is present in the documents, just say you don't have enough information to answer."
128
+
129
+
130
+
131
+ """
132
+ )
133
+
134
+ gr.Markdown(
135
+ """
136
+
137
+ ### βš™οΈTechnical features
138
+
139
+ CSRD_GPT operates through two core modules, the GPT API from OpenAI and an embedding model. The functioning of these components is integrated into a seamless workflow, which can be summarized in the figure below :
140
+
141
+
142
+ <div style="display:flex; justify-content:center;">
143
+ <img src="file/Images/Reg-GPT.png" width="800" height="800" />
144
+ </div>
145
+
146
+
147
+ - Open AI Api version : gpt-3.5-turbo
148
+ - Embedding model : https://huggingface.co/sentence-transformers/multi-qa-mpnet-base-dot-v1
149
+
150
+
151
+
152
+
153
+ """
154
+ )
155
+ gr.Markdown(
156
+ "<h1><center>Disclaimer ⚠️</center></h1>\n"
157
+ + """
158
+ - Please be aware that this is Version 0 of our application. You may encounter certain errors or glitches as we continue to refine and enhance its functionality. You might experience some nonsensical answers, similar to those experienced when using chat-GPT. If you encounter any issues, don't hesitate to reach out to us at [email protected].
159
+ - Our application relies on an external API provided by OpenAI. There may be instances where errors occur due to high demand on the API. If you encounter such an issue, we recommend that you refresh the page and retry your query, or try again a little bit later.
160
+ - When using our application, we urge you to ask clear and explicit questions that adhere to the scope of credit risk regulations. This will ensure that you receive the most accurate and relevant responses from the system.
161
+ """
162
+ )
163
+
164
+ demo.launch()
assets/style.css ADDED
@@ -0,0 +1,215 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ .warning-box {
2
+ background-color: #fff3cd;
3
+ border: 1px solid #ffeeba;
4
+ border-radius: 4px;
5
+ padding: 15px 20px;
6
+ font-size: 14px;
7
+ color: #856404;
8
+ display: inline-block;
9
+ margin-bottom: 15px;
10
+ }
11
+
12
+
13
+ .tip-box {
14
+ background-color: #f0f9ff;
15
+ border: 1px solid #80d4fa;
16
+ border-radius: 4px;
17
+ margin-top: 20px;
18
+ padding: 15px 20px;
19
+ font-size: 14px;
20
+ color: #006064;
21
+ display: inline-block;
22
+ margin-bottom: 15px;
23
+ width: auto;
24
+ }
25
+
26
+ .tip-box-title {
27
+ font-weight: bold;
28
+ font-size: 14px;
29
+ margin-bottom: 5px;
30
+ }
31
+
32
+ .light-bulb {
33
+ display: inline;
34
+ margin-right: 5px;
35
+ }
36
+
37
+ .gr-box {
38
+ border-color: #d6c37c
39
+ }
40
+
41
+ #hidden-message {
42
+ display: none;
43
+ }
44
+
45
+ .message {
46
+ font-size: 14px !important;
47
+ }
48
+
49
+
50
+ a {
51
+ text-decoration: none;
52
+ color: inherit;
53
+ }
54
+
55
+ .card {
56
+ background-color: #233f55;
57
+ border-radius: 10px;
58
+ box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
59
+ overflow: hidden;
60
+ display: flex;
61
+ flex-direction: column;
62
+ margin: 20px;
63
+ }
64
+
65
+ .card-content {
66
+ padding: 20px;
67
+ }
68
+
69
+ .card-content h2 {
70
+ font-size: 14px !important;
71
+ font-weight: bold;
72
+ margin-bottom: 10px;
73
+ margin-top: 0px !important;
74
+ color: #577b9b !important;
75
+ ;
76
+ }
77
+
78
+ .card-content p {
79
+ font-size: 12px;
80
+ margin-bottom: 0;
81
+ }
82
+
83
+ .card-footer {
84
+ background-color: #f4f4f4;
85
+ font-size: 10px;
86
+ padding: 10px;
87
+ display: flex;
88
+ justify-content: space-between;
89
+ align-items: center;
90
+ }
91
+
92
+ .card-footer span {
93
+ flex-grow: 1;
94
+ text-align: left;
95
+ color: #999 !important;
96
+ }
97
+
98
+ .pdf-link {
99
+ display: inline-flex;
100
+ align-items: center;
101
+ margin-left: auto;
102
+ text-decoration: none !important;
103
+ font-size: 14px;
104
+ }
105
+
106
+
107
+
108
+ .message.user {
109
+ background-color: #b20032 !important;
110
+ border: none;
111
+ color: white !important;
112
+ }
113
+
114
+ .message.bot {
115
+ /* background-color: #f2f2f7 !important; */
116
+ border: none;
117
+ }
118
+
119
+ .gallery-item>div:hover {
120
+ background-color: #7494b0 !important;
121
+ color: white !important;
122
+ }
123
+
124
+ .gallery-item:hover {
125
+ border: #7494b0 !important;
126
+ }
127
+
128
+ .gallery-item>div {
129
+ background-color: white !important;
130
+ color: #577b9b !important;
131
+ }
132
+
133
+ .label {
134
+ color: #577b9b !important;
135
+ }
136
+
137
+ .paginate {
138
+ color: #577b9b !important;
139
+ }
140
+
141
+
142
+ label>span {
143
+ color: #577b9b !important;
144
+ }
145
+
146
+ /* Pseudo-element for the circularly cropped picture */
147
+ .message.bot::before {
148
+ content: '';
149
+ position: absolute;
150
+ top: -10px;
151
+ left: -10px;
152
+ width: 30px;
153
+ height: 30px;
154
+ background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAACnUlEQVR4AcXXA4wkQRiG4eHZtm3btm3btm3bDs+2bdvm2vPfm6Qu6XRuOz3LSp7xdH3ltCU8Za+lsA1JYLVER6HiOFiFXkgGa1QHiIvzCMQplI2uAKJMiY4A50ILwHs7bGG9eFqUQgx3A2gq74X+SAGrO5U7MQvfsAKF4XAzQD68QSDOoLbp3lAt/wxR3mMGssNmFEDTgAUQJQTTYDO7ticgEKLhwhMMRVpYDQIUwyeI8hhZzbbeipQYgNsIhmgE4xraIqk+AGJiNUQJwjCD1hsGSYfheIgQiIYXJuASRJmM8vgBUa4hdXi328yYgGdwQZSvuq4ehi0QxR9dYTVTUWIUQmEDtbESbzRBXBB4Yyb+QJTjSGx22U3DD/wMxQ+8xxXswRt8wjUInuKsboiamG19aXyBuCEQC9AIP/AZPhC4sBVxzVQeG2vgDR8YCYDgG1YhNZxoiWsIgi/2IA/iwojTwkMsFEN5VAhFRYzAc7hwFbXggBX5sB1+8MRNnNc5p3MAxcyuhOJ4ppvdX9ABuXET4qbtZocoLnZBFG+ch+AeNsED9/AFIRAY+YSSZjejBvCCKCdwGoJA+CII97EAA9Efg3SGYBRGoxkcZgIkwTGI8ge98RqCYHhClACcQRskMlqCZlvfCQEQZScqwQMCH6yFN0TDD0fRFAnCGiANrkKUH6iICvDRBKiOAZpe0fLBftRFXHf3/yG6k3ADYkIfoDzsKICV+ArR8cQGJDYbIBseQ5TP/2bt/wJo/hcD5bADHhCNrYhtNkA5PIILgiVwGgbQ7a6oh8PwxUeUdHcIcmABrqGAhWIygPY6CdEefY2XnfEpmQ52gwAVTKwmmyW8xTBAVBZ1yt2DK7oC2JAdc/EM5aPrztiJEkgXnuv8BdWTESwwR9FxAAAAAElFTkSuQmCC');
155
+ background-color: #fff;
156
+ background-size: cover;
157
+ background-position: center;
158
+ border-radius: 50%;
159
+ z-index: 10;
160
+ }
161
+
162
+
163
+
164
+ .user.svelte-6roggh.svelte-6roggh {
165
+ padding: 17px 24px;
166
+ text-align: justify;
167
+ }
168
+
169
+ .gallery.svelte-1ayixqk {
170
+ text-align: left;
171
+ }
172
+
173
+ .card-content p,
174
+ .card-content ul li {
175
+ color: #fff !important;}
176
+
177
+
178
+ .message.bot, .bot.svelte-6roggh.svelte-6roggh {
179
+ background: #233f55 !important;
180
+ padding: 17px 24px !important;
181
+ text-align: justify !important;
182
+ color: #fff !important;
183
+ }
184
+
185
+ #chatbot{
186
+ height: auto !important;
187
+ max-height: 1000px;
188
+ }
189
+
190
+ #type-emb label {
191
+ background: #ebeaea;
192
+ }
193
+
194
+ .source {
195
+ background-color: #f8f9fa;
196
+ border: 1px solid #ddd;
197
+ padding: 15px;
198
+ margin-bottom: 10px;
199
+ border-radius: 4px;
200
+ }
201
+
202
+ .title {
203
+ font-size: 18px;
204
+ color: #333;
205
+ margin-bottom: 5px;
206
+ font-weight: bold;
207
+ }
208
+
209
+ .wrap.svelte-6roggh.svelte-6roggh {
210
+ padding: var(--block-padding);
211
+ height: 100%;
212
+ max-height: 480px;
213
+ overflow-y: auto;
214
+ max-height: 1000px;
215
+ }
config.py ADDED
@@ -0,0 +1,73 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ class CFG_APP:
2
+ DEBUG = True
3
+ K_TOTAL = 10 # Number of paragraphs
4
+ THRESHOLD = 0.3
5
+ DEVICE = "cpu"
6
+ BOT_NAME = "CSRD_GPT"
7
+ MODEL_NAME = "gpt-3.5-turbo"
8
+ DEFAULT_LANGUAGE = "English"
9
+
10
+ DATA_FOLDER = "data/"
11
+ EMBEDDING_MODEL = "sentence-transformers/multi-qa-mpnet-base-dot-v1"
12
+
13
+ MAX_TOKENS_REF_QUESTION = 128 # Number of tokens in reformulated question
14
+ MAX_TOKENS_ANSWER = 1024 # Number of tokens in answers
15
+ MAX_TOKENS_API = 3100
16
+ INIT_PROMPT = (
17
+ f"You are {BOT_NAME}, an expert in CSRD regulations, an AI Assistant by Nexialog Consulting. "
18
+ "You are given a question and extracted parts of regulation reports."
19
+ "Provide a clear and structured answer based only on the context provided. "
20
+ "When relevant, use bullet points and lists to structure your answers."
21
+ )
22
+ SOURCES_PROMPT = (
23
+ "When relevant, use facts and numbers from the following documents in your answer. "
24
+ "Whenever you use information from a document, reference it at the end of the sentence by naming it Exc (ex: [exc 2])."
25
+ "Very important ! Never use the word Document or Doc for referencing an Excerpt, always exc. "
26
+ "You don't have to use all documents, only if it makes sense in the conversation. "
27
+ "If no relevant information to answer the question is present in the documents, "
28
+ "just say you don't have enough information to answer."
29
+ )
30
+
31
+ DEFAULT_QUESTIONS = (
32
+ "What are the key requirements of the CSRD for companies in the EU?",
33
+ "How does the CSRD differ from the previous Non-Financial Reporting Directive (NFRD)?",
34
+ "Which types of companies are affected by the CSRD, and what are the thresholds for compliance?",
35
+ "How will the CSRD impact the way companies report on sustainability and environmental issues?",
36
+ "Are there specific guidelines or standards that companies must follow under the CSRD for reporting sustainability measures?",
37
+ "Comment la CSRD va-t-elle influencer la transparence et la responsabilité des entreprises en matière de pratiques durables ?",
38
+ "Quelles sont les consΓ©quences pour les entreprises qui ne respectent pas les normes de la CSRD ?",
39
+ "La CSRD exige-t-elle des entreprises de rapporter sur des indicateurs spΓ©cifiques de durabilitΓ© environnementale et sociale ?",
40
+ "Comment la mise en Ε“uvre de la CSRD peut-elle bΓ©nΓ©ficier Γ  la performance globale des entreprises ?",
41
+ "Quel rôle jouent les auditeurs et les conseillers en matière de conformité aux exigences de la CSRD ?",
42
+ )
43
+
44
+ REFORMULATION_PROMPT = """
45
+ Important ! Give the output as a standalone question followed by the detected language whatever the form of the query.
46
+ Reformulate the following user message to be a short standalone question in English, in the context of an educational discussion about regulations in banks. Then detect the language of the query
47
+ Sometimes, explanations of some abbreviations will be given in parentheses, keep them.
48
+ ---
49
+ query: C'est quoi les rΓ©gles que les banques amΓ©ricaines doivent suivre ?
50
+ standalone question: What are the key regulations that banks in the United States must follow?
51
+ language: French
52
+ ---
53
+ query: what are the main effects of bank regulations?
54
+ standalone question: What are the main causes of bank regulations change in the last century?
55
+ language: English
56
+ ---
57
+ query: UL (Unexpected Loss)
58
+ standalone question: What does UL (Unexpected Loss) stand for?
59
+ language: English
60
+ """
61
+
62
+ HYDE_PROMPT ="""
63
+ Important ! Give the output as an answer to the query. First you will translate the query in English and then answer it, in English, in 2 sentences maximum using the right vocabulary of the context of the query.
64
+ Very important : the answer must be followed by the detected language of the query whatever the form of the query. You must keep the question at the begining of the answer.
65
+ Here is an example of the template you must follow to create your answer :
66
+ ---
67
+ query : C'est quoi les rΓ©gles que les banques amΓ©ricaines doivent suivre ?
68
+ output : What are the rules that American banks must follow ? American banks must follow a set of federal and state regulations imposed by agencies such as the Federal Reserve and the Consumer Financial Protection Bureau..
69
+ language : French
70
+ """
71
+
72
+
73
+ DOC_METADATA_PATH = f"{DATA_FOLDER}/doc_metadata.json"
data/cache-f1c6bb9d30103bcf.arrow ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:87c87020f08505f5c44170014acaae9ae57ab85c2f04f5a11c34ac5823a4bd33
3
+ size 5024312
data/data-00000-of-00001.arrow ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:74e5cbe1254f5911d3eb8b9645487a72c4caaecf65aea2bae78e149f2fa69bb3
3
+ size 1388056
data/dataset_info.json ADDED
@@ -0,0 +1,52 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "citation": "",
3
+ "description": "",
4
+ "features": {
5
+ "id": {
6
+ "dtype": "string",
7
+ "_type": "Value"
8
+ },
9
+ "document_id": {
10
+ "dtype": "string",
11
+ "_type": "Value"
12
+ },
13
+ "content_type": {
14
+ "dtype": "string",
15
+ "_type": "Value"
16
+ },
17
+ "content": {
18
+ "dtype": "string",
19
+ "_type": "Value"
20
+ },
21
+ "length": {
22
+ "dtype": "int64",
23
+ "_type": "Value"
24
+ },
25
+ "idx_block": {
26
+ "dtype": "int64",
27
+ "_type": "Value"
28
+ },
29
+ "page_number": {
30
+ "dtype": "int64",
31
+ "_type": "Value"
32
+ },
33
+ "x0": {
34
+ "dtype": "float64",
35
+ "_type": "Value"
36
+ },
37
+ "y0": {
38
+ "dtype": "float64",
39
+ "_type": "Value"
40
+ },
41
+ "x1": {
42
+ "dtype": "float64",
43
+ "_type": "Value"
44
+ },
45
+ "y1": {
46
+ "dtype": "float64",
47
+ "_type": "Value"
48
+ }
49
+ },
50
+ "homepage": "",
51
+ "license": ""
52
+ }
data/doc_metadata.json ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ [{"id": "f20d9592e5232f906ca26833bb63fdab", "title": "", "author": "", "subject": "", "creation_date": "D:20230731101034+02'00'", "modification_date": "D:20230731101034+02'00'", "n_pages": 13, "url": "https://webgate.ec.europa.eu/regdel/web/delegatedActs/2111/documents/latest?lang=en", "file_name": "CSRD - Delegated Act.pdf", "short_name": "CSRD - Delegated Act.pdf", "release_date": "", "report_type": "", "source": ""},
2
+ {"id": "ba860baaf00570c824351b7e2be3ed09", "title": "", "author": "BOTTAZZI Giulia (FISMA)", "subject": "", "creation_date": "D:20230731101209+02'00'", "modification_date": "D:20230731101209+02'00'", "n_pages": 245, "url": "https://ec.europa.eu/finance/docs/level-2-measures/csrd-delegated-act-2023-5303-annex-1_en.pdf", "file_name": "ESRS \u2013 CSRD DA annex1.pdf", "short_name": "ESRS \u2013 CSRD DA annex1.pdf", "release_date": "", "report_type": "", "source": ""},
3
+ {"id": "42e11a73824e7da1206260d851c0409d", "title": "", "author": "", "subject": "", "creation_date": "D:20230811124305+02'00'", "modification_date": "", "n_pages": 5, "url": "https://ec.europa.eu/commission/presscorner/detail/en/qanda_23_4043", "file_name": "Q&A on the Adoption of European Sustainability Reporting Standards.pdf", "short_name": "Q&A on the Adoption of European Sustainability Reporting Standards.pdf", "release_date": "", "report_type": "", "source": ""},
4
+ {"id": "60d2167e44781f7a3679e3dc4fd877a9", "title": "Publications Office", "author": "Publications Office", "subject": "", "creation_date": "D:20221215163241+01'00'", "modification_date": "D:20221215163241+01'00'", "n_pages": 66, "url": "https://eur-lex.europa.eu/legal-content/EN/TXT/PDF/?uri=CELEX:32022L2464", "file_name": "CSRD.pdf", "short_name": "CSRD.pdf", "release_date": "", "report_type": "", "source": ""},
5
+ {"id": "52fe10867100623bad10c1370eda2e6d", "title": "", "author": "BOTTAZZI Giulia (FISMA)", "subject": "", "creation_date": "D:20230731101109+02'00'", "modification_date": "D:20230731101109+02'00'", "n_pages": 34, "url": "https://ec.europa.eu/finance/docs/level-2-measures/csrd-delegated-act-2023-5303-annex-2_en.pdf", "file_name": "ESRS \u2013 CSRD DA annex2.pdf", "short_name": "ESRS \u2013 CSRD DA annex2.pdf", "release_date": "", "report_type": "", "source": ""}]
data/index.faiss ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:932f188d2abad7ec11b296960084c933328e55f3a6591448adc5275e502b774b
3
+ size 3631149
data/state.json ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "_data_files": [
3
+ {
4
+ "filename": "data-00000-of-00001.arrow"
5
+ }
6
+ ],
7
+ "_fingerprint": "2c6b766609c8e690",
8
+ "_format_columns": null,
9
+ "_format_kwargs": {},
10
+ "_format_type": null,
11
+ "_output_all_columns": false,
12
+ "_split": null
13
+ }
glossary.json ADDED
@@ -0,0 +1,403 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "ABoR": "Administrative Board of Review",
3
+ "ABS": "asset-backed security",
4
+ "ABSPP": "asset-backed securities purchase programme",
5
+ "ACH": "automated clearing house",
6
+ "AIF": "alternative investment fund",
7
+ "AMA": "advanced measurement approach",
8
+ "AMC": "asset management company",
9
+ "AMI-Pay": "Advisory Group on Market Infrastructures for Payments",
10
+ "AMI-SeCo": "Advisory Group on Market Infrastructures for Securities and Collateral",
11
+ "AML": "anti-money laundering",
12
+ "API": "application programming interface",
13
+ "APP": "asset purchase programme",
14
+ "ASC": "Advisory Scientific Committee",
15
+ "ASLP": "automated security lending programme",
16
+ "AT1": "Additional Tier 1",
17
+ "ATC": "Advisory Technical Committee",
18
+ "ATM": "automated teller machine",
19
+ "b.o.p.": "balance of payments",
20
+ "BCBS": "Basel Committee on Banking Supervision",
21
+ "BCPs": "Basel Core Principles",
22
+ "BEPGs": "Broad Economic Policy Guidelines",
23
+ "BIC": "Business Identifier Code",
24
+ "BIS": "Bank for International Settlements",
25
+ "BPM6": "Balance of Payments and International Investment Position Manual",
26
+ "bps": "basis points",
27
+ "BRM": "breach reporting mechanism",
28
+ "BRRD": "Bank Recovery and Resolution Directive",
29
+ "c.i.f.": "Cost, insurance and freight at the importer’s border",
30
+ "CAPE": "cyclically adjusted price/earnings (ratio)",
31
+ "CAPM": "capital asset pricing model",
32
+ "CAS": "capital adequacy statement",
33
+ "CBOE": "Chicago Board Options Exchange",
34
+ "CBPP": "covered bond purchase programme",
35
+ "CBR": "combined buffer requirement",
36
+ "CCBM": "correspondent central banking model",
37
+ "CCBM2": "Collateral Central Bank Management",
38
+ "CCoB": "capital conservation buffer",
39
+ "CCP": "central counterparty",
40
+ "CCyB": "countercyclical capital buffer",
41
+ "CDS": "credit default swap",
42
+ "CESR": "Committee of European Securities Regulators",
43
+ "CET1": "Common Equity Tier 1",
44
+ "CGFS": "Committee on the Global Financial System",
45
+ "CGO": "Compliance and Governance Office",
46
+ "CISS": "composite indicator of systemic stress",
47
+ "CJEU": "Court of Justice of the European Union",
48
+ "CMU": "capital markets union",
49
+ "CO2": "carbon dioxide",
50
+ "COGESI": "Contact Group on Euro Securities Infrastructures",
51
+ "COI": "Centralised On-Site Inspections Division",
52
+ "COREP": "common reporting",
53
+ "CPI": "consumer price index",
54
+ "CPMI": "Committee on Payments and Market Infrastructures",
55
+ "CPSIPS": "Core Principles for Systemically Important Payment Systems",
56
+ "CRD": "Capital Requirements Directive",
57
+ "CRE": "commercial real estate",
58
+ "CRR": "Capital Requirements Regulation",
59
+ "CSD": "central securities depository ",
60
+ "CSPP": "corporate sector purchase programme",
61
+ "D-SIB": "domestic systemically important bank",
62
+ "DFR": "deposit facility rate",
63
+ "DG ECFIN": "Directorate General for Economic and Financial Affairs, European Commission",
64
+ "DGS": "deposit guarantee scheme",
65
+ "DLT": "distributed ledger technology",
66
+ "DNSH": "Do No Significant Harm",
67
+ "DSR": "debt service ratio",
68
+ "DSTI": "debt service-to-income",
69
+ "DTA": "deferred tax asset",
70
+ "DTI": "debt-to-income",
71
+ "DvD": "delivery versus delivery",
72
+ "DvP": "delivery versus payment",
73
+ "EAD": "exposure at default",
74
+ "EBA": "European Banking Authority",
75
+ "EBITDA": "earnings before interest, taxes, depreciation and amortisation",
76
+ "EBP": "excess bond premium",
77
+ "EBPP": "Electronic Bill Presentment and Payment ",
78
+ "ECA": "European Court of Auditors",
79
+ "ECAF": "Eurosystem credit assessment framework",
80
+ "ECB": "European Central Bank ",
81
+ "ECL": "expected credit loss",
82
+ "ECOFIN": "Economic and Financial Affairs Council. Council of the European Union",
83
+ "ECU": "European Currency Unit ",
84
+ "EDF": "expected default frequency",
85
+ "EDI": "electronic data interchange ",
86
+ "EDIS": "European Deposit Insurance Scheme",
87
+ "EDP": "excessive deficit procedure ",
88
+ "EDW": "European Data Warehouse",
89
+ "EEA": "European Economic Area ",
90
+ "EER": "effective exchange rate ",
91
+ "EFC": "Economic and Financial Committee ",
92
+ "EFSF": "European Financial Stability Facility ",
93
+ "EFSM": "European Financial Stabilisation Mechanism ",
94
+ "EIOPA": "European Insurance and Occupational Pensions Authority",
95
+ "EL": "Expected Loss",
96
+ "ELB": "effective lower bound",
97
+ "ELBE": "Expected Loss Best Estimate",
98
+ "ELMI": "electronic money institution",
99
+ "EMIR": "European Market Infrastructure Regulation",
100
+ "EMMS": "Euro Money Market Survey",
101
+ "EMS": "European Monetary System ",
102
+ "EMU": "Economic and Monetary Union ",
103
+ "EONIA": "euro overnight index average",
104
+ "ERM II": "exchange rate mechanism II",
105
+ "ERPB": "Euro Retail Payments Board",
106
+ "ESA": "European Supervisory Authority",
107
+ "ESA 2010": "European System of Accounts 2010 ",
108
+ "ESA 95": "European System of Accounts 1995 ",
109
+ "ESCB": "European System of Central Banks",
110
+ "ESCG": "European Systemic Cyber Group",
111
+ "ESFS": "European System of Financial Supervision",
112
+ "ESM": "European Stability Mechanism",
113
+ "ESMA": "European Securities and Markets Authority",
114
+ "ESRB": "European Systemic Risk Board",
115
+ "ETF": "exchange-traded fund",
116
+ "EUCLID": "European centralised infrastructure for supervisory data",
117
+ "EURIBOR": "euro interbank offered rate",
118
+ "€STR": "euro short-term rate",
119
+ "EVE": "economic value of equity",
120
+ "f.o.b.": "Free on board at the exporter’s border",
121
+ "FINREP": "financial reporting",
122
+ "FMI": "financial market infrastructure",
123
+ "FOLTF": "failing or likely to fail",
124
+ "FOMC": "Federal Open Market Committee",
125
+ "FRA": "forward rate agreement",
126
+ "FSB": "Financial Stability Board",
127
+ "FSR": "Financial Stability Review",
128
+ "FTS": "funds transfer system",
129
+ "FVA": "fair value accounting",
130
+ "FVC": "financial vehicle corporation",
131
+ "FX": "foreign exchange",
132
+ "G-SIB": "global systemically important bank",
133
+ "G-SII": "global systemically important institution",
134
+ "GAAP": "generally accepted accounting principles",
135
+ "GDP": "gross domestic product",
136
+ "HICP": "Harmonised Index of Consumer Prices",
137
+ "HLEG": "High-Level Expert Group on Sustainable Finance",
138
+ "HoM": "Head of Mission",
139
+ "HQLA": "high-quality liquid asset",
140
+ "i.i.p.": "international investment position",
141
+ "IAIG": "internationally active insurance group",
142
+ "IAIS": "International Association of Insurance Supervisors",
143
+ "IAS": "International Accounting Standards",
144
+ "IBAN": "International Bank Account Number",
145
+ "IC": "internal capital",
146
+ "ICAAP": "Internal Capital Adequacy Assessment Process",
147
+ "ICMA": "International Capital Market Association",
148
+ "ICPFs": "insurance corporations and pension funds",
149
+ "ICR": "interest coverage ratio",
150
+ "ICS": "Insurance Capital Standard",
151
+ "ICSD": "international central securities depository",
152
+ "IF": "investment fund",
153
+ "IFRS": "International Financial Reporting Standards",
154
+ "IFTS": "interbank funds transfer system",
155
+ "ILAAP": "Internal Liquidity Adequacy Assessment Process",
156
+ "ILO": "International Labour Organization",
157
+ "ILS": "inflation-linked swap",
158
+ "IMAS": "SSM Information Management System",
159
+ "IMF": "International Monetary Fund",
160
+ "IMI": "internal model investigation",
161
+ "IOSCO": "International Organization of Securities Commissions",
162
+ "IPS": "institutional protection scheme",
163
+ "IRB": "internal ratings-based",
164
+ "IRBA": "internal ratings-based approach",
165
+ "IRR": "internal rate of return",
166
+ "IRRBB": "interest rate risk in the banking book",
167
+ "IRT": "Internal Resolution Team",
168
+ "ISIN": "International Securities Identification Number",
169
+ "ITS": "Implementing Technical Standards",
170
+ "JSS": "Joint Supervisory Standards",
171
+ "JST": "Joint Supervisory Team",
172
+ "JSTC": "Joint Supervisory Team coordinator",
173
+ "KRI": "key risk indicator",
174
+ "LCBG": "large and complex banking group",
175
+ "LCR": "liquidity coverage ratio",
176
+ "LGD": "loss-given-default",
177
+ "LSI": "less significant institution",
178
+ "LSTI": "loan service-to-income",
179
+ "LTD": "loan-to-deposit",
180
+ "LTG": "long-term guarantee",
181
+ "LTI": "loan-to-income",
182
+ "LTRO": "longer-term refinancing operation",
183
+ "LTSF": "loan-to-stable-funding",
184
+ "LTV": "loan-to-value",
185
+ "M&A": "mergers and acquisitions",
186
+ "MDA": "maximum distributable amount",
187
+ "MFI": "monetary financial institution",
188
+ "MiFID": "Markets in Financial Instruments Directive",
189
+ "MiFIR": "Markets in Financial Instruments Regulation",
190
+ "MIP": "macroeconomic imbalance procedure",
191
+ "MMF": "money market fund",
192
+ "MMS": "money market statistics",
193
+ "MMSR": "money market statistical reporting",
194
+ "MPC": "Monetary Policy Committee",
195
+ "MREL": "minimum requirement for own funds and eligible liabilities",
196
+ "MSC": "merchant service charge",
197
+ "NAV": "net asset value",
198
+ "NBNI": "non-bank, non-insurance",
199
+ "NCA": "national competent authority",
200
+ "NCB": "national central bank",
201
+ "NDA": "national designated authority",
202
+ "NFC": "non-financial corporation",
203
+ "NFCI": "net fee and commission income",
204
+ "NII": "net interest income",
205
+ "NIRP": "negative interest rate policy",
206
+ "NPE": "non-performing exposure",
207
+ "NPLs": "non-performing loans",
208
+ "NRA": "national resolution authority",
209
+ "NSA": "national supervisory authority",
210
+ "NSFR": "net stable funding ratio",
211
+ "O&D": "options and discretions",
212
+ "O-SII": "other systemically important institution",
213
+ "OECD": "Organisation for Economic Co-operation and Development",
214
+ "OFI": "other financial institution",
215
+ "OIS": "overnight index swap",
216
+ "OJ": "Official Journal of the European Union",
217
+ "ORC": "overall recovery capacity",
218
+ "OSI": "on-site inspection",
219
+ "OTC": "over-the-counter",
220
+ "P&L": "profit and loss",
221
+ "P/E": "price/earnings (ratio)",
222
+ "P2G": "Pillar 2 guidance",
223
+ "P2P payment": "peer-to-peer payment",
224
+ "P2R": "Pillar 2 requirement",
225
+ "PCE": "personal consumption expenditure",
226
+ "PD": "probability of default",
227
+ "PE-ACH": "pan-European automated clearing house",
228
+ "PIN": "personal identification number",
229
+ "PPI": "prudential policy index",
230
+ "PPP": "purchasing power parity",
231
+ "PQD": "public quantitative disclosure",
232
+ "PSPP": "public sector purchase programme",
233
+ "PvP": "payment versus payment",
234
+ "QE": "quantitative easing",
235
+ "RAROC": "risk-adjusted return on capital",
236
+ "RAS": "risk appetite statement",
237
+ "repo": "repurchase agreement, repurchase operation",
238
+ "ROA": "return on assets",
239
+ "ROE": "return on equity",
240
+ "RORAC": "return on risk-adjusted capital",
241
+ "RRE": "residential real estate",
242
+ "RTGS system": "real-time gross settlement system",
243
+ "RTS": "Regulatory Technical Standards",
244
+ "RWA": "risk-weighted asset",
245
+ "S&P": "Standard & Poor’s",
246
+ "SBBS": "sovereign bond-backed security",
247
+ "SCR": "Solvency Capital Requirement",
248
+ "SDR": "special drawing right",
249
+ "SEP": "Supervisory Examination Programme",
250
+ "SEPA": "Single Euro Payments Area",
251
+ "SFT": "securities financing transaction",
252
+ "SGP": "Stability and Growth Pact",
253
+ "SI": "significant institution",
254
+ "SII": "systemically important institution",
255
+ "SIPS": "systemically important payment system",
256
+ "SMEs": "small and medium-sized enterprises",
257
+ "SPV": "special-purpose vehicle",
258
+ "SQA": "Supervisory Quality Assurance",
259
+ "SRB": "systemic risk buffer",
260
+ "SREP": "Supervisory Review and Evaluation Process",
261
+ "SRF": "Single Resolution Fund",
262
+ "SRM": "Single Resolution Mechanism",
263
+ "SRMR": "Single Resolution Mechanism Regulation",
264
+ "SSG": "SSM Simplification Group",
265
+ "SSM": "Single Supervisory Mechanism",
266
+ "SSMR": "Single Supervisory Mechanism Regulation",
267
+ "SSS": "securities settlement system",
268
+ "STE": "Short Term Exercise",
269
+ "STP": "straight-through processing",
270
+ "T2": "Tier 2",
271
+ "T2S": "TARGET2-Securities",
272
+ "TFEU": "Treaty on the Functioning of the European Union",
273
+ "TIPS": "TARGET instant payment settlement",
274
+ "TLAC": "total loss-absorbing capacity",
275
+ "TLTRO": "targeted longer-term refinancing operation",
276
+ "TREA": "total risk exposure amount",
277
+ "TRIM": "targeted review of internal models",
278
+ "TRN": "transaction reference number",
279
+ "TSCG": "Treaty on Stability, Coordination and Governance in the Economic and Monetary Union",
280
+ "UL": "Unexpeccted Loss",
281
+ "TSCR": "total SREP capital requirement (P1R+P2R)",
282
+ "UCITS": "undertaking for collective investment in transferable securities",
283
+ "ULCM": "Unit labour costs in the manufacturing sector.",
284
+ "ULCT": "Unit labour costs in the total economy.",
285
+ "VaR": "value at risk",
286
+ "VIX": "Chicago Board Options Exchange’s Volatility Index",
287
+ "XML": "Extensible Markup Language",
288
+ "AMS": "Automated Measuring Systems",
289
+ "AQI": "Air Quality Indices",
290
+ "AR": "Application Requirements",
291
+ "AWS": "Alliance for Water Stewardship",
292
+ "BAT": "Best Available Technique",
293
+ "BAT-AEL": "Best Available Technique-Associated Emission Level",
294
+ "BAT-AEPL": "Best Available Technique-Associated Environmental Performance Level",
295
+ "BREFs": "Best Available Techniques Reference Documents",
296
+ "Btu": "British Thermal Units",
297
+ "CapEx": "Capital Expenditure",
298
+ "CBD": "Convention for Biological Diversity",
299
+ "CDDA": "Common Database on Designated Areas",
300
+ "CEN": "European Committee for Standardization",
301
+ "CENELEC": "European Committee for Electrotechnical Standardization",
302
+ "CH4": "Methane",
303
+ "CICES": "Common International Classification of Ecosystem Services",
304
+ "C02": "Carbon Dioxide",
305
+ "DEGURBA": "Degree of Urbanisation",
306
+ "DR BP-1": "Disclosure Requirement - General basis for preparation of the sustainability statements",
307
+ "DR BP-2": "Disclosure Requirement - Disclosures in relation to specific circumstances",
308
+ "DR GOV-1": "Disclosure Requirement - The role of the administrative, management and supervisory bodies",
309
+ "DR GOV-2": "Disclosure Requirement - Information provided to and sustainability matters addressed by the undertaking's administrative, management and supervisory bodies",
310
+ "DR GOV-3": "Disclosure Requirement - Integration of sustainability- related performance in incentive schemes",
311
+ "DR GOV-4": "Disclosure Requirement - Statement on sustainability due diligence",
312
+ "DR GOV-5": "Disclosure Requirement - Risk management and internal controls over sustainability reporting",
313
+ "DR SBM-1": "Disclosure Requirement - Market position, strategy, business model(s) and value chain",
314
+ "DR SBM-2": "Disclosure Requirement - Interests and views of stakeholders",
315
+ "DR SBM-3": "Disclosure Requirement - Material impacts, risks and opportunities and their interaction with strategy and business model(s)",
316
+ "DR IRO-1": "Disclosure Requirement - Description of the processes to identify and assess material impacts, risks and opportunities",
317
+ "DR IRO-2": "Disclosure Requirements in ESRS covered by the undertaking's sustainability statements",
318
+ "DR": "Disclosure Requirements",
319
+ "EC": "European Commission",
320
+ "EFRAG": "European Financial Reporting Advisory Group",
321
+ "EFRAG SRB": "European Financial Reporting Advisory Group Sustainability Reporting Board",
322
+ "EIA": "Environmental Impact Assessment",
323
+ "EMAS": "Eco-Management and Audit Scheme",
324
+ "EPC": "Energy Performance Certificate",
325
+ "E-PRTR": "European Pollutant Release and Transfer Register",
326
+ "ESRS": "European Sustainability Reporting Standards",
327
+ "ESRS 1": "European Sustainability Reporting Standard 1 General requirements",
328
+ "ESRS 2": "European Sustainability Reporting Standard 2 General disclosures",
329
+ "ESRS E1": "European Sustainability Reporting Standard E1 Climate change",
330
+ "ESRS E2": "European Sustainability Reporting Standard E2 Pollution",
331
+ "ESRS E3": "European Sustainability Reporting Standard E3 Water and marine resources",
332
+ "ESRS E4": "European Sustainability Reporting Standard E4 Biodiversity and ecosystems",
333
+ "ESRS E5": "European Sustainability Reporting Standard E5 Resource use and circular economy",
334
+ "ESRS G1": "European Sustainability Reporting Standard G1 Business conduct",
335
+ "ESRS S1": "European Sustainability Reporting Standard S1 Own workforce",
336
+ "ESRS S2": "European Sustainability Reporting Standard S2 Workers in the value chain",
337
+ "ESRS S3": "European Sustainability Reporting Standard S3 Affected communities",
338
+ "ESRS S4": "European Sustainability Reporting Standard S4 Consumers & end-users",
339
+ "EU": "European Union",
340
+ "EU ETS": "European Union Emissions Trading System",
341
+ "EWC": "European Works Council",
342
+ "FPIC": "Free, Prior and Informed Consent",
343
+ "FTE": "Full-time equivalent",
344
+ "GHG": "Greenhouse Gas",
345
+ "GJ": "Giga-Joules",
346
+ "GRI": "Global Reporting Initiative",
347
+ "GWP": "Global Warming Potential",
348
+ "HFCs": "Hydrofluorocarbons",
349
+ "IED": "Directive 2010/75/EU of the European Parliament and of the Council _ (Industrial Emissions Directive)",
350
+ "IFC": "International Finance Corporation",
351
+ "IPBES": "Intergovernmental Science-Policy Platform on Biodiversity and Ecosystem Services",
352
+ "IPCC": "Intergovernmental Panel on Climate Change",
353
+ "ISEAL": "International Social and Environmental Accreditation and Labelling Alliance",
354
+ "ISO": "International Organization for Standardization",
355
+ "ISSB": "International Sustainability Standards Board",
356
+ "IUCN": "International Union for Conservation of Nature",
357
+ "KBA": "Key Biodiversity Areas",
358
+ "Kg": "Kilogram",
359
+ "lb": "Pounds",
360
+ "LEAP": "Locate Evaluate Assess Prepare",
361
+ "LGBTQI": "Lesbian, Gay, Bisexual, Transgender, Queer, Intersex",
362
+ "MDR": "Minimum Disclosure Requirement",
363
+ "MWh": "Mega-Watt-hours",
364
+ "N2O": "Nitrous Oxide",
365
+ "NACE": "Statistical Classification of Economic Activities in the European Community",
366
+ "NF3": "Nitrogen trifluoride",
367
+ "NGOs": "Non-Governmental Organisations",
368
+ "NH3": "Ammonia",
369
+ "NOX": "Nitrogen oxides",
370
+ "NUTS": "Nomenclature of Territorial Units of Statistics",
371
+ "ODS": "Ozone-depleting substance",
372
+ "OECM": "One Earth Climate Model",
373
+ "OpEX": "Operating Expenditure",
374
+ "PBTS": "Persistent, bioaccumulative and toxic substances",
375
+ "PCAF": "Partnership for Carbon Accounting Financial",
376
+ "PCFs": "Perfluorocarbons",
377
+ "PM": "Particulate Matter",
378
+ "PMTs": "Persistent, Mobile and Toxic Substances",
379
+ "POPs": "Persistent organic pollutants",
380
+ "REACH": "Registration, Evaluation, Authorisation and Restriction of Chemicals",
381
+ "SBTi": "Science Based Targets Initiative",
382
+ "SBTN": "Science Based Targets Network",
383
+ "SCE": "Societas Cooperativa Europaea",
384
+ "SDA": "Sectoral Decarbonisation Approach",
385
+ "SDGs": "Sustainable Development Goals",
386
+ "SDPI": "Sustainable Development Performance Indicator",
387
+ "SE": "Societas Europaea",
388
+ "SEEA": "System of Environmental-Economic Accounting",
389
+ "SEEA EA": "System of Environmental-Economic Accounting Ecosystem Accounting",
390
+ "SFDR": "Regulation (EU) 2019/2088 of the European Parliament and of the Council_ (Sustainable Finance Disclosures Regulation)",
391
+ "SOX": "Sulphur oxides",
392
+ "SVHC": "Substances of Very High Concern",
393
+ "TCFD": "Task Force on Climate-Related Financial Disclosures",
394
+ "TNFD": "Taskforce on Nature-related Financial Disclosures",
395
+ "UN": "United Nations",
396
+ "UNEP": "United Nations Environment Programme",
397
+ "UNESCO": "United Nations Educational, Scientific and Cultural Organization",
398
+ "vPvBs": "Very persistent and very bioaccumulative substances",
399
+ "vPvMs": "Very persistent and very mobile substances",
400
+ "WDPA": "World Database of Protected Areas",
401
+ "WRI": "World Resources Institute",
402
+ "WWF": "World-Wide Fund for Nature"
403
+ }
requirements.txt ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ altair==4.2.2
2
+ datasets==2.12.0
3
+ faiss-cpu==1.7.4
4
+ gradio==3.39.0
5
+ gradio_client==0.3.0
6
+ openai==0.27.0
7
+ PyMuPDF==1.22.3
8
+ python-dotenv==1.0.0
9
+ sentence-transformers==2.2.2
10
+ torch==2.0.1
11
+ matplotlib==3.7.1
12
+ tiktoken==0.4.0
text_embedder.py ADDED
@@ -0,0 +1,132 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from abc import ABC, abstractmethod
2
+
3
+ import pandas as pd
4
+ import torch
5
+ from datasets import load_from_disk
6
+ from sentence_transformers import SentenceTransformer
7
+
8
+ # from finbert_embedding.embedding import FinbertEmbedding
9
+
10
+
11
+ class TextEmbedder(ABC):
12
+ def __init__(self, model_name, paragraphs_path, device, load_existing_index=False):
13
+ """Initialize an instance of the TextEmbedder class.
14
+ Args:
15
+ model_name (str): The name of the SentenceTransformer model to be used for embeddings.
16
+ paragraphs_path (str): The path to the dataset of paragraphs to be embedded.
17
+ device (str): The target device to run the model ('cpu' or 'cuda').
18
+ load_existing_index (bool): If True, load an existing Faiss index, if available.
19
+ Returns:
20
+ None
21
+ """
22
+ self.dataset = load_from_disk(paragraphs_path)
23
+ self.model = self._load_model(model_name, device)
24
+
25
+ assert len(self.dataset) > 0, "The loaded dataset is empty !!"
26
+
27
+ if load_existing_index == True:
28
+ self.dataset.load_faiss_index(
29
+ "embeddings", f"{paragraphs_path}/index.faiss"
30
+ )
31
+
32
+ # Generate embeddings for each paragraph
33
+ def generate_paragraphs_embedding(self):
34
+ """Generate embeddings for paragraphs in the dataset.
35
+ This function computes embeddings for each paragraph's content in the dataset and adds
36
+ the embeddings as a new column named "embeddings" to the dataset.
37
+ Args:
38
+ None
39
+ Returns:
40
+ None
41
+ """
42
+ self.dataset = self.dataset.map(
43
+ lambda x: {"embeddings": self._generate_embeddings(x["content"])}
44
+ )
45
+
46
+ # Save embeddings
47
+ def save_embeddings(self, output_path):
48
+ """Save Faiss embeddings index to a specified output path.
49
+ Args:
50
+ output_path (str): The path to save the Faiss embeddings index.
51
+ Returns:
52
+ None
53
+ """
54
+ self.dataset.add_faiss_index(column="embeddings")
55
+ self.dataset.save_faiss_index("embeddings", f"{output_path}/index.faiss")
56
+
57
+ # Allows the search
58
+ def retrieve_faiss(self, query: str, k_total: int, threshold: int):
59
+ """Retrieve passages using Faiss similarity search.
60
+ Args:
61
+ query (str): The query for which similar passages are to be retrieved.
62
+ k_total (int): The total number of passages to retrieve.
63
+ threshold (int): The minimum similarity score threshold for passages to be considered.
64
+ Returns:
65
+ Tuple[List[Dict[str, Union[str, Dict[str, Any]]], np.ndarray]]:
66
+ A tuple containing:
67
+ - List of dictionaries, each representing a passage with 'content' (str) and 'meta' (dict) fields.
68
+ - Numpy array of similarity scores for the retrieved passages.
69
+ """
70
+ question_embedding = self._generate_embeddings(query)
71
+ scores, samples = self.dataset.get_nearest_examples(
72
+ "embeddings", question_embedding, k=k_total
73
+ )
74
+ passages_df = pd.DataFrame(samples)
75
+ passages_df["scores"] = scores / 100
76
+ passages_df = passages_df[passages_df["scores"] > threshold]
77
+ passages_df = passages_df.sort_values(by=["scores"], ascending=False)
78
+
79
+ if len(passages_df) == 0:
80
+ return [], []
81
+
82
+ contents = passages_df["content"].tolist()
83
+ meta = passages_df.drop(columns=["content"]).to_dict(orient="records")
84
+ passages = []
85
+ for i in range(len(contents)):
86
+ passages.append({"content": contents[i], "meta": meta[i]})
87
+ return passages, passages_df["scores"].values
88
+
89
+ def retrieve_elastic(self, query: str, k_total: int, threshold: int):
90
+ raise NotImplementedError
91
+
92
+ @abstractmethod
93
+ def _load_model(self, model_name: str, device: str):
94
+ pass
95
+
96
+ @abstractmethod
97
+ def _generate_embeddings(self, text: str):
98
+ pass
99
+
100
+
101
+ class SentenceTransformersTextEmbedder(TextEmbedder):
102
+ def _load_model(self, model_name: str, device: str):
103
+ """Load a SentenceTransformer model onto the specified device.
104
+ Args:
105
+ model_name (str): The name of the SentenceTransformer model to be loaded.
106
+ device (str): The target device to move the model to ('cpu' or 'cuda').
107
+ Returns:
108
+ SentenceTransformer: The loaded SentenceTransformer model placed on the specified device.
109
+ """
110
+ model = SentenceTransformer(model_name)
111
+ torch_device = torch.device(device)
112
+ model.to(torch_device)
113
+ return model
114
+
115
+ def _generate_embeddings(self, text: str):
116
+ """Generate embeddings for a given text using the loaded model.
117
+ Args:
118
+ text (str): The input text for which embeddings are to be generated.
119
+ Returns:
120
+ np.ndarray: An array representing the embeddings of the input text.
121
+ """
122
+ return self.model.encode(text)
123
+
124
+
125
+ # class FinBertTextEmbedder(TextEmbedder):
126
+ # def _load_model(self, model_name: str, device: str):
127
+ # model = FinbertEmbedding(device=device)
128
+ # return model
129
+
130
+ # def _generate_embeddings(self, text: str):
131
+ # output = self.model.sentence_vector(text)
132
+ # return output.cpu().numpy()
utils.py ADDED
@@ -0,0 +1,381 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import json
2
+ from collections import defaultdict
3
+ import openai
4
+ import re
5
+ from config import CFG_APP
6
+ from text_embedder import SentenceTransformersTextEmbedder
7
+ from datetime import datetime
8
+ import tiktoken
9
+
10
+ doc_metadata = json.load(open(CFG_APP.DOC_METADATA_PATH, "r"))
11
+ # Embedding Model
12
+ if "sentence-transformers" in CFG_APP.EMBEDDING_MODEL:
13
+ text_embedder = SentenceTransformersTextEmbedder(
14
+ model_name=CFG_APP.EMBEDDING_MODEL,
15
+ paragraphs_path=CFG_APP.DATA_FOLDER,
16
+ device=CFG_APP.DEVICE,
17
+ load_existing_index=True,
18
+ )
19
+ else:
20
+ raise ValueError("Embedding model not found !")
21
+
22
+
23
+ # Util Functions
24
+ def retrieve_doc_metadata(doc_metadata, doc_id):
25
+ for meta in doc_metadata:
26
+ if meta["id"] == doc_id:
27
+ return meta
28
+
29
+
30
+ def get_reformulation_prompt(query: str) -> list:
31
+ return [
32
+ {
33
+ "role": "user",
34
+ "content": f"""{CFG_APP.REFORMULATION_PROMPT}
35
+ ---
36
+ query: {query}
37
+ standalone question: """,
38
+ }
39
+ ]
40
+
41
+ def get_hyde_prompt(query: str) -> list:
42
+ return [
43
+ {
44
+ "role": "user",
45
+ "content": f"""{CFG_APP.HYDE_PROMPT}
46
+ ---
47
+ query: {query}
48
+ output: """,
49
+ }
50
+ ]
51
+
52
+
53
+ def make_pairs(lst):
54
+ """From a list of even lenght, make tupple pairs
55
+ Args:
56
+ lst (list): a list of even lenght
57
+ Returns:
58
+ list: the list as tupple pairs
59
+ """
60
+ assert not (l := len(lst) % 2), f"your list is of lenght {l} which is not even"
61
+ return [(lst[i], lst[i + 1]) for i in range(0, len(lst), 2)]
62
+
63
+
64
+ def make_html_source(paragraph, meta_doc, i):
65
+ content = paragraph["content"]
66
+ meta_paragraph = paragraph["meta"]
67
+ return f"""
68
+ <div class="card" id="document-{i}">
69
+ <div class="card-content">
70
+ <h2>Excerpts {i} - Document {meta_doc['num_doc']} - Page {meta_paragraph['page_number']}</h2>
71
+ <p>{content}</p>
72
+ </div>
73
+ <div class="card-footer">
74
+ <span>{meta_doc['short_name']}</span>
75
+ <a href="{meta_doc['url']}#page={meta_paragraph['page_number']}" target="_blank" class="pdf-link">
76
+ <span role="img" aria-label="Open PDF">πŸ”—</span>
77
+ </a>
78
+ </div>
79
+ </div>
80
+ """
81
+
82
+ def make_citations_source(citation_dic, query, Hyde: False):
83
+ citation_list = [f'Doc {values[0]} - {keys} (excerpts {values[1]})' for keys, values in citation_dic.items()]
84
+
85
+ html_output = '<div class="source">\n'
86
+ html_output += ' <div class="title">Sources</div>\n'
87
+ if Hyde :
88
+ html_output += f' <div>Query used for retrieval (with the HyDE technique after no response): {query}</div>\n'
89
+ else :
90
+ html_output += f' <div>Query used for retrieval: {query}</div>\n'
91
+ html_output += ' <br>\n'
92
+ html_output += ' <ul>\n'
93
+
94
+ for row in citation_list :
95
+ html_output += f'<li>{row}</li>'
96
+
97
+ html_output += ' </ul>\n'
98
+ html_output += '</div>\n'
99
+
100
+ return html_output
101
+
102
+
103
+ def preprocess_message(text: str, docs_url: dict) -> str:
104
+ return re.sub(
105
+ r"\[doc (\d+)\]",
106
+ lambda match: f'<a href="{docs_url[match.group(1)]}" target="_blank" class="pdf-link">{match.group(0)}</a>',
107
+ text,
108
+ )
109
+
110
+
111
+ def parse_glossary(query):
112
+ file = "glossary.json"
113
+ glossary = json.load(open(file, "r"))
114
+ words_query = query.split(" ")
115
+ for i, word in enumerate(words_query):
116
+ for key in glossary.keys():
117
+ if word.lower() == key.lower():
118
+ words_query[i] = words_query[i] + f" ({glossary[key]})"
119
+ return " ".join(words_query)
120
+
121
+
122
+ def num_tokens_from_string(string: str, encoding_name: str) -> int:
123
+ encoding = tiktoken.encoding_for_model(encoding_name)
124
+ num_tokens = len(encoding.encode(string))
125
+ return num_tokens
126
+
127
+
128
+ def chat(
129
+ query: str,
130
+ history: list,
131
+ threshold: float = CFG_APP.THRESHOLD,
132
+ k_total: int = CFG_APP.K_TOTAL,
133
+ ) -> tuple:
134
+ """retrieve relevant documents in the document store then query gpt-turbo
135
+ Args:
136
+ query (str): user message.
137
+ history (list, optional): history of the conversation. Defaults to [system_template].
138
+ report_type (str, optional): should be "All available" or "IPCC only". Defaults to "All available".
139
+ threshold (float, optional): similarity threshold, don't increase more than 0.568. Defaults to 0.56.
140
+ Yields:
141
+ tuple: chat gradio format, chat openai format, sources used.
142
+ """
143
+
144
+ reformulated_query = openai.ChatCompletion.create(
145
+ model=CFG_APP.MODEL_NAME,
146
+ messages=get_reformulation_prompt(parse_glossary(query)),
147
+ temperature=0,
148
+ max_tokens=CFG_APP.MAX_TOKENS_REF_QUESTION,
149
+ )
150
+
151
+ reformulated_query = reformulated_query["choices"][0]["message"]["content"]
152
+
153
+ if len(reformulated_query.split("\n")) == 2:
154
+ reformulated_query, language = reformulated_query.split("\n")
155
+ language = language.split(":")[1].strip()
156
+ else:
157
+ reformulated_query = reformulated_query.split("\n")[0]
158
+ language = "English"
159
+
160
+ sources, scores = text_embedder.retrieve_faiss(
161
+ reformulated_query,
162
+ k_total=k_total,
163
+ threshold=threshold,
164
+ )
165
+
166
+ if CFG_APP.DEBUG == True:
167
+ print("Scores : \n", scores)
168
+
169
+ messages = history + [{"role": "user", "content": query}]
170
+
171
+ docs_url = defaultdict(str)
172
+
173
+ if len(sources) > 0:
174
+ docs_string = []
175
+ docs_html = []
176
+ citations = {}
177
+
178
+ num_tokens = num_tokens_from_string(CFG_APP.SOURCES_PROMPT, CFG_APP.MODEL_NAME)
179
+ num_doc = 1
180
+
181
+ for i, data in enumerate(sources, 1):
182
+ meta_doc = retrieve_doc_metadata(doc_metadata, data["meta"]["document_id"])
183
+ doc_content = f"πŸ“ƒ Doc {i}: \n{data['content']}"
184
+ num_tokens_doc = num_tokens_from_string(doc_content, CFG_APP.MODEL_NAME)
185
+ if num_tokens + num_tokens_doc > CFG_APP.MAX_TOKENS_API:
186
+ break
187
+ num_tokens += num_tokens_doc
188
+ docs_string.append(doc_content)
189
+
190
+ if meta_doc['short_name'] in citations.keys():
191
+ citations[meta_doc['short_name']][1] += f', {i}'
192
+ else :
193
+ citations[meta_doc['short_name']] = [num_doc, f'{i}']
194
+ num_doc += 1
195
+
196
+ meta_doc["num_doc"] = citations[meta_doc['short_name']][0]
197
+
198
+ docs_html.append(make_html_source(data, meta_doc, i))
199
+
200
+ url_doc = f'<a href="{meta_doc["url"]}#page={data["meta"]["page_number"]}" target="_blank" class="pdf-link">'
201
+ docs_url[i] = url_doc
202
+
203
+ html_cit = [make_citations_source(citations, reformulated_query, Hyde=False)]
204
+
205
+ docs_string = "\n\n".join( [f"Query used for retrieval:\n{reformulated_query}"] + docs_string)
206
+
207
+ docs_html = "\n\n".join(html_cit + docs_html)
208
+
209
+ messages.append(
210
+ {
211
+ "role": "system",
212
+ "content": f"{CFG_APP.SOURCES_PROMPT}\n\n{docs_string}\n\nAnswer in {language}:",
213
+ }
214
+ )
215
+
216
+ if CFG_APP.DEBUG == True:
217
+ print(f" πŸ‘¨β€πŸ’» question asked by the user : {query}")
218
+ print(f" πŸ•› time : {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
219
+
220
+ print(" πŸ”Œ messages sent to the API :")
221
+ api_messages = [
222
+ {"role": "system", "content": CFG_APP.INIT_PROMPT},
223
+ {"role": "user", "content": reformulated_query},
224
+ {
225
+ "role": "system",
226
+ "content": f"{CFG_APP.SOURCES_PROMPT}\n\n{docs_string}\n\nAnswer in {language}:",
227
+ },
228
+ ]
229
+ for message in api_messages:
230
+ print(
231
+ f"length : {len(message['content'])}, content : {message['content']}"
232
+ )
233
+
234
+ response = openai.ChatCompletion.create(
235
+ model=CFG_APP.MODEL_NAME,
236
+ messages=[
237
+ {"role": "system", "content": CFG_APP.INIT_PROMPT},
238
+ {"role": "user", "content": reformulated_query},
239
+ {
240
+ "role": "system",
241
+ "content": f"{CFG_APP.SOURCES_PROMPT}\n\nVery important : Answer in {language}.\n\n{docs_string}:",
242
+ },
243
+ ],
244
+ temperature=0, # deterministic
245
+ stream=True,
246
+ max_tokens=CFG_APP.MAX_TOKENS_ANSWER,
247
+ )
248
+ complete_response = ""
249
+ messages.pop()
250
+ messages.append({"role": "assistant", "content": complete_response})
251
+ for chunk in response:
252
+ chunk_message = chunk["choices"][0]["delta"].get("content")
253
+ if chunk_message:
254
+ complete_response += chunk_message
255
+ complete_response = preprocess_message(complete_response, docs_url)
256
+ messages[-1]["content"] = complete_response
257
+ gradio_format = make_pairs([a["content"] for a in messages[1:]])
258
+ yield gradio_format, messages, docs_html
259
+
260
+ else:
261
+ reformulated_query = openai.ChatCompletion.create(
262
+ model=CFG_APP.MODEL_NAME,
263
+ messages=get_hyde_prompt(parse_glossary(query)),
264
+ temperature=0,
265
+ max_tokens=CFG_APP.MAX_TOKENS_REF_QUESTION,
266
+ )
267
+
268
+ reformulated_query = reformulated_query["choices"][0]["message"]["content"]
269
+
270
+ if len(reformulated_query.split("\n")) == 2:
271
+ reformulated_query, language = reformulated_query.split("\n")
272
+ language = language.split(":")[1].strip()
273
+ else:
274
+ reformulated_query = reformulated_query.split("\n")[0]
275
+ language = "English"
276
+
277
+ sources, scores = text_embedder.retrieve_faiss(
278
+ reformulated_query,
279
+ k_total=k_total,
280
+ threshold=threshold,
281
+ )
282
+
283
+ if CFG_APP.DEBUG == True:
284
+ print("Scores : \n", scores)
285
+
286
+ if len(sources) > 0 :
287
+ docs_string = []
288
+ docs_html = []
289
+ citations = {}
290
+
291
+ num_tokens = num_tokens_from_string(CFG_APP.SOURCES_PROMPT, CFG_APP.MODEL_NAME)
292
+
293
+ num_doc = 1
294
+
295
+ for i, data in enumerate(sources, 1):
296
+ meta_doc = retrieve_doc_metadata(doc_metadata, data["meta"]["document_id"])
297
+ doc_content = f"πŸ“ƒ Doc {i}: \n{data['content']}"
298
+ num_tokens_doc = num_tokens_from_string(doc_content, CFG_APP.MODEL_NAME)
299
+ if num_tokens + num_tokens_doc > CFG_APP.MAX_TOKENS_API:
300
+ break
301
+ num_tokens += num_tokens_doc
302
+ docs_string.append(doc_content)
303
+
304
+ if meta_doc['short_name'] in citations.keys():
305
+ citations[meta_doc['short_name']][1] += f', {i}'
306
+ else:
307
+ citations[meta_doc['short_name']] = [num_doc, f'{i}']
308
+ num_doc += 1
309
+
310
+ meta_doc["num_doc"] = citations[meta_doc['short_name']][0]
311
+
312
+ docs_html.append(make_html_source(data, meta_doc, i))
313
+
314
+ url_doc = f'<a href="{meta_doc["url"]}#page={data["meta"]["page_number"]}" target="_blank" class="pdf-link">'
315
+ docs_url[i] = url_doc
316
+
317
+ html_cit = [make_citations_source(citations, reformulated_query, Hyde=True)]
318
+
319
+ docs_string = "\n\n".join([f"Query used for retrieval:\n{reformulated_query}"] + docs_string)
320
+
321
+ docs_html = "\n\n".join(html_cit + docs_html)
322
+
323
+ messages.append(
324
+ {
325
+ "role": "system",
326
+ "content": f"{CFG_APP.SOURCES_PROMPT}\n\n{docs_string}\n\nAnswer in {language}:",
327
+ }
328
+ )
329
+
330
+ if CFG_APP.DEBUG == True:
331
+ print(f" πŸ‘¨β€πŸ’» question asked by the user : {query}")
332
+ print(f" πŸ•› time : {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
333
+
334
+ print(" πŸ”Œ messages sent to the API :")
335
+ api_messages = [
336
+ {"role": "system", "content": CFG_APP.INIT_PROMPT},
337
+ {"role": "user", "content": reformulated_query},
338
+ {
339
+ "role": "system",
340
+ "content": f"{CFG_APP.SOURCES_PROMPT}\n\nVery important : Answer in {language}.\n\n{docs_string}:",
341
+ },
342
+ ]
343
+ for message in api_messages:
344
+ print(
345
+ f"length : {len(message['content'])}, content : {message['content']}"
346
+ )
347
+
348
+ response = openai.ChatCompletion.create(
349
+ model=CFG_APP.MODEL_NAME,
350
+ messages=[
351
+ {"role": "system", "content": CFG_APP.INIT_PROMPT},
352
+ {"role": "user", "content": reformulated_query},
353
+ {
354
+ "role": "system",
355
+ "content": f"{CFG_APP.SOURCES_PROMPT}\n\nVery important : Answer in {language}.\n\n{docs_string}:",
356
+ },
357
+ ],
358
+ temperature=0, # deterministic
359
+ stream=True,
360
+ max_tokens=CFG_APP.MAX_TOKENS_ANSWER,
361
+ )
362
+ complete_response = ""
363
+ messages.pop()
364
+ messages.append({"role": "assistant", "content": complete_response})
365
+ for chunk in response:
366
+ chunk_message = chunk["choices"][0]["delta"].get("content")
367
+ if chunk_message:
368
+ complete_response += chunk_message
369
+ complete_response = preprocess_message(complete_response, docs_url)
370
+ messages[-1]["content"] = complete_response
371
+ gradio_format = make_pairs([a["content"] for a in messages[1:]])
372
+ yield gradio_format, messages, docs_html
373
+
374
+ else :
375
+ docs_string = "⚠️ No relevant passages found in this report"
376
+ complete_response = "**⚠️ No relevant passages found in this report, you may want to ask a more specific question.**"
377
+ messages.append({"role": "assistant", "content": complete_response})
378
+ gradio_format = make_pairs([a["content"] for a in messages[1:]])
379
+ yield gradio_format, messages, docs_string
380
+
381
+