Added new folders and files in muhammad_qasim_sheikh directory

This commit is contained in:
aashahid
2025-10-22 17:46:05 +05:00
parent 0b4e4be9a0
commit 2549f89d1e
16 changed files with 581 additions and 1284 deletions

View File

@@ -1,50 +0,0 @@
# **Automated Bitcoin Daily Summary Generator**
This project automates the process of generating a daily summary of the Bitcoin network's status. It fetches real-time data from multiple public API endpoints, processes it, and then uses a Large Language Model (LLM) to generate a clear, structured, and human-readable report in Markdown format.
## **Project Overview**
The core goal of this project is to provide a snapshot of key Bitcoin metrics without manual analysis. By leveraging the Braiins Public API for data and OpenAI's GPT models for summarization, it can produce insightful daily reports covering market trends, network health, miner revenue, and future outlooks like the next halving event.
### **Key Features**
- **Automated Data Fetching**: Pulls data from 7 different Braiins API endpoints covering price, hashrate, difficulty, transaction fees, and more.
- **Data Cleaning**: Pre-processes the raw JSON data to make it clean and suitable for the LLM.
- **Intelligent Summarization**: Uses an advanced LLM to analyze the data and generate a structured report with explanations for technical terms.
- **Dynamic Dating**: The report is always dated for the day it is run, providing a timely summary regardless of the timestamps in the source data.
- **Markdown Output**: Generates a clean, well-formatted Markdown file that is easy to read or integrate into other systems.
## **How It Works**
The project is split into two main files:
1. **utils.py**: A utility script responsible for all data fetching and cleaning operations.
- It defines the Braiins API endpoints to be queried.
- It contains functions to handle HTTP requests, parse JSON responses, and clean up keys and values to ensure consistency.
2. **day_1_bitcoin_daily_brief.ipynb**: A Jupyter Notebook that acts as the main orchestrator.
- It imports the necessary functions from utils.py.
- It calls fetch_clean_data() to get the latest Bitcoin network data.
- It constructs a detailed system and user prompt for the LLM, explicitly instructing it on the desired format and, crucially, to use the current date for the summary.
- It sends the data and prompt to the OpenAI API.
- It receives the generated summary and displays it as formatted Markdown.
## **Setup and Usage**
To run this project, you will need to have Python and the required libraries installed.
### **1\. Prerequisites**
- Python 3.x
- Jupyter Notebook or JupyterLab
### **2\. Installation**
- Install the necessary Python libraries: pip install requests openai python-dotenv jupyter
### **3\. Configuration**
You need an API key from OpenAI to use the summarization feature.
1. Create a file named .env in the root directory of the project.
2. Add your OpenAI API key to the .env file as follows:
OPENAI_API_KEY='your_openai_api_key_here'

View File

@@ -1,156 +0,0 @@
{
"cells": [
{
"cell_type": "markdown",
"id": "abaef96b",
"metadata": {},
"source": [
"## Importing The Libraries"
]
},
{
"cell_type": "code",
"execution_count": 1,
"id": "f90c541b",
"metadata": {},
"outputs": [],
"source": [
"import os\n",
"import datetime\n",
"from utils import fetch_clean_data\n",
"from openai import OpenAI\n",
"from IPython.display import Markdown, display\n",
"from dotenv import load_dotenv\n",
"import json"
]
},
{
"cell_type": "markdown",
"id": "6e6c864b",
"metadata": {},
"source": [
"## Configuration"
]
},
{
"cell_type": "code",
"execution_count": 2,
"id": "be62299d",
"metadata": {},
"outputs": [],
"source": [
"load_dotenv(override=True)\n",
"api_key = os.getenv('OPENAI_API_KEY')\n",
"\n",
"client = OpenAI()"
]
},
{
"cell_type": "code",
"execution_count": 3,
"id": "3aa8e3e2",
"metadata": {},
"outputs": [],
"source": [
"def generate_markdown_summary(data: dict, today_date_str: str) -> str:\n",
" \"\"\"\n",
" Send cleaned Bitcoin data to an LLM and receive a Markdown summary.\n",
" \"\"\"\n",
"\n",
" system_prompt = f\"\"\"\n",
" You are a professional crypto analyst. Your job is to read the provided Bitcoin network data \n",
" and write a clear, structured report that can be read directly as a daily summary.\n",
"\n",
" Following are the rules that you must adhere to:\n",
" - **IMPORTANT**: The summary title MUST use today's date: {today_date_str}. The title must be: \"Bitcoin Daily Summary - {today_date_str}\".\n",
" - **CRITICAL**: Do NOT infer the reporting period from the data. The data contains historical records, but your report is for {today_date_str}.\n",
" - Include **headings** for sections like \"Market Overview\", \"Network Metrics Explained\", \"Miner Revenue Trends\", and \"Halving Outlook\".\n",
" - Use **bullet points** for key metrics.\n",
" - Use a **table** for historical or time-series data if available.\n",
" - Explain important terms (like hashrate, difficulty, transaction fees) in plain language.\n",
"\n",
" Respond in markdown. Do not wrap the markdown in a code block - respond just with the markdown.\n",
" \"\"\"\n",
"\n",
" # Convert the Python data dictionary into a clean JSON string for the prompt\n",
" data_str = json.dumps(data, indent=2)\n",
"\n",
" user_prompt = f\"\"\"\n",
" Today's date is {today_date_str}. Use this as the reference point for the report.\n",
"\n",
" The following data may contain historical records (e.g., from 2024), \n",
" but you must treat it as background context and write the summary as of {today_date_str}.\n",
"\n",
" Here is the data for you to summarize: \n",
" {data_str}\n",
" \"\"\"\n",
" \n",
" response = client.chat.completions.create(\n",
" model= \"gpt-4.1-mini\", \n",
" messages=[\n",
" {\"role\": \"system\", \"content\": system_prompt},\n",
" {\"role\": \"user\", \"content\": user_prompt}\n",
" ]\n",
" )\n",
"\n",
" markdown_text = response.choices[0].message.content.strip()\n",
" return markdown_text"
]
},
{
"cell_type": "markdown",
"id": "1e8c2d7d",
"metadata": {},
"source": [
"## Main Function"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "05059ed9",
"metadata": {},
"outputs": [],
"source": [
"def main():\n",
" # 0. Get today's date as a string\n",
" today_str = datetime.datetime.now().strftime('%B %d, %Y')\n",
" \n",
" # 1. Fetch and clean data\n",
" print(\"Fetching Bitcoin data...\")\n",
" data = fetch_clean_data()\n",
"\n",
" # 2. Generate Markdown summary\n",
" print(\"Generating LLM summary...\")\n",
" markdown_report = generate_markdown_summary(data, today_str)\n",
"\n",
" # 3. Display Output\n",
" display(Markdown(markdown_report))\n",
"\n",
"if __name__ == \"__main__\":\n",
" main()"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "llm-engineering",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.12.12"
}
},
"nbformat": 4,
"nbformat_minor": 5
}

View File

@@ -1,121 +0,0 @@
# utils.py
import requests
import re
import datetime
import logging
from typing import Dict, Optional, Union
# -----------------------------------------
# Logging setup
# -----------------------------------------
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
# -----------------------------------------
# Braiins API endpoints (7 selected)
# -----------------------------------------
BRAIINS_APIS = {
'price_stats': 'https://insights.braiins.com/api/v1.0/price-stats',
'hashrate_stats': 'https://insights.braiins.com/api/v1.0/hashrate-stats',
'difficulty_stats': 'https://insights.braiins.com/api/v1.0/difficulty-stats',
'transaction_fees_history': 'https://insights.braiins.com/api/v1.0/transaction-fees-history',
'daily_revenue_history': 'https://insights.braiins.com/api/v1.0/daily-revenue-history',
'hashrate_value_history': 'https://insights.braiins.com/api/v1.0/hashrate-value-history',
'halvings': 'https://insights.braiins.com/api/v2.0/halvings'
}
# -----------------------------------------
# Utility Functions
# -----------------------------------------
def clean_value(value):
"""Clean strings, remove brackets/quotes and standardize whitespace."""
if value is None:
return ""
s = str(value)
s = s.replace(",", " ")
s = re.sub(r"[\[\]\{\}\(\)]", "", s)
s = s.replace('"', "").replace("'", "")
s = re.sub(r"\s+", " ", s)
return s.strip()
def parse_date(date_str: str) -> Optional[str]:
"""Parse dates into a standard readable format."""
if not date_str or not isinstance(date_str, str):
return None
try:
if 'T' in date_str:
return datetime.datetime.fromisoformat(date_str.replace('Z', '').split('.')[0]).strftime('%Y-%m-%d %H:%M:%S')
if '-' in date_str and len(date_str) == 10:
return datetime.datetime.strptime(date_str, '%Y-%m-%d').strftime('%Y-%m-%d %H:%M:%S')
if '/' in date_str and len(date_str) == 10:
return datetime.datetime.strptime(date_str, '%m/%d/%Y').strftime('%Y-%m-%d %H:%M:%S')
except Exception:
return date_str
return date_str
def fetch_endpoint_data(url: str) -> Optional[Union[Dict, list]]:
"""Generic GET request to Braiins API endpoint."""
try:
resp = requests.get(url, timeout=15)
resp.raise_for_status()
return resp.json()
except Exception as e:
logger.error(f"Failed to fetch {url}: {e}")
return None
def clean_and_process_data(data: Union[Dict, list]) -> Union[Dict, list]:
"""Clean all keys and values in the fetched data."""
if isinstance(data, dict):
return {clean_value(k): clean_value(v) for k, v in data.items()}
elif isinstance(data, list):
cleaned_list = []
for item in data:
if isinstance(item, dict):
cleaned_list.append({clean_value(k): clean_value(v) for k, v in item.items()})
else:
cleaned_list.append(clean_value(item))
return cleaned_list
return clean_value(data)
# -----------------------------------------
# Main data fetcher
# -----------------------------------------
def fetch_clean_data(history_limit: int = 30) -> Dict[str, Union[Dict, list]]:
"""
Fetch and clean data from 7 selected Braiins endpoints.
For historical data, it limits the number of records.
Returns a dictionary ready to be passed into an LLM.
"""
logger.info("Fetching Bitcoin network data from Braiins...")
results = {}
for key, url in BRAIINS_APIS.items():
logger.info(f"Fetching {key} ...")
raw_data = fetch_endpoint_data(url)
if raw_data is not None:
# --- START OF THE NEW CODE ---
# If the endpoint is for historical data, limit the number of records
if "history" in key and isinstance(raw_data, list):
logger.info(f"Limiting {key} data to the last {history_limit} records.")
raw_data = raw_data[-history_limit:]
# --- END OF THE NEW CODE ---
results[key] = clean_and_process_data(raw_data)
else:
results[key] = {"error": "Failed to fetch"}
logger.info("All data fetched and cleaned successfully.")
return results
# -----------------------------------------
# Local test run (optional)
# -----------------------------------------
if __name__ == "__main__":
data = fetch_clean_data()
print("Sample keys fetched:", list(data.keys()))

View File

@@ -1,50 +0,0 @@
# **Automated Bitcoin Daily Summary Generator**
This project automates the process of generating a daily summary of the Bitcoin network's status. It fetches real-time data from multiple public API endpoints, processes it, and then uses a Large Language Model (LLM) to generate a clear, structured, and human-readable report in Markdown format.
## **Project Overview**
The core goal of this project is to provide a snapshot of key Bitcoin metrics without manual analysis. By leveraging the Braiins Public API for data and OpenAI's GPT models for summarization, it can produce insightful daily reports covering market trends, network health, miner revenue, and future outlooks like the next halving event.
### **Key Features**
- **Automated Data Fetching**: Pulls data from 7 different Braiins API endpoints covering price, hashrate, difficulty, transaction fees, and more.
- **Data Cleaning**: Pre-processes the raw JSON data to make it clean and suitable for the LLM.
- **Intelligent Summarization**: Uses an advanced LLM to analyze the data and generate a structured report with explanations for technical terms.
- **Dynamic Dating**: The report is always dated for the day it is run, providing a timely summary regardless of the timestamps in the source data.
- **Markdown Output**: Generates a clean, well-formatted Markdown file that is easy to read or integrate into other systems.
## **How It Works**
The project is split into two main files:
1. **utils.py**: A utility script responsible for all data fetching and cleaning operations.
- It defines the Braiins API endpoints to be queried.
- It contains functions to handle HTTP requests, parse JSON responses, and clean up keys and values to ensure consistency.
2. **day_1_bitcoin_daily_brief.ipynb**: A Jupyter Notebook that acts as the main orchestrator.
- It imports the necessary functions from utils.py.
- It calls fetch_clean_data() to get the latest Bitcoin network data.
- It constructs a detailed system and user prompt for the LLM, explicitly instructing it on the desired format and, crucially, to use the current date for the summary.
- It sends the data and prompt to the OpenAI API.
- It receives the generated summary and displays it as formatted Markdown.
## **Setup and Usage**
To run this project, you will need to have Python and the required libraries installed.
### **1\. Prerequisites**
- Python 3.x
- Jupyter Notebook or JupyterLab
### **2\. Installation**
- Install the necessary Python libraries: pip install requests openai python-dotenv jupyter
### **3\. Configuration**
You need an API key from OpenAI to use the summarization feature.
1. Create a file named .env in the root directory of the project.
2. Add your OpenAI API key to the .env file as follows:
OPENAI_API_KEY='your_openai_api_key_here'

View File

@@ -1,152 +0,0 @@
{
"cells": [
{
"cell_type": "markdown",
"id": "abaef96b",
"metadata": {},
"source": [
"## Importing The Libraries"
]
},
{
"cell_type": "code",
"execution_count": 5,
"id": "f90c541b",
"metadata": {},
"outputs": [],
"source": [
"import os\n",
"import datetime\n",
"from utils import fetch_clean_data\n",
"from openai import OpenAI\n",
"from IPython.display import Markdown, display\n",
"import json"
]
},
{
"cell_type": "markdown",
"id": "6e6c864b",
"metadata": {},
"source": [
"## Configuration"
]
},
{
"cell_type": "code",
"execution_count": 6,
"id": "be62299d",
"metadata": {},
"outputs": [],
"source": [
"client = OpenAI(base_url='http://localhost:11434/v1', api_key = 'ollama')"
]
},
{
"cell_type": "code",
"execution_count": 7,
"id": "3aa8e3e2",
"metadata": {},
"outputs": [],
"source": [
"def generate_markdown_summary(data: dict, today_date_str: str) -> str:\n",
" \"\"\"\n",
" Send cleaned Bitcoin data to an LLM and receive a Markdown summary.\n",
" \"\"\"\n",
"\n",
" system_prompt = f\"\"\"\n",
" You are a professional crypto analyst. Your job is to read the provided Bitcoin network data \n",
" and write a clear, structured report that can be read directly as a daily summary.\n",
"\n",
" Following are the rules that you must adhere to:\n",
" - **IMPORTANT**: The summary title MUST use today's date: {today_date_str}. The title must be: \"Bitcoin Daily Summary - {today_date_str}\".\n",
" - **CRITICAL**: Do NOT infer the reporting period from the data. The data contains historical records, but your report is for {today_date_str}.\n",
" - Include **headings** for sections like \"Market Overview\", \"Network Metrics Explained\", \"Miner Revenue Trends\", and \"Halving Outlook\".\n",
" - Use **bullet points** for key metrics.\n",
" - Use a **table** for historical or time-series data if available.\n",
" - Explain important terms (like hashrate, difficulty, transaction fees) in plain language.\n",
"\n",
" Respond in markdown. Do not wrap the markdown in a code block - respond just with the markdown.\n",
" \"\"\"\n",
"\n",
" # Convert the Python data dictionary into a clean JSON string for the prompt\n",
" data_str = json.dumps(data, indent=2)\n",
"\n",
" user_prompt = f\"\"\"\n",
" Today's date is {today_date_str}. Use this as the reference point for the report.\n",
"\n",
" The following data may contain historical records (e.g., from 2024), \n",
" but you must treat it as background context and write the summary as of {today_date_str}.\n",
"\n",
" Here is the data for you to summarize: \n",
" {data_str}\n",
" \"\"\"\n",
" \n",
" response = client.chat.completions.create(\n",
" model= \"llama3.2\", \n",
" messages=[\n",
" {\"role\": \"system\", \"content\": system_prompt},\n",
" {\"role\": \"user\", \"content\": user_prompt}\n",
" ]\n",
" )\n",
"\n",
" markdown_text = response.choices[0].message.content.strip()\n",
" return markdown_text"
]
},
{
"cell_type": "markdown",
"id": "1e8c2d7d",
"metadata": {},
"source": [
"## Main Function"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "05059ed9",
"metadata": {},
"outputs": [],
"source": [
"def main():\n",
" # 0. Get today's date as a string\n",
" today_str = datetime.datetime.now().strftime('%B %d, %Y')\n",
" \n",
" # 1. Fetch and clean data\n",
" print(\"Fetching Bitcoin data...\")\n",
" data = fetch_clean_data()\n",
"\n",
" # 2. Generate Markdown summary\n",
" print(\"Generating LLM summary...\")\n",
" markdown_report = generate_markdown_summary(data, today_str)\n",
"\n",
" # 3. Display Output\n",
" display(Markdown(markdown_report))\n",
"\n",
"if __name__ == \"__main__\":\n",
" main()"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "llm-engineering",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.12.12"
}
},
"nbformat": 4,
"nbformat_minor": 5
}

View File

@@ -1,113 +0,0 @@
# utils.py
import requests
import re
import datetime
import logging
from typing import Dict, Optional, Union
# -----------------------------------------
# Logging setup
# -----------------------------------------
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
# -----------------------------------------
# Braiins API endpoints (7 selected)
# -----------------------------------------
BRAIINS_APIS = {
'price_stats': 'https://insights.braiins.com/api/v1.0/price-stats',
'hashrate_stats': 'https://insights.braiins.com/api/v1.0/hashrate-stats',
'difficulty_stats': 'https://insights.braiins.com/api/v1.0/difficulty-stats',
'transaction_fees_history': 'https://insights.braiins.com/api/v1.0/transaction-fees-history',
'daily_revenue_history': 'https://insights.braiins.com/api/v1.0/daily-revenue-history',
'hashrate_value_history': 'https://insights.braiins.com/api/v1.0/hashrate-value-history',
'halvings': 'https://insights.braiins.com/api/v2.0/halvings'
}
# -----------------------------------------
# Utility Functions
# -----------------------------------------
def clean_value(value):
"""Clean strings, remove brackets/quotes and standardize whitespace."""
if value is None:
return ""
s = str(value)
s = s.replace(",", " ")
s = re.sub(r"[\[\]\{\}\(\)]", "", s)
s = s.replace('"', "").replace("'", "")
s = re.sub(r"\s+", " ", s)
return s.strip()
def parse_date(date_str: str) -> Optional[str]:
"""Parse dates into a standard readable format."""
if not date_str or not isinstance(date_str, str):
return None
try:
if 'T' in date_str:
return datetime.datetime.fromisoformat(date_str.replace('Z', '').split('.')[0]).strftime('%Y-%m-%d %H:%M:%S')
if '-' in date_str and len(date_str) == 10:
return datetime.datetime.strptime(date_str, '%Y-%m-%d').strftime('%Y-%m-%d %H:%M:%S')
if '/' in date_str and len(date_str) == 10:
return datetime.datetime.strptime(date_str, '%m/%d/%Y').strftime('%Y-%m-%d %H:%M:%S')
except Exception:
return date_str
return date_str
def fetch_endpoint_data(url: str) -> Optional[Union[Dict, list]]:
"""Generic GET request to Braiins API endpoint."""
try:
resp = requests.get(url, timeout=15)
resp.raise_for_status()
return resp.json()
except Exception as e:
logger.error(f"Failed to fetch {url}: {e}")
return None
def clean_and_process_data(data: Union[Dict, list]) -> Union[Dict, list]:
"""Clean all keys and values in the fetched data."""
if isinstance(data, dict):
return {clean_value(k): clean_value(v) for k, v in data.items()}
elif isinstance(data, list):
cleaned_list = []
for item in data:
if isinstance(item, dict):
cleaned_list.append({clean_value(k): clean_value(v) for k, v in item.items()})
else:
cleaned_list.append(clean_value(item))
return cleaned_list
return clean_value(data)
# -----------------------------------------
# Main data fetcher
# -----------------------------------------
def fetch_clean_data() -> Dict[str, Union[Dict, list]]:
"""
Fetch and clean data from 7 selected Braiins endpoints.
Returns a dictionary ready to be passed into an LLM.
"""
logger.info("Fetching Bitcoin network data from Braiins...")
results = {}
for key, url in BRAIINS_APIS.items():
logger.info(f"Fetching {key} ...")
raw_data = fetch_endpoint_data(url)
if raw_data is not None:
results[key] = clean_and_process_data(raw_data)
else:
results[key] = {"error": "Failed to fetch"}
logger.info("All data fetched and cleaned successfully.")
return results
# -----------------------------------------
# Local test run (optional)
# -----------------------------------------
if __name__ == "__main__":
data = fetch_clean_data()
print("Sample keys fetched:", list(data.keys()))

View File

@@ -0,0 +1,207 @@
{
"cells": [
{
"cell_type": "code",
"execution_count": 9,
"id": "57499cf2",
"metadata": {},
"outputs": [],
"source": [
"import os\n",
"import json\n",
"from dotenv import load_dotenv\n",
"from IPython.display import Markdown, display, update_display\n",
"from scraper import fetch_website_links, fetch_website_contents\n",
"from openai import OpenAI"
]
},
{
"cell_type": "code",
"execution_count": 10,
"id": "310a13f3",
"metadata": {},
"outputs": [],
"source": [
"load_dotenv(override=True)\n",
"api_key = os.getenv('OPENAI_API_KEY')\n",
"\n",
"client = OpenAI()"
]
},
{
"cell_type": "code",
"execution_count": 11,
"id": "79226a7f",
"metadata": {},
"outputs": [],
"source": [
"link_analyzer_prompt = \"\"\"\n",
"You are a skilled research analyst. Your task is to identify the most useful introductory links for a given topic from a list of URLs. \n",
"You must ignore forum posts, product pages, and social media links. Focus on high-quality articles, documentation, and educational resources.\n",
"Respond ONLY with a JSON object in the following format:\n",
"{\n",
" \"links\": [\n",
" {\"type\": \"overview_article\", \"url\": \"https://...\"},\n",
" {\"type\": \"technical_docs\", \"url\": \"https://...\"},\n",
" {\"type\": \"history_summary\", \"url\": \"https://...\"}\n",
" ]\n",
"}\n",
"\"\"\""
]
},
{
"cell_type": "code",
"execution_count": 12,
"id": "73d02b52",
"metadata": {},
"outputs": [],
"source": [
"briefing_prompt = \"\"\"\n",
"You are an expert intelligence analyst. You will be given raw text from several articles about a topic. \n",
"Your mission is to synthesize this information into a clear and structured research brief. \n",
"The brief must contain the following sections in Markdown:\n",
"\n",
"Research Brief: {topic}\n",
"\n",
"1. Executive Summary\n",
"(A one-paragraph overview of the entire topic.)\n",
"\n",
"2. Key Concepts\n",
"(Use bullet points to list and explain the most important terms and ideas.)\n",
"\n",
"3. Important Figures / Events\n",
"(List the key people, organizations, or historical events relevant to the topic.)\n",
"\n",
"4. Further Reading\n",
"(Provide a list of the original URLs you analyzed for deeper study.)\n",
"\"\"\""
]
},
{
"cell_type": "code",
"execution_count": 13,
"id": "ab04efb6",
"metadata": {},
"outputs": [],
"source": [
"def get_relevant_links(topic: str, starting_url: str) -> dict:\n",
" \n",
" # getting all links from the starting URL\n",
" links_on_page = fetch_website_links(starting_url)\n",
" \n",
" # user prompt for the Link Analyst\n",
" user_prompt = f\"\"\"\n",
" Please analyze the following links related to the topic \"{topic}\" and return the most relevant ones for a research brief.\n",
" The main URL is {starting_url}. Make sure all returned URLs are absolute.\n",
"\n",
" Links:\n",
" {\"\\n\".join(links_on_page)}\n",
" \"\"\"\n",
" \n",
" response = client.chat.completions.create(\n",
" model=\"gpt-4o-mini\", \n",
" messages=[\n",
" {\"role\": \"system\", \"content\": link_analyzer_prompt},\n",
" {\"role\": \"user\", \"content\": user_prompt}\n",
" ],\n",
" response_format={\"type\": \"json_object\"}\n",
" )\n",
" \n",
" result_json = response.choices[0].message.content\n",
" relevant_links = json.loads(result_json)\n",
" return relevant_links"
]
},
{
"cell_type": "code",
"execution_count": 14,
"id": "ef6ef363",
"metadata": {},
"outputs": [],
"source": [
"def get_all_content(links_data: dict) -> str:\n",
" all_content = \"\"\n",
" original_urls = []\n",
"\n",
" for link in links_data.get(\"links\", []):\n",
" url = link.get(\"url\")\n",
" if url:\n",
" original_urls.append(url)\n",
" content = fetch_website_contents(url)\n",
" all_content += f\"Content from {url} \\n{content}\\n\\n\"\n",
" \n",
" all_content += f\"Original URLs for Reference\\n\" + \"\\n\".join(original_urls)\n",
" return all_content"
]
},
{
"cell_type": "code",
"execution_count": 15,
"id": "c2020492",
"metadata": {},
"outputs": [],
"source": [
"def create_research_brief(topic: str, starting_url: str):\n",
" relevant_links = get_relevant_links(topic, starting_url)\n",
" full_content = get_all_content(relevant_links)\n",
"\n",
" user_prompt = f\"\"\"\n",
" Please create a research brief on the topic \"{topic}\" using the following content.\n",
" Remember to include the original URLs in the 'Further Reading' section.\n",
"\n",
" Content:\n",
" {full_content[:15000]}\n",
" \"\"\"\n",
" \n",
" stream = client.chat.completions.create(\n",
" model=\"gpt-4o-mini\",\n",
" messages=[\n",
" {\"role\": \"system\", \"content\": briefing_prompt.format(topic=topic)},\n",
" {\"role\": \"user\", \"content\": user_prompt}\n",
" ],\n",
" stream=True\n",
" )\n",
" \n",
" response = \"\"\n",
" display_handle = display(Markdown(\"\"), display_id=True)\n",
" for chunk in stream:\n",
" response += chunk.choices[0].delta.content or ''\n",
" update_display(Markdown(response), display_id=display_handle.display_id)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "594e940c",
"metadata": {},
"outputs": [],
"source": [
"create_research_brief(\n",
" topic=\"The Rise of Artificial Intelligence\", \n",
" starting_url=\"https://en.wikipedia.org/wiki/Artificial_intelligence\"\n",
")"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "llm-engineering",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.12.12"
}
},
"nbformat": 4,
"nbformat_minor": 5
}

View File

@@ -0,0 +1,37 @@
from bs4 import BeautifulSoup
import requests
# Standard headers to fetch a website
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/117.0.0.0 Safari/537.36"
}
def fetch_website_contents(url):
"""
Return the title and contents of the website at the given url;
truncate to 2,000 characters as a sensible limit
"""
response = requests.get(url, headers=headers)
soup = BeautifulSoup(response.content, "html.parser")
title = soup.title.string if soup.title else "No title found"
if soup.body:
for irrelevant in soup.body(["script", "style", "img", "input"]):
irrelevant.decompose()
text = soup.body.get_text(separator="\n", strip=True)
else:
text = ""
return (title + "\n\n" + text)[:2_000]
def fetch_website_links(url):
"""
Return the links on the webiste at the given url
I realize this is inefficient as we're parsing twice! This is to keep the code in the lab simple.
Feel free to use a class and optimize it!
"""
response = requests.get(url, headers=headers)
soup = BeautifulSoup(response.content, "html.parser")
links = [link.get("href") for link in soup.find_all("a")]
return [link for link in links if link]

View File

@@ -0,0 +1,337 @@
{
"cells": [
{
"cell_type": "code",
"execution_count": null,
"id": "1665a5cf",
"metadata": {},
"outputs": [],
"source": [
"import os\n",
"import re\n",
"import time\n",
"import json\n",
"import sqlite3\n",
"from dotenv import load_dotenv\n",
"import gradio as gr\n",
"from openai import OpenAI"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "5cb6632c",
"metadata": {},
"outputs": [],
"source": [
"load_dotenv()\n",
"client = OpenAI(api_key=os.getenv(\"OPENAI_API_KEY\"))\n",
"DB_PATH = \"nova_support.db\""
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "2cd3ac8c",
"metadata": {},
"outputs": [],
"source": [
"def init_db():\n",
" conn = sqlite3.connect(DB_PATH)\n",
" cur = conn.cursor()\n",
" cur.execute(\"\"\"\n",
" CREATE TABLE IF NOT EXISTS tickets (\n",
" ticket_id TEXT PRIMARY KEY,\n",
" name TEXT,\n",
" company TEXT,\n",
" email TEXT,\n",
" issue TEXT,\n",
" priority TEXT,\n",
" status TEXT,\n",
" created_at TEXT\n",
" )\n",
" \"\"\")\n",
" conn.commit()\n",
" conn.close()"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "70e0556c",
"metadata": {},
"outputs": [],
"source": [
"def new_ticket_id():\n",
" conn = sqlite3.connect(DB_PATH)\n",
" cur = conn.cursor()\n",
" cur.execute(\"SELECT COUNT(*) FROM tickets\")\n",
" count = cur.fetchone()[0]\n",
" conn.close()\n",
" return f\"RT-{1001 + count}\""
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "38525d5c",
"metadata": {},
"outputs": [],
"source": [
"def create_ticket(name, company, email, issue, priority=\"P3\"):\n",
" tid = new_ticket_id()\n",
" ts = time.strftime(\"%Y-%m-%d %H:%M:%S\")\n",
" conn = sqlite3.connect(DB_PATH)\n",
" cur = conn.cursor()\n",
" cur.execute(\"\"\"\n",
" INSERT INTO tickets (ticket_id, name, company, email, issue, priority, status, created_at)\n",
" VALUES (?, ?, ?, ?, ?, ?, ?, ?)\n",
" \"\"\", (tid, name, company, email, issue, priority.upper(), \"OPEN\", ts))\n",
" conn.commit()\n",
" conn.close()\n",
" return tid, ts"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "58e803c5",
"metadata": {},
"outputs": [],
"source": [
"def get_ticket(ticket_id):\n",
" conn = sqlite3.connect(DB_PATH)\n",
" cur = conn.cursor()\n",
" cur.execute(\"SELECT * FROM tickets WHERE ticket_id=?\", (ticket_id,))\n",
" row = cur.fetchone()\n",
" conn.close()\n",
" if not row:\n",
" return None\n",
" keys = [\"ticket_id\", \"name\", \"company\", \"email\", \"issue\", \"priority\", \"status\", \"created_at\"]\n",
" return dict(zip(keys, row))"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "b97601ff",
"metadata": {},
"outputs": [],
"source": [
"def synthesize_speech(text):\n",
" if not text.strip():\n",
" return None\n",
" output_path = Path(tempfile.gettempdir()) / \"nova_reply.mp3\"\n",
" with client.audio.speech.with_streaming_response.create(\n",
" model=\"gpt-4o-mini-tts\",\n",
" voice=\"alloy\",\n",
" input=text\n",
" ) as response:\n",
" response.stream_to_file(output_path)\n",
" return str(output_path)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "e4e20aad",
"metadata": {},
"outputs": [],
"source": [
"SYSTEM_PROMPT = \"\"\"\n",
"You are Nova, the AI Support and Sales Assistant for Reallytics.ai.\n",
"You help customers with:\n",
"- Reporting issues (create tickets)\n",
"- Checking existing tickets\n",
"- Providing product/service information\n",
"- Explaining pricing ranges\n",
"- Reassuring integration compatibility with client systems\n",
"Respond in a professional, business tone.\n",
"\"\"\""
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "0d1c094d",
"metadata": {},
"outputs": [],
"source": [
"def detect_intent(message):\n",
" text = message.lower()\n",
" if any(k in text for k in [\"create ticket\", \"open ticket\", \"new ticket\", \"issue\", \"problem\"]):\n",
" return \"create_ticket\"\n",
" if re.search(r\"rt-\\d+\", text):\n",
" return \"check_ticket\"\n",
" if \"price\" in text or \"cost\" in text:\n",
" return \"pricing\"\n",
" if \"integration\" in text:\n",
" return \"integration\"\n",
" return \"general\""
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "ed9114d5",
"metadata": {},
"outputs": [],
"source": [
"def chat(message, history, model, name, company, email):\n",
" history_msgs = [{\"role\": h[\"role\"], \"content\": h[\"content\"]} for h in history]\n",
" intent = detect_intent(message)\n",
"\n",
" if intent == \"create_ticket\":\n",
" priority = \"P2\" if \"urgent\" in message.lower() or \"high\" in message.lower() else \"P3\"\n",
" tid, ts = create_ticket(name, company, email, message, priority)\n",
" text = f\"A new support ticket has been created.\\nTicket ID: {tid}\\nCreated at: {ts}\\nStatus: OPEN\"\n",
" yield text, synthesize_speech(text)\n",
" return\n",
"\n",
" if intent == \"check_ticket\":\n",
" match = re.search(r\"(rt-\\d+)\", message.lower())\n",
" if match:\n",
" ticket_id = match.group(1).upper()\n",
" data = get_ticket(ticket_id)\n",
" if data:\n",
" text = (\n",
" f\"Ticket {ticket_id} Details:\\n\"\n",
" f\"Issue: {data['issue']}\\n\"\n",
" f\"Status: {data['status']}\\n\"\n",
" f\"Priority: {data['priority']}\\n\"\n",
" f\"Created at: {data['created_at']}\"\n",
" )\n",
" else:\n",
" text = f\"No ticket found with ID {ticket_id}.\"\n",
" else:\n",
" text = \"Please provide a valid ticket ID.\"\n",
" yield text, synthesize_speech(text)\n",
" return"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "280c7d2f",
"metadata": {},
"outputs": [],
"source": [
"def chat(message, history, model, name, company, email):\n",
" if not message.strip():\n",
" yield \"Please type a message to start.\", None\n",
" return\n",
"\n",
" history_msgs = [{\"role\": h[\"role\"], \"content\": h[\"content\"]} for h in history]\n",
" intent = detect_intent(message)\n",
" reply, audio_path = \"\", None\n",
"\n",
" if intent == \"create_ticket\":\n",
" priority = \"P2\" if \"urgent\" in message.lower() or \"high\" in message.lower() else \"P3\"\n",
" tid, ts = create_ticket(name, company, email, message, priority)\n",
" reply = f\"A new support ticket has been created.\\nTicket ID: {tid}\\nCreated at: {ts}\\nStatus: OPEN\"\n",
" audio_path = synthesize_speech(reply)\n",
" yield reply, audio_path\n",
" return\n",
"\n",
" if intent == \"check_ticket\":\n",
" match = re.search(r\"(rt-\\d+)\", message.lower())\n",
" if match:\n",
" ticket_id = match.group(1).upper()\n",
" data = get_ticket(ticket_id)\n",
" if data:\n",
" reply = (\n",
" f\"Ticket {ticket_id} Details:\\n\"\n",
" f\"Issue: {data['issue']}\\n\"\n",
" f\"Status: {data['status']}\\n\"\n",
" f\"Priority: {data['priority']}\\n\"\n",
" f\"Created at: {data['created_at']}\"\n",
" )\n",
" else:\n",
" reply = f\"No ticket found with ID {ticket_id}.\"\n",
" else:\n",
" reply = \"Please provide a valid ticket ID.\"\n",
" audio_path = synthesize_speech(reply)\n",
" yield reply, audio_path\n",
" return\n",
"\n",
" messages = [{\"role\": \"system\", \"content\": SYSTEM_PROMPT}] + history_msgs + [{\"role\": \"user\", \"content\": message}]\n",
" stream = client.chat.completions.create(model=model, messages=messages, stream=True)\n",
"\n",
" full_reply = \"\"\n",
" for chunk in stream:\n",
" delta = chunk.choices[0].delta.content or \"\"\n",
" full_reply += delta\n",
" yield full_reply, None \n",
" audio_path = synthesize_speech(full_reply)\n",
" yield full_reply, audio_path "
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "0cb1977d",
"metadata": {},
"outputs": [],
"source": [
"init_db()"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "8a0557ba",
"metadata": {},
"outputs": [],
"source": [
"with gr.Blocks(title=\"Nova | Business AI Assistant\", theme=gr.themes.Soft()) as demo:\n",
" gr.Markdown(\"## Nova | Reallytics.ai Customer Support & Sales Assistant\")\n",
" gr.Markdown(\n",
" \"Nova helps clients create or track support tickets, understand services, and explore automation options. \"\n",
" \"Type your questions and Nova will respond in both text and voice.\"\n",
" )\n",
"\n",
" with gr.Row():\n",
" name = gr.Textbox(label=\"Your Name\", placeholder=\"Liam\")\n",
" company = gr.Textbox(label=\"Company (optional)\", placeholder=\"ABC Corp\")\n",
" email = gr.Textbox(label=\"Email\", placeholder=\"you@example.com\")\n",
"\n",
" model = gr.Dropdown([\"gpt-4o-mini\", \"gpt-4\", \"gpt-3.5-turbo\"], value=\"gpt-4o-mini\", label=\"Model\")\n",
"\n",
" audio_output = gr.Audio(label=\"Nova's Voice Reply\", autoplay=True, interactive=False)\n",
"\n",
" gr.ChatInterface(\n",
" fn=chat,\n",
" type=\"messages\",\n",
" additional_inputs=[model, name, company, email],\n",
" additional_outputs=[audio_output],\n",
" title=\"Chat with Nova\",\n",
" description=\"Ask about tickets, automation services, pricing, or integration and Nova will also speak her reply.\"\n",
" )\n",
"\n",
"if __name__ == \"__main__\":\n",
" demo.launch()"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "llm-engineering",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.12.12"
}
},
"nbformat": 4,
"nbformat_minor": 5
}

View File

@@ -1,144 +0,0 @@
{
"cells": [
{
"cell_type": "code",
"execution_count": null,
"id": "d59206dc",
"metadata": {},
"outputs": [],
"source": [
"import os\n",
"from dotenv import load_dotenv\n",
"from openai import OpenAI\n",
"import ollama\n",
"from IPython.display import Markdown, display"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "ad035727",
"metadata": {},
"outputs": [],
"source": [
"# Load keys\n",
"load_dotenv()\n",
"client = OpenAI(api_key=os.getenv(\"OPENAI_API_KEY\"))\n",
"ollama_via_openai = OpenAI(base_url='http://localhost:11434/v1', api_key = 'ollama')"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "3f521334",
"metadata": {},
"outputs": [],
"source": [
"# ---- SYSTEM PROMPTS ----\n",
"athena_system = \"\"\"\n",
"You are Athena, a strategic thinker and visionary. You seek meaning, long-term implications,\n",
"and practical wisdom in every discussion. Be concise (1-2 sentences).\n",
"\"\"\"\n",
"\n",
"loki_system = \"\"\"\n",
"You are Loki, a sarcastic trickster who mocks and challenges everyone else's opinions.\n",
"You use humor, wit, and irony to undermine serious arguments. Be concise (1-2 sentences).\n",
"\"\"\"\n",
"\n",
"orion_system = \"\"\"\n",
"You are Orion, a data-driven realist. You respond with evidence, statistics, or factual analysis.\n",
"If data is not available, make a logical deduction. Be concise (1-2 sentences).\n",
"\"\"\""
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "0a6d04f6",
"metadata": {},
"outputs": [],
"source": [
"# ---- INITIAL CONVERSATION ----\n",
"conversation = [\n",
" {\"role\": \"system\", \"name\": \"Athena\", \"content\": athena_system},\n",
" {\"role\": \"system\", \"name\": \"Loki\", \"content\": loki_system},\n",
" {\"role\": \"system\", \"name\": \"Orion\", \"content\": orion_system},\n",
" {\"role\": \"user\", \"content\": \"Topic: 'Why did the chicken cross the road?' Begin your discussion.\"}\n",
"]"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "e292a27b",
"metadata": {},
"outputs": [],
"source": [
"# ---- HELPER FUNCTIONS ----\n",
"def call_gpt(name, system_prompt, conversation):\n",
" \"\"\"Call GPT model with current conversation context.\"\"\"\n",
" messages = [{\"role\": \"system\", \"content\": system_prompt}]\n",
" messages += [{\"role\": \"user\", \"content\": f\"The conversation so far:\\n{format_conversation(conversation)}\\nNow respond as {name}.\"}]\n",
" resp = client.chat.completions.create(model=\"gpt-4o-mini\", messages=messages)\n",
" return resp.choices[0].message.content.strip()\n",
"\n",
"def call_ollama(name, system_prompt, conversation):\n",
" \"\"\"Call Ollama (Llama3.2) as a local model.\"\"\"\n",
" messages = [{\"role\": \"system\", \"content\": system_prompt}]\n",
" messages += [{\"role\": \"user\", \"content\": f\"The conversation so far:\\n{format_conversation(conversation)}\\nNow respond as {name}.\"}]\n",
" resp = ollama.chat(model=\"llama3.2\", messages=messages)\n",
" return resp['message']['content'].strip()\n",
"\n",
"def format_conversation(conv):\n",
" return \"\\n\".join([f\"{m.get('name', m['role']).upper()}: {m['content']}\" for m in conv if m['role'] != \"system\"])"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "f0eb4d72",
"metadata": {},
"outputs": [],
"source": [
"# ---- MAIN LOOP ----\n",
"rounds = 5\n",
"for i in range(rounds):\n",
" # Athena responds\n",
" athena_reply = call_gpt(\"Athena\", athena_system, conversation)\n",
" conversation.append({\"role\": \"assistant\", \"name\": \"Athena\", \"content\": athena_reply})\n",
" display(Markdown(f\"**Athena:** {athena_reply}\"))\n",
"\n",
" # Loki responds\n",
" loki_reply = call_ollama(\"Loki\", loki_system, conversation)\n",
" conversation.append({\"role\": \"assistant\", \"name\": \"Loki\", \"content\": loki_reply})\n",
" display(Markdown(f\"**Loki:** {loki_reply}\"))\n",
"\n",
" # Orion responds\n",
" orion_reply = call_gpt(\"Orion\", orion_system, conversation)\n",
" conversation.append({\"role\": \"assistant\", \"name\": \"Orion\", \"content\": orion_reply})\n",
" display(Markdown(f\"**Orion:** {orion_reply}\"))"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "llm-engineering",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.12.12"
}
},
"nbformat": 4,
"nbformat_minor": 5
}

View File

@@ -1,47 +0,0 @@
# Multi-Agent Conversation Simulator (OpenAI + Ollama)
## Project Overview
This project is an experimental **multi-agent conversational simulation** built with **OpenAI GPT models** and a locally-hosted **Ollama LLM (Llama 3.2)**. It demonstrates how multiple AI personas can participate in a shared conversation, each with distinct roles, perspectives, and behaviors — producing a dynamic, evolving debate from different angles.
The script orchestrates a **three-way dialogue** around a single topic (“Why did the chicken cross the road?”) between three agents, each powered by a different model and persona definition:
- **Athena (OpenAI GPT-4o):** A strategic thinker who looks for deeper meaning, long-term consequences, and practical wisdom.
- **Loki (Ollama Llama 3.2):** A sarcastic trickster who mocks, questions, and challenges the others with wit and irony.
- **Orion (OpenAI GPT-4o):** A data-driven realist who grounds the discussion in facts, statistics, or logical deductions.
## Whats Happening in the Code
1. **Environment Setup**
- Loads the OpenAI API key from a `.env` file.
- Initializes OpenAIs Python client and configures a local Ollama endpoint.
2. **Persona System Prompts**
- Defines system prompts for each agent to give them unique personalities and communication styles.
- These prompts act as the “character definitions” for Athena, Loki, and Orion.
3. **Conversation Initialization**
- Starts with a single conversation topic provided by the user.
- All three agents are aware of the discussion context and prior messages.
4. **Conversation Loop**
- The conversation runs in multiple rounds (default: 5).
- In each round:
- **Athena (GPT)** responds first with a strategic viewpoint.
- **Loki (Ollama)** replies next, injecting sarcasm and skepticism.
- **Orion (GPT)** follows with a fact-based or analytical perspective.
- Each response is appended to the conversation history so future replies build on previous statements.
5. **Dynamic Context Sharing**
- Each agent receives the **entire conversation so far** as context before generating a response.
- This ensures their replies are relevant, coherent, and responsive to what the others have said.
6. **Output Rendering**
- Responses are displayed as Markdown in a readable, chat-like format for each speaker, round by round.
## Key Highlights
- Demonstrates **multi-agent orchestration** with different models working together in a single script.
- Uses **OpenAI GPT models** for reasoning and **Ollama (Llama 3.2)** for local, cost-free inference.
- Shows how **system prompts** and **context-aware message passing** can simulate realistic dialogues.
- Provides a template for experimenting with **AI characters**, **debate simulations**, or **collaborative agent systems**.

View File

@@ -1,224 +0,0 @@
{
"cells": [
{
"cell_type": "code",
"execution_count": null,
"id": "4ef1e715",
"metadata": {},
"outputs": [],
"source": [
"import os\n",
"import gradio as gr\n",
"from openai import OpenAI\n",
"from dotenv import load_dotenv"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "d3426558",
"metadata": {},
"outputs": [],
"source": [
"# Load API key\n",
"load_dotenv()\n",
"client = OpenAI(api_key=os.getenv(\"OPENAI_API_KEY\"))"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "e18a59a3",
"metadata": {},
"outputs": [],
"source": [
"# -------------------------------\n",
"# Helper: Prompt Builder\n",
"# -------------------------------\n",
"def build_prompt(task, topic, tone, audience):\n",
" task_prompts = {\n",
" \"Brochure\": f\"Write a compelling marketing brochure about {topic}.\",\n",
" \"Blog Post\": f\"Write a blog post on {topic} with engaging storytelling and useful insights.\",\n",
" \"Product Comparison\": f\"Write a product comparison summary focusing on {topic}, including pros, cons, and recommendations.\",\n",
" \"Idea Brainstorm\": f\"Brainstorm creative ideas or solutions related to {topic}.\"\n",
" }\n",
" base = task_prompts.get(task, \"Write something creative.\")\n",
" if tone:\n",
" base += f\" Use a {tone} tone.\"\n",
" if audience:\n",
" base += f\" Tailor it for {audience}.\"\n",
" return base"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "65a27bfb",
"metadata": {},
"outputs": [],
"source": [
"# -------------------------------\n",
"# Generate with multiple models\n",
"# -------------------------------\n",
"def generate_stream(task, topic, tone, audience, model):\n",
" if not topic.strip():\n",
" yield \"⚠️ Please enter a topic.\"\n",
" return\n",
"\n",
" prompt = build_prompt(task, topic, tone, audience)\n",
"\n",
" stream = client.chat.completions.create(\n",
" model=model,\n",
" messages=[\n",
" {\"role\": \"system\", \"content\": \"You are a helpful assistant.\"},\n",
" {\"role\": \"user\", \"content\": prompt}\n",
" ],\n",
" max_tokens=800,\n",
" stream=True\n",
" )\n",
"\n",
" result = \"\"\n",
" for chunk in stream:\n",
" result += chunk.choices[0].delta.content or \"\"\n",
" yield result"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "9e15abee",
"metadata": {},
"outputs": [],
"source": [
"# -------------------------------\n",
"# Refinement logic\n",
"# -------------------------------\n",
"def refine_stream(original_text, instruction, model):\n",
" if not original_text.strip():\n",
" yield \"⚠️ Please paste the text you want to refine.\"\n",
" return\n",
" if not instruction.strip():\n",
" yield \"⚠️ Please provide a refinement instruction.\"\n",
" return\n",
"\n",
" refined_prompt = f\"Refine the following text based on this instruction: {instruction}\\n\\nText:\\n{original_text}\"\n",
"\n",
" stream = client.chat.completions.create(\n",
" model=model,\n",
" messages=[\n",
" {\"role\": \"system\", \"content\": \"You are a writing assistant.\"},\n",
" {\"role\": \"user\", \"content\": refined_prompt}\n",
" ],\n",
" max_tokens=800,\n",
" stream=True\n",
" )\n",
"\n",
" result = \"\"\n",
" for chunk in stream:\n",
" result += chunk.choices[0].delta.content or \"\"\n",
" yield result\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "8ee02feb",
"metadata": {},
"outputs": [],
"source": [
"# -------------------------------\n",
"# Gradio UI\n",
"# -------------------------------\n",
"with gr.Blocks(title=\"AI Creative Studio\") as demo:\n",
" gr.Markdown(\"# AI Creative Studio\\nGenerate marketing content, blog posts, or creative ideas — streamed in real-time!\")\n",
"\n",
" with gr.Row():\n",
" task = gr.Dropdown(\n",
" [\"Brochure\", \"Blog Post\", \"Product Comparison\", \"Idea Brainstorm\"],\n",
" label=\"Task Type\",\n",
" value=\"Brochure\"\n",
" )\n",
" topic = gr.Textbox(label=\"Topic\", placeholder=\"e.g., Electric Cars, AI in Education...\")\n",
" with gr.Row():\n",
" tone = gr.Textbox(label=\"Tone (optional)\", placeholder=\"e.g., professional, casual, humorous...\")\n",
" audience = gr.Textbox(label=\"Target Audience (optional)\", placeholder=\"e.g., investors, students, developers...\")\n",
"\n",
" model = gr.Dropdown(\n",
" [\"gpt-4o-mini\", \"gpt-3.5-turbo\", \"gpt-4\"],\n",
" label=\"Choose a model\",\n",
" value=\"gpt-4o-mini\"\n",
" )\n",
"\n",
" generate_btn = gr.Button(\"Generate Content\")\n",
" output_md = gr.Markdown(label=\"Generated Content\", show_label=True)\n",
"\n",
" generate_btn.click(\n",
" fn=generate_stream,\n",
" inputs=[task, topic, tone, audience, model],\n",
" outputs=output_md\n",
" )\n",
"\n",
" gr.Markdown(\"---\\n## Refine Your Content\")\n",
"\n",
" original_text = gr.Textbox(\n",
" label=\"Original Content\",\n",
" placeholder=\"Paste content you want to refine...\",\n",
" lines=10\n",
" )\n",
" instruction = gr.Textbox(\n",
" label=\"Refinement Instruction\",\n",
" placeholder=\"e.g., Make it shorter and more persuasive.\",\n",
" )\n",
" refine_model = gr.Dropdown(\n",
" [\"gpt-4o-mini\", \"gpt-3.5-turbo\", \"gpt-4\"],\n",
" label=\"Model for Refinement\",\n",
" value=\"gpt-4o-mini\"\n",
" )\n",
"\n",
" refine_btn = gr.Button(\"Refine\")\n",
" refined_output = gr.Markdown(label=\"Refined Content\", show_label=True)\n",
"\n",
" refine_btn.click(\n",
" fn=refine_stream,\n",
" inputs=[original_text, instruction, refine_model],\n",
" outputs=refined_output\n",
" )\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "55d42c7e",
"metadata": {},
"outputs": [],
"source": [
"# -------------------------------\n",
"# Launch the App\n",
"# -------------------------------\n",
"if __name__ == \"__main__\":\n",
" demo.launch()"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "llm-engineering",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.12.12"
}
},
"nbformat": 4,
"nbformat_minor": 5
}

View File

@@ -1,48 +0,0 @@
# AI Creative Studio
## Project Overview
AI Creative Studio is a web-based application built with Gradio that allows users to generate and refine high-quality written content in real time using OpenAI language models. It is designed as a flexible creative tool for content creation tasks such as writing brochures, blog posts, product comparisons, and brainstorming ideas. The application also supports interactive refinement, enabling users to improve or adapt existing text based on specific instructions.
The core idea is to combine the power of OpenAI models with an intuitive, user-friendly interface that streams responses as they are generated. This provides a fast, engaging, and highly interactive writing experience without waiting for the entire response to complete before it appears.
---
## Whats Happening in the Project
1. **Environment Setup and Model Initialization**
- The application loads the OpenAI API key from a `.env` file and initializes the OpenAI client for model interactions.
- Supported models include `gpt-4o-mini`, `gpt-3.5-turbo`, and `gpt-4`, which the user can select from a dropdown menu.
2. **Prompt Construction and Content Generation**
- The `build_prompt` function constructs a task-specific prompt based on the users choices: content type (brochure, blog post, etc.), topic, tone, and target audience.
- Once the user provides the inputs and selects a model, the application sends the prompt to the model.
- The models response is streamed back incrementally, showing text chunk by chunk for a real-time generation experience.
3. **Content Refinement Feature**
- Users can paste existing text and provide a refinement instruction (e.g., “make it more persuasive” or “summarize it”).
- The application then streams an improved version of the text, following the instruction, allowing users to iterate and polish content efficiently.
4. **Gradio User Interface**
- The app is built using Gradio Blocks, providing an organized and interactive layout.
- Key UI elements include:
- Task selection dropdown for choosing the type of content.
- Text inputs for topic, tone, and target audience.
- Model selection dropdown for choosing a specific OpenAI model.
- Real-time markdown display of generated content.
- A refinement panel for improving existing text.
5. **Streaming Workflow**
- Both generation and refinement use OpenAIs streaming API to display the models response as its produced.
- This provides an immediate and responsive user experience, allowing users to see results build up in real time rather than waiting for the entire completion.
---
### Key Features
- Real-time streaming responses for fast and interactive content creation.
- Multiple content generation modes: brochure, blog post, product comparison, and idea brainstorming.
- Customization options for tone and audience to tailor the writing style.
- Interactive refinement tool to enhance or transform existing text.
- Clean and intuitive web interface powered by Gradio.
AI Creative Studio demonstrates how large language models can be integrated into user-facing applications to support creative workflows and improve productivity in content generation and editing.

View File

@@ -1,137 +0,0 @@
{
"cells": [
{
"cell_type": "code",
"execution_count": null,
"id": "6f612c5a",
"metadata": {},
"outputs": [],
"source": [
"import os\n",
"import gradio as gr\n",
"from dotenv import load_dotenv\n",
"from openai import OpenAI"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "39c144fd",
"metadata": {},
"outputs": [],
"source": [
"# Load API Key\n",
"load_dotenv()\n",
"client = OpenAI(api_key=os.getenv(\"OPENAI_API_KEY\"))"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "f656e0d1",
"metadata": {},
"outputs": [],
"source": [
"# -------------------------------\n",
"# 1. System Prompt (Business Context)\n",
"# -------------------------------\n",
"system_message = \"\"\"\n",
"You are Nova, an AI Sales & Solutions Consultant for Reallytics.ai a company specializing in building\n",
"custom AI chatbots, voice assistants, data dashboards, and automation solutions for businesses.\n",
"You are professional, insightful, and always focused on solving the user's business challenges.\n",
"First, try to understand their use case. Then suggest relevant solutions from our services with clear value propositions.\n",
"If the user is unsure, give them examples of how similar businesses have benefited from AI.\n",
"\"\"\"\n",
"\n",
"MODEL = \"gpt-4o-mini\""
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "f2faba29",
"metadata": {},
"outputs": [],
"source": [
"# -------------------------------\n",
"# 2. Smart Chat Function (Streaming)\n",
"# -------------------------------\n",
"def chat(message, history):\n",
" # Convert Gradio's chat history to OpenAI format\n",
" history_messages = [{\"role\": h[\"role\"], \"content\": h[\"content\"]} for h in history]\n",
"\n",
" # Adjust system message based on context dynamically\n",
" relevant_system_message = system_message\n",
" if \"price\" in message.lower():\n",
" relevant_system_message += (\n",
" \" If the user asks about pricing, explain that pricing depends on project complexity, \"\n",
" \"but typical POCs start around $2,000 - $5,000, and full enterprise deployments scale beyond that.\"\n",
" )\n",
" if \"integration\" in message.lower():\n",
" relevant_system_message += (\n",
" \" If integration is mentioned, reassure the user that our solutions are built to integrate seamlessly with CRMs, ERPs, or internal APIs.\"\n",
" )\n",
"\n",
" # Compose final messages\n",
" messages = [{\"role\": \"system\", \"content\": relevant_system_message}] + history_messages + [\n",
" {\"role\": \"user\", \"content\": message}\n",
" ]\n",
"\n",
" # Stream the response\n",
" stream = client.chat.completions.create(\n",
" model=MODEL,\n",
" messages=messages,\n",
" stream=True\n",
" )\n",
"\n",
" response = \"\"\n",
" for chunk in stream:\n",
" response += chunk.choices[0].delta.content or \"\"\n",
" yield response"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "b9d9515e",
"metadata": {},
"outputs": [],
"source": [
"# -------------------------------\n",
"# 3. Gradio Chat UI\n",
"# -------------------------------\n",
"with gr.Blocks(title=\"AI Business Assistant\") as demo:\n",
" gr.Markdown(\"# AI Business Assistant\\nYour intelligent sales and solution consultant, powered by OpenAI.\")\n",
"\n",
" \n",
"gr.ChatInterface(\n",
" fn=chat,\n",
" type=\"messages\",\n",
" title=\"Business AI Consultant\",\n",
" description=\"Ask about automation, chatbots, dashboards, or voice AI Nova will help you discover the right solution.\"\n",
").launch()\n"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "llm-engineering",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.12.12"
}
},
"nbformat": 4,
"nbformat_minor": 5
}

View File

@@ -1,42 +0,0 @@
# AI Business Assistant
## Project Overview
This project is a prototype of an **AI-powered business consultant chatbot** built with **Gradio** and **OpenAI**. The assistant, named **Nova**, is designed to act as a virtual sales and solutions consultant for a company offering AI services such as chatbots, voice assistants, dashboards, and automation tools.
The purpose of the project is to demonstrate how an LLM (Large Language Model) can be adapted for a business context by carefully designing the **system prompt** and providing **dynamic behavior** based on user inputs. The chatbot responds to user queries in real time with streaming responses, making it interactive and natural to use.
## Whats Happening in the Code
1. **Environment Setup**
- The code loads the OpenAI API key from a `.env` file.
- The `OpenAI` client is initialized for communication with the language model.
- The chosen model is `gpt-4o-mini`.
2. **System Prompt for Business Context**
- The assistant is given a clear identity: *Nova, an AI Sales & Solutions Consultant for Reallytics.ai*.
- The system prompt defines Novas tone (professional, insightful) and role (understand user needs, propose relevant AI solutions, share examples).
3. **Dynamic Chat Function**
- The `chat()` function processes user input and the conversation history.
- It modifies the system prompt dynamically:
- If the user mentions **price**, Nova explains pricing ranges and factors.
- If the user mentions **integration**, Nova reassures the user about system compatibility.
- Messages are formatted for the OpenAI API, combining system, history, and user inputs.
- Responses are streamed back chunk by chunk, so users see the assistant typing in real time.
4. **Gradio Chat Interface**
- A Gradio interface is created with `ChatInterface` in `messages` mode.
- This automatically provides a chat-style UI with user/assistant message bubbles and a send button.
- The title and description help set context for end users: *“Ask about automation, chatbots, dashboards, or voice AI.”*
## Key Features
- **Business-specific persona:** The assistant is contextualized as a sales consultant rather than a generic chatbot.
- **Adaptive responses:** System prompt is adjusted based on keywords like "price" and "integration".
- **Streaming output:** Responses are displayed incrementally, improving user experience.
- **Clean chat UI:** Built with Gradios `ChatInterface` for simplicity and usability.
This project demonstrates how to combine **system prompts**, **dynamic context handling**, and **Gradio chat interfaces** to build a specialized AI assistant tailored for business use cases.