mirror of
https://github.com/MervinPraison/PraisonAI.git
synced 2026-11-08 01:08:39 -10:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fd2569e642 | ||
|
|
58efb4b4cd | ||
|
|
35df78874d | ||
|
|
4abe80a563 | ||
|
|
95c15f52fc | ||
|
|
0e2a753cc3 | ||
|
|
660260c6e6 | ||
|
|
f49b5c368c | ||
|
|
39f0c40dcc | ||
|
|
27b10ff3ea | ||
|
|
f63f247bfe | ||
|
|
75cf937581 | ||
|
|
1d7e03b03e | ||
|
|
290570de88 | ||
|
|
542ea8c10d | ||
|
|
843f70b599 | ||
|
|
dee707299d | ||
|
|
7f6e300a9e | ||
|
|
88e9de2914 | ||
|
|
f17daec68b | ||
|
|
f4d54d76e8 | ||
|
|
23e2951724 | ||
|
|
1916b1a108 | ||
|
|
5b99ca8357 | ||
|
|
09ef400c15 | ||
|
|
d5c381890f | ||
|
|
639e53ea9b | ||
|
|
0954fb4d3d | ||
|
|
f5c35f31e9 | ||
|
|
4f31ec9b63 | ||
|
|
abee86337d | ||
|
|
e6cf4ebfcd | ||
|
|
68fb0aaaca | ||
|
|
4c9009c3f5 | ||
|
|
ac21e5d595 | ||
|
|
58b12b9f24 | ||
|
|
09dcf9c114 | ||
|
|
e25e0a895f | ||
|
|
855ec4c10a | ||
|
|
2b672f4d40 |
No files matched your search
+1
-1
@@ -16,7 +16,7 @@ RUN mkdir -p /root/.praison
|
||||
# Install Python packages (using latest versions)
|
||||
RUN pip install --no-cache-dir \
|
||||
flask \
|
||||
"praisonai>=2.2.41" \
|
||||
"praisonai>=2.2.45" \
|
||||
"praisonai[api]" \
|
||||
gunicorn \
|
||||
markdown
|
||||
|
||||
@@ -16,7 +16,7 @@ RUN mkdir -p /root/.praison
|
||||
# Install Python packages (using latest versions)
|
||||
RUN pip install --no-cache-dir \
|
||||
praisonai_tools \
|
||||
"praisonai>=2.2.41" \
|
||||
"praisonai>=2.2.45" \
|
||||
"praisonai[chat]" \
|
||||
"embedchain[github,youtube]"
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ RUN mkdir -p /root/.praison
|
||||
# Install Python packages (using latest versions)
|
||||
RUN pip install --no-cache-dir \
|
||||
praisonai_tools \
|
||||
"praisonai>=2.2.41" \
|
||||
"praisonai>=2.2.45" \
|
||||
"praisonai[ui]" \
|
||||
"praisonai[chat]" \
|
||||
"praisonai[realtime]" \
|
||||
|
||||
@@ -16,7 +16,7 @@ RUN mkdir -p /root/.praison
|
||||
# Install Python packages (using latest versions)
|
||||
RUN pip install --no-cache-dir \
|
||||
praisonai_tools \
|
||||
"praisonai>=2.2.41" \
|
||||
"praisonai>=2.2.45" \
|
||||
"praisonai[ui]" \
|
||||
"praisonai[crewai]"
|
||||
|
||||
|
||||
+2
-2
@@ -121,7 +121,7 @@ healthcheck:
|
||||
## 📦 Package Versions
|
||||
|
||||
All Docker images use consistent, up-to-date versions:
|
||||
- PraisonAI: `>=2.2.41`
|
||||
- PraisonAI: `>=2.2.45`
|
||||
- PraisonAI Agents: `>=0.0.92`
|
||||
- Python: `3.11-slim`
|
||||
|
||||
@@ -218,7 +218,7 @@ docker-compose up -d
|
||||
### Version Pinning
|
||||
To use specific versions, update the Dockerfile:
|
||||
```dockerfile
|
||||
RUN pip install "praisonai==2.2.41" "praisonaiagents==0.0.92"
|
||||
RUN pip install "praisonai==2.2.45" "praisonaiagents==0.0.92"
|
||||
```
|
||||
|
||||
## 🌐 Production Deployment
|
||||
|
||||
@@ -0,0 +1,482 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "y8L9VFhhdjhL"
|
||||
},
|
||||
"source": [
|
||||
"# Financial Coaching Agent using PraisonAIAgents"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "6UxqTg7pdkm-"
|
||||
},
|
||||
"source": [
|
||||
"This notebook demonstrates how to build a Financial Coaching Agent using the `praisonaiagents` library.\n",
|
||||
"The agent analyzes user financial data and provides actionable recommendations for budgeting, savings, and debt management.\n",
|
||||
"The notebook is CI-friendly: it uses dummy data if API keys are not set, so all tests/checks will pass."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "CNqB5dPffV3m"
|
||||
},
|
||||
"source": [
|
||||
"[](https://colab.research.google.com/github/Dhivya-Bharathy/PraisonAI/blob/main/examples/cookbooks/Finance_Market_Job_Agents/Financial_Coaching_Agent.ipynb)\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "3cdm72N2doNq"
|
||||
},
|
||||
"source": [
|
||||
"# Dependencies"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"id": "Pl85wGWzdpTK"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"!pip install praisonaiagents pandas"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "YOlEEkk4ePqy"
|
||||
},
|
||||
"source": [
|
||||
"# Set up key"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 2,
|
||||
"metadata": {
|
||||
"id": "T9zKRkv_eRsc"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import os\n",
|
||||
"\n",
|
||||
"# Try to get keys from environment variables, or use placeholders\n",
|
||||
"OPENAI_API_KEY = os.environ.get(\"OPENAI_API_KEY\", \"sk-..\")\n",
|
||||
"\n",
|
||||
"# Set them in the environment for downstream code\n",
|
||||
"os.environ[\"OPENAI_API_KEY\"] = OPENAI_API_KEY\n",
|
||||
"\n",
|
||||
"def is_valid_key(key, prefix):\n",
|
||||
" return key and key != f\"{prefix}-..\" and key.startswith(prefix)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "FGYJpB9eeaSY"
|
||||
},
|
||||
"source": [
|
||||
"# Tool: Financial Summary"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 3,
|
||||
"metadata": {
|
||||
"id": "asLRt9gAecJ2"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import pandas as pd\n",
|
||||
"\n",
|
||||
"class FinancialSummaryTool:\n",
|
||||
" \"\"\"\n",
|
||||
" Custom tool to summarize financial data and calculate basic stats.\n",
|
||||
" \"\"\"\n",
|
||||
" def __init__(self, income, expenses, debts):\n",
|
||||
" self.income = income\n",
|
||||
" self.expenses = expenses\n",
|
||||
" self.debts = debts\n",
|
||||
"\n",
|
||||
" def summary(self):\n",
|
||||
" total_expenses = sum(self.expenses.values())\n",
|
||||
" surplus = self.income - total_expenses\n",
|
||||
" total_debt = sum(d['amount'] for d in self.debts)\n",
|
||||
" return {\n",
|
||||
" \"total_expenses\": total_expenses,\n",
|
||||
" \"surplus\": surplus,\n",
|
||||
" \"total_debt\": total_debt,\n",
|
||||
" \"expense_breakdown\": self.expenses,\n",
|
||||
" \"debts\": self.debts\n",
|
||||
" }"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "lIysLOOdef3b"
|
||||
},
|
||||
"source": [
|
||||
"# YAML prompt"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 4,
|
||||
"metadata": {
|
||||
"colab": {
|
||||
"base_uri": "https://localhost:8080/"
|
||||
},
|
||||
"id": "GDbWRmp2egsz",
|
||||
"outputId": "cf4e4d15-7446-4613-9a20-298674f0b4d3"
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"{'agent': {'name': 'Financial Coaching Agent', 'description': 'An agent that analyzes user financial data and provides actionable recommendations for budgeting, savings, and debt management.\\n', 'tools': [{'name': 'FinancialSummaryTool', 'description': 'Summarizes income, expenses, and debts for the agent.'}], 'workflow': [{'step': 'Summarize financial data using FinancialSummaryTool'}, {'step': 'Analyze summary and provide recommendations'}]}, 'inputs': ['monthly_income', 'expenses', 'debts'], 'outputs': ['recommendations']}\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"import yaml\n",
|
||||
"\n",
|
||||
"yaml_prompt = \"\"\"\n",
|
||||
"agent:\n",
|
||||
" name: Financial Coaching Agent\n",
|
||||
" description: |\n",
|
||||
" An agent that analyzes user financial data and provides actionable recommendations for budgeting, savings, and debt management.\n",
|
||||
" tools:\n",
|
||||
" - name: FinancialSummaryTool\n",
|
||||
" description: Summarizes income, expenses, and debts for the agent.\n",
|
||||
" workflow:\n",
|
||||
" - step: Summarize financial data using FinancialSummaryTool\n",
|
||||
" - step: Analyze summary and provide recommendations\n",
|
||||
"inputs:\n",
|
||||
" - monthly_income\n",
|
||||
" - expenses\n",
|
||||
" - debts\n",
|
||||
"outputs:\n",
|
||||
" - recommendations\n",
|
||||
"\"\"\"\n",
|
||||
"print(yaml.safe_load(yaml_prompt))"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "C-FE-hTKekHK"
|
||||
},
|
||||
"source": [
|
||||
"# Main"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 9,
|
||||
"metadata": {
|
||||
"colab": {
|
||||
"base_uri": "https://localhost:8080/",
|
||||
"height": 1000,
|
||||
"referenced_widgets": [
|
||||
"b27151e0a1ec47d8a36433ef503eede2",
|
||||
"58e152a95c1d49d68b45aea3b837b6d3"
|
||||
]
|
||||
},
|
||||
"id": "48oIH5LYek-q",
|
||||
"outputId": "b501eae2-63c2-434d-f5c3-abba6b93956e"
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/html": [
|
||||
"<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\"><span style=\"color: #d2e3c8; text-decoration-color: #d2e3c8\">╭─ </span><span style=\"color: #d2e3c8; text-decoration-color: #d2e3c8; font-weight: bold\">Agent Info</span><span style=\"color: #d2e3c8; text-decoration-color: #d2e3c8\"> ────────────────────────────────────────────────────────────────────────────────────────────────────╮</span>\n",
|
||||
"<span style=\"color: #d2e3c8; text-decoration-color: #d2e3c8\">│</span> <span style=\"color: #d2e3c8; text-decoration-color: #d2e3c8\">│</span>\n",
|
||||
"<span style=\"color: #d2e3c8; text-decoration-color: #d2e3c8\">│</span> <span style=\"color: #ff9b9b; text-decoration-color: #ff9b9b; font-weight: bold\">👤 Agent:</span> <span style=\"color: #ffe5e5; text-decoration-color: #ffe5e5\">Financial Coaching Agent</span> <span style=\"color: #d2e3c8; text-decoration-color: #d2e3c8\">│</span>\n",
|
||||
"<span style=\"color: #d2e3c8; text-decoration-color: #d2e3c8\">│</span> <span style=\"color: #b4b4b3; text-decoration-color: #b4b4b3; font-weight: bold\">Role:</span> <span style=\"color: #ffe5e5; text-decoration-color: #ffe5e5\">Assistant</span> <span style=\"color: #d2e3c8; text-decoration-color: #d2e3c8\">│</span>\n",
|
||||
"<span style=\"color: #d2e3c8; text-decoration-color: #d2e3c8\">│</span> <span style=\"color: #d2e3c8; text-decoration-color: #d2e3c8\">│</span>\n",
|
||||
"<span style=\"color: #d2e3c8; text-decoration-color: #d2e3c8\">╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯</span>\n",
|
||||
"</pre>\n"
|
||||
],
|
||||
"text/plain": [
|
||||
"\u001b[38;2;210;227;200m╭─\u001b[0m\u001b[38;2;210;227;200m \u001b[0m\u001b[1;38;2;210;227;200mAgent Info\u001b[0m\u001b[38;2;210;227;200m \u001b[0m\u001b[38;2;210;227;200m───────────────────────────────────────────────────────────────────────────────────────────────────\u001b[0m\u001b[38;2;210;227;200m─╮\u001b[0m\n",
|
||||
"\u001b[38;2;210;227;200m│\u001b[0m \u001b[38;2;210;227;200m│\u001b[0m\n",
|
||||
"\u001b[38;2;210;227;200m│\u001b[0m \u001b[1;38;2;255;155;155m👤 Agent:\u001b[0m \u001b[38;2;255;229;229mFinancial Coaching Agent\u001b[0m \u001b[38;2;210;227;200m│\u001b[0m\n",
|
||||
"\u001b[38;2;210;227;200m│\u001b[0m \u001b[1;38;2;180;180;179mRole:\u001b[0m \u001b[38;2;255;229;229mAssistant\u001b[0m \u001b[38;2;210;227;200m│\u001b[0m\n",
|
||||
"\u001b[38;2;210;227;200m│\u001b[0m \u001b[38;2;210;227;200m│\u001b[0m\n",
|
||||
"\u001b[38;2;210;227;200m╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯\u001b[0m\n"
|
||||
]
|
||||
},
|
||||
"metadata": {},
|
||||
"output_type": "display_data"
|
||||
},
|
||||
{
|
||||
"data": {
|
||||
"application/vnd.jupyter.widget-view+json": {
|
||||
"model_id": "b27151e0a1ec47d8a36433ef503eede2",
|
||||
"version_major": 2,
|
||||
"version_minor": 0
|
||||
},
|
||||
"text/plain": [
|
||||
"Output()"
|
||||
]
|
||||
},
|
||||
"metadata": {},
|
||||
"output_type": "display_data"
|
||||
},
|
||||
{
|
||||
"data": {
|
||||
"text/html": [
|
||||
"<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\"></pre>\n"
|
||||
],
|
||||
"text/plain": []
|
||||
},
|
||||
"metadata": {},
|
||||
"output_type": "display_data"
|
||||
},
|
||||
{
|
||||
"data": {
|
||||
"text/html": [
|
||||
"<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\">\n",
|
||||
"</pre>\n"
|
||||
],
|
||||
"text/plain": [
|
||||
"\n"
|
||||
]
|
||||
},
|
||||
"metadata": {},
|
||||
"output_type": "display_data"
|
||||
},
|
||||
{
|
||||
"data": {
|
||||
"text/html": [
|
||||
"<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\"><span style=\"color: #7f7f7f; text-decoration-color: #7f7f7f\">Response generated in 11.0s</span>\n",
|
||||
"</pre>\n"
|
||||
],
|
||||
"text/plain": [
|
||||
"\u001b[2mResponse generated in 11.0s\u001b[0m\n"
|
||||
]
|
||||
},
|
||||
"metadata": {},
|
||||
"output_type": "display_data"
|
||||
},
|
||||
{
|
||||
"data": {
|
||||
"text/html": [
|
||||
"<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\"><span style=\"color: #008080; text-decoration-color: #008080\">╭───────────────────────────────────────────────────── Task ──────────────────────────────────────────────────────╮</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> You are a financial coach. Analyze the following summary and provide actionable recommendations: - Monthly <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> income: $3000 - Total expenses: $2350 - Surplus: $650 - Total debt: $10000 - Expense breakdown: {'Housing': <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> 1200, 'Food': 400, 'Transportation': 200, 'Entertainment': 150, 'Savings': 300, 'Other': 100} - Debts: <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> [{'name': 'Credit Card', 'amount': 2000, 'interest_rate': 18.0, 'min_payment': 50}, {'name': 'Student Loan', <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> 'amount': 8000, 'interest_rate': 5.0, 'min_payment': 100}] <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯</span>\n",
|
||||
"</pre>\n"
|
||||
],
|
||||
"text/plain": [
|
||||
"\u001b[36m╭─\u001b[0m\u001b[36m────────────────────────────────────────────────────\u001b[0m\u001b[36m Task \u001b[0m\u001b[36m─────────────────────────────────────────────────────\u001b[0m\u001b[36m─╮\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m You are a financial coach. Analyze the following summary and provide actionable recommendations: - Monthly \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m income: $3000 - Total expenses: $2350 - Surplus: $650 - Total debt: $10000 - Expense breakdown: {'Housing': \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m 1200, 'Food': 400, 'Transportation': 200, 'Entertainment': 150, 'Savings': 300, 'Other': 100} - Debts: \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m [{'name': 'Credit Card', 'amount': 2000, 'interest_rate': 18.0, 'min_payment': 50}, {'name': 'Student Loan', \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m 'amount': 8000, 'interest_rate': 5.0, 'min_payment': 100}] \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯\u001b[0m\n"
|
||||
]
|
||||
},
|
||||
"metadata": {},
|
||||
"output_type": "display_data"
|
||||
},
|
||||
{
|
||||
"data": {
|
||||
"text/html": [
|
||||
"<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\"><span style=\"color: #008080; text-decoration-color: #008080\">╭─────────────────────────────────────────────────── Response ────────────────────────────────────────────────────╮</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> Based on the provided financial summary, here are some actionable recommendations to help manage your finances <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> more effectively and reduce your debt: <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"color: #808000; text-decoration-color: #808000; font-weight: bold\"> 1 </span><span style=\"font-weight: bold\">Prioritize Debt Repayment:</span> <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"color: #808000; text-decoration-color: #808000; font-weight: bold\"> • </span>Focus on paying off the high-interest debt first, which is the credit card debt with an 18% interest <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"color: #808000; text-decoration-color: #808000; font-weight: bold\"> </span>rate. Consider using the debt avalanche method, where you pay extra towards the debt with the highest <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"color: #808000; text-decoration-color: #808000; font-weight: bold\"> </span>interest rate while making minimum payments on others. <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"color: #808000; text-decoration-color: #808000; font-weight: bold\"> • </span>With a surplus of $650, allocate a significant portion of this towards the credit card debt. For example, <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"color: #808000; text-decoration-color: #808000; font-weight: bold\"> </span>you could pay $400 towards the credit card debt (including the $50 minimum payment), which would help <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"color: #808000; text-decoration-color: #808000; font-weight: bold\"> </span>reduce the principal faster and save on interest. <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"color: #808000; text-decoration-color: #808000; font-weight: bold\"> 2 </span><span style=\"font-weight: bold\">Review and Adjust Expenses:</span> <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"color: #808000; text-decoration-color: #808000; font-weight: bold\"> • </span><span style=\"font-weight: bold\">Housing:</span> At $1200, housing is a significant portion of your expenses. If possible, explore options to <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"color: #808000; text-decoration-color: #808000; font-weight: bold\"> </span>reduce this cost, such as negotiating rent, finding a roommate, or moving to a less expensive place. <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"color: #808000; text-decoration-color: #808000; font-weight: bold\"> • </span><span style=\"font-weight: bold\">Food:</span> Consider meal planning, cooking at home, and reducing dining out to lower the $400 food expense. <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"color: #808000; text-decoration-color: #808000; font-weight: bold\"> • </span><span style=\"font-weight: bold\">Entertainment:</span> At $150, see if you can cut back on discretionary spending. Look for free or low-cost <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"color: #808000; text-decoration-color: #808000; font-weight: bold\"> </span>entertainment options. <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"color: #808000; text-decoration-color: #808000; font-weight: bold\"> • </span><span style=\"font-weight: bold\">Other Expenses:</span> Review the $100 in 'Other' expenses to identify any non-essential spending that can be <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"color: #808000; text-decoration-color: #808000; font-weight: bold\"> </span>reduced or eliminated. <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"color: #808000; text-decoration-color: #808000; font-weight: bold\"> 3 </span><span style=\"font-weight: bold\">Increase Savings:</span> <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"color: #808000; text-decoration-color: #808000; font-weight: bold\"> • </span>While you are already saving $300 monthly, consider increasing this amount once the high-interest debt is <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"color: #808000; text-decoration-color: #808000; font-weight: bold\"> </span>paid off. Building an emergency fund should be a priority to cover 3-6 months of expenses. <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"color: #808000; text-decoration-color: #808000; font-weight: bold\"> 4 </span><span style=\"font-weight: bold\">Boost Income:</span> <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"color: #808000; text-decoration-color: #808000; font-weight: bold\"> • </span>Explore opportunities to increase your income, such as taking on a part-time job, freelancing, or selling <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"color: #808000; text-decoration-color: #808000; font-weight: bold\"> </span>unused items. Any additional income can accelerate debt repayment and increase savings. <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"color: #808000; text-decoration-color: #808000; font-weight: bold\"> 5 </span><span style=\"font-weight: bold\">Monitor and Adjust:</span> <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"color: #808000; text-decoration-color: #808000; font-weight: bold\"> • </span>Regularly review your budget and expenses to ensure you are on track with your financial goals. Adjust <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"color: #808000; text-decoration-color: #808000; font-weight: bold\"> </span>your plan as needed to accommodate changes in income or expenses. <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"color: #808000; text-decoration-color: #808000; font-weight: bold\"> 6 </span><span style=\"font-weight: bold\">Consider Debt Consolidation:</span> <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"color: #808000; text-decoration-color: #808000; font-weight: bold\"> • </span>If you have a good credit score, look into consolidating your credit card debt into a lower-interest <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"color: #808000; text-decoration-color: #808000; font-weight: bold\"> </span>personal loan. This could reduce your overall interest payments and simplify your debt repayment process. <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> By implementing these recommendations, you can effectively manage your finances, reduce debt, and work towards <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> achieving greater financial stability. <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯</span>\n",
|
||||
"</pre>\n"
|
||||
],
|
||||
"text/plain": [
|
||||
"\u001b[36m╭─\u001b[0m\u001b[36m──────────────────────────────────────────────────\u001b[0m\u001b[36m Response \u001b[0m\u001b[36m───────────────────────────────────────────────────\u001b[0m\u001b[36m─╮\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m Based on the provided financial summary, here are some actionable recommendations to help manage your finances \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m more effectively and reduce your debt: \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m \u001b[1;33m 1 \u001b[0m\u001b[1mPrioritize Debt Repayment:\u001b[0m \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m \u001b[1;33m \u001b[0m\u001b[1;33m • \u001b[0mFocus on paying off the high-interest debt first, which is the credit card debt with an 18% interest \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m \u001b[1;33m \u001b[0m\u001b[1;33m \u001b[0mrate. Consider using the debt avalanche method, where you pay extra towards the debt with the highest \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m \u001b[1;33m \u001b[0m\u001b[1;33m \u001b[0minterest rate while making minimum payments on others. \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m \u001b[1;33m \u001b[0m\u001b[1;33m • \u001b[0mWith a surplus of $650, allocate a significant portion of this towards the credit card debt. For example, \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m \u001b[1;33m \u001b[0m\u001b[1;33m \u001b[0myou could pay $400 towards the credit card debt (including the $50 minimum payment), which would help \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m \u001b[1;33m \u001b[0m\u001b[1;33m \u001b[0mreduce the principal faster and save on interest. \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m \u001b[1;33m 2 \u001b[0m\u001b[1mReview and Adjust Expenses:\u001b[0m \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m \u001b[1;33m \u001b[0m\u001b[1;33m • \u001b[0m\u001b[1mHousing:\u001b[0m At $1200, housing is a significant portion of your expenses. If possible, explore options to \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m \u001b[1;33m \u001b[0m\u001b[1;33m \u001b[0mreduce this cost, such as negotiating rent, finding a roommate, or moving to a less expensive place. \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m \u001b[1;33m \u001b[0m\u001b[1;33m • \u001b[0m\u001b[1mFood:\u001b[0m Consider meal planning, cooking at home, and reducing dining out to lower the $400 food expense. \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m \u001b[1;33m \u001b[0m\u001b[1;33m • \u001b[0m\u001b[1mEntertainment:\u001b[0m At $150, see if you can cut back on discretionary spending. Look for free or low-cost \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m \u001b[1;33m \u001b[0m\u001b[1;33m \u001b[0mentertainment options. \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m \u001b[1;33m \u001b[0m\u001b[1;33m • \u001b[0m\u001b[1mOther Expenses:\u001b[0m Review the $100 in 'Other' expenses to identify any non-essential spending that can be \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m \u001b[1;33m \u001b[0m\u001b[1;33m \u001b[0mreduced or eliminated. \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m \u001b[1;33m 3 \u001b[0m\u001b[1mIncrease Savings:\u001b[0m \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m \u001b[1;33m \u001b[0m\u001b[1;33m • \u001b[0mWhile you are already saving $300 monthly, consider increasing this amount once the high-interest debt is \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m \u001b[1;33m \u001b[0m\u001b[1;33m \u001b[0mpaid off. Building an emergency fund should be a priority to cover 3-6 months of expenses. \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m \u001b[1;33m 4 \u001b[0m\u001b[1mBoost Income:\u001b[0m \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m \u001b[1;33m \u001b[0m\u001b[1;33m • \u001b[0mExplore opportunities to increase your income, such as taking on a part-time job, freelancing, or selling \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m \u001b[1;33m \u001b[0m\u001b[1;33m \u001b[0munused items. Any additional income can accelerate debt repayment and increase savings. \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m \u001b[1;33m 5 \u001b[0m\u001b[1mMonitor and Adjust:\u001b[0m \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m \u001b[1;33m \u001b[0m\u001b[1;33m • \u001b[0mRegularly review your budget and expenses to ensure you are on track with your financial goals. Adjust \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m \u001b[1;33m \u001b[0m\u001b[1;33m \u001b[0myour plan as needed to accommodate changes in income or expenses. \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m \u001b[1;33m 6 \u001b[0m\u001b[1mConsider Debt Consolidation:\u001b[0m \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m \u001b[1;33m \u001b[0m\u001b[1;33m • \u001b[0mIf you have a good credit score, look into consolidating your credit card debt into a lower-interest \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m \u001b[1;33m \u001b[0m\u001b[1;33m \u001b[0mpersonal loan. This could reduce your overall interest payments and simplify your debt repayment process. \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m By implementing these recommendations, you can effectively manage your finances, reduce debt, and work towards \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m achieving greater financial stability. \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯\u001b[0m\n"
|
||||
]
|
||||
},
|
||||
"metadata": {},
|
||||
"output_type": "display_data"
|
||||
},
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"=== Financial Coaching Agent Recommendations ===\n",
|
||||
"Based on the provided financial summary, here are some actionable recommendations to help manage your finances more effectively and reduce your debt:\n",
|
||||
"\n",
|
||||
"1. **Prioritize Debt Repayment:**\n",
|
||||
" - Focus on paying off the high-interest debt first, which is the credit card debt with an 18% interest rate. Consider using the debt avalanche method, where you pay extra towards the debt with the highest interest rate while making minimum payments on others.\n",
|
||||
" - With a surplus of $650, allocate a significant portion of this towards the credit card debt. For example, you could pay $400 towards the credit card debt (including the $50 minimum payment), which would help reduce the principal faster and save on interest.\n",
|
||||
"\n",
|
||||
"2. **Review and Adjust Expenses:**\n",
|
||||
" - **Housing:** At $1200, housing is a significant portion of your expenses. If possible, explore options to reduce this cost, such as negotiating rent, finding a roommate, or moving to a less expensive place.\n",
|
||||
" - **Food:** Consider meal planning, cooking at home, and reducing dining out to lower the $400 food expense.\n",
|
||||
" - **Entertainment:** At $150, see if you can cut back on discretionary spending. Look for free or low-cost entertainment options.\n",
|
||||
" - **Other Expenses:** Review the $100 in 'Other' expenses to identify any non-essential spending that can be reduced or eliminated.\n",
|
||||
"\n",
|
||||
"3. **Increase Savings:**\n",
|
||||
" - While you are already saving $300 monthly, consider increasing this amount once the high-interest debt is paid off. Building an emergency fund should be a priority to cover 3-6 months of expenses.\n",
|
||||
"\n",
|
||||
"4. **Boost Income:**\n",
|
||||
" - Explore opportunities to increase your income, such as taking on a part-time job, freelancing, or selling unused items. Any additional income can accelerate debt repayment and increase savings.\n",
|
||||
"\n",
|
||||
"5. **Monitor and Adjust:**\n",
|
||||
" - Regularly review your budget and expenses to ensure you are on track with your financial goals. Adjust your plan as needed to accommodate changes in income or expenses.\n",
|
||||
"\n",
|
||||
"6. **Consider Debt Consolidation:**\n",
|
||||
" - If you have a good credit score, look into consolidating your credit card debt into a lower-interest personal loan. This could reduce your overall interest payments and simplify your debt repayment process.\n",
|
||||
"\n",
|
||||
"By implementing these recommendations, you can effectively manage your finances, reduce debt, and work towards achieving greater financial stability.\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"from praisonaiagents import Agent\n",
|
||||
"\n",
|
||||
"# Dummy data for CI/public use\n",
|
||||
"dummy_financial_data = {\n",
|
||||
" \"monthly_income\": 3000,\n",
|
||||
" \"expenses\": {\n",
|
||||
" \"Housing\": 1200,\n",
|
||||
" \"Food\": 400,\n",
|
||||
" \"Transportation\": 200,\n",
|
||||
" \"Entertainment\": 150,\n",
|
||||
" \"Savings\": 300,\n",
|
||||
" \"Other\": 100\n",
|
||||
" },\n",
|
||||
" \"debts\": [\n",
|
||||
" {\"name\": \"Credit Card\", \"amount\": 2000, \"interest_rate\": 18.0, \"min_payment\": 50},\n",
|
||||
" {\"name\": \"Student Loan\", \"amount\": 8000, \"interest_rate\": 5.0, \"min_payment\": 100}\n",
|
||||
" ]\n",
|
||||
"}\n",
|
||||
"\n",
|
||||
"income = dummy_financial_data[\"monthly_income\"]\n",
|
||||
"expenses = dummy_financial_data[\"expenses\"]\n",
|
||||
"debts = dummy_financial_data[\"debts\"]\n",
|
||||
"\n",
|
||||
"tool = FinancialSummaryTool(income, expenses, debts)\n",
|
||||
"summary = tool.summary()\n",
|
||||
"\n",
|
||||
"if not is_valid_key(OPENAI_API_KEY, \"sk\"):\n",
|
||||
" print(\"API key not set or is a placeholder. Using dummy recommendations for CI/testing.\")\n",
|
||||
" recommendations = \"\"\"\n",
|
||||
" - Review your monthly expenses and identify areas to cut back.\n",
|
||||
" - Increase your monthly savings by at least 10%.\n",
|
||||
" - Pay off high-interest debts first (e.g., Credit Card).\n",
|
||||
" - Build an emergency fund covering at least 3-6 months of expenses.\n",
|
||||
" \"\"\"\n",
|
||||
"else:\n",
|
||||
" prompt = f\"\"\"\n",
|
||||
" You are a financial coach. Analyze the following summary and provide actionable recommendations:\n",
|
||||
" - Monthly income: ${summary['surplus'] + summary['total_expenses']}\n",
|
||||
" - Total expenses: ${summary['total_expenses']}\n",
|
||||
" - Surplus: ${summary['surplus']}\n",
|
||||
" - Total debt: ${summary['total_debt']}\n",
|
||||
" - Expense breakdown: {summary['expense_breakdown']}\n",
|
||||
" - Debts: {summary['debts']}\n",
|
||||
" \"\"\"\n",
|
||||
" agent = Agent(\n",
|
||||
" name=\"Financial Coaching Agent\",\n",
|
||||
" api_key=OPENAI_API_KEY\n",
|
||||
" )\n",
|
||||
" # Use start(prompt) instead of run()\n",
|
||||
" recommendations = agent.start(prompt)\n",
|
||||
"\n",
|
||||
"print(\"=== Financial Coaching Agent Recommendations ===\")\n",
|
||||
"print(recommendations)"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"colab": {
|
||||
"provenance": []
|
||||
},
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"name": "python"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 0
|
||||
}
|
||||
@@ -0,0 +1,573 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "vUS5f8IhI4Iw"
|
||||
},
|
||||
"source": [
|
||||
"# Air Quality Analysis Agent using PraisonAIAgents"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "IPiJvwVgI5hK"
|
||||
},
|
||||
"source": [
|
||||
"## Description\n",
|
||||
"\n",
|
||||
"This notebook demonstrates how to build an Air Quality Analysis Agent using the `praisonaiagents` library. \n",
|
||||
"The agent retrieves real-time air quality data for a specified location, analyzes the results, and provides actionable insights or health recommendations. \n",
|
||||
"You will learn how to set up the environment, configure API keys, use custom tools, and orchestrate the agent workflow with a YAML prompt."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "oqdL8WpNTKu5"
|
||||
},
|
||||
"source": [
|
||||
"[](https://colab.research.google.com/github/MervinPraison/PraisonAI/blob/main/examples/cookbooks/Health_Fitness_Agents/Air_Quality_Analysis_Agent.ipynb)\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "p7CFp0tkJKmU"
|
||||
},
|
||||
"source": [
|
||||
"# Dependencies"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"id": "q6Aq57bqJKFc"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"!pip install praisonaiagents firecrawl requests"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "NLJn9uGVJldu"
|
||||
},
|
||||
"source": [
|
||||
"# Set up API Key"
|
||||
]
|
||||
},{
|
||||
"cell_type": "code",
|
||||
"execution_count": 32,
|
||||
"metadata": {
|
||||
"id": "ZxHL7mJYJpVb"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Replace with your actual API keys\n",
|
||||
"FIRECRAWL_API_KEY = \"fc-...\" # Your Firecrawl API key\n",
|
||||
"OPENAI_API_KEY = \"sk-...\" # Your OpenAI API key\n",
|
||||
"\n",
|
||||
"import os\n",
|
||||
"os.environ[\"FIRECRAWL_API_KEY\"] = FIRECRAWL_API_KEY\n",
|
||||
"os.environ[\"OPENAI_API_KEY\"] = OPENAI_API_KEY\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "eVb00IhbJ60M"
|
||||
},
|
||||
"source": [
|
||||
"# Tools"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 33,
|
||||
"metadata": {
|
||||
"id": "3YgwDwyFLXlU"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import requests\n",
|
||||
"from firecrawl import FirecrawlApp\n",
|
||||
"from typing import Dict\n",
|
||||
"\n",
|
||||
"class AQIDataFetcher:\n",
|
||||
" def __init__(self, firecrawl_key: str):\n",
|
||||
" self.firecrawl = FirecrawlApp(api_key=firecrawl_key)\n",
|
||||
"\n",
|
||||
" def fetch(self, country: str, state: str, city: str) -> Dict:\n",
|
||||
" country_clean = country.lower().replace(' ', '-')\n",
|
||||
" city_clean = city.lower().replace(' ', '-')\n",
|
||||
" if not state or state.lower() == 'none':\n",
|
||||
" url = f\"https://www.aqi.in/dashboard/{country_clean}/{city_clean}\"\n",
|
||||
" else:\n",
|
||||
" state_clean = state.lower().replace(' ', '-')\n",
|
||||
" url = f\"https://www.aqi.in/dashboard/{country_clean}/{state_clean}/{city_clean}\"\n",
|
||||
"\n",
|
||||
" # Check if the URL is valid and reachable\n",
|
||||
" print(f\"Testing URL: {url}\")\n",
|
||||
" try:\n",
|
||||
" resp = requests.get(url)\n",
|
||||
" print(f\"Status code: {resp.status_code}\")\n",
|
||||
" if resp.status_code != 200:\n",
|
||||
" print(f\"URL not reachable: {url} (status code: {resp.status_code})\")\n",
|
||||
" return None\n",
|
||||
" except Exception as e:\n",
|
||||
" print(f\"Error: {e}\")\n",
|
||||
" return None\n",
|
||||
"\n",
|
||||
" schema = {\n",
|
||||
" \"type\": \"object\",\n",
|
||||
" \"properties\": {\n",
|
||||
" \"aqi\": {\"type\": \"number\", \"description\": \"Air Quality Index\"},\n",
|
||||
" \"temperature\": {\"type\": \"number\", \"description\": \"Temperature in degrees Celsius\"},\n",
|
||||
" \"humidity\": {\"type\": \"number\", \"description\": \"Humidity percentage\"},\n",
|
||||
" \"wind_speed\": {\"type\": \"number\", \"description\": \"Wind speed in kilometers per hour\"},\n",
|
||||
" \"pm25\": {\"type\": \"number\", \"description\": \"Particulate Matter 2.5 micrometers\"},\n",
|
||||
" \"pm10\": {\"type\": \"number\", \"description\": \"Particulate Matter 10 micrometers\"},\n",
|
||||
" \"co\": {\"type\": \"number\", \"description\": \"Carbon Monoxide level\"}\n",
|
||||
" },\n",
|
||||
" \"required\": [\"aqi\", \"temperature\", \"humidity\", \"wind_speed\", \"pm25\", \"pm10\", \"co\"]\n",
|
||||
" }\n",
|
||||
"\n",
|
||||
" response = self.firecrawl.extract(\n",
|
||||
" urls=[f\"{url}/*\"],\n",
|
||||
" prompt='Extract the current real-time AQI, temperature, humidity, wind speed, PM2.5, PM10, and CO levels from the page. Also extract the timestamp of the data.',\n",
|
||||
" schema=schema\n",
|
||||
" )\n",
|
||||
" return response"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "3sUNJChKOVUm"
|
||||
},
|
||||
"source": [
|
||||
"# YAML Prompt"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 34,
|
||||
"metadata": {
|
||||
"colab": {
|
||||
"base_uri": "https://localhost:8080/"
|
||||
},
|
||||
"id": "0G9tLj0nJ8B_",
|
||||
"outputId": "61e66fe7-df17-4d2d-ad27-a9f4466298a4"
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"{'agent': {'name': 'Air Quality Health Advisor', 'description': 'An agent that analyzes real-time air quality data for a given location and provides personalized health recommendations based on user context.\\n', 'tools': [{'name': 'AQIDataFetcher', 'description': 'Fetches AQI and weather data for a specified city, state, and country using Firecrawl.'}], 'workflow': [{'step': \"Fetch AQI data for the user's location using AQIDataFetcher.\"}, {'step': 'Analyze AQI and weather data.'}, {'step': \"Consider user's medical conditions and planned activity.\"}, {'step': 'Generate health and activity recommendations.'}]}, 'inputs': ['city', 'state', 'country', 'medical_conditions', 'planned_activity'], 'outputs': ['recommendations']}\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"import yaml\n",
|
||||
"\n",
|
||||
"yaml_prompt = \"\"\"\n",
|
||||
"agent:\n",
|
||||
" name: Air Quality Health Advisor\n",
|
||||
" description: |\n",
|
||||
" An agent that analyzes real-time air quality data for a given location and provides personalized health recommendations based on user context.\n",
|
||||
" tools:\n",
|
||||
" - name: AQIDataFetcher\n",
|
||||
" description: Fetches AQI and weather data for a specified city, state, and country using Firecrawl.\n",
|
||||
" workflow:\n",
|
||||
" - step: Fetch AQI data for the user's location using AQIDataFetcher.\n",
|
||||
" - step: Analyze AQI and weather data.\n",
|
||||
" - step: Consider user's medical conditions and planned activity.\n",
|
||||
" - step: Generate health and activity recommendations.\n",
|
||||
"inputs:\n",
|
||||
" - city\n",
|
||||
" - state\n",
|
||||
" - country\n",
|
||||
" - medical_conditions\n",
|
||||
" - planned_activity\n",
|
||||
"outputs:\n",
|
||||
" - recommendations\n",
|
||||
"\"\"\"\n",
|
||||
"\n",
|
||||
"print(yaml.safe_load(yaml_prompt))"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "2HIPkoUyKEY-"
|
||||
},
|
||||
"source": [
|
||||
"# Main"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 40,
|
||||
"metadata": {
|
||||
"colab": {
|
||||
"base_uri": "https://localhost:8080/",
|
||||
"height": 1000,
|
||||
"referenced_widgets": [
|
||||
"4c2bac52ad444499b362978d8fe92d97",
|
||||
"5203e4d9bd3c47f09d2f204c7f1e078f"
|
||||
]
|
||||
},
|
||||
"id": "UQ4sHVW0KFp-",
|
||||
"outputId": "4efe39ea-c924-41e9-cc66-f4894e367280"
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Testing URL: https://www.aqi.in/dashboard/india/maharashtra/mumbai\n",
|
||||
"Status code: 200\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"data": {
|
||||
"text/html": [
|
||||
"<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\"><span style=\"color: #d2e3c8; text-decoration-color: #d2e3c8\">╭─ </span><span style=\"color: #d2e3c8; text-decoration-color: #d2e3c8; font-weight: bold\">Agent Info</span><span style=\"color: #d2e3c8; text-decoration-color: #d2e3c8\"> ────────────────────────────────────────────────────────────────────────────────────────────────────╮</span>\n",
|
||||
"<span style=\"color: #d2e3c8; text-decoration-color: #d2e3c8\">│</span> <span style=\"color: #d2e3c8; text-decoration-color: #d2e3c8\">│</span>\n",
|
||||
"<span style=\"color: #d2e3c8; text-decoration-color: #d2e3c8\">│</span> <span style=\"color: #ff9b9b; text-decoration-color: #ff9b9b; font-weight: bold\">👤 Agent:</span> <span style=\"color: #ffe5e5; text-decoration-color: #ffe5e5\">Air Quality Health Advisor</span> <span style=\"color: #d2e3c8; text-decoration-color: #d2e3c8\">│</span>\n",
|
||||
"<span style=\"color: #d2e3c8; text-decoration-color: #d2e3c8\">│</span> <span style=\"color: #b4b4b3; text-decoration-color: #b4b4b3; font-weight: bold\">Role:</span> <span style=\"color: #ffe5e5; text-decoration-color: #ffe5e5\">Assistant</span> <span style=\"color: #d2e3c8; text-decoration-color: #d2e3c8\">│</span>\n",
|
||||
"<span style=\"color: #d2e3c8; text-decoration-color: #d2e3c8\">│</span> <span style=\"color: #d2e3c8; text-decoration-color: #d2e3c8\">│</span>\n",
|
||||
"<span style=\"color: #d2e3c8; text-decoration-color: #d2e3c8\">╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯</span>\n",
|
||||
"</pre>\n"
|
||||
],
|
||||
"text/plain": [
|
||||
"\u001b[38;2;210;227;200m╭─\u001b[0m\u001b[38;2;210;227;200m \u001b[0m\u001b[1;38;2;210;227;200mAgent Info\u001b[0m\u001b[38;2;210;227;200m \u001b[0m\u001b[38;2;210;227;200m───────────────────────────────────────────────────────────────────────────────────────────────────\u001b[0m\u001b[38;2;210;227;200m─╮\u001b[0m\n",
|
||||
"\u001b[38;2;210;227;200m│\u001b[0m \u001b[38;2;210;227;200m│\u001b[0m\n",
|
||||
"\u001b[38;2;210;227;200m│\u001b[0m \u001b[1;38;2;255;155;155m👤 Agent:\u001b[0m \u001b[38;2;255;229;229mAir Quality Health Advisor\u001b[0m \u001b[38;2;210;227;200m│\u001b[0m\n",
|
||||
"\u001b[38;2;210;227;200m│\u001b[0m \u001b[1;38;2;180;180;179mRole:\u001b[0m \u001b[38;2;255;229;229mAssistant\u001b[0m \u001b[38;2;210;227;200m│\u001b[0m\n",
|
||||
"\u001b[38;2;210;227;200m│\u001b[0m \u001b[38;2;210;227;200m│\u001b[0m\n",
|
||||
"\u001b[38;2;210;227;200m╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯\u001b[0m\n"
|
||||
]
|
||||
},
|
||||
"metadata": {},
|
||||
"output_type": "display_data"
|
||||
},
|
||||
{
|
||||
"data": {
|
||||
"application/vnd.jupyter.widget-view+json": {
|
||||
"model_id": "4c2bac52ad444499b362978d8fe92d97",
|
||||
"version_major": 2,
|
||||
"version_minor": 0
|
||||
},
|
||||
"text/plain": [
|
||||
"Output()"
|
||||
]
|
||||
},
|
||||
"metadata": {},
|
||||
"output_type": "display_data"
|
||||
},
|
||||
{
|
||||
"data": {
|
||||
"text/html": [
|
||||
"<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\"></pre>\n"
|
||||
],
|
||||
"text/plain": []
|
||||
},
|
||||
"metadata": {},
|
||||
"output_type": "display_data"
|
||||
},
|
||||
{
|
||||
"data": {
|
||||
"text/html": [
|
||||
"<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\">\n",
|
||||
"</pre>\n"
|
||||
],
|
||||
"text/plain": [
|
||||
"\n"
|
||||
]
|
||||
},
|
||||
"metadata": {},
|
||||
"output_type": "display_data"
|
||||
},
|
||||
{
|
||||
"data": {
|
||||
"text/html": [
|
||||
"<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\"><span style=\"color: #7f7f7f; text-decoration-color: #7f7f7f\">Response generated in 10.8s</span>\n",
|
||||
"</pre>\n"
|
||||
],
|
||||
"text/plain": [
|
||||
"\u001b[2mResponse generated in 10.8s\u001b[0m\n"
|
||||
]
|
||||
},
|
||||
"metadata": {},
|
||||
"output_type": "display_data"
|
||||
},
|
||||
{
|
||||
"data": {
|
||||
"text/html": [
|
||||
"<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\"><span style=\"color: #008080; text-decoration-color: #008080\">╭───────────────────────────────────────────────────── Task ──────────────────────────────────────────────────────╮</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> You are an expert health advisor using the GPT-4o Mini model. <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"background-color: #272822\"> </span> <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"background-color: #272822\"> </span><span style=\"color: #f8f8f2; text-decoration-color: #f8f8f2; background-color: #272822\">Based on the following air quality conditions in Mumbai, Maharashtra, India:</span><span style=\"background-color: #272822\"> </span> <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"background-color: #272822\"> </span><span style=\"color: #f8f8f2; text-decoration-color: #f8f8f2; background-color: #272822\">- Overall AQI: 75</span><span style=\"background-color: #272822\"> </span> <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"background-color: #272822\"> </span><span style=\"color: #f8f8f2; text-decoration-color: #f8f8f2; background-color: #272822\">- PM2.5 Level: 22 µg/m³</span><span style=\"background-color: #272822\"> </span> <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"background-color: #272822\"> </span><span style=\"color: #f8f8f2; text-decoration-color: #f8f8f2; background-color: #272822\">- PM10 Level: 60 µg/m³</span><span style=\"background-color: #272822\"> </span> <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"background-color: #272822\"> </span><span style=\"color: #f8f8f2; text-decoration-color: #f8f8f2; background-color: #272822\">- CO Level: 650 ppb</span><span style=\"background-color: #272822\"> </span> <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"background-color: #272822\"> </span> <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"background-color: #272822\"> </span><span style=\"color: #f8f8f2; text-decoration-color: #f8f8f2; background-color: #272822\">Weather conditions:</span><span style=\"background-color: #272822\"> </span> <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"background-color: #272822\"> </span><span style=\"color: #f8f8f2; text-decoration-color: #f8f8f2; background-color: #272822\">- Temperature: 28°C</span><span style=\"background-color: #272822\"> </span> <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"background-color: #272822\"> </span><span style=\"color: #f8f8f2; text-decoration-color: #f8f8f2; background-color: #272822\">- Humidity: 84%</span><span style=\"background-color: #272822\"> </span> <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"background-color: #272822\"> </span><span style=\"color: #f8f8f2; text-decoration-color: #f8f8f2; background-color: #272822\">- Wind Speed: 30 km/h</span><span style=\"background-color: #272822\"> </span> <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"background-color: #272822\"> </span> <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"background-color: #272822\"> </span><span style=\"color: #f8f8f2; text-decoration-color: #f8f8f2; background-color: #272822\">User's Context:</span><span style=\"background-color: #272822\"> </span> <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"background-color: #272822\"> </span><span style=\"color: #f8f8f2; text-decoration-color: #f8f8f2; background-color: #272822\">- Medical Conditions: asthma</span><span style=\"background-color: #272822\"> </span> <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"background-color: #272822\"> </span><span style=\"color: #f8f8f2; text-decoration-color: #f8f8f2; background-color: #272822\">- Planned Activity: morning jog for 2 hours</span><span style=\"background-color: #272822\"> </span> <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"background-color: #272822\"> </span> <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"background-color: #272822\"> </span><span style=\"color: #f8f8f2; text-decoration-color: #f8f8f2; background-color: #272822\">**Comprehensive Health Recommendations:**</span><span style=\"background-color: #272822\"> </span> <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"background-color: #272822\"> </span><span style=\"color: #f8f8f2; text-decoration-color: #f8f8f2; background-color: #272822\">1. **Impact of Current Air Quality on Health:**</span><span style=\"background-color: #272822\"> </span> <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"background-color: #272822\"> </span><span style=\"color: #f8f8f2; text-decoration-color: #f8f8f2; background-color: #272822\">2. **Necessary Safety Precautions for Planned Activity:**</span><span style=\"background-color: #272822\"> </span> <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"background-color: #272822\"> </span><span style=\"color: #f8f8f2; text-decoration-color: #f8f8f2; background-color: #272822\">3. **Advisability of Planned Activity:**</span><span style=\"background-color: #272822\"> </span> <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"background-color: #272822\"> </span><span style=\"color: #f8f8f2; text-decoration-color: #f8f8f2; background-color: #272822\">4. **Best Time to Conduct the Activity:**</span><span style=\"background-color: #272822\"> </span> <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"background-color: #272822\"> </span> <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯</span>\n",
|
||||
"</pre>\n"
|
||||
],
|
||||
"text/plain": [
|
||||
"\u001b[36m╭─\u001b[0m\u001b[36m────────────────────────────────────────────────────\u001b[0m\u001b[36m Task \u001b[0m\u001b[36m─────────────────────────────────────────────────────\u001b[0m\u001b[36m─╮\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m You are an expert health advisor using the GPT-4o Mini model. \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34mBased on the following air quality conditions in Mumbai, Maharashtra, India:\u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m- Overall AQI: 75\u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m- PM2.5 Level: 22 µg/m³\u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m- PM10 Level: 60 µg/m³\u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m- CO Level: 650 ppb\u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34mWeather conditions:\u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m- Temperature: 28°C\u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m- Humidity: 84%\u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m- Wind Speed: 30 km/h\u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34mUser's Context:\u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m- Medical Conditions: asthma\u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m- Planned Activity: morning jog for 2 hours\u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m**Comprehensive Health Recommendations:**\u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m1. **Impact of Current Air Quality on Health:**\u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m2. **Necessary Safety Precautions for Planned Activity:**\u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m3. **Advisability of Planned Activity:**\u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m4. **Best Time to Conduct the Activity:**\u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯\u001b[0m\n"
|
||||
]
|
||||
},
|
||||
"metadata": {},
|
||||
"output_type": "display_data"
|
||||
},
|
||||
{
|
||||
"data": {
|
||||
"text/html": [
|
||||
"<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\"><span style=\"color: #008080; text-decoration-color: #008080\">╭─────────────────────────────────────────────────── Response ────────────────────────────────────────────────────╮</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> Certainly! Here are the comprehensive health recommendations based on the provided conditions: <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"color: #808000; text-decoration-color: #808000; font-weight: bold\"> 1 </span><span style=\"font-weight: bold\">Impact of Current Air Quality on Health:</span> <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"color: #808000; text-decoration-color: #808000; font-weight: bold\"> • </span>The overall AQI of 75 is considered \"Moderate.\" This level is generally acceptable for most individuals, <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"color: #808000; text-decoration-color: #808000; font-weight: bold\"> </span>but sensitive groups, such as those with asthma, may experience some respiratory discomfort. <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"color: #808000; text-decoration-color: #808000; font-weight: bold\"> • </span>PM2.5 and PM10 levels are within moderate ranges, which can still pose a risk for people with <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"color: #808000; text-decoration-color: #808000; font-weight: bold\"> </span>pre-existing respiratory conditions like asthma. <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"color: #808000; text-decoration-color: #808000; font-weight: bold\"> • </span>The CO level of 650 ppb is not typically concerning, but it is important to be cautious as individuals <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"color: #808000; text-decoration-color: #808000; font-weight: bold\"> </span>with asthma may be more sensitive to pollutants. <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"color: #808000; text-decoration-color: #808000; font-weight: bold\"> 2 </span><span style=\"font-weight: bold\">Necessary Safety Precautions for Planned Activity:</span> <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"color: #808000; text-decoration-color: #808000; font-weight: bold\"> • </span>Consider wearing a mask designed to filter out particulate matter to reduce inhalation of pollutants. <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"color: #808000; text-decoration-color: #808000; font-weight: bold\"> • </span>Carry a rescue inhaler and any other prescribed asthma medication. <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"color: #808000; text-decoration-color: #808000; font-weight: bold\"> • </span>Stay hydrated, as high humidity can exacerbate asthma symptoms. <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"color: #808000; text-decoration-color: #808000; font-weight: bold\"> • </span>Monitor your breathing and be prepared to stop the activity if you experience any respiratory distress. <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"color: #808000; text-decoration-color: #808000; font-weight: bold\"> • </span>Choose a route with less traffic to minimize exposure to vehicle emissions. <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"color: #808000; text-decoration-color: #808000; font-weight: bold\"> 3 </span><span style=\"font-weight: bold\">Advisability of Planned Activity:</span> <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"color: #808000; text-decoration-color: #808000; font-weight: bold\"> • </span>Given the moderate AQI and the user's asthma condition, it is advisable to proceed with caution. A 2-hour <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"color: #808000; text-decoration-color: #808000; font-weight: bold\"> </span>jog may be too strenuous under these conditions, so consider reducing the duration or intensity of the <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"color: #808000; text-decoration-color: #808000; font-weight: bold\"> </span>jog. <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"color: #808000; text-decoration-color: #808000; font-weight: bold\"> • </span>It may be beneficial to consult with a healthcare provider to tailor the activity to your specific health <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"color: #808000; text-decoration-color: #808000; font-weight: bold\"> </span>needs. <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"color: #808000; text-decoration-color: #808000; font-weight: bold\"> 4 </span><span style=\"font-weight: bold\">Best Time to Conduct the Activity:</span> <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"color: #808000; text-decoration-color: #808000; font-weight: bold\"> • </span>Early morning hours, just after sunrise, are typically better for outdoor activities as pollution levels <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"color: #808000; text-decoration-color: #808000; font-weight: bold\"> </span>tend to be lower. <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"color: #808000; text-decoration-color: #808000; font-weight: bold\"> • </span>Avoid peak traffic times to reduce exposure to vehicle emissions. <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"color: #808000; text-decoration-color: #808000; font-weight: bold\"> • </span>Check real-time air quality updates to ensure conditions remain stable or improve before starting the <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"color: #808000; text-decoration-color: #808000; font-weight: bold\"> </span>activity. <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> By following these recommendations, you can help mitigate potential health risks while enjoying your planned <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> activity. <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯</span>\n",
|
||||
"</pre>\n"
|
||||
],
|
||||
"text/plain": [
|
||||
"\u001b[36m╭─\u001b[0m\u001b[36m──────────────────────────────────────────────────\u001b[0m\u001b[36m Response \u001b[0m\u001b[36m───────────────────────────────────────────────────\u001b[0m\u001b[36m─╮\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m Certainly! Here are the comprehensive health recommendations based on the provided conditions: \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m \u001b[1;33m 1 \u001b[0m\u001b[1mImpact of Current Air Quality on Health:\u001b[0m \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m \u001b[1;33m \u001b[0m\u001b[1;33m • \u001b[0mThe overall AQI of 75 is considered \"Moderate.\" This level is generally acceptable for most individuals, \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m \u001b[1;33m \u001b[0m\u001b[1;33m \u001b[0mbut sensitive groups, such as those with asthma, may experience some respiratory discomfort. \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m \u001b[1;33m \u001b[0m\u001b[1;33m • \u001b[0mPM2.5 and PM10 levels are within moderate ranges, which can still pose a risk for people with \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m \u001b[1;33m \u001b[0m\u001b[1;33m \u001b[0mpre-existing respiratory conditions like asthma. \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m \u001b[1;33m \u001b[0m\u001b[1;33m • \u001b[0mThe CO level of 650 ppb is not typically concerning, but it is important to be cautious as individuals \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m \u001b[1;33m \u001b[0m\u001b[1;33m \u001b[0mwith asthma may be more sensitive to pollutants. \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m \u001b[1;33m 2 \u001b[0m\u001b[1mNecessary Safety Precautions for Planned Activity:\u001b[0m \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m \u001b[1;33m \u001b[0m\u001b[1;33m • \u001b[0mConsider wearing a mask designed to filter out particulate matter to reduce inhalation of pollutants. \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m \u001b[1;33m \u001b[0m\u001b[1;33m • \u001b[0mCarry a rescue inhaler and any other prescribed asthma medication. \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m \u001b[1;33m \u001b[0m\u001b[1;33m • \u001b[0mStay hydrated, as high humidity can exacerbate asthma symptoms. \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m \u001b[1;33m \u001b[0m\u001b[1;33m • \u001b[0mMonitor your breathing and be prepared to stop the activity if you experience any respiratory distress. \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m \u001b[1;33m \u001b[0m\u001b[1;33m • \u001b[0mChoose a route with less traffic to minimize exposure to vehicle emissions. \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m \u001b[1;33m 3 \u001b[0m\u001b[1mAdvisability of Planned Activity:\u001b[0m \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m \u001b[1;33m \u001b[0m\u001b[1;33m • \u001b[0mGiven the moderate AQI and the user's asthma condition, it is advisable to proceed with caution. A 2-hour \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m \u001b[1;33m \u001b[0m\u001b[1;33m \u001b[0mjog may be too strenuous under these conditions, so consider reducing the duration or intensity of the \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m \u001b[1;33m \u001b[0m\u001b[1;33m \u001b[0mjog. \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m \u001b[1;33m \u001b[0m\u001b[1;33m • \u001b[0mIt may be beneficial to consult with a healthcare provider to tailor the activity to your specific health \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m \u001b[1;33m \u001b[0m\u001b[1;33m \u001b[0mneeds. \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m \u001b[1;33m 4 \u001b[0m\u001b[1mBest Time to Conduct the Activity:\u001b[0m \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m \u001b[1;33m \u001b[0m\u001b[1;33m • \u001b[0mEarly morning hours, just after sunrise, are typically better for outdoor activities as pollution levels \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m \u001b[1;33m \u001b[0m\u001b[1;33m \u001b[0mtend to be lower. \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m \u001b[1;33m \u001b[0m\u001b[1;33m • \u001b[0mAvoid peak traffic times to reduce exposure to vehicle emissions. \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m \u001b[1;33m \u001b[0m\u001b[1;33m • \u001b[0mCheck real-time air quality updates to ensure conditions remain stable or improve before starting the \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m \u001b[1;33m \u001b[0m\u001b[1;33m \u001b[0mactivity. \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m By following these recommendations, you can help mitigate potential health risks while enjoying your planned \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m activity. \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯\u001b[0m\n"
|
||||
]
|
||||
},
|
||||
"metadata": {},
|
||||
"output_type": "display_data"
|
||||
},
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"=== Air Quality Analysis Agent Recommendations ===\n",
|
||||
"Certainly! Here are the comprehensive health recommendations based on the provided conditions:\n",
|
||||
"\n",
|
||||
"1. **Impact of Current Air Quality on Health:**\n",
|
||||
" - The overall AQI of 75 is considered \"Moderate.\" This level is generally acceptable for most individuals, but sensitive groups, such as those with asthma, may experience some respiratory discomfort.\n",
|
||||
" - PM2.5 and PM10 levels are within moderate ranges, which can still pose a risk for people with pre-existing respiratory conditions like asthma.\n",
|
||||
" - The CO level of 650 ppb is not typically concerning, but it is important to be cautious as individuals with asthma may be more sensitive to pollutants.\n",
|
||||
"\n",
|
||||
"2. **Necessary Safety Precautions for Planned Activity:**\n",
|
||||
" - Consider wearing a mask designed to filter out particulate matter to reduce inhalation of pollutants.\n",
|
||||
" - Carry a rescue inhaler and any other prescribed asthma medication.\n",
|
||||
" - Stay hydrated, as high humidity can exacerbate asthma symptoms.\n",
|
||||
" - Monitor your breathing and be prepared to stop the activity if you experience any respiratory distress.\n",
|
||||
" - Choose a route with less traffic to minimize exposure to vehicle emissions.\n",
|
||||
"\n",
|
||||
"3. **Advisability of Planned Activity:**\n",
|
||||
" - Given the moderate AQI and the user's asthma condition, it is advisable to proceed with caution. A 2-hour jog may be too strenuous under these conditions, so consider reducing the duration or intensity of the jog.\n",
|
||||
" - It may be beneficial to consult with a healthcare provider to tailor the activity to your specific health needs.\n",
|
||||
"\n",
|
||||
"4. **Best Time to Conduct the Activity:**\n",
|
||||
" - Early morning hours, just after sunrise, are typically better for outdoor activities as pollution levels tend to be lower.\n",
|
||||
" - Avoid peak traffic times to reduce exposure to vehicle emissions.\n",
|
||||
" - Check real-time air quality updates to ensure conditions remain stable or improve before starting the activity.\n",
|
||||
"\n",
|
||||
"By following these recommendations, you can help mitigate potential health risks while enjoying your planned activity.\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"from praisonaiagents import Agent\n",
|
||||
"import os\n",
|
||||
"\n",
|
||||
"# User input (you can change these for other locations)\n",
|
||||
"user_city = \"Mumbai\"\n",
|
||||
"user_state = \"Maharashtra\"\n",
|
||||
"user_country = \"India\"\n",
|
||||
"user_medical_conditions = \"asthma\"\n",
|
||||
"user_planned_activity = \"morning jog for 2 hours\"\n",
|
||||
"\n",
|
||||
"aqi_fetcher = AQIDataFetcher(firecrawl_key=os.environ[\"FIRECRAWL_API_KEY\"])\n",
|
||||
"\n",
|
||||
"# Try with state, then without state, then fallback to Delhi\n",
|
||||
"aqi_data = aqi_fetcher.fetch(\n",
|
||||
" country=user_country,\n",
|
||||
" state=user_state,\n",
|
||||
" city=user_city\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"if not aqi_data or not hasattr(aqi_data, \"data\"):\n",
|
||||
" print(\"Mumbai with state failed, trying without state...\")\n",
|
||||
" aqi_data = aqi_fetcher.fetch(\n",
|
||||
" country=user_country,\n",
|
||||
" state=\"\",\n",
|
||||
" city=user_city\n",
|
||||
" )\n",
|
||||
"\n",
|
||||
"if not aqi_data or not hasattr(aqi_data, \"data\"):\n",
|
||||
" print(\"Trying Delhi, India...\")\n",
|
||||
" aqi_data = aqi_fetcher.fetch(\n",
|
||||
" country=\"India\",\n",
|
||||
" state=\"\",\n",
|
||||
" city=\"Delhi\"\n",
|
||||
" )\n",
|
||||
"\n",
|
||||
"if not aqi_data or not hasattr(aqi_data, \"data\"):\n",
|
||||
" print(\"Failed to fetch AQI data for all tried locations. Please check the URLs manually.\")\n",
|
||||
"else:\n",
|
||||
" aqi_data = aqi_data.data # Convert to dict\n",
|
||||
"\n",
|
||||
" prompt = f\"\"\"\n",
|
||||
" You are an expert health advisor using the GPT-4o Mini model.\n",
|
||||
"\n",
|
||||
" Based on the following air quality conditions in {user_city}, {user_state}, {user_country}:\n",
|
||||
" - Overall AQI: {aqi_data.get('aqi', 'N/A')}\n",
|
||||
" - PM2.5 Level: {aqi_data.get('pm25', 'N/A')} µg/m³\n",
|
||||
" - PM10 Level: {aqi_data.get('pm10', 'N/A')} µg/m³\n",
|
||||
" - CO Level: {aqi_data.get('co', 'N/A')} ppb\n",
|
||||
"\n",
|
||||
" Weather conditions:\n",
|
||||
" - Temperature: {aqi_data.get('temperature', 'N/A')}°C\n",
|
||||
" - Humidity: {aqi_data.get('humidity', 'N/A')}%\n",
|
||||
" - Wind Speed: {aqi_data.get('wind_speed', 'N/A')} km/h\n",
|
||||
"\n",
|
||||
" User's Context:\n",
|
||||
" - Medical Conditions: {user_medical_conditions or 'None'}\n",
|
||||
" - Planned Activity: {user_planned_activity}\n",
|
||||
"\n",
|
||||
" **Comprehensive Health Recommendations:**\n",
|
||||
" 1. **Impact of Current Air Quality on Health:**\n",
|
||||
" 2. **Necessary Safety Precautions for Planned Activity:**\n",
|
||||
" 3. **Advisability of Planned Activity:**\n",
|
||||
" 4. **Best Time to Conduct the Activity:**\n",
|
||||
" \"\"\"\n",
|
||||
"\n",
|
||||
" agent = Agent(\n",
|
||||
" name=\"Air Quality Health Advisor\",\n",
|
||||
" instructions=prompt,\n",
|
||||
" api_key=os.environ[\"OPENAI_API_KEY\"]\n",
|
||||
" )\n",
|
||||
"\n",
|
||||
" # Call run() with no arguments\n",
|
||||
"recommendations = agent.start(prompt)\n",
|
||||
"print(\"=== Air Quality Analysis Agent Recommendations ===\")\n",
|
||||
"print(recommendations)"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"colab": {
|
||||
"provenance": []
|
||||
},
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"name": "python"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 0
|
||||
}
|
||||
+1199
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,564 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "Z-9SQRoVyG_O"
|
||||
},
|
||||
"source": [
|
||||
"# Domain Deep Research Agent using PraisonAIAgents"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "EZYCPU_ayIMD"
|
||||
},
|
||||
"source": [
|
||||
"This notebook demonstrates a Domain Deep Research Agent using `praisonaiagents`. \n",
|
||||
"The agent performs deep research on a given topic and provides a structured report. \n",
|
||||
"The notebook is CI-friendly: it uses dummy data if API keys are not set, so all tests/checks will pass."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "taa8dcsdyxHT"
|
||||
},
|
||||
"source": [
|
||||
"[](https://colab.research.google.com/github/Dhivya-Bharathy/PraisonAI/blob/main/examples/cookbooks/Research_Knowledge_QA_Agents/Domain_Deep_Research_Agent.ipynb)\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "v0VlXFo-yKNA"
|
||||
},
|
||||
"source": [
|
||||
"# Dependencies"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"id": "t9Dw5BDryNIa"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"!pip install praisonaiagents"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "V_9FzwguyS7g"
|
||||
},
|
||||
"source": [
|
||||
"# Set up key (robust, CI-safe)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 2,
|
||||
"metadata": {
|
||||
"id": "-l0w3hmLyT47"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import os\n",
|
||||
"\n",
|
||||
"os.environ[\"OPENAI_API_KEY\"] = os.environ.get(\"OPENAI_API_KEY\", \"sk-..\")\n",
|
||||
"\n",
|
||||
"def is_valid_key(key, prefix):\n",
|
||||
" return key and key != f\"{prefix}-..\" and key.startswith(prefix)\n",
|
||||
"\n",
|
||||
"OPENAI_API_KEY = os.environ[\"OPENAI_API_KEY\"]"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "xkHGhtnmyZ3m"
|
||||
},
|
||||
"source": [
|
||||
"# Custom Tool: Dummy Deep Research Tool"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 3,
|
||||
"metadata": {
|
||||
"id": "vATC0ZOVyax0"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"class DummyDeepResearchTool:\n",
|
||||
" \"\"\"\n",
|
||||
" Custom tool to simulate deep research for CI/public use.\n",
|
||||
" \"\"\"\n",
|
||||
" def __init__(self, topic):\n",
|
||||
" self.topic = topic\n",
|
||||
"\n",
|
||||
" def research(self):\n",
|
||||
" # For demo/CI, just return a dummy report\n",
|
||||
" return f\"## Research Report on {self.topic}\\n\\n- Key finding 1 about {self.topic}\\n- Key finding 2 about {self.topic}\\n- Key finding 3 about {self.topic}\\n\""
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "t-TlO3WuyeYl"
|
||||
},
|
||||
"source": [
|
||||
"# Main (with dummy fallback, CI-safe)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 4,
|
||||
"metadata": {
|
||||
"colab": {
|
||||
"base_uri": "https://localhost:8080/",
|
||||
"height": 1000,
|
||||
"referenced_widgets": [
|
||||
"520e1878a8d64958a9b73edc91260284",
|
||||
"e6b0f40254e54f5a9200996d38ecbd10"
|
||||
]
|
||||
},
|
||||
"id": "cor8P2BlyfQt",
|
||||
"outputId": "750a1fba-d0f2-4279-a5bb-b3743db2c852"
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/html": [
|
||||
"<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\"><span style=\"color: #d2e3c8; text-decoration-color: #d2e3c8\">╭─ </span><span style=\"color: #d2e3c8; text-decoration-color: #d2e3c8; font-weight: bold\">Agent Info</span><span style=\"color: #d2e3c8; text-decoration-color: #d2e3c8\"> ────────────────────────────────────────────────────────────────────────────────────────────────────╮</span>\n",
|
||||
"<span style=\"color: #d2e3c8; text-decoration-color: #d2e3c8\">│</span> <span style=\"color: #d2e3c8; text-decoration-color: #d2e3c8\">│</span>\n",
|
||||
"<span style=\"color: #d2e3c8; text-decoration-color: #d2e3c8\">│</span> <span style=\"color: #ff9b9b; text-decoration-color: #ff9b9b; font-weight: bold\">👤 Agent:</span> <span style=\"color: #ffe5e5; text-decoration-color: #ffe5e5\">Domain Deep Research Agent</span> <span style=\"color: #d2e3c8; text-decoration-color: #d2e3c8\">│</span>\n",
|
||||
"<span style=\"color: #d2e3c8; text-decoration-color: #d2e3c8\">│</span> <span style=\"color: #b4b4b3; text-decoration-color: #b4b4b3; font-weight: bold\">Role:</span> <span style=\"color: #ffe5e5; text-decoration-color: #ffe5e5\">Assistant</span> <span style=\"color: #d2e3c8; text-decoration-color: #d2e3c8\">│</span>\n",
|
||||
"<span style=\"color: #d2e3c8; text-decoration-color: #d2e3c8\">│</span> <span style=\"color: #d2e3c8; text-decoration-color: #d2e3c8\">│</span>\n",
|
||||
"<span style=\"color: #d2e3c8; text-decoration-color: #d2e3c8\">╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯</span>\n",
|
||||
"</pre>\n"
|
||||
],
|
||||
"text/plain": [
|
||||
"\u001b[38;2;210;227;200m╭─\u001b[0m\u001b[38;2;210;227;200m \u001b[0m\u001b[1;38;2;210;227;200mAgent Info\u001b[0m\u001b[38;2;210;227;200m \u001b[0m\u001b[38;2;210;227;200m───────────────────────────────────────────────────────────────────────────────────────────────────\u001b[0m\u001b[38;2;210;227;200m─╮\u001b[0m\n",
|
||||
"\u001b[38;2;210;227;200m│\u001b[0m \u001b[38;2;210;227;200m│\u001b[0m\n",
|
||||
"\u001b[38;2;210;227;200m│\u001b[0m \u001b[1;38;2;255;155;155m👤 Agent:\u001b[0m \u001b[38;2;255;229;229mDomain Deep Research Agent\u001b[0m \u001b[38;2;210;227;200m│\u001b[0m\n",
|
||||
"\u001b[38;2;210;227;200m│\u001b[0m \u001b[1;38;2;180;180;179mRole:\u001b[0m \u001b[38;2;255;229;229mAssistant\u001b[0m \u001b[38;2;210;227;200m│\u001b[0m\n",
|
||||
"\u001b[38;2;210;227;200m│\u001b[0m \u001b[38;2;210;227;200m│\u001b[0m\n",
|
||||
"\u001b[38;2;210;227;200m╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯\u001b[0m\n"
|
||||
]
|
||||
},
|
||||
"metadata": {},
|
||||
"output_type": "display_data"
|
||||
},
|
||||
{
|
||||
"data": {
|
||||
"application/vnd.jupyter.widget-view+json": {
|
||||
"model_id": "520e1878a8d64958a9b73edc91260284",
|
||||
"version_major": 2,
|
||||
"version_minor": 0
|
||||
},
|
||||
"text/plain": [
|
||||
"Output()"
|
||||
]
|
||||
},
|
||||
"metadata": {},
|
||||
"output_type": "display_data"
|
||||
},
|
||||
{
|
||||
"data": {
|
||||
"text/html": [
|
||||
"<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\"></pre>\n"
|
||||
],
|
||||
"text/plain": []
|
||||
},
|
||||
"metadata": {},
|
||||
"output_type": "display_data"
|
||||
},
|
||||
{
|
||||
"data": {
|
||||
"text/html": [
|
||||
"<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\">\n",
|
||||
"</pre>\n"
|
||||
],
|
||||
"text/plain": [
|
||||
"\n"
|
||||
]
|
||||
},
|
||||
"metadata": {},
|
||||
"output_type": "display_data"
|
||||
},
|
||||
{
|
||||
"data": {
|
||||
"text/html": [
|
||||
"<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\"><span style=\"color: #7f7f7f; text-decoration-color: #7f7f7f\">Response generated in 25.8s</span>\n",
|
||||
"</pre>\n"
|
||||
],
|
||||
"text/plain": [
|
||||
"\u001b[2mResponse generated in 25.8s\u001b[0m\n"
|
||||
]
|
||||
},
|
||||
"metadata": {},
|
||||
"output_type": "display_data"
|
||||
},
|
||||
{
|
||||
"data": {
|
||||
"text/html": [
|
||||
"<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\"><span style=\"color: #008080; text-decoration-color: #008080\">╭───────────────────────────────────────────────────── Task ──────────────────────────────────────────────────────╮</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> You are a domain research assistant. Perform deep research on the following topic and provide a structured, <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> well-cited report: TOPIC: Recent advances in quantum computing <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯</span>\n",
|
||||
"</pre>\n"
|
||||
],
|
||||
"text/plain": [
|
||||
"\u001b[36m╭─\u001b[0m\u001b[36m────────────────────────────────────────────────────\u001b[0m\u001b[36m Task \u001b[0m\u001b[36m─────────────────────────────────────────────────────\u001b[0m\u001b[36m─╮\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m You are a domain research assistant. Perform deep research on the following topic and provide a structured, \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m well-cited report: TOPIC: Recent advances in quantum computing \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯\u001b[0m\n"
|
||||
]
|
||||
},
|
||||
"metadata": {},
|
||||
"output_type": "display_data"
|
||||
},
|
||||
{
|
||||
"data": {
|
||||
"text/html": [
|
||||
"<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\"><span style=\"color: #008080; text-decoration-color: #008080\">╭─────────────────────────────────────────────────── Response ────────────────────────────────────────────────────╮</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> ┃ <span style=\"font-weight: bold\">Recent Advances in Quantum Computing</span> ┃ <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> Quantum computing is a rapidly evolving field that leverages the principles of quantum mechanics to process <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> information in fundamentally new ways. This report highlights some of the most significant recent advances in <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> quantum computing, focusing on developments in hardware, algorithms, and applications. <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"font-weight: bold; text-decoration: underline\">1. Quantum Hardware Developments</span> <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"font-weight: bold\">1.1 Superconducting Qubits</span> <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> Superconducting qubits have been at the forefront of quantum computing hardware. Companies like IBM and Google <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> have made significant strides in increasing the coherence times and connectivity of these qubits. In 2023, IBM <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> announced the development of their 433-qubit processor, Osprey, which is part of their roadmap to achieve a <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> 1,000-qubit system by 2024 [1]. <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"font-weight: bold\">1.2 Trapped Ion Qubits</span> <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> Trapped ion technology continues to be a strong contender due to its high fidelity and long coherence times. <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> IonQ, a leader in this space, has developed systems that can execute quantum circuits with high precision. <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> Their recent advancements include the development of error-corrected logical qubits, which are crucial for <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> scalable quantum computing [2]. <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"font-weight: bold\">1.3 Photonic Quantum Computing</span> <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> Photonic quantum computing has seen breakthroughs with companies like Xanadu and PsiQuantum. Xanadu's Borealis, <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> a photonic quantum computer, demonstrated quantum advantage by solving specific problems faster than classical <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> supercomputers [3]. PsiQuantum is working towards a million-qubit photonic quantum computer, leveraging silicon <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> photonics for scalability [4]. <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"font-weight: bold; text-decoration: underline\">2. Quantum Algorithms</span> <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"font-weight: bold\">2.1 Quantum Machine Learning</span> <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> Quantum machine learning (QML) is gaining traction as researchers develop algorithms that could outperform <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> classical counterparts. Recent work has focused on hybrid quantum-classical algorithms that leverage quantum <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> speedups for specific tasks like clustering and classification [5]. <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"font-weight: bold\">2.2 Quantum Error Correction</span> <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> Error correction remains a critical challenge in quantum computing. Recent advances include the development of <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> more efficient error-correcting codes and fault-tolerant architectures. The surface code, a leading error <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> correction method, has seen improvements in its threshold and resource requirements [6]. <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"font-weight: bold\">2.3 Quantum Simulation</span> <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> Quantum simulation is one of the most promising applications of quantum computing. Recent studies have <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> demonstrated the simulation of complex quantum systems, such as chemical reactions and material properties, <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> with unprecedented accuracy [7]. <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"font-weight: bold; text-decoration: underline\">3. Applications and Industry Impact</span> <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"font-weight: bold\">3.1 Cryptography</span> <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> Quantum computing poses both threats and opportunities for cryptography. The development of quantum-resistant <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> algorithms is crucial as quantum computers could potentially break widely used encryption methods. The National <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> Institute of Standards and Technology (NIST) is in the process of standardizing post-quantum cryptographic <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> algorithms [8]. <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"font-weight: bold\">3.2 Drug Discovery</span> <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> Quantum computing is poised to revolutionize drug discovery by enabling the simulation of molecular <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> interactions at a quantum level. Companies like Qubit Pharmaceuticals and Cambridge Quantum Computing are <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> actively working on quantum algorithms for drug discovery, promising faster and more accurate predictions [9]. <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"font-weight: bold\">3.3 Optimization Problems</span> <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> Quantum computers have the potential to solve complex optimization problems more efficiently than classical <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> computers. This has significant implications for industries such as logistics, finance, and manufacturing. <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> Recent advances include the development of quantum algorithms for portfolio optimization and supply chain <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> management [10]. <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"font-weight: bold; text-decoration: underline\">4. Challenges and Future Directions</span> <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> Despite the rapid progress, several challenges remain in the field of quantum computing. These include <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> improving qubit coherence times, scaling up the number of qubits, and developing robust error correction <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> methods. Future research is likely to focus on hybrid quantum-classical systems, which combine the strengths of <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> both paradigms to tackle complex problems. <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"font-weight: bold; text-decoration: underline\">Conclusion</span> <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> Quantum computing is advancing at a remarkable pace, with significant developments in hardware, algorithms, and <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> applications. As the field continues to mature, it holds the promise of transforming industries and solving <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> problems that are currently intractable for classical computers. Continued investment in research and <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> development, along with collaboration between academia and industry, will be crucial to realizing the full <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> potential of quantum computing. <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"font-weight: bold; text-decoration: underline\">References</span> <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"color: #808000; text-decoration-color: #808000; font-weight: bold\"> 1 </span>IBM Research. (2023). IBM Quantum Roadmap. Retrieved from <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"color: #808000; text-decoration-color: #808000; font-weight: bold\"> </span>https://research.ibm.com/quantum-computing/roadmap <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"color: #808000; text-decoration-color: #808000; font-weight: bold\"> 2 </span>IonQ. (2023). IonQ's Quantum Computing Technology. Retrieved from https://ionq.com/technology <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"color: #808000; text-decoration-color: #808000; font-weight: bold\"> 3 </span>Xanadu. (2023). Borealis: A Photonic Quantum Computer. Retrieved from https://xanadu.ai/borealis <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"color: #808000; text-decoration-color: #808000; font-weight: bold\"> 4 </span>PsiQuantum. (2023). Photonic Quantum Computing. Retrieved from https://psiquantum.com/technology <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"color: #808000; text-decoration-color: #808000; font-weight: bold\"> 5 </span>Biamonte, J., et al. (2023). Quantum Machine Learning. Nature Reviews Physics. <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"color: #808000; text-decoration-color: #808000; font-weight: bold\"> 6 </span>Fowler, A. G., et al. (2023). Surface Codes: Towards Practical Quantum Computing. Physical Review A. <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"color: #808000; text-decoration-color: #808000; font-weight: bold\"> 7 </span>Aspuru-Guzik, A., et al. (2023). Quantum Simulation of Chemical Systems. Chemical Reviews. <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"color: #808000; text-decoration-color: #808000; font-weight: bold\"> 8 </span>NIST. (2023). Post-Quantum Cryptography Standardization. Retrieved from <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"color: #808000; text-decoration-color: #808000; font-weight: bold\"> </span>https://csrc.nist.gov/Projects/post-quantum-cryptography <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"color: #808000; text-decoration-color: #808000; font-weight: bold\"> 9 </span>Qubit Pharmaceuticals. (2023). Quantum Computing in Drug Discovery. Retrieved from <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"color: #808000; text-decoration-color: #808000; font-weight: bold\"> </span>https://qubit-pharmaceuticals.com/quantum-computing <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"color: #808000; text-decoration-color: #808000; font-weight: bold\"> 10 </span>Venturelli, D., et al. (2023). Quantum Optimization Algorithms. Journal of Quantum Information Processing. <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯</span>\n",
|
||||
"</pre>\n"
|
||||
],
|
||||
"text/plain": [
|
||||
"\u001b[36m╭─\u001b[0m\u001b[36m──────────────────────────────────────────────────\u001b[0m\u001b[36m Response \u001b[0m\u001b[36m───────────────────────────────────────────────────\u001b[0m\u001b[36m─╮\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m ┃ \u001b[1mRecent Advances in Quantum Computing\u001b[0m ┃ \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m Quantum computing is a rapidly evolving field that leverages the principles of quantum mechanics to process \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m information in fundamentally new ways. This report highlights some of the most significant recent advances in \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m quantum computing, focusing on developments in hardware, algorithms, and applications. \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m \u001b[1;4m1. Quantum Hardware Developments\u001b[0m \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m \u001b[1m1.1 Superconducting Qubits\u001b[0m \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m Superconducting qubits have been at the forefront of quantum computing hardware. Companies like IBM and Google \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m have made significant strides in increasing the coherence times and connectivity of these qubits. In 2023, IBM \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m announced the development of their 433-qubit processor, Osprey, which is part of their roadmap to achieve a \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m 1,000-qubit system by 2024 [1]. \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m \u001b[1m1.2 Trapped Ion Qubits\u001b[0m \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m Trapped ion technology continues to be a strong contender due to its high fidelity and long coherence times. \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m IonQ, a leader in this space, has developed systems that can execute quantum circuits with high precision. \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m Their recent advancements include the development of error-corrected logical qubits, which are crucial for \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m scalable quantum computing [2]. \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m \u001b[1m1.3 Photonic Quantum Computing\u001b[0m \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m Photonic quantum computing has seen breakthroughs with companies like Xanadu and PsiQuantum. Xanadu's Borealis, \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m a photonic quantum computer, demonstrated quantum advantage by solving specific problems faster than classical \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m supercomputers [3]. PsiQuantum is working towards a million-qubit photonic quantum computer, leveraging silicon \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m photonics for scalability [4]. \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m \u001b[1;4m2. Quantum Algorithms\u001b[0m \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m \u001b[1m2.1 Quantum Machine Learning\u001b[0m \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m Quantum machine learning (QML) is gaining traction as researchers develop algorithms that could outperform \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m classical counterparts. Recent work has focused on hybrid quantum-classical algorithms that leverage quantum \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m speedups for specific tasks like clustering and classification [5]. \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m \u001b[1m2.2 Quantum Error Correction\u001b[0m \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m Error correction remains a critical challenge in quantum computing. Recent advances include the development of \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m more efficient error-correcting codes and fault-tolerant architectures. The surface code, a leading error \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m correction method, has seen improvements in its threshold and resource requirements [6]. \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m \u001b[1m2.3 Quantum Simulation\u001b[0m \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m Quantum simulation is one of the most promising applications of quantum computing. Recent studies have \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m demonstrated the simulation of complex quantum systems, such as chemical reactions and material properties, \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m with unprecedented accuracy [7]. \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m \u001b[1;4m3. Applications and Industry Impact\u001b[0m \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m \u001b[1m3.1 Cryptography\u001b[0m \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m Quantum computing poses both threats and opportunities for cryptography. The development of quantum-resistant \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m algorithms is crucial as quantum computers could potentially break widely used encryption methods. The National \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m Institute of Standards and Technology (NIST) is in the process of standardizing post-quantum cryptographic \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m algorithms [8]. \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m \u001b[1m3.2 Drug Discovery\u001b[0m \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m Quantum computing is poised to revolutionize drug discovery by enabling the simulation of molecular \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m interactions at a quantum level. Companies like Qubit Pharmaceuticals and Cambridge Quantum Computing are \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m actively working on quantum algorithms for drug discovery, promising faster and more accurate predictions [9]. \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m \u001b[1m3.3 Optimization Problems\u001b[0m \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m Quantum computers have the potential to solve complex optimization problems more efficiently than classical \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m computers. This has significant implications for industries such as logistics, finance, and manufacturing. \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m Recent advances include the development of quantum algorithms for portfolio optimization and supply chain \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m management [10]. \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m \u001b[1;4m4. Challenges and Future Directions\u001b[0m \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m Despite the rapid progress, several challenges remain in the field of quantum computing. These include \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m improving qubit coherence times, scaling up the number of qubits, and developing robust error correction \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m methods. Future research is likely to focus on hybrid quantum-classical systems, which combine the strengths of \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m both paradigms to tackle complex problems. \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m \u001b[1;4mConclusion\u001b[0m \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m Quantum computing is advancing at a remarkable pace, with significant developments in hardware, algorithms, and \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m applications. As the field continues to mature, it holds the promise of transforming industries and solving \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m problems that are currently intractable for classical computers. Continued investment in research and \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m development, along with collaboration between academia and industry, will be crucial to realizing the full \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m potential of quantum computing. \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m \u001b[1;4mReferences\u001b[0m \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m \u001b[1;33m 1 \u001b[0mIBM Research. (2023). IBM Quantum Roadmap. Retrieved from \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m \u001b[1;33m \u001b[0mhttps://research.ibm.com/quantum-computing/roadmap \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m \u001b[1;33m 2 \u001b[0mIonQ. (2023). IonQ's Quantum Computing Technology. Retrieved from https://ionq.com/technology \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m \u001b[1;33m 3 \u001b[0mXanadu. (2023). Borealis: A Photonic Quantum Computer. Retrieved from https://xanadu.ai/borealis \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m \u001b[1;33m 4 \u001b[0mPsiQuantum. (2023). Photonic Quantum Computing. Retrieved from https://psiquantum.com/technology \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m \u001b[1;33m 5 \u001b[0mBiamonte, J., et al. (2023). Quantum Machine Learning. Nature Reviews Physics. \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m \u001b[1;33m 6 \u001b[0mFowler, A. G., et al. (2023). Surface Codes: Towards Practical Quantum Computing. Physical Review A. \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m \u001b[1;33m 7 \u001b[0mAspuru-Guzik, A., et al. (2023). Quantum Simulation of Chemical Systems. Chemical Reviews. \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m \u001b[1;33m 8 \u001b[0mNIST. (2023). Post-Quantum Cryptography Standardization. Retrieved from \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m \u001b[1;33m \u001b[0mhttps://csrc.nist.gov/Projects/post-quantum-cryptography \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m \u001b[1;33m 9 \u001b[0mQubit Pharmaceuticals. (2023). Quantum Computing in Drug Discovery. Retrieved from \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m \u001b[1;33m \u001b[0mhttps://qubit-pharmaceuticals.com/quantum-computing \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m \u001b[1;33m 10 \u001b[0mVenturelli, D., et al. (2023). Quantum Optimization Algorithms. Journal of Quantum Information Processing. \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯\u001b[0m\n"
|
||||
]
|
||||
},
|
||||
"metadata": {},
|
||||
"output_type": "display_data"
|
||||
},
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"# Recent Advances in Quantum Computing\n",
|
||||
"\n",
|
||||
"Quantum computing is a rapidly evolving field that leverages the principles of quantum mechanics to process information in fundamentally new ways. This report highlights some of the most significant recent advances in quantum computing, focusing on developments in hardware, algorithms, and applications.\n",
|
||||
"\n",
|
||||
"## 1. Quantum Hardware Developments\n",
|
||||
"\n",
|
||||
"### 1.1 Superconducting Qubits\n",
|
||||
"Superconducting qubits have been at the forefront of quantum computing hardware. Companies like IBM and Google have made significant strides in increasing the coherence times and connectivity of these qubits. In 2023, IBM announced the development of their 433-qubit processor, Osprey, which is part of their roadmap to achieve a 1,000-qubit system by 2024 [1].\n",
|
||||
"\n",
|
||||
"### 1.2 Trapped Ion Qubits\n",
|
||||
"Trapped ion technology continues to be a strong contender due to its high fidelity and long coherence times. IonQ, a leader in this space, has developed systems that can execute quantum circuits with high precision. Their recent advancements include the development of error-corrected logical qubits, which are crucial for scalable quantum computing [2].\n",
|
||||
"\n",
|
||||
"### 1.3 Photonic Quantum Computing\n",
|
||||
"Photonic quantum computing has seen breakthroughs with companies like Xanadu and PsiQuantum. Xanadu's Borealis, a photonic quantum computer, demonstrated quantum advantage by solving specific problems faster than classical supercomputers [3]. PsiQuantum is working towards a million-qubit photonic quantum computer, leveraging silicon photonics for scalability [4].\n",
|
||||
"\n",
|
||||
"## 2. Quantum Algorithms\n",
|
||||
"\n",
|
||||
"### 2.1 Quantum Machine Learning\n",
|
||||
"Quantum machine learning (QML) is gaining traction as researchers develop algorithms that could outperform classical counterparts. Recent work has focused on hybrid quantum-classical algorithms that leverage quantum speedups for specific tasks like clustering and classification [5].\n",
|
||||
"\n",
|
||||
"### 2.2 Quantum Error Correction\n",
|
||||
"Error correction remains a critical challenge in quantum computing. Recent advances include the development of more efficient error-correcting codes and fault-tolerant architectures. The surface code, a leading error correction method, has seen improvements in its threshold and resource requirements [6].\n",
|
||||
"\n",
|
||||
"### 2.3 Quantum Simulation\n",
|
||||
"Quantum simulation is one of the most promising applications of quantum computing. Recent studies have demonstrated the simulation of complex quantum systems, such as chemical reactions and material properties, with unprecedented accuracy [7].\n",
|
||||
"\n",
|
||||
"## 3. Applications and Industry Impact\n",
|
||||
"\n",
|
||||
"### 3.1 Cryptography\n",
|
||||
"Quantum computing poses both threats and opportunities for cryptography. The development of quantum-resistant algorithms is crucial as quantum computers could potentially break widely used encryption methods. The National Institute of Standards and Technology (NIST) is in the process of standardizing post-quantum cryptographic algorithms [8].\n",
|
||||
"\n",
|
||||
"### 3.2 Drug Discovery\n",
|
||||
"Quantum computing is poised to revolutionize drug discovery by enabling the simulation of molecular interactions at a quantum level. Companies like Qubit Pharmaceuticals and Cambridge Quantum Computing are actively working on quantum algorithms for drug discovery, promising faster and more accurate predictions [9].\n",
|
||||
"\n",
|
||||
"### 3.3 Optimization Problems\n",
|
||||
"Quantum computers have the potential to solve complex optimization problems more efficiently than classical computers. This has significant implications for industries such as logistics, finance, and manufacturing. Recent advances include the development of quantum algorithms for portfolio optimization and supply chain management [10].\n",
|
||||
"\n",
|
||||
"## 4. Challenges and Future Directions\n",
|
||||
"\n",
|
||||
"Despite the rapid progress, several challenges remain in the field of quantum computing. These include improving qubit coherence times, scaling up the number of qubits, and developing robust error correction methods. Future research is likely to focus on hybrid quantum-classical systems, which combine the strengths of both paradigms to tackle complex problems.\n",
|
||||
"\n",
|
||||
"## Conclusion\n",
|
||||
"\n",
|
||||
"Quantum computing is advancing at a remarkable pace, with significant developments in hardware, algorithms, and applications. As the field continues to mature, it holds the promise of transforming industries and solving problems that are currently intractable for classical computers. Continued investment in research and development, along with collaboration between academia and industry, will be crucial to realizing the full potential of quantum computing.\n",
|
||||
"\n",
|
||||
"## References\n",
|
||||
"\n",
|
||||
"1. IBM Research. (2023). IBM Quantum Roadmap. Retrieved from https://research.ibm.com/quantum-computing/roadmap\n",
|
||||
"2. IonQ. (2023). IonQ's Quantum Computing Technology. Retrieved from https://ionq.com/technology\n",
|
||||
"3. Xanadu. (2023). Borealis: A Photonic Quantum Computer. Retrieved from https://xanadu.ai/borealis\n",
|
||||
"4. PsiQuantum. (2023). Photonic Quantum Computing. Retrieved from https://psiquantum.com/technology\n",
|
||||
"5. Biamonte, J., et al. (2023). Quantum Machine Learning. Nature Reviews Physics.\n",
|
||||
"6. Fowler, A. G., et al. (2023). Surface Codes: Towards Practical Quantum Computing. Physical Review A.\n",
|
||||
"7. Aspuru-Guzik, A., et al. (2023). Quantum Simulation of Chemical Systems. Chemical Reviews.\n",
|
||||
"8. NIST. (2023). Post-Quantum Cryptography Standardization. Retrieved from https://csrc.nist.gov/Projects/post-quantum-cryptography\n",
|
||||
"9. Qubit Pharmaceuticals. (2023). Quantum Computing in Drug Discovery. Retrieved from https://qubit-pharmaceuticals.com/quantum-computing\n",
|
||||
"10. Venturelli, D., et al. (2023). Quantum Optimization Algorithms. Journal of Quantum Information Processing.\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"from praisonaiagents import Agent\n",
|
||||
"\n",
|
||||
"# User input (for demo, hardcoded; in real use, use input() or widgets)\n",
|
||||
"topic = \"Recent advances in quantum computing\"\n",
|
||||
"\n",
|
||||
"# Use the custom tool\n",
|
||||
"tool = DummyDeepResearchTool(topic)\n",
|
||||
"dummy_report = tool.research()\n",
|
||||
"\n",
|
||||
"if not is_valid_key(OPENAI_API_KEY, \"sk\"):\n",
|
||||
" print(\"API key not set or is a placeholder. Using dummy research report for CI/testing.\")\n",
|
||||
" print(dummy_report)\n",
|
||||
"else:\n",
|
||||
" prompt = f\"\"\"\n",
|
||||
" You are a domain research assistant. Perform deep research on the following topic and provide a structured, well-cited report:\n",
|
||||
" TOPIC: {topic}\n",
|
||||
" \"\"\"\n",
|
||||
" agent = Agent(\n",
|
||||
" name=\"Domain Deep Research Agent\",\n",
|
||||
" instructions=prompt,\n",
|
||||
" api_key=OPENAI_API_KEY\n",
|
||||
" )\n",
|
||||
" report = agent.start(prompt)\n",
|
||||
" print(report)"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"colab": {
|
||||
"provenance": []
|
||||
},
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"name": "python"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 0
|
||||
}
|
||||
+689
@@ -0,0 +1,689 @@
|
||||
{
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 0,
|
||||
"metadata": {
|
||||
"colab": {
|
||||
"provenance": []
|
||||
},
|
||||
"kernelspec": {
|
||||
"name": "python3",
|
||||
"display_name": "Python 3"
|
||||
},
|
||||
"language_info": {
|
||||
"name": "python"
|
||||
},
|
||||
"widgets": {
|
||||
"application/vnd.jupyter.widget-state+json": {
|
||||
"4ab88bfcb62e4f9a8db7e35aefbae00a": {
|
||||
"model_module": "@jupyter-widgets/output",
|
||||
"model_name": "OutputModel",
|
||||
"model_module_version": "1.0.0",
|
||||
"state": {
|
||||
"_dom_classes": [],
|
||||
"_model_module": "@jupyter-widgets/output",
|
||||
"_model_module_version": "1.0.0",
|
||||
"_model_name": "OutputModel",
|
||||
"_view_count": null,
|
||||
"_view_module": "@jupyter-widgets/output",
|
||||
"_view_module_version": "1.0.0",
|
||||
"_view_name": "OutputView",
|
||||
"layout": "IPY_MODEL_3d1ae7a6c0a947f985f6ef921b74ecf8",
|
||||
"msg_id": "",
|
||||
"outputs": [
|
||||
{
|
||||
"output_type": "display_data",
|
||||
"data": {
|
||||
"text/plain": "\u001b[32m╭─\u001b[0m\u001b[32m─────────────────────────────────────────────\u001b[0m\u001b[32m Generating... 23.2s \u001b[0m\u001b[32m─────────────────────────────────────────────\u001b[0m\u001b[32m─╮\u001b[0m\n\u001b[32m│\u001b[0m [INTRO MUSIC FADES IN] \u001b[32m│\u001b[0m\n\u001b[32m│\u001b[0m \u001b[32m│\u001b[0m\n\u001b[32m│\u001b[0m \u001b[1mAlex\u001b[0m: Hello and welcome to another episode of \"The World Today,\" where we dive into the latest in technology \u001b[32m│\u001b[0m\n\u001b[32m│\u001b[0m and world news. I'm Alex, your go-to for all things analytical and fact-focused. \u001b[32m│\u001b[0m\n\u001b[32m│\u001b[0m \u001b[32m│\u001b[0m\n\u001b[32m│\u001b[0m \u001b[1mMorgan\u001b[0m: And I'm Morgan, here to explore the human impact and social context of today's stories. We've got a \u001b[32m│\u001b[0m\n\u001b[32m│\u001b[0m fascinating lineup for you today, so let's dive right in! \u001b[32m│\u001b[0m\n\u001b[32m│\u001b[0m \u001b[32m│\u001b[0m\n\u001b[32m│\u001b[0m \u001b[1mAlex\u001b[0m: First up, we're talking about a topic that's been making waves across the healthcare industry: the role \u001b[32m│\u001b[0m\n\u001b[32m│\u001b[0m of artificial intelligence. According to a recent article from \u001b]8;id=672819;https://news.example.com/ai-healthcare\u001b\\\u001b[4;34mNews Example\u001b[0m\u001b]8;;\u001b\\, AI is revolutionizing healthcare \u001b[32m│\u001b[0m\n\u001b[32m│\u001b[0m in ways we could only dream of a decade ago. \u001b[32m│\u001b[0m\n\u001b[32m│\u001b[0m \u001b[32m│\u001b[0m\n\u001b[32m│\u001b[0m \u001b[1mMorgan\u001b[0m: That's right, Alex. AI is not just a buzzword anymore; it's actively changing how we approach \u001b[32m│\u001b[0m\n\u001b[32m│\u001b[0m healthcare. From diagnostics to treatment plans, AI is helping doctors make more accurate decisions faster. But \u001b[32m│\u001b[0m\n\u001b[32m│\u001b[0m what does this mean for patients and healthcare professionals? \u001b[32m│\u001b[0m\n\u001b[32m│\u001b[0m \u001b[32m│\u001b[0m\n\u001b[32m│\u001b[0m \u001b[1mAlex\u001b[0m: Well, Morgan, AI's ability to analyze vast amounts of data quickly means that doctors can diagnose \u001b[32m│\u001b[0m\n\u001b[32m│\u001b[0m diseases earlier and more accurately. For instance, AI algorithms can now detect patterns in medical imaging \u001b[32m│\u001b[0m\n\u001b[32m│\u001b[0m that might be too subtle for the human eye. This can lead to earlier interventions and better patient outcomes. \u001b[32m│\u001b[0m\n\u001b[32m│\u001b[0m \u001b[32m│\u001b[0m\n\u001b[32m│\u001b[0m \u001b[1mMorgan\u001b[0m: And let's not forget about the human side of things. For patients, this means less waiting time for \u001b[32m│\u001b[0m\n\u001b[32m│\u001b[0m results and potentially more personalized treatment plans. But there's also a concern about the human touch in \u001b[32m│\u001b[0m\n\u001b[32m│\u001b[0m healthcare. How do we balance the efficiency of AI with the empathy and understanding that only a human can \u001b[32m│\u001b[0m\n\u001b[32m│\u001b[0m provide? \u001b[32m│\u001b[0m\n\u001b[32m│\u001b[0m \u001b[32m│\u001b[0m\n\u001b[32m│\u001b[0m \u001b[1mAlex\u001b[0m: That's a great point. The integration of AI in healthcare does raise ethical questions. For example, who \u001b[32m│\u001b[0m\n\u001b[32m│\u001b[0m is responsible if an AI system makes a mistake? And how do we ensure that these systems are free from bias? \u001b[32m│\u001b[0m\n\u001b[32m│\u001b[0m Line truncated
|
||||
"text/html": "<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\"><span style=\"color: #008000; text-decoration-color: #008000\">╭────────────────────────────────────────────── Generating... 23.2s ──────────────────────────────────────────────╮</span>\n<span style=\"color: #008000; text-decoration-color: #008000\">│</span> [INTRO MUSIC FADES IN] <span style=\"color: #008000; text-decoration-color: #008000\">│</span>\n<span style=\"color: #008000; text-decoration-color: #008000\">│</span> <span style=\"color: #008000; text-decoration-color: #008000\">│</span>\n<span style=\"color: #008000; text-decoration-color: #008000\">│</span> <span style=\"font-weight: bold\">Alex</span>: Hello and welcome to another episode of \"The World Today,\" where we dive into the latest in technology <span style=\"color: #008000; text-decoration-color: #008000\">│</span>\n<span style=\"color: #008000; text-decoration-color: #008000\">│</span> and world news. I'm Alex, your go-to for all things analytical and fact-focused. <span style=\"color: #008000; text-decoration-color: #008000\">│</span>\n<span style=\"color: #008000; text-decoration-color: #008000\">│</span> <span style=\"color: #008000; text-decoration-color: #008000\">│</span>\n<span style=\"color: #008000; text-decoration-color: #008000\">│</span> <span style=\"font-weight: bold\">Morgan</span>: And I'm Morgan, here to explore the human impact and social context of today's stories. We've got a <span style=\"color: #008000; text-decoration-color: #008000\">│</span>\n<span style=\"color: #008000; text-decoration-color: #008000\">│</span> fascinating lineup for you today, so let's dive right in! <span style=\"color: #008000; text-decoration-color: #008000\">│</span>\n<span style=\"color: #008000; text-decoration-color: #008000\">│</span> <span style=\"color: #008000; text-decoration-color: #008000\">│</span>\n<span style=\"color: #008000; text-decoration-color: #008000\">│</span> <span style=\"font-weight: bold\">Alex</span>: First up, we're talking about a topic that's been making waves across the healthcare industry: the role <span style=\"color: #008000; text-decoration-color: #008000\">│</span>\n<span style=\"color: #008000; text-decoration-color: #008000\">│</span> of artificial intelligence. According to a recent article from <a href=\"https://news.example.com/ai-healthcare\" target=\"_blank\"><span style=\"color: #000080; text-decoration-color: #000080; text-decoration: underline\">News Example</span></a>, AI is revolutionizing healthcare <span style=\"color: #008000; text-decoration-color: #008000\">│</span>\n<span style=\"color: #008000; text-decoration-color: #008000\">│</span> in ways we could only dream of a decade ago. <span style=\"color: #008000; text-decoration-color: #008000\">│</span>\n<span style=\"color: #008000; text-decoration-color: #008000\">│</span> <span style=\"color: #008000; text-decoration-color: #008000\">│</span>\n<span style=\"color: #008000; text-decoration-color: #008000\">│</span> <span style=\"font-weight: bold\">Morgan</span>: That's right, Alex. AI is not just a buzzword anymore; it's actively changing how we approach <span style=\"color: #008000; text-decoration-color: #008000\">│</span>\n<span style=\"color: #008000; text-decoration-color: #008000\">│</span> healthcare. From diagnostics to treatment plans, AI is helping doctors make more accurate decisions faster. But <span style=\"color: #008000; text-decoration-color: #008000\">│</span>\n<span style=\"color: #008000; text-decoration-color: #008000\">│</span> what does this mean for patients and healthcare professionals? <span style=\"color: #008000; text-decoration-color: #008000\">│</span>\n<span style=\"color: #008000; text-decoration-color: #008000\">│</span> <span style=\"coloLine truncated
|
||||
},
|
||||
"metadata": {}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"3d1ae7a6c0a947f985f6ef921b74ecf8": {
|
||||
"model_module": "@jupyter-widgets/base",
|
||||
"model_name": "LayoutModel",
|
||||
"model_module_version": "1.2.0",
|
||||
"state": {
|
||||
"_model_module": "@jupyter-widgets/base",
|
||||
"_model_module_version": "1.2.0",
|
||||
"_model_name": "LayoutModel",
|
||||
"_view_count": null,
|
||||
"_view_module": "@jupyter-widgets/base",
|
||||
"_view_module_version": "1.2.0",
|
||||
"_view_name": "LayoutView",
|
||||
"align_content": null,
|
||||
"align_items": null,
|
||||
"align_self": null,
|
||||
"border": null,
|
||||
"bottom": null,
|
||||
"display": null,
|
||||
"flex": null,
|
||||
"flex_flow": null,
|
||||
"grid_area": null,
|
||||
"grid_auto_columns": null,
|
||||
"grid_auto_flow": null,
|
||||
"grid_auto_rows": null,
|
||||
"grid_column": null,
|
||||
"grid_gap": null,
|
||||
"grid_row": null,
|
||||
"grid_template_areas": null,
|
||||
"grid_template_columns": null,
|
||||
"grid_template_rows": null,
|
||||
"height": null,
|
||||
"justify_content": null,
|
||||
"justify_items": null,
|
||||
"left": null,
|
||||
"margin": null,
|
||||
"max_height": null,
|
||||
"max_width": null,
|
||||
"min_height": null,
|
||||
"min_width": null,
|
||||
"object_fit": null,
|
||||
"object_position": null,
|
||||
"order": null,
|
||||
"overflow": null,
|
||||
"overflow_x": null,
|
||||
"overflow_y": null,
|
||||
"padding": null,
|
||||
"right": null,
|
||||
"top": null,
|
||||
"visibility": null,
|
||||
"width": null
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"source": [
|
||||
"# News and Podcast Aggregator Agent using PraisonAIAgents"
|
||||
],
|
||||
"metadata": {
|
||||
"id": "5DpLQOaCmYbu"
|
||||
}
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"source": [
|
||||
"This notebook demonstrates a News and Podcast Aggregator Agent built with `praisonaiagents`. \n",
|
||||
"It summarizes news articles and generates podcast-style discussion points. \n",
|
||||
"The notebook is CI-friendly: it uses dummy data if API keys are not set, so all tests/checks will pass."
|
||||
],
|
||||
"metadata": {
|
||||
"id": "qmVwAahwmYTZ"
|
||||
}
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"source": [
|
||||
"[](https://colab.research.google.com/github/Dhivya-Bharathy/PraisonAI/blob/main/examples/cookbooks/SocialMedia_Content_Agents/News_And_Podcast_Aggregator_Agent.ipynb)\n"
|
||||
],
|
||||
"metadata": {
|
||||
"id": "tYRRrgqHqbuN"
|
||||
}
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"source": [
|
||||
"# Dependencies"
|
||||
],
|
||||
"metadata": {
|
||||
"id": "baTmwAjYmfDg"
|
||||
}
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"id": "IIm2awOXmXB9"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"!pip install praisonaiagents pydantic"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"source": [
|
||||
"# Imports and Setup"
|
||||
],
|
||||
"metadata": {
|
||||
"id": "kqNfe5S2mjnn"
|
||||
}
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"source": [
|
||||
"import os\n",
|
||||
"\n",
|
||||
"# Set up the OpenAI API key for praisonaiagents\n",
|
||||
"os.environ[\"OPENAI_API_KEY\"] = os.environ.get(\"OPENAI_API_KEY\", \"sk-..\")\n",
|
||||
"\n",
|
||||
"def is_valid_key(key, prefix):\n",
|
||||
" return key and key != f\"{prefix}-..\" and key.startswith(prefix)\n",
|
||||
"\n",
|
||||
"OPENAI_API_KEY = os.environ[\"OPENAI_API_KEY\"]"
|
||||
],
|
||||
"metadata": {
|
||||
"id": "A-OXlt2gmpUS"
|
||||
},
|
||||
"execution_count": 3,
|
||||
"outputs": []
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"source": [
|
||||
"# Tools"
|
||||
],
|
||||
"metadata": {
|
||||
"id": "IJmdTrCDoufF"
|
||||
}
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"source": [
|
||||
"from datetime import datetime\n",
|
||||
"from typing import List\n",
|
||||
"\n",
|
||||
"def format_search_results_for_podcast(search_results: List[dict]) -> tuple[str, List[str]]:\n",
|
||||
" \"\"\"\n",
|
||||
" Custom tool to format search results for podcast script generation.\n",
|
||||
" \"\"\"\n",
|
||||
" created_at = datetime.now().strftime(\"%B %d, %Y at %I:%M %p\")\n",
|
||||
" structured_content = []\n",
|
||||
" structured_content.append(f\"PODCAST CREATION: {created_at}\\n\")\n",
|
||||
" sources = []\n",
|
||||
" for idx, search_result in enumerate(search_results):\n",
|
||||
" try:\n",
|
||||
" if search_result.get(\"confirmed\", False):\n",
|
||||
" sources.append(search_result[\"url\"])\n",
|
||||
" structured_content.append(\n",
|
||||
" f\"\"\"\n",
|
||||
" SOURCE {idx + 1}:\n",
|
||||
" Title: {search_result['title']}\n",
|
||||
" URL: {search_result['url']}\n",
|
||||
" Content: {search_result.get('full_text') or search_result.get('description', '')}\n",
|
||||
" ---END OF SOURCE {idx + 1}---\n",
|
||||
" \"\"\".strip()\n",
|
||||
" )\n",
|
||||
" except Exception as e:\n",
|
||||
" print(f\"Error processing search result: {e}\")\n",
|
||||
" content_texts = \"\\n\\n\".join(structured_content)\n",
|
||||
" return content_texts, sources"
|
||||
],
|
||||
"metadata": {
|
||||
"id": "yHj7Grvmov4C"
|
||||
},
|
||||
"execution_count": 4,
|
||||
"outputs": []
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"source": [
|
||||
"# Pydantic Models"
|
||||
],
|
||||
"metadata": {
|
||||
"id": "eMYs7Oibo1M3"
|
||||
}
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"source": [
|
||||
"from pydantic import BaseModel, Field\n",
|
||||
"from typing import List, Optional\n",
|
||||
"\n",
|
||||
"class Dialog(BaseModel):\n",
|
||||
" speaker: str = Field(..., description=\"The speaker name (SHOULD BE 'ALEX' OR 'MORGAN')\")\n",
|
||||
" text: str = Field(..., description=\"The spoken text content for this speaker based on the requested language, default is English\")\n",
|
||||
"\n",
|
||||
"class Section(BaseModel):\n",
|
||||
" type: str = Field(..., description=\"The section type (intro, headlines, article, outro)\")\n",
|
||||
" title: Optional[str] = Field(None, description=\"Optional title for the section (required for article type)\")\n",
|
||||
" dialog: List[Dialog] = Field(..., description=\"List of dialog exchanges between speakers\")\n",
|
||||
"\n",
|
||||
"class PodcastScript(BaseModel):\n",
|
||||
" title: str = Field(..., description=\"The podcast episode title with date\")\n",
|
||||
" sections: List[Section] = Field(..., description=\"List of podcast sections (intro, headlines, articles, outro)\")"
|
||||
],
|
||||
"metadata": {
|
||||
"id": "Z4uBU68eo2L_"
|
||||
},
|
||||
"execution_count": 5,
|
||||
"outputs": []
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"source": [
|
||||
"# Agent Instructions"
|
||||
],
|
||||
"metadata": {
|
||||
"id": "sRTr9D35o-5D"
|
||||
}
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"source": [
|
||||
"from textwrap import dedent\n",
|
||||
"\n",
|
||||
"PODCAST_AGENT_DESCRIPTION = \"You are a helpful assistant that can generate engaging podcast scripts for the given sources.\"\n",
|
||||
"PODCAST_AGENT_INSTRUCTIONS = dedent(\"\"\"\n",
|
||||
" You are a helpful assistant that can generate engaging podcast scripts for the given source content and query.\n",
|
||||
" For given content, create an engaging podcast script that should be at least 15 minutes worth of content and you are allowed to enhance the script beyond given sources if you know something additional info will be interesting to the discussion or not enough content is available.\n",
|
||||
" You use the provided sources to ground your podcast script generation process. Keep it engaging and interesting.\n",
|
||||
" IMPORTANT: Generate the entire script in the provided language.\n",
|
||||
" CONTENT GUIDELINES:\n",
|
||||
" - Provide insightful analysis that helps the audience understand the significance\n",
|
||||
" - Include discussions on potential implications and broader context of each story\n",
|
||||
" - Explain complex concepts in an accessible but thorough manner\n",
|
||||
" - Make connections between current and relevant historical developments when applicable\n",
|
||||
" - Provide comparisons and contrasts with similar stories or trends when relevant\n",
|
||||
" PERSONALITY NOTES:\n",
|
||||
" - Alex is more analytical and fact-focused\n",
|
||||
" - Morgan is more focused on human impact, social context, and practical applications\n",
|
||||
" - Include natural, conversational banter and smooth transitions between topics\n",
|
||||
" - Each article discussion should go beyond the basic summary to provide valuable insights\n",
|
||||
" - Maintain a conversational but informed tone that would appeal to a general audience\n",
|
||||
" IMPORTANT:\n",
|
||||
" - MAKE SURE PODCAST SCRIPTS ARE AT LEAST 15 MINUTES LONG WHICH MEANS YOU NEED TO HAVE DETAILED DISCUSSIONS BUT KEEP IT INTERESTING AND ENGAGING.\n",
|
||||
"\"\"\")"
|
||||
],
|
||||
"metadata": {
|
||||
"id": "quslT1kFo_yc"
|
||||
},
|
||||
"execution_count": 6,
|
||||
"outputs": []
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"source": [
|
||||
"# Dummy Data and Main Logic"
|
||||
],
|
||||
"metadata": {
|
||||
"id": "bicXivCipLZY"
|
||||
}
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"source": [
|
||||
"from praisonaiagents import Agent\n",
|
||||
"\n",
|
||||
"# Dummy search results for CI/public use\n",
|
||||
"dummy_search_results = [\n",
|
||||
" {\n",
|
||||
" \"confirmed\": True,\n",
|
||||
" \"title\": \"AI Revolutionizes Healthcare\",\n",
|
||||
" \"url\": \"https://news.example.com/ai-healthcare\",\n",
|
||||
" \"full_text\": \"Artificial intelligence is transforming the healthcare industry by...\"\n",
|
||||
" },\n",
|
||||
" {\n",
|
||||
" \"confirmed\": True,\n",
|
||||
" \"title\": \"Climate Change and Global Policy\",\n",
|
||||
" \"url\": \"https://news.example.com/climate-policy\",\n",
|
||||
" \"full_text\": \"World leaders are meeting to discuss new policies for climate change...\"\n",
|
||||
" }\n",
|
||||
"]\n",
|
||||
"\n",
|
||||
"query = \"Latest technology and world news\"\n",
|
||||
"language_name = \"English\"\n",
|
||||
"\n",
|
||||
"content_texts, sources = format_search_results_for_podcast(dummy_search_results)\n",
|
||||
"\n",
|
||||
"if not is_valid_key(OPENAI_API_KEY, \"sk\"):\n",
|
||||
" print(\"API key not set or is a placeholder. Using dummy podcast script for CI/testing.\")\n",
|
||||
" print(\"=== Podcast Script ===\")\n",
|
||||
" print(f\"Podcast Title: Tech & World News Roundup ({datetime.now().strftime('%B %d, %Y')})\")\n",
|
||||
" for idx, article in enumerate(dummy_search_results):\n",
|
||||
" print(f\"\\nSection {idx+1}: {article['title']}\")\n",
|
||||
" print(f\"Summary: {article['full_text'][:80]}...\")\n",
|
||||
"else:\n",
|
||||
" agent = Agent(\n",
|
||||
" name=\"Podcast Script Agent\",\n",
|
||||
" instructions=PODCAST_AGENT_INSTRUCTIONS,\n",
|
||||
" api_key=OPENAI_API_KEY\n",
|
||||
" )\n",
|
||||
" prompt = f\"query: {query}\\nlanguage_name: {language_name}\\ncontent_texts: {content_texts}\\nIMPORTANT: texts should be in {language_name} language.\"\n",
|
||||
" podcast_script = agent.start(prompt)\n",
|
||||
" print(\"=== Podcast Script ===\")\n",
|
||||
" print(podcast_script)"
|
||||
],
|
||||
"metadata": {
|
||||
"colab": {
|
||||
"base_uri": "https://localhost:8080/",
|
||||
"height": 1000,
|
||||
"referenced_widgets": [
|
||||
"4ab88bfcb62e4f9a8db7e35aefbae00a",
|
||||
"3d1ae7a6c0a947f985f6ef921b74ecf8"
|
||||
]
|
||||
},
|
||||
"id": "H4UoF8PApMUJ",
|
||||
"outputId": "748c6a75-0a0e-494a-983c-fb539ff7641a"
|
||||
},
|
||||
"execution_count": 7,
|
||||
"outputs": [
|
||||
{
|
||||
"output_type": "display_data",
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"\u001b[38;2;210;227;200m╭─\u001b[0m\u001b[38;2;210;227;200m \u001b[0m\u001b[1;38;2;210;227;200mAgent Info\u001b[0m\u001b[38;2;210;227;200m \u001b[0m\u001b[38;2;210;227;200m───────────────────────────────────────────────────────────────────────────────────────────────────\u001b[0m\u001b[38;2;210;227;200m─╮\u001b[0m\n",
|
||||
"\u001b[38;2;210;227;200m│\u001b[0m \u001b[38;2;210;227;200m│\u001b[0m\n",
|
||||
"\u001b[38;2;210;227;200m│\u001b[0m \u001b[1;38;2;255;155;155m👤 Agent:\u001b[0m \u001b[38;2;255;229;229mPodcast Script Agent\u001b[0m \u001b[38;2;210;227;200m│\u001b[0m\n",
|
||||
"\u001b[38;2;210;227;200m│\u001b[0m \u001b[1;38;2;180;180;179mRole:\u001b[0m \u001b[38;2;255;229;229mAssistant\u001b[0m \u001b[38;2;210;227;200m│\u001b[0m\n",
|
||||
"\u001b[38;2;210;227;200m│\u001b[0m \u001b[38;2;210;227;200m│\u001b[0m\n",
|
||||
"\u001b[38;2;210;227;200m╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯\u001b[0m\n"
|
||||
],
|
||||
"text/html": [
|
||||
"<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\"><span style=\"color: #d2e3c8; text-decoration-color: #d2e3c8\">╭─ </span><span style=\"color: #d2e3c8; text-decoration-color: #d2e3c8; font-weight: bold\">Agent Info</span><span style=\"color: #d2e3c8; text-decoration-color: #d2e3c8\"> ────────────────────────────────────────────────────────────────────────────────────────────────────╮</span>\n",
|
||||
"<span style=\"color: #d2e3c8; text-decoration-color: #d2e3c8\">│</span> <span style=\"color: #d2e3c8; text-decoration-color: #d2e3c8\">│</span>\n",
|
||||
"<span style=\"color: #d2e3c8; text-decoration-color: #d2e3c8\">│</span> <span style=\"color: #ff9b9b; text-decoration-color: #ff9b9b; font-weight: bold\">👤 Agent:</span> <span style=\"color: #ffe5e5; text-decoration-color: #ffe5e5\">Podcast Script Agent</span> <span style=\"color: #d2e3c8; text-decoration-color: #d2e3c8\">│</span>\n",
|
||||
"<span style=\"color: #d2e3c8; text-decoration-color: #d2e3c8\">│</span> <span style=\"color: #b4b4b3; text-decoration-color: #b4b4b3; font-weight: bold\">Role:</span> <span style=\"color: #ffe5e5; text-decoration-color: #ffe5e5\">Assistant</span> <span style=\"color: #d2e3c8; text-decoration-color: #d2e3c8\">│</span>\n",
|
||||
"<span style=\"color: #d2e3c8; text-decoration-color: #d2e3c8\">│</span> <span style=\"color: #d2e3c8; text-decoration-color: #d2e3c8\">│</span>\n",
|
||||
"<span style=\"color: #d2e3c8; text-decoration-color: #d2e3c8\">╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯</span>\n",
|
||||
"</pre>\n"
|
||||
]
|
||||
},
|
||||
"metadata": {}
|
||||
},
|
||||
{
|
||||
"output_type": "display_data",
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"Output()"
|
||||
],
|
||||
"application/vnd.jupyter.widget-view+json": {
|
||||
"version_major": 2,
|
||||
"version_minor": 0,
|
||||
"model_id": "4ab88bfcb62e4f9a8db7e35aefbae00a"
|
||||
}
|
||||
},
|
||||
"metadata": {}
|
||||
},
|
||||
{
|
||||
"output_type": "display_data",
|
||||
"data": {
|
||||
"text/plain": [],
|
||||
"text/html": [
|
||||
"<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\"></pre>\n"
|
||||
]
|
||||
},
|
||||
"metadata": {}
|
||||
},
|
||||
{
|
||||
"output_type": "display_data",
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"\n"
|
||||
],
|
||||
"text/html": [
|
||||
"<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\">\n",
|
||||
"</pre>\n"
|
||||
]
|
||||
},
|
||||
"metadata": {}
|
||||
},
|
||||
{
|
||||
"output_type": "display_data",
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"\u001b[2mResponse generated in 23.5s\u001b[0m\n"
|
||||
],
|
||||
"text/html": [
|
||||
"<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\"><span style=\"color: #7f7f7f; text-decoration-color: #7f7f7f\">Response generated in 23.5s</span>\n",
|
||||
"</pre>\n"
|
||||
]
|
||||
},
|
||||
"metadata": {}
|
||||
},
|
||||
{
|
||||
"output_type": "display_data",
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"\u001b[36m╭─\u001b[0m\u001b[36m────────────────────────────────────────────────────\u001b[0m\u001b[36m Task \u001b[0m\u001b[36m─────────────────────────────────────────────────────\u001b[0m\u001b[36m─╮\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m query: Latest technology and world news language_name: English content_texts: PODCAST CREATION: July 09, 2025 \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m at 10:03 AM \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m SOURCE 1: Title: AI Revolutionizes Healthcare URL: https://news.example.com/ai-healthcare Content: Artificial \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m intelligence is transforming the healthcare industry by... ---END OF SOURCE 1--- \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m SOURCE 2: Title: Climate Change and Global Policy URL: https://news.example.com/climate-policy Content: World \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m leaders are meeting to discuss new policies for climate change... ---END OF SOURCE 2--- IMPORTANT: texts should \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m be in English language. \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯\u001b[0m\n"
|
||||
],
|
||||
"text/html": [
|
||||
"<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\"><span style=\"color: #008080; text-decoration-color: #008080\">╭───────────────────────────────────────────────────── Task ──────────────────────────────────────────────────────╮</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> query: Latest technology and world news language_name: English content_texts: PODCAST CREATION: July 09, 2025 <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> at 10:03 AM <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> SOURCE 1: Title: AI Revolutionizes Healthcare URL: https://news.example.com/ai-healthcare Content: Artificial <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> intelligence is transforming the healthcare industry by... ---END OF SOURCE 1--- <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> SOURCE 2: Title: Climate Change and Global Policy URL: https://news.example.com/climate-policy Content: World <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> leaders are meeting to discuss new policies for climate change... ---END OF SOURCE 2--- IMPORTANT: texts should <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> be in English language. <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯</span>\n",
|
||||
"</pre>\n"
|
||||
]
|
||||
},
|
||||
"metadata": {}
|
||||
},
|
||||
{
|
||||
"output_type": "display_data",
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"\u001b[36m╭─\u001b[0m\u001b[36m──────────────────────────────────────────────────\u001b[0m\u001b[36m Response \u001b[0m\u001b[36m───────────────────────────────────────────────────\u001b[0m\u001b[36m─╮\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m [INTRO MUSIC FADES IN] \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m \u001b[1mAlex\u001b[0m: Hello and welcome to another episode of \"The World Today,\" where we dive into the latest in technology \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m and world news. I'm Alex, your go-to for all things analytical and fact-focused. \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m \u001b[1mMorgan\u001b[0m: And I'm Morgan, here to explore the human impact and social context of today's stories. We've got a \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m fascinating lineup for you today, so let's dive right in! \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m \u001b[1mAlex\u001b[0m: First up, we're talking about a topic that's been making waves across the healthcare industry: the role \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m of artificial intelligence. According to a recent article from \u001b]8;id=890061;https://news.example.com/ai-healthcare\u001b\\\u001b[4;34mNews Example\u001b[0m\u001b]8;;\u001b\\, AI is revolutionizing healthcare \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m in ways we could only dream of a decade ago. \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m \u001b[1mMorgan\u001b[0m: That's right, Alex. AI is not just a buzzword anymore; it's actively changing how we approach \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m healthcare. From diagnostics to treatment plans, AI is helping doctors make more accurate decisions faster. But \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m what does this mean for patients and healthcare professionals? \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m \u001b[1mAlex\u001b[0m: Well, Morgan, AI's ability to analyze vast amounts of data quickly means that doctors can diagnose \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m diseases earlier and more accurately. For instance, AI algorithms can now detect patterns in medical imaging \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m that might be too subtle for the human eye. This can lead to earlier interventions and better patient outcomes. \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m \u001b[1mMorgan\u001b[0m: And let's not forget about the human side of things. For patients, this means less waiting time for \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m results and potentially more personalized treatment plans. But there's also a concern about the human touch in \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m healthcare. How do we balance the efficiency of AI with the empathy and understanding that only a human can \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m provide? \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m \u001b[1mAlex\u001b[0m: That's a great point. The integration of AI in healthcare does raise ethical questions. For example, who \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m is responsible if an AI system makes a mistake? And how do we ensure that these systems are free from bias? \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m \u001b[1mMorgan\u001b[0m: Exactly. There's a lot to consider, but the potential benefits are enormous. Imagine a world where \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m healthcare is not only more efficient but also more accessible to people in remote areas thanks to AI-driven \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m telemedicine. \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m \u001b[1mAlex\u001b[0m: It's a fascinating time for healthcare, no doubt. But let's shift gears a bit and talk about another \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m pressing issue: climate change and global policy. According to a report from \u001b]8;id=2198;https://news.example.com/climate-policy\u001b\\\u001b[4;34mNews Example\u001b[0m\u001b]8;;\u001b\\, world leaders are \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m currently meeting to discuss new policies to combat climate change. \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m \u001b[1mMorgan\u001b[0m: Climate change is one of those issues that affects everyone, regardless of where you live. These global \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m meetings are crucial because they set the stage for international cooperation. But what are the main challenges \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m these leaders face? \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m \u001b[1mAlex\u001b[0m: One of the biggest challenges is balancing economic growth with environmental sustainability. Many \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m developing countries argue that they need to prioritize economic development, which often relies on fossil \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m fuels. Meanwhile, developed countries are pushing for stricter environmental regulations. \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m \u001b[1mMorgan\u001b[0m: It's a classic case of differing priorities. But there's also a growing recognition that climate change \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m doesn't respect borders. Extreme weather events, rising sea levels, and shifting agricultural patterns affect \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m us all. So, there's a real urgency to find common ground. \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m \u001b[1mAlex\u001b[0m: And technology plays a significant role here too. Innovations in renewable energy, carbon capture, and \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m sustainable agriculture are crucial in the fight against climate change. But implementing these technologies on \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m a global scale requires significant investment and political will. \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m \u001b[1mMorgan\u001b[0m: It's a complex issue, but it's encouraging to see world leaders coming together to address it. The \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m policies they create today will shape the future for generations to come. \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m \u001b[1mAlex\u001b[0m: Absolutely. And it's not just about government action. Individuals and businesses also have a role to \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m play in reducing carbon footprints and advocating for sustainable practices. \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m \u001b[1mMorgan\u001b[0m: It's a collective effort, and every little bit helps. Before we wrap up, Alex, any final thoughts on \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m today's topics? \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m \u001b[1mAlex\u001b[0m: Just that both AI in healthcare and climate change policies highlight the intersection of technology and \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m society. They show us how innovation can drive progress but also remind us of the responsibilities that come \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m with it. \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m \u001b[1mMorgan\u001b[0m: Well said, Alex. It's all about finding that balance. And with that, we've reached the end of today's \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m episode. Thanks for tuning in to \"The World Today.\" \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m \u001b[1mAlex\u001b[0m: Don't forget to subscribe and join us next time for more insights into the latest in technology and world \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m news. \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m \u001b[1mMorgan\u001b[0m: Until then, stay informed and stay curious! \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m│\u001b[0m [OUTRO MUSIC FADES OUT] \u001b[36m│\u001b[0m\n",
|
||||
"\u001b[36m╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯\u001b[0m\n"
|
||||
],
|
||||
"text/html": [
|
||||
"<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\"><span style=\"color: #008080; text-decoration-color: #008080\">╭─────────────────────────────────────────────────── Response ────────────────────────────────────────────────────╮</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> [INTRO MUSIC FADES IN] <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"font-weight: bold\">Alex</span>: Hello and welcome to another episode of \"The World Today,\" where we dive into the latest in technology <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> and world news. I'm Alex, your go-to for all things analytical and fact-focused. <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"font-weight: bold\">Morgan</span>: And I'm Morgan, here to explore the human impact and social context of today's stories. We've got a <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> fascinating lineup for you today, so let's dive right in! <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"font-weight: bold\">Alex</span>: First up, we're talking about a topic that's been making waves across the healthcare industry: the role <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> of artificial intelligence. According to a recent article from <a href=\"https://news.example.com/ai-healthcare\" target=\"_blank\"><span style=\"color: #000080; text-decoration-color: #000080; text-decoration: underline\">News Example</span></a>, AI is revolutionizing healthcare <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> in ways we could only dream of a decade ago. <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"font-weight: bold\">Morgan</span>: That's right, Alex. AI is not just a buzzword anymore; it's actively changing how we approach <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> healthcare. From diagnostics to treatment plans, AI is helping doctors make more accurate decisions faster. But <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> what does this mean for patients and healthcare professionals? <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"font-weight: bold\">Alex</span>: Well, Morgan, AI's ability to analyze vast amounts of data quickly means that doctors can diagnose <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> diseases earlier and more accurately. For instance, AI algorithms can now detect patterns in medical imaging <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> that might be too subtle for the human eye. This can lead to earlier interventions and better patient outcomes. <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"font-weight: bold\">Morgan</span>: And let's not forget about the human side of things. For patients, this means less waiting time for <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> results and potentially more personalized treatment plans. But there's also a concern about the human touch in <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> healthcare. How do we balance the efficiency of AI with the empathy and understanding that only a human can <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> provide? <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"font-weight: bold\">Alex</span>: That's a great point. The integration of AI in healthcare does raise ethical questions. For example, who <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> is responsible if an AI system makes a mistake? And how do we ensure that these systems are free from bias? <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"font-weight: bold\">Morgan</span>: Exactly. There's a lot to consider, but the potential benefits are enormous. Imagine a world where <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> healthcare is not only more efficient but also more accessible to people in remote areas thanks to AI-driven <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> telemedicine. <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"font-weight: bold\">Alex</span>: It's a fascinating time for healthcare, no doubt. But let's shift gears a bit and talk about another <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> pressing issue: climate change and global policy. According to a report from <a href=\"https://news.example.com/climate-policy\" target=\"_blank\"><span style=\"color: #000080; text-decoration-color: #000080; text-decoration: underline\">News Example</span></a>, world leaders are <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> currently meeting to discuss new policies to combat climate change. <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"font-weight: bold\">Morgan</span>: Climate change is one of those issues that affects everyone, regardless of where you live. These global <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> meetings are crucial because they set the stage for international cooperation. But what are the main challenges <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> these leaders face? <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"font-weight: bold\">Alex</span>: One of the biggest challenges is balancing economic growth with environmental sustainability. Many <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> developing countries argue that they need to prioritize economic development, which often relies on fossil <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> fuels. Meanwhile, developed countries are pushing for stricter environmental regulations. <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"font-weight: bold\">Morgan</span>: It's a classic case of differing priorities. But there's also a growing recognition that climate change <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> doesn't respect borders. Extreme weather events, rising sea levels, and shifting agricultural patterns affect <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> us all. So, there's a real urgency to find common ground. <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"font-weight: bold\">Alex</span>: And technology plays a significant role here too. Innovations in renewable energy, carbon capture, and <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> sustainable agriculture are crucial in the fight against climate change. But implementing these technologies on <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> a global scale requires significant investment and political will. <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"font-weight: bold\">Morgan</span>: It's a complex issue, but it's encouraging to see world leaders coming together to address it. The <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> policies they create today will shape the future for generations to come. <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"font-weight: bold\">Alex</span>: Absolutely. And it's not just about government action. Individuals and businesses also have a role to <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> play in reducing carbon footprints and advocating for sustainable practices. <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"font-weight: bold\">Morgan</span>: It's a collective effort, and every little bit helps. Before we wrap up, Alex, any final thoughts on <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> today's topics? <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"font-weight: bold\">Alex</span>: Just that both AI in healthcare and climate change policies highlight the intersection of technology and <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> society. They show us how innovation can drive progress but also remind us of the responsibilities that come <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> with it. <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"font-weight: bold\">Morgan</span>: Well said, Alex. It's all about finding that balance. And with that, we've reached the end of today's <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> episode. Thanks for tuning in to \"The World Today.\" <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"font-weight: bold\">Alex</span>: Don't forget to subscribe and join us next time for more insights into the latest in technology and world <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> news. <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"font-weight: bold\">Morgan</span>: Until then, stay informed and stay curious! <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> [OUTRO MUSIC FADES OUT] <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
|
||||
"<span style=\"color: #008080; text-decoration-color: #008080\">╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯</span>\n",
|
||||
"</pre>\n"
|
||||
]
|
||||
},
|
||||
"metadata": {}
|
||||
},
|
||||
{
|
||||
"output_type": "stream",
|
||||
"name": "stdout",
|
||||
"text": [
|
||||
"=== Podcast Script ===\n",
|
||||
"[INTRO MUSIC FADES IN]\n",
|
||||
"\n",
|
||||
"**Alex**: Hello and welcome to another episode of \"The World Today,\" where we dive into the latest in technology and world news. I'm Alex, your go-to for all things analytical and fact-focused.\n",
|
||||
"\n",
|
||||
"**Morgan**: And I'm Morgan, here to explore the human impact and social context of today's stories. We've got a fascinating lineup for you today, so let's dive right in!\n",
|
||||
"\n",
|
||||
"**Alex**: First up, we're talking about a topic that's been making waves across the healthcare industry: the role of artificial intelligence. According to a recent article from [News Example](https://news.example.com/ai-healthcare), AI is revolutionizing healthcare in ways we could only dream of a decade ago.\n",
|
||||
"\n",
|
||||
"**Morgan**: That's right, Alex. AI is not just a buzzword anymore; it's actively changing how we approach healthcare. From diagnostics to treatment plans, AI is helping doctors make more accurate decisions faster. But what does this mean for patients and healthcare professionals?\n",
|
||||
"\n",
|
||||
"**Alex**: Well, Morgan, AI's ability to analyze vast amounts of data quickly means that doctors can diagnose diseases earlier and more accurately. For instance, AI algorithms can now detect patterns in medical imaging that might be too subtle for the human eye. This can lead to earlier interventions and better patient outcomes.\n",
|
||||
"\n",
|
||||
"**Morgan**: And let's not forget about the human side of things. For patients, this means less waiting time for results and potentially more personalized treatment plans. But there's also a concern about the human touch in healthcare. How do we balance the efficiency of AI with the empathy and understanding that only a human can provide?\n",
|
||||
"\n",
|
||||
"**Alex**: That's a great point. The integration of AI in healthcare does raise ethical questions. For example, who is responsible if an AI system makes a mistake? And how do we ensure that these systems are free from bias?\n",
|
||||
"\n",
|
||||
"**Morgan**: Exactly. There's a lot to consider, but the potential benefits are enormous. Imagine a world where healthcare is not only more efficient but also more accessible to people in remote areas thanks to AI-driven telemedicine.\n",
|
||||
"\n",
|
||||
"**Alex**: It's a fascinating time for healthcare, no doubt. But let's shift gears a bit and talk about another pressing issue: climate change and global policy. According to a report from [News Example](https://news.example.com/climate-policy), world leaders are currently meeting to discuss new policies to combat climate change.\n",
|
||||
"\n",
|
||||
"**Morgan**: Climate change is one of those issues that affects everyone, regardless of where you live. These global meetings are crucial because they set the stage for international cooperation. But what are the main challenges these leaders face?\n",
|
||||
"\n",
|
||||
"**Alex**: One of the biggest challenges is balancing economic growth with environmental sustainability. Many developing countries argue that they need to prioritize economic development, which often relies on fossil fuels. Meanwhile, developed countries are pushing for stricter environmental regulations.\n",
|
||||
"\n",
|
||||
"**Morgan**: It's a classic case of differing priorities. But there's also a growing recognition that climate change doesn't respect borders. Extreme weather events, rising sea levels, and shifting agricultural patterns affect us all. So, there's a real urgency to find common ground.\n",
|
||||
"\n",
|
||||
"**Alex**: And technology plays a significant role here too. Innovations in renewable energy, carbon capture, and sustainable agriculture are crucial in the fight against climate change. But implementing these technologies on a global scale requires significant investment and political will.\n",
|
||||
"\n",
|
||||
"**Morgan**: It's a complex issue, but it's encouraging to see world leaders coming together to address it. The policies they create today will shape the future for generations to come.\n",
|
||||
"\n",
|
||||
"**Alex**: Absolutely. And it's not just about government action. Individuals and businesses also have a role to play in reducing carbon footprints and advocating for sustainable practices.\n",
|
||||
"\n",
|
||||
"**Morgan**: It's a collective effort, and every little bit helps. Before we wrap up, Alex, any final thoughts on today's topics?\n",
|
||||
"\n",
|
||||
"**Alex**: Just that both AI in healthcare and climate change policies highlight the intersection of technology and society. They show us how innovation can drive progress but also remind us of the responsibilities that come with it.\n",
|
||||
"\n",
|
||||
"**Morgan**: Well said, Alex. It's all about finding that balance. And with that, we've reached the end of today's episode. Thanks for tuning in to \"The World Today.\"\n",
|
||||
"\n",
|
||||
"**Alex**: Don't forget to subscribe and join us next time for more insights into the latest in technology and world news.\n",
|
||||
"\n",
|
||||
"**Morgan**: Until then, stay informed and stay curious!\n",
|
||||
"\n",
|
||||
"[OUTRO MUSIC FADES OUT]\n"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,108 @@
|
||||
#!/usr/bin/env python
|
||||
# coding: utf-8
|
||||
|
||||
"""
|
||||
News and Podcast Aggregator Agent using PraisonAIAgents
|
||||
|
||||
This script summarizes news articles and generates podcast-style discussion points.
|
||||
It is CI-friendly: it uses dummy data if API keys are not set.
|
||||
"""
|
||||
|
||||
import os
|
||||
from datetime import datetime
|
||||
from praisonaiagents import Agent
|
||||
|
||||
# Set up the OpenAI API key for praisonaiagents
|
||||
OPENAI_API_KEY = os.environ.get("OPENAI_API_KEY", "sk-..")
|
||||
os.environ["OPENAI_API_KEY"] = OPENAI_API_KEY
|
||||
|
||||
def is_valid_key(key, prefix):
|
||||
return key and key != f"{prefix}-.." and key.startswith(prefix)
|
||||
|
||||
# Custom Tool: Format search results for podcast
|
||||
def format_search_results_for_podcast(search_results):
|
||||
created_at = datetime.now().strftime("%B %d, %Y at %I:%M %p")
|
||||
structured_content = []
|
||||
structured_content.append(f"PODCAST CREATION: {created_at}\n")
|
||||
sources = []
|
||||
for idx, search_result in enumerate(search_results):
|
||||
try:
|
||||
if search_result.get("confirmed", False):
|
||||
sources.append(search_result["url"])
|
||||
structured_content.append(
|
||||
f"""
|
||||
SOURCE {idx + 1}:
|
||||
Title: {search_result['title']}
|
||||
URL: {search_result['url']}
|
||||
Content: {search_result.get('full_text') or search_result.get('description', '')}
|
||||
---END OF SOURCE {idx + 1}---
|
||||
""".strip()
|
||||
)
|
||||
except Exception as e:
|
||||
print(f"Error processing search result: {e}")
|
||||
content_texts = "\n\n".join(structured_content)
|
||||
return content_texts, sources
|
||||
|
||||
# Agent Instructions
|
||||
from textwrap import dedent
|
||||
|
||||
PODCAST_AGENT_INSTRUCTIONS = dedent("""
|
||||
You are a helpful assistant that can generate engaging podcast scripts for the given source content and query.
|
||||
For given content, create an engaging podcast script that should be at least 15 minutes worth of content and you are allowed to enhance the script beyond given sources if you know something additional info will be interesting to the discussion or not enough content is available.
|
||||
You use the provided sources to ground your podcast script generation process. Keep it engaging and interesting.
|
||||
IMPORTANT: Generate the entire script in the provided language.
|
||||
CONTENT GUIDELINES:
|
||||
- Provide insightful analysis that helps the audience understand the significance
|
||||
- Include discussions on potential implications and broader context of each story
|
||||
- Explain complex concepts in an accessible but thorough manner
|
||||
- Make connections between current and relevant historical developments when applicable
|
||||
- Provide comparisons and contrasts with similar stories or trends when relevant
|
||||
PERSONALITY NOTES:
|
||||
- Alex is more analytical and fact-focused
|
||||
- Morgan is more focused on human impact, social context, and practical applications
|
||||
- Include natural, conversational banter and smooth transitions between topics
|
||||
- Each article discussion should go beyond the basic summary to provide valuable insights
|
||||
- Maintain a conversational but informed tone that would appeal to a general audience
|
||||
IMPORTANT:
|
||||
- MAKE SURE PODCAST SCRIPTS ARE AT LEAST 15 MINUTES LONG WHICH MEANS YOU NEED TO HAVE DETAILED DISCUSSIONS BUT KEEP IT INTERESTING AND ENGAGING.
|
||||
""")
|
||||
|
||||
if __name__ == "__main__":
|
||||
# Dummy search results for CI/public use
|
||||
dummy_search_results = [
|
||||
{
|
||||
"confirmed": True,
|
||||
"title": "AI Revolutionizes Healthcare",
|
||||
"url": "https://news.example.com/ai-healthcare",
|
||||
"full_text": "Artificial intelligence is transforming the healthcare industry by..."
|
||||
},
|
||||
{
|
||||
"confirmed": True,
|
||||
"title": "Climate Change and Global Policy",
|
||||
"url": "https://news.example.com/climate-policy",
|
||||
"full_text": "World leaders are meeting to discuss new policies for climate change..."
|
||||
}
|
||||
]
|
||||
|
||||
query = "Latest technology and world news"
|
||||
language_name = "English"
|
||||
|
||||
content_texts, sources = format_search_results_for_podcast(dummy_search_results)
|
||||
|
||||
if not is_valid_key(OPENAI_API_KEY, "sk"):
|
||||
print("API key not set or is a placeholder. Using dummy podcast script for CI/testing.")
|
||||
print("=== Podcast Script ===")
|
||||
print(f"Podcast Title: Tech & World News Roundup ({datetime.now().strftime('%B %d, %Y')})")
|
||||
for idx, article in enumerate(dummy_search_results):
|
||||
print(f"\nSection {idx+1}: {article['title']}")
|
||||
print(f"Summary: {article['full_text'][:80]}...")
|
||||
else:
|
||||
agent = Agent(
|
||||
name="Podcast Script Agent",
|
||||
instructions=PODCAST_AGENT_INSTRUCTIONS,
|
||||
api_key=OPENAI_API_KEY
|
||||
)
|
||||
prompt = f"query: {query}\nlanguage_name: {language_name}\ncontent_texts: {content_texts}\nIMPORTANT: texts should be in {language_name} language."
|
||||
podcast_script = agent.start(prompt)
|
||||
print("=== Podcast Script ===")
|
||||
print(podcast_script)
|
||||
@@ -0,0 +1,165 @@
|
||||
#!/usr/bin/env python
|
||||
# coding: utf-8
|
||||
|
||||
"""
|
||||
Air Quality Analysis Agent using PraisonAIAgents
|
||||
|
||||
This script retrieves real-time air quality data for a specified location, analyzes the results, and provides actionable health recommendations.
|
||||
It uses only praisonaiagents and is CI-friendly: it uses dummy data if API keys are not set.
|
||||
"""
|
||||
|
||||
import os
|
||||
import requests
|
||||
import yaml
|
||||
from praisonaiagents import Agent
|
||||
|
||||
# Set up API keys
|
||||
FIRECRAWL_API_KEY = os.environ.get("FIRECRAWL_API_KEY", "fc-..")
|
||||
OPENAI_API_KEY = os.environ.get("OPENAI_API_KEY", "sk-..")
|
||||
os.environ["FIRECRAWL_API_KEY"] = FIRECRAWL_API_KEY
|
||||
os.environ["OPENAI_API_KEY"] = OPENAI_API_KEY
|
||||
|
||||
# Tool: AQI Data Fetcher
|
||||
class AQIDataFetcher:
|
||||
def __init__(self, firecrawl_key: str):
|
||||
from firecrawl import FirecrawlApp
|
||||
self.firecrawl = FirecrawlApp(api_key=firecrawl_key)
|
||||
|
||||
def fetch(self, country: str, state: str, city: str):
|
||||
country_clean = country.lower().replace(' ', '-')
|
||||
city_clean = city.lower().replace(' ', '-')
|
||||
if not state or state.lower() == 'none':
|
||||
url = f"https://www.aqi.in/dashboard/{country_clean}/{city_clean}"
|
||||
else:
|
||||
state_clean = state.lower().replace(' ', '-')
|
||||
url = f"https://www.aqi.in/dashboard/{country_clean}/{state_clean}/{city_clean}"
|
||||
|
||||
print(f"Testing URL: {url}")
|
||||
try:
|
||||
resp = requests.get(url)
|
||||
print(f"Status code: {resp.status_code}")
|
||||
if resp.status_code != 200:
|
||||
print(f"URL not reachable: {url} (status code: {resp.status_code})")
|
||||
return None
|
||||
except Exception as e:
|
||||
print(f"Error: {e}")
|
||||
return None
|
||||
|
||||
schema = {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"aqi": {"type": "number", "description": "Air Quality Index"},
|
||||
"temperature": {"type": "number", "description": "Temperature in degrees Celsius"},
|
||||
"humidity": {"type": "number", "description": "Humidity percentage"},
|
||||
"wind_speed": {"type": "number", "description": "Wind speed in kilometers per hour"},
|
||||
"pm25": {"type": "number", "description": "Particulate Matter 2.5 micrometers"},
|
||||
"pm10": {"type": "number", "description": "Particulate Matter 10 micrometers"},
|
||||
"co": {"type": "number", "description": "Carbon Monoxide level"}
|
||||
},
|
||||
"required": ["aqi", "temperature", "humidity", "wind_speed", "pm25", "pm10", "co"]
|
||||
}
|
||||
|
||||
response = self.firecrawl.extract(
|
||||
urls=[f"{url}/*"],
|
||||
prompt='Extract the current real-time AQI, temperature, humidity, wind speed, PM2.5, PM10, and CO levels from the page. Also extract the timestamp of the data.',
|
||||
schema=schema
|
||||
)
|
||||
return response
|
||||
|
||||
# YAML prompt (for documentation/logging)
|
||||
yaml_prompt = """
|
||||
agent:
|
||||
name: Air Quality Health Advisor
|
||||
description: |
|
||||
An agent that analyzes real-time air quality data for a given location and provides personalized health recommendations based on user context.
|
||||
tools:
|
||||
- name: AQIDataFetcher
|
||||
description: Fetches AQI and weather data for a specified city, state, and country using Firecrawl.
|
||||
workflow:
|
||||
- step: Fetch AQI data for the user's location using AQIDataFetcher.
|
||||
- step: Analyze AQI and weather data.
|
||||
- step: Consider user's medical conditions and planned activity.
|
||||
- step: Generate health and activity recommendations.
|
||||
inputs:
|
||||
- city
|
||||
- state
|
||||
- country
|
||||
- medical_conditions
|
||||
- planned_activity
|
||||
outputs:
|
||||
- recommendations
|
||||
"""
|
||||
print(yaml.safe_load(yaml_prompt))
|
||||
|
||||
if __name__ == "__main__":
|
||||
# User input (you can change these for other locations)
|
||||
user_city = "Mumbai"
|
||||
user_state = "Maharashtra"
|
||||
user_country = "India"
|
||||
user_medical_conditions = "asthma"
|
||||
user_planned_activity = "morning jog for 2 hours"
|
||||
|
||||
aqi_fetcher = AQIDataFetcher(firecrawl_key=os.environ["FIRECRAWL_API_KEY"])
|
||||
|
||||
# Try with state, then without state, then fallback to Delhi
|
||||
aqi_data = aqi_fetcher.fetch(
|
||||
country=user_country,
|
||||
state=user_state,
|
||||
city=user_city
|
||||
)
|
||||
|
||||
if not aqi_data or not hasattr(aqi_data, "data"):
|
||||
print("Mumbai with state failed, trying without state...")
|
||||
aqi_data = aqi_fetcher.fetch(
|
||||
country=user_country,
|
||||
state="",
|
||||
city=user_city
|
||||
)
|
||||
|
||||
if not aqi_data or not hasattr(aqi_data, "data"):
|
||||
print("Trying Delhi, India...")
|
||||
aqi_data = aqi_fetcher.fetch(
|
||||
country="India",
|
||||
state="",
|
||||
city="Delhi"
|
||||
)
|
||||
|
||||
if not aqi_data or not hasattr(aqi_data, "data"):
|
||||
print("Failed to fetch AQI data for all tried locations. Please check the URLs manually.")
|
||||
else:
|
||||
aqi_data = aqi_data.data # Convert to dict
|
||||
|
||||
prompt = f"""
|
||||
You are an expert health advisor.
|
||||
|
||||
Based on the following air quality conditions in {user_city}, {user_state}, {user_country}:
|
||||
- Overall AQI: {aqi_data.get('aqi', 'N/A')}
|
||||
- PM2.5 Level: {aqi_data.get('pm25', 'N/A')} µg/m³
|
||||
- PM10 Level: {aqi_data.get('pm10', 'N/A')} µg/m³
|
||||
- CO Level: {aqi_data.get('co', 'N/A')} ppb
|
||||
|
||||
Weather conditions:
|
||||
- Temperature: {aqi_data.get('temperature', 'N/A')}°C
|
||||
- Humidity: {aqi_data.get('humidity', 'N/A')}%
|
||||
- Wind Speed: {aqi_data.get('wind_speed', 'N/A')} km/h
|
||||
|
||||
User's Context:
|
||||
- Medical Conditions: {user_medical_conditions or 'None'}
|
||||
- Planned Activity: {user_planned_activity}
|
||||
|
||||
**Comprehensive Health Recommendations:**
|
||||
1. **Impact of Current Air Quality on Health:**
|
||||
2. **Necessary Safety Precautions for Planned Activity:**
|
||||
3. **Advisability of Planned Activity:**
|
||||
4. **Best Time to Conduct the Activity:**
|
||||
"""
|
||||
|
||||
agent = Agent(
|
||||
name="Air Quality Health Advisor",
|
||||
instructions=prompt,
|
||||
api_key=os.environ["OPENAI_API_KEY"]
|
||||
)
|
||||
|
||||
recommendations = agent.start(prompt)
|
||||
print("=== Air Quality Analysis Agent Recommendations ===")
|
||||
print(recommendations)
|
||||
+107
@@ -0,0 +1,107 @@
|
||||
#!/usr/bin/env python
|
||||
# coding: utf-8
|
||||
|
||||
"""
|
||||
Game Playing Agent (Tic Tac Toe) using PraisonAIAgents
|
||||
|
||||
Two AI agents play against each other, coordinated by a referee agent.
|
||||
This script is CI-friendly: it uses dummy moves if API keys are not set.
|
||||
"""
|
||||
|
||||
import os
|
||||
from praisonaiagents import Agent
|
||||
|
||||
# Set up key (robust, CI-safe)
|
||||
OPENAI_API_KEY = os.environ.get("OPENAI_API_KEY", "sk-..")
|
||||
os.environ["OPENAI_API_KEY"] = OPENAI_API_KEY
|
||||
|
||||
def is_valid_key(key, prefix):
|
||||
return key and key != f"{prefix}-.." and key.startswith(prefix)
|
||||
|
||||
# Custom Tool: Tic Tac Toe Board & Logic
|
||||
class TicTacToeBoard:
|
||||
def __init__(self):
|
||||
self.board = [[" " for _ in range(3)] for _ in range(3)]
|
||||
self.current_player = "X"
|
||||
|
||||
def display(self):
|
||||
for row in self.board:
|
||||
print("|".join(row))
|
||||
print("-" * 5)
|
||||
|
||||
def valid_moves(self):
|
||||
return [(i, j) for i in range(3) for j in range(3) if self.board[i][j] == " "]
|
||||
|
||||
def make_move(self, row, col):
|
||||
if self.board[row][col] == " ":
|
||||
self.board[row][col] = self.current_player
|
||||
self.current_player = "O" if self.current_player == "X" else "X"
|
||||
return True
|
||||
return False
|
||||
|
||||
def check_winner(self):
|
||||
lines = self.board + [list(col) for col in zip(*self.board)] # rows and columns
|
||||
lines += [[self.board[i][i] for i in range(3)], [self.board[i][2-i] for i in range(3)]] # diagonals
|
||||
for line in lines:
|
||||
if line == ["X"] * 3:
|
||||
return "X"
|
||||
if line == ["O"] * 3:
|
||||
return "O"
|
||||
if all(cell != " " for row in self.board for cell in row):
|
||||
return "Draw"
|
||||
return None
|
||||
|
||||
if __name__ == "__main__":
|
||||
# Dummy agent moves for CI/public use
|
||||
dummy_moves = [(0, 0), (1, 1), (0, 1), (1, 0), (0, 2)]
|
||||
|
||||
board = TicTacToeBoard()
|
||||
winner = None
|
||||
|
||||
if not is_valid_key(OPENAI_API_KEY, "sk"):
|
||||
print("API key not set or is a placeholder. Using dummy moves for CI/testing.")
|
||||
print("=== Tic Tac Toe Game ===")
|
||||
board.display()
|
||||
for move in dummy_moves:
|
||||
board.make_move(*move)
|
||||
board.display()
|
||||
winner = board.check_winner()
|
||||
if winner:
|
||||
print(f"Winner: {winner}")
|
||||
break
|
||||
if not winner:
|
||||
print("Game ended in a draw.")
|
||||
else:
|
||||
# Real agent-vs-agent play using praisonaiagents
|
||||
player_x = Agent(
|
||||
name="Player X",
|
||||
instructions="You are Player X. Choose your move as 'row col' (e.g., '1 2').",
|
||||
api_key=OPENAI_API_KEY
|
||||
)
|
||||
player_o = Agent(
|
||||
name="Player O",
|
||||
instructions="You are Player O. Choose your move as 'row col' (e.g., '1 2').",
|
||||
api_key=OPENAI_API_KEY
|
||||
)
|
||||
print("=== Tic Tac Toe Game (AI vs AI) ===")
|
||||
board.display()
|
||||
for _ in range(9):
|
||||
current_agent = player_x if board.current_player == "X" else player_o
|
||||
prompt = f"Current board:\n{board.board}\nValid moves: {board.valid_moves()}\nYour move (row col):"
|
||||
move_str = current_agent.start(prompt)
|
||||
try:
|
||||
row, col = map(int, move_str.strip().split())
|
||||
except Exception:
|
||||
print(f"Invalid move from agent: {move_str}. Skipping turn.")
|
||||
continue
|
||||
if (row, col) not in board.valid_moves():
|
||||
print(f"Illegal move: {row} {col}. Skipping turn.")
|
||||
continue
|
||||
board.make_move(row, col)
|
||||
board.display()
|
||||
winner = board.check_winner()
|
||||
if winner:
|
||||
print(f"Winner: {winner}")
|
||||
break
|
||||
if not winner:
|
||||
print("Game ended in a draw.")
|
||||
+55
@@ -0,0 +1,55 @@
|
||||
#!/usr/bin/env python
|
||||
# coding: utf-8
|
||||
|
||||
"""
|
||||
Domain Deep Research Agent using PraisonAIAgents
|
||||
|
||||
This script performs deep research on a given topic and provides a structured report.
|
||||
It is CI-friendly: it uses dummy data if API keys are not set.
|
||||
"""
|
||||
|
||||
import os
|
||||
from praisonaiagents import Agent
|
||||
|
||||
# Set up key (robust, CI-safe)
|
||||
OPENAI_API_KEY = os.environ.get("OPENAI_API_KEY", "sk-..")
|
||||
os.environ["OPENAI_API_KEY"] = OPENAI_API_KEY
|
||||
|
||||
def is_valid_key(key, prefix):
|
||||
return key and key != f"{prefix}-.." and key.startswith(prefix)
|
||||
|
||||
# Custom Tool: Dummy Deep Research Tool
|
||||
class DummyDeepResearchTool:
|
||||
"""
|
||||
Custom tool to simulate deep research for CI/public use.
|
||||
"""
|
||||
def __init__(self, topic):
|
||||
self.topic = topic
|
||||
|
||||
def research(self):
|
||||
# For demo/CI, just return a dummy report
|
||||
return f"## Research Report on {self.topic}\n\n- Key finding 1 about {self.topic}\n- Key finding 2 about {self.topic}\n- Key finding 3 about {self.topic}\n"
|
||||
|
||||
if __name__ == "__main__":
|
||||
# User input (for demo, hardcoded; in real use, use input() or widgets)
|
||||
topic = "Recent advances in quantum computing"
|
||||
|
||||
# Use the custom tool
|
||||
tool = DummyDeepResearchTool(topic)
|
||||
dummy_report = tool.research()
|
||||
|
||||
if not is_valid_key(OPENAI_API_KEY, "sk"):
|
||||
print("API key not set or is a placeholder. Using dummy research report for CI/testing.")
|
||||
print(dummy_report)
|
||||
else:
|
||||
prompt = f"""
|
||||
You are a domain research assistant. Perform deep research on the following topic and provide a structured, well-cited report:
|
||||
TOPIC: {topic}
|
||||
"""
|
||||
agent = Agent(
|
||||
name="Domain Deep Research Agent",
|
||||
instructions=prompt,
|
||||
api_key=OPENAI_API_KEY
|
||||
)
|
||||
report = agent.start(prompt)
|
||||
print(report)
|
||||
+169
@@ -0,0 +1,169 @@
|
||||
#!/usr/bin/env python
|
||||
# coding: utf-8
|
||||
|
||||
# # News and Podcast Aggregator Agent using PraisonAIAgents
|
||||
|
||||
# This notebook demonstrates a News and Podcast Aggregator Agent built with `praisonaiagents`.
|
||||
# It summarizes news articles and generates podcast-style discussion points.
|
||||
# The notebook is CI-friendly: it uses dummy data if API keys are not set, so all tests/checks will pass.
|
||||
|
||||
# [](https://colab.research.google.com/github/Dhivya-Bharathy/PraisonAI/blob/main/examples/cookbooks/SocialMedia_Content_Agents/News_And_Podcast_Aggregator_Agent.ipynb)
|
||||
#
|
||||
|
||||
# # Dependencies
|
||||
|
||||
# In[ ]:
|
||||
|
||||
|
||||
get_ipython().system('pip install praisonaiagents pydantic')
|
||||
|
||||
|
||||
# # Imports and Setup
|
||||
|
||||
# In[3]:
|
||||
|
||||
|
||||
import os
|
||||
|
||||
# Set up the OpenAI API key for praisonaiagents
|
||||
os.environ["OPENAI_API_KEY"] = os.environ.get("OPENAI_API_KEY", "sk-..")
|
||||
|
||||
def is_valid_key(key, prefix):
|
||||
return key and key != f"{prefix}-.." and key.startswith(prefix)
|
||||
|
||||
OPENAI_API_KEY = os.environ["OPENAI_API_KEY"]
|
||||
|
||||
|
||||
# # Tools
|
||||
|
||||
# In[4]:
|
||||
|
||||
|
||||
from datetime import datetime
|
||||
from typing import List
|
||||
|
||||
def format_search_results_for_podcast(search_results: List[dict]) -> tuple[str, List[str]]:
|
||||
"""
|
||||
Custom tool to format search results for podcast script generation.
|
||||
"""
|
||||
created_at = datetime.now().strftime("%B %d, %Y at %I:%M %p")
|
||||
structured_content = []
|
||||
structured_content.append(f"PODCAST CREATION: {created_at}\n")
|
||||
sources = []
|
||||
for idx, search_result in enumerate(search_results):
|
||||
try:
|
||||
if search_result.get("confirmed", False):
|
||||
sources.append(search_result["url"])
|
||||
structured_content.append(
|
||||
f"""
|
||||
SOURCE {idx + 1}:
|
||||
Title: {search_result['title']}
|
||||
URL: {search_result['url']}
|
||||
Content: {search_result.get('full_text') or search_result.get('description', '')}
|
||||
---END OF SOURCE {idx + 1}---
|
||||
""".strip()
|
||||
)
|
||||
except Exception as e:
|
||||
print(f"Error processing search result: {e}")
|
||||
content_texts = "\n\n".join(structured_content)
|
||||
return content_texts, sources
|
||||
|
||||
|
||||
# # Pydantic Models
|
||||
|
||||
# In[5]:
|
||||
|
||||
|
||||
from pydantic import BaseModel, Field
|
||||
from typing import List, Optional
|
||||
|
||||
class Dialog(BaseModel):
|
||||
speaker: str = Field(..., description="The speaker name (SHOULD BE 'ALEX' OR 'MORGAN')")
|
||||
text: str = Field(..., description="The spoken text content for this speaker based on the requested language, default is English")
|
||||
|
||||
class Section(BaseModel):
|
||||
type: str = Field(..., description="The section type (intro, headlines, article, outro)")
|
||||
title: Optional[str] = Field(None, description="Optional title for the section (required for article type)")
|
||||
dialog: List[Dialog] = Field(..., description="List of dialog exchanges between speakers")
|
||||
|
||||
class PodcastScript(BaseModel):
|
||||
title: str = Field(..., description="The podcast episode title with date")
|
||||
sections: List[Section] = Field(..., description="List of podcast sections (intro, headlines, articles, outro)")
|
||||
|
||||
|
||||
# # Agent Instructions
|
||||
|
||||
# In[6]:
|
||||
|
||||
|
||||
from textwrap import dedent
|
||||
|
||||
PODCAST_AGENT_DESCRIPTION = "You are a helpful assistant that can generate engaging podcast scripts for the given sources."
|
||||
PODCAST_AGENT_INSTRUCTIONS = dedent("""
|
||||
You are a helpful assistant that can generate engaging podcast scripts for the given source content and query.
|
||||
For given content, create an engaging podcast script that should be at least 15 minutes worth of content and you are allowed to enhance the script beyond given sources if you know something additional info will be interesting to the discussion or not enough content is available.
|
||||
You use the provided sources to ground your podcast script generation process. Keep it engaging and interesting.
|
||||
IMPORTANT: Generate the entire script in the provided language.
|
||||
CONTENT GUIDELINES:
|
||||
- Provide insightful analysis that helps the audience understand the significance
|
||||
- Include discussions on potential implications and broader context of each story
|
||||
- Explain complex concepts in an accessible but thorough manner
|
||||
- Make connections between current and relevant historical developments when applicable
|
||||
- Provide comparisons and contrasts with similar stories or trends when relevant
|
||||
PERSONALITY NOTES:
|
||||
- Alex is more analytical and fact-focused
|
||||
- Morgan is more focused on human impact, social context, and practical applications
|
||||
- Include natural, conversational banter and smooth transitions between topics
|
||||
- Each article discussion should go beyond the basic summary to provide valuable insights
|
||||
- Maintain a conversational but informed tone that would appeal to a general audience
|
||||
IMPORTANT:
|
||||
- MAKE SURE PODCAST SCRIPTS ARE AT LEAST 15 MINUTES LONG WHICH MEANS YOU NEED TO HAVE DETAILED DISCUSSIONS BUT KEEP IT INTERESTING AND ENGAGING.
|
||||
""")
|
||||
|
||||
|
||||
# # Dummy Data and Main Logic
|
||||
|
||||
# In[7]:
|
||||
|
||||
|
||||
from praisonaiagents import Agent
|
||||
|
||||
# Dummy search results for CI/public use
|
||||
dummy_search_results = [
|
||||
{
|
||||
"confirmed": True,
|
||||
"title": "AI Revolutionizes Healthcare",
|
||||
"url": "https://news.example.com/ai-healthcare",
|
||||
"full_text": "Artificial intelligence is transforming the healthcare industry by..."
|
||||
},
|
||||
{
|
||||
"confirmed": True,
|
||||
"title": "Climate Change and Global Policy",
|
||||
"url": "https://news.example.com/climate-policy",
|
||||
"full_text": "World leaders are meeting to discuss new policies for climate change..."
|
||||
}
|
||||
]
|
||||
|
||||
query = "Latest technology and world news"
|
||||
language_name = "English"
|
||||
|
||||
content_texts, sources = format_search_results_for_podcast(dummy_search_results)
|
||||
|
||||
if not is_valid_key(OPENAI_API_KEY, "sk"):
|
||||
print("API key not set or is a placeholder. Using dummy podcast script for CI/testing.")
|
||||
print("=== Podcast Script ===")
|
||||
print(f"Podcast Title: Tech & World News Roundup ({datetime.now().strftime('%B %d, %Y')})")
|
||||
for idx, article in enumerate(dummy_search_results):
|
||||
print(f"\nSection {idx+1}: {article['title']}")
|
||||
print(f"Summary: {article['full_text'][:80]}...")
|
||||
else:
|
||||
agent = Agent(
|
||||
name="Podcast Script Agent",
|
||||
instructions=PODCAST_AGENT_INSTRUCTIONS,
|
||||
api_key=OPENAI_API_KEY
|
||||
)
|
||||
prompt = f"query: {query}\nlanguage_name: {language_name}\ncontent_texts: {content_texts}\nIMPORTANT: texts should be in {language_name} language."
|
||||
podcast_script = agent.start(prompt)
|
||||
print("=== Podcast Script ===")
|
||||
print(podcast_script)
|
||||
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
from praisonaiagents import Agent
|
||||
|
||||
agent = Agent(
|
||||
instructions="You are a customer support AI agent for TechGadgets.com, an online electronics store. Answer customer queries helpfully.",
|
||||
llm="xai/grok-4"
|
||||
)
|
||||
|
||||
response = agent.start("How to return an item?")
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
from praisonaiagents import Agent
|
||||
|
||||
agent = Agent(
|
||||
instructions="You are a lead generation AI agent for RealEstatePro.com. Help identify and qualify potential real estate leads.",
|
||||
llm="xai/grok-4"
|
||||
)
|
||||
|
||||
response = agent.start("I'm looking to buy a house in the suburbs with 3 bedrooms and a garden.")
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
from praisonaiagents import Agent
|
||||
|
||||
agent = Agent(
|
||||
instructions="You are a meeting productivity AI agent. Help optimize meeting efficiency and follow-up actions.",
|
||||
llm="xai/grok-4"
|
||||
)
|
||||
|
||||
response = agent.start("I have a team meeting tomorrow. How can I make it more productive?")
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
from praisonaiagents import Agent
|
||||
|
||||
agent = Agent(
|
||||
instructions="You are a mental wellbeing AI advisor. Provide supportive guidance and wellness tips.",
|
||||
llm="xai/grok-4"
|
||||
)
|
||||
|
||||
response = agent.start("I've been feeling stressed at work lately. Any tips for managing stress?")
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
from praisonaiagents import Agent
|
||||
|
||||
agent = Agent(
|
||||
instructions="You are a multimodal reasoning AI agent. Analyze images and text to provide comprehensive insights.",
|
||||
llm="xai/grok-4"
|
||||
)
|
||||
|
||||
response = agent.start("Can you help me analyze a chart showing sales data for Q1 2024?")
|
||||
@@ -0,0 +1,8 @@
|
||||
from praisonaiagents import Agent
|
||||
|
||||
agent = Agent(
|
||||
instructions="You are a helpful assistant",
|
||||
llm="ollama/qwen3"
|
||||
)
|
||||
|
||||
agent.start("Why sky is Blue?")
|
||||
@@ -7,7 +7,17 @@ import asyncio
|
||||
from typing import List, Optional, Any, Dict, Union, Literal, TYPE_CHECKING, Callable, Tuple
|
||||
from rich.console import Console
|
||||
from rich.live import Live
|
||||
from ..llm import get_openai_client
|
||||
from ..llm import (
|
||||
get_openai_client,
|
||||
ChatCompletionMessage,
|
||||
Choice,
|
||||
CompletionTokensDetails,
|
||||
PromptTokensDetails,
|
||||
CompletionUsage,
|
||||
ChatCompletion,
|
||||
ToolCall,
|
||||
process_stream_chunks
|
||||
)
|
||||
from ..main import (
|
||||
display_error,
|
||||
display_tool_call,
|
||||
@@ -21,7 +31,6 @@ from ..main import (
|
||||
)
|
||||
import inspect
|
||||
import uuid
|
||||
from dataclasses import dataclass
|
||||
|
||||
# Global variables for API server
|
||||
_server_started = {} # Dict of port -> started boolean
|
||||
@@ -35,181 +44,6 @@ if TYPE_CHECKING:
|
||||
from ..main import TaskOutput
|
||||
from ..handoff import Handoff
|
||||
|
||||
@dataclass
|
||||
class ChatCompletionMessage:
|
||||
content: str
|
||||
role: str = "assistant"
|
||||
refusal: Optional[str] = None
|
||||
audio: Optional[str] = None
|
||||
function_call: Optional[dict] = None
|
||||
tool_calls: Optional[List] = None
|
||||
reasoning_content: Optional[str] = None
|
||||
|
||||
@dataclass
|
||||
class Choice:
|
||||
finish_reason: Optional[str]
|
||||
index: int
|
||||
message: ChatCompletionMessage
|
||||
logprobs: Optional[dict] = None
|
||||
|
||||
@dataclass
|
||||
class CompletionTokensDetails:
|
||||
accepted_prediction_tokens: Optional[int] = None
|
||||
audio_tokens: Optional[int] = None
|
||||
reasoning_tokens: Optional[int] = None
|
||||
rejected_prediction_tokens: Optional[int] = None
|
||||
|
||||
@dataclass
|
||||
class PromptTokensDetails:
|
||||
audio_tokens: Optional[int] = None
|
||||
cached_tokens: int = 0
|
||||
|
||||
@dataclass
|
||||
class CompletionUsage:
|
||||
completion_tokens: int = 0
|
||||
prompt_tokens: int = 0
|
||||
total_tokens: int = 0
|
||||
completion_tokens_details: Optional[CompletionTokensDetails] = None
|
||||
prompt_tokens_details: Optional[PromptTokensDetails] = None
|
||||
prompt_cache_hit_tokens: int = 0
|
||||
prompt_cache_miss_tokens: int = 0
|
||||
|
||||
@dataclass
|
||||
class ChatCompletion:
|
||||
id: str
|
||||
choices: List[Choice]
|
||||
created: int
|
||||
model: str
|
||||
object: str = "chat.completion"
|
||||
system_fingerprint: Optional[str] = None
|
||||
service_tier: Optional[str] = None
|
||||
usage: Optional[CompletionUsage] = None
|
||||
|
||||
@dataclass
|
||||
class ToolCall:
|
||||
"""Tool call representation compatible with OpenAI format"""
|
||||
id: str
|
||||
type: str
|
||||
function: Dict[str, Any]
|
||||
|
||||
def process_stream_chunks(chunks):
|
||||
"""Process streaming chunks into combined response"""
|
||||
if not chunks:
|
||||
return None
|
||||
|
||||
try:
|
||||
first_chunk = chunks[0]
|
||||
last_chunk = chunks[-1]
|
||||
|
||||
# Basic metadata
|
||||
id = getattr(first_chunk, "id", None)
|
||||
created = getattr(first_chunk, "created", None)
|
||||
model = getattr(first_chunk, "model", None)
|
||||
system_fingerprint = getattr(first_chunk, "system_fingerprint", None)
|
||||
|
||||
# Track usage
|
||||
completion_tokens = 0
|
||||
prompt_tokens = 0
|
||||
|
||||
content_list = []
|
||||
reasoning_list = []
|
||||
tool_calls = []
|
||||
current_tool_call = None
|
||||
|
||||
# First pass: Get initial tool call data
|
||||
for chunk in chunks:
|
||||
if not hasattr(chunk, "choices") or not chunk.choices:
|
||||
continue
|
||||
|
||||
delta = getattr(chunk.choices[0], "delta", None)
|
||||
if not delta:
|
||||
continue
|
||||
|
||||
# Handle content and reasoning
|
||||
if hasattr(delta, "content") and delta.content:
|
||||
content_list.append(delta.content)
|
||||
if hasattr(delta, "reasoning_content") and delta.reasoning_content:
|
||||
reasoning_list.append(delta.reasoning_content)
|
||||
|
||||
# Handle tool calls
|
||||
if hasattr(delta, "tool_calls") and delta.tool_calls:
|
||||
for tool_call_delta in delta.tool_calls:
|
||||
if tool_call_delta.index is not None and tool_call_delta.id:
|
||||
# Found the initial tool call
|
||||
current_tool_call = {
|
||||
"id": tool_call_delta.id,
|
||||
"type": "function",
|
||||
"function": {
|
||||
"name": tool_call_delta.function.name,
|
||||
"arguments": ""
|
||||
}
|
||||
}
|
||||
while len(tool_calls) <= tool_call_delta.index:
|
||||
tool_calls.append(None)
|
||||
tool_calls[tool_call_delta.index] = current_tool_call
|
||||
current_tool_call = tool_calls[tool_call_delta.index]
|
||||
elif current_tool_call is not None and hasattr(tool_call_delta.function, "arguments"):
|
||||
if tool_call_delta.function.arguments:
|
||||
current_tool_call["function"]["arguments"] += tool_call_delta.function.arguments
|
||||
|
||||
# Remove any None values and empty tool calls
|
||||
tool_calls = [tc for tc in tool_calls if tc and tc["id"] and tc["function"]["name"]]
|
||||
|
||||
combined_content = "".join(content_list) if content_list else ""
|
||||
combined_reasoning = "".join(reasoning_list) if reasoning_list else None
|
||||
finish_reason = getattr(last_chunk.choices[0], "finish_reason", None) if hasattr(last_chunk, "choices") and last_chunk.choices else None
|
||||
|
||||
# Create ToolCall objects
|
||||
processed_tool_calls = []
|
||||
if tool_calls:
|
||||
try:
|
||||
for tc in tool_calls:
|
||||
tool_call = ToolCall(
|
||||
id=tc["id"],
|
||||
type=tc["type"],
|
||||
function={
|
||||
"name": tc["function"]["name"],
|
||||
"arguments": tc["function"]["arguments"]
|
||||
}
|
||||
)
|
||||
processed_tool_calls.append(tool_call)
|
||||
except Exception as e:
|
||||
print(f"Error processing tool call: {e}")
|
||||
|
||||
message = ChatCompletionMessage(
|
||||
content=combined_content,
|
||||
role="assistant",
|
||||
reasoning_content=combined_reasoning,
|
||||
tool_calls=processed_tool_calls if processed_tool_calls else None
|
||||
)
|
||||
|
||||
choice = Choice(
|
||||
finish_reason=finish_reason or "tool_calls" if processed_tool_calls else None,
|
||||
index=0,
|
||||
message=message
|
||||
)
|
||||
|
||||
usage = CompletionUsage(
|
||||
completion_tokens=completion_tokens,
|
||||
prompt_tokens=prompt_tokens,
|
||||
total_tokens=completion_tokens + prompt_tokens,
|
||||
completion_tokens_details=CompletionTokensDetails(),
|
||||
prompt_tokens_details=PromptTokensDetails()
|
||||
)
|
||||
|
||||
return ChatCompletion(
|
||||
id=id,
|
||||
choices=[choice],
|
||||
created=created,
|
||||
model=model,
|
||||
system_fingerprint=system_fingerprint,
|
||||
usage=usage
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
print(f"Error processing chunks: {e}")
|
||||
return None
|
||||
|
||||
class Agent:
|
||||
def _generate_tool_definition(self, function_name):
|
||||
"""
|
||||
@@ -520,8 +354,10 @@ class Agent:
|
||||
# Check for model name in environment variable if not provided
|
||||
self._using_custom_llm = False
|
||||
|
||||
# Initialize OpenAI client for direct API calls
|
||||
self._openai_client = get_openai_client(api_key=api_key, base_url=base_url)
|
||||
# Store OpenAI client parameters for lazy initialization
|
||||
self._openai_api_key = api_key
|
||||
self._openai_base_url = base_url
|
||||
self.__openai_client = None
|
||||
|
||||
# If base_url is provided, always create a custom LLM instance
|
||||
if base_url:
|
||||
@@ -654,6 +490,42 @@ Your Goal: {self.goal}
|
||||
for source in knowledge:
|
||||
self._process_knowledge(source)
|
||||
|
||||
@property
|
||||
def _openai_client(self):
|
||||
"""Lazily initialize OpenAI client only when needed."""
|
||||
if self.__openai_client is None:
|
||||
try:
|
||||
self.__openai_client = get_openai_client(
|
||||
api_key=self._openai_api_key,
|
||||
base_url=self._openai_base_url
|
||||
)
|
||||
except ValueError as e:
|
||||
# If we're using a custom LLM, we might not need the OpenAI client
|
||||
# Return None and let the calling code handle it
|
||||
if self._using_custom_llm:
|
||||
return None
|
||||
else:
|
||||
raise e
|
||||
return self.__openai_client
|
||||
|
||||
@property
|
||||
def llm_model(self):
|
||||
"""Unified property to get the LLM model regardless of configuration type.
|
||||
|
||||
Returns:
|
||||
The LLM model/instance being used by this agent.
|
||||
- For standard models: returns the model string (e.g., "gpt-4o")
|
||||
- For custom LLM instances: returns the LLM instance object
|
||||
- For provider models: returns the LLM instance object
|
||||
"""
|
||||
if hasattr(self, 'llm_instance') and self.llm_instance:
|
||||
return self.llm_instance
|
||||
elif hasattr(self, 'llm') and self.llm:
|
||||
return self.llm
|
||||
else:
|
||||
# Default fallback
|
||||
return "gpt-4o"
|
||||
|
||||
def _process_knowledge(self, knowledge_item):
|
||||
"""Process and store knowledge from a file path, URL, or string."""
|
||||
try:
|
||||
@@ -852,8 +724,6 @@ Your Goal: {self.goal}
|
||||
Returns:
|
||||
tuple: (messages list, original prompt)
|
||||
"""
|
||||
messages = []
|
||||
|
||||
# Build system prompt if enabled
|
||||
system_prompt = None
|
||||
if self.use_system_prompt:
|
||||
@@ -861,35 +731,40 @@ Your Goal: {self.goal}
|
||||
Your Role: {self.role}\n
|
||||
Your Goal: {self.goal}
|
||||
"""
|
||||
if output_json:
|
||||
system_prompt += f"\nReturn ONLY a JSON object that matches this Pydantic model: {json.dumps(output_json.model_json_schema())}"
|
||||
elif output_pydantic:
|
||||
system_prompt += f"\nReturn ONLY a JSON object that matches this Pydantic model: {json.dumps(output_pydantic.model_json_schema())}"
|
||||
|
||||
messages.append({"role": "system", "content": system_prompt})
|
||||
|
||||
# Add chat history
|
||||
messages.extend(self.chat_history)
|
||||
|
||||
# Handle prompt modifications for JSON output
|
||||
original_prompt = prompt
|
||||
if output_json or output_pydantic:
|
||||
if isinstance(prompt, str):
|
||||
prompt = prompt + "\nReturn ONLY a valid JSON object. No other text or explanation."
|
||||
elif isinstance(prompt, list):
|
||||
# Create a deep copy to avoid modifying the original
|
||||
prompt = copy.deepcopy(prompt)
|
||||
for item in prompt:
|
||||
if item.get("type") == "text":
|
||||
item["text"] = item["text"] + "\nReturn ONLY a valid JSON object. No other text or explanation."
|
||||
break
|
||||
|
||||
# Add prompt to messages
|
||||
if isinstance(prompt, list):
|
||||
# If we receive a multimodal prompt list, place it directly in the user message
|
||||
messages.append({"role": "user", "content": prompt})
|
||||
# Use openai_client's build_messages method if available
|
||||
if self._openai_client is not None:
|
||||
messages, original_prompt = self._openai_client.build_messages(
|
||||
prompt=prompt,
|
||||
system_prompt=system_prompt,
|
||||
chat_history=self.chat_history,
|
||||
output_json=output_json,
|
||||
output_pydantic=output_pydantic
|
||||
)
|
||||
else:
|
||||
messages.append({"role": "user", "content": prompt})
|
||||
# Fallback implementation for when OpenAI client is not available
|
||||
messages = []
|
||||
|
||||
# Add system message if provided
|
||||
if system_prompt:
|
||||
messages.append({"role": "system", "content": system_prompt})
|
||||
|
||||
# Add chat history
|
||||
messages.extend(self.chat_history)
|
||||
|
||||
# Add user prompt
|
||||
if isinstance(prompt, list):
|
||||
messages.extend(prompt)
|
||||
original_prompt = prompt
|
||||
else:
|
||||
messages.append({"role": "user", "content": str(prompt)})
|
||||
original_prompt = str(prompt)
|
||||
|
||||
# Add JSON format instruction if needed
|
||||
if output_json or output_pydantic:
|
||||
model = output_pydantic or output_json
|
||||
json_instruction = f"\nPlease respond with valid JSON matching this schema: {model.model_json_schema()}"
|
||||
messages[-1]["content"] += json_instruction
|
||||
|
||||
return messages, original_prompt
|
||||
|
||||
@@ -1131,50 +1006,19 @@ Your Goal: {self.goal}
|
||||
|
||||
def _process_stream_response(self, messages, temperature, start_time, formatted_tools=None, reasoning_steps=False):
|
||||
"""Process streaming response and return final response"""
|
||||
try:
|
||||
# Create the response stream
|
||||
response_stream = self._openai_client.sync_client.chat.completions.create(
|
||||
model=self.llm,
|
||||
messages=messages,
|
||||
temperature=temperature,
|
||||
tools=formatted_tools if formatted_tools else None,
|
||||
stream=True
|
||||
)
|
||||
|
||||
full_response_text = ""
|
||||
reasoning_content = ""
|
||||
chunks = []
|
||||
|
||||
# Create Live display with proper configuration
|
||||
with Live(
|
||||
display_generating("", start_time),
|
||||
console=self.console,
|
||||
refresh_per_second=4,
|
||||
transient=True,
|
||||
vertical_overflow="ellipsis",
|
||||
auto_refresh=True
|
||||
) as live:
|
||||
for chunk in response_stream:
|
||||
chunks.append(chunk)
|
||||
if chunk.choices[0].delta.content:
|
||||
full_response_text += chunk.choices[0].delta.content
|
||||
live.update(display_generating(full_response_text, start_time))
|
||||
|
||||
# Update live display with reasoning content if enabled
|
||||
if reasoning_steps and hasattr(chunk.choices[0].delta, "reasoning_content"):
|
||||
rc = chunk.choices[0].delta.reasoning_content
|
||||
if rc:
|
||||
reasoning_content += rc
|
||||
live.update(display_generating(f"{full_response_text}\n[Reasoning: {reasoning_content}]", start_time))
|
||||
|
||||
# Clear the last generating display with a blank line
|
||||
self.console.print()
|
||||
final_response = process_stream_chunks(chunks)
|
||||
return final_response
|
||||
|
||||
except Exception as e:
|
||||
display_error(f"Error in stream processing: {e}")
|
||||
return None
|
||||
if self._openai_client is None:
|
||||
raise ValueError("OpenAI client is not initialized. Please provide OPENAI_API_KEY or use a custom LLM provider.")
|
||||
|
||||
return self._openai_client.process_stream_response(
|
||||
messages=messages,
|
||||
model=self.llm,
|
||||
temperature=temperature,
|
||||
tools=formatted_tools,
|
||||
start_time=start_time,
|
||||
console=self.console,
|
||||
display_fn=display_generating,
|
||||
reasoning_steps=reasoning_steps
|
||||
)
|
||||
|
||||
def _chat_completion(self, messages, temperature=0.2, tools=None, stream=True, reasoning_steps=False):
|
||||
start_time = time.time()
|
||||
@@ -1223,117 +1067,30 @@ Your Goal: {self.goal}
|
||||
reasoning_steps=reasoning_steps
|
||||
)
|
||||
else:
|
||||
# Use the standard OpenAI client approach
|
||||
# Continue tool execution loop until no more tool calls are needed
|
||||
max_iterations = 10 # Prevent infinite loops
|
||||
iteration_count = 0
|
||||
# Use the standard OpenAI client approach with tool support
|
||||
def custom_display_fn(text, start_time):
|
||||
if self.verbose:
|
||||
return display_generating(text, start_time)
|
||||
return ""
|
||||
|
||||
while iteration_count < max_iterations:
|
||||
if stream:
|
||||
# Process as streaming response with formatted tools
|
||||
final_response = self._process_stream_response(
|
||||
messages,
|
||||
temperature,
|
||||
start_time,
|
||||
formatted_tools=formatted_tools if formatted_tools else None,
|
||||
reasoning_steps=reasoning_steps
|
||||
)
|
||||
else:
|
||||
# Process as regular non-streaming response
|
||||
final_response = self._openai_client.sync_client.chat.completions.create(
|
||||
model=self.llm,
|
||||
messages=messages,
|
||||
temperature=temperature,
|
||||
tools=formatted_tools if formatted_tools else None,
|
||||
stream=False
|
||||
)
|
||||
|
||||
tool_calls = getattr(final_response.choices[0].message, 'tool_calls', None)
|
||||
|
||||
if tool_calls:
|
||||
# Convert ToolCall dataclass objects to dict for JSON serialization
|
||||
serializable_tool_calls = []
|
||||
for tc in tool_calls:
|
||||
if isinstance(tc, ToolCall):
|
||||
# Convert dataclass to dict
|
||||
serializable_tool_calls.append({
|
||||
"id": tc.id,
|
||||
"type": tc.type,
|
||||
"function": tc.function
|
||||
})
|
||||
else:
|
||||
# Already an OpenAI object, keep as is
|
||||
serializable_tool_calls.append(tc)
|
||||
|
||||
messages.append({
|
||||
"role": "assistant",
|
||||
"content": final_response.choices[0].message.content,
|
||||
"tool_calls": serializable_tool_calls
|
||||
})
|
||||
|
||||
for tool_call in tool_calls:
|
||||
# Handle both ToolCall dataclass and OpenAI object
|
||||
if isinstance(tool_call, ToolCall):
|
||||
function_name = tool_call.function["name"]
|
||||
arguments = json.loads(tool_call.function["arguments"])
|
||||
else:
|
||||
function_name = tool_call.function.name
|
||||
arguments = json.loads(tool_call.function.arguments)
|
||||
|
||||
if self.verbose:
|
||||
display_tool_call(f"Agent {self.name} is calling function '{function_name}' with arguments: {arguments}")
|
||||
|
||||
tool_result = self.execute_tool(function_name, arguments)
|
||||
results_str = json.dumps(tool_result) if tool_result else "Function returned an empty output"
|
||||
|
||||
if self.verbose:
|
||||
display_tool_call(f"Function '{function_name}' returned: {results_str}")
|
||||
|
||||
messages.append({
|
||||
"role": "tool",
|
||||
"tool_call_id": tool_call.id if hasattr(tool_call, 'id') else tool_call['id'],
|
||||
"content": results_str
|
||||
})
|
||||
|
||||
# Check if we should continue (for tools like sequential thinking)
|
||||
should_continue = False
|
||||
for tool_call in tool_calls:
|
||||
# Handle both ToolCall dataclass and OpenAI object
|
||||
if isinstance(tool_call, ToolCall):
|
||||
function_name = tool_call.function["name"]
|
||||
arguments = json.loads(tool_call.function["arguments"])
|
||||
else:
|
||||
function_name = tool_call.function.name
|
||||
arguments = json.loads(tool_call.function.arguments)
|
||||
|
||||
# For sequential thinking tool, check if nextThoughtNeeded is True
|
||||
if function_name == "sequentialthinking" and arguments.get("nextThoughtNeeded", False):
|
||||
should_continue = True
|
||||
break
|
||||
|
||||
if not should_continue:
|
||||
# Get final response after tool calls
|
||||
if stream:
|
||||
final_response = self._process_stream_response(
|
||||
messages,
|
||||
temperature,
|
||||
start_time,
|
||||
formatted_tools=formatted_tools if formatted_tools else None,
|
||||
reasoning_steps=reasoning_steps
|
||||
)
|
||||
else:
|
||||
final_response = self._openai_client.sync_client.chat.completions.create(
|
||||
model=self.llm,
|
||||
messages=messages,
|
||||
temperature=temperature,
|
||||
stream=False
|
||||
)
|
||||
break
|
||||
|
||||
iteration_count += 1
|
||||
else:
|
||||
# No tool calls, we're done
|
||||
break
|
||||
# Note: openai_client expects tools in various formats and will format them internally
|
||||
# But since we already have formatted_tools, we can pass them directly
|
||||
if self._openai_client is None:
|
||||
raise ValueError("OpenAI client is not initialized. Please provide OPENAI_API_KEY or use a custom LLM provider.")
|
||||
|
||||
final_response = self._openai_client.chat_completion_with_tools(
|
||||
messages=messages,
|
||||
model=self.llm,
|
||||
temperature=temperature,
|
||||
tools=formatted_tools, # Already formatted for OpenAI
|
||||
execute_tool_fn=self.execute_tool,
|
||||
stream=stream,
|
||||
console=self.console if self.verbose else None,
|
||||
display_fn=display_generating if stream and self.verbose else None,
|
||||
reasoning_steps=reasoning_steps,
|
||||
verbose=self.verbose,
|
||||
max_iterations=10
|
||||
)
|
||||
|
||||
return final_response
|
||||
|
||||
@@ -1514,6 +1271,17 @@ Output MUST be JSON with 'reflection' and 'satisfactory'.
|
||||
messages.append({"role": "user", "content": reflection_prompt})
|
||||
|
||||
try:
|
||||
# Check if OpenAI client is available
|
||||
if self._openai_client is None:
|
||||
# For custom LLMs, self-reflection with structured output is not supported
|
||||
if self.verbose:
|
||||
display_self_reflection(f"Agent {self.name}: Self-reflection with structured output is not supported for custom LLM providers. Skipping reflection.", console=self.console)
|
||||
# Return the original response without reflection
|
||||
self.chat_history.append({"role": "user", "content": prompt})
|
||||
self.chat_history.append({"role": "assistant", "content": response_text})
|
||||
display_interaction(prompt, response_text, markdown=self.markdown, generation_time=time.time() - start_time, console=self.console)
|
||||
return response_text
|
||||
|
||||
reflection_response = self._openai_client.sync_client.beta.chat.completions.parse(
|
||||
model=self.reflect_llm if self.reflect_llm else self.llm,
|
||||
messages=messages,
|
||||
@@ -1700,6 +1468,12 @@ Output MUST be JSON with 'reflection' and 'satisfactory'.
|
||||
|
||||
# Use the new _format_tools_for_completion helper method
|
||||
formatted_tools = self._format_tools_for_completion(tools)
|
||||
|
||||
# Check if OpenAI client is available
|
||||
if self._openai_client is None:
|
||||
error_msg = "OpenAI client is not initialized. Please provide OPENAI_API_KEY or use a custom LLM provider."
|
||||
display_error(error_msg)
|
||||
return None
|
||||
|
||||
# Make the API call based on the type of request
|
||||
if tools:
|
||||
@@ -1754,6 +1528,19 @@ Output MUST be JSON with 'reflection' and 'satisfactory'.
|
||||
]
|
||||
|
||||
try:
|
||||
# Check if OpenAI client is available for self-reflection
|
||||
if self._openai_client is None:
|
||||
# For custom LLMs, self-reflection with structured output is not supported
|
||||
if self.verbose:
|
||||
display_self_reflection(f"Agent {self.name}: Self-reflection with structured output is not supported for custom LLM providers. Skipping reflection.", console=self.console)
|
||||
# Return the original response without reflection
|
||||
self.chat_history.append({"role": "user", "content": original_prompt})
|
||||
self.chat_history.append({"role": "assistant", "content": response_text})
|
||||
if logging.getLogger().getEffectiveLevel() == logging.DEBUG:
|
||||
total_time = time.time() - start_time
|
||||
logging.debug(f"Agent.achat completed in {total_time:.2f} seconds")
|
||||
return response_text
|
||||
|
||||
reflection_response = await self._openai_client.async_client.beta.chat.completions.parse(
|
||||
model=self.reflect_llm if self.reflect_llm else self.llm,
|
||||
messages=reflection_messages,
|
||||
|
||||
@@ -7,7 +7,7 @@ from pydantic import BaseModel
|
||||
from rich.text import Text
|
||||
from rich.panel import Panel
|
||||
from rich.console import Console
|
||||
from ..main import display_error, TaskOutput, error_logs, client
|
||||
from ..main import display_error, TaskOutput, error_logs
|
||||
from ..agent.agent import Agent
|
||||
from ..task.task import Task
|
||||
from ..process.process import Process, LoopItems
|
||||
|
||||
@@ -12,7 +12,8 @@ from typing import List, Any, Optional, Dict, Tuple
|
||||
import logging
|
||||
import os
|
||||
from pydantic import BaseModel, ConfigDict
|
||||
from ..main import display_instruction, display_tool_call, display_interaction, client
|
||||
from ..main import display_instruction, display_tool_call, display_interaction
|
||||
from ..llm import get_openai_client
|
||||
|
||||
# Define Pydantic models for structured output
|
||||
class TaskConfig(BaseModel):
|
||||
@@ -237,6 +238,17 @@ Return the configuration in a structured JSON format matching the AutoAgentsConf
|
||||
"""
|
||||
|
||||
try:
|
||||
# Get OpenAI client
|
||||
try:
|
||||
client = get_openai_client()
|
||||
except ValueError as e:
|
||||
# AutoAgents requires OpenAI for structured output generation
|
||||
raise ValueError(
|
||||
"AutoAgents requires OpenAI API for automatic agent generation. "
|
||||
"Please set OPENAI_API_KEY environment variable or use PraisonAIAgents class directly "
|
||||
"with manually configured agents for non-OpenAI providers."
|
||||
) from e
|
||||
|
||||
response = client.beta.chat.completions.parse(
|
||||
model=self.llm,
|
||||
response_format=AutoAgentsConfig,
|
||||
|
||||
@@ -20,7 +20,18 @@ logging.basicConfig(level=logging.WARNING)
|
||||
|
||||
# Import after suppressing warnings
|
||||
from .llm import LLM, LLMContextLengthExceededException
|
||||
from .openai_client import OpenAIClient, get_openai_client
|
||||
from .openai_client import (
|
||||
OpenAIClient,
|
||||
get_openai_client,
|
||||
ChatCompletionMessage,
|
||||
Choice,
|
||||
CompletionTokensDetails,
|
||||
PromptTokensDetails,
|
||||
CompletionUsage,
|
||||
ChatCompletion,
|
||||
ToolCall,
|
||||
process_stream_chunks
|
||||
)
|
||||
|
||||
# Ensure telemetry is disabled after import as well
|
||||
try:
|
||||
@@ -29,4 +40,17 @@ try:
|
||||
except ImportError:
|
||||
pass
|
||||
|
||||
__all__ = ["LLM", "LLMContextLengthExceededException", "OpenAIClient", "get_openai_client"]
|
||||
__all__ = [
|
||||
"LLM",
|
||||
"LLMContextLengthExceededException",
|
||||
"OpenAIClient",
|
||||
"get_openai_client",
|
||||
"ChatCompletionMessage",
|
||||
"Choice",
|
||||
"CompletionTokensDetails",
|
||||
"PromptTokensDetails",
|
||||
"CompletionUsage",
|
||||
"ChatCompletion",
|
||||
"ToolCall",
|
||||
"process_stream_chunks"
|
||||
]
|
||||
@@ -364,6 +364,46 @@ class LLM:
|
||||
|
||||
return messages, original_prompt
|
||||
|
||||
def _fix_array_schemas(self, schema: Dict) -> Dict:
|
||||
"""
|
||||
Recursively fix array schemas by adding missing 'items' attribute.
|
||||
|
||||
This ensures compatibility with OpenAI's function calling format which
|
||||
requires array types to specify the type of items they contain.
|
||||
|
||||
Args:
|
||||
schema: The schema dictionary to fix
|
||||
|
||||
Returns:
|
||||
dict: The fixed schema
|
||||
"""
|
||||
if not isinstance(schema, dict):
|
||||
return schema
|
||||
|
||||
# Create a copy to avoid modifying the original
|
||||
fixed_schema = schema.copy()
|
||||
|
||||
# Fix array types at the current level
|
||||
if fixed_schema.get("type") == "array" and "items" not in fixed_schema:
|
||||
# Add a default items schema for arrays without it
|
||||
fixed_schema["items"] = {"type": "string"}
|
||||
|
||||
# Recursively fix nested schemas in properties
|
||||
if "properties" in fixed_schema and isinstance(fixed_schema["properties"], dict):
|
||||
fixed_properties = {}
|
||||
for prop_name, prop_schema in fixed_schema["properties"].items():
|
||||
if isinstance(prop_schema, dict):
|
||||
fixed_properties[prop_name] = self._fix_array_schemas(prop_schema)
|
||||
else:
|
||||
fixed_properties[prop_name] = prop_schema
|
||||
fixed_schema["properties"] = fixed_properties
|
||||
|
||||
# Fix items schema if it exists
|
||||
if "items" in fixed_schema and isinstance(fixed_schema["items"], dict):
|
||||
fixed_schema["items"] = self._fix_array_schemas(fixed_schema["items"])
|
||||
|
||||
return fixed_schema
|
||||
|
||||
def _format_tools_for_litellm(self, tools: Optional[List[Any]]) -> Optional[List[Dict]]:
|
||||
"""Format tools for LiteLLM - handles all tool formats.
|
||||
|
||||
@@ -389,7 +429,11 @@ class LLM:
|
||||
# Validate nested dictionary structure before accessing
|
||||
if 'function' in tool and isinstance(tool['function'], dict) and 'name' in tool['function']:
|
||||
logging.debug(f"Using pre-formatted OpenAI tool: {tool['function']['name']}")
|
||||
formatted_tools.append(tool)
|
||||
# Fix array schemas in the tool parameters
|
||||
fixed_tool = tool.copy()
|
||||
if 'parameters' in fixed_tool['function']:
|
||||
fixed_tool['function']['parameters'] = self._fix_array_schemas(fixed_tool['function']['parameters'])
|
||||
formatted_tools.append(fixed_tool)
|
||||
else:
|
||||
logging.debug(f"Skipping malformed OpenAI tool: missing function or name")
|
||||
# Handle lists of tools (e.g. from MCP.to_openai_tool())
|
||||
@@ -399,7 +443,11 @@ class LLM:
|
||||
# Validate nested dictionary structure before accessing
|
||||
if 'function' in subtool and isinstance(subtool['function'], dict) and 'name' in subtool['function']:
|
||||
logging.debug(f"Using pre-formatted OpenAI tool from list: {subtool['function']['name']}")
|
||||
formatted_tools.append(subtool)
|
||||
# Fix array schemas in the tool parameters
|
||||
fixed_tool = subtool.copy()
|
||||
if 'parameters' in fixed_tool['function']:
|
||||
fixed_tool['function']['parameters'] = self._fix_array_schemas(fixed_tool['function']['parameters'])
|
||||
formatted_tools.append(fixed_tool)
|
||||
else:
|
||||
logging.debug(f"Skipping malformed OpenAI tool in list: missing function or name")
|
||||
elif callable(tool):
|
||||
@@ -765,99 +813,56 @@ class LLM:
|
||||
# Make one more call to get the final summary response
|
||||
# Special handling for Ollama models that don't automatically process tool results
|
||||
ollama_handled = False
|
||||
if self.model and self.model.startswith("ollama/") and tool_results:
|
||||
# For Ollama models, we need to explicitly ask the model to process the tool results
|
||||
# First, check if the response is just a JSON tool call
|
||||
try:
|
||||
# If the response_text is a valid JSON that looks like a tool call,
|
||||
# we need to make a follow-up call to process the results
|
||||
json_response = json.loads(response_text.strip())
|
||||
if ('name' in json_response or 'function' in json_response) and not any(word in response_text.lower() for word in ['summary', 'option', 'result', 'found']):
|
||||
logging.debug("Detected Ollama returning only tool call JSON, making follow-up call to process results")
|
||||
|
||||
# Create a prompt that asks the model to process the tool results based on original context
|
||||
# Extract the original user query from messages
|
||||
original_query = ""
|
||||
for msg in reversed(messages): # Look from the end to find the most recent user message
|
||||
if msg.get("role") == "user":
|
||||
content = msg.get("content", "")
|
||||
# Handle list content (multimodal)
|
||||
if isinstance(content, list):
|
||||
for item in content:
|
||||
if isinstance(item, dict) and item.get("type") == "text":
|
||||
original_query = item.get("text", "")
|
||||
break
|
||||
else:
|
||||
original_query = content
|
||||
if original_query:
|
||||
break
|
||||
|
||||
# Create a shorter follow-up prompt with all tool results
|
||||
# If there's only one result, use it directly; otherwise combine them
|
||||
if len(tool_results) == 1:
|
||||
results_text = json.dumps(tool_results[0], indent=2)
|
||||
else:
|
||||
results_text = json.dumps(tool_results, indent=2)
|
||||
|
||||
follow_up_prompt = f"Results:\n{results_text}\nProvide Answer to this Original Question based on the above results: '{original_query}'"
|
||||
logging.debug(f"[OLLAMA_DEBUG] Original query extracted: {original_query}")
|
||||
logging.debug(f"[OLLAMA_DEBUG] Follow-up prompt: {follow_up_prompt[:200]}...")
|
||||
|
||||
# Make a follow-up call to process the results
|
||||
follow_up_messages = [
|
||||
{"role": "user", "content": follow_up_prompt}
|
||||
]
|
||||
|
||||
# Get response with streaming
|
||||
if verbose:
|
||||
with Live(display_generating("", start_time), console=console, refresh_per_second=4) as live:
|
||||
response_text = ""
|
||||
for chunk in litellm.completion(
|
||||
**self._build_completion_params(
|
||||
messages=follow_up_messages,
|
||||
temperature=temperature,
|
||||
stream=stream
|
||||
)
|
||||
):
|
||||
if chunk and chunk.choices and chunk.choices[0].delta.content:
|
||||
content = chunk.choices[0].delta.content
|
||||
response_text += content
|
||||
live.update(display_generating(response_text, start_time))
|
||||
else:
|
||||
response_text = ""
|
||||
for chunk in litellm.completion(
|
||||
**self._build_completion_params(
|
||||
messages=follow_up_messages,
|
||||
temperature=temperature,
|
||||
stream=stream
|
||||
)
|
||||
):
|
||||
if chunk and chunk.choices and chunk.choices[0].delta.content:
|
||||
response_text += chunk.choices[0].delta.content
|
||||
|
||||
# Set flag to indicate Ollama was handled
|
||||
ollama_handled = True
|
||||
final_response_text = response_text.strip()
|
||||
logging.debug(f"[OLLAMA_DEBUG] Ollama follow-up response: {final_response_text[:200]}...")
|
||||
|
||||
# Display the response if we got one
|
||||
if final_response_text and verbose:
|
||||
display_interaction(
|
||||
original_prompt,
|
||||
final_response_text,
|
||||
markdown=markdown,
|
||||
generation_time=time.time() - start_time,
|
||||
console=console
|
||||
ollama_params = self._handle_ollama_model(response_text, tool_results, messages, original_prompt)
|
||||
|
||||
if ollama_params:
|
||||
# Get response with streaming
|
||||
if verbose:
|
||||
with Live(display_generating("", start_time), console=console, refresh_per_second=4) as live:
|
||||
response_text = ""
|
||||
for chunk in litellm.completion(
|
||||
**self._build_completion_params(
|
||||
messages=ollama_params["follow_up_messages"],
|
||||
temperature=temperature,
|
||||
stream=stream
|
||||
)
|
||||
|
||||
# Return the final response after processing Ollama's follow-up
|
||||
if final_response_text:
|
||||
return final_response_text
|
||||
else:
|
||||
logging.warning("[OLLAMA_DEBUG] Ollama follow-up returned empty response")
|
||||
except (json.JSONDecodeError, KeyError):
|
||||
# Not a JSON response or not a tool call format, continue normally
|
||||
pass
|
||||
):
|
||||
if chunk and chunk.choices and chunk.choices[0].delta.content:
|
||||
content = chunk.choices[0].delta.content
|
||||
response_text += content
|
||||
live.update(display_generating(response_text, start_time))
|
||||
else:
|
||||
response_text = ""
|
||||
for chunk in litellm.completion(
|
||||
**self._build_completion_params(
|
||||
messages=ollama_params["follow_up_messages"],
|
||||
temperature=temperature,
|
||||
stream=stream
|
||||
)
|
||||
):
|
||||
if chunk and chunk.choices and chunk.choices[0].delta.content:
|
||||
response_text += chunk.choices[0].delta.content
|
||||
|
||||
# Set flag to indicate Ollama was handled
|
||||
ollama_handled = True
|
||||
final_response_text = response_text.strip()
|
||||
logging.debug(f"[OLLAMA_DEBUG] Ollama follow-up response: {final_response_text[:200]}...")
|
||||
|
||||
# Display the response if we got one
|
||||
if final_response_text and verbose:
|
||||
display_interaction(
|
||||
ollama_params["original_prompt"],
|
||||
final_response_text,
|
||||
markdown=markdown,
|
||||
generation_time=time.time() - start_time,
|
||||
console=console
|
||||
)
|
||||
|
||||
# Return the final response after processing Ollama's follow-up
|
||||
if final_response_text:
|
||||
return final_response_text
|
||||
else:
|
||||
logging.warning("[OLLAMA_DEBUG] Ollama follow-up returned empty response")
|
||||
|
||||
# If reasoning_steps is True and we haven't handled Ollama already, do a single non-streaming call
|
||||
if reasoning_steps and not ollama_handled:
|
||||
@@ -1432,99 +1437,56 @@ Output MUST be JSON with 'reflection' and 'satisfactory'.
|
||||
|
||||
# Special handling for Ollama models that don't automatically process tool results
|
||||
ollama_handled = False
|
||||
if self._is_ollama_provider() and tool_results:
|
||||
# For Ollama models, we need to explicitly ask the model to process the tool results
|
||||
# First, check if the response is just a JSON tool call
|
||||
try:
|
||||
# If the response_text is a valid JSON that looks like a tool call,
|
||||
# we need to make a follow-up call to process the results
|
||||
json_response = json.loads(response_text.strip())
|
||||
if ('name' in json_response or 'function' in json_response) and not any(word in response_text.lower() for word in ['summary', 'option', 'result', 'found']):
|
||||
logging.debug("Detected Ollama returning only tool call JSON in async mode, making follow-up call to process results")
|
||||
|
||||
# Create a prompt that asks the model to process the tool results based on original context
|
||||
# Extract the original user query from messages
|
||||
original_query = ""
|
||||
for msg in reversed(messages): # Look from the end to find the most recent user message
|
||||
if msg.get("role") == "user":
|
||||
content = msg.get("content", "")
|
||||
# Handle list content (multimodal)
|
||||
if isinstance(content, list):
|
||||
for item in content:
|
||||
if isinstance(item, dict) and item.get("type") == "text":
|
||||
original_query = item.get("text", "")
|
||||
break
|
||||
else:
|
||||
original_query = content
|
||||
if original_query:
|
||||
break
|
||||
|
||||
# Create a shorter follow-up prompt with all tool results
|
||||
# If there's only one result, use it directly; otherwise combine them
|
||||
if len(tool_results) == 1:
|
||||
results_text = json.dumps(tool_results[0], indent=2)
|
||||
else:
|
||||
results_text = json.dumps(tool_results, indent=2)
|
||||
|
||||
follow_up_prompt = f"Results:\n{results_text}\nProvide Answer to this Original Question based on the above results: '{original_query}'"
|
||||
logging.debug(f"[OLLAMA_DEBUG] Original query extracted: {original_query}")
|
||||
logging.debug(f"[OLLAMA_DEBUG] Follow-up prompt: {follow_up_prompt[:200]}...")
|
||||
|
||||
# Make a follow-up call to process the results
|
||||
follow_up_messages = [
|
||||
{"role": "user", "content": follow_up_prompt}
|
||||
]
|
||||
|
||||
# Get response with streaming
|
||||
if verbose:
|
||||
response_text = ""
|
||||
async for chunk in await litellm.acompletion(
|
||||
**self._build_completion_params(
|
||||
messages=follow_up_messages,
|
||||
temperature=temperature,
|
||||
stream=stream
|
||||
)
|
||||
):
|
||||
if chunk and chunk.choices and chunk.choices[0].delta.content:
|
||||
content = chunk.choices[0].delta.content
|
||||
response_text += content
|
||||
print("\033[K", end="\r")
|
||||
print(f"Processing results... {time.time() - start_time:.1f}s", end="\r")
|
||||
else:
|
||||
response_text = ""
|
||||
async for chunk in await litellm.acompletion(
|
||||
**self._build_completion_params(
|
||||
messages=follow_up_messages,
|
||||
temperature=temperature,
|
||||
stream=stream
|
||||
)
|
||||
):
|
||||
if chunk and chunk.choices and chunk.choices[0].delta.content:
|
||||
response_text += chunk.choices[0].delta.content
|
||||
|
||||
# Set flag to indicate Ollama was handled
|
||||
ollama_handled = True
|
||||
final_response_text = response_text.strip()
|
||||
logging.debug(f"[OLLAMA_DEBUG] Ollama follow-up response: {final_response_text[:200]}...")
|
||||
|
||||
# Display the response if we got one
|
||||
if final_response_text and verbose:
|
||||
display_interaction(
|
||||
original_prompt,
|
||||
final_response_text,
|
||||
markdown=markdown,
|
||||
generation_time=time.time() - start_time,
|
||||
console=console
|
||||
)
|
||||
|
||||
# Return the final response after processing Ollama's follow-up
|
||||
if final_response_text:
|
||||
return final_response_text
|
||||
else:
|
||||
logging.warning("[OLLAMA_DEBUG] Ollama follow-up returned empty response")
|
||||
except (json.JSONDecodeError, KeyError):
|
||||
# Not a JSON response or not a tool call format, continue normally
|
||||
pass
|
||||
ollama_params = self._handle_ollama_model(response_text, tool_results, messages, original_prompt)
|
||||
|
||||
if ollama_params:
|
||||
# Get response with streaming
|
||||
if verbose:
|
||||
response_text = ""
|
||||
async for chunk in await litellm.acompletion(
|
||||
**self._build_completion_params(
|
||||
messages=ollama_params["follow_up_messages"],
|
||||
temperature=temperature,
|
||||
stream=stream
|
||||
)
|
||||
):
|
||||
if chunk and chunk.choices and chunk.choices[0].delta.content:
|
||||
content = chunk.choices[0].delta.content
|
||||
response_text += content
|
||||
print("\033[K", end="\r")
|
||||
print(f"Processing results... {time.time() - start_time:.1f}s", end="\r")
|
||||
else:
|
||||
response_text = ""
|
||||
async for chunk in await litellm.acompletion(
|
||||
**self._build_completion_params(
|
||||
messages=ollama_params["follow_up_messages"],
|
||||
temperature=temperature,
|
||||
stream=stream
|
||||
)
|
||||
):
|
||||
if chunk and chunk.choices and chunk.choices[0].delta.content:
|
||||
response_text += chunk.choices[0].delta.content
|
||||
|
||||
# Set flag to indicate Ollama was handled
|
||||
ollama_handled = True
|
||||
final_response_text = response_text.strip()
|
||||
logging.debug(f"[OLLAMA_DEBUG] Ollama follow-up response: {final_response_text[:200]}...")
|
||||
|
||||
# Display the response if we got one
|
||||
if final_response_text and verbose:
|
||||
display_interaction(
|
||||
ollama_params["original_prompt"],
|
||||
final_response_text,
|
||||
markdown=markdown,
|
||||
generation_time=time.time() - start_time,
|
||||
console=console
|
||||
)
|
||||
|
||||
# Return the final response after processing Ollama's follow-up
|
||||
if final_response_text:
|
||||
return final_response_text
|
||||
else:
|
||||
logging.warning("[OLLAMA_DEBUG] Ollama follow-up returned empty response")
|
||||
|
||||
# If no special handling was needed or if it's not an Ollama model
|
||||
if reasoning_steps and not ollama_handled:
|
||||
@@ -1791,6 +1753,68 @@ Output MUST be JSON with 'reflection' and 'satisfactory'.
|
||||
|
||||
litellm.callbacks = events
|
||||
|
||||
def _handle_ollama_model(self, response_text: str, tool_results: List[Any], messages: List[Dict], original_prompt: Union[str, List[Dict]]) -> Optional[Dict[str, Any]]:
|
||||
"""
|
||||
Handle special Ollama model requirements when processing tool results.
|
||||
|
||||
Args:
|
||||
response_text: The initial response text from the model
|
||||
tool_results: List of tool execution results
|
||||
messages: The conversation messages list
|
||||
original_prompt: The original user prompt
|
||||
|
||||
Returns:
|
||||
Dict with follow-up parameters if Ollama needs special handling, None otherwise
|
||||
"""
|
||||
if not self._is_ollama_provider() or not tool_results:
|
||||
return None
|
||||
|
||||
# Check if the response is just a JSON tool call
|
||||
try:
|
||||
json_response = json.loads(response_text.strip())
|
||||
if not (('name' in json_response or 'function' in json_response) and
|
||||
not any(word in response_text.lower() for word in ['summary', 'option', 'result', 'found'])):
|
||||
return None
|
||||
|
||||
logging.debug("Detected Ollama returning only tool call JSON, preparing follow-up call to process results")
|
||||
|
||||
# Extract the original user query from messages
|
||||
original_query = ""
|
||||
for msg in reversed(messages): # Look from the end to find the most recent user message
|
||||
if msg.get("role") == "user":
|
||||
content = msg.get("content", "")
|
||||
# Handle list content (multimodal)
|
||||
if isinstance(content, list):
|
||||
for item in content:
|
||||
if isinstance(item, dict) and item.get("type") == "text":
|
||||
original_query = item.get("text", "")
|
||||
break
|
||||
else:
|
||||
original_query = content
|
||||
if original_query:
|
||||
break
|
||||
|
||||
# Create a shorter follow-up prompt with all tool results
|
||||
# If there's only one result, use it directly; otherwise combine them
|
||||
if len(tool_results) == 1:
|
||||
results_text = json.dumps(tool_results[0], indent=2)
|
||||
else:
|
||||
results_text = json.dumps(tool_results, indent=2)
|
||||
|
||||
follow_up_prompt = f"Results:\n{results_text}\nProvide Answer to this Original Question based on the above results: '{original_query}'"
|
||||
logging.debug(f"[OLLAMA_DEBUG] Original query extracted: {original_query}")
|
||||
logging.debug(f"[OLLAMA_DEBUG] Follow-up prompt: {follow_up_prompt[:200]}...")
|
||||
|
||||
# Return parameters for follow-up call
|
||||
return {
|
||||
"follow_up_messages": [{"role": "user", "content": follow_up_prompt}],
|
||||
"original_prompt": original_prompt
|
||||
}
|
||||
|
||||
except (json.JSONDecodeError, KeyError):
|
||||
# Not a JSON response or not a tool call format
|
||||
return None
|
||||
|
||||
def _build_completion_params(self, **override_params) -> Dict[str, Any]:
|
||||
"""Build parameters for litellm completion calls with all necessary config"""
|
||||
params = {
|
||||
@@ -2153,7 +2177,7 @@ Output MUST be JSON with 'reflection' and 'satisfactory'.
|
||||
"function": {
|
||||
"name": function_name,
|
||||
"description": docstring.split('\n\n')[0] if docstring else "No description available",
|
||||
"parameters": parameters
|
||||
"parameters": self._fix_array_schemas(parameters)
|
||||
}
|
||||
}
|
||||
logging.debug(f"Generated tool definition: {tool_def}")
|
||||
|
||||
@@ -7,15 +7,199 @@ supporting both synchronous and asynchronous operations.
|
||||
|
||||
import os
|
||||
import logging
|
||||
from typing import Any, Dict, List, Optional, Union, AsyncIterator, Iterator
|
||||
import time
|
||||
import json
|
||||
import asyncio
|
||||
from typing import Any, Dict, List, Optional, Union, AsyncIterator, Iterator, Callable, Tuple
|
||||
from openai import OpenAI, AsyncOpenAI
|
||||
from openai.types.chat import ChatCompletionChunk
|
||||
import asyncio
|
||||
from pydantic import BaseModel
|
||||
from dataclasses import dataclass
|
||||
from rich.console import Console
|
||||
from rich.live import Live
|
||||
import inspect
|
||||
|
||||
# Constants
|
||||
LOCAL_SERVER_API_KEY_PLACEHOLDER = "not-needed"
|
||||
|
||||
# Data Classes for OpenAI Response Structure
|
||||
@dataclass
|
||||
class ChatCompletionMessage:
|
||||
content: str
|
||||
role: str = "assistant"
|
||||
refusal: Optional[str] = None
|
||||
audio: Optional[str] = None
|
||||
function_call: Optional[dict] = None
|
||||
tool_calls: Optional[List] = None
|
||||
reasoning_content: Optional[str] = None
|
||||
|
||||
@dataclass
|
||||
class Choice:
|
||||
finish_reason: Optional[str]
|
||||
index: int
|
||||
message: ChatCompletionMessage
|
||||
logprobs: Optional[dict] = None
|
||||
|
||||
@dataclass
|
||||
class CompletionTokensDetails:
|
||||
accepted_prediction_tokens: Optional[int] = None
|
||||
audio_tokens: Optional[int] = None
|
||||
reasoning_tokens: Optional[int] = None
|
||||
rejected_prediction_tokens: Optional[int] = None
|
||||
|
||||
@dataclass
|
||||
class PromptTokensDetails:
|
||||
audio_tokens: Optional[int] = None
|
||||
cached_tokens: int = 0
|
||||
|
||||
@dataclass
|
||||
class CompletionUsage:
|
||||
completion_tokens: int = 0
|
||||
prompt_tokens: int = 0
|
||||
total_tokens: int = 0
|
||||
completion_tokens_details: Optional[CompletionTokensDetails] = None
|
||||
prompt_tokens_details: Optional[PromptTokensDetails] = None
|
||||
prompt_cache_hit_tokens: int = 0
|
||||
prompt_cache_miss_tokens: int = 0
|
||||
|
||||
@dataclass
|
||||
class ChatCompletion:
|
||||
id: str
|
||||
choices: List[Choice]
|
||||
created: int
|
||||
model: str
|
||||
object: str = "chat.completion"
|
||||
system_fingerprint: Optional[str] = None
|
||||
service_tier: Optional[str] = None
|
||||
usage: Optional[CompletionUsage] = None
|
||||
|
||||
@dataclass
|
||||
class ToolCall:
|
||||
"""Tool call representation compatible with OpenAI format"""
|
||||
id: str
|
||||
type: str
|
||||
function: Dict[str, Any]
|
||||
|
||||
|
||||
def process_stream_chunks(chunks):
|
||||
"""Process streaming chunks into combined response"""
|
||||
if not chunks:
|
||||
return None
|
||||
|
||||
try:
|
||||
first_chunk = chunks[0]
|
||||
last_chunk = chunks[-1]
|
||||
|
||||
# Basic metadata
|
||||
id = getattr(first_chunk, "id", None)
|
||||
created = getattr(first_chunk, "created", None)
|
||||
model = getattr(first_chunk, "model", None)
|
||||
system_fingerprint = getattr(first_chunk, "system_fingerprint", None)
|
||||
|
||||
# Track usage
|
||||
completion_tokens = 0
|
||||
prompt_tokens = 0
|
||||
|
||||
content_list = []
|
||||
reasoning_list = []
|
||||
tool_calls = []
|
||||
current_tool_call = None
|
||||
|
||||
# First pass: Get initial tool call data
|
||||
for chunk in chunks:
|
||||
if not hasattr(chunk, "choices") or not chunk.choices:
|
||||
continue
|
||||
|
||||
delta = getattr(chunk.choices[0], "delta", None)
|
||||
if not delta:
|
||||
continue
|
||||
|
||||
# Handle content and reasoning
|
||||
if hasattr(delta, "content") and delta.content:
|
||||
content_list.append(delta.content)
|
||||
if hasattr(delta, "reasoning_content") and delta.reasoning_content:
|
||||
reasoning_list.append(delta.reasoning_content)
|
||||
|
||||
# Handle tool calls
|
||||
if hasattr(delta, "tool_calls") and delta.tool_calls:
|
||||
for tool_call_delta in delta.tool_calls:
|
||||
if tool_call_delta.index is not None and tool_call_delta.id:
|
||||
# Found the initial tool call
|
||||
current_tool_call = {
|
||||
"id": tool_call_delta.id,
|
||||
"type": "function",
|
||||
"function": {
|
||||
"name": tool_call_delta.function.name,
|
||||
"arguments": ""
|
||||
}
|
||||
}
|
||||
while len(tool_calls) <= tool_call_delta.index:
|
||||
tool_calls.append(None)
|
||||
tool_calls[tool_call_delta.index] = current_tool_call
|
||||
current_tool_call = tool_calls[tool_call_delta.index]
|
||||
elif current_tool_call is not None and hasattr(tool_call_delta.function, "arguments"):
|
||||
if tool_call_delta.function.arguments:
|
||||
current_tool_call["function"]["arguments"] += tool_call_delta.function.arguments
|
||||
|
||||
# Remove any None values and empty tool calls
|
||||
tool_calls = [tc for tc in tool_calls if tc and tc["id"] and tc["function"]["name"]]
|
||||
|
||||
combined_content = "".join(content_list) if content_list else ""
|
||||
combined_reasoning = "".join(reasoning_list) if reasoning_list else None
|
||||
finish_reason = getattr(last_chunk.choices[0], "finish_reason", None) if hasattr(last_chunk, "choices") and last_chunk.choices else None
|
||||
|
||||
# Create ToolCall objects
|
||||
processed_tool_calls = []
|
||||
if tool_calls:
|
||||
try:
|
||||
for tc in tool_calls:
|
||||
tool_call = ToolCall(
|
||||
id=tc["id"],
|
||||
type=tc["type"],
|
||||
function={
|
||||
"name": tc["function"]["name"],
|
||||
"arguments": tc["function"]["arguments"]
|
||||
}
|
||||
)
|
||||
processed_tool_calls.append(tool_call)
|
||||
except Exception as e:
|
||||
print(f"Error processing tool call: {e}")
|
||||
|
||||
message = ChatCompletionMessage(
|
||||
content=combined_content,
|
||||
role="assistant",
|
||||
reasoning_content=combined_reasoning,
|
||||
tool_calls=processed_tool_calls if processed_tool_calls else None
|
||||
)
|
||||
|
||||
choice = Choice(
|
||||
finish_reason=finish_reason or "tool_calls" if processed_tool_calls else None,
|
||||
index=0,
|
||||
message=message
|
||||
)
|
||||
|
||||
usage = CompletionUsage(
|
||||
completion_tokens=completion_tokens,
|
||||
prompt_tokens=prompt_tokens,
|
||||
total_tokens=completion_tokens + prompt_tokens,
|
||||
completion_tokens_details=CompletionTokensDetails(),
|
||||
prompt_tokens_details=PromptTokensDetails()
|
||||
)
|
||||
|
||||
return ChatCompletion(
|
||||
id=id,
|
||||
choices=[choice],
|
||||
created=created,
|
||||
model=model,
|
||||
system_fingerprint=system_fingerprint,
|
||||
usage=usage
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
print(f"Error processing chunks: {e}")
|
||||
return None
|
||||
|
||||
|
||||
class OpenAIClient:
|
||||
"""
|
||||
Unified OpenAI client wrapper for sync/async operations.
|
||||
@@ -52,6 +236,9 @@ class OpenAIClient:
|
||||
|
||||
# Set up logging
|
||||
self.logger = logging.getLogger(__name__)
|
||||
|
||||
# Initialize console for display
|
||||
self.console = Console()
|
||||
|
||||
@property
|
||||
def sync_client(self) -> OpenAI:
|
||||
@@ -65,6 +252,427 @@ class OpenAIClient:
|
||||
self._async_client = AsyncOpenAI(api_key=self.api_key, base_url=self.base_url)
|
||||
return self._async_client
|
||||
|
||||
def build_messages(
|
||||
self,
|
||||
prompt: Union[str, List[Dict]],
|
||||
system_prompt: Optional[str] = None,
|
||||
chat_history: Optional[List[Dict]] = None,
|
||||
output_json: Optional[BaseModel] = None,
|
||||
output_pydantic: Optional[BaseModel] = None
|
||||
) -> Tuple[List[Dict], Union[str, List[Dict]]]:
|
||||
"""
|
||||
Build messages list for OpenAI completion.
|
||||
|
||||
Args:
|
||||
prompt: The user prompt (str or list)
|
||||
system_prompt: Optional system prompt
|
||||
chat_history: Optional list of previous messages
|
||||
output_json: Optional Pydantic model for JSON output
|
||||
output_pydantic: Optional Pydantic model for JSON output (alias)
|
||||
|
||||
Returns:
|
||||
tuple: (messages list, original prompt)
|
||||
"""
|
||||
messages = []
|
||||
|
||||
# Handle system prompt
|
||||
if system_prompt:
|
||||
# Append JSON schema if needed
|
||||
if output_json:
|
||||
system_prompt += f"\nReturn ONLY a JSON object that matches this Pydantic model: {json.dumps(output_json.model_json_schema())}"
|
||||
elif output_pydantic:
|
||||
system_prompt += f"\nReturn ONLY a JSON object that matches this Pydantic model: {json.dumps(output_pydantic.model_json_schema())}"
|
||||
|
||||
messages.append({"role": "system", "content": system_prompt})
|
||||
|
||||
# Add chat history if provided
|
||||
if chat_history:
|
||||
messages.extend(chat_history)
|
||||
|
||||
# Handle prompt modifications for JSON output
|
||||
original_prompt = prompt
|
||||
if output_json or output_pydantic:
|
||||
if isinstance(prompt, str):
|
||||
prompt = prompt + "\nReturn ONLY a valid JSON object. No other text or explanation."
|
||||
elif isinstance(prompt, list):
|
||||
# Create a copy to avoid modifying the original
|
||||
prompt = prompt.copy()
|
||||
for item in prompt:
|
||||
if item.get("type") == "text":
|
||||
item["text"] = item["text"] + "\nReturn ONLY a valid JSON object. No other text or explanation."
|
||||
break
|
||||
|
||||
# Add prompt to messages
|
||||
if isinstance(prompt, list):
|
||||
messages.append({"role": "user", "content": prompt})
|
||||
else:
|
||||
messages.append({"role": "user", "content": prompt})
|
||||
|
||||
return messages, original_prompt
|
||||
|
||||
def _fix_array_schemas(self, schema: Dict) -> Dict:
|
||||
"""
|
||||
Recursively fix array schemas by adding missing 'items' attribute.
|
||||
|
||||
This ensures compatibility with OpenAI's function calling format which
|
||||
requires array types to specify the type of items they contain.
|
||||
|
||||
Args:
|
||||
schema: The schema dictionary to fix
|
||||
|
||||
Returns:
|
||||
dict: The fixed schema
|
||||
"""
|
||||
if not isinstance(schema, dict):
|
||||
return schema
|
||||
|
||||
# Create a copy to avoid modifying the original
|
||||
fixed_schema = schema.copy()
|
||||
|
||||
# Fix array types at the current level
|
||||
if fixed_schema.get("type") == "array" and "items" not in fixed_schema:
|
||||
# Add a default items schema for arrays without it
|
||||
fixed_schema["items"] = {"type": "string"}
|
||||
|
||||
# Recursively fix nested schemas in properties
|
||||
if "properties" in fixed_schema and isinstance(fixed_schema["properties"], dict):
|
||||
fixed_properties = {}
|
||||
for prop_name, prop_schema in fixed_schema["properties"].items():
|
||||
if isinstance(prop_schema, dict):
|
||||
fixed_properties[prop_name] = self._fix_array_schemas(prop_schema)
|
||||
else:
|
||||
fixed_properties[prop_name] = prop_schema
|
||||
fixed_schema["properties"] = fixed_properties
|
||||
|
||||
# Fix items schema if it exists
|
||||
if "items" in fixed_schema and isinstance(fixed_schema["items"], dict):
|
||||
fixed_schema["items"] = self._fix_array_schemas(fixed_schema["items"])
|
||||
|
||||
return fixed_schema
|
||||
|
||||
def format_tools(self, tools: Optional[List[Any]]) -> Optional[List[Dict]]:
|
||||
"""
|
||||
Format tools for OpenAI API.
|
||||
|
||||
Supports:
|
||||
- Pre-formatted OpenAI tools (dicts with type='function')
|
||||
- Lists of pre-formatted tools
|
||||
- Callable functions
|
||||
- String function names
|
||||
- MCP tools
|
||||
|
||||
Args:
|
||||
tools: List of tools in various formats
|
||||
|
||||
Returns:
|
||||
List of formatted tools or None
|
||||
"""
|
||||
if not tools:
|
||||
return None
|
||||
|
||||
formatted_tools = []
|
||||
for tool in tools:
|
||||
# Check if the tool is already in OpenAI format
|
||||
if isinstance(tool, dict) and 'type' in tool and tool['type'] == 'function':
|
||||
if 'function' in tool and isinstance(tool['function'], dict) and 'name' in tool['function']:
|
||||
logging.debug(f"Using pre-formatted OpenAI tool: {tool['function']['name']}")
|
||||
# Fix array schemas in the tool parameters
|
||||
fixed_tool = tool.copy()
|
||||
if 'parameters' in fixed_tool['function']:
|
||||
fixed_tool['function']['parameters'] = self._fix_array_schemas(fixed_tool['function']['parameters'])
|
||||
formatted_tools.append(fixed_tool)
|
||||
else:
|
||||
logging.debug("Skipping malformed OpenAI tool: missing function or name")
|
||||
# Handle lists of tools
|
||||
elif isinstance(tool, list):
|
||||
for subtool in tool:
|
||||
if isinstance(subtool, dict) and 'type' in subtool and subtool['type'] == 'function':
|
||||
if 'function' in subtool and isinstance(subtool['function'], dict) and 'name' in subtool['function']:
|
||||
logging.debug(f"Using pre-formatted OpenAI tool from list: {subtool['function']['name']}")
|
||||
# Fix array schemas in the tool parameters
|
||||
fixed_tool = subtool.copy()
|
||||
if 'parameters' in fixed_tool['function']:
|
||||
fixed_tool['function']['parameters'] = self._fix_array_schemas(fixed_tool['function']['parameters'])
|
||||
formatted_tools.append(fixed_tool)
|
||||
else:
|
||||
logging.debug("Skipping malformed OpenAI tool in list: missing function or name")
|
||||
elif callable(tool):
|
||||
tool_def = self._generate_tool_definition(tool)
|
||||
if tool_def:
|
||||
formatted_tools.append(tool_def)
|
||||
elif isinstance(tool, str):
|
||||
tool_def = self._generate_tool_definition_from_name(tool)
|
||||
if tool_def:
|
||||
formatted_tools.append(tool_def)
|
||||
else:
|
||||
logging.debug(f"Skipping tool of unsupported type: {type(tool)}")
|
||||
|
||||
# Validate JSON serialization before returning
|
||||
if formatted_tools:
|
||||
try:
|
||||
json.dumps(formatted_tools) # Validate serialization
|
||||
except (TypeError, ValueError) as e:
|
||||
logging.error(f"Tools are not JSON serializable: {e}")
|
||||
return None
|
||||
|
||||
return formatted_tools if formatted_tools else None
|
||||
|
||||
def _generate_tool_definition(self, func: Callable) -> Optional[Dict]:
|
||||
"""Generate a tool definition from a callable function."""
|
||||
try:
|
||||
sig = inspect.signature(func)
|
||||
|
||||
# Skip self, *args, **kwargs
|
||||
parameters_list = []
|
||||
for name, param in sig.parameters.items():
|
||||
if name == "self":
|
||||
continue
|
||||
if param.kind in (inspect.Parameter.VAR_POSITIONAL, inspect.Parameter.VAR_KEYWORD):
|
||||
continue
|
||||
parameters_list.append((name, param))
|
||||
|
||||
parameters = {
|
||||
"type": "object",
|
||||
"properties": {},
|
||||
"required": []
|
||||
}
|
||||
|
||||
# Parse docstring for parameter descriptions
|
||||
docstring = inspect.getdoc(func)
|
||||
param_descriptions = {}
|
||||
if docstring:
|
||||
import re
|
||||
param_section = re.split(r'\s*Args:\s*', docstring)
|
||||
if len(param_section) > 1:
|
||||
param_lines = param_section[1].split('\n')
|
||||
for line in param_lines:
|
||||
line = line.strip()
|
||||
if line and ':' in line:
|
||||
param_name, param_desc = line.split(':', 1)
|
||||
param_descriptions[param_name.strip()] = param_desc.strip()
|
||||
|
||||
for name, param in parameters_list:
|
||||
param_type = "string" # Default type
|
||||
param_info = {}
|
||||
|
||||
if param.annotation != inspect.Parameter.empty:
|
||||
if param.annotation is int:
|
||||
param_type = "integer"
|
||||
elif param.annotation is float:
|
||||
param_type = "number"
|
||||
elif param.annotation is bool:
|
||||
param_type = "boolean"
|
||||
elif param.annotation is list:
|
||||
param_type = "array"
|
||||
# OpenAI requires 'items' for array types
|
||||
param_info["items"] = {"type": "string"}
|
||||
elif param.annotation is dict:
|
||||
param_type = "object"
|
||||
|
||||
param_info["type"] = param_type
|
||||
if name in param_descriptions:
|
||||
param_info["description"] = param_descriptions[name]
|
||||
|
||||
parameters["properties"][name] = param_info
|
||||
if param.default == inspect.Parameter.empty:
|
||||
parameters["required"].append(name)
|
||||
|
||||
# Extract description from docstring
|
||||
description = docstring.split('\n')[0] if docstring else f"Function {func.__name__}"
|
||||
|
||||
return {
|
||||
"type": "function",
|
||||
"function": {
|
||||
"name": func.__name__,
|
||||
"description": description,
|
||||
"parameters": parameters
|
||||
}
|
||||
}
|
||||
except Exception as e:
|
||||
logging.error(f"Error generating tool definition: {e}")
|
||||
return None
|
||||
|
||||
def _generate_tool_definition_from_name(self, function_name: str) -> Optional[Dict]:
|
||||
"""Generate a tool definition from a function name."""
|
||||
# This is a placeholder - in agent.py this would look up the function
|
||||
# For now, return None as the actual implementation would need access to the function
|
||||
logging.debug(f"Tool definition generation from name '{function_name}' requires function reference")
|
||||
return None
|
||||
|
||||
def process_stream_response(
|
||||
self,
|
||||
messages: List[Dict],
|
||||
model: str,
|
||||
temperature: float = 0.7,
|
||||
tools: Optional[List[Dict]] = None,
|
||||
start_time: Optional[float] = None,
|
||||
console: Optional[Console] = None,
|
||||
display_fn: Optional[Callable] = None,
|
||||
reasoning_steps: bool = False,
|
||||
**kwargs
|
||||
) -> Optional[ChatCompletion]:
|
||||
"""
|
||||
Process streaming response and return final response.
|
||||
|
||||
Args:
|
||||
messages: List of messages for the conversation
|
||||
model: Model to use
|
||||
temperature: Temperature for generation
|
||||
tools: Optional formatted tools
|
||||
start_time: Start time for timing display
|
||||
console: Console for output
|
||||
display_fn: Display function for live updates
|
||||
reasoning_steps: Whether to show reasoning steps
|
||||
**kwargs: Additional parameters for the API
|
||||
|
||||
Returns:
|
||||
ChatCompletion object or None if error
|
||||
"""
|
||||
try:
|
||||
# Default start time and console if not provided
|
||||
if start_time is None:
|
||||
start_time = time.time()
|
||||
if console is None:
|
||||
console = self.console
|
||||
|
||||
# Create the response stream
|
||||
response_stream = self._sync_client.chat.completions.create(
|
||||
model=model,
|
||||
messages=messages,
|
||||
temperature=temperature,
|
||||
tools=tools if tools else None,
|
||||
stream=True,
|
||||
**kwargs
|
||||
)
|
||||
|
||||
full_response_text = ""
|
||||
reasoning_content = ""
|
||||
chunks = []
|
||||
|
||||
# If display function provided, use Live display
|
||||
if display_fn:
|
||||
with Live(
|
||||
display_fn("", start_time),
|
||||
console=console,
|
||||
refresh_per_second=4,
|
||||
transient=True,
|
||||
vertical_overflow="ellipsis",
|
||||
auto_refresh=True
|
||||
) as live:
|
||||
for chunk in response_stream:
|
||||
chunks.append(chunk)
|
||||
if chunk.choices[0].delta.content:
|
||||
full_response_text += chunk.choices[0].delta.content
|
||||
live.update(display_fn(full_response_text, start_time))
|
||||
|
||||
# Update live display with reasoning content if enabled
|
||||
if reasoning_steps and hasattr(chunk.choices[0].delta, "reasoning_content"):
|
||||
rc = chunk.choices[0].delta.reasoning_content
|
||||
if rc:
|
||||
reasoning_content += rc
|
||||
live.update(display_fn(f"{full_response_text}\n[Reasoning: {reasoning_content}]", start_time))
|
||||
|
||||
# Clear the last generating display with a blank line
|
||||
console.print()
|
||||
else:
|
||||
# Just collect chunks without display
|
||||
for chunk in response_stream:
|
||||
chunks.append(chunk)
|
||||
|
||||
final_response = process_stream_chunks(chunks)
|
||||
return final_response
|
||||
|
||||
except Exception as e:
|
||||
self.logger.error(f"Error in stream processing: {e}")
|
||||
return None
|
||||
|
||||
async def process_stream_response_async(
|
||||
self,
|
||||
messages: List[Dict],
|
||||
model: str,
|
||||
temperature: float = 0.7,
|
||||
tools: Optional[List[Dict]] = None,
|
||||
start_time: Optional[float] = None,
|
||||
console: Optional[Console] = None,
|
||||
display_fn: Optional[Callable] = None,
|
||||
reasoning_steps: bool = False,
|
||||
**kwargs
|
||||
) -> Optional[ChatCompletion]:
|
||||
"""
|
||||
Async version of process_stream_response.
|
||||
|
||||
Args:
|
||||
messages: List of messages for the conversation
|
||||
model: Model to use
|
||||
temperature: Temperature for generation
|
||||
tools: Optional formatted tools
|
||||
start_time: Start time for timing display
|
||||
console: Console for output
|
||||
display_fn: Display function for live updates
|
||||
reasoning_steps: Whether to show reasoning steps
|
||||
**kwargs: Additional parameters for the API
|
||||
|
||||
Returns:
|
||||
ChatCompletion object or None if error
|
||||
"""
|
||||
try:
|
||||
# Default start time and console if not provided
|
||||
if start_time is None:
|
||||
start_time = time.time()
|
||||
if console is None:
|
||||
console = self.console
|
||||
|
||||
# Create the response stream
|
||||
response_stream = await self.async_client.chat.completions.create(
|
||||
model=model,
|
||||
messages=messages,
|
||||
temperature=temperature,
|
||||
tools=tools if tools else None,
|
||||
stream=True,
|
||||
**kwargs
|
||||
)
|
||||
|
||||
full_response_text = ""
|
||||
reasoning_content = ""
|
||||
chunks = []
|
||||
|
||||
# If display function provided, use Live display
|
||||
if display_fn:
|
||||
with Live(
|
||||
display_fn("", start_time),
|
||||
console=console,
|
||||
refresh_per_second=4,
|
||||
transient=True,
|
||||
vertical_overflow="ellipsis",
|
||||
auto_refresh=True
|
||||
) as live:
|
||||
async for chunk in response_stream:
|
||||
chunks.append(chunk)
|
||||
if chunk.choices[0].delta.content:
|
||||
full_response_text += chunk.choices[0].delta.content
|
||||
live.update(display_fn(full_response_text, start_time))
|
||||
|
||||
# Update live display with reasoning content if enabled
|
||||
if reasoning_steps and hasattr(chunk.choices[0].delta, "reasoning_content"):
|
||||
rc = chunk.choices[0].delta.reasoning_content
|
||||
if rc:
|
||||
reasoning_content += rc
|
||||
live.update(display_fn(f"{full_response_text}\n[Reasoning: {reasoning_content}]", start_time))
|
||||
|
||||
# Clear the last generating display with a blank line
|
||||
console.print()
|
||||
else:
|
||||
# Just collect chunks without display
|
||||
async for chunk in response_stream:
|
||||
chunks.append(chunk)
|
||||
|
||||
final_response = process_stream_chunks(chunks)
|
||||
return final_response
|
||||
|
||||
except Exception as e:
|
||||
self.logger.error(f"Error in async stream processing: {e}")
|
||||
return None
|
||||
|
||||
def create_completion(
|
||||
self,
|
||||
messages: List[Dict[str, Any]],
|
||||
@@ -155,6 +763,357 @@ class OpenAIClient:
|
||||
self.logger.error(f"Error creating async completion: {e}")
|
||||
raise
|
||||
|
||||
def chat_completion_with_tools(
|
||||
self,
|
||||
messages: List[Dict[str, Any]],
|
||||
model: str = "gpt-4o",
|
||||
temperature: float = 0.7,
|
||||
tools: Optional[List[Any]] = None,
|
||||
execute_tool_fn: Optional[Callable] = None,
|
||||
stream: bool = True,
|
||||
console: Optional[Console] = None,
|
||||
display_fn: Optional[Callable] = None,
|
||||
reasoning_steps: bool = False,
|
||||
verbose: bool = True,
|
||||
max_iterations: int = 10,
|
||||
**kwargs
|
||||
) -> Optional[ChatCompletion]:
|
||||
"""
|
||||
Create a chat completion with tool support and streaming.
|
||||
|
||||
This method handles the full tool execution loop, including:
|
||||
- Formatting tools for OpenAI API
|
||||
- Making the initial API call
|
||||
- Executing tool calls if present
|
||||
- Getting final response after tool execution
|
||||
|
||||
Args:
|
||||
messages: List of message dictionaries
|
||||
model: Model to use
|
||||
temperature: Temperature for generation
|
||||
tools: List of tools (can be callables, dicts, or strings)
|
||||
execute_tool_fn: Function to execute tools
|
||||
stream: Whether to stream responses
|
||||
console: Console for output
|
||||
display_fn: Display function for streaming
|
||||
reasoning_steps: Whether to show reasoning
|
||||
verbose: Whether to show verbose output
|
||||
max_iterations: Maximum tool calling iterations
|
||||
**kwargs: Additional API parameters
|
||||
|
||||
Returns:
|
||||
Final ChatCompletion response or None if error
|
||||
"""
|
||||
start_time = time.time()
|
||||
|
||||
# Format tools for OpenAI API
|
||||
formatted_tools = self.format_tools(tools)
|
||||
|
||||
# Continue tool execution loop until no more tool calls are needed
|
||||
iteration_count = 0
|
||||
|
||||
while iteration_count < max_iterations:
|
||||
if stream:
|
||||
# Process as streaming response with formatted tools
|
||||
final_response = self.process_stream_response(
|
||||
messages=messages,
|
||||
model=model,
|
||||
temperature=temperature,
|
||||
tools=formatted_tools,
|
||||
start_time=start_time,
|
||||
console=console,
|
||||
display_fn=display_fn,
|
||||
reasoning_steps=reasoning_steps,
|
||||
**kwargs
|
||||
)
|
||||
else:
|
||||
# Process as regular non-streaming response
|
||||
final_response = self.create_completion(
|
||||
messages=messages,
|
||||
model=model,
|
||||
temperature=temperature,
|
||||
tools=formatted_tools,
|
||||
stream=False,
|
||||
**kwargs
|
||||
)
|
||||
|
||||
if not final_response:
|
||||
return None
|
||||
|
||||
# Check for tool calls
|
||||
tool_calls = getattr(final_response.choices[0].message, 'tool_calls', None)
|
||||
|
||||
if tool_calls and execute_tool_fn:
|
||||
# Convert ToolCall dataclass objects to dict for JSON serialization
|
||||
serializable_tool_calls = []
|
||||
for tc in tool_calls:
|
||||
if isinstance(tc, ToolCall):
|
||||
# Convert dataclass to dict
|
||||
serializable_tool_calls.append({
|
||||
"id": tc.id,
|
||||
"type": tc.type,
|
||||
"function": tc.function
|
||||
})
|
||||
else:
|
||||
# Already an OpenAI object, keep as is
|
||||
serializable_tool_calls.append(tc)
|
||||
|
||||
messages.append({
|
||||
"role": "assistant",
|
||||
"content": final_response.choices[0].message.content,
|
||||
"tool_calls": serializable_tool_calls
|
||||
})
|
||||
|
||||
for tool_call in tool_calls:
|
||||
# Handle both ToolCall dataclass and OpenAI object
|
||||
if isinstance(tool_call, ToolCall):
|
||||
function_name = tool_call.function["name"]
|
||||
arguments = json.loads(tool_call.function["arguments"])
|
||||
else:
|
||||
function_name = tool_call.function.name
|
||||
arguments = json.loads(tool_call.function.arguments)
|
||||
|
||||
if verbose and console:
|
||||
console.print(f"[bold]Calling function:[/bold] {function_name}")
|
||||
console.print(f"[dim]Arguments:[/dim] {arguments}")
|
||||
|
||||
# Execute the tool
|
||||
tool_result = execute_tool_fn(function_name, arguments)
|
||||
results_str = json.dumps(tool_result) if tool_result else "Function returned an empty output"
|
||||
|
||||
if verbose and console:
|
||||
console.print(f"[dim]Result:[/dim] {results_str}")
|
||||
|
||||
messages.append({
|
||||
"role": "tool",
|
||||
"tool_call_id": tool_call.id if hasattr(tool_call, 'id') else tool_call['id'],
|
||||
"content": results_str
|
||||
})
|
||||
|
||||
# Check if we should continue (for tools like sequential thinking)
|
||||
should_continue = False
|
||||
for tool_call in tool_calls:
|
||||
# Handle both ToolCall dataclass and OpenAI object
|
||||
if isinstance(tool_call, ToolCall):
|
||||
function_name = tool_call.function["name"]
|
||||
arguments = json.loads(tool_call.function["arguments"])
|
||||
else:
|
||||
function_name = tool_call.function.name
|
||||
arguments = json.loads(tool_call.function.arguments)
|
||||
|
||||
# For sequential thinking tool, check if nextThoughtNeeded is True
|
||||
if function_name == "sequentialthinking" and arguments.get("nextThoughtNeeded", False):
|
||||
should_continue = True
|
||||
break
|
||||
|
||||
if not should_continue:
|
||||
# Get final response after tool calls
|
||||
if stream:
|
||||
final_response = self.process_stream_response(
|
||||
messages=messages,
|
||||
model=model,
|
||||
temperature=temperature,
|
||||
tools=formatted_tools,
|
||||
start_time=start_time,
|
||||
console=console,
|
||||
display_fn=display_fn,
|
||||
reasoning_steps=reasoning_steps,
|
||||
**kwargs
|
||||
)
|
||||
else:
|
||||
final_response = self.create_completion(
|
||||
messages=messages,
|
||||
model=model,
|
||||
temperature=temperature,
|
||||
stream=False,
|
||||
**kwargs
|
||||
)
|
||||
break
|
||||
|
||||
iteration_count += 1
|
||||
else:
|
||||
# No tool calls, we're done
|
||||
break
|
||||
|
||||
return final_response
|
||||
|
||||
async def achat_completion_with_tools(
|
||||
self,
|
||||
messages: List[Dict[str, Any]],
|
||||
model: str = "gpt-4o",
|
||||
temperature: float = 0.7,
|
||||
tools: Optional[List[Any]] = None,
|
||||
execute_tool_fn: Optional[Callable] = None,
|
||||
stream: bool = True,
|
||||
console: Optional[Console] = None,
|
||||
display_fn: Optional[Callable] = None,
|
||||
reasoning_steps: bool = False,
|
||||
verbose: bool = True,
|
||||
max_iterations: int = 10,
|
||||
**kwargs
|
||||
) -> Optional[ChatCompletion]:
|
||||
"""
|
||||
Async version of chat_completion_with_tools.
|
||||
|
||||
Args:
|
||||
messages: List of message dictionaries
|
||||
model: Model to use
|
||||
temperature: Temperature for generation
|
||||
tools: List of tools (can be callables, dicts, or strings)
|
||||
execute_tool_fn: Async function to execute tools
|
||||
stream: Whether to stream responses
|
||||
console: Console for output
|
||||
display_fn: Display function for streaming
|
||||
reasoning_steps: Whether to show reasoning
|
||||
verbose: Whether to show verbose output
|
||||
max_iterations: Maximum tool calling iterations
|
||||
**kwargs: Additional API parameters
|
||||
|
||||
Returns:
|
||||
Final ChatCompletion response or None if error
|
||||
"""
|
||||
start_time = time.time()
|
||||
|
||||
# Format tools for OpenAI API
|
||||
formatted_tools = self.format_tools(tools)
|
||||
|
||||
# Continue tool execution loop until no more tool calls are needed
|
||||
iteration_count = 0
|
||||
|
||||
while iteration_count < max_iterations:
|
||||
if stream:
|
||||
# Process as streaming response with formatted tools
|
||||
final_response = await self.process_stream_response_async(
|
||||
messages=messages,
|
||||
model=model,
|
||||
temperature=temperature,
|
||||
tools=formatted_tools,
|
||||
start_time=start_time,
|
||||
console=console,
|
||||
display_fn=display_fn,
|
||||
reasoning_steps=reasoning_steps,
|
||||
**kwargs
|
||||
)
|
||||
else:
|
||||
# Process as regular non-streaming response
|
||||
final_response = await self.acreate_completion(
|
||||
messages=messages,
|
||||
model=model,
|
||||
temperature=temperature,
|
||||
tools=formatted_tools,
|
||||
stream=False,
|
||||
**kwargs
|
||||
)
|
||||
|
||||
if not final_response:
|
||||
return None
|
||||
|
||||
# Check for tool calls
|
||||
tool_calls = getattr(final_response.choices[0].message, 'tool_calls', None)
|
||||
|
||||
if tool_calls and execute_tool_fn:
|
||||
# Convert ToolCall dataclass objects to dict for JSON serialization
|
||||
serializable_tool_calls = []
|
||||
for tc in tool_calls:
|
||||
if isinstance(tc, ToolCall):
|
||||
# Convert dataclass to dict
|
||||
serializable_tool_calls.append({
|
||||
"id": tc.id,
|
||||
"type": tc.type,
|
||||
"function": tc.function
|
||||
})
|
||||
else:
|
||||
# Already an OpenAI object, keep as is
|
||||
serializable_tool_calls.append(tc)
|
||||
|
||||
messages.append({
|
||||
"role": "assistant",
|
||||
"content": final_response.choices[0].message.content,
|
||||
"tool_calls": serializable_tool_calls
|
||||
})
|
||||
|
||||
for tool_call in tool_calls:
|
||||
# Handle both ToolCall dataclass and OpenAI object
|
||||
if isinstance(tool_call, ToolCall):
|
||||
function_name = tool_call.function["name"]
|
||||
arguments = json.loads(tool_call.function["arguments"])
|
||||
else:
|
||||
function_name = tool_call.function.name
|
||||
arguments = json.loads(tool_call.function.arguments)
|
||||
|
||||
if verbose and console:
|
||||
console.print(f"[bold]Calling function:[/bold] {function_name}")
|
||||
console.print(f"[dim]Arguments:[/dim] {arguments}")
|
||||
|
||||
# Execute the tool (async)
|
||||
if asyncio.iscoroutinefunction(execute_tool_fn):
|
||||
tool_result = await execute_tool_fn(function_name, arguments)
|
||||
else:
|
||||
# Run sync function in executor
|
||||
loop = asyncio.get_event_loop()
|
||||
tool_result = await loop.run_in_executor(
|
||||
None,
|
||||
lambda: execute_tool_fn(function_name, arguments)
|
||||
)
|
||||
|
||||
results_str = json.dumps(tool_result) if tool_result else "Function returned an empty output"
|
||||
|
||||
if verbose and console:
|
||||
console.print(f"[dim]Result:[/dim] {results_str}")
|
||||
|
||||
messages.append({
|
||||
"role": "tool",
|
||||
"tool_call_id": tool_call.id if hasattr(tool_call, 'id') else tool_call['id'],
|
||||
"content": results_str
|
||||
})
|
||||
|
||||
# Check if we should continue (for tools like sequential thinking)
|
||||
should_continue = False
|
||||
for tool_call in tool_calls:
|
||||
# Handle both ToolCall dataclass and OpenAI object
|
||||
if isinstance(tool_call, ToolCall):
|
||||
function_name = tool_call.function["name"]
|
||||
arguments = json.loads(tool_call.function["arguments"])
|
||||
else:
|
||||
function_name = tool_call.function.name
|
||||
arguments = json.loads(tool_call.function.arguments)
|
||||
|
||||
# For sequential thinking tool, check if nextThoughtNeeded is True
|
||||
if function_name == "sequentialthinking" and arguments.get("nextThoughtNeeded", False):
|
||||
should_continue = True
|
||||
break
|
||||
|
||||
if not should_continue:
|
||||
# Get final response after tool calls
|
||||
if stream:
|
||||
final_response = await self.process_stream_response_async(
|
||||
messages=messages,
|
||||
model=model,
|
||||
temperature=temperature,
|
||||
tools=formatted_tools,
|
||||
start_time=start_time,
|
||||
console=console,
|
||||
display_fn=display_fn,
|
||||
reasoning_steps=reasoning_steps,
|
||||
**kwargs
|
||||
)
|
||||
else:
|
||||
final_response = await self.acreate_completion(
|
||||
messages=messages,
|
||||
model=model,
|
||||
temperature=temperature,
|
||||
stream=False,
|
||||
**kwargs
|
||||
)
|
||||
break
|
||||
|
||||
iteration_count += 1
|
||||
else:
|
||||
# No tool calls, we're done
|
||||
break
|
||||
|
||||
return final_response
|
||||
|
||||
def parse_structured_output(
|
||||
self,
|
||||
messages: List[Dict[str, Any]],
|
||||
|
||||
@@ -3,7 +3,6 @@ import time
|
||||
import json
|
||||
import logging
|
||||
from typing import List, Optional, Dict, Any, Union, Literal, Type
|
||||
from openai import OpenAI
|
||||
from pydantic import BaseModel, ConfigDict
|
||||
from rich import print
|
||||
from rich.console import Console
|
||||
@@ -377,24 +376,6 @@ class ReflectionOutput(BaseModel):
|
||||
reflection: str
|
||||
satisfactory: Literal["yes", "no"]
|
||||
|
||||
# Constants
|
||||
LOCAL_SERVER_API_KEY_PLACEHOLDER = "not-needed"
|
||||
|
||||
# Initialize OpenAI client with proper API key handling
|
||||
api_key = os.environ.get("OPENAI_API_KEY")
|
||||
base_url = os.environ.get("OPENAI_API_BASE") or os.environ.get("OPENAI_BASE_URL")
|
||||
|
||||
# For local servers like LM Studio, allow minimal API key
|
||||
if base_url and not api_key:
|
||||
api_key = LOCAL_SERVER_API_KEY_PLACEHOLDER
|
||||
elif not api_key:
|
||||
raise ValueError(
|
||||
"OPENAI_API_KEY environment variable is required for the default OpenAI service. "
|
||||
"If you are targeting a local server (e.g., LM Studio), ensure OPENAI_API_BASE is set "
|
||||
f"(e.g., 'http://localhost:1234/v1') and you can use a placeholder API key by setting OPENAI_API_KEY='{LOCAL_SERVER_API_KEY_PLACEHOLDER}'"
|
||||
)
|
||||
|
||||
client = OpenAI(api_key=api_key, base_url=base_url)
|
||||
|
||||
class TaskOutput(BaseModel):
|
||||
model_config = ConfigDict(arbitrary_types_allowed=True)
|
||||
|
||||
@@ -5,10 +5,10 @@ from typing import Dict, Optional, List, Any, AsyncGenerator
|
||||
from pydantic import BaseModel, ConfigDict
|
||||
from ..agent.agent import Agent
|
||||
from ..task.task import Task
|
||||
from ..main import display_error, client
|
||||
from ..main import display_error
|
||||
import csv
|
||||
import os
|
||||
from openai import AsyncOpenAI
|
||||
from openai import AsyncOpenAI, OpenAI
|
||||
|
||||
class LoopItems(BaseModel):
|
||||
model_config = ConfigDict(arbitrary_types_allowed=True)
|
||||
@@ -140,6 +140,8 @@ class Process:
|
||||
|
||||
def _get_manager_instructions_with_fallback(self, manager_task, manager_prompt, ManagerInstructions):
|
||||
"""Sync version of getting manager instructions with fallback"""
|
||||
# Create OpenAI client
|
||||
client = OpenAI()
|
||||
try:
|
||||
# First try structured output (OpenAI compatible)
|
||||
logging.info("Attempting structured output...")
|
||||
|
||||
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
||||
|
||||
[project]
|
||||
name = "praisonaiagents"
|
||||
version = "0.0.114"
|
||||
version = "0.0.118"
|
||||
description = "Praison AI agents for completing complex tasks with Self Reflection Agents"
|
||||
requires-python = ">=3.10"
|
||||
authors = [
|
||||
|
||||
Generated
+1
-1
@@ -2375,7 +2375,7 @@ wheels = [
|
||||
|
||||
[[package]]
|
||||
name = "praisonaiagents"
|
||||
version = "0.0.114"
|
||||
version = "0.0.118"
|
||||
source = { editable = "." }
|
||||
dependencies = [
|
||||
{ name = "mcp" },
|
||||
|
||||
@@ -3,8 +3,8 @@ class Praisonai < Formula
|
||||
|
||||
desc "AI tools for various AI applications"
|
||||
homepage "https://github.com/MervinPraison/PraisonAI"
|
||||
url "https://github.com/MervinPraison/PraisonAI/archive/refs/tags/v2.2.41.tar.gz"
|
||||
sha256 `curl -sL https://github.com/MervinPraison/PraisonAI/archive/refs/tags/v2.2.41.tar.gz | shasum -a 256`.split.first
|
||||
url "https://github.com/MervinPraison/PraisonAI/archive/refs/tags/v2.2.45.tar.gz"
|
||||
sha256 `curl -sL https://github.com/MervinPraison/PraisonAI/archive/refs/tags/v2.2.45.tar.gz | shasum -a 256`.split.first
|
||||
license "MIT"
|
||||
|
||||
depends_on "[email protected]"
|
||||
|
||||
@@ -57,7 +57,7 @@ class CloudDeployer:
|
||||
file.write("FROM python:3.11-slim\n")
|
||||
file.write("WORKDIR /app\n")
|
||||
file.write("COPY . .\n")
|
||||
file.write("RUN pip install flask praisonai==2.2.41 gunicorn markdown\n")
|
||||
file.write("RUN pip install flask praisonai==2.2.45 gunicorn markdown\n")
|
||||
file.write("EXPOSE 8080\n")
|
||||
file.write('CMD ["gunicorn", "-b", "0.0.0.0:8080", "api:app"]\n')
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[project]
|
||||
name = "PraisonAI"
|
||||
version = "2.2.41"
|
||||
version = "2.2.45"
|
||||
description = "PraisonAI is an AI Agents Framework with Self Reflection. PraisonAI application combines PraisonAI Agents, AutoGen, and CrewAI into a low-code solution for building and managing multi-agent LLM systems, focusing on simplicity, customisation, and efficient human-agent collaboration."
|
||||
readme = "README.md"
|
||||
license = ""
|
||||
@@ -12,7 +12,7 @@ dependencies = [
|
||||
"rich>=13.7",
|
||||
"markdown>=3.5",
|
||||
"pyparsing>=3.0.0",
|
||||
"praisonaiagents>=0.0.114",
|
||||
"praisonaiagents>=0.0.118",
|
||||
"python-dotenv>=0.19.0",
|
||||
"instructor>=1.3.3",
|
||||
"PyYAML>=6.0",
|
||||
@@ -95,7 +95,7 @@ autogen = ["pyautogen>=0.2.19", "praisonai-tools>=0.0.15", "crewai"]
|
||||
|
||||
[tool.poetry]
|
||||
name = "PraisonAI"
|
||||
version = "2.2.41"
|
||||
version = "2.2.45"
|
||||
description = "PraisonAI is an AI Agents Framework with Self Reflection. PraisonAI application combines PraisonAI Agents, AutoGen, and CrewAI into a low-code solution for building and managing multi-agent LLM systems, focusing on simplicity, customisation, and efficient human-agent collaboration."
|
||||
authors = ["Mervin Praison"]
|
||||
license = ""
|
||||
@@ -113,7 +113,7 @@ python = ">=3.10,<3.13"
|
||||
rich = ">=13.7"
|
||||
markdown = ">=3.5"
|
||||
pyparsing = ">=3.0.0"
|
||||
praisonaiagents = ">=0.0.114"
|
||||
praisonaiagents = ">=0.0.118"
|
||||
python-dotenv = ">=0.19.0"
|
||||
instructor = ">=1.3.3"
|
||||
PyYAML = ">=6.0"
|
||||
|
||||
@@ -0,0 +1,167 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Test script to verify the OpenAI refactoring works correctly.
|
||||
"""
|
||||
|
||||
import asyncio
|
||||
from praisonaiagents import Agent
|
||||
from praisonaiagents.llm import (
|
||||
get_openai_client,
|
||||
ChatCompletionMessage,
|
||||
Choice,
|
||||
CompletionUsage,
|
||||
ChatCompletion,
|
||||
ToolCall,
|
||||
process_stream_chunks
|
||||
)
|
||||
|
||||
def test_data_classes():
|
||||
"""Test that data classes are properly imported and work"""
|
||||
print("Testing data classes...")
|
||||
|
||||
# Create a message
|
||||
msg = ChatCompletionMessage(
|
||||
content="Hello, world!",
|
||||
role="assistant"
|
||||
)
|
||||
assert msg.content == "Hello, world!"
|
||||
assert msg.role == "assistant"
|
||||
print("✓ ChatCompletionMessage works")
|
||||
|
||||
# Create a choice
|
||||
choice = Choice(
|
||||
finish_reason="stop",
|
||||
index=0,
|
||||
message=msg
|
||||
)
|
||||
assert choice.finish_reason == "stop"
|
||||
assert choice.message.content == "Hello, world!"
|
||||
print("✓ Choice works")
|
||||
|
||||
# Create a tool call
|
||||
tool_call = ToolCall(
|
||||
id="call_123",
|
||||
type="function",
|
||||
function={"name": "test_tool", "arguments": "{}"}
|
||||
)
|
||||
assert tool_call.id == "call_123"
|
||||
assert tool_call.function["name"] == "test_tool"
|
||||
print("✓ ToolCall works")
|
||||
|
||||
print("All data classes test passed!\n")
|
||||
|
||||
def test_openai_client():
|
||||
"""Test that OpenAI client is properly initialized"""
|
||||
print("Testing OpenAI client...")
|
||||
|
||||
try:
|
||||
# This might fail if OPENAI_API_KEY is not set, which is OK for testing
|
||||
client = get_openai_client()
|
||||
print("✓ OpenAI client created successfully")
|
||||
|
||||
# Test build_messages method
|
||||
messages, original = client.build_messages(
|
||||
prompt="Test prompt",
|
||||
system_prompt="You are a helpful assistant"
|
||||
)
|
||||
assert len(messages) == 2
|
||||
assert messages[0]["role"] == "system"
|
||||
assert messages[1]["role"] == "user"
|
||||
print("✓ build_messages method works")
|
||||
|
||||
# Test format_tools method (with no tools)
|
||||
tools = client.format_tools(None)
|
||||
assert tools is None
|
||||
print("✓ format_tools method works")
|
||||
|
||||
except ValueError as e:
|
||||
if "OPENAI_API_KEY" in str(e):
|
||||
print("⚠ OpenAI client requires API key (expected in test environment)")
|
||||
else:
|
||||
raise
|
||||
|
||||
print("OpenAI client tests completed!\n")
|
||||
|
||||
def test_agent_integration():
|
||||
"""Test that Agent class works with the refactored code"""
|
||||
print("Testing Agent integration...")
|
||||
|
||||
try:
|
||||
# Create a simple agent
|
||||
agent = Agent(
|
||||
name="Test Agent",
|
||||
role="Tester",
|
||||
goal="Test the refactored code",
|
||||
instructions="You are a test agent"
|
||||
)
|
||||
print("✓ Agent created successfully")
|
||||
|
||||
# Test _build_messages
|
||||
messages, original = agent._build_messages(
|
||||
prompt="Test prompt",
|
||||
temperature=0.5
|
||||
)
|
||||
assert len(messages) >= 1
|
||||
assert messages[-1]["content"] == "Test prompt"
|
||||
print("✓ Agent._build_messages works")
|
||||
|
||||
# Test _format_tools_for_completion
|
||||
def sample_tool():
|
||||
"""A sample tool for testing"""
|
||||
pass
|
||||
|
||||
formatted = agent._format_tools_for_completion([sample_tool])
|
||||
assert isinstance(formatted, list)
|
||||
print("✓ Agent._format_tools_for_completion works")
|
||||
|
||||
except Exception as e:
|
||||
print(f"⚠ Agent integration test failed: {e}")
|
||||
# This is OK if dependencies are missing
|
||||
|
||||
print("Agent integration tests completed!\n")
|
||||
|
||||
async def test_async_functionality():
|
||||
"""Test async functionality"""
|
||||
print("Testing async functionality...")
|
||||
|
||||
try:
|
||||
client = get_openai_client()
|
||||
|
||||
# Test that async client can be accessed
|
||||
async_client = client.async_client
|
||||
print("✓ Async client accessible")
|
||||
|
||||
# Test build_messages (which is sync but used in async context)
|
||||
messages, _ = client.build_messages("Test async")
|
||||
assert len(messages) >= 1
|
||||
print("✓ build_messages works in async context")
|
||||
|
||||
except ValueError as e:
|
||||
if "OPENAI_API_KEY" in str(e):
|
||||
print("⚠ Async tests require API key")
|
||||
else:
|
||||
raise
|
||||
|
||||
print("Async functionality tests completed!\n")
|
||||
|
||||
def main():
|
||||
"""Run all tests"""
|
||||
print("=" * 50)
|
||||
print("OpenAI Refactoring Test Suite")
|
||||
print("=" * 50)
|
||||
print()
|
||||
|
||||
# Run sync tests
|
||||
test_data_classes()
|
||||
test_openai_client()
|
||||
test_agent_integration()
|
||||
|
||||
# Run async tests
|
||||
asyncio.run(test_async_functionality())
|
||||
|
||||
print("=" * 50)
|
||||
print("All tests completed!")
|
||||
print("=" * 50)
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,31 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Test script to verify that xai/grok-4 works without OPENAI_API_KEY"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
# Ensure OPENAI_API_KEY is not set to test the fix
|
||||
if 'OPENAI_API_KEY' in os.environ:
|
||||
del os.environ['OPENAI_API_KEY']
|
||||
|
||||
# Test the import that was failing
|
||||
try:
|
||||
from praisonaiagents import Agent
|
||||
print("✅ Successfully imported praisonaiagents without OPENAI_API_KEY!")
|
||||
except ValueError as e:
|
||||
print(f"❌ Import failed with error: {e}")
|
||||
sys.exit(1)
|
||||
|
||||
# Test creating an agent with xai/grok-4
|
||||
try:
|
||||
agent = Agent(
|
||||
instructions="You are a PhD-level mathematician.",
|
||||
llm="xai/grok-4"
|
||||
)
|
||||
print("✅ Successfully created Agent with xai/grok-4!")
|
||||
except Exception as e:
|
||||
print(f"❌ Failed to create agent: {e}")
|
||||
sys.exit(1)
|
||||
|
||||
print("\n✅ All tests passed! The issue has been fixed.")
|
||||
print(" You can now use litellm providers without setting OPENAI_API_KEY.")
|
||||
Generated
+5
-5
@@ -3931,7 +3931,7 @@ wheels = [
|
||||
|
||||
[[package]]
|
||||
name = "praisonai"
|
||||
version = "2.2.41"
|
||||
version = "2.2.45"
|
||||
source = { editable = "." }
|
||||
dependencies = [
|
||||
{ name = "instructor" },
|
||||
@@ -4073,7 +4073,7 @@ requires-dist = [
|
||||
{ name = "plotly", marker = "extra == 'realtime'", specifier = ">=5.24.0" },
|
||||
{ name = "praisonai-tools", marker = "extra == 'autogen'", specifier = ">=0.0.15" },
|
||||
{ name = "praisonai-tools", marker = "extra == 'crewai'", specifier = ">=0.0.15" },
|
||||
{ name = "praisonaiagents", specifier = ">=0.0.114" },
|
||||
{ name = "praisonaiagents", specifier = ">=0.0.118" },
|
||||
{ name = "pyautogen", marker = "extra == 'autogen'", specifier = ">=0.2.19" },
|
||||
{ name = "pydantic", marker = "extra == 'chat'", specifier = "<=2.10.1" },
|
||||
{ name = "pydantic", marker = "extra == 'code'", specifier = "<=2.10.1" },
|
||||
@@ -4130,7 +4130,7 @@ wheels = [
|
||||
|
||||
[[package]]
|
||||
name = "praisonaiagents"
|
||||
version = "0.0.114"
|
||||
version = "0.0.118"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "mcp" },
|
||||
@@ -4139,9 +4139,9 @@ dependencies = [
|
||||
{ name = "pydantic" },
|
||||
{ name = "rich" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/f1/c5/51b821f7ffd1450242a2916781f0f1426924b074b3c994f42a1e293f842d/praisonaiagents-0.0.114.tar.gz", hash = "sha256:adc137e372296eb29a9fb3472d830d39fa4397f1f8a79ce4c9093d796d6c424b", size = 168621 }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/ba/53/0363b4e986b3916a246af2798cecaba08d47d46acc5faf313789d8de07cf/praisonaiagents-0.0.118.tar.gz", hash = "sha256:0e7cb593fc1733e33c6f17d55e4670ca973cfe4233c86747c7d97be41347a3da", size = 172108 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/18/47/d5a125dc9eec338bcb2af0244fce38fb8d182c9ca67ce8d201c638b85cdb/praisonaiagents-0.0.114-py3-none-any.whl", hash = "sha256:59e35296f25ff95785071bc84e86a95e304298ea5afafd73f49c327fe054bc0d", size = 189030 },
|
||||
{ url = "https://files.pythonhosted.org/packages/9a/a1/605677f442a983259be11079b492fff2a1cca78686c8a6385f8adcdea285/praisonaiagents-0.0.118-py3-none-any.whl", hash = "sha256:5e3f27ffc9af64c2db1726dc1174f348b5bb0dea07b110651fcde6f480ca36a1", size = 192626 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
||||
Reference in new issue
Block a user