How to Automate Financial Risk Reports: A Guide for Product Managers
Financial risk can have a significant impact on the production of your products and your industry as whole. If you’re a product manager, you can use AI and news data from various sources to shape your product and prepare for potential financial risks. This guide shows you how to automatically generate financial risk reports using powerful tools from Webz.io and OpenAI. Depending on your skill sets, you may need technical help to complete the steps outlined in this guide. The steps show you how to create a Python script that puts these powerful tools together.
So, buckle up and prepare to gain actionable insights into financial risk!
What you’ll need
- News Data — You should obtain news data from a reliable source. For this guide, we’re getting the data from the Webz.io News API. It provides structured news data feeds in 170+ languages from millions of news sites.
- OpenAI API — You’ll use OpenAI’s API to leverage the GPT-4 and DALL·E models. GPT-4 analyzes and summarizes the text from customer reviews, while DALL·E generates a main image for the report.
- Python — We’re using Python to automate the report creation process. You’ll need to ensure you can run Python code on your machine.
Set up your development environment
Setting up the environment to create automated reports requires the following:
- Get a Webz.io API key — You need an API key to use the Webz.io News API. To get a key, contact Webz.io.
- Get an OpenAI API key — You also need an API key for the OpenAI API. Create an account or sign in at OpenAI to get a key. OpenAI uses pay-per-use pricing for its language and image models. You can see the price points on the OpenAI website.
- Install Python — If you don’t already have a development environment with Python installed, you’ll need to set one up. If you’re using a Windows operating system, you can find a tutorial on how to get started using Python on Windows on the Microsoft website. Next, install the Python packages using pip, the standard package installer and manager for Python.
Create your automated financial risk report
Now that you’ve set up your development environment, you can move on to automating the report generation process. The below steps will let you automatically generate a detailed financial risk report.
Gather relevant data
Use the Webz.io News API to obtain news articles, creating a query that returns articles pertaining to financial risk. Use the API’s robust filters to ensure you only get high-quality, news content. The Python Levenshtein module ratio function in the script removes similar articles to ensure uniqueness.
Unlock and summarize hidden insights
Unleash the magic of OpenAI’s GPT-4 model to analyze the data gathered by the Webz.io News API. Use this powerful large language model to discover potential financial risks that could impact your customers or even your own business.
The GPT-4 model determines if an article explicitly discusses a specific financial risk. If the article does contain relevant information, the model generates a detailed report about it in HTML format. The script has a global variable that you can use to set the number of reports you’d like generated. Make sure you’ve set up your OpenAI API key in your development environment before completing this step.
Craft a compelling report
Utilize Python’s Docx package to create a professional Word document for your financial risk report. The script inserts each analyzed article as a section in the document, structured with:
- Executive Summary
- Background Information
- Key Data Extracted
- Market and Economic Indicators Impacted
- Industry-Specific Impact
- Company-Specific Impact
- Regulatory and Compliance Implications
- Risk Assessment
- Mitigation Strategies and Recommendations
- Conclusion
Boost visual appeal
Use OpenAI’s DALL-E model to generate an impactful visual to use as the cover image for the report.
Finalize and share the report
Compile all the textual and visual elements into your report and review the contents carefully. Go through and polish the report for clarity and coherence. Once satisfied with the finalized report, share it with key stakeholders, incorporating their feedback to improve the report’s utility. We also recommend that you regularly review the accuracy and relevance of generated reports.
Have fun experimenting with Webz.io and OpenAI
You’re all set to start automating financial risk reports. By following this guide and leveraging tools from Webz.io and OpenAI, you’ll gain invaluable insights from news data that you can use to aid in strategic decision-making. Let the automated reports production begin!
Download the example code and report:
The full Python script.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
|
import docx
import requests
from openai import OpenAI
import os
import openai
from Levenshtein import ratio
from docx.shared import Pt
from bs4 import BeautifulSoup
import io
from docx.oxml.shared import OxmlElement, qn
from docx.shared import Pt
from docx.enum.text import WD_ALIGN_PARAGRAPH
import json
WEBZ_API_KEY = os.getenv(“WEBZ_API_KEY”)
openai.api_key = os.getenv(“OPENAI_API_KEY”)
NUM_OF_REPORTS = 5
client = OpenAI()
def are_similar(str1, str2, threshold=1):
“””
Check if two strings are similar based on Levenshtein ratio.
“””
return ratio(str1, str2) > threshold
def remove_similar_strings(articles):
unique_articles = []
for article in articles:
if not any(are_similar(article[‘text’], existing[‘text’], 0.7) for existing in unique_articles):
unique_articles.append(article)
return unique_articles
def trim_string(string, max_length):
if len(string) > max_length:
return string[:max_length]
else:
return string
# Function to get news articles from Webz.io API
def fetch_articles(query, api_key, total):
endpoint = f“https://api.webz.io/filterWebContent?token={api_key}&format=json&q={query}&size=100&ts=0”
all_posts = []
# load from local file if you don’t have access to webz.io
# with open(‘financial_posts.json’, ‘r’, encoding=’utf-8′) as file:
# all_posts = json.load(file)[‘posts’]
# total = 0
while total > 0:
response = requests.get(endpoint)
data = response.json()
posts = data[“posts”]
all_posts.extend(posts)
total -= len(posts)
if total > 0 and “next” in data:
endpoint = f“https://api.webz.io{data[‘next’]}”
else:
break
articles = []
for article in all_posts:
article = {‘title’: article[“title”],
‘text’: trim_string(trim_title(article[“title”]) + “nn” + article[“text”], 10000),
‘link’: article[‘url’],
‘published’: article[‘published’]}
articles.append(article)
return articles
def trim_title(input_string):
words = input_string.split()
if “|” in input_string:
return input_string.split(“|”)[0]
last_dash_index = input_string.rfind(“-“)
if last_dash_index != –1:
right_of_dash = input_string[last_dash_index + 1:]
right_words = right_of_dash.split()
if len(right_words) <= 3 and len(words) > 10:
return input_string[:last_dash_index]
return input_string
def add_image_from_base64(doc, image_url):
response = requests.get(image_url)
# Check if the request was successful
if response.status_code == 200:
image_stream = io.BytesIO(response.content)
doc.add_picture(image_stream, width=docx.shared.Inches(6))
else:
print(f“Failed to download image. Status code: {response.status_code}”)
def html_to_word(doc, html_content):
soup = BeautifulSoup(html_content, ‘html.parser’)
for element in soup.find_all([‘b’, ‘ul’]):
if element.name == ‘b’:
# Add bold text as a heading
doc.add_paragraph(element.get_text(), style=‘Heading 2’)
elif element.name == ‘ul’:
for item in element.find_all(‘li’):
# Add list items
doc.add_paragraph(item.get_text(), style=‘List Bullet’)
def add_hyperlink(paragraph, url, text):
“””
Add a hyperlink to a paragraph.
“””
part = paragraph.part
r_id = part.relate_to(url, docx.opc.constants.RELATIONSHIP_TYPE.HYPERLINK, is_external=True)
hyperlink = OxmlElement(‘w:hyperlink’)
hyperlink.set(qn(‘r:id’), r_id,)
new_run = OxmlElement(‘w:r’)
rPr = OxmlElement(‘w:rPr’)
u = OxmlElement(‘w:u’)
u.set(qn(‘w:val’), ‘single’)
rPr.append(u)
u = OxmlElement(‘w:u’)
u.set(qn(‘w:val’), ‘single’)
rPr.append(u)
new_run.append(rPr)
new_run.text = text
hyperlink.append(new_run)
paragraph._p.append(hyperlink)
return hyperlink
def insert_titles_in_text(text, reports):
# Placeholder for inserting the titles
placeholder = “[]”
# Extracting the titles from the reports and formatting them with new lines
titles = “n”.join([report[‘title’] for report in reports])
# Replacing the placeholder with the titles
updated_text = text.replace(placeholder, titles)
return updated_text
def generate_article_image():
print(“Generating post image”)
image_url = “”
try:
response = client.images.generate(
model=“dall-e-3”,
prompt=“Create a realistic featured image for a financial risk reports. The image should depict a modern office environment with a large, clear display screen in the background showing graphs, random companies logos and financial data. In the foreground, arrange a series of different, but related, documents or tablets, each representing a different financial risk report. These documents should be partially overlapped to convey a sense of abundance and detail. Include elements like pens, glasses, and other office accessories to add to the realism. The overall tone should be professional and sophisticated.”,
n=1,
size=“1024×1024”
)
image_url = response.data[0].url
except Exception as e:
print(“An error occurred generating the image:”, str(e))
return image_url
def get_unique_posts_from_webz(query):
print(“Fetch posts from Webz.io”)
articles = fetch_articles(query, WEBZ_API_KEY, 100)
filtered_articles = remove_similar_strings(articles)
return filtered_articles
def call_gpt_completion(prompt):
return client.chat.completions.create(
model=“gpt-4-1106-preview”,
max_tokens=4096,
messages=[
{“role”: “user”, “content”: prompt},
]
)
def generate_reports(filtered_articles):
print(“Generating Reports”)
reports = []
for article in filtered_articles:
print(f“Creating report about: {article[‘title’]}”)
prompt = f“””Carefully review the following negative news article in the ‘Economy, Business, and Finance’ category and determine if there is an explicit financial risk emerging from its content. The article is as follows:
[
{article[‘text’]}
]
If the article explicitly mentions or clearly implies a financial risk, generate a detailed financial risk analysis report in HTML format. Use <B> tags to highlight the titles of each section and <UL> and <LI> tags for listing items. The report should include the following sections:
<HTML>
<B>1. Executive Summary:</B>
<UL>
<LI>Summarize the main points and the explicit financial risk identified in the article.</LI>
</UL>
<B>2. Background Information:</B>
<UL>
<LI>Provide background on the event or issue, focusing on aspects related to the identified financial risk.</LI>
</UL>
<B>3. Key Data Extracted:</B>
<UL>
<LI>List key figures, statistics, and significant quotes that are relevant to the financial risk.</LI>
</UL>
<B>4. Market and Economic Indicators Impacted:</B>
<UL>
<LI>Discuss the impact on financial markets and economic indicators as it relates to the identified risk.</LI>
</UL>
<B>5. Industry-Specific Impact:</B>
<UL>
<LI>Detail the effects on industries, specifically in relation to the financial risk highlighted in the article.</LI>
</UL>
<B>6. Company-Specific Impact:</B>
<UL>
<LI>If specific companies are mentioned in the context of the financial risk, explain how the event impacts them.</LI>
</UL>
<B>7. Regulatory and Compliance Implications:</B>
<UL>
<LI>Mention any regulatory or compliance issues related to the financial risk.</LI>
</UL>
<B>8. Risk Assessment:</B>
<UL>
<LI>Assess the financial risks, focusing on those explicitly mentioned or implied in the article.</LI>
</UL>
<B>9. Mitigation Strategies and Recommendations:</B>
<UL>
<LI>Suggest strategies for mitigating the identified financial risks, based on the article.</LI>
</UL>
<B>10. Conclusion:</B>
<UL>
<LI>Conclude with the overall implications of the identified financial risk.</LI>
</UL>
</HTML>
If the article does not explicitly mention or imply a financial risk, please respond with: can’t produce report.
“””
try:
response = call_gpt_completion(prompt)
report = {‘text’: ”}
for choice in response.choices:
report[‘text’] += choice.message.content
if “Executive Summary” in report[‘text’]:
report[‘link’] = article[‘link’]
report[‘title’] = article[‘title’]
report[‘published’] = article[‘published’]
reports.append(report)
print(f“Created a report about: {article[‘title’]}”)
else:
print(f“Can’t product report for: {article[‘title’]}”)
if len(reports) == NUM_OF_REPORTS:
break
except Exception as e:
print(“An error occurred:”, str(e))
return reports
def generate_intro(reports):
print(“Generate post intro”)
prompt = “””
Write a paragraph introducing a digest that contains financial risk reports about the following titles, don’t elaborate on these titles:
[]
The reports are created automatically by using Webz.io news api and ChatGPT. The reports are generated by calling the Webz.io news API for negative sentiment news articles categorized as “Economy, Business and Finance”. The matching news articles are then run through a ChatGPT prompt to analyze if there is a financial risk in the article. If so it create a structured financial risk report.
“””
prompt = insert_titles_in_text(prompt, reports)
intro = “”
try:
response = call_gpt_completion(prompt)
for choice in response.choices:
intro += choice.message.content
except Exception as e:
print(“An error occurred:”, str(e))
return intro
def generate_title(intro):
print(“Creating a title”)
prompt = “Create a title using the following text as a context:n” + intro
title_text = “”
try:
response = call_gpt_completion(prompt)
for choice in response.choices:
title_text += choice.message.content
except Exception as e:
print(“An error occurred:”, str(e))
title_text = title_text.strip().strip(‘”‘)
if title_text.startswith(“Title:”): # Sometimes ChatGPT prefix the title with Title:
return title_text[len(“Title:”):]
return title_text
def create_word_doc(file_name, title_text, image_url, intro, reports):
print(“Saving to word document”)
doc = docx.Document()
# Add a title
title = doc.add_paragraph()
title.style = ‘Title’
title_run = title.add_run(title_text)
title_run.font.size = Pt(24) # Set the font size
title_run.font.name = ‘Arial (Body)’ # Set the font
title.alignment = WD_ALIGN_PARAGRAPH.CENTER # Center align the title
if len(image_url) > 0:
add_image_from_base64(doc, image_url)
doc.add_paragraph(intro)
# Add each report
for report in reports:
p = doc.add_paragraph(style=‘Heading 1’)
add_hyperlink(p, report[‘link’], report[‘title’])
doc.add_paragraph(f“Published on: {report[‘published’]}”)
html_to_word(doc, report[‘text’])
doc.add_paragraph(“””
“””)
p = doc.add_paragraph(“If you’re interested in understanding the process behind this report’s generation, you have the opportunity to explore it in detail. The complete code used to create this report is openly available for download on GitHub. By visiting the following address: “)
add_hyperlink(p, “https://github.com/Webhose/financial-risk-report”,“https://github.com/Webhose/financial-risk-report”)
p.add_run(“, you can access and review the code, offering you an insightful look into the methodologies and techniques employed in the development of this financial risk report. This transparency allows for a deeper understanding and potential customization to suit specific analytical needs.”)
for paragraph in doc.paragraphs:
for run in paragraph.runs:
run.font.name = ‘Arial (Body)’
# Save the document
doc.save(file_name)
def main():
image_url = generate_article_image()
filtered_articles = get_unique_posts_from_webz(“””category:”Economy, Business and Finance” num_chars:>1000 sentiment:negative language:english published:>now-7d social.facebook.likes:>10″””)
reports = generate_reports(filtered_articles)
intro = generate_intro(reports)
title_text = generate_title(intro)
create_word_doc(“financial risk digest.docx”, title_text, image_url, intro, reports)
if __name__ == “__main__”:
main()
|
Download the auto-generated report
Curious to see what the report looks like? Download the document in PDF format here.
To run the script:
- Ensure that Python and the required Python libraries are installed on your machine.
- Set your OpenAI API key in your development environment.
- Set your Webz.io News API key in your development environment.
- Run the script.
Ready to automate news insights for your organization faster? Talk to one of our experts today.