Why?

In today’s rapidly evolving technological landscape, artificial intelligence represents both a transformative opportunity and a significant disruption risk for established companies across all industries. This use case showcases a streamlined workflow that integrates advanced information retrieval using the Bigdata.com API and large language model (LLM) summarization to automatically generate a curated report on risks related to AI Disruption within a watchlist of companies, along with how proactive these companies have been with incorporating GenAI into their products and establishing partnerships aimed at improving their GenAI offerings.

This workflow provides a comprehensive framework for systematically evaluating how AI impacts a specific group of companies across multiple dimensions:

  • AI Disruption Risks: How vulnerable the companies in the watchlist are to AI-driven market disruptions
  • Proactive AI Adoption: How actively these selected companies are integrating GenAI into their products and forming strategic partnerships

The analysis leverages the GenerateReport class, which orchestrates the entire process from data retrieval to final report generation, providing actionable insights for investment decisions and risk assessment focused on the designated company watchlist.

The Report Generator workflow follows these simple steps:

  1. Retrieve the universe of relevant companies from the predefined watchlist to analyze

  2. For each company in the selected group, use the Bigdata to search for news, filings and transcripts related to AI risk and AI adoption

  3. Categorize the relevance of each document and filter out non-relevant ones

  4. Summarize the documents

  5. Generate AI Disruption Risk Score and AI Proactivity Score for each company in the watchlist

  6. Create the final report covering the analyzed company watchlist

This notebook demonstrates how to implement this workflow, transforming unstructured data into structured, decision-ready intelligence for AI disruption analysis within a curated set of companies.

Setup and Imports

Below is the Python code required for setting up our environment and importing necessary libraries.

from src.report_generator import GenerateReport #the source will be changed
from src.summary.summary import SummarizerCompany #the source will be changed

from bigdata_research_tools.search.screener_search import search_by_companies
from bigdata_research_tools.labeler.screener_labeler import ScreenerLabeler
from bigdata_research_tools.excel import ExcelManager
from bigdata_client.models.search import DocumentType
from bigdata_client import Bigdata

import matplotlib.pyplot as plt
import numpy as np
from datetime import datetime
import pandas as pd
from IPython.display import display, HTML

Define Output Paths

Set up the directory structure where analysis results and reports will be saved.

# Define output file paths for our report
output_dir = f"{current_dir}/output"
os.makedirs(output_dir, exist_ok=True)

export_path = f"{output_dir}/ai_disruption_report.xlsx"

Load Environment Variables

The Report Generator requires API credentials for both the Bigdata API and the LLM API (in this case, OpenAI). Make sure you have these credentials available as environment variables or in a secure credential store.

Never hardcode credentials directly in your notebook or scripts.

# Secure way to access credentials
from google.colab import userdata

BIGDATA_USERNAME = userdata.get('BIGDATA_USERNAME')
BIGDATA_PASSWORD = userdata.get('BIGDATA_PASSWORD')

# Set environment variables for any new client instances
os.environ["BIGDATA_USERNAME"] = BIGDATA_USERNAME
os.environ["BIGDATA_PASSWORD"] = BIGDATA_PASSWORD

# Use them in your code
bigdata = Bigdata(BIGDATA_USERNAME, BIGDATA_PASSWORD)

OPENAI_API_KEY = userdata.get('OPENAI_API_KEY')
os.environ["OPENAI_API_KEY"] = OPENAI_API_KEY

Defining the Report Parameters

Fixed Parameters

  • Keywords (keywords): Keywords used for improving retrieval
  • Main Theme (main_theme_risk): The central concept to explore
  • Main Theme Proactivity (main_theme_proactivity): Proactive measures and strategies companies take to address the main theme risk
  • List of sentences about risks themes (list_sentences_risks): Sentences used to improve the retrieval regarding the main theme
  • List of sentences about risks proactivity themes (list_sentences_proactivity): Sentences used to improve the retrieval regarding the proactivity against the main theme
  • Bigdata (bigdata): Bigdata connection
# ===== Fixed Parameters =====

# Keywords for filtering content
keywords = ['AI']

# Risk Theme
main_theme_risk = 'Risks or concerns related to AI disruption'

# Proactivity Theme
main_theme_proactivity = 'Integrating GenAI into products or forming partnerships to improve GenAI offerings'

# Sentences expressing risk-related narratives
list_sentences_risks = [
    "Companies face substantial risks from AI-driven market disruptions today.",
    "AI advancements threaten traditional business models and competitive advantages.",
    "Disruption by AI can lead to loss of market share rapidly.",
    "Existing workflows may become obsolete due to AI innovations.",
    "Companies risk being outpaced by agile AI-focused competitors."
]

# Sentences expressing proactivity-related narratives
list_sentences_proactivity = [
    "Companies actively incorporate GenAI to enhance product offerings and features.",
    "Partnerships aim to improve GenAI solutions in competitive markets.",
    "Proactive firms leverage GenAI technology to boost customer engagement strategies.",
    "Organizations collaborate to advance GenAI capabilities and applications effectively.",
    "Firms invest in GenAI partnerships to innovate their service delivery."
]

Customizable Parameters

  • Watchlist (my_watchlist_id): The set of companies to analyze. This is the ID of your watchlist in the watchlist section of the app.
  • Model Selection (llm_model): The LLM model used to label search result document chunks and generate summaries
  • Frequency (freq): The frequency of the date ranges to search over. Supported values:
    • Y: Yearly intervals.
    • M: Monthly intervals.
    • W: Weekly intervals.
    • D: Daily intervals. Defaults to 3M.
  • Time Period (start_date and end_date): The date range over which to run the analysis
  • Focus (focus): Specify a focus within the main theme
  • Document Limit (document_limit_news, document_limit_filings, document_limit_transcripts): The maximum number of documents to return per query to Bigdata API for each category of documents
  • Batch Size (batch_size): The number of entities to include in a single batched query
# ===== Customizable Parameters =====

# Company Universe (from Watchlist)
my_watchlist_id = "37fe5403-9688-4313-9775-9fd9770ca6e2"
watchlist = bigdata.watchlists.get(my_watchlist_id)
companies = bigdata.knowledge_graph.get_entities(watchlist.items)

# LLM Specification
llm_model = "openai::gpt-4o-mini"

# Search Frequency
search_frequency='M'

# Specify Time Range
start_date="2025-01-01"
end_date="2025-04-20"

# Document Limits
document_limit_news=10
document_limit_filings=5
document_limit_transcripts=5

# Others
batch_size=1

Generate Report

We initialize the class GenerateReport and in the following section of the notebook, we will go through each step used by this class to generate the report. In the colab notebook you can skip the step-by-step process and directly run the generate_report() method in the section Direct Method.

report_generator = GenerateReport(
        watchlist_id=my_watchlist_id,
        keywords=['AI'],
        main_theme_risk='Risks or concerns related to AI disruption',
        main_theme_proactivity='Integrating GenAI into products or forming partnerships to improve GenAI offerings',
        list_sentences_risks=list_sentences_risks,
        list_sentences_proactivity=list_sentences_proactivity,
        llm_model= llm_model,
        api_key=OPENAI_API_KEY,
        start_date=start_date,
        end_date=end_date,
        search_frequency=search_frequency,
        document_limit_news=document_limit_news,
        document_limit_filings=document_limit_filings,
        document_limit_transcripts=document_limit_transcripts,
        batch_size=batch_size,
        bigdata=bigdata
)

Retrieve Content

You can leverage the Bigdata API to run a search on company news, filings and transcripts.

# Initialize empty lists to collect dataframes
df_risk_list = []
df_proactivity_list = []

# Define the document types and limits
doc_configs = [
   (DocumentType.NEWS, document_limit_news),
   (DocumentType.FILINGS, document_limit_filings),
   (DocumentType.TRANSCRIPTS, document_limit_transcripts)
]

# Iterate through each document type configuration
for doc_type, doc_limit in doc_configs:
   if doc_limit > 0:
       # Search for semantic risk sentences
       df_sentences_semantic_risk_search = search_by_companies(
           companies=companies,
           keywords=keywords,
           sentences=list_sentences_risks,
           start_date=start_date,
           end_date=end_date,
           scope=doc_type,
           freq=search_frequency,
           document_limit=doc_limit,
           batch_size=batch_size
       )
       df_risk_list.append(df_sentences_semantic_risk_search)

       # Search for semantic proactivity sentences
       df_sentences_semantic_proactivity_search = search_by_companies(
           companies=companies,
           keywords=keywords,
           sentences=list_sentences_proactivity,
           start_date=start_date,
           end_date=end_date,
           scope=doc_type,
           freq=search_frequency,
           document_limit=doc_limit,
           batch_size=batch_size
       )
       df_proactivity_list.append(df_sentences_semantic_proactivity_search)

# Combine all risk dataframes into a single dataset
df_sentences_semantic_risk = pd.concat(df_risk_list, ignore_index=True)

# Combine all proactivity dataframes into a single dataset
df_sentences_semantic_proactivity = pd.concat(df_proactivity_list, ignore_index=True)

Label the Results

Use an LLM to analyze each document chunk and determine its relevance to the main theme. Any document chunks which aren’t explicitly linked to AI Disruption Risk will be filtered out.

labeler = ScreenerLabeler(llm_model=llm_model)

df_risk_labels = labeler.get_labels(
                main_theme=main_theme_risk,
                labels=['risk'],
                texts=df_sentences_semantic_risk["masked_text"].tolist()
            )

# Merge the datasets
df_risk_labeled = pd.merge(df_sentences_semantic_risk, df_risk_labels, left_index=True, right_index=True)

df_proactivity_labels = labeler.get_labels(
                main_theme=main_theme_proactivity,
                labels=['proactivity'],
                texts=df_sentences_semantic_risk["masked_text"].tolist()
            )


# Merge the datasets
df_proactivity_labeled = pd.merge(df_sentences_semantic_proactivity, df_proactivity_labels, left_index=True, right_index=True)

# Process the results
df_risk_labeled_relevant = df_risk_labeled.loc[~df_risk_labeled.label.isin(['', 'unassigned', 'unclear'])].copy()
df_proactivity_labeled_relevant = df_proactivity_labeled.loc[~df_proactivity_labeled.label.isin(['', 'unassigned', 'unclear'])].copy()

Document Distribution Visualization

You can visualize the tables showing the count of different document types for each company in the given universe. This helps you understand the distribution and availability of information across different sources for each entity.

def create_styled_table(df, title, companies_list, entity_column='entity_name', document_column='document_type'):
    """
    Creates a styled table image showing unique document count by entity and document type

    Parameters:
    -----------
    df : pandas.DataFrame
        The dataframe containing entity and document type data
    title : str
        Title for the table
    companies_list : list
        List of all companies to include in the table (even if they have 0 counts)
    entity_column : str
        Name of the column containing entity names (default: 'entity_name')
    document_column : str
        Name of the column containing document types (default: 'document_type')

    Returns:
    --------
    pandas.DataFrame
        The pivot table with the data
    """
    import pandas as pd
    import matplotlib.pyplot as plt

    # Create pivot table counting unique document_ids
    pivot_table = df.groupby([entity_column, document_column])['document_id'].nunique().unstack(fill_value=0)

    # Ensure all companies from the list are included, even if they have 0 counts
    pivot_table = pivot_table.reindex(companies_list, fill_value=0)

    # Reset index to make it a normal table
    normal_table = pivot_table.reset_index()

    # Change the first column name to "company"
    normal_table.columns.values[0] = 'Company'

    # Create figure and axis
    fig, ax = plt.subplots(figsize=(12, 8))
    ax.axis('tight')
    ax.axis('off')

    # Create table
    table = ax.table(cellText=normal_table.values,
                     colLabels=normal_table.columns,
                     cellLoc='center',
                     loc='center')

    # Style the table
    table.auto_set_font_size(False)
    table.set_fontsize(10)
    table.scale(1.2, 2)

    # Style header row
    for i in range(len(normal_table.columns)):
        table[(0, i)].set_facecolor('#4CAF50')
        table[(0, i)].set_text_props(weight='bold', color='white')

    # Style data rows - alternate colors
    for i in range(1, len(normal_table) + 1):
        for j in range(len(normal_table.columns)):
            if i % 2 == 0:
                table[(i, j)].set_facecolor('#e0e0e0')
            else:
                table[(i, j)].set_facecolor('white')

    # Add title closer to the table
    plt.figtext(0.5, 0.9, title, fontsize=16, fontweight='bold', ha='center')

    plt.tight_layout()
    plt.show()

    return

Table for Documents about AI Disruption Risk

create_styled_table(df_risk_labeled_relevant, title='Relevant Document Count for AI Disruption Risk by Company and Document Type', companies_list = company_names)

Table for Documents about AI Disruption Proactivity

create_styled_table(df_proactivity_labeled_relevant, title='Relevant Document Count for AI Proactivity by Company and Document Type', companies_list = company_names)

Summarizer

The following code is used to create a summary for each company using the information from the retrieved documents.

summarizer_company = SummarizerCompany(
    model=llm_model.split('::')[1],
    api_key=OPENAI_API_KEY,
    logger= GenerateReport.logger,
    verbose=True
)
df_risk_by_company = asyncio.run(
            summarizer_company.process_by_company(
                df_labeled=df_risk_labeled_relevant,
                list_entities=companies,
                theme=main_theme_risk,
                focus='risk'
            ))

df_proactivity_by_company = asyncio.run(
            summarizer_company.process_by_company(
                df_labeled=df_proactivity_labeled_relevant,
                list_entities=companies,
                theme=main_theme_proactivity,
                focus=''
            )
        )

Getting the Scores

Processing the datasets and computing the AI Disruption Risk Score and AI Proactivity Score.

dfr = df_risk_by_company[['entity_id', 'entity_name', 'topic_summary', 'n_documents']].copy()
dfr = dfr.rename(columns={'topic_summary': 'risk_summary', 'n_documents': 'n_documents_risk'})
dfp = df_proactivity_by_company[['entity_id', 'entity_name', 'topic_summary', 'n_documents']].copy()
dfp = dfp.rename(columns={'topic_summary': 'proactivity_summary', 'n_documents': 'n_documents_proactivity'})
df_by_company = dfr.merge(dfp, on=['entity_id', 'entity_name'], how='outer')

df_by_company['n_documents_risk'] = df_by_company['n_documents_risk'].fillna(0)
df_by_company['n_documents_proactivity'] = df_by_company['n_documents_proactivity'].fillna(0)
df_by_company['ai_disruption_risk_score'] = df_by_company['n_documents_risk']/df_by_company['n_documents_risk'].mean()
df_by_company['ai_proactivity_score'] = df_by_company['n_documents_proactivity']/df_by_company['n_documents_proactivity'].mean()
df_by_company['ai_proactivity_minus_disruption_risk_score'] = df_by_company['ai_proactivity_score'] - df_by_company['ai_disruption_risk_score']

Final Dataset

The final dataset for the report is generated by processing and merging the risk and proactivity datasets.


df_quotes_risk = GenerateReport.aggregate_verbatim(df_risk_labeled_relevant, 'risk')
df_by_company = pd.merge(df_by_company, df_quotes_risk, how='left', on='entity_name')
df_quotes_proactivity = GenerateReport.aggregate_verbatim(df_proactivity_labeled_relevant, 'proactivity')
df_report = pd.merge(df_by_company, df_quotes_proactivity, how='left', on='entity_name')

Results Visualization

This is to visualize the values for each of the companies

def plot_company_scores(df, score_1, score_2, title):
    """
    Plots entity_name on a plane defined by score_1 and score_2.

    Parameters:
    df (pd.DataFrame): DataFrame containing score_1, score_2, and 'entity_name' columns.
    """
    # Create a figure and axis
    fig, ax = plt.subplots(figsize=(10, 8))

    # Scatter plot: each point represents a company
    ax.scatter(df[score_1], df[score_2], color='blue', alpha=0.6)

    # Add the company name as a label on each point
    for _, row in df.iterrows():
        ax.annotate(row['entity_name'],
                    (row[score_1], row[score_2]),
                    textcoords="offset points",  # Use offset to position text more cleanly
                    xytext=(5, 5),               # Offset: 5 points right and 5 points up
                    ha='left',                   # Horizontal alignment of text
                    fontsize=9)                  # Adjust font size as needed

    # Set plot labels and title
    ax.set_xlabel('AI Disruption Risk Score')
    ax.set_ylabel('AI Proactivity Score')
    ax.set_title(title)

    # Optionally, adjust grid or styling
    ax.grid(True)

    # Show the plot
    plt.show()

def plot_company_scores_log_log(df, score_1, score_2, title):
    """
    Plots entity_name on a plane defined by score_1 and score_2.

    Parameters:
    df (pd.DataFrame): DataFrame containing score_1, score_2, and 'entity_name' columns.
    """

    df_log = df.copy()
    df_log[score_1] = np.log(df_log[score_1].clip(lower=0.01))
    df_log[score_1] = df_log[score_1] + np.abs(df_log[score_1].min())
    df_log[score_2] = np.log(df_log[score_2].clip(lower=0.01))
    df_log[score_2] = df_log[score_2] + np.abs(df_log[score_2].min())

    plot_company_scores(df_log, score_1, score_2, title + ' - log-log scale')

AI Disruption Risk Score vs AI Proactivity Score

plot_company_scores_log_log(df_report, 'ai_disruption_risk_score', 'ai_proactivity_score', 'AI Narrative Signals')

AI Disruption Risk Score vs AI Proactivity Score - (Log-Log Scale)

plot_company_scores(df_report, 'ai_disruption_risk_score', 'ai_proactivity_score', 'AI Narrative Signals')

Generate Final Report

The following code provides an example on how the final report could be formatted.

def generate_html_report_v4(df, title, definitions, section_title):

    # Generate current report date.
    report_date = datetime.now().strftime("%B %d, %Y")

    def build_entity_section(df):
        """
        Build the HTML for each row in the dataframe.
        Expects each row to contain:
        - entity_name
        - risk_summary
        - proactivity_summary
        - ai_proactivity_minus_disruption_risk_score
        - ai_disruption_risk_score
        - ai_proactivity_score
        - n_documents_risk
        - n_documents_proactivity
        """
        sections = ""
        for _, record in df.iterrows():
            entity = record["entity_name"]
            risk_summary = record["risk_summary"] if pd.notnull(record["risk_summary"]) else "No relevant content was retrieved."
            proactivity_summary = record["proactivity_summary"] if pd.notnull(record["proactivity_summary"]) else "No relevant content was retrieved."

            ai_proactivity_minus_disruption_risk_score = f"{record['ai_proactivity_minus_disruption_risk_score']:.2f}" if pd.notnull(record["ai_proactivity_minus_disruption_risk_score"]) else "N/A"
            ai_disruption_risk_score = f"{record['ai_disruption_risk_score']:.2f}" if pd.notnull(record["ai_disruption_risk_score"]) else "N/A"
            ai_proactivity_score = f"{record['ai_proactivity_score']:.2f}" if pd.notnull(record["ai_proactivity_score"]) else "N/A"

            nb_documents_risk = f"{record['n_documents_risk']}" if pd.notnull(record["n_documents_risk"]) else "N/A"
            nb_documents_proactivity = f"{record['n_documents_proactivity']}" if pd.notnull(record["n_documents_proactivity"]) else "N/A"

            # Build header HTML: display the entity name.
            header_html = f"<h3>{entity}</h3>"

            # Build a dedicated score box with scores in three rows.
            score_box_html = f"""
                <div class="report-score-box">
                    <div class="score-row">
                        <p><strong>AI Proactivity Minus Disruption Risk Score:</strong> {ai_proactivity_minus_disruption_risk_score}</p>
                    </div>
                    <div class="score-row">
                    <p>
                        <strong>AI Disruption Risk Score:</strong> {ai_disruption_risk_score} /
                        <strong>Nb Documents Risk:</strong> {nb_documents_risk}
                    </p>
                </div>
                <div class="score-row">
                    <p>
                        <strong>AI Proactivity Score:</strong> {ai_proactivity_score} /
                        <strong>Nb Documents Proactivity:</strong> {nb_documents_proactivity}
                    </p>
                    </div>
                </div>
            """

            # Build the summary boxes (Risk Summary and Proactivity Summary) as before.
            summary_boxes = f"""
                <div class="report-flex-container">
                    <div class="report-criterion-box">
                        <h4>AI Disruption Risk</h4>
                        <p>{risk_summary}</p>
                    </div>
                    <div class="report-criterion-box">
                        <h4>AI Proactivity</h4>
                        <p>{proactivity_summary}</p>
                    </div>
                </div>
            """

            sections += "<div class='report-entity'>"
            sections += header_html
            sections += score_box_html
            sections += summary_boxes
            sections += "</div>"  # Close entity block
        return sections

    # Build company section using the provided df.
    company_section = build_entity_section(df)

    # Build definitions section by iterating over the dictionary.
    definitions_html = ""
    for score, definition in definitions.items():
        definitions_html += f"<p><strong>{score}</strong>: {definition}</p>"

    definitions_section = f"""
        <div class="report-section-box">
            <p class="report-section-title">Score Definitions</p>
            {definitions_html}
        </div>
    """

    html_report = f"""
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>{title}</title>
        <style>
            .report-container {{
                font-family: Arial, sans-serif;
                padding: 30px;
                background-color: #ffffff;
                color: #333;
            }}
            .report-container h1 {{
                color: #003A70;
                font-size: 24px;
                margin-bottom: 5px;
                font-weight: 700;
                text-align: center;
            }}
            .report-date {{
                font-size: 16px;
                color: #555;
                margin-bottom: 20px;
                text-align: center;
            }}
            .report-section-box {{
                border: 1px solid #003A70;
                padding: 15px;
                margin: 25px 0;
                border-radius: 8px;
                background: #FAFBFC;
            }}
            .report-section-title {{
                font-size: 22px;
                color: #003A70;
                margin: 0 0 15px 0;
                text-align: left;
            }}
            .report-entity {{
                border: 2px solid #003A70;
                margin: 15px 0;
                padding: 20px;
                border-radius: 8px;
                background: #F7F9FC;
            }}
            .report-score-box {{
                border: 1px solid #B0B0B0;
                padding: 10px;
                margin: 10px 0;
                background: #FFFFFF;
                border-radius: 5px;
            }}
            .score-row {{
                display: flex;
                gap: 10px;
                flex-wrap: wrap;
            }}
            .score-row p {{
                margin: 5px 0;
                font-size: 14px;
                color: #333;
            }}
            .entity-subheader {{
                font-size: 16px;
                font-weight: bold;
                color: grey;
                margin-top: -5px;
                margin-bottom: 20px;
            }}
            .report-flex-container {{
                display: flex;
                flex-wrap: wrap;
                gap: 15px;
                justify-content: space-between;
            }}
            .report-criterion-box {{
                flex: 1;
                min-width: 200px;
                padding: 15px;
                border: 1px solid #B0B0B0;
                border-radius: 5px;
                background: #FFFFFF;
            }}
            .report-criterion-box h4 {{
                margin-top: 0;
                color: #003A70;
            }}
            h3 {{
                margin-bottom: 5px;
                font-size: 20px;
                color: #003A70;
            }}
        </style>
    </head>
    <body>
        <div class="report-container">
            <h1>{title}</h1>
            <div class="report-date">{report_date}</div>

            {definitions_section}

            <div class="report-section-box">
                <p class="report-section-title">{section_title}</p>
                {company_section}
            </div>
        </div>
    </body>
    </html>
    """
    return html_report


def display_report(df_report, score, top, nb_entities, export_to_path=None):

    dict_definitions = {
            'AI Disruption Risk Score' : 'The number of unique documents related to the risk of GenAI disruption, normalized by the average number of risk documents retrieved across the entire watchlist.',
            'AI Proactivity Score' : 'The number of unique documents related to the proactive adoption of GenAI, normalized by the average number of proactivity documents retrieved across the entire watchlist.',
            'AI Proactivity Minus Disruption Risk Score' : "The difference between the AI Proactivity Score and the AI Disruption Risk Score. A higher score indicates a stronger company response relative to the identified risks.",
            }

    score_name_dict = {
            'ai_disruption_risk_score' : 'AI Disruption Risk Score',
            'ai_proactivity_score' : 'AI Proactivity Score',
            'ai_proactivity_minus_disruption_risk_score' : 'AI Proactivity Minus Disruption Risk Score',
    }

    if top == 'top':
        df = df_report.sort_values(by=[score], ascending=[False]).head(nb_entities).copy()
        section_title = 'Top ' + str(nb_entities) + ' Companies for ' + score_name_dict[score]
    elif top == 'bottom':
        df = df_report.sort_values(by=[score], ascending=[True]).head(nb_entities).copy()
        section_title = 'Bottom ' + str(nb_entities) + ' Companies for ' + score_name_dict[score]
    elif top == 'all':
        df = df_report.sort_values(by=['entity_name'], ascending=[True]).copy()
        section_title = ''
    df = df.reset_index(drop=True)

    html_content = generate_html_report_v4(df=df, title='AI Disruption Risk and Proactive Responses', definitions=dict_definitions, section_title=section_title)

    if export_to_path:
        # save the html report
        with open(export_to_path, 'w') as file:
            file.write(html_content)

    display(HTML(html_content))

display_report(df_report=df_report, score='ai_proactivity_minus_disruption_risk_score', top='top', nb_entities=5, export_to_path=output_dir+'/report_ai_disruption_top_5.html')

By looking at the top 3 companies with the highest AI Proactivity Minus Disruption Risk Score we get the following:

Score Definitions

AI Disruption Risk Score: The number of unique documents related to the risk of GenAI disruption, normalized by the average number of risk documents retrieved across the entire watchlist.

AI Proactivity Score: The number of unique documents related to the proactive adoption of GenAI, normalized by the average number of proactivity documents retrieved across the entire watchlist.

AI Proactivity Minus Disruption Risk Score: The difference between the AI Proactivity Score and the AI Disruption Risk Score. A higher score indicates a stronger company response relative to the identified risks.

1. Palantir Technologies Inc. 🥇

AI Proactivity Minus Disruption Risk Score: 0.72

AI Disruption Risk Score: 0.48 / Nb Documents Risk: 18

AI Proactivity Score: 1.19 / Nb Documents Proactivity: 45

AI Disruption Risk

Palantir Technologies Inc. faces significant risks related to AI disruption, particularly from emerging competitors like DeepSeek, which could undermine its market position and pricing model. The company’s reliance on government contracts exposes it to vulnerabilities from potential policy changes and defense spending cuts, which could impact its revenue stability. Additionally, the rapid commoditization of AI models and the increasing competition from larger tech firms threaten to erode Palantir’s competitive advantages, especially as AI infrastructure evolves. Investors are advised to remain cautious due to these competitive pressures and the high valuation of Palantir’s stock amidst these uncertainties.

AI Proactivity

Palantir Technologies Inc. has significantly advanced its integration of Generative AI (GenAI) through various strategic partnerships, including collaborations with EllisDon, SAUR, and TWG Global, aimed at enhancing operational efficiencies and transforming contract management processes. The company has also formed alliances with Databricks and Everfox to deliver secure AI solutions and improve military operations, respectively. Notably, Palantir’s AI services have driven substantial revenue growth, with a reported $1.8 billion in contracts and a 73% increase in its U.S. commercial customer base. These initiatives underscore Palantir’s commitment to leveraging AI across multiple sectors, including defense, healthcare, and financial services, positioning it as a leader in the AI landscape.

2. Advanced Micro Devices Inc. 🥈

AI Proactivity Minus Disruption Risk Score: 0.69

AI Disruption Risk Score: 0.45 / Nb Documents Risk: 17

AI Proactivity Score: 1.14 / Nb Documents Proactivity: 43

AI Disruption Risk

Advanced Micro Devices Inc. (AMD) faces significant risks related to AI disruption, including a decline in market share due to competition from Nvidia and emerging custom AI chip solutions from companies like Broadcom and Marvell. The company’s heavy investment in AI has not yielded expected returns, with recent reports indicating a 9.9% drop in shares following disappointing AI chip revenue and a forecasted 7% decrease in data center sales. Additionally, AMD is projected to incur an $800 million loss due to export restrictions on its AI chips, further complicating its financial outlook. Analysts have expressed concerns over AMD’s ability to sustain growth in the AI sector, leading to downgrades and reduced price targets amid a challenging market environment.

AI Proactivity

Advanced Micro Devices Inc. (AMD) has made significant strides in integrating Generative AI (GenAI) into its product offerings and forming strategic partnerships to enhance its AI capabilities. Notably, AMD’s collaboration with Absci, which includes a $20 million investment, aims to accelerate AI-driven drug discovery, leveraging AMD’s high-performance computing solutions. Additionally, AMD’s partnerships with companies like Dell and Ocient focus on enhancing AI capabilities in commercial devices and data analytics, respectively. Furthermore, AMD’s recent acquisition of ZT Systems is set to bolster its AI infrastructure, enabling faster deployment of AI solutions tailored for various customer needs.

3. Adobe Inc. 🥉

AI Proactivity Minus Disruption Risk Score: 0.61

AI Disruption Risk Score: 0.66 / Nb Documents Risk: 25

AI Proactivity Score: 1.27 / Nb Documents Proactivity: 48

AI Disruption Risk

Adobe Inc. faces significant risks related to AI disruption, particularly in monetizing its AI innovations like Firefly, which has shown user engagement but lacks clear revenue growth strategies. The company is under pressure from established competitors like Microsoft and Salesforce, which have stronger pricing power and bundled offerings, potentially limiting Adobe’s market share. Additionally, regulatory challenges and compliance costs associated with AI could hinder Adobe’s ability to adapt and innovate effectively, impacting its financial performance. Concerns about the rapid evolution of AI technologies and the competitive landscape further exacerbate the uncertainty surrounding Adobe’s future in the market.

AI Proactivity

Adobe Inc. is significantly enhancing its product offerings through the integration of generative AI (GenAI) technologies, particularly with its Firefly suite, which has been embedded across Creative, Document, and Experience Clouds to improve user productivity and streamline workflows. Partnerships with companies like IBM and Publicis Groupe are expanding Adobe’s capabilities in digital marketing and content creation, leveraging Firefly for personalized customer experiences and efficient content production. The launch of new AI-driven features, such as the Firefly Video Model and Acrobat AI Assistant, is expected to drive revenue growth and user engagement, with Adobe’s AI innovations already contributing to a substantial increase in annual recurring revenue. As of early 2025, Adobe’s strategic focus on GenAI is positioned to attract new users and enhance retention, further solidifying its market leadership in creative and marketing solutions.

Export the Results

Export the data as Excel files for further analysis or to share with the team.

try:
    # Create the Excel manager
    excel_manager = ExcelManager()

    # Define the dataframes and their sheet configurations
    df_args = [
        (df_report, "Report AI Disruption Risk", (2, 3))
    ]

    # Save the workbook
    excel_manager.save_workbook(df_args, export_path)

except Exception as e:
    print(f"Warning while exporting to excel: {e}")

Conclusion

The Report Generator provides a comprehensive automated framework for analyzing AI threats and opportunities across your investment universe. By systematically combining advanced information retrieval with LLM-powered analysis, this workflow transforms unstructured data from news, filings, and transcripts into actionable intelligence for strategic decision-making.

Through the automated analysis of AI disruption risks and proactive responses, you can:

  1. Identify AI-resilient leaders - Discover companies that are not only aware of AI disruption risks but are actively positioning themselves to capitalize on these changes through strategic partnerships and product integration

  2. Assess competitive positioning - Compare how companies within your watchlist are responding to AI transformation relative to their peers, highlighting potential winners and laggards

  3. Quantify risk-response balance - The AI Proactivity Minus Disruption Risk Score provides a clear metric to identify companies that demonstrate strong strategic responses relative to their exposure to AI-driven market disruption

  4. Monitor strategic evolution - Track how companies’ AI strategies and risk profiles evolve over time, enabling dynamic watchlist adjustments based on changing competitive landscapes

  5. Generate watchlist insights - Create comprehensive reports that can inform investment committees, risk management decisions, and thematic investment strategies

From conducting due diligence on AI exposure to building thematic watchlists focused on artificial intelligence or assessing watchlist-wide risks from technological disruption, the Report Generator automates the research process while maintaining the depth and nuance required for professional analysis. The standardized scoring methodology ensures consistent evaluation across companies and time periods, making it an invaluable tool for systematic AI impact assessment.