Article Analyzer with Hugging Face

Build an AI app that analyzes articles with local ML and cloud LLMs.

Introduction

30 Second Summary

You find a long article online and want to quickly know two things: what is the overall tone, and what are the key points. Reading the whole thing takes time, but AI can answer both questions in seconds.

In this project, you will build a web-based Article Analyzer that takes any block of text and provides instant AI-powered insights. You paste in an article, click a button, and get back both the emotional tone and a concise summary.

What You'll Build

Picture pasting a 500-word news article into a browser tab, clicking one button, and instantly seeing a confidence-scored sentiment label alongside a two-sentence summary generated by a large language model.

By the end of this project, you'll have:

  • A local sentiment analysis pipeline that instantly classifies any text as positive, negative, or neutral with a confidence score, powered by Hugging Face Transformers running entirely on your machine.
  • A cloud-powered summarization feature that produces concise, high-quality summaries of long articles using OpenRouter's free LLM tier.
  • A professional tabbed web interface built with Gradio that you can share with anyone via a public URL generated with one line of code.
  • Secret Mission: Add a combined "Full Analysis" mode that runs both sentiment and summarization in a single click and displays results side-by-side.

Are there any prerequisites?

You need Python installed on your machine and basic familiarity with running Python scripts and using virtual environments. You will also create a free OpenRouter account during setup. No prior experience with AI or machine learning is required.

Before We Start

You're about to build an Article Analyzer that uses AI to read any text you paste and return insights about it. The tool combines a local machine learning model for sentiment analysis with a cloud-powered LLM for summarization.

Before you can start writing code, you need a working development environment. This step gets your project folder, Python packages, and API access ready so you can jump straight into building.

In this step, get ready to:
  • Create a project folder with a Python virtual environment.
  • Install Hugging Face Transformers, Gradio, and OpenRouter packages.
  • Get a free OpenRouter API key for cloud AI access.
Create your project folder and virtual environment

Every Python project starts with an isolated environment. A virtual environment keeps this project's packages separate from your system Python, so nothing conflicts.

  • Press Cmd+Space (macOS) or the Windows key (Windows) to open your search bar.
  • Type Visual Studio Code and press Enter to open it.
  • Open a terminal inside VS Code by pressing Ctrl+` (backtick key, same shortcut on macOS and Windows).

Using IntelliJ IDEA instead?

All terminal commands in this project work the same way regardless of your editor. If you prefer IntelliJ IDEA, open it and use its built-in terminal (View > Tool Windows > Terminal).

  • Move to your Desktop by running this command:
cd ~/Desktop
  • Create your project folder and move into it by running these commands:
mkdir article-analyzer
cd article-analyzer
  • Create a Python virtual environment by running:
python -m venv venv
  • Confirm the venv folder was created by running:
ls

You should see a venv folder listed in the output.

  • Activate the virtual environment:

macOS

source venv/bin/activate

Your terminal prompt now shows (venv) at the beginning, confirming the environment is active.

Windows

venv\Scripts\activate

Your terminal prompt now shows (venv) at the beginning, confirming the environment is active.

Don't see (venv) in your prompt?

On Windows, you may need to allow script execution first. Run Set-ExecutionPolicy -Scope CurrentUser RemoteSigned in PowerShell, then try the activate command again.

On macOS or Linux, make sure you typed source before the path. Without it, the activate script won't modify your current shell session.

help me activate my Python virtual environment

  • Install the required packages by running:
pip install transformers==5.14.1 gradio==6.20.0 openrouter==1.0.18 torch

What are these packages?

  • transformers is Hugging Face's library for running pre-trained AI models locally on your machine.
  • gradio is a library that wraps Python functions in a web UI with just a few lines of code.
  • openrouter is the SDK for calling cloud LLMs through OpenRouter's unified API.
  • torch is PyTorch, the deep learning framework that powers the Transformers models under the hood.

This download takes a few minutes. You'll see progress bars and a final line reading Successfully installed... followed by the package names.

Seeing an installation error?

If you see errors mentioning Python version compatibility, confirm you're running Python 3.10 or higher by running python --version. Gradio requires Python 3.10 as a minimum.

If the command pip is not found, make sure your virtual environment is activated (you should see (venv) in your prompt).

help me fix my pip install error for this project

  • Create a requirements.txt file to document your dependencies. In VS Code, click File > New File, then save it as requirements.txt inside the article-analyzer folder.
  • Paste the following content into requirements.txt:
transformers==5.14.1
gradio==6.20.0
openrouter==1.0.18
torch

Why create requirements.txt?

This file documents exactly which packages your project needs. Anyone who clones your project can install everything with a single pip install -r requirements.txt command.

  • Save requirements.txt.
  • Confirm the file exists by running:
ls

You should see both venv and requirements.txt in the output.

Get a free OpenRouter API key

OpenRouter gives you access to powerful cloud LLMs through a single API. The free tier includes 50 requests per day, which is more than enough for this project.

  • Open your browser and go to https://openrouter.ai.
  • Click Sign Up and create a free account using your email or a social login.
  • Once signed in, navigate to https://openrouter.ai/keys to open your API keys page.
  • Click Create Key.
  • Copy the key that appears. It starts with sk-or-. Save it somewhere safe immediately because you cannot view it again after closing the dialog.

What is OpenRouter?

OpenRouter is a unified API that routes your requests to 400+ AI models from different providers. You get one API key, one base URL, and pick any model you want. For this project, you'll use a free Llama model for text summarization.

  • Back in VS Code, create a new file called .env inside your article-analyzer folder.
  • Paste the following into the file, replacing your-api-key-here with the key you just copied:
OPENROUTER_API_KEY=your-api-key-here

Why a .env file?

The .env file stores your API key outside your code. This keeps secrets out of version control and makes it easy to swap keys without editing source files.

When you run the app later, you'll export this value as an environment variable so Python can read it with os.getenv.

  • Save the .env file.
Verify the installation

Before moving on, confirm that all three core packages import correctly in Python.

  • Before you run the next command, what do you think will happen if one of the packages failed to install?
  • Verify your packages by running:
python -c "import transformers; import gradio; import openrouter; print('All packages installed!')"

You should see All packages installed! printed in your terminal. If any package failed to install, Python would throw an ImportError instead.

Seeing an ImportError?

Double-check that your virtual environment is still active (look for (venv) in your prompt). If it deactivated, run the activate command from earlier and try again.

If a specific package is missing, re-run the pip install command for just that package. For example: pip install gradio==6.20.0.

help me fix my ImportError when verifying my packages

✔️ Awesome, I've got everything!

Great. Double check that you've saved both requirements.txt and .env in your article-analyzer folder.

ⓧ I'd like to double check the full code

Your requirements.txt should contain:

transformers==5.14.1
gradio==6.20.0
openrouter==1.0.18
torch

Your .env should contain:

OPENROUTER_API_KEY=your-api-key-here

Replace your-api-key-here with the actual key you copied from your OpenRouter dashboard.

Your environment is ready and every package is importable. Next up, you'll use Hugging Face Transformers to build a sentiment analysis feature that runs entirely on your machine.

Build Sentiment Analysis with Hugging Face

Your environment is set up and every package is installed. Now it's time to write your first piece of AI-powered code.

Before reaching for cloud APIs, you'll start with what can run entirely on your machine. Hugging Face Transformers includes pre-trained models that perform production-quality sentiment analysis with zero API keys and zero cost.

In this step, get ready to:
  • Load a pre-trained sentiment analysis model from Hugging Face.
  • Build a function that takes text and returns its emotional tone with a confidence score.
  • Run the analyzer on a sample article and see the result.
Create app.py and build the sentiment analyzer

The pipeline function from Hugging Face Transformers handles model loading, tokenization, and inference in one call. You give it a task name and it downloads the right model automatically.

  • In your editor, create a new file called app.py inside your article-analyzer folder.
  • Paste the following code into app.py:
from transformers import pipeline

# Initialize Hugging Face sentiment pipeline
sentiment_analyzer = pipeline("sentiment-analysis")


def analyze_sentiment(text):
    """Analyze sentiment using local Hugging Face model."""
    if not text.strip():
        return "Please enter some text to analyze."
    result = sentiment_analyzer(text[:512])[0]
    label = result["label"]
    score = result["score"]
    return f"Sentiment: {label}\nConfidence: {score:.2%}"


# Test
if __name__ == "__main__":
    sample = "The new policy has brought tremendous improvements to the community."
    print(analyze_sentiment(sample))

What does this code do?

pipeline("sentiment-analysis") loads a pre-trained DistilBERT model that classifies text as POSITIVE or NEGATIVE. On first run, it downloads and caches the model (~260MB) from the Hugging Face Hub.

text[:512] truncates the input to 512 characters because the model has a fixed token limit. The if __name__ block runs a quick test only when you execute the file directly.

First run takes a minute

The very first time you run this script, Hugging Face downloads the pre-trained model from its servers. This takes about a minute depending on your connection. Subsequent runs load from cache and start instantly.

  • Save app.py.

Before you run this, what do you think the output will look like? A single word, a full sentence, or something else entirely?

  • Run the script in your terminal:
python app.py

You should see output like this:

Sentiment: POSITIVE
Confidence: 99.54%

The model identified the sample text as positive with high confidence. Your exact confidence percentage may differ slightly, but the label should be POSITIVE.

Seeing an error instead of a sentiment result?

  • If you see ModuleNotFoundError: No module named 'transformers', your virtual environment is not active. Run venv\Scripts\activate (Windows) or source venv/bin/activate (macOS/Linux) and try again.
  • If the download seems stuck or you see a network error, check your internet connection. The model needs to download once from Hugging Face's servers.
  • If you see a RuntimeError related to torch, confirm that torch is installed by running pip list | grep torch.

Why is my sentiment analysis script failing?

✔️ Awesome, I've got everything!

Great. Double check you've saved app.py and move on to the next step.

ⓧ I'd like to double check the full code

Here is the complete app.py at this point:

from transformers import pipeline

# Initialize Hugging Face sentiment pipeline
sentiment_analyzer = pipeline("sentiment-analysis")


def analyze_sentiment(text):
    """Analyze sentiment using local Hugging Face model."""
    if not text.strip():
        return "Please enter some text to analyze."
    result = sentiment_analyzer(text[:512])[0]
    label = result["label"]
    score = result["score"]
    return f"Sentiment: {label}\nConfidence: {score:.2%}"


# Test
if __name__ == "__main__":
    sample = "The new policy has brought tremendous improvements to the community."
    print(analyze_sentiment(sample))

Your sentiment analyzer works locally with zero API calls. Next up, you'll try local summarization and discover why it falls short for longer articles.

Attempt Local Summarization

In the last step, you proved that local AI can handle sentiment analysis with speed and accuracy. Now let's push further and ask the same local approach to do something harder: summarize an entire article.

Summarization is a generative task. Instead of picking a label from a short list, the model has to produce entirely new sentences that capture the meaning of a longer piece of text. Let's see how the local Hugging Face pipeline handles it.

In this step, get ready to:
  • Add a local summarization pipeline to your app.
  • Test both sentiment and summarization on a long article.
  • Observe the quality gap between classification and generation tasks.
Add a local summarization pipeline

Just like you created a sentiment pipeline with one line, you can create a summarization pipeline the same way. The Transformers library downloads a pretrained summarization model automatically on first run.

  • In app.py, find this comment near the top of the file:
# Initialize Hugging Face sentiment pipeline
  • Update it to say pipelines (plural), so the line now looks like this:
# Initialize Hugging Face pipelines
  • Directly below the sentiment_analyzer line, add the summarization pipeline by pasting this code:
summarizer = pipeline("summarization")
  • Below your analyze_sentiment function, add the function that uses this pipeline by pasting the following:
def summarize_local(text):
    """Summarize text using local Hugging Face model."""
    if not text.strip():
        return "Please enter some text to summarize."
    result = summarizer(text, max_length=130, min_length=30)[0]
    return result["summary_text"]

What does this code do?

The summarize_local function takes a block of text and feeds it to the local summarization model.

  • max_length=130 caps the summary at 130 tokens so it stays concise.
  • min_length=30 prevents the model from returning a single-sentence summary that's too short to be useful.
  • The [0] grabs the first (and only) result from the pipeline's output list.
  • Save app.py.

Seeing a syntax error?

Make sure the summarize_local function is placed after the closing line of analyze_sentiment, not inside it. Both functions should be at the same indentation level (no indentation).

Help me debug my summarize_local function

Test with a long article

To really test summarization, you need a longer piece of text. A single sentence won't reveal whether the model can actually condense complex ideas.

  • In app.py, find the test block at the bottom of the file:
# Test
if __name__ == "__main__":
    sample = "The new policy has brought tremendous improvements to the community."
    print(analyze_sentiment(sample))
  • Replace the entire test block with the following code, which uses a multi-paragraph article and runs both analyses:
# Test
if __name__ == "__main__":
    long_article = """Artificial intelligence is transforming industries worldwide. From healthcare to finance, organizations are deploying machine learning models to automate tasks, improve decision-making, and uncover insights from vast datasets. In healthcare, AI systems can now detect certain cancers from medical images with accuracy rivaling experienced radiologists. Financial institutions use AI to detect fraud in real time, saving billions of dollars annually. The transportation sector is being reshaped by autonomous vehicles that rely on deep learning to navigate complex environments. Meanwhile, natural language processing breakthroughs have enabled virtual assistants and translation tools that were unimaginable a decade ago. Despite these advances, challenges remain around data privacy, algorithmic bias, and the displacement of workers in certain sectors. Policymakers, researchers, and industry leaders are working to establish frameworks that ensure AI development proceeds responsibly and equitably."""
    print(analyze_sentiment(long_article))
    print(summarize_local(long_article))

What does this test do?

This test feeds a roughly 150-word article about AI into both your sentiment analyzer and your local summarizer. You'll see two outputs printed: the sentiment label with a confidence score, and a summary of the article.

  • Save app.py.

Before you run this, what do you think the summary will look like? Do you expect it to capture all the key points from the article?

  • Run your script by entering this command:
python app.py

What should I see?

The first time you run this, the summarization model downloads automatically (this may take a minute). Once it finishes, you'll see two outputs.

The sentiment result prints a clear label (likely POSITIVE) with a high confidence score. That part works well.

The summary, however, is noticeably choppy, repetitive, or only covers part of the article. The local model is a compact, distilled version designed to be fast and small, not to produce high-quality summaries of dense text.

This is the gap. Sentiment analysis (picking one label from a list) is a classification task that small local models handle easily. Summarization (generating new coherent text) is a generative task that benefits enormously from larger, more powerful models.

Model download seems stuck?

The summarization model can be over 1GB. On slower connections this can take several minutes. Let it finish downloading before rerunning.

If you see a connection error, check your internet connection and try again. The model only downloads once and is cached locally for future runs.

Help me troubleshoot model downloads

✔️ Awesome, I've got everything!

Great. Double check you've saved app.py and confirmed both outputs print when you run it.

ⓧ I'd like to double check the full code

Here is the complete app.py at this point. Confirm your file matches:

from transformers import pipeline

# Initialize Hugging Face pipelines
sentiment_analyzer = pipeline("sentiment-analysis")
summarizer = pipeline("summarization")


def analyze_sentiment(text):
    """Analyze sentiment using local Hugging Face model."""
    if not text.strip():
        return "Please enter some text to analyze."
    result = sentiment_analyzer(text[:512])[0]
    label = result["label"]
    score = result["score"]
    return f"Sentiment: {label}\nConfidence: {score:.2%}"


def summarize_local(text):
    """Summarize text using local Hugging Face model."""
    if not text.strip():
        return "Please enter some text to summarize."
    result = summarizer(text, max_length=130, min_length=30)[0]
    return result["summary_text"]


# Test
if __name__ == "__main__":
    long_article = """Artificial intelligence is transforming industries worldwide. From healthcare to finance, organizations are deploying machine learning models to automate tasks, improve decision-making, and uncover insights from vast datasets. In healthcare, AI systems can now detect certain cancers from medical images with accuracy rivaling experienced radiologists. Financial institutions use AI to detect fraud in real time, saving billions of dollars annually. The transportation sector is being reshaped by autonomous vehicles that rely on deep learning to navigate complex environments. Meanwhile, natural language processing breakthroughs have enabled virtual assistants and translation tools that were unimaginable a decade ago. Despite these advances, challenges remain around data privacy, algorithmic bias, and the displacement of workers in certain sectors. Policymakers, researchers, and industry leaders are working to establish frameworks that ensure AI development proceeds responsibly and equitably."""
    print(analyze_sentiment(long_article))
    print(summarize_local(long_article))

You've now seen local AI at both its best and its limits. Sentiment analysis runs instantly and accurately. Summarization produces something, but the quality gap is obvious. In the next step, you'll plug in a powerful cloud LLM through OpenRouter and see the difference a large model makes.

Upgrade Summarization with OpenRouter

In the last step, you saw the local summarization pipeline struggle with longer articles. The output was choppy, incomplete, or overly generic.

That gap is exactly what cloud LLMs solve. OpenRouter gives you free access to powerful models like Llama 3.3 70B through a single Python SDK. In this step, you will swap in a cloud-powered summarizer and see the quality jump firsthand.

In this step, get ready to:
  • Import and configure the OpenRouter client with your API key.
  • Write a new summarization function that calls a free LLM.
  • Compare local and cloud summaries side-by-side.
Import and configure the OpenRouter client

Your script currently imports only transformers. To call OpenRouter, you need the SDK imported and your API key loaded from the environment.

  • In app.py, find the import line at the top of the file:
from transformers import pipeline
  • Replace it with the following imports and configuration block:
import os
from transformers import pipeline
from openrouter import OpenRouter

# Load environment variable
OPENROUTER_API_KEY = os.getenv("OPENROUTER_API_KEY", "")

What does this code do?

  • import os gives access to environment variables stored in your terminal session.
  • from openrouter import OpenRouter brings in the SDK client you will use to call cloud LLMs.
  • os.getenv("OPENROUTER_API_KEY", "") reads your API key from the system environment. The empty string fallback lets the app start even without a key set. It will show a helpful error message instead of crashing.
  • Save app.py.
Write the summarization function

Now you will write the function that sends article text to a free Llama 3.3 70B model and gets back a concise summary.

  • In app.py, add this function below your existing summarize_local function:
def summarize_with_llm(text):
    """Summarize text using OpenRouter free LLM."""
    if not text.strip():
        return "Please enter some text to summarize."
    if not OPENROUTER_API_KEY:
        return "Error: OPENROUTER_API_KEY not set. Please add it to your .env file."

    with OpenRouter(api_key=OPENROUTER_API_KEY) as client:
        response = client.chat.send(
            model="meta-llama/llama-3.3-70b-instruct:free",
            messages=[
                {
                    "role": "system",
                    "content": "You are a helpful assistant. Summarize the following text concisely in 2-3 sentences.",
                },
                {"role": "user", "content": text},
            ],
            stream=False,
        )
    return response.choices[0].message.content

What does this code do?

  • The function first checks for empty text and a missing API key, returning clear error messages instead of crashing.
  • with OpenRouter(api_key=...) as client: creates a managed connection to the OpenRouter API. The context manager ensures the connection is cleaned up afterwards.
  • The system message tells the LLM how to behave (summarize concisely). The user message contains the actual article text.
  • model="meta-llama/llama-3.3-70b-instruct:free" targets a powerful 70-billion parameter model at zero cost. The :free suffix tells OpenRouter to use the free tier.
  • response.choices[0].message.content extracts the generated summary text from the API response.

Why cloud LLMs for summarization?

Classification tasks like sentiment analysis work great with small local models because they only need to pick a label. Generative tasks like summarization require the model to compose fluent, coherent prose from scratch. That demands billions of parameters and massive training data that only large cloud-hosted models provide.

This local-for-classification, cloud-for-generation split is a common real-world pattern. You get speed and zero cost where a small model suffices, and reach for cloud power only where you need it.

Compare the two summaries

Time to see the difference. You will update the test code to print both summaries side-by-side with clear labels.

  • In app.py, scroll down to the if __name__ == "__main__": block and find these two lines at the bottom:
    print(analyze_sentiment(long_article))
    print(summarize_local(long_article))
  • Replace those two lines with the following, which prints both summaries with clear headers:
    print("--- LOCAL SUMMARY ---")
    print(summarize_local(long_article))
    print("--- LLM SUMMARY ---")
    print(summarize_with_llm(long_article))
  • Save app.py.

Before you can run the script, your terminal session needs your API key available as an environment variable.

  • Export your OpenRouter API key in the terminal by running this command:

macOS

export OPENROUTER_API_KEY=your-api-key-here

Windows

set OPENROUTER_API_KEY=your-api-key-here
  • Replace your-api-key-here with the actual API key you saved in your .env file earlier.

Before you run this, what do you expect the LLM summary to look like compared to the local one?

  • Run the script by running this command:
python app.py

You will see two summaries printed. The local summary under --- LOCAL SUMMARY --- is the same choppy output from before. The LLM summary under --- LLM SUMMARY --- is dramatically more coherent, complete, and readable.

Seeing an error about OPENROUTER_API_KEY?

  • If you see the message Error: OPENROUTER_API_KEY not set, your environment variable was not exported correctly. Run the export command again and make sure there are no spaces around the = sign.
  • If you get a network error or authentication failure, double-check that you copied the full API key from your OpenRouter dashboard with no trailing spaces.
  • On Windows, use set (not export). On macOS/Linux, use export.

Help me debug my OpenRouter summarization function

✔️ Awesome, I've got everything!

Great. Double check you have saved app.py and that both summaries printed successfully.

ⓧ I'd like to double check the full code

Your app.py is now over 30 lines. Confirm these sections are present in order:

  • Imports (os, pipeline, OpenRouter) and OPENROUTER_API_KEY loaded from environment.
  • Hugging Face pipelines initialized (sentiment_analyzer and summarizer).
  • analyze_sentiment(text) function.
  • summarize_local(text) function.
  • summarize_with_llm(text) function using OpenRouter.
  • Test block printing both local and LLM summaries with --- LOCAL SUMMARY --- and --- LLM SUMMARY --- headers.

Scroll up and confirm each section is present in your file, in order.

Your local model still handles sentiment perfectly. Now you have a cloud-powered LLM filling the gap where local models fall short. Next up, you will wrap both of these features in a professional web interface that anyone can use.

Build the Gradio Web Interface

You now have two powerful AI tools working from the command line: local sentiment analysis and cloud-powered summarization.

A terminal script is useful for testing, but nobody else can use it. Gradio lets you wrap your Python functions in a professional web interface that anyone can access from their browser.

In this step, get ready to:
  • Replace the test script with a Gradio web interface.
  • Create a tabbed layout with Summarize and Sentiment Analysis tabs.
  • Launch the app with a shareable public URL.
Import Gradio and create a Blocks layout with tabs

Before adding the UI code, you need to clean up the file. The local summarizer served its purpose as a comparison tool, but the LLM version is clearly better. You will remove the local summarization code and the test block, then replace them with the Gradio interface.

  • In app.py, find and delete the following line near the top:
summarizer = pipeline("summarization")
  • Update the comment above sentiment_analyzer from # Initialize Hugging Face pipelines to:
# Initialize Hugging Face sentiment pipeline
  • Delete the entire summarize_local function (the def summarize_local(text): block and its body).
  • Delete the entire if __name__ == "__main__": test block at the bottom of the file (everything from that line to the end).
  • Add import gradio as gr as the second import line, right after import os.

Your file now has the imports, the analyze_sentiment function, and the summarize_with_llm function. The bottom of the file is empty, ready for the Gradio interface.

  • Add the Gradio Blocks layout with the Summarize tab by pasting the following code at the bottom of app.py:
# Build Gradio interface
with gr.Blocks() as demo:
    gr.Markdown("# Article Analyzer\nPaste any article to get AI-powered sentiment analysis and summarization.")

    with gr.Tab("Summarize"):
        summary_input = gr.Textbox(
            label="Article Text",
            placeholder="Paste your article here...",
            lines=8,
        )
        summary_button = gr.Button("Summarize")
        summary_output = gr.Textbox(label="Summary", lines=4)
        summary_button.click(
            fn=summarize_with_llm, inputs=summary_input, outputs=summary_output
        )

What does this code do?

  • gr.Blocks() creates a flexible layout container. Everything inside the with block becomes part of the web page.
  • gr.Markdown() renders a title header at the top of the app.
  • gr.Tab("Summarize") creates a named tab. All components defined inside it appear only when that tab is active.
  • summary_button.click() wires the button to your summarize_with_llm function. When clicked, Gradio passes the input textbox value to the function and displays the return value in the output textbox.
Wire up the Sentiment Analysis tab

The second tab follows the same pattern but connects to your local sentiment analysis function instead.

  • Add the Sentiment Analysis tab and the launch command directly below the Summarize tab code (still inside the with gr.Blocks() as demo: block):
    with gr.Tab("Sentiment Analysis"):
        sentiment_input = gr.Textbox(
            label="Article Text",
            placeholder="Paste your article here...",
            lines=8,
        )
        sentiment_button = gr.Button("Analyze Sentiment")
        sentiment_output = gr.Textbox(label="Sentiment Result", lines=2)
        sentiment_button.click(
            fn=analyze_sentiment, inputs=sentiment_input, outputs=sentiment_output
        )

demo.launch(share=True)

What does this code do?

  • The Sentiment Analysis tab uses the same component pattern: a Textbox for input, a Button to trigger, and a Textbox for output.
  • sentiment_button.click() connects the button to analyze_sentiment, which runs entirely on your machine with no API call needed.
  • demo.launch(share=True) starts a local web server on port 7860 and creates a public URL that tunnels to your local app. Anyone with the link can try it.
  • Save app.py.

✔️ Awesome, I've got everything!

Great. Make sure you have saved app.py before continuing.

ⓧ I'd like to double check the full code

Scroll through your app.py and confirm these sections are present in order:

  • Four import lines at the top: os, gradio as gr, pipeline from transformers, OpenRouter from openrouter.
  • OPENROUTER_API_KEY loaded with os.getenv.
  • The sentiment_analyzer pipeline (no summarizer pipeline).
  • The analyze_sentiment function.
  • The summarize_with_llm function.
  • The # Build Gradio interface section with two tabs (Summarize and Sentiment Analysis).
  • demo.launch(share=True) as the very last line.
Launch with a public share link

Your app is ready to go live. Before you run it, think about what you expect to happen.

  • Before running the app, predict: do you think Gradio will print just a local URL, or something else?
  • Make sure your OPENROUTER_API_KEY environment variable is set in your terminal. On macOS/Linux, run:
export OPENROUTER_API_KEY=your-api-key-here
  • On Windows, run:
set OPENROUTER_API_KEY=your-api-key-here
  • Launch the app by running:
python app.py

You will see Gradio print both a local URL (http://localhost:7860) and a public share link (something like https://xxxxx.gradio.live). That public link means anyone on the internet can reach your app right now.

  • Open http://localhost:7860 in your browser.
  • You should see a tabbed interface with a title that reads "Article Analyzer" and two tabs: Summarize and Sentiment Analysis.
  • Click the Summarize tab, paste any paragraph of text into the input box, and click the Summarize button.
  • Confirm the output box fills with a concise LLM-generated summary.
  • Switch to the Sentiment Analysis tab, paste text, and click Analyze Sentiment.
  • Confirm you see a sentiment label (POSITIVE or NEGATIVE) with a confidence percentage.

Why two URLs?

The local URL (localhost:7860) only works on your machine. The gradio.live URL tunnels internet traffic to your local server so anyone else can use your app. Share links expire after 72 hours.

App not loading or buttons not responding?

  • If you see an import error for gradio, make sure your virtual environment is activated and you installed gradio==6.20.0.
  • If the Summarize button returns an error about OPENROUTER_API_KEY, make sure you exported the variable in the same terminal session before running python app.py.
  • If you do not see a public URL, your network may block outbound tunneling. The local URL still works for testing on your own machine.

Help me debug my Gradio app

Your Article Analyzer is live. You now have a professional web interface backed by both local ML and cloud AI, accessible to anyone with the share link. Next up, you will tackle a Secret Mission that combines both analysis modes into a single click.

Secret mission

Add a Full Analysis Mode

Your app can analyze sentiment and summarize separately. But what if a user wants both at once? Add a third tab that runs both pipelines in a single click and displays the results together.

Clean Up Your Resources

Clean Up Your Resources

Decide whether to keep your resources running, pause them to come back later, or delete them entirely. This project runs entirely locally and uses OpenRouter's free tier, so there are no ongoing costs.

Resources you used:

  • The article-analyzer project folder on your Desktop (contains app.py, .env, requirements.txt, and the venv virtual environment).
  • Hugging Face model cache stored at ~/.cache/huggingface/hub (macOS/Linux) or C:\Users\username\.cache\huggingface\hub (Windows).
  • Your OpenRouter API key (created on the OpenRouter dashboard).

Keep everything running

No action needed. Choose this if you plan to keep experimenting with your Article Analyzer or want to add more features.

  • Your project folder stays on your Desktop, ready to run anytime with python app.py.
  • The cached Hugging Face model stays on disk so future runs load instantly without re-downloading.
  • Your OpenRouter API key remains active for up to 50 free requests per day.

Pause - I'll come back to this later

Stop the running Gradio server to free up your terminal. Your files and API key stay intact for next time.

  • Press Ctrl+C in the terminal where app.py is running to stop the Gradio server.
  • Deactivate your virtual environment by running:
deactivate
  • When you return, navigate to your article-analyzer folder, reactivate the virtual environment, and run python app.py again.

Delete - I don't want to use this again

Remove all project files, cached models, and revoke your API key to start completely fresh.

  • Press Ctrl+C to stop the Gradio server if it is still running.
  • Deactivate your virtual environment by running:
deactivate
  • Delete the project folder by running:

macOS

rm -rf ~/Desktop/article-analyzer

Windows

rmdir /s /q %USERPROFILE%\Desktop\article-analyzer
  • Delete the cached Hugging Face models to free up disk space:

macOS

rm -rf ~/.cache/huggingface/hub

Windows

rmdir /s /q %USERPROFILE%\.cache\huggingface\hub
  • Revoke your OpenRouter API key by visiting your key settings page at https://openrouter.ai/settings/keys.
  • Find the key you created for this project and click the delete button next to it.

Nice Work!

Nice Work!

You just built and deployed a full AI-powered Article Analyzer that combines local machine learning with cloud LLM APIs behind a professional web interface.

You've learned how to:

  • Run sentiment analysis locally using a Hugging Face Transformers pipeline, with zero API cost and instant results.
  • Integrate OpenRouter's free LLM API for high-quality text summarization, proving the real-world pattern of using cloud models where local ones fall short.
  • Build a tabbed web interface with Gradio and deploy it with a public shareable URL in one line of code.
  • Secret Mission: Combined multiple AI backends into a single unified Full Analysis workflow that runs sentiment and summarization in one click.

Ready to quiz yourself?