mirror of
https://github.com/MervinPraison/PraisonAI.git
synced 2026-11-07 17:33:33 -10:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8c0e4277a4 | ||
|
|
41448617d5 | ||
|
|
49ea23c676 | ||
|
|
bb0dc63680 | ||
|
|
7774f2c565 | ||
|
|
5533fd3476 | ||
|
|
262a90a235 | ||
|
|
60928dcb90 | ||
|
|
c8552e1158 | ||
|
|
c57d7db9bb | ||
|
|
236abc2c83 | ||
|
|
76c5f8fe3f | ||
|
|
82750020d2 | ||
|
|
f49ad9fbc2 | ||
|
|
c086c60fd6 | ||
|
|
4f8f4f2036 | ||
|
|
8e91c20967 | ||
|
|
6f092c1507 | ||
|
|
8f553d3a54 | ||
|
|
2d647e25b5 | ||
|
|
039bb772f5 | ||
|
|
459c2f2b70 | ||
|
|
ee59706357 | ||
|
|
2a51644773 | ||
|
|
cce908fa22 | ||
|
|
acf476f715 | ||
|
|
e5d77de79c | ||
|
|
9ab444b54c | ||
|
|
e13f543c6d | ||
|
|
4f235d358c | ||
|
|
b7847feb1e | ||
|
|
7ac730462c | ||
|
|
9cbc8d082d | ||
|
|
7fb0aed7ac | ||
|
|
206f0d01e7 | ||
|
|
e19a310314 | ||
|
|
1ea572689e | ||
|
|
96df649b05 | ||
|
|
5aed75837a | ||
|
|
9c8f68a05f | ||
|
|
9778a69c4d | ||
|
|
73c7994380 | ||
|
|
82b83ded41 | ||
|
|
fc80db32c2 | ||
|
|
3f115ca7ba | ||
|
|
a32d45e6da | ||
|
|
8823df26ff | ||
|
|
9c2126fbd6 | ||
|
|
741b01bdf0 | ||
|
|
6ed9a69cd8 | ||
|
|
56a42e6d95 | ||
|
|
d2b4affdd1 | ||
|
|
0d5c8b478f | ||
|
|
fdfad70319 | ||
|
|
fba6b2e2a0 | ||
|
|
f9bfb85f44 | ||
|
|
aab4b5b466 | ||
|
|
7ccadde004 | ||
|
|
22a9d5ff23 | ||
|
|
98a11209ea | ||
|
|
df3c97e73a | ||
|
|
27808964be | ||
|
|
b5daf16e0d | ||
|
|
a2cac05d16 | ||
|
|
ad9828d3bb | ||
|
|
85ddf04b47 | ||
|
|
1c1a1b719b | ||
|
|
a8e0914e05 | ||
|
|
ec6d883f4f | ||
|
|
d094cbfac5 | ||
|
|
14e3724aed | ||
|
|
92436277d9 | ||
|
|
3e0fd298e2 | ||
|
|
fad0b41b52 | ||
|
|
6c3e5ee187 | ||
|
|
f842ee7048 | ||
|
|
b0ff6f3f60 | ||
|
|
798f6dad14 | ||
|
|
629bf0d669 | ||
|
|
eaca447b82 | ||
|
|
bef3693627 | ||
|
|
aa62babed6 | ||
|
|
b73f181200 | ||
|
|
66d2998047 |
No files matched your search
+2
-1
@@ -65,4 +65,5 @@ outputs
|
||||
agents/praisonaiagents/build
|
||||
agents/praisonaiagents/dist
|
||||
agents/praisonaiagents/praisonaiagents.egg-info
|
||||
.codegpt
|
||||
.codegpt
|
||||
.praison
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
FROM python:3.11-slim
|
||||
WORKDIR /app
|
||||
COPY . .
|
||||
RUN pip install flask praisonai==2.0.37 gunicorn markdown
|
||||
RUN pip install flask praisonai==2.0.53 gunicorn markdown
|
||||
EXPOSE 8080
|
||||
CMD ["gunicorn", "-b", "0.0.0.0:8080", "api:app"]
|
||||
@@ -1,6 +1,7 @@
|
||||
framework: praisonai
|
||||
process: sequential
|
||||
topic: create movie script about cat in mars
|
||||
memory: false
|
||||
roles:
|
||||
researcher:
|
||||
backstory: Skilled in research, with a focus on gathering accurate and relevant
|
||||
|
||||
+8
-6
@@ -1,6 +1,8 @@
|
||||
Make it minimal change as possible
|
||||
|
||||
Firstly try not to make any modification to the existing code as possible
|
||||
|
||||
Only if its highly required, without that if it can't be done, then modify the existing.
|
||||
So by default try to add new code section and not modify the existing.
|
||||
1. Make minimal code changes as possible
|
||||
2. if you are creating function, make sure to name it in more easy, user friendly , optimised manner.
|
||||
3. Never copy the exact code if presented with a code from other location or file or codebase, just make it optimised
|
||||
4. Always Follow the principle LESS IS MORE
|
||||
5. Make it minimal change as possible
|
||||
6. Firstly try not to make any modification to the existing code as possible
|
||||
7. Only modify the existing code if its highly required, without that if it cant be done, then add new code section.
|
||||
8. If you are adding new code, make sure to add it in a way that it can be easily integrated with the existing codebase.
|
||||
@@ -0,0 +1,43 @@
|
||||
FROM mcr.microsoft.com/devcontainers/python:3.11
|
||||
|
||||
# Prevent apt from showing prompts
|
||||
ENV DEBIAN_FRONTEND=noninteractive
|
||||
|
||||
# Install system dependencies
|
||||
RUN apt-get update && apt-get install -y \
|
||||
git \
|
||||
curl \
|
||||
build-essential \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# Create a non-root user
|
||||
ARG USERNAME=vscode
|
||||
ARG USER_UID=1000
|
||||
ARG USER_GID=$USER_UID
|
||||
|
||||
# Create the user and group only if they don't exist
|
||||
RUN if ! getent group $USER_GID > /dev/null 2>&1; then \
|
||||
groupadd --gid $USER_GID $USERNAME; \
|
||||
fi && \
|
||||
if ! getent passwd $USER_UID > /dev/null 2>&1; then \
|
||||
useradd --uid $USER_UID --gid $USER_GID -m $USERNAME; \
|
||||
fi && \
|
||||
apt-get update && \
|
||||
apt-get install -y sudo && \
|
||||
echo $USERNAME ALL=\(root\) NOPASSWD:ALL > /etc/sudoers.d/$USERNAME && \
|
||||
chmod 0440 /etc/sudoers.d/$USERNAME
|
||||
|
||||
# Set Python environment variables
|
||||
ENV PYTHONUNBUFFERED=1 \
|
||||
PYTHONDONTWRITEBYTECODE=1
|
||||
|
||||
# Install Python dependencies
|
||||
COPY requirements.txt /tmp/pip-tmp/
|
||||
RUN pip3 --disable-pip-version-check --no-cache-dir install -r /tmp/pip-tmp/requirements.txt \
|
||||
&& rm -rf /tmp/pip-tmp
|
||||
|
||||
# Switch to non-root user
|
||||
USER $USERNAME
|
||||
|
||||
# Set the default shell to bash
|
||||
ENV SHELL=/bin/bash
|
||||
@@ -0,0 +1,36 @@
|
||||
{
|
||||
"name": "PraisonAI Development",
|
||||
"dockerFile": "Dockerfile",
|
||||
"context": "..",
|
||||
"runArgs": [
|
||||
"--env-file",
|
||||
".env",
|
||||
"--network=host"
|
||||
],
|
||||
"customizations": {
|
||||
"vscode": {
|
||||
"extensions": [
|
||||
"ms-python.python",
|
||||
"ms-python.vscode-pylance",
|
||||
"ms-python.black-formatter",
|
||||
"ms-toolsai.jupyter",
|
||||
"yzhang.markdown-all-in-one",
|
||||
"streetsidesoftware.code-spell-checker"
|
||||
],
|
||||
"settings": {
|
||||
"python.defaultInterpreterPath": "/usr/local/bin/python",
|
||||
"python.linting.enabled": true,
|
||||
"python.formatting.provider": "black",
|
||||
"editor.formatOnSave": true,
|
||||
"editor.rulers": [88],
|
||||
"files.trimTrailingWhitespace": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"remoteUser": "vscode",
|
||||
"updateRemoteUserUID": false,
|
||||
"forwardPorts": [],
|
||||
"appPort": ["56040:56040"],
|
||||
"overrideCommand": false,
|
||||
"init": true
|
||||
}
|
||||
+2
-1
@@ -83,4 +83,5 @@ dist
|
||||
build
|
||||
*.mp4
|
||||
*.png
|
||||
graph.py
|
||||
graph.py
|
||||
chroma_db/
|
||||
Whitespace-only changes.
@@ -0,0 +1,32 @@
|
||||
.cursorrules
|
||||
.gitignore
|
||||
.praisoncontext
|
||||
.praisonignore
|
||||
.windsurfrules
|
||||
async_example.py
|
||||
async_example_full.py
|
||||
async_example_full_multigroups.py
|
||||
auto_agents_example.py
|
||||
code_agents_example.py
|
||||
example_callback.py
|
||||
example_custom_tools.py
|
||||
example_sequential.py
|
||||
image.jpg
|
||||
langchain_example.py
|
||||
langchain_logs.py
|
||||
long_term.db
|
||||
mini_agents_example.py
|
||||
multimodal.py
|
||||
praisonaiagents/tools/*
|
||||
praisonaiagents/process/*
|
||||
pyproject.toml
|
||||
short_term.db
|
||||
structured_agents_example.py
|
||||
structured_response_example.py
|
||||
test.py
|
||||
tools_example.py
|
||||
uv.lock
|
||||
workflow_example_basic.py
|
||||
workflow_example_detailed.py
|
||||
__pycache__
|
||||
__pycache__/*
|
||||
@@ -0,0 +1,8 @@
|
||||
1. Make minimal code changes as possible
|
||||
2. if you are creating function, make sure to name it in more easy, user friendly , optimised manner.
|
||||
3. Never copy the exact code if presented with a code from other location or file or codebase, just make it optimised
|
||||
4. Always Follow the principle LESS IS MORE
|
||||
5. Make it minimal change as possible
|
||||
6. Firstly try not to make any modification to the existing code as possible
|
||||
7. Only modify the existing code if its highly required, without that if it cant be done, then add new code section.
|
||||
8. If you are adding new code, make sure to add it in a way that it can be easily integrated with the existing codebase.
|
||||
@@ -0,0 +1,114 @@
|
||||
from praisonaiagents import Agent, Task, PraisonAIAgents
|
||||
import time
|
||||
|
||||
def get_environment_state():
|
||||
"""Simulates getting current environment state"""
|
||||
current_time = int(time.time())
|
||||
states = ["normal", "critical", "optimal"]
|
||||
state = states[current_time % 3]
|
||||
print(f"Environment state: {state}")
|
||||
return state
|
||||
|
||||
def perform_action(state: str):
|
||||
"""Simulates performing an action based on state"""
|
||||
actions = {
|
||||
"normal": "maintain",
|
||||
"critical": "fix",
|
||||
"optimal": "enhance"
|
||||
}
|
||||
action = actions.get(state, "observe")
|
||||
print(f"Performing action: {action} for state: {state}")
|
||||
return action
|
||||
|
||||
def get_feedback():
|
||||
"""Simulates environment feedback"""
|
||||
current_time = int(time.time())
|
||||
feedback = "positive" if current_time % 2 == 0 else "negative"
|
||||
print(f"Feedback received: {feedback}")
|
||||
return feedback
|
||||
|
||||
# Create specialized agents
|
||||
llm_caller = Agent(
|
||||
name="Environment Monitor",
|
||||
role="State analyzer",
|
||||
goal="Monitor environment and analyze state",
|
||||
instructions="Check environment state and provide analysis",
|
||||
tools=[get_environment_state]
|
||||
)
|
||||
|
||||
action_agent = Agent(
|
||||
name="Action Executor",
|
||||
role="Action performer",
|
||||
goal="Execute appropriate actions based on state",
|
||||
instructions="Determine and perform actions based on environment state",
|
||||
tools=[perform_action]
|
||||
)
|
||||
|
||||
feedback_agent = Agent(
|
||||
name="Feedback Processor",
|
||||
role="Feedback analyzer",
|
||||
goal="Process environment feedback and adapt strategy",
|
||||
instructions="Analyze feedback and provide adaptation recommendations",
|
||||
tools=[get_feedback]
|
||||
)
|
||||
|
||||
# Create tasks for autonomous workflow
|
||||
monitor_task = Task(
|
||||
name="monitor_environment",
|
||||
description="Monitor and analyze environment state",
|
||||
expected_output="Current environment state analysis",
|
||||
agent=llm_caller,
|
||||
is_start=True,
|
||||
task_type="decision",
|
||||
next_tasks=["execute_action"],
|
||||
condition={
|
||||
"normal": ["execute_action"],
|
||||
"critical": ["execute_action"],
|
||||
"optimal": "exit"
|
||||
}
|
||||
)
|
||||
|
||||
action_task = Task(
|
||||
name="execute_action",
|
||||
description="Execute appropriate action based on state",
|
||||
expected_output="Action execution result",
|
||||
agent=action_agent,
|
||||
next_tasks=["process_feedback"]
|
||||
)
|
||||
|
||||
feedback_task = Task(
|
||||
name="process_feedback",
|
||||
description="Process feedback and adapt strategy",
|
||||
expected_output="Strategy adaptation based on feedback",
|
||||
agent=feedback_agent,
|
||||
next_tasks=["monitor_environment"], # Create feedback loop
|
||||
context=[monitor_task, action_task] # Access to previous states and actions
|
||||
)
|
||||
|
||||
# Create workflow manager
|
||||
workflow = PraisonAIAgents(
|
||||
agents=[llm_caller, action_agent, feedback_agent],
|
||||
tasks=[monitor_task, action_task, feedback_task],
|
||||
process="workflow",
|
||||
verbose=True
|
||||
)
|
||||
|
||||
def main():
|
||||
print("\nStarting Autonomous Agent Workflow...")
|
||||
print("=" * 50)
|
||||
|
||||
# Run autonomous workflow
|
||||
results = workflow.start()
|
||||
|
||||
# Print results
|
||||
print("\nAutonomous Agent Results:")
|
||||
print("=" * 50)
|
||||
for task_id, result in results["task_results"].items():
|
||||
if result:
|
||||
task_name = result.description
|
||||
print(f"\nTask: {task_name}")
|
||||
print(f"Result: {result.raw}")
|
||||
print("-" * 50)
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,14 @@
|
||||
from praisonaiagents.knowledge import Chunking
|
||||
|
||||
# No heavy imports or initialization happens here
|
||||
chunking = Chunking(chunker_type='token')
|
||||
|
||||
# Chunker is only initialized when first used
|
||||
chunks = chunking.chunk("Your text here")
|
||||
|
||||
# Embedding model is only loaded if using semantic chunking
|
||||
semantic_chunking = Chunking(chunker_type='recursive')
|
||||
# Embedding model and chunker are loaded here on first use
|
||||
semantic_chunks = semantic_chunking.chunk("Your text here")
|
||||
|
||||
print(semantic_chunks)
|
||||
@@ -0,0 +1,97 @@
|
||||
from praisonaiagents import Agent, Task, PraisonAIAgents
|
||||
from pydantic import BaseModel
|
||||
from typing import List, Dict
|
||||
from gitingest import ingest
|
||||
|
||||
class CodeMetrics(BaseModel):
|
||||
category: str
|
||||
score: int
|
||||
findings: List[str]
|
||||
|
||||
class CodeAnalysisReport(BaseModel):
|
||||
overall_quality: int
|
||||
code_metrics: List[CodeMetrics]
|
||||
architecture_score: int
|
||||
maintainability_score: int
|
||||
performance_score: int
|
||||
security_score: int
|
||||
test_coverage: int
|
||||
key_strengths: List[str]
|
||||
improvement_areas: List[str]
|
||||
tech_stack: List[str]
|
||||
recommendations: List[str]
|
||||
complexity_metrics: Dict[str, int]
|
||||
best_practices: List[Dict[str, str]]
|
||||
potential_risks: List[str]
|
||||
documentation_quality: int
|
||||
|
||||
code_analyzer = Agent(
|
||||
role="Code Analysis Expert",
|
||||
goal="Provide comprehensive code evaluation and recommendations",
|
||||
backstory="""Expert code analyst specializing in architecture review,
|
||||
best practices, and technical debt assessment.""",
|
||||
verbose=True
|
||||
)
|
||||
|
||||
code_analysis_task = Task(
|
||||
description="""Analyze code repository and provide structured evaluation:
|
||||
|
||||
1. Overall Quality (0-100)
|
||||
2. Core Metrics Analysis:
|
||||
- Architecture and Design
|
||||
- Code Maintainability
|
||||
- Performance Optimization
|
||||
- Security Practices
|
||||
- Test Coverage
|
||||
3. Technical Assessment:
|
||||
- Technology Stack Review
|
||||
- Code Complexity Analysis
|
||||
- Best Practices Adherence
|
||||
- Risk Assessment
|
||||
4. Recommendations:
|
||||
- Key Improvements
|
||||
- Architecture Suggestions
|
||||
- Security Enhancements""",
|
||||
expected_output="Detailed code analysis report with metrics and recommendations",
|
||||
agent=code_analyzer,
|
||||
output_pydantic=CodeAnalysisReport
|
||||
)
|
||||
|
||||
def analyze_code(code_source: str) -> CodeAnalysisReport:
|
||||
"""
|
||||
Analyze code from directory path or GitHub URL
|
||||
"""
|
||||
# Ingest code content
|
||||
summary, tree, content = ingest(code_source)
|
||||
|
||||
# Concatenate context into structured format
|
||||
context_text = f"""
|
||||
CODE REPOSITORY ANALYSIS
|
||||
=======================
|
||||
|
||||
SUMMARY
|
||||
-------
|
||||
{summary}
|
||||
|
||||
REPOSITORY STRUCTURE
|
||||
-------------------
|
||||
{tree}
|
||||
|
||||
SOURCE CODE
|
||||
-----------
|
||||
{content}
|
||||
"""
|
||||
|
||||
# Initialize and run analysis
|
||||
agents = PraisonAIAgents(
|
||||
agents=[code_analyzer],
|
||||
tasks=[code_analysis_task]
|
||||
)
|
||||
|
||||
return agents.start(context_text)
|
||||
|
||||
if __name__ == "__main__":
|
||||
# Example usage
|
||||
code_source = "https://github.com/openai/openai-python/tree/main/src/openai/cli/_api/chat" # GitHub URL or local directory
|
||||
result = analyze_code(code_source)
|
||||
print(result)
|
||||
@@ -0,0 +1,217 @@
|
||||
import streamlit as st
|
||||
from praisonaiagents import Agent, Task, PraisonAIAgents
|
||||
from pydantic import BaseModel
|
||||
from typing import List, Dict, Any
|
||||
from gitingest import ingest
|
||||
|
||||
# Import the same classes and code from code-analysis-agents.py
|
||||
class CodeMetrics(BaseModel):
|
||||
category: str
|
||||
score: int
|
||||
findings: List[str]
|
||||
|
||||
class CodeAnalysisReport(BaseModel):
|
||||
overall_quality: int
|
||||
code_metrics: List[CodeMetrics]
|
||||
architecture_score: int
|
||||
maintainability_score: int
|
||||
performance_score: int
|
||||
security_score: int
|
||||
test_coverage: int
|
||||
key_strengths: List[str]
|
||||
improvement_areas: List[str]
|
||||
tech_stack: List[str]
|
||||
recommendations: List[str]
|
||||
complexity_metrics: Dict[str, int]
|
||||
best_practices: List[Dict[str, str]]
|
||||
potential_risks: List[str]
|
||||
documentation_quality: int
|
||||
|
||||
def analyze_code(code_source: str) -> CodeAnalysisReport:
|
||||
"""
|
||||
Analyze code from directory path or GitHub URL
|
||||
"""
|
||||
# Create code analyzer agent
|
||||
code_analyzer = Agent(
|
||||
role="Code Analysis Expert",
|
||||
goal="Provide comprehensive code evaluation and recommendations",
|
||||
backstory="""Expert code analyst specializing in architecture review,
|
||||
best practices, and technical debt assessment.""",
|
||||
verbose=True
|
||||
)
|
||||
|
||||
# Create analysis task
|
||||
code_analysis_task = Task(
|
||||
description="""Analyze code repository and provide structured evaluation:
|
||||
|
||||
1. Overall Quality (0-100)
|
||||
2. Core Metrics Analysis:
|
||||
- Architecture and Design
|
||||
- Code Maintainability
|
||||
- Performance Optimization
|
||||
- Security Practices
|
||||
- Test Coverage
|
||||
3. Technical Assessment:
|
||||
- Technology Stack Review
|
||||
- Code Complexity Analysis
|
||||
- Best Practices Adherence
|
||||
- Risk Assessment
|
||||
4. Recommendations:
|
||||
- Key Improvements
|
||||
- Architecture Suggestions
|
||||
- Security Enhancements""",
|
||||
expected_output="Detailed code analysis report with metrics and recommendations",
|
||||
agent=code_analyzer,
|
||||
output_pydantic=CodeAnalysisReport
|
||||
)
|
||||
|
||||
# Ingest code content
|
||||
summary, tree, content = ingest(code_source)
|
||||
|
||||
# Concatenate context into structured format
|
||||
context_text = f"""
|
||||
CODE REPOSITORY ANALYSIS
|
||||
=======================
|
||||
|
||||
SUMMARY
|
||||
-------
|
||||
{summary}
|
||||
|
||||
REPOSITORY STRUCTURE
|
||||
-------------------
|
||||
{tree}
|
||||
|
||||
SOURCE CODE
|
||||
-----------
|
||||
{content}
|
||||
"""
|
||||
|
||||
# Initialize and run analysis
|
||||
agents = PraisonAIAgents(
|
||||
agents=[code_analyzer],
|
||||
tasks=[code_analysis_task]
|
||||
)
|
||||
|
||||
result = agents.start(context_text)
|
||||
|
||||
# Extract the Pydantic model from the result
|
||||
if isinstance(result, dict) and 'task_results' in result:
|
||||
# Get the first task result's pydantic output
|
||||
analysis_result = result['task_results'][0].pydantic
|
||||
if isinstance(analysis_result, CodeAnalysisReport):
|
||||
return analysis_result
|
||||
|
||||
# If we can't get the Pydantic model, create one from the raw data
|
||||
return CodeAnalysisReport(**result)
|
||||
|
||||
def display_code_metrics(metrics, cols):
|
||||
"""Display code metrics in columns with color-coded scores"""
|
||||
for i, metric in enumerate(metrics):
|
||||
score = metric.score
|
||||
color = "red" if score < 60 else "orange" if score < 75 else "green"
|
||||
|
||||
# Use modulo to alternate between columns
|
||||
with cols[i % len(cols)]:
|
||||
st.markdown(f"### {metric.category}")
|
||||
st.markdown(f"**Score:** :{color}[{score}%]")
|
||||
for finding in metric.findings:
|
||||
st.markdown(f"• {finding}")
|
||||
|
||||
def display_section(title: str, items: list, icon: str = "•"):
|
||||
"""Display a section with items in a consistent format"""
|
||||
st.markdown(f"### {title}")
|
||||
for item in items:
|
||||
if isinstance(item, dict):
|
||||
for key, value in item.items():
|
||||
st.markdown(f"{icon} **{key}**: {value}")
|
||||
else:
|
||||
st.markdown(f"{icon} {item}")
|
||||
|
||||
def main():
|
||||
st.set_page_config(
|
||||
page_title="Code Analysis Agent",
|
||||
layout="wide",
|
||||
initial_sidebar_state="expanded"
|
||||
)
|
||||
|
||||
st.title("Code Analysis Agent")
|
||||
|
||||
with st.sidebar:
|
||||
st.header("Input")
|
||||
code_source = st.text_input(
|
||||
"GitHub URL or Local Path",
|
||||
placeholder="https://github.com/username/repo or /path/to/directory"
|
||||
)
|
||||
analyze_button = st.button("Analyze Code", type="primary")
|
||||
|
||||
if analyze_button and code_source:
|
||||
try:
|
||||
with st.spinner("Analyzing code..."):
|
||||
result = analyze_code(code_source)
|
||||
|
||||
# Overall Metrics
|
||||
st.header("Overall Metrics")
|
||||
cols = st.columns(6)
|
||||
metrics = {
|
||||
"Overall Quality": result.overall_quality,
|
||||
"Architecture": result.architecture_score,
|
||||
"Maintainability": result.maintainability_score,
|
||||
"Performance": result.performance_score,
|
||||
"Security": result.security_score,
|
||||
"Test Coverage": result.test_coverage
|
||||
}
|
||||
|
||||
for (metric, value), col in zip(metrics.items(), cols):
|
||||
color = "red" if value < 60 else "orange" if value < 75 else "green"
|
||||
col.metric(metric, f"{value}%")
|
||||
col.markdown(f":{color}[{'●' * (value // 20)}]")
|
||||
|
||||
# Detailed Analysis
|
||||
st.header("Detailed Analysis")
|
||||
metric_cols = st.columns(2)
|
||||
display_code_metrics(result.code_metrics, metric_cols)
|
||||
|
||||
# Technology Stack
|
||||
col1, col2 = st.columns(2)
|
||||
with col1:
|
||||
st.header("Technology Stack")
|
||||
for tech in result.tech_stack:
|
||||
st.markdown(f"🔧 {tech}")
|
||||
|
||||
with col2:
|
||||
st.header("Complexity Metrics")
|
||||
for metric, value in result.complexity_metrics.items():
|
||||
st.metric(metric.replace('_', ' ').title(), value)
|
||||
|
||||
# Key Findings
|
||||
st.header("Key Findings")
|
||||
cols = st.columns(2)
|
||||
|
||||
with cols[0]:
|
||||
display_section("✅ Strengths", result.key_strengths)
|
||||
display_section("🔄 Best Practices", result.best_practices)
|
||||
|
||||
with cols[1]:
|
||||
display_section("⚠️ Areas for Improvement", result.improvement_areas)
|
||||
display_section("❗ Potential Risks", result.potential_risks)
|
||||
|
||||
# Recommendations
|
||||
st.header("Recommendations")
|
||||
for i, rec in enumerate(result.recommendations, 1):
|
||||
st.markdown(f"**{i}.** {rec}")
|
||||
|
||||
# Documentation Quality
|
||||
st.header("Documentation")
|
||||
doc_score = result.documentation_quality
|
||||
color = "red" if doc_score < 60 else "orange" if doc_score < 75 else "green"
|
||||
st.markdown(f"Documentation Quality: :{color}[{doc_score}%]")
|
||||
|
||||
except Exception as e:
|
||||
st.error(f"Error analyzing code: {str(e)}")
|
||||
st.exception(e)
|
||||
|
||||
elif analyze_button:
|
||||
st.warning("Please enter a GitHub URL or local path")
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,108 @@
|
||||
from praisonaiagents import Agent, Task, PraisonAIAgents
|
||||
import time
|
||||
from typing import List, Dict
|
||||
|
||||
def analyze_code_changes():
|
||||
"""Simulates code analysis"""
|
||||
issues = [
|
||||
{"type": "style", "severity": "low", "file": "main.py"},
|
||||
{"type": "security", "severity": "high", "file": "auth.py"},
|
||||
{"type": "performance", "severity": "medium", "file": "data.py"}
|
||||
]
|
||||
return issues[int(time.time()) % 3]
|
||||
|
||||
def suggest_fixes(issue: Dict):
|
||||
"""Simulates fix suggestions"""
|
||||
fixes = {
|
||||
"style": "Apply PEP 8 formatting",
|
||||
"security": "Implement input validation",
|
||||
"performance": "Use list comprehension"
|
||||
}
|
||||
return fixes.get(issue["type"], "Review manually")
|
||||
|
||||
def apply_automated_fix(fix: str):
|
||||
"""Simulates applying automated fixes"""
|
||||
success = int(time.time()) % 2 == 0
|
||||
return "fixed" if success else "manual_review"
|
||||
|
||||
# Create specialized agents
|
||||
analyzer = Agent(
|
||||
name="Code Analyzer",
|
||||
role="Code analysis",
|
||||
goal="Analyze code changes and identify issues",
|
||||
instructions="Review code changes and report issues",
|
||||
tools=[analyze_code_changes]
|
||||
)
|
||||
|
||||
fix_suggester = Agent(
|
||||
name="Fix Suggester",
|
||||
role="Solution provider",
|
||||
goal="Suggest fixes for identified issues",
|
||||
instructions="Provide appropriate fix suggestions",
|
||||
tools=[suggest_fixes]
|
||||
)
|
||||
|
||||
fix_applier = Agent(
|
||||
name="Fix Applier",
|
||||
role="Fix implementation",
|
||||
goal="Apply suggested fixes automatically when possible",
|
||||
instructions="Implement suggested fixes and report results",
|
||||
tools=[apply_automated_fix]
|
||||
)
|
||||
|
||||
# Create workflow tasks
|
||||
analysis_task = Task(
|
||||
name="analyze_code",
|
||||
description="Analyze code changes for issues",
|
||||
expected_output="Identified code issues",
|
||||
agent=analyzer,
|
||||
is_start=True,
|
||||
next_tasks=["suggest_fixes"]
|
||||
)
|
||||
|
||||
suggestion_task = Task(
|
||||
name="suggest_fixes",
|
||||
description="Suggest fixes for identified issues",
|
||||
expected_output="Fix suggestions",
|
||||
agent=fix_suggester,
|
||||
next_tasks=["apply_fixes"]
|
||||
)
|
||||
|
||||
fix_task = Task(
|
||||
name="apply_fixes",
|
||||
description="Apply suggested fixes",
|
||||
expected_output="Fix application status",
|
||||
agent=fix_applier,
|
||||
task_type="decision",
|
||||
condition={
|
||||
"fixed": "",
|
||||
"manual_review": ["suggest_fixes"] # Loop back for manual review
|
||||
}
|
||||
)
|
||||
|
||||
# Create workflow
|
||||
workflow = PraisonAIAgents(
|
||||
agents=[analyzer, fix_suggester, fix_applier],
|
||||
tasks=[analysis_task, suggestion_task, fix_task],
|
||||
process="workflow",
|
||||
verbose=True
|
||||
)
|
||||
|
||||
def main():
|
||||
print("\nStarting Code Review Workflow...")
|
||||
print("=" * 50)
|
||||
|
||||
# Run workflow
|
||||
results = workflow.start()
|
||||
|
||||
# Print results
|
||||
print("\nCode Review Results:")
|
||||
print("=" * 50)
|
||||
for task_id, result in results["task_results"].items():
|
||||
if result:
|
||||
print(f"\nTask: {task_id}")
|
||||
print(f"Result: {result.raw}")
|
||||
print("-" * 50)
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,98 @@
|
||||
from praisonaiagents import Agent, Task, PraisonAIAgents
|
||||
from pydantic import BaseModel
|
||||
from typing import List, Dict
|
||||
|
||||
class SkillMetrics(BaseModel):
|
||||
name: str
|
||||
score: int
|
||||
comments: str
|
||||
|
||||
class CVAnalysisReport(BaseModel):
|
||||
overall_score: int
|
||||
skill_metrics: List[SkillMetrics]
|
||||
experience_score: int
|
||||
education_score: int
|
||||
presentation_score: int
|
||||
achievement_impact_score: int
|
||||
market_readiness: int
|
||||
key_strengths: List[str]
|
||||
areas_for_improvement: List[str]
|
||||
market_fit: str
|
||||
recommendations: List[str]
|
||||
technical_skills: List[Dict[str, int]]
|
||||
soft_skills: List[Dict[str, int]]
|
||||
skill_gaps: List[str]
|
||||
key_achievements: List[str]
|
||||
impact_metrics: List[Dict[str, str]]
|
||||
areas_of_expertise: List[str]
|
||||
|
||||
# Create single CV analysis agent
|
||||
cv_analyzer = Agent(
|
||||
role="CV Analysis Expert",
|
||||
goal="Provide comprehensive CV evaluation and recommendations",
|
||||
backstory="""You are an expert CV analyst with deep knowledge of industry requirements,
|
||||
market trends, and talent assessment. You excel at evaluating skills, experience,
|
||||
and providing actionable recommendations.""",
|
||||
verbose=True
|
||||
)
|
||||
|
||||
# Single comprehensive analysis task
|
||||
cv_analysis_task = Task(
|
||||
description="""Perform a detailed CV analysis with scoring metrics and provide output in the following format:
|
||||
|
||||
1. Overall Score (0-100):
|
||||
- Calculate based on weighted average of all metrics
|
||||
|
||||
2. Individual Skill Metrics:
|
||||
- For each major skill found in CV:
|
||||
* Name of skill
|
||||
* Score (0-100)
|
||||
* Specific feedback/comments
|
||||
|
||||
3. Core Metrics (0-100 each):
|
||||
- Experience Score: Based on relevance and years
|
||||
- Education Score: Based on relevance and level
|
||||
- Presentation Score: CV format, clarity, structure
|
||||
- Achievement Impact Score: Measurable results
|
||||
- Market Readiness: Current market fit
|
||||
|
||||
4. Technical Skills:
|
||||
- List each skill with proficiency score (0-100)
|
||||
- Example: {"Python": 85, "AWS": 70}
|
||||
|
||||
5. Soft Skills:
|
||||
- List each skill with proficiency score (0-100)
|
||||
- Example: {"Communication": 90, "Leadership": 75}
|
||||
|
||||
6. Detailed Analysis:
|
||||
- Key Strengths: Top 3-5 standout points
|
||||
- Areas for Improvement: 3-5 specific points
|
||||
- Market Fit: Current industry alignment
|
||||
- Skill Gaps: Missing critical skills for target role
|
||||
- Key Achievements: Quantifiable accomplishments
|
||||
- Impact Metrics: {"metric": "value"}
|
||||
- Areas of Expertise: Primary domains of expertise
|
||||
|
||||
7. Recommendations:
|
||||
- 3-5 actionable steps for improvement
|
||||
|
||||
Provide clear justification for all scores and ensure feedback is specific and actionable.""",
|
||||
expected_output="Structured CV analysis report with detailed metrics and scoring justification",
|
||||
agent=cv_analyzer,
|
||||
output_pydantic=CVAnalysisReport
|
||||
)
|
||||
|
||||
# Create and run the agent
|
||||
agents = PraisonAIAgents(
|
||||
agents=[cv_analyzer],
|
||||
tasks=[cv_analysis_task]
|
||||
)
|
||||
|
||||
# Read and pass CV content through start()
|
||||
with open('cv.txt', 'r') as file:
|
||||
cv_content = file.read()
|
||||
|
||||
# Start the analysis by passing CV content
|
||||
result = agents.start(cv_content)
|
||||
|
||||
print(result)
|
||||
@@ -0,0 +1,202 @@
|
||||
import streamlit as st
|
||||
from praisonaiagents import Agent, Task, PraisonAIAgents
|
||||
from pydantic import BaseModel
|
||||
from typing import List, Dict
|
||||
import json
|
||||
import asyncio
|
||||
import nest_asyncio
|
||||
from functools import partial
|
||||
|
||||
# Enable nested event loops
|
||||
nest_asyncio.apply()
|
||||
|
||||
class SkillMetrics(BaseModel):
|
||||
name: str
|
||||
score: int
|
||||
comments: str
|
||||
|
||||
class CVAnalysisReport(BaseModel):
|
||||
overall_score: int
|
||||
skill_metrics: List[SkillMetrics]
|
||||
experience_score: int
|
||||
education_score: int
|
||||
presentation_score: int
|
||||
achievement_impact_score: int
|
||||
market_readiness: int
|
||||
key_strengths: List[str]
|
||||
areas_for_improvement: List[str]
|
||||
market_fit: str
|
||||
recommendations: List[str]
|
||||
technical_skills: List[Dict[str, int]]
|
||||
soft_skills: List[Dict[str, int]]
|
||||
skill_gaps: List[str]
|
||||
key_achievements: List[str]
|
||||
impact_metrics: List[Dict[str, str]]
|
||||
areas_of_expertise: List[str]
|
||||
|
||||
async def analyze_cv_async(cv_content):
|
||||
cv_analyzer = Agent(
|
||||
role="CV Analysis Expert",
|
||||
goal="Provide comprehensive CV evaluation and recommendations",
|
||||
backstory="""You are an expert CV analyst with deep knowledge of industry requirements,
|
||||
market trends, and talent assessment. You excel at evaluating skills, experience,
|
||||
and providing actionable recommendations.""",
|
||||
verbose=True
|
||||
)
|
||||
|
||||
cv_analysis_task = Task(
|
||||
description="""Perform a detailed CV analysis with scoring metrics and provide output in the following format:
|
||||
1. Overall Score (0-100):
|
||||
- Calculate based on weighted average of all metrics
|
||||
|
||||
2. Individual Skill Metrics:
|
||||
- For each major skill found in CV:
|
||||
* Name of skill
|
||||
* Score (0-100)
|
||||
* Specific feedback/comments
|
||||
|
||||
3. Core Metrics (0-100 each):
|
||||
- Experience Score: Based on relevance and years
|
||||
- Education Score: Based on relevance and level
|
||||
- Presentation Score: CV format, clarity, structure
|
||||
- Achievement Impact Score: Measurable results
|
||||
- Market Readiness: Current market fit
|
||||
|
||||
4. Technical Skills:
|
||||
- List each skill with proficiency score (0-100)
|
||||
|
||||
5. Soft Skills:
|
||||
- List each skill with proficiency score (0-100)
|
||||
|
||||
6. Detailed Analysis sections
|
||||
|
||||
7. Recommendations:
|
||||
- 3-5 actionable steps for improvement""",
|
||||
expected_output="Structured CV analysis report with detailed metrics and scoring justification",
|
||||
agent=cv_analyzer,
|
||||
output_pydantic=CVAnalysisReport
|
||||
)
|
||||
|
||||
agents = PraisonAIAgents(
|
||||
agents=[cv_analyzer],
|
||||
tasks=[cv_analysis_task]
|
||||
)
|
||||
|
||||
try:
|
||||
result = await agents.astart(cv_content)
|
||||
return result['task_results'][0].pydantic
|
||||
except Exception as e:
|
||||
print(f"Error during analysis: {str(e)}")
|
||||
raise e
|
||||
|
||||
def analyze_cv(cv_content):
|
||||
async def run_analysis():
|
||||
return await analyze_cv_async(cv_content)
|
||||
|
||||
try:
|
||||
loop = asyncio.new_event_loop()
|
||||
asyncio.set_event_loop(loop)
|
||||
result = loop.run_until_complete(run_analysis())
|
||||
return result
|
||||
except Exception as e:
|
||||
raise e
|
||||
finally:
|
||||
loop.close()
|
||||
|
||||
def main():
|
||||
st.set_page_config(page_title="CV Analyzer", layout="wide")
|
||||
st.title("Professional CV Analyzer")
|
||||
|
||||
# File upload
|
||||
cv_file = st.file_uploader("Upload your CV (TXT format)", type=['txt'])
|
||||
|
||||
if cv_file:
|
||||
cv_content = cv_file.read().decode()
|
||||
|
||||
with st.spinner('Analyzing your CV...'):
|
||||
try:
|
||||
analysis = analyze_cv(cv_content)
|
||||
|
||||
# Display Overall Score
|
||||
col1, col2, col3 = st.columns(3)
|
||||
with col1:
|
||||
st.metric("Overall Score", f"{analysis.overall_score}/100")
|
||||
with col2:
|
||||
st.metric("Market Readiness", f"{analysis.market_readiness}/100")
|
||||
with col3:
|
||||
st.metric("Experience Score", f"{analysis.experience_score}/100")
|
||||
|
||||
# Core Metrics
|
||||
st.subheader("Core Metrics")
|
||||
metrics_cols = st.columns(4)
|
||||
with metrics_cols[0]:
|
||||
st.metric("Education", f"{analysis.education_score}/100")
|
||||
with metrics_cols[1]:
|
||||
st.metric("Presentation", f"{analysis.presentation_score}/100")
|
||||
with metrics_cols[2]:
|
||||
st.metric("Achievement Impact", f"{analysis.achievement_impact_score}/100")
|
||||
with metrics_cols[3]:
|
||||
st.metric("Market Readiness", f"{analysis.market_readiness}/100")
|
||||
|
||||
# Skill Metrics
|
||||
st.subheader("Detailed Skill Analysis")
|
||||
for skill in analysis.skill_metrics:
|
||||
with st.expander(f"{skill.name} - Score: {skill.score}/100"):
|
||||
st.write(skill.comments)
|
||||
|
||||
# Technical and Soft Skills
|
||||
col1, col2 = st.columns(2)
|
||||
with col1:
|
||||
st.subheader("Technical Skills")
|
||||
for skill in analysis.technical_skills:
|
||||
for skill_name, score in skill.items():
|
||||
st.progress(score/100)
|
||||
st.caption(f"{skill_name}: {score}/100")
|
||||
|
||||
with col2:
|
||||
st.subheader("Soft Skills")
|
||||
for skill in analysis.soft_skills:
|
||||
for skill_name, score in skill.items():
|
||||
st.progress(score/100)
|
||||
st.caption(f"{skill_name}: {score}/100")
|
||||
|
||||
# Key Information
|
||||
st.subheader("Key Analysis")
|
||||
col1, col2 = st.columns(2)
|
||||
with col1:
|
||||
st.write("🎯 Key Strengths")
|
||||
for strength in analysis.key_strengths:
|
||||
st.write(f"• {strength}")
|
||||
|
||||
st.write("🎮 Areas of Expertise")
|
||||
for expertise in analysis.areas_of_expertise:
|
||||
st.write(f"• {expertise}")
|
||||
|
||||
with col2:
|
||||
st.write("🔄 Areas for Improvement")
|
||||
for area in analysis.areas_for_improvement:
|
||||
st.write(f"• {area}")
|
||||
|
||||
st.write("⚠️ Skill Gaps")
|
||||
for gap in analysis.skill_gaps:
|
||||
st.write(f"• {gap}")
|
||||
|
||||
# Impact Metrics
|
||||
st.subheader("Impact Metrics")
|
||||
for metric in analysis.impact_metrics:
|
||||
for key, value in metric.items():
|
||||
st.metric(key, value)
|
||||
|
||||
# Recommendations
|
||||
st.subheader("📋 Recommendations")
|
||||
for rec in analysis.recommendations:
|
||||
st.write(f"• {rec}")
|
||||
|
||||
except Exception as e:
|
||||
st.error(f"An error occurred during analysis: {str(e)}")
|
||||
|
||||
else:
|
||||
st.info("Please upload your CV in TXT format to begin the analysis")
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,61 @@
|
||||
from praisonaiagents import Agent, Task, PraisonAIAgents
|
||||
from pydantic import BaseModel
|
||||
from typing import List, Dict
|
||||
|
||||
class CVAnalysisReport(BaseModel):
|
||||
overall_score: int
|
||||
key_strengths: List[str]
|
||||
areas_for_improvement: List[str]
|
||||
market_fit: str
|
||||
recommendations: List[str]
|
||||
technical_skills: List[str]
|
||||
soft_skills: List[str]
|
||||
skill_gaps: List[str]
|
||||
key_achievements: List[str]
|
||||
impact_metrics: List[Dict[str, str]]
|
||||
areas_of_expertise: List[str]
|
||||
|
||||
# Create single CV analysis agent
|
||||
cv_analyzer = Agent(
|
||||
role="CV Analysis Expert",
|
||||
goal="Provide comprehensive CV evaluation and recommendations",
|
||||
backstory="""You are an expert CV analyst with deep knowledge of industry requirements,
|
||||
market trends, and talent assessment. You excel at evaluating skills, experience,
|
||||
and providing actionable recommendations.""",
|
||||
verbose=True
|
||||
)
|
||||
|
||||
# Read CV content first
|
||||
with open('cv.txt', 'r') as file:
|
||||
cv_content = file.read()
|
||||
|
||||
cv_key_strengths = Task(
|
||||
description="List the key strengths to look",
|
||||
expected_output="List of key strengths",
|
||||
agent=cv_analyzer,
|
||||
)
|
||||
|
||||
# Single comprehensive analysis task with CV content in context
|
||||
cv_analysis_task = Task(
|
||||
description="""Analyze the CV comprehensively including:
|
||||
1. Technical and soft skills assessment
|
||||
2. Experience and achievements evaluation
|
||||
3. Overall CV evaluation with recommendations
|
||||
Provide detailed insights and actionable recommendations.""",
|
||||
expected_output="Complete CV analysis report",
|
||||
agent=cv_analyzer,
|
||||
output_pydantic=CVAnalysisReport,
|
||||
context=[cv_content, cv_key_strengths] # Pass CV content directly in task context
|
||||
)
|
||||
|
||||
# Create and run the agent
|
||||
agents = PraisonAIAgents(
|
||||
agents=[cv_analyzer],
|
||||
tasks=[cv_key_strengths,cv_analysis_task],
|
||||
process="sequential"
|
||||
)
|
||||
|
||||
# Start the analysis - no need to pass content again since it's in task context
|
||||
result = agents.start()
|
||||
|
||||
print(result)
|
||||
@@ -0,0 +1,27 @@
|
||||
# example tools.py
|
||||
from duckduckgo_search import DDGS
|
||||
from praisonai_tools import BaseTool
|
||||
|
||||
class InternetSearchTool(BaseTool):
|
||||
name: str = "InternetSearchTool"
|
||||
description: str = "Search Internet for relevant information based on a query or latest news"
|
||||
|
||||
def _run(self, query: str):
|
||||
ddgs = DDGS()
|
||||
results = ddgs.text(keywords=query, region='wt-wt', safesearch='moderate', max_results=5)
|
||||
return results
|
||||
|
||||
# Example agent
|
||||
from praisonaiagents import Agent
|
||||
from praisonaiagents import PraisonAIAgents
|
||||
agent = Agent(
|
||||
name="Internet Search Agent",
|
||||
tools=[InternetSearchTool],
|
||||
instructions="""
|
||||
You are an agent that can search the internet for relevant information based on a query or latest news.
|
||||
"""
|
||||
)
|
||||
|
||||
# Run the agent
|
||||
result = PraisonAIAgents(agents=[agent], verbose=10).start()
|
||||
print(result)
|
||||
@@ -0,0 +1,57 @@
|
||||
Name: Alex Johnson
|
||||
Location: London, UK
|
||||
|
||||
Professional Summary
|
||||
Dynamic and results-oriented leader with a proven track record of driving innovation, scaling operations, and achieving transformational growth. Over 15 years of experience in engineering, strategic management, and executive leadership in the automotive and renewable energy sectors. Passionate about sustainable technologies and visionary leadership.
|
||||
|
||||
Professional Experience
|
||||
Chief Operating Officer (COO)
|
||||
NextGen Mobility Ltd. | Palo Alto, CA | 2020 – Present
|
||||
|
||||
Spearheaded global operations for an electric vehicle company, scaling production by 200% in three years.
|
||||
Introduced automation-driven supply chain strategies, reducing costs by 15%.
|
||||
Collaborated with R&D to launch three new EV models, driving 25% revenue growth annually.
|
||||
Vice President of Engineering
|
||||
ElectroDrive Systems | San Francisco, CA | 2015 – 2020
|
||||
|
||||
Led a team of 500+ engineers in developing next-generation EV batteries, achieving a 30% increase in energy efficiency.
|
||||
Secured $50M in government funding for sustainable energy innovation.
|
||||
Drove cross-functional collaboration, aligning product development with market needs.
|
||||
Director of Renewable Energy Initiatives
|
||||
GreenTech Innovations | London, UK | 2011 – 2015
|
||||
|
||||
Oversaw £100M projects in solar and wind energy deployment across Europe.
|
||||
Established partnerships with policymakers to influence renewable energy legislation.
|
||||
Pioneered a smart energy grid system, enhancing energy distribution efficiency by 40%.
|
||||
Senior Project Manager
|
||||
Innovate Auto Ltd. | Munich, Germany | 2008 – 2011
|
||||
|
||||
Managed R&D projects for autonomous driving technologies.
|
||||
Delivered projects 20% under budget through strategic resource allocation.
|
||||
Filed 10+ patents in automotive AI and renewable integration.
|
||||
Mechanical Engineer
|
||||
AutoFusion Technologies | Berlin, Germany | 2005 – 2008
|
||||
|
||||
Designed core systems for EV powertrains, optimising energy consumption by 15%.
|
||||
Collaborated with suppliers to improve material efficiency, cutting costs by £5M annually.
|
||||
Education
|
||||
MBA in Strategic Management
|
||||
Harvard Business School | Cambridge, MA | 2015
|
||||
|
||||
MSc in Renewable Energy Engineering
|
||||
Imperial College London | London, UK | 2007
|
||||
|
||||
BSc in Mechanical Engineering
|
||||
Technical University of Munich | Munich, Germany | 2005
|
||||
|
||||
Skills
|
||||
Strategic Leadership & Visionary Thinking
|
||||
Electric Vehicle Engineering
|
||||
Renewable Energy Systems
|
||||
Global Operations Management
|
||||
Policy Advocacy & Government Relations
|
||||
Supply Chain Optimisation
|
||||
Achievements
|
||||
Featured in Forbes 30 Under 40 for innovations in EV technology.
|
||||
Author of The Future of Sustainable Mobility.
|
||||
Keynote speaker at World Energy Summit, 2023.
|
||||
@@ -0,0 +1,10 @@
|
||||
from praisonaiagents import Agent, Tools
|
||||
from praisonaiagents.tools import read_csv, read_excel, write_csv, write_excel, filter_data, get_summary, group_by, pivot_table
|
||||
import os
|
||||
|
||||
agent = Agent(instructions="You are a Data Analyst Agent", tools=[read_csv, read_excel, write_csv, write_excel, filter_data, get_summary, group_by, pivot_table])
|
||||
agent.start(f"""
|
||||
Read the data from the csv file {os.path.join(os.path.dirname(__file__), "tesla-stock-price.csv")}
|
||||
Analyse the data and give me the insights
|
||||
read_csv to read the file
|
||||
""")
|
||||
@@ -0,0 +1,3 @@
|
||||
I am Mervin Praison, a software engineer and entrepreneur.
|
||||
|
||||
I am the founder of Praison AI, a company that is building AI agents to help people with their daily tasks.
|
||||
@@ -0,0 +1,70 @@
|
||||
from praisonaiagents import Agent, Task, PraisonAIAgents
|
||||
|
||||
# Create generator and evaluator agents
|
||||
generator = Agent(
|
||||
name="Generator",
|
||||
role="Solution generator",
|
||||
goal="Generate initial solutions and incorporate feedback",
|
||||
instructions=(
|
||||
"1. Look at the context from previous tasks.\n"
|
||||
"2. If you see that you have already produced 2 points, then add another 2 new points "
|
||||
" so that the total becomes 10.\n"
|
||||
"3. Otherwise, just produce the first 2 points.\n"
|
||||
"4. Return only the final list of points, with no extra explanation."
|
||||
)
|
||||
)
|
||||
|
||||
evaluator = Agent(
|
||||
name="Evaluator",
|
||||
role="Solution evaluator",
|
||||
goal="Evaluate solutions and provide improvement feedback",
|
||||
instructions=(
|
||||
"1. Count how many lines in the response start with a number and a period (like '1. ' or '2. ').\n"
|
||||
"2. If there are 10 or more, respond with 'done'.\n"
|
||||
"3. Otherwise, respond with 'more'.\n"
|
||||
"4. Return only the single word: 'done' or 'more'."
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
# Create tasks for the feedback loop
|
||||
generate_task = Task(
|
||||
name="generate",
|
||||
description="Write 2 points about AI incuding if anything exiting from previous points",
|
||||
expected_output="2 points",
|
||||
agent=generator,
|
||||
is_start=True,
|
||||
task_type="decision",
|
||||
next_tasks=["evaluate"]
|
||||
)
|
||||
|
||||
evaluate_task = Task(
|
||||
name="evaluate",
|
||||
description="Check if there are 10 points about AI",
|
||||
expected_output="more or done",
|
||||
agent=evaluator,
|
||||
next_tasks=["generate"],
|
||||
context=[generate_task],
|
||||
task_type="decision",
|
||||
condition={
|
||||
"more": ["generate"], # Continue to generate
|
||||
"done": [""] # Exit when optimization complete
|
||||
}
|
||||
)
|
||||
|
||||
# Create workflow manager
|
||||
workflow = PraisonAIAgents(
|
||||
agents=[generator, evaluator],
|
||||
tasks=[generate_task, evaluate_task],
|
||||
process="workflow",
|
||||
verbose=True
|
||||
)
|
||||
|
||||
# Run optimization workflow
|
||||
results = workflow.start()
|
||||
|
||||
# Print results
|
||||
print("\nEvaluator-Optimizer Results:")
|
||||
for task_id, result in results["task_results"].items():
|
||||
if result:
|
||||
print(f"Task {task_id}: {result.raw}")
|
||||
@@ -0,0 +1,5 @@
|
||||
from praisonaiagents import Agent, Tools
|
||||
from praisonaiagents.tools import get_stock_price, get_stock_info, get_historical_data
|
||||
|
||||
agent = Agent(instructions="You are a Research Agent", tools=[get_stock_price, get_stock_info, get_historical_data])
|
||||
agent.start("Understand current stock price and historical data of Apple and Google. Tell me if I can invest in them")
|
||||
@@ -0,0 +1,34 @@
|
||||
import gradio as gr
|
||||
from praisonaiagents import Agent, Tools
|
||||
from praisonaiagents.tools import duckduckgo
|
||||
|
||||
def research(query):
|
||||
agent = Agent(instructions="You are a Research Agent", tools=[duckduckgo])
|
||||
result = agent.start(query)
|
||||
# Format the result with enhanced markdown
|
||||
formatted_result = f"""
|
||||
{result}
|
||||
----
|
||||
*Generated by PraisonAI Research Assistant*
|
||||
"""
|
||||
return formatted_result
|
||||
|
||||
# Create a simple Gradio interface
|
||||
demo = gr.Interface(
|
||||
fn=research,
|
||||
inputs=gr.Textbox(
|
||||
label="Research Query",
|
||||
placeholder="Enter your research topic...",
|
||||
lines=2
|
||||
),
|
||||
outputs=gr.Markdown(
|
||||
show_copy_button=True,
|
||||
height=500,
|
||||
container=True
|
||||
),
|
||||
title="AI Research Assistant",
|
||||
description="Enter your research query below to get started!",
|
||||
)
|
||||
|
||||
if __name__ == "__main__":
|
||||
demo.launch()
|
||||
Whitespace-only changes.
@@ -0,0 +1,159 @@
|
||||
from praisonaiagents import Agent, Task, PraisonAIAgents
|
||||
from pydantic import BaseModel
|
||||
from typing import List, Dict
|
||||
import os
|
||||
import json
|
||||
|
||||
class ProjectEvaluation(BaseModel):
|
||||
innovation_score: int # 0-100
|
||||
technical_complexity: int # 0-100
|
||||
presentation_quality: int # 0-100
|
||||
user_experience: int # 0-100
|
||||
completeness: int # 0-100
|
||||
overall_score: int # 0-100
|
||||
key_strengths: List[str]
|
||||
areas_for_improvement: List[str]
|
||||
notable_features: List[str]
|
||||
technical_highlights: List[str]
|
||||
recommendations: List[str]
|
||||
market_potential: str
|
||||
scalability_assessment: str
|
||||
|
||||
# Create Vision Analysis Agent
|
||||
hackathon_judge = Agent(
|
||||
name="HackathonJudge",
|
||||
role="Technical Project Evaluator",
|
||||
goal="Evaluate hackathon projects through video demonstrations",
|
||||
backstory="""You are an experienced hackathon judge and technical expert.
|
||||
You excel at evaluating innovation, technical implementation, and presentation quality.
|
||||
You provide constructive feedback and identify both strengths and areas for improvement.""",
|
||||
llm="gpt-4o-mini", # Using vision-capable model
|
||||
self_reflect=False,
|
||||
knowledge=""
|
||||
)
|
||||
|
||||
def evaluate_project(video_path: str) -> ProjectEvaluation:
|
||||
"""
|
||||
Evaluate a hackathon project based on its video demonstration
|
||||
"""
|
||||
evaluation_task = Task(
|
||||
name="project_evaluation",
|
||||
description="""Analyze this hackathon project video demonstration and provide a comprehensive evaluation:
|
||||
|
||||
1. Score the following aspects (0-100):
|
||||
- Innovation and Creativity
|
||||
- Technical Complexity
|
||||
- Presentation Quality
|
||||
- User Experience
|
||||
- Project Completeness
|
||||
|
||||
2. Identify:
|
||||
- Key strengths and standout features
|
||||
- Areas that could be improved
|
||||
- Notable technical implementations
|
||||
- Market potential and scalability
|
||||
|
||||
3. Provide:
|
||||
- Specific recommendations for improvement
|
||||
- Technical suggestions
|
||||
- Potential future enhancements""",
|
||||
expected_output="Detailed project evaluation with scores and feedback",
|
||||
agent=hackathon_judge,
|
||||
output_pydantic=ProjectEvaluation,
|
||||
images=[video_path] # Video input for multimodal analysis
|
||||
)
|
||||
|
||||
# Initialize and run evaluation
|
||||
agents = PraisonAIAgents(
|
||||
agents=[hackathon_judge],
|
||||
tasks=[evaluation_task],
|
||||
process="sequential",
|
||||
verbose=True
|
||||
)
|
||||
|
||||
response = agents.start()
|
||||
|
||||
try:
|
||||
# If response contains task_results, extract the Pydantic model directly
|
||||
if isinstance(response, dict) and 'task_results' in response:
|
||||
task_output = response['task_results'][0]
|
||||
if hasattr(task_output, 'pydantic'):
|
||||
return task_output.pydantic
|
||||
elif hasattr(task_output, 'raw'):
|
||||
# Extract JSON from raw string if it's wrapped in ```json
|
||||
raw_text = task_output.raw
|
||||
if raw_text.startswith('```json'):
|
||||
raw_text = raw_text.split('\n', 1)[1].rsplit('\n', 1)[0]
|
||||
evaluation_data = json.loads(raw_text)
|
||||
else:
|
||||
evaluation_data = json.loads(task_output) if isinstance(task_output, str) else task_output
|
||||
# If response is a string, try to parse it as JSON
|
||||
elif isinstance(response, str):
|
||||
evaluation_data = json.loads(response)
|
||||
# If response is a dict with task_status
|
||||
elif isinstance(response, dict) and 'task_status' in response:
|
||||
content = response['task_status']
|
||||
if isinstance(content, dict):
|
||||
evaluation_data = content
|
||||
else:
|
||||
evaluation_data = json.loads(content) if isinstance(content, str) else content
|
||||
else:
|
||||
evaluation_data = response
|
||||
|
||||
print(f"Debug - Parsed evaluation_data: {evaluation_data}")
|
||||
|
||||
# Create and return ProjectEvaluation instance
|
||||
return ProjectEvaluation(
|
||||
innovation_score=int(evaluation_data.get('innovation_score', 0)),
|
||||
technical_complexity=int(evaluation_data.get('technical_complexity', 0)),
|
||||
presentation_quality=int(evaluation_data.get('presentation_quality', 0)),
|
||||
user_experience=int(evaluation_data.get('user_experience', 0)),
|
||||
completeness=int(evaluation_data.get('completeness', 0)),
|
||||
overall_score=int(evaluation_data.get('overall_score', 0)),
|
||||
key_strengths=evaluation_data.get('key_strengths', []),
|
||||
areas_for_improvement=evaluation_data.get('areas_for_improvement', []),
|
||||
notable_features=evaluation_data.get('notable_features', []),
|
||||
technical_highlights=evaluation_data.get('technical_highlights', []),
|
||||
recommendations=evaluation_data.get('recommendations', []),
|
||||
market_potential=str(evaluation_data.get('market_potential', '')),
|
||||
scalability_assessment=str(evaluation_data.get('scalability_assessment', ''))
|
||||
)
|
||||
except Exception as e:
|
||||
print(f"Debug - Raw response: {response}")
|
||||
print(f"Error processing response: {e}")
|
||||
raise
|
||||
|
||||
if __name__ == "__main__":
|
||||
# Example usage
|
||||
current_dir = os.path.dirname(os.path.abspath(__file__))
|
||||
video_path = os.path.join(current_dir, "presentation.mp4")
|
||||
result = evaluate_project(video_path) # Now returns ProjectEvaluation directly
|
||||
|
||||
print("\nHackathon Project Evaluation")
|
||||
print("===========================")
|
||||
print(f"\nOverall Score: {result.overall_score}/100")
|
||||
print("\nDetailed Scores:")
|
||||
print(f"Innovation: {result.innovation_score}/100")
|
||||
print(f"Technical Complexity: {result.technical_complexity}/100")
|
||||
print(f"Presentation: {result.presentation_quality}/100")
|
||||
print(f"User Experience: {result.user_experience}/100")
|
||||
print(f"Completeness: {result.completeness}/100")
|
||||
|
||||
print("\nKey Strengths:")
|
||||
for strength in result.key_strengths:
|
||||
print(f"- {strength}")
|
||||
|
||||
print("\nAreas for Improvement:")
|
||||
for area in result.areas_for_improvement:
|
||||
print(f"- {area}")
|
||||
|
||||
print("\nTechnical Highlights:")
|
||||
for highlight in result.technical_highlights:
|
||||
print(f"- {highlight}")
|
||||
|
||||
print("\nRecommendations:")
|
||||
for rec in result.recommendations:
|
||||
print(f"- {rec}")
|
||||
|
||||
print(f"\nMarket Potential: {result.market_potential}")
|
||||
print(f"\nScalability Assessment: {result.scalability_assessment}")
|
||||
@@ -0,0 +1,159 @@
|
||||
from praisonaiagents import Agent, Task, PraisonAIAgents
|
||||
from pydantic import BaseModel
|
||||
from typing import List, Dict
|
||||
import os
|
||||
import json
|
||||
|
||||
class ProjectEvaluation(BaseModel):
|
||||
innovation_score: int # 0-100
|
||||
technical_complexity: int # 0-100
|
||||
presentation_quality: int # 0-100
|
||||
user_experience: int # 0-100
|
||||
completeness: int # 0-100
|
||||
overall_score: int # 0-100
|
||||
key_strengths: List[str]
|
||||
areas_for_improvement: List[str]
|
||||
notable_features: List[str]
|
||||
technical_highlights: List[str]
|
||||
recommendations: List[str]
|
||||
market_potential: str
|
||||
scalability_assessment: str
|
||||
|
||||
# Create Vision Analysis Agent
|
||||
hackathon_judge = Agent(
|
||||
name="HackathonJudge",
|
||||
role="Technical Project Evaluator",
|
||||
goal="Evaluate hackathon projects through video demonstrations",
|
||||
backstory="""You are an experienced hackathon judge and technical expert.
|
||||
You excel at evaluating innovation, technical implementation, and presentation quality.
|
||||
You provide constructive feedback and identify both strengths and areas for improvement.""",
|
||||
llm="gpt-4o-mini", # Using vision-capable model
|
||||
self_reflect=False,
|
||||
knowledge=""
|
||||
)
|
||||
|
||||
def evaluate_project(video_path: str) -> ProjectEvaluation:
|
||||
"""
|
||||
Evaluate a hackathon project based on its video demonstration
|
||||
"""
|
||||
evaluation_task = Task(
|
||||
name="project_evaluation",
|
||||
description="""Analyze this hackathon project video demonstration and provide a comprehensive evaluation:
|
||||
|
||||
1. Score the following aspects (0-100):
|
||||
- Innovation and Creativity
|
||||
- Technical Complexity
|
||||
- Presentation Quality
|
||||
- User Experience
|
||||
- Project Completeness
|
||||
|
||||
2. Identify:
|
||||
- Key strengths and standout features
|
||||
- Areas that could be improved
|
||||
- Notable technical implementations
|
||||
- Market potential and scalability
|
||||
|
||||
3. Provide:
|
||||
- Specific recommendations for improvement
|
||||
- Technical suggestions
|
||||
- Potential future enhancements""",
|
||||
expected_output="Detailed project evaluation with scores and feedback",
|
||||
agent=hackathon_judge,
|
||||
output_pydantic=ProjectEvaluation,
|
||||
images=[video_path] # Video input for multimodal analysis
|
||||
)
|
||||
|
||||
# Initialize and run evaluation
|
||||
agents = PraisonAIAgents(
|
||||
agents=[hackathon_judge],
|
||||
tasks=[evaluation_task],
|
||||
process="sequential",
|
||||
verbose=True
|
||||
)
|
||||
|
||||
response = agents.start()
|
||||
|
||||
try:
|
||||
# If response contains task_results, extract the Pydantic model directly
|
||||
if isinstance(response, dict) and 'task_results' in response:
|
||||
task_output = response['task_results'][0]
|
||||
if hasattr(task_output, 'pydantic'):
|
||||
return task_output.pydantic
|
||||
elif hasattr(task_output, 'raw'):
|
||||
# Extract JSON from raw string if it's wrapped in ```json
|
||||
raw_text = task_output.raw
|
||||
if raw_text.startswith('```json'):
|
||||
raw_text = raw_text.split('\n', 1)[1].rsplit('\n', 1)[0]
|
||||
evaluation_data = json.loads(raw_text)
|
||||
else:
|
||||
evaluation_data = json.loads(task_output) if isinstance(task_output, str) else task_output
|
||||
# If response is a string, try to parse it as JSON
|
||||
elif isinstance(response, str):
|
||||
evaluation_data = json.loads(response)
|
||||
# If response is a dict with task_status
|
||||
elif isinstance(response, dict) and 'task_status' in response:
|
||||
content = response['task_status']
|
||||
if isinstance(content, dict):
|
||||
evaluation_data = content
|
||||
else:
|
||||
evaluation_data = json.loads(content) if isinstance(content, str) else content
|
||||
else:
|
||||
evaluation_data = response
|
||||
|
||||
print(f"Debug - Parsed evaluation_data: {evaluation_data}")
|
||||
|
||||
# Create and return ProjectEvaluation instance
|
||||
return ProjectEvaluation(
|
||||
innovation_score=int(evaluation_data.get('innovation_score', 0)),
|
||||
technical_complexity=int(evaluation_data.get('technical_complexity', 0)),
|
||||
presentation_quality=int(evaluation_data.get('presentation_quality', 0)),
|
||||
user_experience=int(evaluation_data.get('user_experience', 0)),
|
||||
completeness=int(evaluation_data.get('completeness', 0)),
|
||||
overall_score=int(evaluation_data.get('overall_score', 0)),
|
||||
key_strengths=evaluation_data.get('key_strengths', []),
|
||||
areas_for_improvement=evaluation_data.get('areas_for_improvement', []),
|
||||
notable_features=evaluation_data.get('notable_features', []),
|
||||
technical_highlights=evaluation_data.get('technical_highlights', []),
|
||||
recommendations=evaluation_data.get('recommendations', []),
|
||||
market_potential=str(evaluation_data.get('market_potential', '')),
|
||||
scalability_assessment=str(evaluation_data.get('scalability_assessment', ''))
|
||||
)
|
||||
except Exception as e:
|
||||
print(f"Debug - Raw response: {response}")
|
||||
print(f"Error processing response: {e}")
|
||||
raise
|
||||
|
||||
if __name__ == "__main__":
|
||||
# Example usage
|
||||
current_dir = os.path.dirname(os.path.abspath(__file__))
|
||||
video_path = os.path.join(current_dir, "presentation.mp4")
|
||||
result = evaluate_project(video_path) # Now returns ProjectEvaluation directly
|
||||
|
||||
print("\nHackathon Project Evaluation")
|
||||
print("===========================")
|
||||
print(f"\nOverall Score: {result.overall_score}/100")
|
||||
print("\nDetailed Scores:")
|
||||
print(f"Innovation: {result.innovation_score}/100")
|
||||
print(f"Technical Complexity: {result.technical_complexity}/100")
|
||||
print(f"Presentation: {result.presentation_quality}/100")
|
||||
print(f"User Experience: {result.user_experience}/100")
|
||||
print(f"Completeness: {result.completeness}/100")
|
||||
|
||||
print("\nKey Strengths:")
|
||||
for strength in result.key_strengths:
|
||||
print(f"- {strength}")
|
||||
|
||||
print("\nAreas for Improvement:")
|
||||
for area in result.areas_for_improvement:
|
||||
print(f"- {area}")
|
||||
|
||||
print("\nTechnical Highlights:")
|
||||
for highlight in result.technical_highlights:
|
||||
print(f"- {highlight}")
|
||||
|
||||
print("\nRecommendations:")
|
||||
for rec in result.recommendations:
|
||||
print(f"- {rec}")
|
||||
|
||||
print(f"\nMarket Potential: {result.market_potential}")
|
||||
print(f"\nScalability Assessment: {result.scalability_assessment}")
|
||||
@@ -0,0 +1,210 @@
|
||||
import streamlit as st
|
||||
import os
|
||||
from praisonaiagents import Agent, Task, PraisonAIAgents
|
||||
from pydantic import BaseModel
|
||||
from typing import List, Dict
|
||||
import tempfile
|
||||
import json
|
||||
|
||||
class ProjectEvaluation(BaseModel):
|
||||
innovation_score: int # 0-100
|
||||
technical_complexity: int # 0-100
|
||||
presentation_quality: int # 0-100
|
||||
user_experience: int # 0-100
|
||||
completeness: int # 0-100
|
||||
overall_score: int # 0-100
|
||||
key_strengths: List[str]
|
||||
areas_for_improvement: List[str]
|
||||
notable_features: List[str]
|
||||
technical_highlights: List[str]
|
||||
recommendations: List[str]
|
||||
market_potential: str
|
||||
scalability_assessment: str
|
||||
|
||||
# Set page config
|
||||
st.set_page_config(
|
||||
page_title="Hackathon Project Evaluator",
|
||||
page_icon="🏆",
|
||||
layout="wide"
|
||||
)
|
||||
|
||||
# Create Vision Analysis Agent
|
||||
@st.cache_resource
|
||||
def get_hackathon_judge():
|
||||
return Agent(
|
||||
name="HackathonJudge",
|
||||
role="Technical Project Evaluator",
|
||||
goal="Evaluate hackathon projects through video demonstrations",
|
||||
backstory="""You are an experienced hackathon judge and technical expert.
|
||||
You excel at evaluating innovation, technical implementation, and presentation quality.
|
||||
You provide constructive feedback and identify both strengths and areas for improvement.""",
|
||||
llm="gpt-4o-mini", # Using vision-capable model
|
||||
self_reflect=False,
|
||||
knowledge=""
|
||||
)
|
||||
|
||||
def evaluate_project(video_path: str) -> ProjectEvaluation:
|
||||
"""
|
||||
Evaluate a hackathon project based on its video demonstration
|
||||
"""
|
||||
hackathon_judge = get_hackathon_judge()
|
||||
|
||||
evaluation_task = Task(
|
||||
name="project_evaluation",
|
||||
description="""Analyze this hackathon project video demonstration and provide a comprehensive evaluation:
|
||||
|
||||
1. Score the following aspects (0-100):
|
||||
- Innovation and Creativity
|
||||
- Technical Complexity
|
||||
- Presentation Quality
|
||||
- User Experience
|
||||
- Project Completeness
|
||||
|
||||
2. Identify:
|
||||
- Key strengths and standout features
|
||||
- Areas that could be improved
|
||||
- Notable technical implementations
|
||||
- Market potential and scalability
|
||||
|
||||
3. Provide:
|
||||
- Specific recommendations for improvement
|
||||
- Technical suggestions
|
||||
- Potential future enhancements""",
|
||||
expected_output="Detailed project evaluation with scores and feedback",
|
||||
agent=hackathon_judge,
|
||||
output_pydantic=ProjectEvaluation,
|
||||
images=[video_path] # Video input for multimodal analysis
|
||||
)
|
||||
|
||||
# Initialize and run evaluation
|
||||
agents = PraisonAIAgents(
|
||||
agents=[hackathon_judge],
|
||||
tasks=[evaluation_task],
|
||||
process="sequential",
|
||||
verbose=True
|
||||
)
|
||||
|
||||
response = agents.start()
|
||||
|
||||
try:
|
||||
# If response contains task_results, extract the Pydantic model directly
|
||||
if isinstance(response, dict) and 'task_results' in response:
|
||||
task_output = response['task_results'][0]
|
||||
if hasattr(task_output, 'pydantic'):
|
||||
return task_output.pydantic
|
||||
elif hasattr(task_output, 'raw'):
|
||||
# Extract JSON from raw string if it's wrapped in ```json
|
||||
raw_text = task_output.raw
|
||||
if raw_text.startswith('```json'):
|
||||
raw_text = raw_text.split('\n', 1)[1].rsplit('\n', 1)[0]
|
||||
evaluation_data = json.loads(raw_text)
|
||||
else:
|
||||
evaluation_data = json.loads(task_output) if isinstance(task_output, str) else task_output
|
||||
elif isinstance(response, str):
|
||||
evaluation_data = json.loads(response)
|
||||
elif isinstance(response, dict) and 'task_status' in response:
|
||||
content = response['task_status']
|
||||
if isinstance(content, dict):
|
||||
evaluation_data = content
|
||||
else:
|
||||
evaluation_data = json.loads(content) if isinstance(content, str) else content
|
||||
else:
|
||||
evaluation_data = response
|
||||
|
||||
# Create and return ProjectEvaluation instance
|
||||
return ProjectEvaluation(
|
||||
innovation_score=int(evaluation_data.get('innovation_score', 0)),
|
||||
technical_complexity=int(evaluation_data.get('technical_complexity', 0)),
|
||||
presentation_quality=int(evaluation_data.get('presentation_quality', 0)),
|
||||
user_experience=int(evaluation_data.get('user_experience', 0)),
|
||||
completeness=int(evaluation_data.get('completeness', 0)),
|
||||
overall_score=int(evaluation_data.get('overall_score', 0)),
|
||||
key_strengths=evaluation_data.get('key_strengths', []),
|
||||
areas_for_improvement=evaluation_data.get('areas_for_improvement', []),
|
||||
notable_features=evaluation_data.get('notable_features', []),
|
||||
technical_highlights=evaluation_data.get('technical_highlights', []),
|
||||
recommendations=evaluation_data.get('recommendations', []),
|
||||
market_potential=str(evaluation_data.get('market_potential', '')),
|
||||
scalability_assessment=str(evaluation_data.get('scalability_assessment', ''))
|
||||
)
|
||||
except Exception as e:
|
||||
print(f"Debug - Raw response: {response}")
|
||||
print(f"Error processing response: {e}")
|
||||
raise
|
||||
|
||||
# Title and description
|
||||
st.title("🏆 Hackathon Judge Agent")
|
||||
st.markdown("""
|
||||
Upload your hackathon project demonstration video for an AI-powered evaluation.
|
||||
Get comprehensive feedback on various aspects of your project.
|
||||
""")
|
||||
|
||||
# File uploader
|
||||
uploaded_file = st.file_uploader("Choose a video file", type=['mp4', 'avi', 'mov', 'mkv'])
|
||||
|
||||
if uploaded_file:
|
||||
# Create a temporary file to store the video
|
||||
with tempfile.NamedTemporaryFile(delete=False, suffix='.'+uploaded_file.name.split('.')[-1]) as tmp_file:
|
||||
tmp_file.write(uploaded_file.getvalue())
|
||||
video_path = tmp_file.name
|
||||
|
||||
with st.spinner("🤖 AI is evaluating your project..."):
|
||||
try:
|
||||
# Evaluate the project
|
||||
result = evaluate_project(video_path)
|
||||
|
||||
# Display results
|
||||
st.header("Overall Score")
|
||||
st.metric("Overall Score", f"{result.overall_score}/100")
|
||||
|
||||
# Display detailed scores
|
||||
st.header("Detailed Scores")
|
||||
col1, col2, col3 = st.columns(3)
|
||||
with col1:
|
||||
st.metric("Innovation", f"{result.innovation_score}/100")
|
||||
st.metric("Technical Complexity", f"{result.technical_complexity}/100")
|
||||
with col2:
|
||||
st.metric("Presentation", f"{result.presentation_quality}/100")
|
||||
st.metric("User Experience", f"{result.user_experience}/100")
|
||||
with col3:
|
||||
st.metric("Completeness", f"{result.completeness}/100")
|
||||
|
||||
# Display qualitative feedback
|
||||
st.header("Key Strengths")
|
||||
for strength in result.key_strengths:
|
||||
st.write(f"• {strength}")
|
||||
|
||||
st.header("Areas for Improvement")
|
||||
for area in result.areas_for_improvement:
|
||||
st.write(f"• {area}")
|
||||
|
||||
st.header("Technical Highlights")
|
||||
for highlight in result.technical_highlights:
|
||||
st.write(f"• {highlight}")
|
||||
|
||||
st.header("Notable Features")
|
||||
for feature in result.notable_features:
|
||||
st.write(f"• {feature}")
|
||||
|
||||
st.header("Recommendations")
|
||||
for rec in result.recommendations:
|
||||
st.write(f"• {rec}")
|
||||
|
||||
# Market Analysis
|
||||
st.header("Market Analysis")
|
||||
col1, col2 = st.columns(2)
|
||||
with col1:
|
||||
st.subheader("Market Potential")
|
||||
st.write(result.market_potential)
|
||||
with col2:
|
||||
st.subheader("Scalability Assessment")
|
||||
st.write(result.scalability_assessment)
|
||||
|
||||
except Exception as e:
|
||||
st.error(f"Error evaluating the project: {str(e)}")
|
||||
finally:
|
||||
# Clean up the temporary file
|
||||
os.unlink(video_path)
|
||||
else:
|
||||
# Display placeholder content
|
||||
st.info("👆 Upload a video file to get started!")
|
||||
@@ -0,0 +1,47 @@
|
||||
from praisonaiagents import Agent, Tools
|
||||
from praisonaiagents.tools import duckduckgo
|
||||
|
||||
agent = Agent(instructions="You are a Image Analysis Agent", tools=[duckduckgo])
|
||||
agent.start("I want to go London next week, find me a good hotel and flight")
|
||||
|
||||
from praisonaiagents import Agent, Task, PraisonAIAgents
|
||||
|
||||
# Create Image Analysis Agent
|
||||
image_agent = Agent(
|
||||
name="ImageAnalyst",
|
||||
role="Image Analysis Specialist",
|
||||
goal="Analyze images and videos to extract meaningful information",
|
||||
backstory="""You are an expert in computer vision and image analysis.
|
||||
You excel at describing images, detecting objects, and understanding visual content.""",
|
||||
llm="gpt-4o-mini",
|
||||
self_reflect=False
|
||||
)
|
||||
|
||||
# 1. Task with Image URL
|
||||
task1 = Task(
|
||||
name="analyze_landmark",
|
||||
description="Describe this famous landmark and its architectural features.",
|
||||
expected_output="Detailed description of the landmark's architecture and significance",
|
||||
agent=image_agent,
|
||||
images=["https://upload.wikimedia.org/wikipedia/commons/b/bf/Krakow_-_Kosciol_Mariacki.jpg"]
|
||||
)
|
||||
|
||||
# 2. Task with Local Image File
|
||||
task2 = Task(
|
||||
name="analyze_local_image",
|
||||
description="What objects can you see in this image? Describe their arrangement.",
|
||||
expected_output="Detailed description of objects and their spatial relationships",
|
||||
agent=image_agent,
|
||||
images=["image.jpg"]
|
||||
)
|
||||
|
||||
# Create PraisonAIAgents instance
|
||||
agents = PraisonAIAgents(
|
||||
agents=[image_agent],
|
||||
tasks=[task1, task2],
|
||||
process="sequential",
|
||||
verbose=1
|
||||
)
|
||||
|
||||
# Run all tasks
|
||||
agents.start()
|
||||
@@ -0,0 +1,47 @@
|
||||
from praisonaiagents import Agent, Tools
|
||||
from praisonaiagents.tools import duckduckgo
|
||||
|
||||
agent = Agent(instructions="You are a Image Analysis Agent", tools=[duckduckgo])
|
||||
agent.start("I want to go London next week, find me a good hotel and flight")
|
||||
|
||||
from praisonaiagents import Agent, Task, PraisonAIAgents
|
||||
|
||||
# Create Image Analysis Agent
|
||||
image_agent = Agent(
|
||||
name="ImageAnalyst",
|
||||
role="Image Analysis Specialist",
|
||||
goal="Analyze images and videos to extract meaningful information",
|
||||
backstory="""You are an expert in computer vision and image analysis.
|
||||
You excel at describing images, detecting objects, and understanding visual content.""",
|
||||
llm="gpt-4o-mini",
|
||||
self_reflect=False
|
||||
)
|
||||
|
||||
# 1. Task with Image URL
|
||||
task1 = Task(
|
||||
name="analyze_landmark",
|
||||
description="Describe this famous landmark and its architectural features.",
|
||||
expected_output="Detailed description of the landmark's architecture and significance",
|
||||
agent=image_agent,
|
||||
images=["https://upload.wikimedia.org/wikipedia/commons/b/bf/Krakow_-_Kosciol_Mariacki.jpg"]
|
||||
)
|
||||
|
||||
# 2. Task with Local Image File
|
||||
task2 = Task(
|
||||
name="analyze_local_image",
|
||||
description="What objects can you see in this image? Describe their arrangement.",
|
||||
expected_output="Detailed description of objects and their spatial relationships",
|
||||
agent=image_agent,
|
||||
images=["image.jpg"]
|
||||
)
|
||||
|
||||
# Create PraisonAIAgents instance
|
||||
agents = PraisonAIAgents(
|
||||
agents=[image_agent],
|
||||
tasks=[task1, task2],
|
||||
process="sequential",
|
||||
verbose=1
|
||||
)
|
||||
|
||||
# Run all tasks
|
||||
agents.start()
|
||||
@@ -0,0 +1,48 @@
|
||||
from praisonaiagents import Agent, Task, PraisonAIAgents
|
||||
import logging
|
||||
import os
|
||||
|
||||
# Configure logging
|
||||
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
# Define the configuration for the Knowledge instance
|
||||
config = {
|
||||
"vector_store": {
|
||||
"provider": "chroma",
|
||||
"config": {
|
||||
"collection_name": "knowledge_test",
|
||||
"path": ".praison",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# Create an agent with knowledge capabilities
|
||||
knowledge_agent = Agent(
|
||||
name="KnowledgeAgent",
|
||||
role="Information Specialist",
|
||||
goal="Store and retrieve knowledge efficiently",
|
||||
backstory="Expert in managing and utilizing stored knowledge",
|
||||
knowledge=["sample.pdf"],
|
||||
knowledge_config=config,
|
||||
verbose=True
|
||||
)
|
||||
|
||||
# Define a task for the agent
|
||||
knowledge_task = Task(
|
||||
name="knowledge_task",
|
||||
description="Who is Mervin Praison?",
|
||||
expected_output="Answer to the question",
|
||||
agent=knowledge_agent
|
||||
)
|
||||
|
||||
# Create and start the agents
|
||||
agents = PraisonAIAgents(
|
||||
agents=[knowledge_agent],
|
||||
tasks=[knowledge_task],
|
||||
process="sequential",
|
||||
user_id="user1"
|
||||
)
|
||||
|
||||
# Start execution
|
||||
result = agents.start()
|
||||
@@ -0,0 +1,20 @@
|
||||
from praisonaiagents import Agent
|
||||
|
||||
config = {
|
||||
"vector_store": {
|
||||
"provider": "chroma",
|
||||
"config": {
|
||||
"collection_name": "custom_knowledge",
|
||||
"path": ".praison",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
agent = Agent(
|
||||
name="Knowledge Agent",
|
||||
instructions="You answer questions based on the provided knowledge.",
|
||||
knowledge=["large.pdf"],
|
||||
knowledge_config=config
|
||||
)
|
||||
|
||||
agent.start("What is KAG in one line?")
|
||||
@@ -0,0 +1,171 @@
|
||||
import logging
|
||||
from praisonaiagents.knowledge import Knowledge
|
||||
import os
|
||||
# Configure logging
|
||||
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
config = {
|
||||
"vector_store": {
|
||||
"provider": "chroma",
|
||||
"config": {
|
||||
"collection_name": "test",
|
||||
"path": ".praison",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
knowledge = Knowledge(config)
|
||||
|
||||
# Store memories
|
||||
logger.info("Storing memories...")
|
||||
cricket_memory = knowledge.store("Likes to play cricket on weekends", user_id="alice", metadata={"category": "hobbies"})
|
||||
logger.info(f"Stored cricket memory: {cricket_memory}")
|
||||
tennis_memory = knowledge.store("Enjoys playing tennis with friends", user_id="alice", metadata={"category": "hobbies"})
|
||||
logger.info(f"Stored tennis memory: {tennis_memory}")
|
||||
work_memory = knowledge.store("Works as a software engineer", user_id="alice", metadata={"category": "work"})
|
||||
logger.info(f"Stored work memory: {work_memory}")
|
||||
|
||||
print("Stored memories:")
|
||||
print(cricket_memory)
|
||||
print(tennis_memory)
|
||||
print(work_memory)
|
||||
|
||||
# Retrieve all memories for a user
|
||||
logger.info("Retrieving all memories for Alice...")
|
||||
alice_memories = knowledge.get_all(user_id="alice")
|
||||
logger.info(f"Retrieved memories for Alice: {alice_memories}")
|
||||
print("\nAll memories for Alice:")
|
||||
for memory in alice_memories:
|
||||
print(memory)
|
||||
|
||||
# Retrieve a specific memory by ID
|
||||
logger.info(f"Retrieving memory with ID: {cricket_memory['results'][0]['id']}")
|
||||
retrieved_memory = knowledge.get(cricket_memory['results'][0]["id"])
|
||||
logger.info(f"Retrieved memory: {retrieved_memory}")
|
||||
print("\nRetrieved memory:")
|
||||
print(retrieved_memory)
|
||||
|
||||
# Search for memories based on a query
|
||||
query = "What are Alice's hobbies?"
|
||||
logger.info(f"Searching for memories with query: {query}")
|
||||
search_results = knowledge.search(query, user_id="alice")
|
||||
logger.info(f"Search results: {search_results}")
|
||||
print(f"\nSearch results for '{query}':")
|
||||
for memory in search_results:
|
||||
print(memory)
|
||||
|
||||
# Update a memory
|
||||
logger.info(f"Updating memory with ID: {tennis_memory['results'][0]['id']}")
|
||||
updated_memory = knowledge.update(memory_id=tennis_memory['results'][0]["id"], data="Loves playing tennis on weekends")
|
||||
logger.info(f"Updated memory: {updated_memory}")
|
||||
print("\nUpdated memory:")
|
||||
print(updated_memory)
|
||||
|
||||
# Get memory history
|
||||
logger.info(f"Retrieving memory history for ID: {tennis_memory['results'][0]['id']}")
|
||||
memory_history = knowledge.history(memory_id=tennis_memory['results'][0]["id"])
|
||||
logger.info(f"Memory history: {memory_history}")
|
||||
print("\nMemory history:")
|
||||
for entry in memory_history:
|
||||
print(entry)
|
||||
|
||||
# Delete a memory
|
||||
logger.info(f"Deleting memory with ID: {work_memory['results'][0]['id']}")
|
||||
knowledge.delete(memory_id=work_memory['results'][0]["id"])
|
||||
logger.info("Memory deleted")
|
||||
print("\nDeleted memory")
|
||||
|
||||
# Retrieve memories after deletion
|
||||
logger.info("Retrieving memories after deletion...")
|
||||
alice_memories = knowledge.get_all(user_id="alice")
|
||||
logger.info(f"Retrieved memories after deletion: {alice_memories}")
|
||||
print("\nMemories after deletion:")
|
||||
for memory in alice_memories:
|
||||
print(memory)
|
||||
|
||||
# Delete all memories for a user
|
||||
logger.info("Deleting all memories for Alice...")
|
||||
knowledge.delete_all(user_id="alice")
|
||||
logger.info("All memories for Alice deleted")
|
||||
print("\nAll memories for Alice deleted")
|
||||
|
||||
# Retrieve memories after deleting all
|
||||
logger.info("Retrieving memories after deleting all...")
|
||||
alice_memories = knowledge.get_all(user_id="alice")
|
||||
logger.info(f"Retrieved memories after deleting all: {alice_memories}")
|
||||
print("\nMemories after deleting all:")
|
||||
print(alice_memories)
|
||||
|
||||
# Reset all memories
|
||||
logger.info("Resetting all memories...")
|
||||
knowledge.reset()
|
||||
logger.info("All memories reset")
|
||||
print("\nAll memories reset")
|
||||
|
||||
# Test file handling
|
||||
logger.info("Testing file handling...")
|
||||
|
||||
try:
|
||||
# Get absolute path to test files
|
||||
current_dir = os.path.dirname(os.path.abspath(__file__))
|
||||
pdf_file = os.path.join(current_dir, "small.pdf")
|
||||
txt_file = os.path.join(current_dir, "sample.txt")
|
||||
|
||||
# Test text file
|
||||
logger.info(f"Testing text file: {txt_file}")
|
||||
# Read and display content
|
||||
with open(txt_file, 'r') as file:
|
||||
txt_content = file.read()
|
||||
print("\nText file content:")
|
||||
print(txt_content)
|
||||
# Store the text file using add
|
||||
txt_memory = knowledge.add(txt_file, user_id="bob", metadata={"type": "text"})
|
||||
logger.info(f"Stored text file: {txt_memory}")
|
||||
print("\nStored text content:")
|
||||
if txt_memory and 'results' in txt_memory and txt_memory['results']:
|
||||
for mem in txt_memory['results']:
|
||||
print(mem)
|
||||
else:
|
||||
print("No valid memories were stored from the text file")
|
||||
|
||||
# Verify text memories are stored
|
||||
if txt_memory and 'results' in txt_memory and txt_memory['results']:
|
||||
logger.info("Verifying text memories...")
|
||||
for mem in txt_memory['results']:
|
||||
if isinstance(mem, dict) and 'id' in mem:
|
||||
stored = knowledge.get(mem['id'])
|
||||
logger.info(f"Verified text memory: {stored}")
|
||||
else:
|
||||
logger.warning(f"Unexpected memory format: {mem}")
|
||||
else:
|
||||
logger.warning("No valid memories were stored from the text file")
|
||||
|
||||
# Test pdf file
|
||||
logger.info(f"Testing pdf file: {pdf_file}")
|
||||
pdf_memory = knowledge.add(pdf_file, user_id="bob", metadata={"type": "pdf"})
|
||||
logger.info(f"Stored pdf file: {pdf_memory}")
|
||||
print("\nStored pdf content:")
|
||||
if pdf_memory and 'results' in pdf_memory and pdf_memory['results']:
|
||||
for mem in pdf_memory['results']:
|
||||
print(mem)
|
||||
else:
|
||||
print("No valid memories were stored from the PDF file")
|
||||
|
||||
# Verify stored content
|
||||
if pdf_memory and 'results' in pdf_memory and pdf_memory['results']:
|
||||
for memory in pdf_memory['results']:
|
||||
if isinstance(memory, dict) and 'id' in memory:
|
||||
stored_memory = knowledge.get(memory['id'])
|
||||
logger.info(f"Verified stored memory: {stored_memory}")
|
||||
print("\nVerified content:")
|
||||
print(stored_memory)
|
||||
else:
|
||||
logger.warning(f"Unexpected memory format: {memory}")
|
||||
else:
|
||||
logger.warning("No valid memories were stored from the PDF file")
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Error during file handling test: {str(e)}")
|
||||
raise
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
import logging
|
||||
from praisonaiagents.knowledge import Knowledge
|
||||
import os
|
||||
# Configure logging
|
||||
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
knowledge = Knowledge()
|
||||
try:
|
||||
# Get absolute path to test files
|
||||
current_dir = os.path.dirname(os.path.abspath(__file__))
|
||||
pdf_file = os.path.join(current_dir, "large.pdf")
|
||||
|
||||
# Test pdf file
|
||||
logger.info(f"Testing pdf file: {pdf_file}")
|
||||
pdf_memory = knowledge.add(pdf_file, user_id="bob", metadata={"type": "pdf"})
|
||||
logger.info(f"Stored pdf file: {pdf_memory}")
|
||||
print("\nStored pdf content:")
|
||||
if pdf_memory and 'results' in pdf_memory and pdf_memory['results']:
|
||||
for mem in pdf_memory['results']:
|
||||
print(mem)
|
||||
else:
|
||||
print("No valid memories were stored from the PDF file")
|
||||
|
||||
# Verify stored content
|
||||
if pdf_memory and 'results' in pdf_memory and pdf_memory['results']:
|
||||
for memory in pdf_memory['results']:
|
||||
if isinstance(memory, dict) and 'id' in memory:
|
||||
stored_memory = knowledge.get(memory['id'])
|
||||
logger.info(f"Verified stored memory: {stored_memory}")
|
||||
print("\nVerified content:")
|
||||
print(stored_memory)
|
||||
else:
|
||||
logger.warning(f"Unexpected memory format: {memory}")
|
||||
else:
|
||||
logger.warning("No valid memories were stored from the PDF file")
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Error during file handling test: {str(e)}")
|
||||
raise
|
||||
Binary file not shown.
Whitespace-only changes.
@@ -0,0 +1,4 @@
|
||||
from praisonaiagents import Agent
|
||||
|
||||
agent = Agent(instructions="You are a Markdown Agent, output in markdown format")
|
||||
agent.start("Write a blog post about AI")
|
||||
@@ -0,0 +1,5 @@
|
||||
from markitdown import MarkItDown
|
||||
|
||||
md = MarkItDown()
|
||||
result = md.convert("sample.txt")
|
||||
print(result.text_content)
|
||||
@@ -0,0 +1,183 @@
|
||||
from praisonaiagents import Agent, Task, PraisonAIAgents
|
||||
import logging
|
||||
import os
|
||||
|
||||
def main():
|
||||
# Initialize memory config
|
||||
memory_config = {
|
||||
"provider": "rag",
|
||||
"use_embedding": True,
|
||||
"storage": {
|
||||
"type": "sqlite",
|
||||
"path": "./.praison/memory.db"
|
||||
},
|
||||
"rag_db_path": "./.praison/chroma_db"
|
||||
}
|
||||
|
||||
# Test facts
|
||||
fact1 = "The capital city of Jujuha is Hahanu and its population is 102300"
|
||||
fact2 = "Three main ingredients in a classic proloder are eggs, sugar, and flour"
|
||||
fact3 = "The year the first Josinga was released is 2007"
|
||||
|
||||
# # Check if database exists
|
||||
# if os.path.exists("./memory.db"):
|
||||
# logger.info("Found existing memory database")
|
||||
# else:
|
||||
# logger.info("Creating new memory database")
|
||||
|
||||
# Create task config (without memory config since it's moved to PraisonAIAgents)
|
||||
task_config = {}
|
||||
|
||||
# Create agents with different roles
|
||||
researcher = Agent(
|
||||
role="Research Analyst",
|
||||
goal="Research and document key information about topics",
|
||||
backstory="Expert at analyzing and storing information in memory",
|
||||
llm="gpt-4o-mini"
|
||||
)
|
||||
|
||||
retriever = Agent(
|
||||
role="Information Retriever",
|
||||
goal="Retrieve and verify stored information from memory",
|
||||
backstory="Specialist in searching and validating information from memory",
|
||||
llm="gpt-4o-mini"
|
||||
)
|
||||
|
||||
# Task 1: Process the facts
|
||||
store_task = Task(
|
||||
description=f"""
|
||||
Process and analyze this information:
|
||||
1. {fact1}
|
||||
2. {fact2}
|
||||
3. {fact3}
|
||||
|
||||
Provide a clear summary of each fact.
|
||||
""",
|
||||
expected_output="""
|
||||
Clear statements summarizing each fact.
|
||||
Example format:
|
||||
1. [Summary of fact 1]
|
||||
2. [Summary of fact 2]
|
||||
3. [Summary of fact 3]
|
||||
""",
|
||||
agent=researcher
|
||||
)
|
||||
|
||||
# Task 2: Write essay about AI
|
||||
verify_task = Task(
|
||||
description="""
|
||||
write few points about AI
|
||||
""",
|
||||
expected_output="Points about AI",
|
||||
agent=retriever
|
||||
)
|
||||
|
||||
# Task 3: Query memory
|
||||
query_task = Task(
|
||||
description="""
|
||||
Using ONLY information found in memory:
|
||||
1. What is stored in memory about Hahanu?
|
||||
2. What ingredients for proloder are recorded in memory?
|
||||
3. What year is stored in memory for the Josinga release?
|
||||
|
||||
For each answer, cite the memory record you found.
|
||||
""",
|
||||
expected_output="Answers based solely on memory records with citations",
|
||||
agent=retriever
|
||||
)
|
||||
|
||||
# Task 4: Query both short-term and long-term memory
|
||||
query_both_task = Task(
|
||||
description="""
|
||||
Using ONLY information found in memory:
|
||||
1. What is stored in both short-term and long-term memory about Jujuha?
|
||||
2. What ingredients for proloder are recorded in both short-term and long-term memory?
|
||||
3. What year is stored in both short-term and long-term memory for the Josinga release?
|
||||
|
||||
For each answer, cite the memory record you found.
|
||||
""",
|
||||
expected_output="Answers based solely on memory records with citations",
|
||||
agent=retriever
|
||||
)
|
||||
|
||||
# Initialize PraisonAIAgents with memory configuration
|
||||
agents = PraisonAIAgents(
|
||||
agents=[researcher, retriever],
|
||||
tasks=[store_task, verify_task, query_task, query_both_task],
|
||||
verbose=True, # Use same verbose level as memory
|
||||
memory=True,
|
||||
embedder={
|
||||
"provider": "openai",
|
||||
"config": {
|
||||
"model": "text-embedding-3-small"
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
# agents = PraisonAIAgents(
|
||||
# agents=[researcher, retriever],
|
||||
# tasks=[store_task, verify_task, query_task, query_both_task],
|
||||
# verbose=True, # Use same verbose level as memory
|
||||
# memory=True
|
||||
# )
|
||||
|
||||
# Execute tasks
|
||||
print("\nExecuting Memory Test Tasks...")
|
||||
print("-" * 50)
|
||||
agents.start()
|
||||
|
||||
# Use shared memory for final checks
|
||||
memory = agents.shared_memory
|
||||
|
||||
# Test memory retrieval with different quality thresholds
|
||||
if memory:
|
||||
print("\nFinal Memory Check:")
|
||||
print("-" * 50)
|
||||
|
||||
queries = ["Jujuha", "proloder", "Josinga"]
|
||||
for query in queries:
|
||||
print(f"\nSearching memory for: {query}")
|
||||
|
||||
# Search in both short-term and long-term memory
|
||||
print("\nShort-term memory results:")
|
||||
stm_results = memory.search_short_term(query)
|
||||
if stm_results:
|
||||
for item in stm_results:
|
||||
print(f"Content: {item.get('content', '')[:200]}")
|
||||
if 'meta' in item:
|
||||
print(f"Metadata: {item['meta']}")
|
||||
print("-" * 20)
|
||||
else:
|
||||
print("No results found in short-term memory")
|
||||
|
||||
print("\nLong-term memory results:")
|
||||
ltm_results = memory.search_long_term(query)
|
||||
if ltm_results:
|
||||
for item in ltm_results:
|
||||
print(f"Content: {item.get('text', '')[:200]}")
|
||||
if 'metadata' in item:
|
||||
print(f"Metadata: {item['metadata']}")
|
||||
print("-" * 20)
|
||||
else:
|
||||
print("No results found in long-term memory")
|
||||
|
||||
# Also check ChromaDB if using RAG
|
||||
if memory.use_rag and hasattr(memory, "chroma_col"):
|
||||
print("\nChromaDB results:")
|
||||
try:
|
||||
all_items = memory.chroma_col.get()
|
||||
print(f"Found {len(all_items['ids'])} items in ChromaDB")
|
||||
for i in range(len(all_items['ids'])):
|
||||
print(f"ID: {all_items['ids'][i]}")
|
||||
print(f"Content: {all_items['documents'][i][:200]}")
|
||||
print(f"Metadata: {all_items['metadatas'][i]}")
|
||||
print("-" * 20)
|
||||
except Exception as e:
|
||||
print(f"Error querying ChromaDB: {e}")
|
||||
|
||||
print("-" * 30)
|
||||
else:
|
||||
print("\nNo memory available for final checks")
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,63 @@
|
||||
from praisonaiagents.agents.agents import Agent, Task, PraisonAIAgents
|
||||
from praisonaiagents.tools import duckduckgo
|
||||
|
||||
# Test facts
|
||||
fact1 = "The capital city of Jujuha is Hahanu and its population is 102300"
|
||||
fact2 = "Three main ingredients in a classic proloder are eggs, sugar, and flour"
|
||||
fact3 = "The year the first Josinga was released is 2007"
|
||||
|
||||
fact_agent = Agent(
|
||||
name="Fact Agent",
|
||||
instructions="You are a fact agent, you store and retrieve facts in memory",
|
||||
llm="gpt-4o-mini"
|
||||
)
|
||||
|
||||
research_agent = Agent(
|
||||
name="Research Agent",
|
||||
instructions="You are a research analyst, you research and document key points about topics",
|
||||
llm="gpt-4o-mini"
|
||||
)
|
||||
|
||||
blog_agent = Agent(
|
||||
name="Blog Agent",
|
||||
instructions="You are a blog writer, you write a blog post about the research",
|
||||
llm="gpt-4o-mini"
|
||||
)
|
||||
|
||||
fact_task = Task(
|
||||
description="Store the following facts in memory: " + fact1 + ", " + fact2 + ", " + fact3,
|
||||
agent=fact_agent
|
||||
)
|
||||
|
||||
research_task = Task(
|
||||
description="Research and document 2 key points about AI",
|
||||
agent=research_agent
|
||||
)
|
||||
|
||||
research_task2 = Task(
|
||||
description="Research and document 2 key points about AI in healthcare",
|
||||
agent=research_agent
|
||||
)
|
||||
|
||||
research_task3 = Task(
|
||||
description="Research and document 2 key points about AI in education",
|
||||
agent=research_agent
|
||||
)
|
||||
|
||||
research_task4 = Task(
|
||||
description="Research and document 2 key points about AI in finance",
|
||||
agent=research_agent
|
||||
)
|
||||
|
||||
blog_task = Task(
|
||||
description="Write a blog post about Jujuha",
|
||||
agent=blog_agent
|
||||
)
|
||||
|
||||
agents = PraisonAIAgents(
|
||||
agents=[fact_agent, research_agent, blog_agent],
|
||||
tasks=[fact_task, research_task, research_task2, research_task3, research_task4, blog_task],
|
||||
memory=True
|
||||
)
|
||||
|
||||
agents.start()
|
||||
@@ -51,9 +51,4 @@ agents = PraisonAIAgents(
|
||||
)
|
||||
|
||||
# Run all tasks
|
||||
result = agents.start()
|
||||
|
||||
# Print results
|
||||
for task_id, task_result in result["task_results"].items():
|
||||
print(f"\nTask {task_id} Result:")
|
||||
print(task_result.raw)
|
||||
agents.start()
|
||||
@@ -0,0 +1,110 @@
|
||||
from praisonaiagents import Agent, Task, PraisonAIAgents
|
||||
import time
|
||||
|
||||
def get_time_check():
|
||||
current_time = int(time.time())
|
||||
if current_time % 3 == 0:
|
||||
result = 1
|
||||
elif current_time % 3 == 1:
|
||||
result = 2
|
||||
else:
|
||||
result = 3
|
||||
print(f"Time: {current_time}, Result: {result}")
|
||||
return result
|
||||
|
||||
# Create orchestrator and worker agents
|
||||
router = Agent(
|
||||
name="Router",
|
||||
role="Task router",
|
||||
goal="Distribute tasks to based on response from get_time_check",
|
||||
tools=[get_time_check]
|
||||
)
|
||||
|
||||
worker1 = Agent(
|
||||
name="Worker 1",
|
||||
role="Specialized worker",
|
||||
goal="Handle specific subtask type 1",
|
||||
)
|
||||
|
||||
worker2 = Agent(
|
||||
name="Worker 2",
|
||||
role="Specialized worker",
|
||||
goal="Handle specific subtask type 2",
|
||||
)
|
||||
|
||||
worker3 = Agent(
|
||||
name="Worker 3",
|
||||
role="Specialized worker",
|
||||
goal="Handle specific subtask type 3",
|
||||
)
|
||||
|
||||
synthesizer = Agent(
|
||||
name="Synthesizer",
|
||||
role="Result synthesizer",
|
||||
goal="Combine and synthesize worker outputs",
|
||||
)
|
||||
|
||||
# Create orchestrated workflow tasks
|
||||
router_task = Task(
|
||||
name="route_task",
|
||||
description="Analyze input from get_time_check and route to appropriate workers",
|
||||
expected_output="Task routing decision, 1 , 2 or 3",
|
||||
agent=router,
|
||||
is_start=True,
|
||||
task_type="decision",
|
||||
next_tasks=["worker1_task", "worker2_task", "worker3_task"],
|
||||
condition={
|
||||
"1": ["worker1_task"],
|
||||
"2": ["worker2_task"],
|
||||
"3": ["worker3_task"]
|
||||
}
|
||||
)
|
||||
|
||||
worker1_task = Task(
|
||||
name="worker1_task",
|
||||
description="Process type 1 operation",
|
||||
expected_output="Worker 1 result",
|
||||
agent=worker1,
|
||||
next_tasks=["synthesize_task"]
|
||||
)
|
||||
|
||||
worker2_task = Task(
|
||||
name="worker2_task",
|
||||
description="Process type 2 operation",
|
||||
expected_output="Worker 2 result",
|
||||
agent=worker2,
|
||||
next_tasks=["synthesize_task"]
|
||||
)
|
||||
|
||||
worker3_task = Task(
|
||||
name="worker3_task",
|
||||
description="Process type 3 operation",
|
||||
expected_output="Worker 3 result",
|
||||
agent=worker3,
|
||||
next_tasks=["synthesize_task"]
|
||||
)
|
||||
|
||||
synthesize_task = Task(
|
||||
name="synthesize_task",
|
||||
description="Synthesize worker results into final output",
|
||||
expected_output="Final synthesized result",
|
||||
agent=synthesizer,
|
||||
context=[worker1_task, worker2_task, worker3_task]
|
||||
)
|
||||
|
||||
# Create workflow manager
|
||||
workflow = PraisonAIAgents(
|
||||
agents=[router, worker1, worker2, worker3, synthesizer],
|
||||
tasks=[router_task, worker1_task, worker2_task, worker3_task, synthesize_task],
|
||||
process="workflow",
|
||||
verbose=True
|
||||
)
|
||||
|
||||
# Run orchestrated workflow
|
||||
results = workflow.start()
|
||||
|
||||
# Print results
|
||||
print("\nOrchestrator-Workers Results:")
|
||||
for task_id, result in results["task_results"].items():
|
||||
if result:
|
||||
print(f"Task {task_id}: {result.raw}")
|
||||
@@ -0,0 +1,95 @@
|
||||
from praisonaiagents import Agent, Task, PraisonAIAgents
|
||||
from datetime import datetime
|
||||
import asyncio
|
||||
|
||||
def process_time():
|
||||
"""Simulate processing"""
|
||||
current_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
||||
print(f"Processing at: {current_time}")
|
||||
return f"Processed at {current_time}"
|
||||
|
||||
# Create parallel processing agents
|
||||
agent1 = Agent(
|
||||
name="Processor 1",
|
||||
role="Time collector",
|
||||
goal="Get the time and return it",
|
||||
tools=[process_time]
|
||||
)
|
||||
|
||||
agent2 = Agent(
|
||||
name="Processor 2",
|
||||
role="Time collector",
|
||||
goal="Get the time and return it",
|
||||
tools=[process_time]
|
||||
)
|
||||
|
||||
agent3 = Agent(
|
||||
name="Processor 3",
|
||||
role="Time collector",
|
||||
goal="Get the time and return it",
|
||||
tools=[process_time]
|
||||
)
|
||||
|
||||
aggregator = Agent(
|
||||
name="Aggregator",
|
||||
role="Result aggregator",
|
||||
goal="Collect all the processed time from all tasks"
|
||||
)
|
||||
|
||||
# Create parallel tasks with memory disabled
|
||||
task1 = Task(
|
||||
name="process_1",
|
||||
description="Use process_time tool to get the time",
|
||||
expected_output="processed time",
|
||||
agent=agent1,
|
||||
is_start=True,
|
||||
async_execution=True
|
||||
)
|
||||
|
||||
task2 = Task(
|
||||
name="process_2",
|
||||
description="Use process_time tool to get the time",
|
||||
expected_output="processed time",
|
||||
agent=agent2,
|
||||
is_start=True,
|
||||
async_execution=True
|
||||
)
|
||||
|
||||
task3 = Task(
|
||||
name="process_3",
|
||||
description="Use process_time tool to get the time",
|
||||
expected_output="processed time",
|
||||
agent=agent3,
|
||||
is_start=True,
|
||||
async_execution=True
|
||||
)
|
||||
|
||||
aggregate_task = Task(
|
||||
name="aggregate",
|
||||
description="Collect all the processed time from all tasks",
|
||||
expected_output="Output all the processed time from all tasks and just the time",
|
||||
agent=aggregator,
|
||||
context=[task1, task2, task3]
|
||||
)
|
||||
|
||||
async def main():
|
||||
|
||||
# Create workflow manager
|
||||
workflow = PraisonAIAgents(
|
||||
agents=[agent1, agent2, agent3, aggregator],
|
||||
tasks=[task1, task2, task3, aggregate_task],
|
||||
process="workflow"
|
||||
)
|
||||
|
||||
# Run parallel workflow
|
||||
results = await workflow.astart()
|
||||
|
||||
# Print results
|
||||
print("\nParallel Processing Results:")
|
||||
for task_id, result in results["task_results"].items():
|
||||
if result:
|
||||
print(f"Task {task_id}: {result.raw}")
|
||||
|
||||
# Run the async main function
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
@@ -0,0 +1,41 @@
|
||||
from praisonaiagents import Agent, Task, PraisonAIAgents
|
||||
|
||||
# Create PDF Analysis Agent
|
||||
pdf_agent = Agent(
|
||||
name="PDFAnalyst",
|
||||
role="PDF Document Specialist",
|
||||
goal="Analyze PDF documents to extract meaningful information",
|
||||
backstory="""You are an expert in PDF document analysis and text extraction.
|
||||
You excel at understanding document structure, extracting content, and analyzing textual information.""",
|
||||
llm="gpt-4o-mini",
|
||||
self_reflect=False
|
||||
)
|
||||
|
||||
# 1. Task with PDF URL
|
||||
task1 = Task(
|
||||
name="analyze_pdf_url",
|
||||
description="Extract and analyze content from this PDF document.",
|
||||
expected_output="Detailed analysis of the PDF content and structure",
|
||||
agent=pdf_agent,
|
||||
input=["https://example.com/document.pdf"]
|
||||
)
|
||||
|
||||
# 2. Task with Local PDF File
|
||||
task2 = Task(
|
||||
name="analyze_local_pdf",
|
||||
description="What information can you extract from this PDF? Analyze its content.",
|
||||
expected_output="Detailed analysis of the PDF content and structure",
|
||||
agent=pdf_agent,
|
||||
input=["document.pdf"]
|
||||
)
|
||||
|
||||
# Create PraisonAIAgents instance
|
||||
agents = PraisonAIAgents(
|
||||
agents=[pdf_agent],
|
||||
tasks=[task1, task2],
|
||||
process="sequential",
|
||||
verbose=1
|
||||
)
|
||||
|
||||
# Run all tasks
|
||||
agents.start()
|
||||
@@ -0,0 +1,5 @@
|
||||
from praisonaiagents import Agent, Tools
|
||||
from praisonaiagents.tools import duckduckgo
|
||||
|
||||
agent = Agent(instructions="You are a Planning Agent", tools=[duckduckgo])
|
||||
agent.start("I want to go London next week, find me a good hotel and flight")
|
||||
@@ -7,6 +7,9 @@ from .agents.agents import PraisonAIAgents
|
||||
from .task.task import Task
|
||||
from .tools.tools import Tools
|
||||
from .agents.autoagents import AutoAgents
|
||||
from .knowledge.knowledge import Knowledge
|
||||
from .knowledge.chunking import Chunking
|
||||
from .memory.memory import Memory
|
||||
from .main import (
|
||||
TaskOutput,
|
||||
ReflectionOutput,
|
||||
@@ -35,6 +38,7 @@ __all__ = [
|
||||
'TaskOutput',
|
||||
'ReflectionOutput',
|
||||
'AutoAgents',
|
||||
'Memory',
|
||||
'display_interaction',
|
||||
'display_self_reflection',
|
||||
'display_instruction',
|
||||
@@ -46,4 +50,6 @@ __all__ = [
|
||||
'register_display_callback',
|
||||
'sync_display_callbacks',
|
||||
'async_display_callbacks',
|
||||
'Knowledge',
|
||||
'Chunking'
|
||||
]
|
||||
@@ -16,9 +16,11 @@ from ..main import (
|
||||
display_self_reflection,
|
||||
ReflectionOutput,
|
||||
client,
|
||||
error_logs
|
||||
error_logs,
|
||||
adisplay_instruction
|
||||
)
|
||||
import inspect
|
||||
import uuid
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from ..task.task import Task
|
||||
@@ -69,10 +71,15 @@ class Agent:
|
||||
|
||||
import inspect
|
||||
# Langchain tools
|
||||
if inspect.isclass(func) and hasattr(func, 'run'):
|
||||
if inspect.isclass(func) and hasattr(func, 'run') and not hasattr(func, '_run'):
|
||||
original_func = func
|
||||
func = func.run
|
||||
function_name = original_func.__name__
|
||||
# CrewAI tools
|
||||
elif inspect.isclass(func) and hasattr(func, '_run'):
|
||||
original_func = func
|
||||
func = func._run
|
||||
function_name = original_func.__name__
|
||||
|
||||
sig = inspect.signature(func)
|
||||
logging.debug(f"Function signature: {sig}")
|
||||
@@ -162,7 +169,7 @@ class Agent:
|
||||
max_iter: int = 20,
|
||||
max_rpm: Optional[int] = None,
|
||||
max_execution_time: Optional[int] = None,
|
||||
memory: bool = True,
|
||||
memory: Optional[Any] = None,
|
||||
verbose: bool = True,
|
||||
allow_delegation: bool = False,
|
||||
step_callback: Optional[Any] = None,
|
||||
@@ -175,13 +182,15 @@ class Agent:
|
||||
respect_context_window: bool = True,
|
||||
code_execution_mode: Literal["safe", "unsafe"] = "safe",
|
||||
embedder_config: Optional[Dict[str, Any]] = None,
|
||||
knowledge_sources: Optional[List[Any]] = None,
|
||||
knowledge: Optional[List[str]] = None,
|
||||
knowledge_config: Optional[Dict[str, Any]] = None,
|
||||
use_system_prompt: Optional[bool] = True,
|
||||
markdown: bool = True,
|
||||
self_reflect: Optional[bool] = None,
|
||||
self_reflect: bool = False,
|
||||
max_reflect: int = 3,
|
||||
min_reflect: int = 1,
|
||||
reflect_llm: Optional[str] = None
|
||||
reflect_llm: Optional[str] = None,
|
||||
user_id: Optional[str] = None
|
||||
):
|
||||
# Handle backward compatibility for required fields
|
||||
if all(x is None for x in [name, role, goal, backstory, instructions]):
|
||||
@@ -225,7 +234,7 @@ class Agent:
|
||||
self.respect_context_window = respect_context_window
|
||||
self.code_execution_mode = code_execution_mode
|
||||
self.embedder_config = embedder_config
|
||||
self.knowledge_sources = knowledge_sources
|
||||
self.knowledge = knowledge
|
||||
self.use_system_prompt = use_system_prompt
|
||||
self.chat_history = []
|
||||
self.markdown = markdown
|
||||
@@ -241,6 +250,40 @@ Your Role: {self.role}\n
|
||||
Your Goal: {self.goal}
|
||||
"""
|
||||
|
||||
# Generate unique IDs
|
||||
self.agent_id = str(uuid.uuid4())
|
||||
|
||||
# Store user_id
|
||||
self.user_id = user_id
|
||||
|
||||
# Check if knowledge parameter has any values
|
||||
if not knowledge:
|
||||
self.knowledge = None
|
||||
else:
|
||||
# Initialize Knowledge with provided or default config
|
||||
from praisonaiagents.knowledge import Knowledge
|
||||
self.knowledge = Knowledge(knowledge_config or None)
|
||||
|
||||
# Handle knowledge
|
||||
if knowledge:
|
||||
for source in knowledge:
|
||||
self._process_knowledge(source)
|
||||
|
||||
def _process_knowledge(self, knowledge_item):
|
||||
"""Process and store knowledge from a file path, URL, or string."""
|
||||
try:
|
||||
if os.path.exists(knowledge_item):
|
||||
# It's a file path
|
||||
self.knowledge.add(knowledge_item, user_id=self.user_id, agent_id=self.agent_id)
|
||||
elif knowledge_item.startswith("http://") or knowledge_item.startswith("https://"):
|
||||
# It's a URL
|
||||
pass
|
||||
else:
|
||||
# It's a string content
|
||||
self.knowledge.store(knowledge_item, user_id=self.user_id, agent_id=self.agent_id)
|
||||
except Exception as e:
|
||||
logging.error(f"Error processing knowledge item: {knowledge_item}, error: {e}")
|
||||
|
||||
def generate_task(self) -> 'Task':
|
||||
"""Generate a Task object from the agent's instructions"""
|
||||
from ..task.task import Task
|
||||
@@ -279,14 +322,22 @@ Your Goal: {self.goal}
|
||||
|
||||
if func:
|
||||
try:
|
||||
# If it's a class with run method, instantiate and call run
|
||||
if inspect.isclass(func) and hasattr(func, 'run'):
|
||||
# Langchain: If it's a class with run but not _run, instantiate and call run
|
||||
if inspect.isclass(func) and hasattr(func, 'run') and not hasattr(func, '_run'):
|
||||
instance = func()
|
||||
# Extract only the parameters that run() expects
|
||||
run_params = {k: v for k, v in arguments.items()
|
||||
if k in inspect.signature(instance.run).parameters
|
||||
and k != 'self'}
|
||||
if k in inspect.signature(instance.run).parameters
|
||||
and k != 'self'}
|
||||
return instance.run(**run_params)
|
||||
|
||||
# CrewAI: If it's a class with an _run method, instantiate and call _run
|
||||
elif inspect.isclass(func) and hasattr(func, '_run'):
|
||||
instance = func()
|
||||
run_params = {k: v for k, v in arguments.items()
|
||||
if k in inspect.signature(instance._run).parameters
|
||||
and k != 'self'}
|
||||
return instance._run(**run_params)
|
||||
|
||||
# Otherwise treat as regular function
|
||||
elif callable(func):
|
||||
return func(**arguments)
|
||||
@@ -381,7 +432,7 @@ Your Goal: {self.goal}
|
||||
display_generating("", start_time),
|
||||
console=self.console,
|
||||
refresh_per_second=4,
|
||||
transient=False, # Changed to False to preserve output
|
||||
transient=True, # Changed to False to preserve output
|
||||
vertical_overflow="ellipsis",
|
||||
auto_refresh=True
|
||||
) as live:
|
||||
@@ -417,15 +468,30 @@ Your Goal: {self.goal}
|
||||
return None
|
||||
|
||||
def chat(self, prompt, temperature=0.2, tools=None, output_json=None, output_pydantic=None):
|
||||
# Search for existing knowledge if any knowledge is provided
|
||||
if self.knowledge:
|
||||
search_results = self.knowledge.search(prompt, agent_id=self.agent_id)
|
||||
if search_results:
|
||||
# Check if search_results is a list of dictionaries or strings
|
||||
if isinstance(search_results, dict) and 'results' in search_results:
|
||||
# Extract memory content from the results
|
||||
knowledge_content = "\n".join([result['memory'] for result in search_results['results']])
|
||||
else:
|
||||
# If search_results is a list of strings, join them directly
|
||||
knowledge_content = "\n".join(search_results)
|
||||
|
||||
# Append found knowledge to the prompt
|
||||
prompt = f"{prompt}\n\nKnowledge: {knowledge_content}"
|
||||
|
||||
if self.use_system_prompt:
|
||||
system_prompt = f"""{self.backstory}\n
|
||||
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: {output_json.schema_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: {output_pydantic.schema_json()}"
|
||||
system_prompt += f"\nReturn ONLY a JSON object that matches this Pydantic model: {json.dumps(output_pydantic.model_json_schema())}"
|
||||
else:
|
||||
system_prompt = None
|
||||
|
||||
@@ -466,7 +532,15 @@ Your Goal: {self.goal}
|
||||
display_text = next((item["text"] for item in prompt if item["type"] == "text"), "")
|
||||
|
||||
if display_text and str(display_text).strip():
|
||||
display_instruction(f"Agent {self.name} is processing prompt: {display_text}", console=self.console)
|
||||
# Pass agent information to display_instruction
|
||||
agent_tools = [t.__name__ if hasattr(t, '__name__') else str(t) for t in self.tools]
|
||||
display_instruction(
|
||||
f"Agent {self.name} is processing prompt: {display_text}",
|
||||
console=self.console,
|
||||
agent_name=self.name,
|
||||
agent_role=self.role,
|
||||
agent_tools=agent_tools
|
||||
)
|
||||
|
||||
response = self._chat_completion(messages, temperature=temperature, tools=tools if tools else None)
|
||||
if not response:
|
||||
@@ -525,7 +599,7 @@ Your Goal: {self.goal}
|
||||
self.chat_history.append({"role": "user", "content": original_prompt})
|
||||
self.chat_history.append({"role": "assistant", "content": response_text})
|
||||
if self.verbose:
|
||||
logging.info(f"Agent {self.name} final response: {response_text}")
|
||||
logging.debug(f"Agent {self.name} final response: {response_text}")
|
||||
display_interaction(original_prompt, response_text, markdown=self.markdown, generation_time=time.time() - start_time, console=self.console)
|
||||
return response_text
|
||||
|
||||
@@ -607,9 +681,9 @@ Output MUST be JSON with 'reflection' and 'satisfactory'.
|
||||
# Build system prompt
|
||||
system_prompt = self.system_prompt
|
||||
if output_json:
|
||||
system_prompt += f"\nReturn ONLY a JSON object that matches this Pydantic model: {output_json.schema_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: {output_pydantic.schema_json()}"
|
||||
system_prompt += f"\nReturn ONLY a JSON object that matches this Pydantic model: {json.dumps(output_pydantic.model_json_schema())}"
|
||||
|
||||
# Build messages
|
||||
if isinstance(prompt, str):
|
||||
@@ -630,6 +704,22 @@ Output MUST be JSON with 'reflection' and 'satisfactory'.
|
||||
item["text"] += "\nReturn ONLY a valid JSON object. No other text or explanation."
|
||||
break
|
||||
|
||||
# Display instruction with agent info if verbose
|
||||
if self.verbose:
|
||||
display_text = prompt
|
||||
if isinstance(prompt, list):
|
||||
display_text = next((item["text"] for item in prompt if item["type"] == "text"), "")
|
||||
|
||||
if display_text and str(display_text).strip():
|
||||
agent_tools = [t.__name__ if hasattr(t, '__name__') else str(t) for t in self.tools]
|
||||
await adisplay_instruction(
|
||||
f"Agent {self.name} is processing prompt: {display_text}",
|
||||
console=self.console,
|
||||
agent_name=self.name,
|
||||
agent_role=self.role,
|
||||
agent_tools=agent_tools
|
||||
)
|
||||
|
||||
# Format tools if provided
|
||||
formatted_tools = []
|
||||
if tools:
|
||||
@@ -737,4 +827,8 @@ Output MUST be JSON with 'reflection' and 'satisfactory'.
|
||||
|
||||
def run(self):
|
||||
"""Alias for start() method"""
|
||||
return self.start()
|
||||
return self.start()
|
||||
|
||||
def start(self, prompt: str, **kwargs):
|
||||
"""Start the agent with a prompt. This is a convenience method that wraps chat()."""
|
||||
return self.chat(prompt, **kwargs)
|
||||
@@ -12,6 +12,10 @@ from ..agent.agent import Agent
|
||||
from ..task.task import Task
|
||||
from ..process.process import Process, LoopItems
|
||||
import asyncio
|
||||
import uuid
|
||||
|
||||
# Set up logger
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
def encode_file_to_base64(file_path: str) -> str:
|
||||
"""Base64-encode a file."""
|
||||
@@ -41,10 +45,18 @@ def process_video(video_path: str, seconds_per_frame=2):
|
||||
return base64_frames
|
||||
|
||||
class PraisonAIAgents:
|
||||
def __init__(self, agents, tasks=None, verbose=0, completion_checker=None, max_retries=5, process="sequential", manager_llm=None):
|
||||
def __init__(self, agents, tasks=None, verbose=0, completion_checker=None, max_retries=5, process="sequential", manager_llm=None, memory=False, memory_config=None, embedder=None, user_id=None, max_iter=10):
|
||||
if not agents:
|
||||
raise ValueError("At least one agent must be provided")
|
||||
|
||||
|
||||
self.run_id = str(uuid.uuid4()) # Auto-generate run_id
|
||||
self.user_id = user_id # Optional user_id
|
||||
self.max_iter = max_iter # Add max_iter parameter
|
||||
|
||||
# Pass user_id to each agent
|
||||
for agent in agents:
|
||||
agent.user_id = self.user_id
|
||||
|
||||
self.agents = agents
|
||||
self.tasks = {}
|
||||
if max_retries < 3:
|
||||
@@ -57,8 +69,21 @@ class PraisonAIAgents:
|
||||
|
||||
# Check for manager_llm in environment variable if not provided
|
||||
self.manager_llm = manager_llm or os.getenv('OPENAI_MODEL_NAME', 'gpt-4o')
|
||||
|
||||
# Set logger level based on verbose
|
||||
if verbose >= 5:
|
||||
logger.setLevel(logging.INFO)
|
||||
else:
|
||||
logger.setLevel(logging.WARNING)
|
||||
|
||||
# Also set third-party loggers to WARNING
|
||||
logging.getLogger('chromadb').setLevel(logging.WARNING)
|
||||
logging.getLogger('openai').setLevel(logging.WARNING)
|
||||
logging.getLogger('httpx').setLevel(logging.WARNING)
|
||||
logging.getLogger('httpcore').setLevel(logging.WARNING)
|
||||
|
||||
if self.verbose:
|
||||
logging.info(f"Using model {self.manager_llm} for manager")
|
||||
logger.info(f"Using model {self.manager_llm} for manager")
|
||||
|
||||
# If no tasks provided, generate them from agents
|
||||
if tasks is None:
|
||||
@@ -66,12 +91,12 @@ class PraisonAIAgents:
|
||||
for agent in self.agents:
|
||||
task = agent.generate_task()
|
||||
tasks.append(task)
|
||||
logging.info(f"Auto-generated {len(tasks)} tasks from agents")
|
||||
logger.info(f"Auto-generated {len(tasks)} tasks from agents")
|
||||
else:
|
||||
# Validate tasks for backward compatibility
|
||||
if not tasks:
|
||||
raise ValueError("If tasks are provided, at least one task must be present")
|
||||
logging.info(f"Using {len(tasks)} provided tasks")
|
||||
logger.info(f"Using {len(tasks)} provided tasks")
|
||||
|
||||
# Add tasks and set their status
|
||||
for task in tasks:
|
||||
@@ -87,9 +112,65 @@ class PraisonAIAgents:
|
||||
if tasks[i + 1].context is None:
|
||||
tasks[i + 1].context = []
|
||||
tasks[i + 1].context.append(tasks[i])
|
||||
logging.info("Set up sequential flow with automatic context passing")
|
||||
logger.info("Set up sequential flow with automatic context passing")
|
||||
|
||||
self._state = {} # Add state storage at PraisonAIAgents level
|
||||
|
||||
# Initialize memory system
|
||||
self.shared_memory = None
|
||||
if memory:
|
||||
try:
|
||||
from ..memory.memory import Memory
|
||||
|
||||
# Get memory config from parameter or first task
|
||||
mem_cfg = memory_config
|
||||
if not mem_cfg:
|
||||
mem_cfg = next((t.config.get('memory_config') for t in tasks if hasattr(t, 'config') and t.config), None)
|
||||
|
||||
# Set default memory config if none provided
|
||||
if not mem_cfg:
|
||||
mem_cfg = {
|
||||
"provider": "rag",
|
||||
"use_embedding": True,
|
||||
"storage": {
|
||||
"type": "sqlite",
|
||||
"path": "./.praison/memory.db"
|
||||
},
|
||||
"rag_db_path": "./.praison/chroma_db"
|
||||
}
|
||||
|
||||
# Add embedder config if provided
|
||||
if embedder:
|
||||
if isinstance(embedder, dict):
|
||||
mem_cfg = mem_cfg or {}
|
||||
mem_cfg["embedder"] = embedder
|
||||
else:
|
||||
# Handle direct embedder function
|
||||
mem_cfg = mem_cfg or {}
|
||||
mem_cfg["embedder_function"] = embedder
|
||||
|
||||
if mem_cfg:
|
||||
# Pass verbose level to Memory
|
||||
self.shared_memory = Memory(config=mem_cfg, verbose=verbose)
|
||||
if verbose >= 5:
|
||||
logger.info("Initialized shared memory for PraisonAIAgents")
|
||||
|
||||
# Distribute memory to tasks
|
||||
for task in tasks:
|
||||
if not task.memory:
|
||||
task.memory = self.shared_memory
|
||||
if verbose >= 5:
|
||||
logger.info(f"Assigned shared memory to task {task.id}")
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to initialize shared memory: {e}")
|
||||
|
||||
# Update tasks with shared memory
|
||||
if self.shared_memory:
|
||||
for task in tasks:
|
||||
if not task.memory:
|
||||
task.memory = self.shared_memory
|
||||
logger.info(f"Assigned shared memory to task {task.id}")
|
||||
|
||||
def add_task(self, task):
|
||||
task_id = self.task_id_counter
|
||||
@@ -139,26 +220,44 @@ class PraisonAIAgents:
|
||||
|
||||
executor_agent = task.agent
|
||||
|
||||
# Ensure tools are available from both task and agent
|
||||
tools = task.tools or []
|
||||
if executor_agent and executor_agent.tools:
|
||||
tools.extend(executor_agent.tools)
|
||||
|
||||
task_prompt = f"""
|
||||
You need to do the following task: {task.description}.
|
||||
Expected Output: {task.expected_output}.
|
||||
"""
|
||||
"""
|
||||
if task.context:
|
||||
context_results = ""
|
||||
for context_task in task.context:
|
||||
if context_task.result:
|
||||
context_results += f"Result of previous task {context_task.name if context_task.name else context_task.description}: {context_task.result.raw}\n"
|
||||
else:
|
||||
context_results += f"Previous task {context_task.name if context_task.name else context_task.description} had no result.\n"
|
||||
context_results = [] # Use list to avoid duplicates
|
||||
for context_item in task.context:
|
||||
if isinstance(context_item, str):
|
||||
context_results.append(f"Input Content:\n{context_item}")
|
||||
elif isinstance(context_item, list):
|
||||
context_results.append(f"Input Content: {' '.join(str(x) for x in context_item)}")
|
||||
elif hasattr(context_item, 'result'): # Task object
|
||||
if context_item.result:
|
||||
context_results.append(
|
||||
f"Result of previous task {context_item.name if context_item.name else context_item.description}:\n{context_item.result.raw}"
|
||||
)
|
||||
else:
|
||||
context_results.append(
|
||||
f"Previous task {context_item.name if context_item.name else context_item.description} has no result yet."
|
||||
)
|
||||
|
||||
# Join unique context results
|
||||
unique_contexts = list(dict.fromkeys(context_results)) # Remove duplicates
|
||||
task_prompt += f"""
|
||||
Here are the results of previous tasks that might be useful:\n
|
||||
{context_results}
|
||||
Context:
|
||||
|
||||
{' '.join(unique_contexts)}
|
||||
"""
|
||||
task_prompt += "Please provide only the final result of your work. Do not add any conversation or extra explanation."
|
||||
|
||||
if self.verbose >= 2:
|
||||
logging.info(f"Executing task {task_id}: {task.description} using {executor_agent.name}")
|
||||
logging.debug(f"Starting execution of task {task_id} with prompt:\n{task_prompt}")
|
||||
logger.info(f"Executing task {task_id}: {task.description} using {executor_agent.name}")
|
||||
logger.debug(f"Starting execution of task {task_id} with prompt:\n{task_prompt}")
|
||||
|
||||
if task.images:
|
||||
def _get_multimodal_message(text_prompt, images):
|
||||
@@ -195,14 +294,14 @@ Here are the results of previous tasks that might be useful:\n
|
||||
|
||||
agent_output = await executor_agent.achat(
|
||||
_get_multimodal_message(task_prompt, task.images),
|
||||
tools=task.tools,
|
||||
tools=tools,
|
||||
output_json=task.output_json,
|
||||
output_pydantic=task.output_pydantic
|
||||
)
|
||||
else:
|
||||
agent_output = await executor_agent.achat(
|
||||
task_prompt,
|
||||
tools=task.tools,
|
||||
tools=tools,
|
||||
output_json=task.output_json,
|
||||
output_pydantic=task.output_pydantic
|
||||
)
|
||||
@@ -223,8 +322,8 @@ Here are the results of previous tasks that might be useful:\n
|
||||
task_output.json_dict = parsed
|
||||
task_output.output_format = "JSON"
|
||||
except:
|
||||
logging.warning(f"Warning: Could not parse output of task {task_id} as JSON")
|
||||
logging.debug(f"Output that failed JSON parsing: {agent_output}")
|
||||
logger.warning(f"Warning: Could not parse output of task {task_id} as JSON")
|
||||
logger.debug(f"Output that failed JSON parsing: {agent_output}")
|
||||
|
||||
if task.output_pydantic:
|
||||
cleaned = self.clean_json_output(agent_output)
|
||||
@@ -234,8 +333,8 @@ Here are the results of previous tasks that might be useful:\n
|
||||
task_output.pydantic = pyd_obj
|
||||
task_output.output_format = "Pydantic"
|
||||
except:
|
||||
logging.warning(f"Warning: Could not parse output of task {task_id} as Pydantic Model")
|
||||
logging.debug(f"Output that failed Pydantic parsing: {agent_output}")
|
||||
logger.warning(f"Warning: Could not parse output of task {task_id} as Pydantic Model")
|
||||
logger.debug(f"Output that failed Pydantic parsing: {agent_output}")
|
||||
|
||||
task.result = task_output
|
||||
return task_output
|
||||
@@ -250,37 +349,53 @@ Here are the results of previous tasks that might be useful:\n
|
||||
return
|
||||
task = self.tasks[task_id]
|
||||
if task.status == "completed":
|
||||
logging.info(f"Task with ID {task_id} is already completed")
|
||||
logger.info(f"Task with ID {task_id} is already completed")
|
||||
return
|
||||
|
||||
retries = 0
|
||||
while task.status != "completed" and retries < self.max_retries:
|
||||
logging.debug(f"Attempt {retries+1} for task {task_id}")
|
||||
logger.debug(f"Attempt {retries+1} for task {task_id}")
|
||||
if task.status in ["not started", "in progress"]:
|
||||
task_output = await self.aexecute_task(task_id)
|
||||
if task_output and self.completion_checker(task, task_output.raw):
|
||||
task.status = "completed"
|
||||
if task.callback:
|
||||
# Run execute_callback for memory operations
|
||||
try:
|
||||
await task.execute_callback(task_output)
|
||||
except Exception as e:
|
||||
logger.error(f"Error executing memory callback for task {task_id}: {e}")
|
||||
logger.exception(e)
|
||||
|
||||
# Run task callback if exists
|
||||
if task.callback:
|
||||
try:
|
||||
if asyncio.iscoroutinefunction(task.callback):
|
||||
await task.callback(task_output)
|
||||
else:
|
||||
task.callback(task_output)
|
||||
except Exception as e:
|
||||
logger.error(f"Error executing task callback for task {task_id}: {e}")
|
||||
logger.exception(e)
|
||||
|
||||
self.save_output_to_file(task, task_output)
|
||||
if self.verbose >= 1:
|
||||
logging.info(f"Task {task_id} completed successfully.")
|
||||
logger.info(f"Task {task_id} completed successfully.")
|
||||
else:
|
||||
task.status = "in progress"
|
||||
if self.verbose >= 1:
|
||||
logging.info(f"Task {task_id} not completed, retrying")
|
||||
logger.info(f"Task {task_id} not completed, retrying")
|
||||
await asyncio.sleep(1)
|
||||
retries += 1
|
||||
else:
|
||||
if task.status == "failed":
|
||||
logging.info("Task is failed, resetting to in-progress for another try...")
|
||||
logger.info("Task is failed, resetting to in-progress for another try...")
|
||||
task.status = "in progress"
|
||||
else:
|
||||
logging.info("Invalid Task status")
|
||||
logger.info("Invalid Task status")
|
||||
break
|
||||
|
||||
if retries == self.max_retries and task.status != "completed":
|
||||
logging.info(f"Task {task_id} failed after {self.max_retries} retries.")
|
||||
logger.info(f"Task {task_id} failed after {self.max_retries} retries.")
|
||||
|
||||
async def arun_all_tasks(self):
|
||||
"""Async version of run_all_tasks method"""
|
||||
@@ -288,15 +403,30 @@ Here are the results of previous tasks that might be useful:\n
|
||||
tasks=self.tasks,
|
||||
agents=self.agents,
|
||||
manager_llm=self.manager_llm,
|
||||
verbose=self.verbose
|
||||
verbose=self.verbose,
|
||||
max_iter=self.max_iter
|
||||
)
|
||||
|
||||
if self.process == "workflow":
|
||||
# Collect all tasks that should run in parallel
|
||||
parallel_tasks = []
|
||||
async for task_id in process.aworkflow():
|
||||
if self.tasks[task_id].async_execution:
|
||||
await self.arun_task(task_id)
|
||||
else:
|
||||
self.run_task(task_id)
|
||||
if self.tasks[task_id].async_execution and self.tasks[task_id].is_start:
|
||||
parallel_tasks.append(task_id)
|
||||
elif parallel_tasks:
|
||||
# Execute collected parallel tasks
|
||||
await asyncio.gather(*[self.arun_task(t) for t in parallel_tasks])
|
||||
parallel_tasks = []
|
||||
# Run the current non-parallel task
|
||||
if self.tasks[task_id].async_execution:
|
||||
await self.arun_task(task_id)
|
||||
else:
|
||||
self.run_task(task_id)
|
||||
|
||||
# Execute any remaining parallel tasks
|
||||
if parallel_tasks:
|
||||
await asyncio.gather(*[self.arun_task(t) for t in parallel_tasks])
|
||||
|
||||
elif self.process == "sequential":
|
||||
async for task_id in process.asequential():
|
||||
if self.tasks[task_id].async_execution:
|
||||
@@ -312,8 +442,16 @@ Here are the results of previous tasks that might be useful:\n
|
||||
else:
|
||||
self.run_task(task_id)
|
||||
|
||||
async def astart(self):
|
||||
async def astart(self, content=None, **kwargs):
|
||||
"""Async version of start method"""
|
||||
if content:
|
||||
# Add content to context of all tasks
|
||||
for task in self.tasks.values():
|
||||
if isinstance(content, (str, list)):
|
||||
if not task.context:
|
||||
task.context = []
|
||||
task.context.append(content)
|
||||
|
||||
await self.arun_all_tasks()
|
||||
return {
|
||||
"task_status": self.get_all_tasks_status(),
|
||||
@@ -328,7 +466,7 @@ Here are the results of previous tasks that might be useful:\n
|
||||
with open(task.output_file, "w") as f:
|
||||
f.write(str(task_output))
|
||||
if self.verbose >= 1:
|
||||
logging.info(f"Task output saved to {task.output_file}")
|
||||
logger.info(f"Task output saved to {task.output_file}")
|
||||
except Exception as e:
|
||||
display_error(f"Error saving task output to file: {e}")
|
||||
|
||||
@@ -339,6 +477,15 @@ Here are the results of previous tasks that might be useful:\n
|
||||
return
|
||||
task = self.tasks[task_id]
|
||||
|
||||
logger.info(f"Starting execution of task {task_id}")
|
||||
logger.info(f"Task config: {task.config}")
|
||||
|
||||
# Initialize memory before task execution
|
||||
if not task.memory:
|
||||
task.memory = task.initialize_memory()
|
||||
|
||||
logger.info(f"Task memory status: {'Initialized' if task.memory else 'Not initialized'}")
|
||||
|
||||
# Only import multimodal dependencies if task has images
|
||||
if task.images and task.status == "not started":
|
||||
try:
|
||||
@@ -361,21 +508,44 @@ You need to do the following task: {task.description}.
|
||||
Expected Output: {task.expected_output}.
|
||||
"""
|
||||
if task.context:
|
||||
context_results = ""
|
||||
for context_task in task.context:
|
||||
if context_task.result:
|
||||
context_results += f"Result of previous task {context_task.name if context_task.name else context_task.description}: {context_task.result.raw}\n"
|
||||
else:
|
||||
context_results += f"Previous task {context_task.name if context_task.name else context_task.description} had no result.\n"
|
||||
context_results = [] # Use list to avoid duplicates
|
||||
for context_item in task.context:
|
||||
if isinstance(context_item, str):
|
||||
context_results.append(f"Input Content:\n{context_item}")
|
||||
elif isinstance(context_item, list):
|
||||
context_results.append(f"Input Content: {' '.join(str(x) for x in context_item)}")
|
||||
elif hasattr(context_item, 'result'): # Task object
|
||||
if context_item.result:
|
||||
context_results.append(
|
||||
f"Result of previous task {context_item.name if context_item.name else context_item.description}:\n{context_item.result.raw}"
|
||||
)
|
||||
else:
|
||||
context_results.append(
|
||||
f"Previous task {context_item.name if context_item.name else context_item.description} has no result yet."
|
||||
)
|
||||
|
||||
# Join unique context results
|
||||
unique_contexts = list(dict.fromkeys(context_results)) # Remove duplicates
|
||||
task_prompt += f"""
|
||||
Here are the results of previous tasks that might be useful:\n
|
||||
{context_results}
|
||||
Context:
|
||||
|
||||
{' '.join(unique_contexts)}
|
||||
"""
|
||||
|
||||
# Add memory context if available
|
||||
if task.memory:
|
||||
try:
|
||||
memory_context = task.memory.build_context_for_task(task.description)
|
||||
if memory_context:
|
||||
task_prompt += f"\n\nRelevant memory context:\n{memory_context}"
|
||||
except Exception as e:
|
||||
logger.error(f"Error getting memory context: {e}")
|
||||
|
||||
task_prompt += "Please provide only the final result of your work. Do not add any conversation or extra explanation."
|
||||
|
||||
if self.verbose >= 2:
|
||||
logging.info(f"Executing task {task_id}: {task.description} using {executor_agent.name}")
|
||||
logging.debug(f"Starting execution of task {task_id} with prompt:\n{task_prompt}")
|
||||
logger.info(f"Executing task {task_id}: {task.description} using {executor_agent.name}")
|
||||
logger.debug(f"Starting execution of task {task_id} with prompt:\n{task_prompt}")
|
||||
|
||||
if task.images:
|
||||
def _get_multimodal_message(text_prompt, images):
|
||||
@@ -425,6 +595,17 @@ Here are the results of previous tasks that might be useful:\n
|
||||
)
|
||||
|
||||
if agent_output:
|
||||
# Store the response in memory
|
||||
if task.memory:
|
||||
try:
|
||||
task.store_in_memory(
|
||||
content=agent_output,
|
||||
agent_name=executor_agent.name,
|
||||
task_id=task_id
|
||||
)
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to store agent output in memory: {e}")
|
||||
|
||||
task_output = TaskOutput(
|
||||
description=task.description,
|
||||
summary=task.description[:10],
|
||||
@@ -440,8 +621,8 @@ Here are the results of previous tasks that might be useful:\n
|
||||
task_output.json_dict = parsed
|
||||
task_output.output_format = "JSON"
|
||||
except:
|
||||
logging.warning(f"Warning: Could not parse output of task {task_id} as JSON")
|
||||
logging.debug(f"Output that failed JSON parsing: {agent_output}")
|
||||
logger.warning(f"Warning: Could not parse output of task {task_id} as JSON")
|
||||
logger.debug(f"Output that failed JSON parsing: {agent_output}")
|
||||
|
||||
if task.output_pydantic:
|
||||
cleaned = self.clean_json_output(agent_output)
|
||||
@@ -451,8 +632,8 @@ Here are the results of previous tasks that might be useful:\n
|
||||
task_output.pydantic = pyd_obj
|
||||
task_output.output_format = "Pydantic"
|
||||
except:
|
||||
logging.warning(f"Warning: Could not parse output of task {task_id} as Pydantic Model")
|
||||
logging.debug(f"Output that failed Pydantic parsing: {agent_output}")
|
||||
logger.warning(f"Warning: Could not parse output of task {task_id} as Pydantic Model")
|
||||
logger.debug(f"Output that failed Pydantic parsing: {agent_output}")
|
||||
|
||||
task.result = task_output
|
||||
return task_output
|
||||
@@ -467,37 +648,63 @@ Here are the results of previous tasks that might be useful:\n
|
||||
return
|
||||
task = self.tasks[task_id]
|
||||
if task.status == "completed":
|
||||
logging.info(f"Task with ID {task_id} is already completed")
|
||||
logger.info(f"Task with ID {task_id} is already completed")
|
||||
return
|
||||
|
||||
retries = 0
|
||||
while task.status != "completed" and retries < self.max_retries:
|
||||
logging.debug(f"Attempt {retries+1} for task {task_id}")
|
||||
logger.debug(f"Attempt {retries+1} for task {task_id}")
|
||||
if task.status in ["not started", "in progress"]:
|
||||
task_output = self.execute_task(task_id)
|
||||
if task_output and self.completion_checker(task, task_output.raw):
|
||||
task.status = "completed"
|
||||
# Run execute_callback for memory operations
|
||||
try:
|
||||
if asyncio.get_event_loop().is_running():
|
||||
asyncio.create_task(task.execute_callback(task_output))
|
||||
else:
|
||||
loop = asyncio.new_event_loop()
|
||||
asyncio.set_event_loop(loop)
|
||||
loop.run_until_complete(task.execute_callback(task_output))
|
||||
except Exception as e:
|
||||
logger.error(f"Error executing memory callback for task {task_id}: {e}")
|
||||
logger.exception(e)
|
||||
|
||||
# Run task callback if exists
|
||||
if task.callback:
|
||||
task.callback(task_output)
|
||||
try:
|
||||
if asyncio.iscoroutinefunction(task.callback):
|
||||
if asyncio.get_event_loop().is_running():
|
||||
asyncio.create_task(task.callback(task_output))
|
||||
else:
|
||||
loop = asyncio.new_event_loop()
|
||||
asyncio.set_event_loop(loop)
|
||||
loop.run_until_complete(task.callback(task_output))
|
||||
else:
|
||||
task.callback(task_output)
|
||||
except Exception as e:
|
||||
logger.error(f"Error executing task callback for task {task_id}: {e}")
|
||||
logger.exception(e)
|
||||
|
||||
self.save_output_to_file(task, task_output)
|
||||
if self.verbose >= 1:
|
||||
logging.info(f"Task {task_id} completed successfully.")
|
||||
logger.info(f"Task {task_id} completed successfully.")
|
||||
else:
|
||||
task.status = "in progress"
|
||||
if self.verbose >= 1:
|
||||
logging.info(f"Task {task_id} not completed, retrying")
|
||||
logger.info(f"Task {task_id} not completed, retrying")
|
||||
time.sleep(1)
|
||||
retries += 1
|
||||
else:
|
||||
if task.status == "failed":
|
||||
logging.info("Task is failed, resetting to in-progress for another try...")
|
||||
logger.info("Task is failed, resetting to in-progress for another try...")
|
||||
task.status = "in progress"
|
||||
else:
|
||||
logging.info("Invalid Task status")
|
||||
logger.info("Invalid Task status")
|
||||
break
|
||||
|
||||
if retries == self.max_retries and task.status != "completed":
|
||||
logging.info(f"Task {task_id} failed after {self.max_retries} retries.")
|
||||
logger.info(f"Task {task_id} failed after {self.max_retries} retries.")
|
||||
|
||||
def run_all_tasks(self):
|
||||
"""Synchronous version of run_all_tasks method"""
|
||||
@@ -505,7 +712,8 @@ Here are the results of previous tasks that might be useful:\n
|
||||
tasks=self.tasks,
|
||||
agents=self.agents,
|
||||
manager_llm=self.manager_llm,
|
||||
verbose=self.verbose
|
||||
verbose=self.verbose,
|
||||
max_iter=self.max_iter
|
||||
)
|
||||
|
||||
if self.process == "workflow":
|
||||
@@ -544,12 +752,24 @@ Here are the results of previous tasks that might be useful:\n
|
||||
return str(agent[0])
|
||||
return None
|
||||
|
||||
def start(self):
|
||||
def start(self, content=None, **kwargs):
|
||||
"""Start agent execution with optional content and config"""
|
||||
if content:
|
||||
# Add content to context of all tasks
|
||||
for task in self.tasks.values():
|
||||
if isinstance(content, (str, list)):
|
||||
# If context is empty, initialize it
|
||||
if not task.context:
|
||||
task.context = []
|
||||
# Add content to context
|
||||
task.context.append(content)
|
||||
|
||||
# Run tasks as before
|
||||
self.run_all_tasks()
|
||||
return {
|
||||
"task_status": self.get_all_tasks_status(),
|
||||
"task_results": {task_id: self.get_task_result(task_id) for task_id in self.tasks}
|
||||
}
|
||||
}
|
||||
|
||||
def set_state(self, key: str, value: Any) -> None:
|
||||
"""Set a state value"""
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
"""
|
||||
PraisonAI Knowledge - Advanced knowledge management system with configurable features
|
||||
"""
|
||||
|
||||
from praisonaiagents.knowledge.knowledge import Knowledge
|
||||
from praisonaiagents.knowledge.chunking import Chunking
|
||||
|
||||
__all__ = ["Knowledge", "Chunking"]
|
||||
@@ -0,0 +1,182 @@
|
||||
from typing import List, Union, Optional, Dict, Any
|
||||
from functools import cached_property
|
||||
import importlib
|
||||
|
||||
class Chunking:
|
||||
"""A unified class for text chunking with various chunking strategies."""
|
||||
|
||||
CHUNKER_PARAMS = {
|
||||
'token': ['chunk_size', 'chunk_overlap', 'tokenizer'],
|
||||
'word': ['chunk_size', 'chunk_overlap', 'tokenizer'],
|
||||
'sentence': ['chunk_size', 'chunk_overlap', 'tokenizer'],
|
||||
'semantic': ['chunk_size', 'embedding_model', 'tokenizer'],
|
||||
'sdpm': ['chunk_size', 'embedding_model', 'tokenizer'],
|
||||
'late': ['chunk_size', 'embedding_model', 'tokenizer'],
|
||||
'recursive': ['chunk_size', 'tokenizer']
|
||||
}
|
||||
|
||||
@cached_property
|
||||
def SUPPORTED_CHUNKERS(self) -> Dict[str, Any]:
|
||||
"""Lazy load chunker classes."""
|
||||
try:
|
||||
from chonkie.chunker import (
|
||||
TokenChunker,
|
||||
WordChunker,
|
||||
SentenceChunker,
|
||||
SemanticChunker,
|
||||
SDPMChunker,
|
||||
LateChunker,
|
||||
RecursiveChunker
|
||||
)
|
||||
except ImportError:
|
||||
raise ImportError(
|
||||
"chonkie package not found. Please install it using: pip install 'praisonaiagents[knowledge]'"
|
||||
)
|
||||
|
||||
return {
|
||||
'token': TokenChunker,
|
||||
'word': WordChunker,
|
||||
'sentence': SentenceChunker,
|
||||
'semantic': SemanticChunker,
|
||||
'sdpm': SDPMChunker,
|
||||
'late': LateChunker,
|
||||
'recursive': RecursiveChunker
|
||||
}
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
chunker_type: str = 'token',
|
||||
chunk_size: int = 512,
|
||||
chunk_overlap: int = 128,
|
||||
tokenizer: str = "gpt2",
|
||||
embedding_model: Optional[Union[str, Any]] = None,
|
||||
**kwargs
|
||||
):
|
||||
"""Initialize the Chunking class."""
|
||||
if chunker_type not in self.CHUNKER_PARAMS:
|
||||
raise ValueError(
|
||||
f"Unsupported chunker type: {chunker_type}. "
|
||||
f"Must be one of: {list(self.CHUNKER_PARAMS.keys())}"
|
||||
)
|
||||
|
||||
self.chunker_type = chunker_type
|
||||
self.chunk_size = chunk_size
|
||||
self.chunk_overlap = chunk_overlap
|
||||
self.tokenizer = tokenizer
|
||||
self._embedding_model = embedding_model
|
||||
self.kwargs = kwargs
|
||||
|
||||
# Initialize these as None for lazy loading
|
||||
self._chunker = None
|
||||
self._embeddings = None
|
||||
|
||||
@cached_property
|
||||
def embedding_model(self):
|
||||
"""Lazy load the embedding model."""
|
||||
if self._embedding_model is None and self.chunker_type in ['semantic', 'sdpm', 'late']:
|
||||
from chonkie.embeddings import AutoEmbeddings
|
||||
return AutoEmbeddings.get_embeddings("all-MiniLM-L6-v2")
|
||||
elif isinstance(self._embedding_model, str):
|
||||
from chonkie.embeddings import AutoEmbeddings
|
||||
return AutoEmbeddings.get_embeddings(self._embedding_model)
|
||||
return self._embedding_model
|
||||
|
||||
def _get_chunker_params(self) -> Dict[str, Any]:
|
||||
"""Get the appropriate parameters for the current chunker type."""
|
||||
allowed_params = self.CHUNKER_PARAMS[self.chunker_type]
|
||||
params = {'chunk_size': self.chunk_size}
|
||||
|
||||
if 'chunk_overlap' in allowed_params:
|
||||
params['chunk_overlap'] = self.chunk_overlap
|
||||
|
||||
if 'tokenizer' in allowed_params:
|
||||
if self.chunker_type in ['semantic', 'sdpm', 'late']:
|
||||
params['tokenizer'] = self.embedding_model.get_tokenizer_or_token_counter()
|
||||
else:
|
||||
params['tokenizer'] = self.tokenizer
|
||||
|
||||
if 'embedding_model' in allowed_params:
|
||||
params['embedding_model'] = self.embedding_model
|
||||
|
||||
# Add any additional kwargs that are in allowed_params
|
||||
for key, value in self.kwargs.items():
|
||||
if key in allowed_params:
|
||||
params[key] = value
|
||||
|
||||
return params
|
||||
|
||||
@cached_property
|
||||
def chunker(self):
|
||||
"""Lazy load the chunker instance."""
|
||||
if self._chunker is None:
|
||||
chunker_cls = self.SUPPORTED_CHUNKERS[self.chunker_type]
|
||||
common_params = self._get_chunker_params()
|
||||
self._chunker = chunker_cls(**common_params)
|
||||
|
||||
return self._chunker
|
||||
|
||||
def _get_overlap_refinery(self, context_size: Optional[int] = None, **kwargs):
|
||||
"""Lazy load the overlap refinery."""
|
||||
try:
|
||||
from chonkie.refinery import OverlapRefinery
|
||||
except ImportError:
|
||||
raise ImportError("Failed to import OverlapRefinery from chonkie.refinery")
|
||||
|
||||
if context_size is None:
|
||||
context_size = self.chunk_overlap
|
||||
|
||||
return OverlapRefinery(
|
||||
context_size=context_size,
|
||||
tokenizer=self.chunker.tokenizer,
|
||||
**kwargs
|
||||
)
|
||||
|
||||
def add_overlap_context(
|
||||
self,
|
||||
chunks: List[Any],
|
||||
context_size: int = None,
|
||||
mode: str = "suffix",
|
||||
merge_context: bool = True
|
||||
) -> List[Any]:
|
||||
"""Add overlap context to chunks using OverlapRefinery."""
|
||||
refinery = self._get_overlap_refinery(
|
||||
context_size=context_size,
|
||||
mode=mode,
|
||||
merge_context=merge_context
|
||||
)
|
||||
return refinery.refine(chunks)
|
||||
|
||||
def chunk(
|
||||
self,
|
||||
text: Union[str, List[str]],
|
||||
add_context: bool = False,
|
||||
context_params: Optional[Dict[str, Any]] = None
|
||||
) -> Union[List[Any], List[List[Any]]]:
|
||||
"""Chunk text using the configured chunking strategy."""
|
||||
chunks = self.chunker(text)
|
||||
|
||||
if add_context:
|
||||
context_params = context_params or {}
|
||||
if isinstance(text, str):
|
||||
chunks = self.add_overlap_context(chunks, **context_params)
|
||||
else:
|
||||
chunks = [self.add_overlap_context(c, **context_params) for c in chunks]
|
||||
|
||||
return chunks
|
||||
|
||||
def __call__(
|
||||
self,
|
||||
text: Union[str, List[str]],
|
||||
add_context: bool = False,
|
||||
context_params: Optional[Dict[str, Any]] = None
|
||||
) -> Union[List[Any], List[List[Any]]]:
|
||||
"""Make the Chunking instance callable."""
|
||||
return self.chunk(text, add_context, context_params)
|
||||
|
||||
def __repr__(self) -> str:
|
||||
"""String representation of the Chunking instance."""
|
||||
return (
|
||||
f"Chunking(chunker_type='{self.chunker_type}', "
|
||||
f"chunk_size={self.chunk_size}, "
|
||||
f"chunk_overlap={self.chunk_overlap})"
|
||||
)
|
||||
@@ -0,0 +1,303 @@
|
||||
import os
|
||||
import logging
|
||||
import uuid
|
||||
import time
|
||||
from .chunking import Chunking
|
||||
from functools import cached_property
|
||||
from rich.progress import Progress, SpinnerColumn, TextColumn, BarColumn, TaskProgressColumn
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
class CustomMemory:
|
||||
@classmethod
|
||||
def from_config(cls, config):
|
||||
from mem0 import Memory
|
||||
return type('CustomMemory', (Memory,), {
|
||||
'_add_to_vector_store': cls._add_to_vector_store
|
||||
}).from_config(config)
|
||||
|
||||
@staticmethod
|
||||
def _add_to_vector_store(self, messages, metadata, filters):
|
||||
# Custom implementation that doesn't use LLM
|
||||
parsed_messages = "\n".join([msg["content"] for msg in messages])
|
||||
|
||||
# Create a simple fact without using LLM
|
||||
new_retrieved_facts = [parsed_messages]
|
||||
|
||||
# Process embeddings and continue with vector store operations
|
||||
new_message_embeddings = {}
|
||||
for new_mem in new_retrieved_facts:
|
||||
messages_embeddings = self.embedding_model.embed(new_mem)
|
||||
new_message_embeddings[new_mem] = messages_embeddings
|
||||
|
||||
# Create the memory
|
||||
memory_id = self._create_memory(
|
||||
data=parsed_messages,
|
||||
existing_embeddings=new_message_embeddings,
|
||||
metadata=metadata
|
||||
)
|
||||
|
||||
return [{
|
||||
"id": memory_id,
|
||||
"memory": parsed_messages,
|
||||
"event": "ADD"
|
||||
}]
|
||||
|
||||
class Knowledge:
|
||||
def __init__(self, config=None, verbose=None):
|
||||
self._config = config
|
||||
self._verbose = verbose or 0
|
||||
os.environ['ANONYMIZED_TELEMETRY'] = 'False' # Chromadb
|
||||
|
||||
# Configure logging levels based on verbose setting
|
||||
if not self._verbose:
|
||||
# Suppress logs from all relevant dependencies
|
||||
for logger_name in [
|
||||
'mem0',
|
||||
'chromadb',
|
||||
'local_persistent_hnsw',
|
||||
'_client',
|
||||
'main'
|
||||
]:
|
||||
logging.getLogger(logger_name).setLevel(logging.WARNING)
|
||||
|
||||
# Disable OpenAI API request logging
|
||||
logging.getLogger('openai').setLevel(logging.WARNING)
|
||||
|
||||
# Set root logger to warning to catch any uncategorized logs
|
||||
logging.getLogger().setLevel(logging.WARNING)
|
||||
|
||||
@cached_property
|
||||
def _deps(self):
|
||||
try:
|
||||
from markitdown import MarkItDown
|
||||
import chromadb
|
||||
return {
|
||||
'chromadb': chromadb,
|
||||
'markdown': MarkItDown()
|
||||
}
|
||||
except ImportError:
|
||||
raise ImportError(
|
||||
"Required packages not installed. Please install using: "
|
||||
'pip install "praisonaiagents[knowledge]"'
|
||||
)
|
||||
|
||||
@cached_property
|
||||
def config(self):
|
||||
# Generate unique collection name for each instance
|
||||
collection_name = f"test_{int(time.time())}_{str(uuid.uuid4())[:8]}"
|
||||
persist_dir = ".praison"
|
||||
|
||||
# Create persistent client config
|
||||
base_config = {
|
||||
"vector_store": {
|
||||
"provider": "chroma",
|
||||
"config": {
|
||||
"collection_name": collection_name,
|
||||
"path": persist_dir,
|
||||
"client": self._deps['chromadb'].PersistentClient(path=persist_dir)
|
||||
}
|
||||
},
|
||||
"version": "v1.1",
|
||||
"custom_prompt": "Return {{\"facts\": [text]}} where text is the exact input provided and json response"
|
||||
}
|
||||
|
||||
# If config is provided, merge it with base config
|
||||
if self._config:
|
||||
if "vector_store" in self._config and "config" in self._config["vector_store"]:
|
||||
config_copy = self._config["vector_store"]["config"].copy()
|
||||
for key in ["collection_name", "client"]:
|
||||
if key in config_copy:
|
||||
del config_copy[key]
|
||||
base_config["vector_store"]["config"].update(config_copy)
|
||||
|
||||
return base_config
|
||||
|
||||
@cached_property
|
||||
def memory(self):
|
||||
try:
|
||||
return CustomMemory.from_config(self.config)
|
||||
except (NotImplementedError, ValueError) as e:
|
||||
if "list_collections" in str(e) or "Extra fields not allowed" in str(e):
|
||||
# Keep only allowed fields
|
||||
vector_store_config = {
|
||||
"collection_name": self.config["vector_store"]["config"]["collection_name"],
|
||||
"path": self.config["vector_store"]["config"]["path"]
|
||||
}
|
||||
self.config["vector_store"]["config"] = vector_store_config
|
||||
from mem0 import Memory
|
||||
return Memory.from_config(self.config)
|
||||
raise
|
||||
|
||||
@cached_property
|
||||
def markdown(self):
|
||||
return self._deps['markdown']
|
||||
|
||||
@cached_property
|
||||
def chunker(self):
|
||||
return Chunking(
|
||||
chunker_type='recursive',
|
||||
chunk_size=512,
|
||||
chunk_overlap=50
|
||||
)
|
||||
|
||||
def _log(self, message, level=2):
|
||||
"""Internal logging helper"""
|
||||
if self._verbose and self._verbose >= level:
|
||||
logger.info(message)
|
||||
|
||||
def store(self, content, user_id=None, agent_id=None, run_id=None, metadata=None):
|
||||
"""Store a memory."""
|
||||
try:
|
||||
if isinstance(content, str):
|
||||
if any(content.lower().endswith(ext) for ext in ['.pdf', '.doc', '.docx', '.txt']):
|
||||
self._log(f"Content appears to be a file path, processing file: {content}")
|
||||
return self.add(content, user_id=user_id, agent_id=agent_id, run_id=run_id, metadata=metadata)
|
||||
|
||||
content = content.strip()
|
||||
if not content:
|
||||
return []
|
||||
|
||||
result = self.memory.add(content, user_id=user_id, agent_id=agent_id, run_id=run_id, metadata=metadata)
|
||||
self._log(f"Store operation result: {result}")
|
||||
return result
|
||||
except Exception as e:
|
||||
logger.error(f"Error storing content: {str(e)}")
|
||||
return []
|
||||
|
||||
def get_all(self, user_id=None, agent_id=None, run_id=None):
|
||||
"""Retrieve all memories."""
|
||||
return self.memory.get_all(user_id=user_id, agent_id=agent_id, run_id=run_id)
|
||||
|
||||
def get(self, memory_id):
|
||||
"""Retrieve a specific memory by ID."""
|
||||
return self.memory.get(memory_id)
|
||||
|
||||
def search(self, query, user_id=None, agent_id=None, run_id=None):
|
||||
"""Search for memories related to a query."""
|
||||
return self.memory.search(query, user_id=user_id, agent_id=agent_id, run_id=run_id)
|
||||
|
||||
def update(self, memory_id, data):
|
||||
"""Update a memory."""
|
||||
return self.memory.update(memory_id, data)
|
||||
|
||||
def history(self, memory_id):
|
||||
"""Get the history of changes for a memory."""
|
||||
return self.memory.history(memory_id)
|
||||
|
||||
def delete(self, memory_id):
|
||||
"""Delete a memory."""
|
||||
self.memory.delete(memory_id)
|
||||
|
||||
def delete_all(self, user_id=None, agent_id=None, run_id=None):
|
||||
"""Delete all memories."""
|
||||
self.memory.delete_all(user_id=user_id, agent_id=agent_id, run_id=run_id)
|
||||
|
||||
def reset(self):
|
||||
"""Reset all memories."""
|
||||
self.memory.reset()
|
||||
|
||||
def normalize_content(self, content):
|
||||
"""Normalize content for consistent storage."""
|
||||
# Example normalization: strip whitespace, convert to lowercase
|
||||
return content.strip().lower()
|
||||
|
||||
def add(self, file_path, user_id=None, agent_id=None, run_id=None, metadata=None):
|
||||
"""Read file content and store it in memory.
|
||||
|
||||
Args:
|
||||
file_path: Can be:
|
||||
- A string path to local file
|
||||
- A URL string
|
||||
- A list containing file paths and/or URLs
|
||||
"""
|
||||
if isinstance(file_path, (list, tuple)):
|
||||
results = []
|
||||
for path in file_path:
|
||||
result = self._process_single_input(path, user_id, agent_id, run_id, metadata)
|
||||
results.extend(result.get('results', []))
|
||||
return {'results': results, 'relations': []}
|
||||
|
||||
return self._process_single_input(file_path, user_id, agent_id, run_id, metadata)
|
||||
|
||||
def _process_single_input(self, input_path, user_id=None, agent_id=None, run_id=None, metadata=None):
|
||||
"""Process a single input which can be a file path or URL."""
|
||||
try:
|
||||
# Define supported file extensions
|
||||
DOCUMENT_EXTENSIONS = {
|
||||
'document': ('.pdf', '.ppt', '.pptx', '.doc', '.docx', '.xls', '.xlsx'),
|
||||
'media': ('.jpg', '.jpeg', '.png', '.gif', '.bmp', '.tiff', '.mp3', '.wav', '.ogg', '.m4a'),
|
||||
'text': ('.txt', '.csv', '.json', '.xml', '.md', '.html', '.htm'),
|
||||
'archive': '.zip'
|
||||
}
|
||||
|
||||
# Check if input is URL
|
||||
if isinstance(input_path, str) and (input_path.startswith('http://') or input_path.startswith('https://')):
|
||||
self._log(f"Processing URL: {input_path}")
|
||||
raise NotImplementedError("URL processing not yet implemented")
|
||||
|
||||
# Check if input ends with any supported extension
|
||||
is_supported_file = any(input_path.lower().endswith(ext)
|
||||
for exts in DOCUMENT_EXTENSIONS.values()
|
||||
for ext in (exts if isinstance(exts, tuple) else (exts,)))
|
||||
|
||||
if is_supported_file:
|
||||
self._log(f"Processing as file path: {input_path}")
|
||||
if not os.path.exists(input_path):
|
||||
logger.error(f"File not found: {input_path}")
|
||||
raise FileNotFoundError(f"File not found: {input_path}")
|
||||
|
||||
file_ext = '.' + input_path.lower().split('.')[-1] # Get extension reliably
|
||||
|
||||
# Process file based on type
|
||||
if file_ext in DOCUMENT_EXTENSIONS['text']:
|
||||
with open(input_path, 'r', encoding='utf-8') as file:
|
||||
content = file.read().strip()
|
||||
if not content:
|
||||
raise ValueError("Empty text file")
|
||||
memories = [self.normalize_content(content)]
|
||||
else:
|
||||
# Use MarkItDown for documents and media
|
||||
result = self.markdown.convert(input_path)
|
||||
content = result.text_content
|
||||
if not content:
|
||||
raise ValueError("No content could be extracted from file")
|
||||
chunks = self.chunker.chunk(content)
|
||||
memories = [chunk.text.strip() if hasattr(chunk, 'text') else str(chunk).strip()
|
||||
for chunk in chunks if chunk]
|
||||
|
||||
# Set metadata for file
|
||||
if not metadata:
|
||||
metadata = {}
|
||||
metadata['file_type'] = file_ext.lstrip('.')
|
||||
metadata['filename'] = os.path.basename(input_path)
|
||||
else:
|
||||
# Treat as raw text content only if no file extension
|
||||
memories = [self.normalize_content(input_path)]
|
||||
|
||||
# Create progress display
|
||||
progress = Progress(
|
||||
SpinnerColumn(),
|
||||
TextColumn("[progress.description]{task.description}"),
|
||||
BarColumn(),
|
||||
TaskProgressColumn(),
|
||||
transient=True
|
||||
)
|
||||
|
||||
# Store memories with progress bar
|
||||
all_results = []
|
||||
with progress:
|
||||
store_task = progress.add_task(f"Adding to Knowledge from {os.path.basename(input_path)}", total=len(memories))
|
||||
for memory in memories:
|
||||
if memory:
|
||||
memory_result = self.store(memory, user_id=user_id, agent_id=agent_id,
|
||||
run_id=run_id, metadata=metadata)
|
||||
if memory_result:
|
||||
all_results.extend(memory_result.get('results', []))
|
||||
progress.advance(store_task)
|
||||
|
||||
return {'results': all_results, 'relations': []}
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Error processing input {input_path}: {str(e)}", exc_info=True)
|
||||
raise
|
||||
@@ -23,6 +23,10 @@ logging.basicConfig(
|
||||
handlers=[RichHandler(rich_tracebacks=True)]
|
||||
)
|
||||
|
||||
# Add these lines to suppress markdown parser debug logs
|
||||
logging.getLogger('markdown_it').setLevel(logging.WARNING)
|
||||
logging.getLogger('rich.markdown').setLevel(logging.WARNING)
|
||||
|
||||
# Global list to store error logs
|
||||
error_logs = []
|
||||
|
||||
@@ -116,10 +120,10 @@ def display_interaction(message, response, markdown=True, generation_time=None,
|
||||
console.print(Text(f"Response generated in {generation_time:.1f}s", style="dim"))
|
||||
|
||||
if markdown:
|
||||
console.print(Panel.fit(Markdown(message), title="Message", border_style="cyan"))
|
||||
console.print(Panel.fit(Markdown(message), title="Task", border_style="cyan"))
|
||||
console.print(Panel.fit(Markdown(response), title="Response", border_style="cyan"))
|
||||
else:
|
||||
console.print(Panel.fit(Text(message, style="bold green"), title="Message", border_style="cyan"))
|
||||
console.print(Panel.fit(Text(message, style="bold green"), title="Task", border_style="cyan"))
|
||||
console.print(Panel.fit(Text(response, style="bold blue"), title="Response", border_style="cyan"))
|
||||
|
||||
def display_self_reflection(message: str, console=None):
|
||||
@@ -135,7 +139,7 @@ def display_self_reflection(message: str, console=None):
|
||||
|
||||
console.print(Panel.fit(Text(message, style="bold yellow"), title="Self Reflection", border_style="magenta"))
|
||||
|
||||
def display_instruction(message: str, console=None):
|
||||
def display_instruction(message: str, console=None, agent_name: str = None, agent_role: str = None, agent_tools: List[str] = None):
|
||||
if not message or not message.strip():
|
||||
return
|
||||
if console is None:
|
||||
@@ -146,7 +150,19 @@ def display_instruction(message: str, console=None):
|
||||
if 'instruction' in sync_display_callbacks:
|
||||
sync_display_callbacks['instruction'](message=message)
|
||||
|
||||
console.print(Panel.fit(Text(message, style="bold blue"), title="Instruction", border_style="cyan"))
|
||||
# Display agent info if available
|
||||
if agent_name:
|
||||
agent_info = f"[bold #FF9B9B]👤 Agent:[/] [#FFE5E5]{agent_name}[/]"
|
||||
if agent_role:
|
||||
agent_info += f"\n[bold #B4B4B3]Role:[/] [#FFE5E5]{agent_role}[/]"
|
||||
if agent_tools:
|
||||
tools_str = ", ".join(f"[italic #B4D4FF]{tool}[/]" for tool in agent_tools)
|
||||
agent_info += f"\n[bold #86A789]Tools:[/] {tools_str}"
|
||||
console.print(Panel(agent_info, border_style="#D2E3C8", title="[bold]Agent Info[/]", title_align="left", padding=(1, 2)))
|
||||
|
||||
# Only print if log level is DEBUG
|
||||
if logging.getLogger().getEffectiveLevel() == logging.DEBUG:
|
||||
console.print(Panel.fit(Text(message, style="bold blue"), title="Instruction", border_style="cyan"))
|
||||
|
||||
def display_tool_call(message: str, console=None):
|
||||
if not message or not message.strip():
|
||||
@@ -222,10 +238,10 @@ async def adisplay_interaction(message, response, markdown=True, generation_time
|
||||
console.print(Text(f"Response generated in {generation_time:.1f}s", style="dim"))
|
||||
|
||||
if markdown:
|
||||
console.print(Panel.fit(Markdown(message), title="Message", border_style="cyan"))
|
||||
console.print(Panel.fit(Markdown(message), title="Task", border_style="cyan"))
|
||||
console.print(Panel.fit(Markdown(response), title="Response", border_style="cyan"))
|
||||
else:
|
||||
console.print(Panel.fit(Text(message, style="bold green"), title="Message", border_style="cyan"))
|
||||
console.print(Panel.fit(Text(message, style="bold green"), title="Task", border_style="cyan"))
|
||||
console.print(Panel.fit(Text(response, style="bold blue"), title="Response", border_style="cyan"))
|
||||
|
||||
async def adisplay_self_reflection(message: str, console=None):
|
||||
@@ -241,7 +257,7 @@ async def adisplay_self_reflection(message: str, console=None):
|
||||
|
||||
console.print(Panel.fit(Text(message, style="bold yellow"), title="Self Reflection", border_style="magenta"))
|
||||
|
||||
async def adisplay_instruction(message: str, console=None):
|
||||
async def adisplay_instruction(message: str, console=None, agent_name: str = None, agent_role: str = None, agent_tools: List[str] = None):
|
||||
"""Async version of display_instruction."""
|
||||
if not message or not message.strip():
|
||||
return
|
||||
@@ -252,7 +268,19 @@ async def adisplay_instruction(message: str, console=None):
|
||||
if 'instruction' in async_display_callbacks:
|
||||
await async_display_callbacks['instruction'](message=message)
|
||||
|
||||
console.print(Panel.fit(Text(message, style="bold blue"), title="Instruction", border_style="cyan"))
|
||||
# Display agent info if available
|
||||
if agent_name:
|
||||
agent_info = f"[bold #FF9B9B]👤 Agent:[/] [#FFE5E5]{agent_name}[/]"
|
||||
if agent_role:
|
||||
agent_info += f"\n[bold #B4B4B3]Role:[/] [#FFE5E5]{agent_role}[/]"
|
||||
if agent_tools:
|
||||
tools_str = ", ".join(f"[italic #B4D4FF]{tool}[/]" for tool in agent_tools)
|
||||
agent_info += f"\n[bold #86A789]Tools:[/] {tools_str}"
|
||||
console.print(Panel(agent_info, border_style="#D2E3C8", title="[bold]Agent Info[/]", title_align="left", padding=(1, 2)))
|
||||
|
||||
# Only print if log level is DEBUG
|
||||
if logging.getLogger().getEffectiveLevel() == logging.DEBUG:
|
||||
console.print(Panel.fit(Text(message, style="bold blue"), title="Instruction", border_style="cyan"))
|
||||
|
||||
async def adisplay_tool_call(message: str, console=None):
|
||||
"""Async version of display_tool_call."""
|
||||
|
||||
@@ -0,0 +1,931 @@
|
||||
import os
|
||||
import sqlite3
|
||||
import json
|
||||
import time
|
||||
import shutil
|
||||
from typing import Any, Dict, List, Optional, Union, Literal
|
||||
import logging
|
||||
|
||||
# Set up logger
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
try:
|
||||
import chromadb
|
||||
from chromadb.config import Settings as ChromaSettings
|
||||
CHROMADB_AVAILABLE = True
|
||||
except ImportError:
|
||||
CHROMADB_AVAILABLE = False
|
||||
logger.warning("To use memory features, please run: pip install \"praisonaiagents[memory]\"")
|
||||
|
||||
try:
|
||||
import mem0
|
||||
MEM0_AVAILABLE = True
|
||||
except ImportError:
|
||||
MEM0_AVAILABLE = False
|
||||
|
||||
try:
|
||||
import openai
|
||||
OPENAI_AVAILABLE = True
|
||||
except ImportError:
|
||||
OPENAI_AVAILABLE = False
|
||||
|
||||
|
||||
|
||||
|
||||
class Memory:
|
||||
"""
|
||||
A single-file memory manager covering:
|
||||
- Short-term memory (STM) for ephemeral context
|
||||
- Long-term memory (LTM) for persistent knowledge
|
||||
- Entity memory (structured data about named entities)
|
||||
- User memory (preferences/history for each user)
|
||||
- Quality score logic for deciding which data to store in LTM
|
||||
- Context building from multiple memory sources
|
||||
|
||||
Config example:
|
||||
{
|
||||
"provider": "rag" or "mem0" or "none",
|
||||
"use_embedding": True,
|
||||
"short_db": "short_term.db",
|
||||
"long_db": "long_term.db",
|
||||
"rag_db_path": "rag_db", # optional path for local embedding store
|
||||
"config": {
|
||||
"api_key": "...", # if mem0 usage
|
||||
"org_id": "...",
|
||||
"project_id": "...",
|
||||
...
|
||||
}
|
||||
}
|
||||
"""
|
||||
|
||||
def __init__(self, config: Dict[str, Any], verbose: int = 0):
|
||||
self.cfg = config or {}
|
||||
self.verbose = verbose
|
||||
|
||||
# Set logger level based on verbose
|
||||
if verbose >= 5:
|
||||
logger.setLevel(logging.INFO)
|
||||
else:
|
||||
logger.setLevel(logging.WARNING)
|
||||
|
||||
# Also set ChromaDB and OpenAI client loggers to WARNING
|
||||
logging.getLogger('chromadb').setLevel(logging.WARNING)
|
||||
logging.getLogger('openai').setLevel(logging.WARNING)
|
||||
logging.getLogger('httpx').setLevel(logging.WARNING)
|
||||
logging.getLogger('httpcore').setLevel(logging.WARNING)
|
||||
logging.getLogger('chromadb.segment.impl.vector.local_persistent_hnsw').setLevel(logging.ERROR)
|
||||
|
||||
self.provider = self.cfg.get("provider", "rag")
|
||||
self.use_mem0 = (self.provider.lower() == "mem0") and MEM0_AVAILABLE
|
||||
self.use_rag = (self.provider.lower() == "rag") and CHROMADB_AVAILABLE and self.cfg.get("use_embedding", False)
|
||||
|
||||
# Create .praison directory if it doesn't exist
|
||||
os.makedirs(".praison", exist_ok=True)
|
||||
|
||||
# Short-term DB
|
||||
self.short_db = self.cfg.get("short_db", ".praison/short_term.db")
|
||||
self._init_stm()
|
||||
|
||||
# Long-term DB
|
||||
self.long_db = self.cfg.get("long_db", ".praison/long_term.db")
|
||||
self._init_ltm()
|
||||
|
||||
# Conditionally init Mem0 or local RAG
|
||||
if self.use_mem0:
|
||||
self._init_mem0()
|
||||
elif self.use_rag:
|
||||
self._init_chroma()
|
||||
|
||||
def _log_verbose(self, msg: str, level: int = logging.INFO):
|
||||
"""Only log if verbose >= 5"""
|
||||
if self.verbose >= 5:
|
||||
logger.log(level, msg)
|
||||
|
||||
# -------------------------------------------------------------------------
|
||||
# Initialization
|
||||
# -------------------------------------------------------------------------
|
||||
def _init_stm(self):
|
||||
"""Creates or verifies short-term memory table."""
|
||||
os.makedirs(os.path.dirname(self.short_db) or ".", exist_ok=True)
|
||||
conn = sqlite3.connect(self.short_db)
|
||||
c = conn.cursor()
|
||||
c.execute("""
|
||||
CREATE TABLE IF NOT EXISTS short_mem (
|
||||
id TEXT PRIMARY KEY,
|
||||
content TEXT,
|
||||
meta TEXT,
|
||||
created_at REAL
|
||||
)
|
||||
""")
|
||||
conn.commit()
|
||||
conn.close()
|
||||
|
||||
def _init_ltm(self):
|
||||
"""Creates or verifies long-term memory table."""
|
||||
os.makedirs(os.path.dirname(self.long_db) or ".", exist_ok=True)
|
||||
conn = sqlite3.connect(self.long_db)
|
||||
c = conn.cursor()
|
||||
c.execute("""
|
||||
CREATE TABLE IF NOT EXISTS long_mem (
|
||||
id TEXT PRIMARY KEY,
|
||||
content TEXT,
|
||||
meta TEXT,
|
||||
created_at REAL
|
||||
)
|
||||
""")
|
||||
conn.commit()
|
||||
conn.close()
|
||||
|
||||
def _init_mem0(self):
|
||||
"""Initialize Mem0 client for agent or user memory."""
|
||||
from mem0 import MemoryClient
|
||||
mem_cfg = self.cfg.get("config", {})
|
||||
api_key = mem_cfg.get("api_key", os.getenv("MEM0_API_KEY"))
|
||||
org_id = mem_cfg.get("org_id")
|
||||
proj_id = mem_cfg.get("project_id")
|
||||
if org_id and proj_id:
|
||||
self.mem0_client = MemoryClient(api_key=api_key, org_id=org_id, project_id=proj_id)
|
||||
else:
|
||||
self.mem0_client = MemoryClient(api_key=api_key)
|
||||
|
||||
def _init_chroma(self):
|
||||
"""Initialize a local Chroma client for embedding-based search."""
|
||||
try:
|
||||
# Create directory if it doesn't exist
|
||||
rag_path = self.cfg.get("rag_db_path", "chroma_db")
|
||||
os.makedirs(rag_path, exist_ok=True)
|
||||
|
||||
# Initialize ChromaDB with persistent storage
|
||||
self.chroma_client = chromadb.PersistentClient(
|
||||
path=rag_path,
|
||||
settings=ChromaSettings(
|
||||
anonymized_telemetry=False,
|
||||
allow_reset=True
|
||||
)
|
||||
)
|
||||
|
||||
collection_name = "memory_store"
|
||||
try:
|
||||
self.chroma_col = self.chroma_client.get_collection(name=collection_name)
|
||||
self._log_verbose("Using existing ChromaDB collection")
|
||||
except Exception as e:
|
||||
self._log_verbose(f"Collection '{collection_name}' not found. Creating new collection. Error: {e}")
|
||||
self.chroma_col = self.chroma_client.create_collection(
|
||||
name=collection_name,
|
||||
metadata={"hnsw:space": "cosine"}
|
||||
)
|
||||
self._log_verbose("Created new ChromaDB collection")
|
||||
|
||||
except Exception as e:
|
||||
self._log_verbose(f"Failed to initialize ChromaDB: {e}", logging.ERROR)
|
||||
self.use_rag = False
|
||||
|
||||
# -------------------------------------------------------------------------
|
||||
# Basic Quality Score Computation
|
||||
# -------------------------------------------------------------------------
|
||||
def compute_quality_score(
|
||||
self,
|
||||
completeness: float,
|
||||
relevance: float,
|
||||
clarity: float,
|
||||
accuracy: float,
|
||||
weights: Dict[str, float] = None
|
||||
) -> float:
|
||||
"""
|
||||
Combine multiple sub-metrics into one final score, as an example.
|
||||
|
||||
Args:
|
||||
completeness (float): 0-1
|
||||
relevance (float): 0-1
|
||||
clarity (float): 0-1
|
||||
accuracy (float): 0-1
|
||||
weights (Dict[str, float]): optional weighting like {"completeness": 0.25, "relevance": 0.3, ...}
|
||||
|
||||
Returns:
|
||||
float: Weighted average 0-1
|
||||
"""
|
||||
if not weights:
|
||||
weights = {
|
||||
"completeness": 0.25,
|
||||
"relevance": 0.25,
|
||||
"clarity": 0.25,
|
||||
"accuracy": 0.25
|
||||
}
|
||||
total = (completeness * weights["completeness"]
|
||||
+ relevance * weights["relevance"]
|
||||
+ clarity * weights["clarity"]
|
||||
+ accuracy * weights["accuracy"]
|
||||
)
|
||||
return round(total, 3) # e.g. round to 3 decimal places
|
||||
|
||||
# -------------------------------------------------------------------------
|
||||
# Short-Term Methods
|
||||
# -------------------------------------------------------------------------
|
||||
def store_short_term(
|
||||
self,
|
||||
text: str,
|
||||
metadata: Dict[str, Any] = None,
|
||||
completeness: float = None,
|
||||
relevance: float = None,
|
||||
clarity: float = None,
|
||||
accuracy: float = None,
|
||||
weights: Dict[str, float] = None,
|
||||
evaluator_quality: float = None
|
||||
):
|
||||
"""Store in short-term memory with optional quality metrics"""
|
||||
logger.info(f"Storing in short-term memory: {text[:100]}...")
|
||||
logger.info(f"Metadata: {metadata}")
|
||||
|
||||
metadata = self._process_quality_metrics(
|
||||
metadata, completeness, relevance, clarity,
|
||||
accuracy, weights, evaluator_quality
|
||||
)
|
||||
logger.info(f"Processed metadata: {metadata}")
|
||||
|
||||
# Existing store logic
|
||||
try:
|
||||
conn = sqlite3.connect(self.short_db)
|
||||
ident = str(time.time_ns())
|
||||
conn.execute(
|
||||
"INSERT INTO short_mem (id, content, meta, created_at) VALUES (?,?,?,?)",
|
||||
(ident, text, json.dumps(metadata), time.time())
|
||||
)
|
||||
conn.commit()
|
||||
conn.close()
|
||||
logger.info(f"Successfully stored in short-term memory with ID: {ident}")
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to store in short-term memory: {e}")
|
||||
raise
|
||||
|
||||
def search_short_term(
|
||||
self,
|
||||
query: str,
|
||||
limit: int = 5,
|
||||
min_quality: float = 0.0,
|
||||
relevance_cutoff: float = 0.0
|
||||
) -> List[Dict[str, Any]]:
|
||||
"""Search short-term memory with optional quality filter"""
|
||||
self._log_verbose(f"Searching short memory for: {query}")
|
||||
|
||||
if self.use_mem0 and hasattr(self, "mem0_client"):
|
||||
results = self.mem0_client.search(query=query, limit=limit)
|
||||
filtered = [r for r in results if r.get("score", 1.0) >= relevance_cutoff]
|
||||
return filtered
|
||||
|
||||
elif self.use_rag and hasattr(self, "chroma_col"):
|
||||
try:
|
||||
from openai import OpenAI
|
||||
client = OpenAI()
|
||||
|
||||
response = client.embeddings.create(
|
||||
input=query,
|
||||
model="text-embedding-3-small"
|
||||
)
|
||||
query_embedding = response.data[0].embedding
|
||||
|
||||
resp = self.chroma_col.query(
|
||||
query_embeddings=[query_embedding],
|
||||
n_results=limit
|
||||
)
|
||||
|
||||
results = []
|
||||
if resp["ids"]:
|
||||
for i in range(len(resp["ids"][0])):
|
||||
metadata = resp["metadatas"][0][i] if "metadatas" in resp else {}
|
||||
quality = metadata.get("quality", 0.0)
|
||||
score = 1.0 - (resp["distances"][0][i] if "distances" in resp else 0.0)
|
||||
if quality >= min_quality and score >= relevance_cutoff:
|
||||
results.append({
|
||||
"id": resp["ids"][0][i],
|
||||
"text": resp["documents"][0][i],
|
||||
"metadata": metadata,
|
||||
"score": score
|
||||
})
|
||||
return results
|
||||
except Exception as e:
|
||||
self._log_verbose(f"Error searching ChromaDB: {e}", logging.ERROR)
|
||||
return []
|
||||
|
||||
else:
|
||||
# Local fallback
|
||||
conn = sqlite3.connect(self.short_db)
|
||||
c = conn.cursor()
|
||||
rows = c.execute(
|
||||
"SELECT id, content, meta FROM short_mem WHERE content LIKE ? LIMIT ?",
|
||||
(f"%{query}%", limit)
|
||||
).fetchall()
|
||||
conn.close()
|
||||
|
||||
results = []
|
||||
for row in rows:
|
||||
meta = json.loads(row[2] or "{}")
|
||||
quality = meta.get("quality", 0.0)
|
||||
if quality >= min_quality:
|
||||
results.append({
|
||||
"id": row[0],
|
||||
"text": row[1],
|
||||
"metadata": meta
|
||||
})
|
||||
return results
|
||||
|
||||
def reset_short_term(self):
|
||||
"""Completely clears short-term memory."""
|
||||
conn = sqlite3.connect(self.short_db)
|
||||
conn.execute("DELETE FROM short_mem")
|
||||
conn.commit()
|
||||
conn.close()
|
||||
|
||||
# -------------------------------------------------------------------------
|
||||
# Long-Term Methods
|
||||
# -------------------------------------------------------------------------
|
||||
def _sanitize_metadata(self, metadata: Dict) -> Dict:
|
||||
"""Sanitize metadata for ChromaDB - convert to acceptable types"""
|
||||
sanitized = {}
|
||||
for k, v in metadata.items():
|
||||
if v is None:
|
||||
continue
|
||||
if isinstance(v, (str, int, float, bool)):
|
||||
sanitized[k] = v
|
||||
elif isinstance(v, dict):
|
||||
# Convert dict to string representation
|
||||
sanitized[k] = str(v)
|
||||
else:
|
||||
# Convert other types to string
|
||||
sanitized[k] = str(v)
|
||||
return sanitized
|
||||
|
||||
def store_long_term(
|
||||
self,
|
||||
text: str,
|
||||
metadata: Dict[str, Any] = None,
|
||||
completeness: float = None,
|
||||
relevance: float = None,
|
||||
clarity: float = None,
|
||||
accuracy: float = None,
|
||||
weights: Dict[str, float] = None,
|
||||
evaluator_quality: float = None
|
||||
):
|
||||
"""Store in long-term memory with optional quality metrics"""
|
||||
logger.info(f"Storing in long-term memory: {text[:100]}...")
|
||||
logger.info(f"Initial metadata: {metadata}")
|
||||
|
||||
# Process metadata
|
||||
metadata = metadata or {}
|
||||
metadata = self._process_quality_metrics(
|
||||
metadata, completeness, relevance, clarity,
|
||||
accuracy, weights, evaluator_quality
|
||||
)
|
||||
logger.info(f"Processed metadata: {metadata}")
|
||||
|
||||
# Generate unique ID
|
||||
ident = str(time.time_ns())
|
||||
created = time.time()
|
||||
|
||||
# Store in SQLite
|
||||
try:
|
||||
conn = sqlite3.connect(self.long_db)
|
||||
conn.execute(
|
||||
"INSERT INTO long_mem (id, content, meta, created_at) VALUES (?,?,?,?)",
|
||||
(ident, text, json.dumps(metadata), created)
|
||||
)
|
||||
conn.commit()
|
||||
conn.close()
|
||||
logger.info(f"Successfully stored in SQLite with ID: {ident}")
|
||||
except Exception as e:
|
||||
logger.error(f"Error storing in SQLite: {e}")
|
||||
return
|
||||
|
||||
# Store in vector database if enabled
|
||||
if self.use_rag and hasattr(self, "chroma_col"):
|
||||
try:
|
||||
from openai import OpenAI
|
||||
client = OpenAI(api_key=os.getenv("OPENAI_API_KEY")) # Ensure API key is correctly set
|
||||
|
||||
logger.info("Getting embeddings from OpenAI...")
|
||||
logger.debug(f"Embedding input text: {text}") # Log the input text
|
||||
|
||||
response = client.embeddings.create(
|
||||
input=text,
|
||||
model="text-embedding-3-small"
|
||||
)
|
||||
embedding = response.data[0].embedding
|
||||
logger.info("Successfully got embeddings")
|
||||
logger.debug(f"Received embedding of length: {len(embedding)}") # Log embedding details
|
||||
|
||||
# Sanitize metadata for ChromaDB
|
||||
sanitized_metadata = self._sanitize_metadata(metadata)
|
||||
|
||||
# Store in ChromaDB with embedding
|
||||
self.chroma_col.add(
|
||||
documents=[text],
|
||||
metadatas=[sanitized_metadata],
|
||||
ids=[ident],
|
||||
embeddings=[embedding]
|
||||
)
|
||||
logger.info(f"Successfully stored in ChromaDB with ID: {ident}")
|
||||
except Exception as e:
|
||||
logger.error(f"Error storing in ChromaDB: {e}")
|
||||
|
||||
elif self.use_mem0 and hasattr(self, "mem0_client"):
|
||||
try:
|
||||
self.mem0_client.add(text, metadata=metadata)
|
||||
logger.info("Successfully stored in Mem0")
|
||||
except Exception as e:
|
||||
logger.error(f"Error storing in Mem0: {e}")
|
||||
|
||||
|
||||
def search_long_term(
|
||||
self,
|
||||
query: str,
|
||||
limit: int = 5,
|
||||
relevance_cutoff: float = 0.0,
|
||||
min_quality: float = 0.0
|
||||
) -> List[Dict[str, Any]]:
|
||||
"""Search long-term memory with optional quality filter"""
|
||||
self._log_verbose(f"Searching long memory for: {query}")
|
||||
self._log_verbose(f"Min quality: {min_quality}")
|
||||
|
||||
found = []
|
||||
|
||||
if self.use_mem0 and hasattr(self, "mem0_client"):
|
||||
results = self.mem0_client.search(query=query, limit=limit)
|
||||
# Filter by quality
|
||||
filtered = [r for r in results if r.get("metadata", {}).get("quality", 0.0) >= min_quality]
|
||||
logger.info(f"Found {len(filtered)} results in Mem0")
|
||||
return filtered
|
||||
|
||||
elif self.use_rag and hasattr(self, "chroma_col"):
|
||||
try:
|
||||
from openai import OpenAI
|
||||
client = OpenAI()
|
||||
|
||||
# Get query embedding
|
||||
response = client.embeddings.create(
|
||||
input=query,
|
||||
model="text-embedding-3-small" # Using consistent model
|
||||
)
|
||||
query_embedding = response.data[0].embedding
|
||||
|
||||
# Search ChromaDB with embedding
|
||||
resp = self.chroma_col.query(
|
||||
query_embeddings=[query_embedding],
|
||||
n_results=limit,
|
||||
include=["documents", "metadatas", "distances"]
|
||||
)
|
||||
|
||||
results = []
|
||||
if resp["ids"]:
|
||||
for i in range(len(resp["ids"][0])):
|
||||
metadata = resp["metadatas"][0][i] if "metadatas" in resp else {}
|
||||
text = resp["documents"][0][i]
|
||||
# Add memory record citation
|
||||
text = f"{text} (Memory record: {text})"
|
||||
found.append({
|
||||
"id": resp["ids"][0][i],
|
||||
"text": text,
|
||||
"metadata": metadata,
|
||||
"score": 1.0 - (resp["distances"][0][i] if "distances" in resp else 0.0)
|
||||
})
|
||||
logger.info(f"Found {len(found)} results in ChromaDB")
|
||||
|
||||
except Exception as e:
|
||||
self._log_verbose(f"Error searching ChromaDB: {e}", logging.ERROR)
|
||||
|
||||
# Always try SQLite as fallback or additional source
|
||||
conn = sqlite3.connect(self.long_db)
|
||||
c = conn.cursor()
|
||||
rows = c.execute(
|
||||
"SELECT id, content, meta, created_at FROM long_mem WHERE content LIKE ? LIMIT ?",
|
||||
(f"%{query}%", limit)
|
||||
).fetchall()
|
||||
conn.close()
|
||||
|
||||
for row in rows:
|
||||
meta = json.loads(row[2] or "{}")
|
||||
text = row[1]
|
||||
# Add memory record citation if not already present
|
||||
if "(Memory record:" not in text:
|
||||
text = f"{text} (Memory record: {text})"
|
||||
# Only add if not already found by ChromaDB/Mem0
|
||||
if not any(f["id"] == row[0] for f in found):
|
||||
found.append({
|
||||
"id": row[0],
|
||||
"text": text,
|
||||
"metadata": meta,
|
||||
"created_at": row[3]
|
||||
})
|
||||
logger.info(f"Found {len(found)} total results after SQLite")
|
||||
|
||||
results = found
|
||||
|
||||
# Filter by quality if needed
|
||||
if min_quality > 0:
|
||||
self._log_verbose(f"Found {len(results)} initial results")
|
||||
results = [
|
||||
r for r in results
|
||||
if r.get("metadata", {}).get("quality", 0.0) >= min_quality
|
||||
]
|
||||
self._log_verbose(f"After quality filter: {len(results)} results")
|
||||
|
||||
# Apply relevance cutoff if specified
|
||||
if relevance_cutoff > 0:
|
||||
results = [r for r in results if r.get("score", 1.0) >= relevance_cutoff]
|
||||
logger.info(f"After relevance filter: {len(results)} results")
|
||||
|
||||
return results[:limit]
|
||||
|
||||
def reset_long_term(self):
|
||||
"""Clear local LTM DB, plus Chroma or mem0 if in use."""
|
||||
conn = sqlite3.connect(self.long_db)
|
||||
conn.execute("DELETE FROM long_mem")
|
||||
conn.commit()
|
||||
conn.close()
|
||||
|
||||
if self.use_mem0 and hasattr(self, "mem0_client"):
|
||||
# Mem0 has no universal reset API. Could implement partial or no-op.
|
||||
pass
|
||||
if self.use_rag and hasattr(self, "chroma_client"):
|
||||
self.chroma_client.reset() # entire DB
|
||||
self._init_chroma() # re-init fresh
|
||||
|
||||
# -------------------------------------------------------------------------
|
||||
# Entity Memory Methods
|
||||
# -------------------------------------------------------------------------
|
||||
def store_entity(self, name: str, type_: str, desc: str, relations: str):
|
||||
"""
|
||||
Save entity info in LTM (or mem0/rag).
|
||||
We'll label the metadata type = entity for easy filtering.
|
||||
"""
|
||||
data = f"Entity {name}({type_}): {desc} | relationships: {relations}"
|
||||
self.store_long_term(data, metadata={"category": "entity"})
|
||||
|
||||
def search_entity(self, query: str, limit: int = 5) -> List[Dict[str, Any]]:
|
||||
"""
|
||||
Filter to items that have metadata 'category=entity'.
|
||||
"""
|
||||
all_hits = self.search_long_term(query, limit=20) # gather more
|
||||
ents = []
|
||||
for h in all_hits:
|
||||
meta = h.get("metadata") or {}
|
||||
if meta.get("category") == "entity":
|
||||
ents.append(h)
|
||||
return ents[:limit]
|
||||
|
||||
def reset_entity_only(self):
|
||||
"""
|
||||
If you only want to drop entity items from LTM, you'd do a custom
|
||||
delete from local DB where meta LIKE '%category=entity%'.
|
||||
For brevity, we do a full LTM reset here.
|
||||
"""
|
||||
self.reset_long_term()
|
||||
|
||||
# -------------------------------------------------------------------------
|
||||
# User Memory Methods
|
||||
# -------------------------------------------------------------------------
|
||||
def store_user_memory(self, user_id: str, text: str, extra: Dict[str, Any] = None):
|
||||
"""
|
||||
If mem0 is used, do user-based addition. Otherwise store in LTM with user in metadata.
|
||||
"""
|
||||
meta = {"user_id": user_id}
|
||||
if extra:
|
||||
meta.update(extra)
|
||||
|
||||
if self.use_mem0 and hasattr(self, "mem0_client"):
|
||||
self.mem0_client.add(text, user_id=user_id, metadata=meta)
|
||||
else:
|
||||
self.store_long_term(text, metadata=meta)
|
||||
|
||||
def search_user_memory(self, user_id: str, query: str, limit: int = 5) -> List[Dict[str, Any]]:
|
||||
"""
|
||||
If mem0 is used, pass user_id in. Otherwise fallback to local filter on user in metadata.
|
||||
"""
|
||||
if self.use_mem0 and hasattr(self, "mem0_client"):
|
||||
return self.mem0_client.search(query=query, limit=limit, user_id=user_id)
|
||||
else:
|
||||
hits = self.search_long_term(query, limit=20)
|
||||
filtered = []
|
||||
for h in hits:
|
||||
meta = h.get("metadata", {})
|
||||
if meta.get("user_id") == user_id:
|
||||
filtered.append(h)
|
||||
return filtered[:limit]
|
||||
|
||||
def reset_user_memory(self):
|
||||
"""
|
||||
Clear all user-based info. For simplicity, we do a full LTM reset.
|
||||
Real usage might filter only metadata "user_id".
|
||||
"""
|
||||
self.reset_long_term()
|
||||
|
||||
# -------------------------------------------------------------------------
|
||||
# Putting it all Together: Task Finalization
|
||||
# -------------------------------------------------------------------------
|
||||
def finalize_task_output(
|
||||
self,
|
||||
content: str,
|
||||
agent_name: str,
|
||||
quality_score: float,
|
||||
threshold: float = 0.7,
|
||||
metrics: Dict[str, Any] = None,
|
||||
task_id: str = None
|
||||
):
|
||||
"""Store task output in memory with appropriate metadata"""
|
||||
logger.info(f"Finalizing task output: {content[:100]}...")
|
||||
logger.info(f"Agent: {agent_name}, Quality: {quality_score}, Threshold: {threshold}")
|
||||
|
||||
metadata = {
|
||||
"task_id": task_id,
|
||||
"agent": agent_name,
|
||||
"quality": quality_score,
|
||||
"metrics": metrics,
|
||||
"task_type": "output",
|
||||
"stored_at": time.time()
|
||||
}
|
||||
logger.info(f"Prepared metadata: {metadata}")
|
||||
|
||||
# Always store in short-term memory
|
||||
try:
|
||||
logger.info("Storing in short-term memory...")
|
||||
self.store_short_term(
|
||||
text=content,
|
||||
metadata=metadata
|
||||
)
|
||||
logger.info("Successfully stored in short-term memory")
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to store in short-term memory: {e}")
|
||||
|
||||
# Store in long-term memory if quality meets threshold
|
||||
if quality_score >= threshold:
|
||||
try:
|
||||
logger.info(f"Quality score {quality_score} >= {threshold}, storing in long-term memory...")
|
||||
self.store_long_term(
|
||||
text=content,
|
||||
metadata=metadata
|
||||
)
|
||||
logger.info("Successfully stored in long-term memory")
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to store in long-term memory: {e}")
|
||||
else:
|
||||
logger.info(f"Quality score {quality_score} < {threshold}, skipping long-term storage")
|
||||
|
||||
# -------------------------------------------------------------------------
|
||||
# Building Context (Short, Long, Entities, User)
|
||||
# -------------------------------------------------------------------------
|
||||
def build_context_for_task(
|
||||
self,
|
||||
task_descr: str,
|
||||
user_id: Optional[str] = None,
|
||||
additional: str = "",
|
||||
max_items: int = 3
|
||||
) -> str:
|
||||
"""
|
||||
Merges relevant short-term, long-term, entity, user memories
|
||||
into a single text block with deduplication and clean formatting.
|
||||
"""
|
||||
q = (task_descr + " " + additional).strip()
|
||||
lines = []
|
||||
seen_contents = set() # Track unique contents
|
||||
|
||||
def normalize_content(content: str) -> str:
|
||||
"""Normalize content for deduplication"""
|
||||
# Extract just the main content without citations for comparison
|
||||
normalized = content.split("(Memory record:")[0].strip()
|
||||
# Keep more characters to reduce false duplicates
|
||||
normalized = ''.join(c.lower() for c in normalized if not c.isspace())
|
||||
return normalized
|
||||
|
||||
def format_content(content: str, max_len: int = 150) -> str:
|
||||
"""Format content with clean truncation at word boundaries"""
|
||||
if not content:
|
||||
return ""
|
||||
|
||||
# Clean up content by removing extra whitespace and newlines
|
||||
content = ' '.join(content.split())
|
||||
|
||||
# If content contains a memory citation, preserve it
|
||||
if "(Memory record:" in content:
|
||||
return content # Keep original citation format
|
||||
|
||||
# Regular content truncation
|
||||
if len(content) <= max_len:
|
||||
return content
|
||||
|
||||
truncate_at = content.rfind(' ', 0, max_len - 3)
|
||||
if truncate_at == -1:
|
||||
truncate_at = max_len - 3
|
||||
return content[:truncate_at] + "..."
|
||||
|
||||
def add_section(title: str, hits: List[Any]) -> None:
|
||||
"""Add a section of memory hits with deduplication"""
|
||||
if not hits:
|
||||
return
|
||||
|
||||
formatted_hits = []
|
||||
for h in hits:
|
||||
content = h.get('text', '') if isinstance(h, dict) else str(h)
|
||||
if not content:
|
||||
continue
|
||||
|
||||
# Keep original format if it has a citation
|
||||
if "(Memory record:" in content:
|
||||
formatted = content
|
||||
else:
|
||||
formatted = format_content(content)
|
||||
|
||||
# Only add if we haven't seen this normalized content before
|
||||
normalized = normalize_content(formatted)
|
||||
if normalized not in seen_contents:
|
||||
seen_contents.add(normalized)
|
||||
formatted_hits.append(formatted)
|
||||
|
||||
if formatted_hits:
|
||||
# Add section header
|
||||
if lines:
|
||||
lines.append("") # Space before new section
|
||||
lines.append(title)
|
||||
lines.append("=" * len(title)) # Underline the title
|
||||
lines.append("") # Space after title
|
||||
|
||||
# Add formatted content with bullet points
|
||||
for content in formatted_hits:
|
||||
lines.append(f" • {content}")
|
||||
|
||||
# Add each section
|
||||
# First get all results
|
||||
short_term = self.search_short_term(q, limit=max_items)
|
||||
long_term = self.search_long_term(q, limit=max_items)
|
||||
entities = self.search_entity(q, limit=max_items)
|
||||
user_mem = self.search_user_memory(user_id, q, limit=max_items) if user_id else []
|
||||
|
||||
# Add sections in order of priority
|
||||
add_section("Short-term Memory Context", short_term)
|
||||
add_section("Long-term Memory Context", long_term)
|
||||
add_section("Entity Context", entities)
|
||||
if user_id:
|
||||
add_section("User Context", user_mem)
|
||||
|
||||
return "\n".join(lines) if lines else ""
|
||||
|
||||
# -------------------------------------------------------------------------
|
||||
# Master Reset (Everything)
|
||||
# -------------------------------------------------------------------------
|
||||
def reset_all(self):
|
||||
"""
|
||||
Fully wipes short-term, long-term, and any memory in mem0 or rag.
|
||||
"""
|
||||
self.reset_short_term()
|
||||
self.reset_long_term()
|
||||
# Entities & user memory are stored in LTM or mem0, so no separate step needed.
|
||||
|
||||
def _process_quality_metrics(
|
||||
self,
|
||||
metadata: Dict[str, Any],
|
||||
completeness: float = None,
|
||||
relevance: float = None,
|
||||
clarity: float = None,
|
||||
accuracy: float = None,
|
||||
weights: Dict[str, float] = None,
|
||||
evaluator_quality: float = None
|
||||
) -> Dict[str, Any]:
|
||||
"""Process and store quality metrics in metadata"""
|
||||
metadata = metadata or {}
|
||||
|
||||
# Handle sub-metrics if provided
|
||||
if None not in [completeness, relevance, clarity, accuracy]:
|
||||
metadata.update({
|
||||
"completeness": completeness,
|
||||
"relevance": relevance,
|
||||
"clarity": clarity,
|
||||
"accuracy": accuracy,
|
||||
"quality": self.compute_quality_score(
|
||||
completeness, relevance, clarity, accuracy, weights
|
||||
)
|
||||
})
|
||||
# Handle external evaluator quality if provided
|
||||
elif evaluator_quality is not None:
|
||||
metadata["quality"] = evaluator_quality
|
||||
|
||||
return metadata
|
||||
|
||||
def calculate_quality_metrics(
|
||||
self,
|
||||
output: str,
|
||||
expected_output: str,
|
||||
llm: Optional[str] = None,
|
||||
custom_prompt: Optional[str] = None
|
||||
) -> Dict[str, float]:
|
||||
"""Calculate quality metrics using LLM"""
|
||||
logger.info("Calculating quality metrics for output")
|
||||
logger.info(f"Output: {output[:100]}...")
|
||||
logger.info(f"Expected: {expected_output[:100]}...")
|
||||
|
||||
# Default evaluation prompt
|
||||
default_prompt = f"""
|
||||
Evaluate the following output against expected output.
|
||||
Score each metric from 0.0 to 1.0:
|
||||
- Completeness: Does it address all requirements?
|
||||
- Relevance: Does it match expected output?
|
||||
- Clarity: Is it clear and well-structured?
|
||||
- Accuracy: Is it factually correct?
|
||||
|
||||
Expected: {expected_output}
|
||||
Actual: {output}
|
||||
|
||||
Return ONLY a JSON with these keys: completeness, relevance, clarity, accuracy
|
||||
Example: {{"completeness": 0.95, "relevance": 0.8, "clarity": 0.9, "accuracy": 0.85}}
|
||||
"""
|
||||
|
||||
try:
|
||||
# Use OpenAI client from main.py
|
||||
from ..main import client
|
||||
|
||||
response = client.chat.completions.create(
|
||||
model=llm or "gpt-4o",
|
||||
messages=[{
|
||||
"role": "user",
|
||||
"content": custom_prompt or default_prompt
|
||||
}],
|
||||
response_format={"type": "json_object"},
|
||||
temperature=0.3
|
||||
)
|
||||
|
||||
metrics = json.loads(response.choices[0].message.content)
|
||||
|
||||
# Validate metrics
|
||||
required = ["completeness", "relevance", "clarity", "accuracy"]
|
||||
if not all(k in metrics for k in required):
|
||||
raise ValueError("Missing required metrics in LLM response")
|
||||
|
||||
logger.info(f"Calculated metrics: {metrics}")
|
||||
return metrics
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Error calculating metrics: {e}")
|
||||
return {
|
||||
"completeness": 0.0,
|
||||
"relevance": 0.0,
|
||||
"clarity": 0.0,
|
||||
"accuracy": 0.0
|
||||
}
|
||||
|
||||
def store_quality(
|
||||
self,
|
||||
text: str,
|
||||
quality_score: float,
|
||||
task_id: Optional[str] = None,
|
||||
iteration: Optional[int] = None,
|
||||
metrics: Optional[Dict[str, float]] = None,
|
||||
memory_type: Literal["short", "long"] = "long"
|
||||
) -> None:
|
||||
"""Store quality metrics in memory"""
|
||||
logger.info(f"Attempting to store in {memory_type} memory: {text[:100]}...")
|
||||
|
||||
metadata = {
|
||||
"quality": quality_score,
|
||||
"task_id": task_id,
|
||||
"iteration": iteration
|
||||
}
|
||||
|
||||
if metrics:
|
||||
metadata.update({
|
||||
k: v for k, v in metrics.items() # Remove metric_ prefix
|
||||
})
|
||||
|
||||
logger.info(f"With metadata: {metadata}")
|
||||
|
||||
try:
|
||||
if memory_type == "short":
|
||||
self.store_short_term(text, metadata=metadata)
|
||||
logger.info("Successfully stored in short-term memory")
|
||||
else:
|
||||
self.store_long_term(text, metadata=metadata)
|
||||
logger.info("Successfully stored in long-term memory")
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to store in memory: {e}")
|
||||
|
||||
def search_with_quality(
|
||||
self,
|
||||
query: str,
|
||||
min_quality: float = 0.0,
|
||||
memory_type: Literal["short", "long"] = "long",
|
||||
limit: int = 5
|
||||
) -> List[Dict[str, Any]]:
|
||||
"""Search with quality filter"""
|
||||
logger.info(f"Searching {memory_type} memory for: {query}")
|
||||
logger.info(f"Min quality: {min_quality}")
|
||||
|
||||
search_func = (
|
||||
self.search_short_term if memory_type == "short"
|
||||
else self.search_long_term
|
||||
)
|
||||
|
||||
results = search_func(query, limit=limit)
|
||||
logger.info(f"Found {len(results)} initial results")
|
||||
|
||||
filtered = [
|
||||
r for r in results
|
||||
if r.get("metadata", {}).get("quality", 0.0) >= min_quality
|
||||
]
|
||||
logger.info(f"After quality filter: {len(filtered)} results")
|
||||
|
||||
return filtered
|
||||
@@ -5,19 +5,23 @@ from pydantic import BaseModel
|
||||
from ..agent.agent import Agent
|
||||
from ..task.task import Task
|
||||
from ..main import display_error, client
|
||||
import csv
|
||||
import os
|
||||
|
||||
class LoopItems(BaseModel):
|
||||
items: List[Any]
|
||||
|
||||
class Process:
|
||||
def __init__(self, tasks: Dict[str, Task], agents: List[Agent], manager_llm: Optional[str] = None, verbose: bool = False):
|
||||
def __init__(self, tasks: Dict[str, Task], agents: List[Agent], manager_llm: Optional[str] = None, verbose: bool = False, max_iter: int = 10):
|
||||
self.tasks = tasks
|
||||
self.agents = agents
|
||||
self.manager_llm = manager_llm
|
||||
self.verbose = verbose
|
||||
self.max_iter = max_iter
|
||||
|
||||
async def aworkflow(self) -> AsyncGenerator[str, None]:
|
||||
"""Async version of workflow method"""
|
||||
current_iter = 0 # Track how many times we've looped
|
||||
# Build workflow relationships first
|
||||
for task in self.tasks.values():
|
||||
if task.next_tasks:
|
||||
@@ -41,7 +45,12 @@ class Process:
|
||||
visited_tasks = set()
|
||||
loop_data = {} # Store loop-specific data
|
||||
|
||||
while current_task and current_task.id not in visited_tasks:
|
||||
while current_task:
|
||||
current_iter += 1
|
||||
if current_iter > self.max_iter:
|
||||
logging.info(f"Max iteration limit {self.max_iter} reached, ending workflow.")
|
||||
break
|
||||
|
||||
task_id = current_task.id
|
||||
logging.info(f"Executing workflow task: {current_task.name if current_task.name else task_id}")
|
||||
|
||||
@@ -55,46 +64,47 @@ class Process:
|
||||
if prev_task and prev_task.result:
|
||||
# Handle loop data
|
||||
if current_task.task_type == "loop":
|
||||
# create a loop manager Agent
|
||||
loop_manager = Agent(
|
||||
name="Loop Manager",
|
||||
role="Loop data processor",
|
||||
goal="Process loop data and convert it to list format",
|
||||
backstory="Expert at handling loop data and converting it to proper format",
|
||||
llm=self.manager_llm,
|
||||
verbose=self.verbose,
|
||||
markdown=True
|
||||
)
|
||||
# # create a loop manager Agent
|
||||
# loop_manager = Agent(
|
||||
# name="Loop Manager",
|
||||
# role="Loop data processor",
|
||||
# goal="Process loop data and convert it to list format",
|
||||
# backstory="Expert at handling loop data and converting it to proper format",
|
||||
# llm=self.manager_llm,
|
||||
# verbose=self.verbose,
|
||||
# markdown=True
|
||||
# )
|
||||
|
||||
# get the loop data convert it to list using calling Agent class chat
|
||||
loop_prompt = f"""
|
||||
Process this data into a list format:
|
||||
{prev_task.result.raw}
|
||||
# # get the loop data convert it to list using calling Agent class chat
|
||||
# loop_prompt = f"""
|
||||
# Process this data into a list format:
|
||||
# {prev_task.result.raw}
|
||||
|
||||
Return a JSON object with an 'items' array containing the items to process.
|
||||
"""
|
||||
if current_task.async_execution:
|
||||
loop_data_str = await loop_manager.achat(
|
||||
prompt=loop_prompt,
|
||||
output_json=LoopItems
|
||||
)
|
||||
else:
|
||||
loop_data_str = loop_manager.chat(
|
||||
prompt=loop_prompt,
|
||||
output_json=LoopItems
|
||||
)
|
||||
# Return a JSON object with an 'items' array containing the items to process.
|
||||
# """
|
||||
# if current_task.async_execution:
|
||||
# loop_data_str = await loop_manager.achat(
|
||||
# prompt=loop_prompt,
|
||||
# output_json=LoopItems
|
||||
# )
|
||||
# else:
|
||||
# loop_data_str = loop_manager.chat(
|
||||
# prompt=loop_prompt,
|
||||
# output_json=LoopItems
|
||||
# )
|
||||
|
||||
try:
|
||||
# The response will already be parsed into LoopItems model
|
||||
loop_data[f"loop_{current_task.name}"] = {
|
||||
"items": loop_data_str.items,
|
||||
"index": 0,
|
||||
"remaining": len(loop_data_str.items)
|
||||
}
|
||||
context += f"\nCurrent loop item: {loop_data_str.items[0]}"
|
||||
except Exception as e:
|
||||
display_error(f"Failed to process loop data: {e}")
|
||||
context += f"\n{prev_name}: {prev_task.result.raw}"
|
||||
# try:
|
||||
# # The response will already be parsed into LoopItems model
|
||||
# loop_data[f"loop_{current_task.name}"] = {
|
||||
# "items": loop_data_str.items,
|
||||
# "index": 0,
|
||||
# "remaining": len(loop_data_str.items)
|
||||
# }
|
||||
# context += f"\nCurrent loop item: {loop_data_str.items[0]}"
|
||||
# except Exception as e:
|
||||
# display_error(f"Failed to process loop data: {e}")
|
||||
# context += f"\n{prev_name}: {prev_task.result.raw}"
|
||||
context += f"\n{prev_name}: {prev_task.result.raw}"
|
||||
else:
|
||||
context += f"\n{prev_name}: {prev_task.result.raw}"
|
||||
|
||||
@@ -111,6 +121,11 @@ Return a JSON object with an 'items' array containing the items to process.
|
||||
yield task_id
|
||||
visited_tasks.add(task_id)
|
||||
|
||||
# Reset completed task to "not started" so it can run again
|
||||
if self.tasks[task_id].status == "completed":
|
||||
logging.debug(f"Task {task_id} was completed, resetting to 'not started' for next iteration.")
|
||||
self.tasks[task_id].status = "not started"
|
||||
|
||||
# Handle loop progression
|
||||
if current_task.task_type == "loop":
|
||||
loop_key = f"loop_{current_task.name}"
|
||||
@@ -130,22 +145,32 @@ Return a JSON object with an 'items' array containing the items to process.
|
||||
|
||||
# Determine next task based on result
|
||||
next_task = None
|
||||
if current_task.result:
|
||||
if current_task and current_task.result:
|
||||
if current_task.task_type in ["decision", "loop"]:
|
||||
result = current_task.result.raw.lower()
|
||||
# MINIMAL CHANGE: use pydantic decision if present
|
||||
decision_str = current_task.result.raw.lower()
|
||||
if current_task.result.pydantic and hasattr(current_task.result.pydantic, "decision"):
|
||||
decision_str = current_task.result.pydantic.decision.lower()
|
||||
|
||||
# Check conditions
|
||||
for condition, tasks in current_task.condition.items():
|
||||
if condition.lower() in result and tasks:
|
||||
next_task_name = tasks[0]
|
||||
if condition.lower() == decision_str:
|
||||
# Handle both list and direct string values
|
||||
task_value = tasks[0] if isinstance(tasks, list) else tasks
|
||||
if not task_value or task_value == "exit":
|
||||
logging.info("Workflow exit condition met, ending workflow")
|
||||
current_task = None
|
||||
break
|
||||
next_task_name = task_value
|
||||
next_task = next((t for t in self.tasks.values() if t.name == next_task_name), None)
|
||||
# For loops, allow revisiting the same task
|
||||
if next_task and next_task.id == current_task.id:
|
||||
visited_tasks.discard(current_task.id)
|
||||
break
|
||||
|
||||
if not next_task and current_task.next_tasks:
|
||||
next_task_name = current_task.next_tasks[0]
|
||||
next_task = next((t for t in self.tasks.values() if t.name == next_task_name), None)
|
||||
if not next_task and current_task and current_task.next_tasks:
|
||||
next_task_name = current_task.next_tasks[0]
|
||||
next_task = next((t for t in self.tasks.values() if t.name == next_task_name), None)
|
||||
|
||||
current_task = next_task
|
||||
if not current_task:
|
||||
@@ -285,6 +310,7 @@ Provide a JSON with the structure:
|
||||
|
||||
def workflow(self):
|
||||
"""Synchronous version of workflow method"""
|
||||
current_iter = 0 # Track how many times we've looped
|
||||
# Build workflow relationships first
|
||||
for task in self.tasks.values():
|
||||
if task.next_tasks:
|
||||
@@ -303,12 +329,86 @@ Provide a JSON with the structure:
|
||||
if not start_task:
|
||||
start_task = list(self.tasks.values())[0]
|
||||
logging.info("No start task marked, using first task")
|
||||
|
||||
|
||||
# If loop type and no input_file, default to tasks.csv
|
||||
if start_task and start_task.task_type == "loop" and not start_task.input_file:
|
||||
start_task.input_file = "tasks.csv"
|
||||
|
||||
# --- If loop + input_file, read file & create tasks
|
||||
if start_task and start_task.task_type == "loop" and getattr(start_task, "input_file", None):
|
||||
try:
|
||||
file_ext = os.path.splitext(start_task.input_file)[1].lower()
|
||||
new_tasks = []
|
||||
|
||||
if file_ext == ".csv":
|
||||
# existing CSV reading logic
|
||||
with open(start_task.input_file, "r", encoding="utf-8") as f:
|
||||
# Try as simple CSV first
|
||||
reader = csv.reader(f)
|
||||
previous_task = None
|
||||
for i, row in enumerate(reader):
|
||||
if row: # Skip empty rows
|
||||
task_desc = row[0] # Take first column
|
||||
row_task = Task(
|
||||
description=task_desc, # Keep full row as description
|
||||
agent=start_task.agent,
|
||||
name=task_desc, # Use first column as name
|
||||
is_start=(i == 0),
|
||||
task_type="task",
|
||||
condition={
|
||||
"complete": ["next"],
|
||||
"retry": ["current"]
|
||||
}
|
||||
)
|
||||
self.tasks[row_task.id] = row_task
|
||||
new_tasks.append(row_task)
|
||||
|
||||
if previous_task:
|
||||
previous_task.next_tasks = [row_task.name]
|
||||
previous_task.condition["complete"] = [row_task.name]
|
||||
previous_task = row_task
|
||||
else:
|
||||
# If not CSV, read lines
|
||||
with open(start_task.input_file, "r", encoding="utf-8") as f:
|
||||
lines = f.read().splitlines()
|
||||
previous_task = None
|
||||
for i, line in enumerate(lines):
|
||||
row_task = Task(
|
||||
description=line.strip(),
|
||||
agent=start_task.agent,
|
||||
name=line.strip(),
|
||||
is_start=(i == 0),
|
||||
task_type="task",
|
||||
condition={
|
||||
"complete": ["next"],
|
||||
"retry": ["current"]
|
||||
}
|
||||
)
|
||||
self.tasks[row_task.id] = row_task
|
||||
new_tasks.append(row_task)
|
||||
|
||||
if previous_task:
|
||||
previous_task.next_tasks = [row_task.name]
|
||||
previous_task.condition["complete"] = [row_task.name]
|
||||
previous_task = row_task
|
||||
|
||||
if new_tasks:
|
||||
start_task = new_tasks[0]
|
||||
logging.info(f"Created {len(new_tasks)} tasks from: {start_task.input_file}")
|
||||
except Exception as e:
|
||||
logging.error(f"Failed to read file tasks: {e}")
|
||||
|
||||
# end of the new block
|
||||
current_task = start_task
|
||||
visited_tasks = set()
|
||||
loop_data = {} # Store loop-specific data
|
||||
|
||||
while current_task and current_task.id not in visited_tasks:
|
||||
while current_task:
|
||||
current_iter += 1
|
||||
if current_iter > self.max_iter:
|
||||
logging.info(f"Max iteration limit {self.max_iter} reached, ending workflow.")
|
||||
break
|
||||
|
||||
task_id = current_task.id
|
||||
logging.info(f"Executing workflow task: {current_task.name if current_task.name else task_id}")
|
||||
|
||||
@@ -322,40 +422,41 @@ Provide a JSON with the structure:
|
||||
if prev_task and prev_task.result:
|
||||
# Handle loop data
|
||||
if current_task.task_type == "loop":
|
||||
# create a loop manager Agent
|
||||
loop_manager = Agent(
|
||||
name="Loop Manager",
|
||||
role="Loop data processor",
|
||||
goal="Process loop data and convert it to list format",
|
||||
backstory="Expert at handling loop data and converting it to proper format",
|
||||
llm=self.manager_llm,
|
||||
verbose=self.verbose,
|
||||
markdown=True
|
||||
)
|
||||
# # create a loop manager Agent
|
||||
# loop_manager = Agent(
|
||||
# name="Loop Manager",
|
||||
# role="Loop data processor",
|
||||
# goal="Process loop data and convert it to list format",
|
||||
# backstory="Expert at handling loop data and converting it to proper format",
|
||||
# llm=self.manager_llm,
|
||||
# verbose=self.verbose,
|
||||
# markdown=True
|
||||
# )
|
||||
|
||||
# get the loop data convert it to list using calling Agent class chat
|
||||
loop_prompt = f"""
|
||||
Process this data into a list format:
|
||||
{prev_task.result.raw}
|
||||
# # get the loop data convert it to list using calling Agent class chat
|
||||
# loop_prompt = f"""
|
||||
# Process this data into a list format:
|
||||
# {prev_task.result.raw}
|
||||
|
||||
Return a JSON object with an 'items' array containing the items to process.
|
||||
"""
|
||||
loop_data_str = loop_manager.chat(
|
||||
prompt=loop_prompt,
|
||||
output_json=LoopItems
|
||||
)
|
||||
# Return a JSON object with an 'items' array containing the items to process.
|
||||
# """
|
||||
# loop_data_str = loop_manager.chat(
|
||||
# prompt=loop_prompt,
|
||||
# output_json=LoopItems
|
||||
# )
|
||||
|
||||
try:
|
||||
# The response will already be parsed into LoopItems model
|
||||
loop_data[f"loop_{current_task.name}"] = {
|
||||
"items": loop_data_str.items,
|
||||
"index": 0,
|
||||
"remaining": len(loop_data_str.items)
|
||||
}
|
||||
context += f"\nCurrent loop item: {loop_data_str.items[0]}"
|
||||
except Exception as e:
|
||||
display_error(f"Failed to process loop data: {e}")
|
||||
context += f"\n{prev_name}: {prev_task.result.raw}"
|
||||
# try:
|
||||
# # The response will already be parsed into LoopItems model
|
||||
# loop_data[f"loop_{current_task.name}"] = {
|
||||
# "items": loop_data_str.items,
|
||||
# "index": 0,
|
||||
# "remaining": len(loop_data_str.items)
|
||||
# }
|
||||
# context += f"\nCurrent loop item: {loop_data_str.items[0]}"
|
||||
# except Exception as e:
|
||||
# display_error(f"Failed to process loop data: {e}")
|
||||
# context += f"\n{prev_name}: {prev_task.result.raw}"
|
||||
context += f"\n{prev_name}: {prev_task.result.raw}"
|
||||
else:
|
||||
context += f"\n{prev_name}: {prev_task.result.raw}"
|
||||
|
||||
@@ -372,6 +473,11 @@ Return a JSON object with an 'items' array containing the items to process.
|
||||
yield task_id
|
||||
visited_tasks.add(task_id)
|
||||
|
||||
# Reset completed task to "not started" so it can run again: Only for workflow because some tasks may be revisited
|
||||
if self.tasks[task_id].status == "completed":
|
||||
logging.debug(f"Task {task_id} was completed, resetting to 'not started' for next iteration.")
|
||||
self.tasks[task_id].status = "not started"
|
||||
|
||||
# Handle loop progression
|
||||
if current_task.task_type == "loop":
|
||||
loop_key = f"loop_{current_task.name}"
|
||||
@@ -391,22 +497,32 @@ Return a JSON object with an 'items' array containing the items to process.
|
||||
|
||||
# Determine next task based on result
|
||||
next_task = None
|
||||
if current_task.result:
|
||||
if current_task and current_task.result:
|
||||
if current_task.task_type in ["decision", "loop"]:
|
||||
result = current_task.result.raw.lower()
|
||||
# MINIMAL CHANGE: use pydantic decision if present
|
||||
decision_str = current_task.result.raw.lower()
|
||||
if current_task.result.pydantic and hasattr(current_task.result.pydantic, "decision"):
|
||||
decision_str = current_task.result.pydantic.decision.lower()
|
||||
|
||||
# Check conditions
|
||||
for condition, tasks in current_task.condition.items():
|
||||
if condition.lower() in result and tasks:
|
||||
next_task_name = tasks[0]
|
||||
if condition.lower() == decision_str:
|
||||
# Handle both list and direct string values
|
||||
task_value = tasks[0] if isinstance(tasks, list) else tasks
|
||||
if not task_value or task_value == "exit":
|
||||
logging.info("Workflow exit condition met, ending workflow")
|
||||
current_task = None
|
||||
break
|
||||
next_task_name = task_value
|
||||
next_task = next((t for t in self.tasks.values() if t.name == next_task_name), None)
|
||||
# For loops, allow revisiting the same task
|
||||
if next_task and next_task.id == current_task.id:
|
||||
visited_tasks.discard(current_task.id)
|
||||
break
|
||||
|
||||
if not next_task and current_task.next_tasks:
|
||||
next_task_name = current_task.next_tasks[0]
|
||||
next_task = next((t for t in self.tasks.values() if t.name == next_task_name), None)
|
||||
if not next_task and current_task and current_task.next_tasks:
|
||||
next_task_name = current_task.next_tasks[0]
|
||||
next_task = next((t for t in self.tasks.values() if t.name == next_task_name), None)
|
||||
|
||||
current_task = next_task
|
||||
if not current_task:
|
||||
|
||||
@@ -1,20 +1,25 @@
|
||||
import logging
|
||||
import asyncio
|
||||
from typing import List, Optional, Dict, Any, Type, Callable, Union, Coroutine
|
||||
from typing import List, Optional, Dict, Any, Type, Callable, Union, Coroutine, Literal
|
||||
from pydantic import BaseModel
|
||||
from ..main import TaskOutput
|
||||
from ..agent.agent import Agent
|
||||
import uuid
|
||||
import os
|
||||
import time
|
||||
|
||||
# Set up logger
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
class Task:
|
||||
def __init__(
|
||||
self,
|
||||
description: str,
|
||||
expected_output: str,
|
||||
expected_output: Optional[str] = None,
|
||||
agent: Optional[Agent] = None,
|
||||
name: Optional[str] = None,
|
||||
tools: Optional[List[Any]] = None,
|
||||
context: Optional[List["Task"]] = None,
|
||||
context: Optional[List[Union[str, List, 'Task']]] = None,
|
||||
async_execution: Optional[bool] = False,
|
||||
config: Optional[Dict[str, Any]] = None,
|
||||
output_file: Optional[str] = None,
|
||||
@@ -30,12 +35,16 @@ class Task:
|
||||
task_type: str = "task",
|
||||
condition: Optional[Dict[str, List[str]]] = None,
|
||||
is_start: bool = False,
|
||||
loop_state: Optional[Dict[str, Union[str, int]]] = None
|
||||
loop_state: Optional[Dict[str, Union[str, int]]] = None,
|
||||
memory=None,
|
||||
quality_check=True,
|
||||
input_file: Optional[str] = None
|
||||
):
|
||||
self.input_file = input_file
|
||||
self.id = str(uuid.uuid4()) if id is None else str(id)
|
||||
self.name = name
|
||||
self.description = description
|
||||
self.expected_output = expected_output
|
||||
self.expected_output = expected_output if expected_output is not None else "Complete the task successfully"
|
||||
self.agent = agent
|
||||
self.tools = tools if tools else []
|
||||
self.context = context if context else []
|
||||
@@ -54,6 +63,21 @@ class Task:
|
||||
self.condition = condition if condition else {}
|
||||
self.is_start = is_start
|
||||
self.loop_state = loop_state if loop_state else {}
|
||||
self.memory = memory
|
||||
self.quality_check = quality_check
|
||||
|
||||
# Set logger level based on config verbose level
|
||||
verbose = self.config.get("verbose", 0)
|
||||
if verbose >= 5:
|
||||
logger.setLevel(logging.INFO)
|
||||
else:
|
||||
logger.setLevel(logging.WARNING)
|
||||
|
||||
# Also set third-party loggers to WARNING
|
||||
logging.getLogger('chromadb').setLevel(logging.WARNING)
|
||||
logging.getLogger('openai').setLevel(logging.WARNING)
|
||||
logging.getLogger('httpx').setLevel(logging.WARNING)
|
||||
logging.getLogger('httpcore').setLevel(logging.WARNING)
|
||||
|
||||
if self.output_json and self.output_pydantic:
|
||||
raise ValueError("Only one output type can be defined")
|
||||
@@ -61,14 +85,210 @@ class Task:
|
||||
# Track previous tasks based on next_tasks relationships
|
||||
self.previous_tasks = []
|
||||
|
||||
# If task_type="decision" and output_pydantic is not set
|
||||
if self.task_type == "decision" and not self.output_pydantic:
|
||||
from pydantic import BaseModel
|
||||
from typing import Literal
|
||||
|
||||
# Gather condition keys for the "decision" field
|
||||
condition_keys = list(self.condition.keys())
|
||||
if not condition_keys:
|
||||
# Fall back to placeholders if nothing is specified
|
||||
condition_keys = ["next_task", "exit"]
|
||||
|
||||
# Create a dynamic literal type from condition keys
|
||||
DecisionLiteral = Literal.__getitem__(tuple(condition_keys))
|
||||
|
||||
class DecisionModel(BaseModel):
|
||||
response: str
|
||||
decision: DecisionLiteral
|
||||
|
||||
self.output_pydantic = DecisionModel
|
||||
|
||||
# If task_type="loop" and output_pydantic is not set
|
||||
if self.task_type == "loop" and not self.output_pydantic:
|
||||
from pydantic import BaseModel
|
||||
from typing import Literal
|
||||
|
||||
# Gather condition keys for the "decision" field
|
||||
condition_keys = list(self.condition.keys())
|
||||
if not condition_keys:
|
||||
# Fall back to placeholders if nothing is specified
|
||||
condition_keys = ["next_item", "exit"]
|
||||
|
||||
# Create a dynamic literal type
|
||||
LoopLiteral = Literal.__getitem__(tuple(condition_keys))
|
||||
|
||||
class LoopModel(BaseModel):
|
||||
response: str
|
||||
decision: LoopLiteral
|
||||
loop_id: str # Additional field for loop
|
||||
|
||||
self.output_pydantic = LoopModel
|
||||
|
||||
def __str__(self):
|
||||
return f"Task(name='{self.name if self.name else 'None'}', description='{self.description}', agent='{self.agent.name if self.agent else 'None'}', status='{self.status}')"
|
||||
|
||||
def initialize_memory(self):
|
||||
"""Initialize memory if config exists but memory doesn't"""
|
||||
if not self.memory and self.config.get('memory_config'):
|
||||
try:
|
||||
from ..memory.memory import Memory
|
||||
logger.info(f"Task {self.id}: Initializing memory from config: {self.config['memory_config']}")
|
||||
self.memory = Memory(config=self.config['memory_config'])
|
||||
logger.info(f"Task {self.id}: Memory initialized successfully")
|
||||
|
||||
# Verify database was created
|
||||
if os.path.exists(self.config['memory_config']['storage']['path']):
|
||||
logger.info(f"Task {self.id}: Memory database exists after initialization")
|
||||
else:
|
||||
logger.error(f"Task {self.id}: Failed to create memory database!")
|
||||
return self.memory
|
||||
except Exception as e:
|
||||
logger.error(f"Task {self.id}: Failed to initialize memory: {e}")
|
||||
logger.exception(e)
|
||||
return None
|
||||
|
||||
def store_in_memory(self, content: str, agent_name: str = None, task_id: str = None):
|
||||
"""Store content in memory with metadata"""
|
||||
if self.memory:
|
||||
try:
|
||||
logger.info(f"Task {self.id}: Storing content in memory...")
|
||||
self.memory.store_long_term(
|
||||
text=content,
|
||||
metadata={
|
||||
"agent_name": agent_name or "Agent",
|
||||
"task_id": task_id or self.id,
|
||||
"timestamp": time.time()
|
||||
}
|
||||
)
|
||||
logger.info(f"Task {self.id}: Content stored in memory")
|
||||
except Exception as e:
|
||||
logger.error(f"Task {self.id}: Failed to store content in memory: {e}")
|
||||
logger.exception(e)
|
||||
|
||||
async def execute_callback(self, task_output: TaskOutput) -> None:
|
||||
"""Execute the callback function, handling both sync and async callbacks"""
|
||||
"""Execute callback and store quality metrics if enabled"""
|
||||
logger.info(f"Task {self.id}: execute_callback called")
|
||||
logger.info(f"Quality check enabled: {self.quality_check}")
|
||||
|
||||
# Initialize memory if not already initialized
|
||||
if not self.memory:
|
||||
self.memory = self.initialize_memory()
|
||||
|
||||
logger.info(f"Memory object exists: {self.memory is not None}")
|
||||
if self.memory:
|
||||
logger.info(f"Memory config: {self.memory.cfg}")
|
||||
# Store task output in memory
|
||||
try:
|
||||
logger.info(f"Task {self.id}: Storing task output in memory...")
|
||||
self.store_in_memory(
|
||||
content=task_output.raw,
|
||||
agent_name=self.agent.name if self.agent else "Agent",
|
||||
task_id=self.id
|
||||
)
|
||||
logger.info(f"Task {self.id}: Task output stored in memory")
|
||||
except Exception as e:
|
||||
logger.error(f"Task {self.id}: Failed to store task output in memory: {e}")
|
||||
logger.exception(e)
|
||||
|
||||
logger.info(f"Task output: {task_output.raw[:100]}...")
|
||||
|
||||
if self.quality_check and self.memory:
|
||||
try:
|
||||
logger.info(f"Task {self.id}: Starting memory operations")
|
||||
logger.info(f"Task {self.id}: Calculating quality metrics for output: {task_output.raw[:100]}...")
|
||||
|
||||
# Get quality metrics from LLM
|
||||
metrics = self.memory.calculate_quality_metrics(
|
||||
task_output.raw,
|
||||
self.expected_output
|
||||
)
|
||||
logger.info(f"Task {self.id}: Quality metrics calculated: {metrics}")
|
||||
|
||||
quality_score = metrics.get("accuracy", 0.0)
|
||||
logger.info(f"Task {self.id}: Quality score: {quality_score}")
|
||||
|
||||
# Store in both short and long-term memory with higher threshold
|
||||
logger.info(f"Task {self.id}: Finalizing task output in memory...")
|
||||
self.memory.finalize_task_output(
|
||||
content=task_output.raw,
|
||||
agent_name=self.agent.name if self.agent else "Agent",
|
||||
quality_score=quality_score,
|
||||
threshold=0.7, # Only high quality outputs in long-term memory
|
||||
metrics=metrics,
|
||||
task_id=self.id
|
||||
)
|
||||
logger.info(f"Task {self.id}: Finalized task output in memory")
|
||||
|
||||
# Store quality metrics separately
|
||||
logger.info(f"Task {self.id}: Storing quality metrics...")
|
||||
self.memory.store_quality(
|
||||
text=task_output.raw,
|
||||
quality_score=quality_score,
|
||||
task_id=self.id,
|
||||
metrics=metrics
|
||||
)
|
||||
|
||||
# Store in both short and long-term memory with higher threshold
|
||||
self.memory.finalize_task_output(
|
||||
content=task_output.raw,
|
||||
agent_name=self.agent.name if self.agent else "Agent",
|
||||
quality_score=quality_score,
|
||||
threshold=0.7 # Only high quality outputs in long-term memory
|
||||
)
|
||||
|
||||
# Build context for next tasks
|
||||
if self.next_tasks:
|
||||
logger.info(f"Task {self.id}: Building context for next tasks...")
|
||||
context = self.memory.build_context_for_task(
|
||||
task_descr=task_output.raw,
|
||||
max_items=5
|
||||
)
|
||||
logger.info(f"Task {self.id}: Built context for next tasks: {len(context)} items")
|
||||
|
||||
logger.info(f"Task {self.id}: Memory operations complete")
|
||||
except Exception as e:
|
||||
logger.error(f"Task {self.id}: Failed to process memory operations: {e}")
|
||||
logger.exception(e) # Print full stack trace
|
||||
# Continue execution even if memory operations fail
|
||||
|
||||
# Execute original callback
|
||||
if self.callback:
|
||||
if asyncio.iscoroutinefunction(self.callback):
|
||||
await self.callback(task_output)
|
||||
else:
|
||||
loop = asyncio.get_event_loop()
|
||||
await loop.run_in_executor(None, self.callback, task_output)
|
||||
try:
|
||||
if asyncio.iscoroutinefunction(self.callback):
|
||||
await self.callback(task_output)
|
||||
else:
|
||||
self.callback(task_output)
|
||||
except Exception as e:
|
||||
logger.error(f"Task {self.id}: Failed to execute callback: {e}")
|
||||
logger.exception(e)
|
||||
|
||||
task_prompt = f"""
|
||||
You need to do the following task: {self.description}.
|
||||
Expected Output: {self.expected_output}.
|
||||
"""
|
||||
if self.context:
|
||||
context_results = [] # Use list to avoid duplicates
|
||||
for context_item in self.context:
|
||||
if isinstance(context_item, str):
|
||||
context_results.append(f"Input Content:\n{context_item}")
|
||||
elif isinstance(context_item, list):
|
||||
context_results.append(f"Input Content: {' '.join(str(x) for x in context_item)}")
|
||||
elif hasattr(context_item, 'result'): # Task object
|
||||
if context_item.result:
|
||||
context_results.append(
|
||||
f"Result of previous task {context_item.name if context_item.name else context_item.description}:\n{context_item.result.raw}"
|
||||
)
|
||||
else:
|
||||
context_results.append(
|
||||
f"Previous task {context_item.name if context_item.name else context_item.description} has no result yet."
|
||||
)
|
||||
|
||||
# Join unique context results
|
||||
unique_contexts = list(dict.fromkeys(context_results)) # Remove duplicates
|
||||
task_prompt += f"""
|
||||
Context:
|
||||
|
||||
{' '.join(unique_contexts)}
|
||||
"""
|
||||
@@ -160,6 +160,9 @@ class PandasTools:
|
||||
Dict: Summary statistics and information
|
||||
"""
|
||||
try:
|
||||
if not isinstance(df, pd.DataFrame):
|
||||
raise TypeError(f"Expected pandas DataFrame, got {type(df).__name__}")
|
||||
|
||||
numeric_summary = df.describe().to_dict()
|
||||
# Convert numpy types to native Python types
|
||||
for col in numeric_summary:
|
||||
|
||||
@@ -145,7 +145,15 @@ class YFinanceTools:
|
||||
return [{"error": "yfinance package not available"}]
|
||||
|
||||
hist = ticker.history(period=period, interval=interval, start=start, end=end)
|
||||
return hist.reset_index().to_dict('records')
|
||||
data = hist.reset_index().to_dict('records')
|
||||
|
||||
# Convert timestamps to ISO format strings
|
||||
for record in data:
|
||||
if 'Date' in record and hasattr(record['Date'], 'isoformat'):
|
||||
record['Date'] = record['Date'].isoformat()
|
||||
if 'Datetime' in record and hasattr(record['Datetime'], 'isoformat'):
|
||||
record['Datetime'] = record['Datetime'].isoformat()
|
||||
return data
|
||||
except Exception as e:
|
||||
error_msg = f"Error fetching historical data: {str(e)}"
|
||||
logging.error(error_msg)
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
from praisonaiagents import Agent, Tools
|
||||
from praisonaiagents.tools import execute_code, analyze_code, format_code, lint_code, disassemble_code # Code Tools
|
||||
from praisonaiagents.tools import execute_command, list_processes, kill_process, get_system_info # Shell Tools
|
||||
from praisonaiagents.tools import duckduckgo # Web Search Tool
|
||||
|
||||
agent = Agent(
|
||||
instructions="You are a Programming Agent", self_reflect=True, min_reflect=5, max_reflect=10,
|
||||
tools=[execute_code, analyze_code, format_code, lint_code, disassemble_code, execute_command, list_processes, kill_process, get_system_info, duckduckgo]
|
||||
)
|
||||
agent.start(
|
||||
"Write a python script using yfinance to find the stock price of Tesla"
|
||||
"First check if required packages are installed"
|
||||
"Run it using execute_code"
|
||||
"execute_command if you want to run any terminal command"
|
||||
"search internet using duckduckgo if you want to know update python package information"
|
||||
"Analyse the output using analyze_code and fix error if required"
|
||||
"if no package is installed, install it"
|
||||
"then run the code"
|
||||
)
|
||||
@@ -0,0 +1,91 @@
|
||||
from praisonaiagents.agent import Agent
|
||||
from praisonaiagents.task import Task
|
||||
from praisonaiagents.agents import PraisonAIAgents
|
||||
from typing import List, Dict
|
||||
import time
|
||||
|
||||
def get_time_check():
|
||||
current_time = int(time.time())
|
||||
result = "even" if current_time % 2 == 0 else "odd"
|
||||
print(f"Time check: {current_time} is {result}")
|
||||
return result
|
||||
|
||||
def create_prompt_chain():
|
||||
# Create agents for each step in the chain
|
||||
agent1 = Agent(
|
||||
name="Time Checker",
|
||||
role="Time checker",
|
||||
goal="Check if the time is even or odd",
|
||||
instructions="Check if the time is even or odd",
|
||||
tools=[get_time_check]
|
||||
)
|
||||
|
||||
agent2 = Agent(
|
||||
name="Advanced Analyzer",
|
||||
role="Advanced data analyzer",
|
||||
goal="Perform in-depth analysis of processed data",
|
||||
instructions="Analyze the processed data in detail"
|
||||
)
|
||||
|
||||
agent3 = Agent(
|
||||
name="Final Processor",
|
||||
role="Final data processor",
|
||||
goal="Generate final output based on analysis",
|
||||
instructions="Create final output based on analyzed data"
|
||||
)
|
||||
|
||||
# Create tasks for each step
|
||||
initial_task = Task(
|
||||
name="time_check",
|
||||
description="Getting time check and checking if it is even or odd",
|
||||
expected_output="Getting time check and checking if it is even or odd",
|
||||
agent=agent1,
|
||||
is_start=True, # Mark as the starting task
|
||||
task_type="decision", # This task will make a decision
|
||||
next_tasks=["advanced_analysis"], # Next task if condition passes
|
||||
condition={
|
||||
"even": ["advanced_analysis"], # If passes, go to advanced analysis
|
||||
"odd": ["final_processing"] # If fails, exit the chain
|
||||
}
|
||||
)
|
||||
|
||||
analysis_task = Task(
|
||||
name="advanced_analysis",
|
||||
description="Perform advanced analysis on the processed data",
|
||||
expected_output="Analyzed data ready for final processing",
|
||||
agent=agent2,
|
||||
next_tasks=["final_processing"]
|
||||
)
|
||||
|
||||
final_task = Task(
|
||||
name="final_processing",
|
||||
description="Generate final output",
|
||||
expected_output="Final processed result",
|
||||
agent=agent3
|
||||
)
|
||||
|
||||
# Create the workflow manager
|
||||
workflow = PraisonAIAgents(
|
||||
agents=[agent1, agent2, agent3],
|
||||
tasks=[initial_task, analysis_task, final_task],
|
||||
process="workflow", # Use workflow process type
|
||||
verbose=True
|
||||
)
|
||||
|
||||
return workflow
|
||||
|
||||
def main():
|
||||
# Create and run the prompt chain
|
||||
workflow = create_prompt_chain()
|
||||
|
||||
# Run the workflow
|
||||
results = workflow.start()
|
||||
|
||||
# Print results
|
||||
print("\nWorkflow Results:")
|
||||
for task_id, result in results["task_results"].items():
|
||||
if result:
|
||||
print(f"Task {task_id}: {result.raw}")
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,78 @@
|
||||
from praisonaiagents import Agent, Task, PraisonAIAgents
|
||||
import time
|
||||
|
||||
def get_time_check():
|
||||
current_time = int(time.time())
|
||||
result = "even" if current_time % 2 == 0 else "odd"
|
||||
print(f"Time check: {current_time} is {result}")
|
||||
return result
|
||||
|
||||
# Create agents for each step in the chain
|
||||
agent1 = Agent(
|
||||
name="Time Checker",
|
||||
role="Time checker",
|
||||
goal="Check if the time is even or odd",
|
||||
instructions="Check if the time is even or odd",
|
||||
tools=[get_time_check]
|
||||
)
|
||||
|
||||
agent2 = Agent(
|
||||
name="Advanced Analyzer",
|
||||
role="Advanced data analyzer",
|
||||
goal="Perform in-depth analysis of processed data",
|
||||
instructions="Analyze the processed data in detail"
|
||||
)
|
||||
|
||||
agent3 = Agent(
|
||||
name="Final Processor",
|
||||
role="Final data processor",
|
||||
goal="Generate final output based on analysis",
|
||||
instructions="Create final output based on analyzed data"
|
||||
)
|
||||
|
||||
# Create tasks for each step
|
||||
initial_task = Task(
|
||||
name="time_check",
|
||||
description="Getting time check and checking if it is even or odd",
|
||||
expected_output="Getting time check and checking if it is even or odd",
|
||||
agent=agent1,
|
||||
is_start=True, # Mark as the starting task
|
||||
task_type="decision", # This task will make a decision
|
||||
next_tasks=["advanced_analysis"], # Next task if condition passes
|
||||
condition={
|
||||
"even": ["advanced_analysis"], # If passes, go to advanced analysis
|
||||
"odd": "exit" # If fails, exit the chain
|
||||
}
|
||||
)
|
||||
|
||||
analysis_task = Task(
|
||||
name="advanced_analysis",
|
||||
description="Perform advanced analysis on the processed data",
|
||||
expected_output="Analyzed data ready for final processing",
|
||||
agent=agent2,
|
||||
next_tasks=["final_processing"]
|
||||
)
|
||||
|
||||
final_task = Task(
|
||||
name="final_processing",
|
||||
description="Generate final output",
|
||||
expected_output="Final processed result",
|
||||
agent=agent3
|
||||
)
|
||||
|
||||
# Create the workflow manager
|
||||
workflow = PraisonAIAgents(
|
||||
agents=[agent1, agent2, agent3],
|
||||
tasks=[initial_task, analysis_task, final_task],
|
||||
process="workflow", # Use workflow process type
|
||||
verbose=True
|
||||
)
|
||||
|
||||
# Run the workflow
|
||||
results = workflow.start()
|
||||
|
||||
# Print results
|
||||
print("\nWorkflow Results:")
|
||||
for task_id, result in results["task_results"].items():
|
||||
if result:
|
||||
print(f"Task {task_id}: {result.raw}")
|
||||
+20
-2
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
||||
|
||||
[project]
|
||||
name = "praisonaiagents"
|
||||
version = "0.0.28"
|
||||
version = "0.0.44"
|
||||
description = "Praison AI agents for completing complex tasks with Self Reflection Agents"
|
||||
authors = [
|
||||
{ name="Mervin Praison" }
|
||||
@@ -13,4 +13,22 @@ dependencies = [
|
||||
"pydantic",
|
||||
"rich",
|
||||
"openai"
|
||||
]
|
||||
]
|
||||
|
||||
[project.optional-dependencies]
|
||||
memory = [
|
||||
"chromadb>=0.5.23"
|
||||
]
|
||||
|
||||
knowledge = [
|
||||
"mem0ai>=0.1.0",
|
||||
"chromadb==0.5.23",
|
||||
"markitdown",
|
||||
"chonkie"
|
||||
]
|
||||
|
||||
# Combined features
|
||||
all = [
|
||||
"praisonaiagents[memory]",
|
||||
"praisonaiagents[knowledge]"
|
||||
]
|
||||
@@ -0,0 +1,5 @@
|
||||
from praisonaiagents import Agent, Tools
|
||||
from praisonaiagents.tools import duckduckgo
|
||||
|
||||
agent = Agent(instructions="You are a Recommendation Agent", tools=[duckduckgo])
|
||||
agent.start("Recommend me a good movie to watch in 2025")
|
||||
@@ -0,0 +1,22 @@
|
||||
from praisonaiagents import Agent, Task, PraisonAIAgents
|
||||
|
||||
agent = Agent(
|
||||
instructions="You are a loop agent that creating a loop of tasks.",
|
||||
llm="gpt-4o-mini"
|
||||
)
|
||||
|
||||
task = Task(
|
||||
description="Create the list of tasks to be looped through.",
|
||||
agent=agent,
|
||||
task_type="loop",
|
||||
input_file="tasks.csv"
|
||||
)
|
||||
|
||||
agents = PraisonAIAgents(
|
||||
agents=[agent],
|
||||
tasks=[task],
|
||||
process="workflow",
|
||||
max_iter=30
|
||||
)
|
||||
|
||||
agents.start()
|
||||
@@ -0,0 +1,139 @@
|
||||
from praisonaiagents import Agent, Task, PraisonAIAgents
|
||||
from praisonaiagents.tools import read_csv, write_csv
|
||||
import pandas as pd
|
||||
|
||||
def read_csv_smart(csv_path: str) -> pd.DataFrame:
|
||||
"""Read CSV and use first column as task, handling both header/no-header cases"""
|
||||
# Try reading with headers first
|
||||
df = pd.read_csv(csv_path)
|
||||
|
||||
# Check if first row looks like data
|
||||
if not any(col.lower() in ['task', 'description', 'status', 'state'] for col in df.columns):
|
||||
# If no header-like names found, read without headers
|
||||
df = pd.read_csv(csv_path, header=None)
|
||||
|
||||
# Rename columns consistently
|
||||
df.columns = [*['task'], *[f'col_{i}' for i in range(1, len(df.columns))]]
|
||||
if 'status' not in df.columns:
|
||||
df['status'] = 'pending'
|
||||
if 'loop_id' not in df.columns:
|
||||
# Start loop_id from 1 instead of 0
|
||||
df['loop_id'] = (df.index + 1).astype(str)
|
||||
return df[['task', 'status', 'loop_id']]
|
||||
|
||||
def has_pending_tasks(df: pd.DataFrame) -> bool:
|
||||
"""Check if there are any pending tasks in the DataFrame"""
|
||||
return not df[df['status'] == 'pending'].empty
|
||||
|
||||
def check_task_status(csv_path: str) -> dict:
|
||||
"""Read task status from CSV file"""
|
||||
try:
|
||||
# Always read directly from CSV file
|
||||
df = pd.read_csv(csv_path, keep_default_na=False)
|
||||
|
||||
# Get only pending tasks from original status
|
||||
pending_tasks = df[df['status'].str.lower() == 'pending']
|
||||
|
||||
if not pending_tasks.empty:
|
||||
task_data = pending_tasks.iloc[0].to_dict()
|
||||
return {
|
||||
'has_pending': True,
|
||||
'next_task': task_data
|
||||
}
|
||||
return {'has_pending': False, 'next_task': None}
|
||||
except Exception as e:
|
||||
print(f"Error reading CSV: {e}")
|
||||
return {'has_pending': False, 'next_task': None, 'error': str(e)}
|
||||
|
||||
def get_next_task() -> dict:
|
||||
"""Get the next pending task from CSV"""
|
||||
status = check_task_status("tasks.csv")
|
||||
if status['has_pending'] and status['next_task']:
|
||||
task = status['next_task']
|
||||
if task['status'].lower() == 'pending':
|
||||
return {
|
||||
'loop_data': {
|
||||
'task': task['task'],
|
||||
'loop_id': task['loop_id'],
|
||||
'status': task['status']
|
||||
}
|
||||
}
|
||||
return None
|
||||
|
||||
def update_task_status(loop_id: str, new_status: str) -> bool:
|
||||
"""Update task status in CSV file using loop_id as identifier"""
|
||||
try:
|
||||
# Read directly from CSV file
|
||||
df = pd.read_csv("tasks.csv", keep_default_na=False)
|
||||
df['loop_id'] = df['loop_id'].astype(str)
|
||||
mask = df['loop_id'] == str(loop_id)
|
||||
if mask.any():
|
||||
df.loc[mask, 'status'] = new_status
|
||||
df.to_csv("tasks.csv", index=False)
|
||||
return True
|
||||
print(f"No task found with loop_id: {loop_id}")
|
||||
return False
|
||||
except Exception as e:
|
||||
print(f"Error updating status: {e}")
|
||||
return False
|
||||
|
||||
identify_agent = Agent(
|
||||
name="Identify Agent",
|
||||
role="Pending Task Identifier",
|
||||
goal="Identify the next pending task",
|
||||
tools=[get_next_task],
|
||||
llm="gpt-4o-mini"
|
||||
)
|
||||
|
||||
# Create the repetitive agent
|
||||
repetitive_agent = Agent(
|
||||
name="TaskProcessor",
|
||||
role="Task Processing Specialist",
|
||||
goal="Complete the task response",
|
||||
llm="gpt-4o-mini"
|
||||
)
|
||||
|
||||
update_status_agent = Agent(
|
||||
name="UpdateStatusAgent",
|
||||
role="Status Updater",
|
||||
goal="Update the status of the task in CSV",
|
||||
tools=[update_task_status],
|
||||
llm="gpt-4o-mini"
|
||||
)
|
||||
|
||||
# Define the repetitive task
|
||||
identify_task = Task(
|
||||
name="identify_task",
|
||||
description="Identify the next pending task. If there are no pending tasks decision is completed.",
|
||||
agent=identify_agent,
|
||||
task_type="loop",
|
||||
condition={
|
||||
"pending": ["process_task"],
|
||||
"completed": "exit"
|
||||
}
|
||||
)
|
||||
|
||||
process_task = Task(
|
||||
name="process_task",
|
||||
description="Complete the task mentioned in the response",
|
||||
agent=repetitive_agent,
|
||||
context=[identify_task],
|
||||
task_type="loop",
|
||||
next_tasks=["update_task"]
|
||||
)
|
||||
|
||||
update_task = Task(
|
||||
name="update_task",
|
||||
description="Update the task status",
|
||||
agent=update_status_agent,
|
||||
next_tasks= ["identify_task"]
|
||||
)
|
||||
|
||||
# Create and run agents manager
|
||||
agents = PraisonAIAgents(
|
||||
agents=[identify_agent, repetitive_agent],
|
||||
tasks=[identify_task, process_task, update_task],
|
||||
process="workflow"
|
||||
)
|
||||
|
||||
agents.start()
|
||||
@@ -0,0 +1,15 @@
|
||||
# Core dependencies
|
||||
pydantic
|
||||
rich
|
||||
openai>=1.30.0
|
||||
|
||||
# Memory dependencies
|
||||
chromadb>=0.5.23
|
||||
|
||||
# Knowledge dependencies
|
||||
mem0ai>=0.1.0
|
||||
markitdown
|
||||
chonkie
|
||||
|
||||
# Development dependencies
|
||||
python-dotenv>=0.19.0
|
||||
@@ -0,0 +1,5 @@
|
||||
from praisonaiagents import Agent, Tools
|
||||
from praisonaiagents.tools import duckduckgo
|
||||
|
||||
agent = Agent(instructions="You are a Research Agent", tools=[duckduckgo])
|
||||
agent.start("Research about AI 2024")
|
||||
@@ -0,0 +1,82 @@
|
||||
from praisonaiagents.agent import Agent
|
||||
from praisonaiagents.task import Task
|
||||
from praisonaiagents.agents import PraisonAIAgents
|
||||
import time
|
||||
|
||||
current_time = int(time.time())
|
||||
result = "even" if current_time % 2 == 0 else "odd"
|
||||
print(f"Time check: {current_time} is {result}")
|
||||
|
||||
# Create specialized agents
|
||||
router = Agent(
|
||||
name="Router",
|
||||
role="Input Router",
|
||||
goal="Evaluate input and determine routing path",
|
||||
instructions="Analyze input and decide whether to proceed or exit",
|
||||
tools=[get_time_check]
|
||||
)
|
||||
|
||||
processor1 = Agent(
|
||||
name="Processor 1",
|
||||
role="Secondary Processor",
|
||||
goal="Process valid inputs that passed initial check",
|
||||
instructions="Process data that passed the routing check"
|
||||
)
|
||||
|
||||
processor2 = Agent(
|
||||
name="Processor 2",
|
||||
role="Final Processor",
|
||||
goal="Perform final processing on validated data",
|
||||
instructions="Generate final output for processed data"
|
||||
)
|
||||
|
||||
# Create tasks with routing logic
|
||||
routing_task = Task(
|
||||
name="initial_routing",
|
||||
description="check the time and return according to what is returned",
|
||||
expected_output="pass or fail based on what is returned",
|
||||
agent=router,
|
||||
is_start=True,
|
||||
task_type="decision",
|
||||
condition={
|
||||
"pass": ["process_valid"],
|
||||
"fail": "exit"
|
||||
}
|
||||
)
|
||||
|
||||
processing_task = Task(
|
||||
name="process_valid",
|
||||
description="Process validated input",
|
||||
expected_output="Processed data ready for final step",
|
||||
agent=processor1,
|
||||
next_tasks=["final_process"]
|
||||
)
|
||||
|
||||
final_task = Task(
|
||||
name="final_process",
|
||||
description="Generate final output",
|
||||
expected_output="Final processed result",
|
||||
agent=processor2
|
||||
)
|
||||
|
||||
# Create and run workflow
|
||||
workflow = PraisonAIAgents(
|
||||
agents=[router, processor1, processor2],
|
||||
tasks=[routing_task, processing_task, final_task],
|
||||
process="workflow",
|
||||
verbose=True
|
||||
)
|
||||
|
||||
print("\nStarting Routing Workflow...")
|
||||
print("=" * 50)
|
||||
|
||||
results = workflow.start()
|
||||
|
||||
print("\nWorkflow Results:")
|
||||
print("=" * 50)
|
||||
for task_id, result in results["task_results"].items():
|
||||
if result:
|
||||
task_name = result.description
|
||||
print(f"\nTask: {task_name}")
|
||||
print(f"Result: {result.raw}")
|
||||
print("-" * 50)
|
||||
@@ -0,0 +1,83 @@
|
||||
from praisonaiagents.agent import Agent
|
||||
from praisonaiagents.task import Task
|
||||
from praisonaiagents.agents import PraisonAIAgents
|
||||
import time
|
||||
|
||||
def get_time_check():
|
||||
current_time = int(time.time())
|
||||
result = "even" if current_time % 2 == 0 else "odd"
|
||||
print(f"Time check: {current_time} is {result}")
|
||||
return result
|
||||
|
||||
# Create specialized agents
|
||||
router = Agent(
|
||||
name="Router",
|
||||
role="Input Router",
|
||||
goal="Evaluate input and determine routing path",
|
||||
instructions="Analyze input and decide whether to proceed or exit",
|
||||
tools=[get_time_check]
|
||||
)
|
||||
|
||||
processor1 = Agent(
|
||||
name="Processor 1",
|
||||
role="Secondary Processor",
|
||||
goal="Process valid inputs that passed initial check",
|
||||
instructions="Process data that passed the routing check"
|
||||
)
|
||||
|
||||
processor2 = Agent(
|
||||
name="Processor 2",
|
||||
role="Final Processor",
|
||||
goal="Perform final processing on validated data",
|
||||
instructions="Generate final output for processed data"
|
||||
)
|
||||
|
||||
# Create tasks with routing logic
|
||||
routing_task = Task(
|
||||
name="initial_routing",
|
||||
description="check the time and return according to what is returned",
|
||||
expected_output="pass or fail based on what is returned",
|
||||
agent=router,
|
||||
is_start=True,
|
||||
task_type="decision",
|
||||
condition={
|
||||
"pass": ["process_valid"],
|
||||
"fail": ["process_invalid"]
|
||||
}
|
||||
)
|
||||
|
||||
processing_task = Task(
|
||||
name="process_valid",
|
||||
description="Process validated input",
|
||||
expected_output="Processed data ready for final step",
|
||||
agent=processor1,
|
||||
)
|
||||
|
||||
final_task = Task(
|
||||
name="process_invalid",
|
||||
description="Generate final output",
|
||||
expected_output="Final processed result",
|
||||
agent=processor2
|
||||
)
|
||||
|
||||
# Create and run workflow
|
||||
workflow = PraisonAIAgents(
|
||||
agents=[router, processor1, processor2],
|
||||
tasks=[routing_task, processing_task, final_task],
|
||||
process="workflow",
|
||||
verbose=True
|
||||
)
|
||||
|
||||
print("\nStarting Routing Workflow...")
|
||||
print("=" * 50)
|
||||
|
||||
results = workflow.start()
|
||||
|
||||
print("\nWorkflow Results:")
|
||||
print("=" * 50)
|
||||
for task_id, result in results["task_results"].items():
|
||||
if result:
|
||||
task_name = result.description
|
||||
print(f"\nTask: {task_name}")
|
||||
print(f"Result: {result.raw}")
|
||||
print("-" * 50)
|
||||
Binary file not shown.
@@ -0,0 +1,5 @@
|
||||
# Sample Markdown
|
||||
## Section 1
|
||||
This is a test markdown file.
|
||||
## Section 2
|
||||
It contains some formatted text and sections.
|
||||
@@ -0,0 +1,3 @@
|
||||
This is a sample text file.
|
||||
It contains multiple lines.
|
||||
This is for testing purposes.
|
||||
@@ -0,0 +1,5 @@
|
||||
from praisonaiagents import Agent, Tools
|
||||
from praisonaiagents.tools import duckduckgo
|
||||
|
||||
agent = Agent(instructions="You are a Shopping Agent", tools=[duckduckgo])
|
||||
agent.start("I want to buy iPhone 16 Pro Max, check 5 stores and give me price in table")
|
||||
@@ -0,0 +1,4 @@
|
||||
from praisonaiagents import Agent
|
||||
|
||||
agent = Agent(instructions="You are a Markdown Agent, output in markdown format")
|
||||
agent.start("Write a blog post about AI")
|
||||
Binary file not shown.
@@ -0,0 +1,21 @@
|
||||
import streamlit as st
|
||||
from praisonaiagents import Agent, Tools
|
||||
from praisonaiagents.tools import duckduckgo
|
||||
|
||||
st.title("AI Research Assistant")
|
||||
st.write("Enter your research query below to get started!")
|
||||
|
||||
# Initialize the research agent
|
||||
agent = Agent(instructions="You are a Research Agent", tools=[duckduckgo])
|
||||
|
||||
# Create the input field
|
||||
query = st.text_input("Research Query", placeholder="Enter your research topic...")
|
||||
|
||||
# Add a search button
|
||||
if st.button("Search"):
|
||||
if query:
|
||||
with st.spinner("Researching..."):
|
||||
result = agent.start(query)
|
||||
st.write(result)
|
||||
else:
|
||||
st.warning("Please enter a research query")
|
||||
Whitespace-only changes.
@@ -34,7 +34,8 @@ def get_structured_analysis(query: str, verbose: bool = True) -> AnalysisReport:
|
||||
backstory="Expert at gathering information and providing structured analysis",
|
||||
verbose=verbose,
|
||||
self_reflect=True, # Enable self-reflection for better quality
|
||||
markdown=True
|
||||
markdown=True,
|
||||
llm="gpt-4o-mini"
|
||||
)
|
||||
|
||||
# Create the analysis prompt
|
||||
@@ -71,7 +72,7 @@ Return ONLY the JSON object, no other text.
|
||||
output_json=AnalysisReport # This ensures response matches our model
|
||||
)
|
||||
|
||||
return AnalysisReport.parse_raw(response)
|
||||
return AnalysisReport.model_validate_json(response)
|
||||
|
||||
if __name__ == "__main__":
|
||||
# Example usage
|
||||
|
||||
@@ -0,0 +1,100 @@
|
||||
Write a product description for a smartwatch in 2 lines.
|
||||
Create a user manual for a blender in 2 lines.
|
||||
Draft an apology email for delayed delivery in 2 lines.
|
||||
Write a blog post on "Benefits of Meditation" in 2 lines.
|
||||
Create a privacy policy for a website in 2 lines.
|
||||
Write instructions for setting up a Wi-Fi router in 2 lines.
|
||||
Draft an email to follow up after a job interview in 2 lines.
|
||||
Create a FAQ page for an e-commerce store in 2 lines.
|
||||
Write an invitation email for a webinar in 2 lines.
|
||||
Create a terms and conditions page for an app in 2 lines.
|
||||
Write a press release for a product launch in 2 lines.
|
||||
Create a checklist for house cleaning tasks in 2 lines.
|
||||
Draft a resignation letter template in 2 lines.
|
||||
Write a cover letter for a software developer role in 2 lines.
|
||||
Create onboarding instructions for new employees in 2 lines.
|
||||
Write a memo announcing a new policy in a company in 2 lines.
|
||||
Create a safety guidelines document for a workplace in 2 lines.
|
||||
Write a pitch email to potential investors in 2 lines.
|
||||
Draft a thank-you email for attending a conference in 2 lines.
|
||||
Create a refund policy template for an online store in 2 lines.
|
||||
Write a blog on "How to Improve Time Management" in 2 lines.
|
||||
Create step-by-step instructions for changing a car tyre in 2 lines.
|
||||
Write a welcome email for new subscribers in 2 lines.
|
||||
Draft an event agenda template in 2 lines.
|
||||
Create a code of conduct for an online forum in 2 lines.
|
||||
Write a guide for beginners to start a blog in 2 lines.
|
||||
Create a checklist for organising a party in 2 lines.
|
||||
Draft an email to request a product review in 2 lines.
|
||||
Write a policy for remote work in a company in 2 lines.
|
||||
Create a simple tutorial for using Excel formulas in 2 lines.
|
||||
Write a thank-you letter for a donation in 2 lines.
|
||||
Draft a meeting minutes template in 2 lines.
|
||||
Create an FAQ for a gym membership in 2 lines.
|
||||
Write a blog post about "Healthy Snacks for Kids" in 2 lines.
|
||||
Create a guide for securing your social media accounts in 2 lines.
|
||||
Draft an email to request a testimonial from a client in 2 lines.
|
||||
Write a safety checklist for camping trips in 2 lines.
|
||||
Create a script for a customer service call in 2 lines.
|
||||
Write a tutorial for creating a simple PowerPoint presentation in 2 lines.
|
||||
Create a packing list for a beach vacation in 2 lines.
|
||||
Draft an email to cancel a service subscription in 2 lines.
|
||||
Write a personal statement for university admission in 2 lines.
|
||||
Create a template for tracking monthly expenses in 2 lines.
|
||||
Write a guide for planting and caring for succulents in 2 lines.
|
||||
Create a simple user guide for a mobile app in 2 lines.
|
||||
Draft an email to announce a team-building activity in 2 lines.
|
||||
Write a step-by-step guide for baking a cake in 2 lines.
|
||||
Create a list of house maintenance tasks in 2 lines.
|
||||
Draft a partnership proposal email in 2 lines.
|
||||
Write a guide for basic photography tips in 2 lines.
|
||||
Create a feedback form template for an online course in 2 lines.
|
||||
Write a blog on "Top 5 Budget Travel Destinations" in 2 lines.
|
||||
Draft a letter of recommendation for a colleague in 2 lines.
|
||||
Create a workout plan for beginners in 2 lines.
|
||||
Write a guide for troubleshooting common tech issues in 2 lines.
|
||||
Draft a reminder email for an upcoming appointment in 2 lines.
|
||||
Create a guide for setting personal goals in 2 lines.
|
||||
Write a blog post about "How to Start Freelancing" in 2 lines.
|
||||
Create a template for event planning in 2 lines.
|
||||
Draft an email to notify users about system maintenance in 2 lines.
|
||||
Write a guide for choosing the right laptop in 2 lines.
|
||||
Create a checklist for moving to a new house in 2 lines.
|
||||
Draft an email to update a client on project status in 2 lines.
|
||||
Write a guide for reducing screen time in 2 lines.
|
||||
Create a shopping list template for weekly groceries in 2 lines.
|
||||
Draft a thank-you email for completing a survey in 2 lines.
|
||||
Write a blog on "Simple DIY Crafts for Beginners" in 2 lines.
|
||||
Create a checklist for starting a small business in 2 lines.
|
||||
Draft an email to apologise for a customer complaint in 2 lines.
|
||||
Write a guide for setting up a personal budget in 2 lines.
|
||||
Create a policy for using company-provided equipment in 2 lines.
|
||||
Draft an email to notify about a price increase in 2 lines.
|
||||
Write a tutorial for creating a resume using Word in 2 lines.
|
||||
Create a simple guide for organising a charity event in 2 lines.
|
||||
Draft a formal invitation letter for a conference in 2 lines.
|
||||
Write a blog post about "Top Productivity Apps" in 2 lines.
|
||||
Create a checklist for first-time pet owners in 2 lines.
|
||||
Draft an email to confirm a service appointment in 2 lines.
|
||||
Write a beginner’s guide for learning to code in 2 lines.
|
||||
Create a guide for assembling a basic toolkit in 2 lines.
|
||||
Draft a welcome email for a new team member in 2 lines.
|
||||
Write a guide for preparing a home for winter in 2 lines.
|
||||
Create a schedule template for meal planning in 2 lines.
|
||||
Draft an email to request feedback from a customer in 2 lines.
|
||||
Write a guide on "How to Build a Morning Routine" in 2 lines.
|
||||
Create a checklist for hosting a virtual meeting in 2 lines.
|
||||
Draft a newsletter for a non-profit organisation in 2 lines.
|
||||
Write a guide for beginners to use Canva in 2 lines.
|
||||
Create a guide for organising your workspace in 2 lines.
|
||||
Draft an email to invite users to a beta program in 2 lines.
|
||||
Write a step-by-step guide for creating a podcast in 2 lines.
|
||||
Create a simple guide for buying your first car in 2 lines.
|
||||
Draft an email to announce a new team member in 2 lines.
|
||||
Write a tutorial on creating basic charts in Excel in 2 lines.
|
||||
Create a guide for teaching basic first aid in 2 lines.
|
||||
Draft an email to follow up after a sales call in 2 lines.
|
||||
Write a blog post on "How to Save Money on Utilities" in 2 lines.
|
||||
Create a guide for designing a basic website in 2 lines.
|
||||
Draft a thank-you email for a business referral in 2 lines.
|
||||
Write a guide for setting up a new smartphone in 2 lines.
|
||||
|
Can't render this file because it contains an unexpected character in line 4 and column 22.
|
@@ -0,0 +1,758 @@
|
||||
"date","close","volume","open","high","low"
|
||||
"11:34","270.49","4,787,699","264.50","273.88","262.24"
|
||||
"2018/10/15","259.5900","6189026.0000","259.0600","263.2800","254.5367"
|
||||
"2018/10/12","258.7800","7189257.0000","261.0000","261.9900","252.0100"
|
||||
"2018/10/11","252.2300","8128184.0000","257.5300","262.2500","249.0300"
|
||||
"2018/10/10","256.8800","12781560.0000","264.6100","265.5100","247.7700"
|
||||
"2018/10/09","262.8000","12037780.0000","255.2500","266.7700","253.3000"
|
||||
"2018/10/08","250.5600","13371180.0000","264.5200","267.7599","249.0000"
|
||||
"2018/10/05","261.9500","17900710.0000","274.6500","274.8800","260.0000"
|
||||
"2018/10/04","281.8300","9638885.0000","293.9500","294.0000","277.6700"
|
||||
"2018/10/03","294.8000","7982272.0000","303.3300","304.6000","291.5700"
|
||||
"2018/10/02","301.0200","11699690.0000","313.9500","316.8400","299.1500"
|
||||
"2018/10/01","310.7000","21714210.0000","305.7700","311.4400","301.0500"
|
||||
"2018/09/28","264.7700","33597290.0000","270.2600","278.0000","260.5550"
|
||||
"2018/09/27","307.5200","7337760.0000","312.9000","314.9600","306.9100"
|
||||
"2018/09/26","309.5800","7835863.0000","301.9100","313.8900","301.1093"
|
||||
"2018/09/25","300.9900","4472287.0000","300.0000","304.6000","296.5000"
|
||||
"2018/09/24","299.6800","4834384.0000","298.4800","302.9993","293.5800"
|
||||
"2018/09/21","299.1000","5038497.0000","297.7000","300.5800","295.3700"
|
||||
"2018/09/20","298.3300","7332477.0000","303.5600","305.9800","293.3300"
|
||||
"2018/09/19","299.0200","8264353.0000","280.5100","300.0000","280.5000"
|
||||
"2018/09/18","284.9600","16494280.0000","296.6900","302.6400","275.5000"
|
||||
"2018/09/17","294.8400","6866208.0000","290.0400","300.8700","288.1300"
|
||||
"2018/09/14","295.2000","6757652.0000","288.7600","297.3256","286.5200"
|
||||
"2018/09/13","289.4600","6333281.0000","288.0200","295.0000","285.1800"
|
||||
"2018/09/12","290.5400","10002150.0000","281.4400","292.5000","278.6463"
|
||||
"2018/09/11","279.4400","9161061.0000","279.4700","282.0000","273.5500"
|
||||
"2018/09/10","285.5000","14232250.0000","273.2600","286.0300","271.0000"
|
||||
"2018/09/07","263.2400","22442310.0000","260.1000","268.3500","252.2548"
|
||||
"2018/09/06","280.9500","7472756.0000","284.8000","291.1700","278.8800"
|
||||
"2018/09/05","280.7400","7707342.0000","285.0500","286.7800","277.1800"
|
||||
"2018/09/04","288.9500","8304571.0000","296.9400","298.1900","288.0000"
|
||||
"2018/08/31","301.6600","5367048.0000","302.0000","305.3082","298.6000"
|
||||
"2018/08/30","303.1500","7210625.0000","302.2600","304.6000","297.7200"
|
||||
"2018/08/29","305.0100","7410538.0000","310.2700","311.8500","303.6900"
|
||||
"2018/08/28","311.8600","7639453.0000","318.4100","318.8800","311.1900"
|
||||
"2018/08/27","319.2700","13062650.0000","318.0000","322.4350","308.8100"
|
||||
"2018/08/24","322.8200","3592734.0000","320.7000","323.8500","319.4000"
|
||||
"2018/08/23","320.1000","5138685.0000","319.1400","327.3200","318.1000"
|
||||
"2018/08/22","321.6400","5935853.0000","320.8700","323.8800","314.6700"
|
||||
"2018/08/21","321.9000","13147770.0000","310.6100","324.7900","309.0000"
|
||||
"2018/08/20","308.4400","17380430.0000","291.7040","308.5000","288.2000"
|
||||
"2018/08/17","305.5000","18895880.0000","323.5000","326.7700","303.5300"
|
||||
"2018/08/16","335.4500","6045392.0000","339.9100","342.2800","333.8200"
|
||||
"2018/08/15","338.6900","9073033.0000","341.9060","344.4900","332.1400"
|
||||
"2018/08/14","347.6400","6948511.0000","358.4500","359.1995","347.1000"
|
||||
"2018/08/13","356.4100","10444920.0000","361.1300","363.1900","349.0200"
|
||||
"2018/08/10","355.4900","11530510.0000","354.0000","360.0000","346.0000"
|
||||
"2018/08/09","352.4500","16951800.0000","365.5500","367.0100","345.7300"
|
||||
"2018/08/08","370.3400","24535420.0000","369.0900","382.6400","367.1200"
|
||||
"2018/08/07","379.5700","30596400.0000","343.8400","387.4600","339.1501"
|
||||
"2018/08/06","341.9900","8536766.0000","345.4600","354.9800","341.8200"
|
||||
"2018/08/03","348.1700","13646640.0000","347.8100","355.0000","342.5300"
|
||||
"2018/08/02","349.5400","23159160.0000","328.4400","349.9900","323.1600"
|
||||
"2018/08/01","300.8400","8768099.0000","297.9900","303.0000","293.0000"
|
||||
"2018/07/31","298.1400","5055094.0000","292.2500","298.3200","289.0700"
|
||||
"2018/07/30","290.1700","6799581.0000","295.9000","296.1000","286.1300"
|
||||
"2018/07/27","297.1800","5694690.0000","307.2500","307.6933","295.3404"
|
||||
"2018/07/26","306.6500","4619567.0000","304.8500","310.7000","303.6411"
|
||||
"2018/07/25","308.7400","7031382.0000","296.7400","309.6200","294.5025"
|
||||
"2018/07/24","297.4300","9586186.0000","304.4209","307.7171","292.5452"
|
||||
"2018/07/23","303.2000","10974820.0000","301.8400","305.5000","292.8601"
|
||||
"2018/07/20","313.5800","5159831.0000","321.2300","323.2400","311.7093"
|
||||
"2018/07/19","320.2300","5907116.0000","316.3300","323.5400","314.0100"
|
||||
"2018/07/18","323.8500","5610085.0000","325.0000","325.5000","316.2500"
|
||||
"2018/07/17","322.6900","6987782.0000","308.8100","324.7400","308.5000"
|
||||
"2018/07/16","310.1000","7800454.0000","311.7100","315.1600","306.2500"
|
||||
"2018/07/13","318.8700","5866776.0000","315.5800","319.5849","309.2500"
|
||||
"2018/07/12","316.7100","5711851.0000","321.4300","323.2300","312.7700"
|
||||
"2018/07/11","318.9600","4878595.0000","315.8000","321.9400","315.0700"
|
||||
"2018/07/10","322.4700","9437557.0000","324.5600","327.6771","319.2000"
|
||||
"2018/07/09","318.5100","7579541.0000","311.9900","318.5200","308.0000"
|
||||
"2018/07/06","308.9000","8860198.0000","304.9550","312.0700","302.0000"
|
||||
"2018/07/05","309.1600","17457570.0000","313.7600","314.3900","296.2200"
|
||||
"2018/07/03","310.8600","12282640.0000","331.7500","332.4900","309.6900"
|
||||
"2018/07/02","335.0700","18732710.0000","360.0700","364.7800","329.8500"
|
||||
"2018/06/29","342.9500","6475903.0000","353.3300","353.8600","342.4100"
|
||||
"2018/06/28","349.9300","8388172.0000","348.6600","357.0200","346.1100"
|
||||
"2018/06/27","344.5000","8313817.0000","345.0000","350.7900","339.5000"
|
||||
"2018/06/26","342.0000","7434749.0000","336.0540","343.5500","325.7990"
|
||||
"2018/06/25","333.0100","6925089.0000","330.1200","338.4700","327.5000"
|
||||
"2018/06/22","333.6300","10253770.0000","351.5400","352.2500","332.0000"
|
||||
"2018/06/21","347.5100","7949846.0000","362.0000","366.2139","346.2700"
|
||||
"2018/06/20","362.2200","8370268.0000","358.0400","364.3800","352.0000"
|
||||
"2018/06/19","352.5500","12734840.0000","365.1600","370.0000","346.2500"
|
||||
"2018/06/18","370.8300","12025450.0000","355.4000","373.7300","354.5000"
|
||||
"2018/06/15","358.1700","10827560.0000","353.8400","364.6700","351.2500"
|
||||
"2018/06/14","357.7200","10961150.0000","347.6300","358.7500","346.6000"
|
||||
"2018/06/13","344.7800","9401467.0000","346.7060","347.2000","339.8000"
|
||||
"2018/06/12","342.7700","22256430.0000","344.7000","354.9700","338.0000"
|
||||
"2018/06/11","332.1000","13166050.0000","322.5100","334.6600","322.5000"
|
||||
"2018/06/08","317.6600","8192175.0000","319.0000","324.4800","317.1500"
|
||||
"2018/06/07","316.0900","14336110.0000","316.1500","330.0000","313.5800"
|
||||
"2018/06/06","319.5000","18742400.0000","300.5000","322.1700","297.4800"
|
||||
"2018/06/05","291.1300","5877873.0000","297.7000","297.8000","286.7400"
|
||||
"2018/06/04","296.7400","4793787.0000","294.3400","299.0000","293.5480"
|
||||
"2018/06/01","291.8200","5417984.0000","285.8600","291.9500","283.8390"
|
||||
"2018/05/31","284.7300","5912825.0000","287.2100","290.3700","282.9300"
|
||||
"2018/05/30","291.7200","7473590.0000","283.2900","295.0050","281.6000"
|
||||
"2018/05/29","283.7600","5657153.0000","278.5100","286.5000","276.1500"
|
||||
"2018/05/25","278.8500","3872621.0000","277.6250","279.6400","275.6100"
|
||||
"2018/05/24","277.8500","4170789.0000","278.4000","281.1100","274.8900"
|
||||
"2018/05/23","279.0700","5972237.0000","277.7600","279.9099","274.0000"
|
||||
"2018/05/22","275.0100","8938501.0000","287.7620","288.0000","273.4220"
|
||||
"2018/05/21","284.4900","9167844.0000","281.3300","291.4900","281.3000"
|
||||
"2018/05/18","276.8200","7243699.0000","284.6500","284.6500","274.0000"
|
||||
"2018/05/17","284.5400","4418258.0000","285.9000","289.1873","283.9700"
|
||||
"2018/05/16","286.4800","5669644.0000","283.8300","288.8100","281.5600"
|
||||
"2018/05/15","284.1800","9509753.0000","285.0100","286.9600","280.5000"
|
||||
"2018/05/14","291.9700","7265501.0000","303.3200","304.9400","291.6200"
|
||||
"2018/05/11","301.0600","4665321.0000","307.7000","308.8800","299.0800"
|
||||
"2018/05/10","305.0200","5642771.0000","307.4997","312.9900","304.1119"
|
||||
"2018/05/09","306.8500","5712255.0000","300.4100","307.0100","300.0500"
|
||||
"2018/05/08","301.9700","5927447.0000","300.7950","307.7500","299.0000"
|
||||
"2018/05/07","302.7700","8673090.0000","297.5000","305.9588","295.1700"
|
||||
"2018/05/04","294.0900","8565506.0000","283.0000","296.8600","279.5200"
|
||||
"2018/05/03","284.4500","17339090.0000","278.7900","288.0400","275.2300"
|
||||
"2018/05/02","301.1500","8346176.0000","298.5700","306.8500","297.7844"
|
||||
"2018/05/01","299.9200","4614946.0000","293.5100","300.8200","293.2200"
|
||||
"2018/04/30","293.9000","4224068.0000","293.6100","298.7300","292.5000"
|
||||
"2018/04/27","294.0750","4346854.0000","285.3700","294.4700","283.8300"
|
||||
"2018/04/26","285.4800","4348108.0000","278.7500","285.7900","276.5000"
|
||||
"2018/04/25","280.6900","4000421.0000","283.5000","285.1600","277.2500"
|
||||
"2018/04/24","283.4600","5678242.0000","285.0000","287.0900","278.4600"
|
||||
"2018/04/23","283.3700","4880743.0000","291.2900","291.6200","282.3300"
|
||||
"2018/04/20","290.2400","5622630.0000","295.1700","299.9800","289.7500"
|
||||
"2018/04/19","300.0800","6083800.0000","291.0800","301.0100","288.5500"
|
||||
"2018/04/18","293.3500","6531563.0000","291.0800","300.2400","288.1600"
|
||||
"2018/04/17","287.6900","6931152.0000","288.8700","292.1700","282.5100"
|
||||
"2018/04/16","291.2100","6289497.0000","299.0000","299.6600","289.0100"
|
||||
"2018/04/13","300.3400","7319225.0000","303.6000","303.9499","295.9800"
|
||||
"2018/04/12","294.0800","7595525.0000","302.3200","303.9500","293.6800"
|
||||
"2018/04/11","300.9300","7470204.0000","300.7400","308.9800","299.6600"
|
||||
"2018/04/10","304.7000","11017010.0000","298.9700","307.1000","293.6800"
|
||||
"2018/04/09","289.6600","10241410.0000","300.3700","309.5000","289.2100"
|
||||
"2018/04/06","299.3000","13516530.0000","301.0000","309.2800","295.5000"
|
||||
"2018/04/05","305.7200","19025860.0000","289.3400","306.2600","288.2000"
|
||||
"2018/04/04","286.9400","19880180.0000","252.7800","288.3700","252.0000"
|
||||
"2018/04/03","267.5300","18829650.0000","269.8200","273.3500","254.4900"
|
||||
"2018/04/02","252.4800","16093290.0000","256.2600","260.3318","244.5901"
|
||||
"2018/03/29","266.1300","15014440.0000","256.4900","270.9599","248.2100"
|
||||
"2018/03/28","257.7800","20962280.0000","264.5800","268.6800","252.1000"
|
||||
"2018/03/27","279.1800","13787060.0000","304.0000","304.2700","277.1800"
|
||||
"2018/03/26","304.1800","8364937.0000","307.3400","307.5900","291.3600"
|
||||
"2018/03/23","301.5400","6639960.0000","311.2500","311.6100","300.4500"
|
||||
"2018/03/22","309.1000","4924928.0000","313.8900","318.8200","308.1800"
|
||||
"2018/03/21","316.5300","5954247.0000","310.2500","322.4400","310.1900"
|
||||
"2018/03/20","310.5500","4761031.0000","314.8700","316.2500","308.7600"
|
||||
"2018/03/19","313.5600","7467890.0000","316.5000","320.7500","309.6700"
|
||||
"2018/03/16","321.3500","6113365.0000","325.9600","327.4000","319.0700"
|
||||
"2018/03/15","325.6000","6554568.0000","329.3800","332.8500","321.1000"
|
||||
"2018/03/14","326.6300","7952152.0000","336.7600","339.8100","323.9300"
|
||||
"2018/03/13","341.8400","5960636.0000","344.9200","345.1200","336.2635"
|
||||
"2018/03/12","345.5100","8252919.0000","328.6100","347.2100","326.5000"
|
||||
"2018/03/09","327.1700","5502779.0000","324.1000","328.4900","322.3700"
|
||||
"2018/03/08","329.1000","3514367.0000","332.8600","333.3000","326.2740"
|
||||
"2018/03/07","332.3000","5001940.0000","325.4400","332.5000","321.7400"
|
||||
"2018/03/06","328.2000","4236483.0000","333.7500","336.3700","327.0300"
|
||||
"2018/03/05","333.3500","3820702.0000","332.3900","337.7500","329.2929"
|
||||
"2018/03/02","335.1200","5088789.0000","326.9800","335.2200","322.9700"
|
||||
"2018/03/01","330.9300","6872552.0000","345.0100","348.6700","330.0700"
|
||||
"2018/02/28","343.0600","6066044.0000","352.5700","355.2400","342.2200"
|
||||
"2018/02/27","350.9900","4785022.0000","356.2500","359.9900","350.0100"
|
||||
"2018/02/26","357.4200","4334500.0000","353.5000","359.0000","352.3550"
|
||||
"2018/02/23","352.0500","5814177.0000","347.8300","354.9900","347.1000"
|
||||
"2018/02/22","346.1700","6961880.0000","335.5300","347.4400","334.7501"
|
||||
"2018/02/21","333.3000","3207250.0000","336.0300","339.6929","333.1700"
|
||||
"2018/02/20","334.7700","4005962.0000","334.4700","340.8400","331.5000"
|
||||
"2018/02/16","335.4900","5640184.0000","332.5000","343.1200","331.6400"
|
||||
"2018/02/15","334.0650","5909823.0000","324.5000","334.1200","322.4000"
|
||||
"2018/02/14","322.3100","3948077.0000","320.8400","326.1700","318.5200"
|
||||
"2018/02/13","323.6600","4554631.0000","315.0200","324.1900","312.5105"
|
||||
"2018/02/12","315.7300","6224479.0000","316.1300","318.0800","306.2500"
|
||||
"2018/02/09","310.4200","12924430.0000","319.9300","320.9845","294.7600"
|
||||
"2018/02/08","315.2300","10296420.0000","343.3100","348.6200","314.6000"
|
||||
"2018/02/07","345.0000","6729682.0000","338.9900","346.0000","335.6600"
|
||||
"2018/02/06","333.9700","5080032.0000","325.2100","336.2200","323.5000"
|
||||
"2018/02/05","333.1300","4441166.0000","337.9700","344.4700","333.0000"
|
||||
"2018/02/02","343.7500","3696157.0000","348.4400","351.9500","340.5100"
|
||||
"2018/02/01","349.2500","4187440.0000","351.0000","359.6600","348.6300"
|
||||
"2018/01/31","354.3100","6199373.0000","347.5100","356.1900","345.1900"
|
||||
"2018/01/30","345.8200","4710684.0000","345.1400","348.2700","342.1700"
|
||||
"2018/01/29","349.5300","4738208.0000","339.8500","350.8500","338.2800"
|
||||
"2018/01/26","342.8500","4535457.0000","341.5000","344.0000","335.7100"
|
||||
"2018/01/25","337.6400","6725208.0000","348.2700","349.2000","336.4000"
|
||||
"2018/01/24","345.8900","5277386.0000","354.5800","354.7500","343.5200"
|
||||
"2018/01/23","352.7900","5447622.0000","360.0000","360.5000","351.0000"
|
||||
"2018/01/22","351.5600","6199777.0000","349.4000","357.8300","349.2000"
|
||||
"2018/01/19","350.0200","4871181.0000","345.0000","350.5899","342.6000"
|
||||
"2018/01/18","344.5700","5679629.0000","345.6700","352.3000","343.7400"
|
||||
"2018/01/17","347.1600","7092554.0000","340.4700","349.0000","339.7500"
|
||||
"2018/01/16","340.0600","6429234.0000","337.5400","345.0000","334.8000"
|
||||
"2018/01/12","336.2200","4822509.0000","338.6300","340.4100","333.6700"
|
||||
"2018/01/11","337.9500","6640863.0000","335.2400","344.8099","333.2600"
|
||||
"2018/01/10","334.8000","4303053.0000","332.2000","337.0000","330.0000"
|
||||
"2018/01/09","333.6900","7134525.0000","335.1600","338.8000","327.4050"
|
||||
"2018/01/08","336.4100","9832610.0000","316.0000","337.0199","315.5000"
|
||||
"2018/01/05","316.5800","4588728.0000","316.6200","317.2400","312.0000"
|
||||
"2018/01/04","314.6200","9944593.0000","312.8700","318.5500","305.6800"
|
||||
"2018/01/03","317.2500","4438520.0000","321.0000","325.2500","315.5500"
|
||||
"2018/01/02","320.5300","4345615.0000","312.0000","322.1099","311.0000"
|
||||
"2017/12/29","311.3500","3769504.0000","316.1800","316.4100","310.0000"
|
||||
"2017/12/28","315.3600","4306746.0000","311.7500","315.8200","309.5400"
|
||||
"2017/12/27","311.6400","4705084.0000","316.0000","317.6800","310.7500"
|
||||
"2017/12/26","317.2900","4368699.0000","323.8300","323.9400","316.5800"
|
||||
"2017/12/22","325.2000","4207602.0000","329.5100","330.9214","324.8200"
|
||||
"2017/12/21","331.6600","4369994.0000","329.5900","333.7400","327.2100"
|
||||
"2017/12/20","328.9800","5907378.0000","332.6900","333.1000","325.0400"
|
||||
"2017/12/19","331.1000","6820868.0000","340.2600","341.4925","330.3000"
|
||||
"2017/12/18","338.8700","5466546.0000","344.9000","346.7300","337.5800"
|
||||
"2017/12/15","343.4500","6921246.0000","342.0400","343.9000","335.7600"
|
||||
"2017/12/14","337.8900","5792024.0000","341.0100","347.4400","336.9000"
|
||||
"2017/12/13","339.0300","6217701.0000","340.9300","344.2200","336.5000"
|
||||
"2017/12/12","341.0300","8715570.0000","330.4500","341.4400","330.0300"
|
||||
"2017/12/11","328.9100","7926090.0000","314.6300","329.0100","313.7500"
|
||||
"2017/12/08","315.1300","3466088.0000","314.6000","316.9800","311.2600"
|
||||
"2017/12/07","311.2400","4779590.0000","312.0000","318.6341","311.0500"
|
||||
"2017/12/06","313.2600","7184477.0000","300.1000","313.3900","300.0000"
|
||||
"2017/12/05","303.7000","4643708.0000","302.0000","308.0000","301.0000"
|
||||
"2017/12/04","305.2000","5834227.0000","306.5000","308.2650","300.6100"
|
||||
"2017/12/01","306.5300","4286082.0000","305.4400","310.3200","305.0500"
|
||||
"2017/11/30","308.8500","4345434.0000","308.5600","310.7000","304.5400"
|
||||
"2017/11/29","307.5400","8757463.0000","317.3000","318.0000","301.2300"
|
||||
"2017/11/28","317.5500","4941703.0000","316.3600","320.0000","313.9200"
|
||||
"2017/11/27","316.8100","4537779.0000","313.2500","317.3400","309.5100"
|
||||
"2017/11/24","315.5500","3244065.0000","313.7900","316.4100","311.0000"
|
||||
"2017/11/22","312.6000","4913283.0000","316.7700","317.4200","311.8400"
|
||||
"2017/11/21","317.8100","7256381.0000","310.8600","318.2300","308.7100"
|
||||
"2017/11/20","308.7400","8241821.0000","313.7900","315.5000","304.7500"
|
||||
"2017/11/17","315.0500","13720830.0000","325.6700","326.6700","313.1500"
|
||||
"2017/11/16","312.5000","5794409.0000","313.9900","318.1400","311.3000"
|
||||
"2017/11/15","311.3000","5951835.0000","306.0100","312.4900","301.5000"
|
||||
"2017/11/14","308.7000","5661904.0000","315.0000","316.3500","306.9000"
|
||||
"2017/11/13","315.4000","7565242.0000","300.1300","316.8000","299.1100"
|
||||
"2017/11/10","302.9900","4621080.0000","302.5000","308.3600","301.8500"
|
||||
"2017/11/09","302.9900","5440173.0000","302.5000","304.4600","296.3000"
|
||||
"2017/11/08","304.3900","4725355.0000","305.5000","306.8900","301.3001"
|
||||
"2017/11/07","306.0500","5284844.0000","301.0200","306.5000","300.0300"
|
||||
"2017/11/06","302.7800","6480689.0000","307.0000","307.5000","299.0100"
|
||||
"2017/11/03","306.0900","8885933.0000","299.5000","306.2500","295.1300"
|
||||
"2017/11/02","299.2600","19771280.0000","300.1300","308.6900","292.6300"
|
||||
"2017/11/01","321.0800","8242487.0000","332.2500","332.6089","320.2600"
|
||||
"2017/10/31","331.5300","5650062.0000","320.2300","331.9500","320.1800"
|
||||
"2017/10/30","320.0800","4247619.0000","319.1800","323.7800","317.2500"
|
||||
"2017/10/27","320.8700","6968365.0000","319.7500","324.5900","316.6600"
|
||||
"2017/10/26","326.1700","5010087.0000","327.7800","330.2300","323.2000"
|
||||
"2017/10/25","325.8400","8583619.0000","336.7000","337.5000","323.5600"
|
||||
"2017/10/24","337.3400","4485692.0000","338.8000","342.8000","336.1600"
|
||||
"2017/10/23","337.0200","5739598.0000","349.8800","349.9500","336.2500"
|
||||
"2017/10/20","345.1000","4925657.0000","352.6900","354.5500","344.3400"
|
||||
"2017/10/19","351.8100","5055715.0000","355.5600","357.1465","348.2000"
|
||||
"2017/10/18","359.6500","4936024.0000","355.9700","363.0000","354.1300"
|
||||
"2017/10/17","355.7500","3290290.0000","350.9100","356.2200","350.0700"
|
||||
"2017/10/16","350.6000","5373090.0000","353.7600","354.4800","347.1600"
|
||||
"2017/10/13","355.5700","3538807.0000","356.9800","358.4900","353.6800"
|
||||
"2017/10/12","355.6800","4073552.0000","352.9500","359.7800","352.6400"
|
||||
"2017/10/11","354.6000","4494733.0000","353.8900","357.6000","351.1500"
|
||||
"2017/10/10","355.5900","6972263.0000","346.8000","355.6300","345.5305"
|
||||
"2017/10/09","342.9400","7461461.0000","349.6500","351.7500","342.6700"
|
||||
"2017/10/06","356.8800","4272866.0000","353.1000","360.0992","352.2500"
|
||||
"2017/10/05","355.3300","4167913.0000","356.0000","357.4350","351.3500"
|
||||
"2017/10/04","355.0100","8147995.0000","351.2500","358.6200","349.6000"
|
||||
"2017/10/03","348.1400","10122550.0000","335.9000","348.5500","331.2800"
|
||||
"2017/10/02","341.5300","5227547.0000","342.5200","343.7000","335.5100"
|
||||
"2017/09/29","341.1000","5099051.0000","341.8600","344.6800","338.6010"
|
||||
"2017/09/28","339.6000","5309779.0000","339.8800","342.7500","335.4000"
|
||||
"2017/09/27","340.9700","6027375.0000","349.9000","351.4890","340.5000"
|
||||
"2017/09/26","345.2500","7149649.0000","350.9300","351.2400","340.9000"
|
||||
"2017/09/25","344.9900","7587158.0000","353.1500","357.4690","342.8800"
|
||||
"2017/09/22","351.0900","8142895.0000","366.4900","369.8999","350.8800"
|
||||
"2017/09/21","366.4800","4610872.0000","374.9000","376.8300","364.5100"
|
||||
"2017/09/20","373.9100","4909958.0000","373.0000","378.2490","371.0700"
|
||||
"2017/09/19","375.1000","6435208.0000","380.0000","382.3900","373.5700"
|
||||
"2017/09/18","385.0000","7177773.0000","380.2500","389.6100","377.6800"
|
||||
"2017/09/15","379.8100","5407227.0000","374.5100","380.0000","372.7000"
|
||||
"2017/09/14","377.6400","7170263.0000","364.3300","377.9600","362.6300"
|
||||
"2017/09/13","366.2300","4171185.0000","363.8200","368.0700","359.5900"
|
||||
"2017/09/12","362.7500","5966204.0000","364.4900","368.7600","360.4000"
|
||||
"2017/09/11","363.6900","7651000.0000","351.3500","363.7100","350.0000"
|
||||
"2017/09/08","343.4000","3261333.0000","348.9900","349.7800","342.3000"
|
||||
"2017/09/07","350.6100","4235045.0000","345.9800","352.4800","343.4500"
|
||||
"2017/09/06","344.5300","4082001.0000","349.5000","350.9790","341.5600"
|
||||
"2017/09/05","349.5900","3836402.0000","353.8000","355.4900","345.8900"
|
||||
"2017/09/01","355.4000","3048550.0000","356.1200","357.5900","353.6902"
|
||||
"2017/08/31","355.9000","4063330.0000","353.5500","358.4400","352.8200"
|
||||
"2017/08/30","353.1800","3404165.0000","349.6700","353.4700","347.0000"
|
||||
"2017/08/29","347.3600","4069303.0000","339.4800","349.0500","338.7500"
|
||||
"2017/08/28","345.6600","3746240.0000","347.2800","347.3500","339.7200"
|
||||
"2017/08/25","348.0500","3475186.0000","354.2400","355.6900","347.3000"
|
||||
"2017/08/24","352.9300","4571574.0000","352.5200","356.6600","349.7400"
|
||||
"2017/08/23","352.7700","4941947.0000","338.9900","353.4900","338.3041"
|
||||
"2017/08/22","341.3500","4314268.0000","341.1300","342.2400","337.3725"
|
||||
"2017/08/21","337.8600","6489850.0000","345.8200","345.8200","331.8500"
|
||||
"2017/08/18","347.4600","5390805.0000","352.9100","354.0000","345.8000"
|
||||
"2017/08/17","351.9200","5010825.0000","361.2100","363.3000","351.5900"
|
||||
"2017/08/16","362.9100","3406173.0000","363.0000","366.5000","362.5200"
|
||||
"2017/08/15","362.3300","3084601.0000","365.2000","365.4900","359.3700"
|
||||
"2017/08/14","363.8000","4507969.0000","364.6300","367.6600","362.6000"
|
||||
"2017/08/11","357.8700","4357562.0000","356.9700","361.2600","353.6200"
|
||||
"2017/08/10","355.4000","7063054.0000","361.6000","366.6504","354.6600"
|
||||
"2017/08/09","363.5300","6881182.0000","361.0000","370.0000","358.9500"
|
||||
"2017/08/08","365.2200","7431838.0000","357.5300","368.5800","357.4000"
|
||||
"2017/08/07","355.1700","6309331.0000","357.3500","359.4800","352.7500"
|
||||
"2017/08/04","356.9100","9233295.0000","347.0000","357.2700","343.3000"
|
||||
"2017/08/03","347.0900","13524270.0000","345.3300","350.0000","343.1500"
|
||||
"2017/08/02","325.8900","11942350.0000","318.9400","327.1200","311.2200"
|
||||
"2017/08/01","319.5700","8284997.0000","323.0000","324.4500","316.1300"
|
||||
"2017/07/31","323.4700","8525454.0000","335.5000","341.4900","321.0400"
|
||||
"2017/07/28","335.0700","4869891.0000","336.8900","339.6000","332.5100"
|
||||
"2017/07/27","334.4600","8285879.0000","346.0000","347.5000","326.2900"
|
||||
"2017/07/26","343.8500","4809514.0000","340.3600","345.5000","338.1200"
|
||||
"2017/07/25","339.6000","6977932.0000","345.0000","345.6000","334.1500"
|
||||
"2017/07/24","342.5200","8598292.0000","330.2400","343.3990","330.0100"
|
||||
"2017/07/21","328.4000","4871708.0000","329.4600","331.2575","325.8000"
|
||||
"2017/07/20","329.9200","5142516.0000","326.9000","330.2200","324.2000"
|
||||
"2017/07/19","325.2600","6345884.0000","328.2300","331.6500","323.2193"
|
||||
"2017/07/18","328.2400","6360710.0000","317.5000","329.1300","315.6600"
|
||||
"2017/07/17","319.5700","9827506.0000","325.5400","327.1000","313.4500"
|
||||
"2017/07/14","327.7800","5607924.0000","323.1900","328.4200","321.2200"
|
||||
"2017/07/13","323.4100","8582315.0000","330.1100","331.6000","319.9700"
|
||||
"2017/07/12","329.5200","10317240.0000","330.4000","333.1000","324.5000"
|
||||
"2017/07/11","327.2200","11526760.0000","316.0000","327.2800","314.3000"
|
||||
"2017/07/10","316.0500","13760290.0000","312.9000","317.9400","303.1300"
|
||||
"2017/07/07","313.2200","14129950.0000","313.5000","317.0000","307.3800"
|
||||
"2017/07/06","308.8300","19258040.0000","317.2600","320.7899","306.3000"
|
||||
"2017/07/05","327.0900","16998300.0000","347.2000","347.2400","326.3300"
|
||||
"2017/07/03","352.6200","6305401.0000","370.2400","371.3500","351.5000"
|
||||
"2017/06/30","361.6100","5823046.0000","363.7100","366.7674","359.6187"
|
||||
"2017/06/29","360.7500","8202463.0000","370.6100","371.0000","354.1000"
|
||||
"2017/06/28","371.2400","6290323.0000","366.6800","371.7400","362.5200"
|
||||
"2017/06/27","362.3700","6977494.0000","376.4000","376.4000","362.0200"
|
||||
"2017/06/26","377.4900","6596854.0000","386.6900","386.9500","373.1000"
|
||||
"2017/06/23","383.4500","6425180.0000","382.4500","386.9900","379.3450"
|
||||
"2017/06/22","382.6100","7510406.0000","377.9900","385.0000","373.5700"
|
||||
"2017/06/21","376.4000","4916770.0000","374.3500","376.9900","368.0200"
|
||||
"2017/06/20","372.2400","7419110.0000","376.6700","378.8800","369.7300"
|
||||
"2017/06/19","369.8000","6433434.0000","375.0000","376.7000","367.8000"
|
||||
"2017/06/16","371.4000","6347450.0000","377.9750","378.0100","370.1000"
|
||||
"2017/06/15","375.3400","10412650.0000","372.5000","375.4600","366.4900"
|
||||
"2017/06/14","380.6600","12778480.0000","381.0850","384.2500","376.3100"
|
||||
"2017/06/13","375.9500","11773370.0000","367.6200","376.0000","366.6100"
|
||||
"2017/06/12","359.0100","10507860.0000","357.9900","364.5000","350.6200"
|
||||
"2017/06/09","357.3200","17250060.0000","374.4200","376.8700","354.8000"
|
||||
"2017/06/08","370.0000","9028677.0000","363.7500","371.9000","360.2200"
|
||||
"2017/06/07","359.6500","9348692.0000","356.3400","360.5000","355.1400"
|
||||
"2017/06/06","352.8500","11031920.0000","344.7000","359.4929","339.9700"
|
||||
"2017/06/05","347.3200","6769174.0000","338.5000","348.4400","334.2100"
|
||||
"2017/06/02","339.8500","5583952.0000","339.7700","342.8800","335.9300"
|
||||
"2017/06/01","340.3700","7601764.0000","344.0000","344.8800","337.2900"
|
||||
"2017/05/31","341.0100","9937556.0000","337.6900","342.8900","335.1600"
|
||||
"2017/05/30","335.1000","7771536.0000","326.0000","336.2800","325.7600"
|
||||
"2017/05/26","325.1400","7793009.0000","317.2800","325.4900","316.3100"
|
||||
"2017/05/25","316.8300","5000432.0000","311.0200","316.9700","307.8100"
|
||||
"2017/05/24","310.2200","5035192.0000","306.5100","311.0000","305.4000"
|
||||
"2017/05/23","303.8600","4314267.0000","310.4600","310.7300","303.4800"
|
||||
"2017/05/22","310.3500","4324305.0000","312.8000","314.3700","306.8000"
|
||||
"2017/05/19","310.8300","4654580.0000","315.5000","316.5000","310.2000"
|
||||
"2017/05/18","313.0600","5609153.0000","307.0000","313.9400","305.3100"
|
||||
"2017/05/17","306.1100","6695657.0000","314.3900","314.6300","305.5000"
|
||||
"2017/05/16","317.0100","4141066.0000","317.5900","320.0600","315.1400"
|
||||
"2017/05/15","315.8800","7606854.0000","318.3800","320.2000","312.5300"
|
||||
"2017/05/12","324.8100","4118613.0000","325.4800","327.0000","321.5300"
|
||||
"2017/05/11","323.1000","4747172.0000","323.4000","326.0000","319.6000"
|
||||
"2017/05/10","325.2200","5734524.0000","321.5600","325.5000","318.1200"
|
||||
"2017/05/09","321.2600","9663374.0000","309.3800","321.9900","309.1000"
|
||||
"2017/05/08","307.1900","7002907.0000","310.9000","313.7900","305.8200"
|
||||
"2017/05/05","308.3500","8117449.0000","298.0000","308.5500","296.8000"
|
||||
"2017/05/04","295.4600","14135990.0000","307.4350","307.7700","290.7601"
|
||||
"2017/05/03","311.0200","6879259.0000","317.6700","321.5300","310.4500"
|
||||
"2017/05/02","318.8900","5316551.0000","324.0000","327.6599","316.5601"
|
||||
"2017/05/01","322.8300","8819888.0000","314.8800","327.2500","314.8100"
|
||||
"2017/04/28","314.0700","4496659.0000","309.8300","314.8000","308.0000"
|
||||
"2017/04/27","308.6300","3462663.0000","311.6900","313.0900","307.5000"
|
||||
"2017/04/26","310.1700","4683131.0000","312.3700","314.5000","309.0000"
|
||||
"2017/04/25","313.7900","6734162.0000","308.0000","313.9800","305.8600"
|
||||
"2017/04/24","308.0300","5077771.0000","309.2200","310.5500","306.0215"
|
||||
"2017/04/21","305.6000","4501958.0000","302.0000","306.4000","300.4200"
|
||||
"2017/04/20","302.5100","6145961.0000","306.5100","309.1500","300.2300"
|
||||
"2017/04/19","305.5200","3891145.0000","302.4600","306.6200","302.1100"
|
||||
"2017/04/18","300.2500","3034225.0000","299.7000","300.8399","297.9000"
|
||||
"2017/04/17","301.4400","4128067.0000","302.7000","304.0000","298.6800"
|
||||
"2017/04/13","304.0000","9275682.0000","296.7000","307.3900","295.3000"
|
||||
"2017/04/12","296.8400","6043648.0000","306.3400","308.4481","296.3200"
|
||||
"2017/04/11","308.7100","5718053.0000","313.3800","313.4700","305.5000"
|
||||
"2017/04/10","312.3900","7653623.0000","309.1500","313.7299","308.7100"
|
||||
"2017/04/07","302.5400","4566632.0000","297.5000","302.6900","297.1500"
|
||||
"2017/04/06","298.7000","5517731.0000","296.8800","301.9400","294.1000"
|
||||
"2017/04/05","295.0000","7858565.0000","302.0400","304.8800","294.2000"
|
||||
"2017/04/04","303.7000","10108230.0000","296.8900","304.8100","294.5300"
|
||||
"2017/04/03","298.5200","13864850.0000","286.9000","299.0000","284.5800"
|
||||
"2017/03/31","278.3000","3293698.0000","278.7300","279.6800","276.3197"
|
||||
"2017/03/30","277.9200","4141437.0000","278.0400","282.0000","277.2100"
|
||||
"2017/03/29","277.3800","3672526.0000","278.3400","279.6000","275.5400"
|
||||
"2017/03/28","277.4500","7978665.0000","277.0200","280.6800","275.0000"
|
||||
"2017/03/27","270.2200","6221361.0000","260.6000","270.5700","259.7500"
|
||||
"2017/03/24","263.1600","5637668.0000","255.7000","263.8900","255.0100"
|
||||
"2017/03/23","254.7800","3309844.0000","255.3900","257.6720","253.3000"
|
||||
"2017/03/22","255.0100","4056735.0000","251.5600","255.0700","250.5100"
|
||||
"2017/03/21","250.6800","6901555.0000","262.8300","264.8000","250.2400"
|
||||
"2017/03/20","261.9200","3601616.0000","260.6000","264.5500","258.8210"
|
||||
"2017/03/17","261.5000","6491018.0000","264.0000","265.3300","261.2000"
|
||||
"2017/03/16","262.0500","7127180.0000","262.4000","265.7500","259.0600"
|
||||
"2017/03/15","255.7300","5233365.0000","257.0000","261.0000","254.2700"
|
||||
"2017/03/14","258.0000","7581719.0000","246.1100","258.1200","246.0200"
|
||||
"2017/03/13","246.1700","3011280.0000","244.8200","246.8500","242.7810"
|
||||
"2017/03/10","243.6900","3062785.0000","246.2100","246.5000","243.0000"
|
||||
"2017/03/09","244.9000","3876494.0000","247.6300","248.6600","243.0000"
|
||||
"2017/03/08","246.8700","3726746.0000","247.0000","250.0700","245.3200"
|
||||
"2017/03/07","248.5900","3452587.0000","251.9200","253.8900","248.3200"
|
||||
"2017/03/06","251.2100","3353601.0000","247.9100","251.7000","247.5100"
|
||||
"2017/03/03","251.5700","2925481.0000","250.7400","251.9000","249.0000"
|
||||
"2017/03/02","250.4800","3345751.0000","249.7100","253.2800","248.2700"
|
||||
"2017/03/01","250.0200","4804963.0000","254.1800","254.8500","249.1100"
|
||||
"2017/02/28","249.9900","6073890.0000","244.1900","251.0000","243.9000"
|
||||
"2017/02/27","246.2300","11450160.0000","248.1700","248.3600","242.0100"
|
||||
"2017/02/24","257.0000","8166869.0000","252.6600","258.2500","250.2000"
|
||||
"2017/02/23","255.9900","14877090.0000","264.0000","264.6600","255.5600"
|
||||
"2017/02/22","273.5100","8537811.0000","280.3100","283.4500","272.6000"
|
||||
"2017/02/21","277.3900","5647575.0000","275.4500","281.4000","274.0100"
|
||||
"2017/02/17","272.2300","6251469.0000","265.8000","272.8900","264.1500"
|
||||
"2017/02/16","268.9500","7063860.0000","277.6000","280.0000","268.5000"
|
||||
"2017/02/15","279.7600","4943879.0000","280.0000","282.2400","276.4400"
|
||||
"2017/02/14","280.9800","7341450.0000","279.0300","287.3900","278.6100"
|
||||
"2017/02/13","280.6000","7023072.0000","270.7400","280.7899","270.5100"
|
||||
"2017/02/10","269.2300","3618336.0000","269.7900","270.9500","266.1100"
|
||||
"2017/02/09","269.2000","7812600.0000","266.2500","271.1800","266.1500"
|
||||
"2017/02/08","262.0800","3912428.0000","257.3500","263.3600","256.2000"
|
||||
"2017/02/07","257.4800","4244063.0000","258.1900","260.0000","256.4200"
|
||||
"2017/02/06","257.7700","3557600.0000","251.0000","257.8200","250.6300"
|
||||
"2017/02/03","251.3300","2185230.0000","251.9100","252.1790","249.6800"
|
||||
"2017/02/02","251.5500","2498799.0000","248.3400","252.4200","247.7100"
|
||||
"2017/02/01","249.2400","3953105.0000","253.0500","253.2000","249.0500"
|
||||
"2017/01/31","251.9300","4112013.0000","249.2400","255.8900","247.7000"
|
||||
"2017/01/30","250.6300","3798638.0000","252.5300","255.2899","247.1000"
|
||||
"2017/01/27","252.9500","3161774.0000","251.3800","253.0000","248.5200"
|
||||
"2017/01/26","252.5100","3143717.0000","254.2900","255.7400","250.7500"
|
||||
"2017/01/25","254.4700","5145301.0000","257.3100","258.4600","251.8000"
|
||||
"2017/01/24","254.6100","4958144.0000","250.0000","254.8000","249.6500"
|
||||
"2017/01/23","248.9200","6262097.0000","245.8500","250.8899","245.5000"
|
||||
"2017/01/20","244.7300","4199720.0000","245.4600","246.0000","243.0100"
|
||||
"2017/01/19","243.7600","7717244.0000","247.2500","248.6800","240.7500"
|
||||
"2017/01/18","238.3600","3767272.0000","236.6500","239.7100","235.5800"
|
||||
"2017/01/17","235.5800","4614731.0000","236.7000","239.9600","234.3700"
|
||||
"2017/01/13","237.7500","6085610.0000","230.0000","237.8500","229.5900"
|
||||
"2017/01/12","229.5900","3787547.0000","229.0600","230.7000","225.5800"
|
||||
"2017/01/11","229.7300","3649910.0000","229.0700","229.9800","226.6800"
|
||||
"2017/01/10","229.8700","3658981.0000","232.0000","232.0000","226.8900"
|
||||
"2017/01/09","231.2800","3972716.0000","228.9700","231.9200","228.0000"
|
||||
"2017/01/06","229.0100","5524153.0000","226.9300","230.3100","225.4500"
|
||||
"2017/01/05","226.7500","5908927.0000","226.4200","227.4800","221.9500"
|
||||
"2017/01/04","226.9900","11204560.0000","214.7500","228.0000","214.3100"
|
||||
"2017/01/03","216.9900","5901494.0000","214.8600","220.3300","210.9600"
|
||||
"2016/12/30","213.6900","4641288.0000","216.3000","217.5000","211.6800"
|
||||
"2016/12/29","214.6800","4043086.0000","218.5600","219.2000","214.1225"
|
||||
"2016/12/28","219.7400","3778544.0000","221.5300","223.8000","217.2000"
|
||||
"2016/12/27","219.5300","5913335.0000","214.8800","222.2500","214.4200"
|
||||
"2016/12/23","213.3400","4668263.0000","208.0000","213.4500","207.7100"
|
||||
"2016/12/22","208.4500","3108427.0000","208.2200","209.9900","206.5000"
|
||||
"2016/12/21","207.7000","5206143.0000","208.4500","212.2300","207.4100"
|
||||
"2016/12/20","208.7900","4684269.0000","203.0500","209.0000","202.5000"
|
||||
"2016/12/19","202.7300","3486937.0000","202.4900","204.4500","199.8400"
|
||||
"2016/12/16","202.4900","3795444.0000","198.0800","202.5900","197.6000"
|
||||
"2016/12/15","197.5800","3218653.0000","198.4100","200.7400","197.3900"
|
||||
"2016/12/14","198.6900","4147314.0000","198.7400","203.0000","196.7600"
|
||||
"2016/12/13","198.1500","6819322.0000","193.1800","201.2800","193.0000"
|
||||
"2016/12/12","192.4300","2436428.0000","192.8000","194.4200","191.0400"
|
||||
"2016/12/09","192.1800","2720937.0000","190.8700","193.8360","190.8100"
|
||||
"2016/12/08","192.2900","3193684.0000","192.0500","192.5000","189.5400"
|
||||
"2016/12/07","193.1500","5457071.0000","186.1500","193.4000","185.0000"
|
||||
"2016/12/06","185.8500","3389365.0000","185.5200","186.5800","182.6825"
|
||||
"2016/12/05","186.8000","4069480.0000","182.5100","188.8900","182.5100"
|
||||
"2016/12/02","181.4700","4040201.0000","182.8800","184.8800","180.0000"
|
||||
"2016/12/01","181.8800","5119105.0000","188.2500","188.5300","181.0000"
|
||||
"2016/11/30","189.4000","3544891.0000","191.0000","191.8900","187.5000"
|
||||
"2016/11/29","189.5700","4435312.0000","195.5600","196.7300","189.5000"
|
||||
"2016/11/28","196.1200","4521082.0000","195.4800","199.3500","194.5500"
|
||||
"2016/11/25","196.6500","2366098.0000","193.6400","197.2372","193.6400"
|
||||
"2016/11/23","193.1400","4890285.0000","190.6100","195.6440","189.0000"
|
||||
"2016/11/22","191.1700","5601238.0000","185.8400","191.4700","183.7100"
|
||||
"2016/11/21","184.5200","4355872.0000","185.0400","188.8900","184.4100"
|
||||
"2016/11/18","185.0200","5206473.0000","190.6500","193.0000","185.0000"
|
||||
"2016/11/17","188.6600","4880969.0000","183.4900","189.4900","182.1101"
|
||||
"2016/11/16","183.9300","3432668.0000","182.6500","184.7300","181.2100"
|
||||
"2016/11/15","183.7700","3899743.0000","182.7800","186.4300","182.0500"
|
||||
"2016/11/14","181.4500","6547913.0000","188.0000","188.2500","178.1900"
|
||||
"2016/11/11","188.5600","3987091.0000","184.2400","188.8800","183.0000"
|
||||
"2016/11/10","185.3500","6746290.0000","191.0500","191.6100","180.4200"
|
||||
"2016/11/09","190.0600","8166447.0000","186.8750","192.0000","183.9500"
|
||||
"2016/11/08","194.9400","3252927.0000","193.7900","197.4900","191.2600"
|
||||
"2016/11/07","193.2100","3857682.0000","193.5900","194.2900","190.0500"
|
||||
"2016/11/04","190.5600","5143915.0000","189.0000","193.4600","185.9600"
|
||||
"2016/11/03","187.4200","2644550.0000","189.0000","191.4700","187.0401"
|
||||
"2016/11/02","188.0200","4242250.0000","190.0500","192.6951","187.5050"
|
||||
"2016/11/01","190.7900","7023674.0000","198.0400","198.5000","188.1050"
|
||||
"2016/10/31","197.7300","4691320.0000","202.4900","202.4900","195.8100"
|
||||
"2016/10/28","199.9700","4273456.0000","204.0000","205.3200","199.8300"
|
||||
"2016/10/27","204.0100","13070990.0000","211.3400","213.7000","201.6500"
|
||||
"2016/10/26","202.2400","5346893.0000","201.0000","203.1900","200.1000"
|
||||
"2016/10/25","202.3400","2442118.0000","202.9000","204.6900","201.2000"
|
||||
"2016/10/24","202.7600","2747344.0000","201.0000","203.9452","200.2500"
|
||||
"2016/10/21","200.0900","2936908.0000","198.6000","201.5700","197.4100"
|
||||
"2016/10/20","199.1000","5069410.0000","202.1200","203.0000","197.0500"
|
||||
"2016/10/19","203.5600","6966185.0000","199.7400","206.6600","198.0600"
|
||||
"2016/10/18","199.1000","5676046.0000","195.9900","199.4700","193.2600"
|
||||
"2016/10/17","193.9600","4518331.0000","197.0500","198.3900","192.0000"
|
||||
"2016/10/14","196.5100","4265471.0000","200.6600","201.4300","196.3000"
|
||||
"2016/10/13","200.2400","2495140.0000","200.5000","200.8950","197.0500"
|
||||
"2016/10/12","201.5100","1969099.0000","200.9500","203.8800","200.4200"
|
||||
"2016/10/11","200.1000","2326754.0000","201.8500","202.2000","198.3100"
|
||||
"2016/10/10","200.9500","3311340.0000","201.3500","204.1400","199.6600"
|
||||
"2016/10/07","196.6100","3489480.0000","201.0000","201.3200","195.8000"
|
||||
"2016/10/06","201.0000","4697937.0000","202.4600","204.2099","200.2100"
|
||||
"2016/10/05","208.4600","1872456.0000","212.2400","213.1500","208.1200"
|
||||
"2016/10/04","211.4100","3537953.0000","213.1000","213.3200","208.8200"
|
||||
"2016/10/03","213.7000","5989342.0000","212.3000","215.6688","208.2500"
|
||||
"2016/09/30","204.0300","2581730.0000","202.2100","204.9800","199.5500"
|
||||
"2016/09/29","200.7000","2714040.0000","205.6000","207.3300","200.5800"
|
||||
"2016/09/28","206.2700","2079324.0000","207.5100","208.2500","205.2600"
|
||||
"2016/09/27","205.8100","3367907.0000","209.6500","209.9818","204.6093"
|
||||
"2016/09/26","208.9900","2393373.0000","206.5000","211.0000","206.5000"
|
||||
"2016/09/23","207.4500","2904125.0000","205.9900","210.1800","205.6700"
|
||||
"2016/09/22","206.4300","2381600.0000","206.4000","207.2800","203.0000"
|
||||
"2016/09/21","205.2200","2631285.0000","206.3700","207.0000","201.5600"
|
||||
"2016/09/20","204.6400","2408556.0000","206.8500","207.7500","203.9100"
|
||||
"2016/09/19","206.3400","2298318.0000","207.0000","209.4300","205.0000"
|
||||
"2016/09/16","205.4000","3104266.0000","200.4200","205.7000","199.0000"
|
||||
"2016/09/15","200.4200","3082942.0000","196.4900","202.5193","196.4000"
|
||||
"2016/09/14","196.4100","2256143.0000","195.7500","197.9248","194.8562"
|
||||
"2016/09/13","196.0500","3583140.0000","197.0600","198.4900","193.4500"
|
||||
"2016/09/12","198.3000","3714049.0000","195.0000","201.3690","194.1000"
|
||||
"2016/09/09","194.4700","3753734.0000","199.0900","199.9200","193.7000"
|
||||
"2016/09/08","197.3600","3372293.0000","199.5500","199.8900","196.3600"
|
||||
"2016/09/07","201.7100","3637918.0000","205.5000","206.4968","200.7100"
|
||||
"2016/09/06","202.8300","4386193.0000","199.0200","203.2500","199.0000"
|
||||
"2016/09/02","197.7800","5970154.0000","202.3300","203.2000","196.2000"
|
||||
"2016/09/01","200.7700","7932444.0000","209.0100","211.0999","200.5000"
|
||||
"2016/08/31","212.0100","3274854.0000","210.4300","212.6000","208.6500"
|
||||
"2016/08/30","211.3400","3164222.0000","216.1100","216.1100","210.5200"
|
||||
"2016/08/29","215.2000","3261381.0000","220.1500","220.4000","215.0000"
|
||||
"2016/08/26","219.9900","2238087.0000","222.1400","222.8550","218.8200"
|
||||
"2016/08/25","220.9600","1760212.0000","223.1100","223.8000","220.7700"
|
||||
"2016/08/24","222.6200","2566947.0000","227.0500","227.1500","222.2200"
|
||||
"2016/08/23","224.8400","4747745.0000","224.3200","228.4900","222.8000"
|
||||
"2016/08/22","222.9300","2061692.0000","224.1700","225.1100","222.6800"
|
||||
"2016/08/19","225.0000","1658616.0000","223.5400","225.1690","222.5300"
|
||||
"2016/08/18","223.5100","1699300.0000","223.8200","225.6600","222.2900"
|
||||
"2016/08/17","223.2400","1786408.0000","224.3300","224.8300","222.8000"
|
||||
"2016/08/16","223.6100","2251115.0000","225.4900","227.1900","223.4101"
|
||||
"2016/08/15","225.5900","2017964.0000","226.0200","229.5000","224.9300"
|
||||
"2016/08/12","225.6100","1811850.0000","225.4100","226.6500","224.0400"
|
||||
"2016/08/11","224.9100","1876959.0000","226.1700","227.5700","223.4100"
|
||||
"2016/08/10","225.6500","2336496.0000","228.2400","229.8700","224.6200"
|
||||
"2016/08/09","229.0800","2199766.0000","226.8200","231.5375","226.6500"
|
||||
"2016/08/08","226.1600","2259465.0000","228.0000","229.6000","226.0900"
|
||||
"2016/08/05","230.0300","3190342.0000","230.0000","232.0000","227.4000"
|
||||
"2016/08/04","230.6100","4142155.0000","225.6900","230.8600","222.0500"
|
||||
"2016/08/03","225.7900","3808747.0000","227.3700","229.6990","224.2100"
|
||||
"2016/08/02","227.2000","3928706.0000","229.3700","229.8700","221.4000"
|
||||
"2016/08/01","230.0100","4014048.0000","235.5000","236.6300","229.3800"
|
||||
"2016/07/29","234.7900","3061574.0000","230.7000","235.2800","230.2400"
|
||||
"2016/07/28","230.6100","2415462.0000","227.9500","230.7600","226.6000"
|
||||
"2016/07/27","228.4900","2887028.0000","229.3400","233.3600","226.9200"
|
||||
"2016/07/26","229.5100","3427251.0000","227.6900","230.0000","225.3000"
|
||||
"2016/07/25","230.0100","4479483.0000","222.2700","231.3900","221.3715"
|
||||
"2016/07/22","222.2700","2570462.0000","221.9900","224.5000","218.8800"
|
||||
"2016/07/21","220.5000","4425756.0000","226.0000","227.8470","219.1000"
|
||||
"2016/07/20","228.3600","2556119.0000","226.4700","229.8000","225.0000"
|
||||
"2016/07/19","225.2600","3047535.0000","225.0000","229.1000","224.7500"
|
||||
"2016/07/18","226.2500","3394588.0000","219.6400","227.0900","218.3000"
|
||||
"2016/07/15","220.4000","2230821.0000","222.5200","222.7499","219.6400"
|
||||
"2016/07/14","221.5300","2657899.0000","223.1200","224.9400","221.0500"
|
||||
"2016/07/13","222.5300","3540699.0000","225.5000","225.5900","220.2900"
|
||||
"2016/07/12","224.6500","4573875.0000","224.1000","227.5000","223.2200"
|
||||
"2016/07/11","224.7800","5369066.0000","219.9600","226.7800","219.5100"
|
||||
"2016/07/08","216.7800","4067131.0000","217.8000","219.8100","214.5000"
|
||||
"2016/07/07","215.9400","3603385.0000","213.1000","218.1200","213.0100"
|
||||
"2016/07/06","214.4400","4910285.0000","210.0000","215.2300","209.0000"
|
||||
"2016/07/05","213.9800","5169832.0000","209.7300","214.5441","208.0000"
|
||||
"2016/07/01","216.5000","5396030.0000","206.1400","218.2400","206.0000"
|
||||
"2016/06/30","212.2800","4794440.0000","212.9700","213.4999","209.0200"
|
||||
"2016/06/29","210.1900","5987120.0000","205.1300","211.7800","203.0000"
|
||||
"2016/06/28","201.7900","6158996.0000","201.8900","204.0500","199.4100"
|
||||
"2016/06/27","198.5500","7211823.0000","190.8600","198.8100","187.8700"
|
||||
"2016/06/24","193.1500","6988949.0000","190.0500","195.1200","189.7300"
|
||||
"2016/06/23","196.4000","10098190.0000","195.6900","197.5500","192.1300"
|
||||
"2016/06/22","196.6600","23706100.0000","199.4700","205.9500","195.7500"
|
||||
"2016/06/21","219.6100","2855619.0000","220.6800","222.5690","218.8100"
|
||||
"2016/06/20","219.7000","3549768.0000","219.5000","223.7500","218.2300"
|
||||
"2016/06/17","215.4700","3107734.0000","217.8100","219.9900","214.5000"
|
||||
"2016/06/16","217.9300","2438692.0000","217.4200","218.0400","213.5000"
|
||||
"2016/06/15","217.7000","2905002.0000","216.9500","221.9000","215.1300"
|
||||
"2016/06/14","214.9600","3575822.0000","218.8800","222.2000","212.5300"
|
||||
"2016/06/13","217.8700","4187833.0000","219.5000","225.7700","217.6600"
|
||||
"2016/06/10","218.7900","5994548.0000","227.3900","227.9700","218.4217"
|
||||
"2016/06/09","229.3600","4454222.0000","234.9800","235.3300","227.0600"
|
||||
"2016/06/08","235.5200","5965110.0000","233.8000","240.8450","232.6050"
|
||||
"2016/06/07","232.3400","6194154.0000","222.2400","234.4400","221.5200"
|
||||
"2016/06/06","220.6800","2242634.0000","218.0000","220.9000","215.4500"
|
||||
"2016/06/03","218.9900","2226110.0000","220.0000","221.9400","218.0100"
|
||||
"2016/06/02","218.9600","2017279.0000","219.5900","219.9090","217.1100"
|
||||
"2016/06/01","219.5600","2982270.0000","221.4800","222.4000","216.8900"
|
||||
"2016/05/31","223.2300","2786682.0000","223.0400","224.7497","221.5001"
|
||||
"2016/05/27","223.0400","3645792.0000","224.9900","225.9300","220.7500"
|
||||
"2016/05/26","225.1200","4066512.0000","220.5000","225.2600","219.0500"
|
||||
"2016/05/25","219.5800","3131279.0000","217.9100","221.3600","216.5100"
|
||||
"2016/05/24","217.9100","3009327.0000","216.6000","218.7400","215.1800"
|
||||
"2016/05/23","216.2200","5096751.0000","219.8700","222.6000","215.8600"
|
||||
"2016/05/20","220.2800","8996546.0000","216.9900","220.5500","216.3500"
|
||||
"2016/05/19","215.2100","6817922.0000","213.6200","216.7900","207.3000"
|
||||
"2016/05/18","211.1700","5552692.0000","209.1500","215.3100","207.7500"
|
||||
"2016/05/17","204.6600","2842028.0000","209.0500","209.8199","204.0200"
|
||||
"2016/05/16","208.2900","2945754.0000","208.1500","213.1500","207.9200"
|
||||
"2016/05/13","207.6100","2820616.0000","207.7800","211.2000","206.7000"
|
||||
"2016/05/12","207.2800","3650075.0000","211.4400","211.6700","203.6572"
|
||||
"2016/05/11","208.9600","5159640.0000","207.5900","215.4800","206.0500"
|
||||
"2016/05/10","208.6900","4068053.0000","207.5500","209.4700","205.0000"
|
||||
"2016/05/09","208.9200","4772992.0000","215.7200","216.1500","206.8000"
|
||||
"2016/05/06","214.9300","5683675.0000","210.8700","216.3700","208.1100"
|
||||
"2016/05/05","211.5300","11248340.0000","228.4600","228.6400","209.7900"
|
||||
"2016/05/04","222.5600","8550004.0000","230.2900","234.4600","220.4000"
|
||||
"2016/05/03","232.3200","4296325.0000","237.3600","238.9100","231.6200"
|
||||
"2016/05/02","241.8000","3838958.0000","241.5000","243.1900","234.8200"
|
||||
"2016/04/29","240.7600","5405164.0000","248.1400","248.4300","237.8100"
|
||||
"2016/04/28","247.7100","2515595.0000","249.8500","253.4300","247.4400"
|
||||
"2016/04/27","251.4700","3198105.0000","252.7500","255.0000","249.4000"
|
||||
"2016/04/26","253.7400","3217779.0000","252.0500","255.7300","249.3900"
|
||||
"2016/04/25","251.8200","3665088.0000","253.0100","257.3800","250.7600"
|
||||
"2016/04/22","253.7500","3783126.0000","248.8900","254.0000","245.7100"
|
||||
"2016/04/21","248.2900","2777079.0000","248.9900","250.9000","246.9100"
|
||||
"2016/04/20","249.9700","5192343.0000","246.2600","253.6600","241.5000"
|
||||
"2016/04/19","247.3700","6351360.0000","253.1200","254.3699","241.2510"
|
||||
"2016/04/18","253.8800","4263246.0000","252.2300","258.3100","251.6600"
|
||||
"2016/04/15","254.5100","3748593.0000","251.3100","254.6000","249.1200"
|
||||
"2016/04/14","251.8600","4129258.0000","253.0000","256.8390","251.0501"
|
||||
"2016/04/13","254.5300","4921554.0000","248.5100","255.5000","247.3300"
|
||||
"2016/04/12","247.8200","5755351.0000","249.5000","251.8000","243.6300"
|
||||
"2016/04/11","249.9200","9156404.0000","251.0000","258.9900","245.3000"
|
||||
"2016/04/08","250.0700","7352707.0000","260.5000","260.8200","248.0201"
|
||||
"2016/04/07","257.2000","8845567.0000","266.4500","269.3400","254.5100"
|
||||
"2016/04/06","265.4200","11695760.0000","253.9700","267.7400","253.4500"
|
||||
"2016/04/05","255.4700","9931470.0000","240.5000","256.5600","240.0000"
|
||||
"2016/04/04","246.9900","13381160.0000","249.1200","252.1200","243.6400"
|
||||
"2016/04/01","237.5900","15979910.0000","244.8250","247.9000","233.2500"
|
||||
"2016/03/31","229.7700","7975638.0000","229.3400","237.4200","225.0100"
|
||||
"2016/03/30","226.8900","4025670.0000","235.0900","235.5000","226.5000"
|
||||
"2016/03/29","230.1300","4006037.0000","229.8900","232.3800","225.3300"
|
||||
"2016/03/28","230.2600","3878599.0000","231.6100","234.8100","225.0000"
|
||||
"2016/03/24","227.7500","4956604.0000","215.7800","228.8877","215.0000"
|
||||
"2016/03/23","222.5800","4936203.0000","232.3700","234.7300","222.0300"
|
||||
"2016/03/22","234.2400","4303052.0000","237.2100","238.9900","232.5580"
|
||||
"2016/03/21","238.3200","5289014.0000","235.3400","239.8800","235.0000"
|
||||
"2016/03/18","232.7400","4704761.0000","229.1000","234.4800","228.0600"
|
||||
"2016/03/17","226.3800","3769083.0000","221.4700","228.5000","220.0000"
|
||||
"2016/03/16","221.9300","3511873.0000","218.0000","222.5800","217.0200"
|
||||
"2016/03/15","218.3400","3133230.0000","214.2700","218.9700","211.5000"
|
||||
"2016/03/14","215.1500","4062304.0000","212.6500","216.7200","210.6400"
|
||||
"2016/03/11","207.5000","3339148.0000","207.9300","209.4200","205.3300"
|
||||
"2016/03/10","205.1800","5191602.0000","210.0000","213.2900","200.6710"
|
||||
"2016/03/09","208.7200","3207597.0000","204.5200","209.3726","202.7900"
|
||||
"2016/03/08","202.6000","4175498.0000","203.5000","207.5000","202.2000"
|
||||
"2016/03/07","205.2900","5331097.0000","197.6800","209.7000","197.4000"
|
||||
"2016/03/04","201.0400","6479858.0000","198.0000","204.0300","197.5001"
|
||||
"2016/03/03","195.7400","4822993.0000","188.2800","197.4200","184.2200"
|
||||
"2016/03/02","188.3400","4858631.0000","183.7300","188.5200","181.5000"
|
||||
"2016/03/01","186.3500","6695704.0000","194.2500","195.9484","182.7000"
|
||||
"2016/02/29","191.9300","4495402.0000","192.4000","196.3500","189.2220"
|
||||
"2016/02/26","190.3400","6054061.0000","188.7000","192.0000","185.0000"
|
||||
"2016/02/25","187.4300","5727008.0000","178.6500","188.5192","175.2000"
|
||||
"2016/02/24","179.0000","5385369.0000","172.7500","179.5000","167.8400"
|
||||
"2016/02/23","177.2100","5982993.0000","176.1600","181.7300","173.6800"
|
||||
"2016/02/22","177.7400","5055340.0000","170.1200","178.9100","169.8500"
|
||||
"2016/02/19","166.5800","2955832.0000","163.6600","167.4900","162.5000"
|
||||
"2016/02/18","166.7700","3883107.0000","172.4200","172.9500","164.7700"
|
||||
"2016/02/17","168.6800","5820264.0000","159.0000","169.3400","156.6800"
|
||||
"2016/02/16","155.1700","5561638.0000","158.7000","162.9500","154.1100"
|
||||
"2016/02/12","151.0400","7233264.0000","155.0000","157.0100","143.7000"
|
||||
"2016/02/11","150.4700","14236900.0000","152.0000","163.2600","147.0000"
|
||||
"2016/02/10","143.6700","10104690.0000","150.5000","154.9700","141.7400"
|
||||
"2016/02/09","148.2500","8639661.0000","142.3200","159.7900","141.0500"
|
||||
"2016/02/08","147.9900","9306754.0000","157.1050","157.1500","146.0000"
|
||||
"2016/02/05","162.6000","9434495.0000","171.3000","173.0000","157.7442"
|
||||
"2016/02/04","175.3300","4379442.0000","170.7000","175.9800","166.9900"
|
||||
"2016/02/03","173.4800","7927640.0000","183.5900","183.9400","170.1800"
|
||||
"2016/02/02","182.7800","5764817.0000","192.4200","193.1200","180.2300"
|
||||
"2016/02/01","196.9400","5295685.0000","188.7600","199.5200","182.7500"
|
||||
"2016/01/29","191.2000","2848929.0000","189.9500","193.7400","188.0800"
|
||||
"2016/01/28","189.7000","4586328.0000","190.7900","191.2800","182.4100"
|
||||
"2016/01/27","188.0700","3577353.0000","192.3800","193.2600","185.7700"
|
||||
"2016/01/26","193.5600","4956918.0000","196.7000","197.8200","188.8800"
|
||||
"2016/01/25","196.3800","2695408.0000","200.0600","203.5700","195.8800"
|
||||
"2016/01/22","202.5500","3122066.0000","204.8010","205.5000","199.0300"
|
||||
"2016/01/21","199.9700","3164424.0000","201.5500","203.2300","195.0200"
|
||||
"2016/01/20","198.7000","5826110.0000","199.4000","201.2800","191.2500"
|
||||
"2016/01/19","204.7200","4031271.0000","208.7100","210.4700","200.7800"
|
||||
"2016/01/15","204.9900","5325773.0000","198.9700","205.0700","197.2500"
|
||||
"2016/01/14","206.1800","6490579.0000","202.2100","210.0000","193.3800"
|
||||
"2016/01/13","200.3100","4120993.0000","212.0100","212.6500","200.0000"
|
||||
"2016/01/12","209.9700","3079051.0000","211.6000","213.7395","205.3100"
|
||||
"2016/01/11","207.8500","4090843.0000","214.0100","214.4500","203.0000"
|
||||
"2016/01/08","211.0000","3572360.0000","217.8600","220.4400","210.7700"
|
||||
"2016/01/07","215.6500","3550704.0000","214.1900","218.4400","213.6700"
|
||||
"2016/01/06","219.0400","3774353.0000","220.0000","220.0500","215.9800"
|
||||
"2016/01/05","223.4300","3185525.0000","226.3600","226.8900","220.0000"
|
||||
"2016/01/04","223.4100","6823510.0000","230.7200","231.3800","219.0000"
|
||||
"2015/12/31","240.0100","2713817.0000","238.5100","243.4500","238.3700"
|
||||
"2015/12/30","238.0900","3694448.0000","236.6000","243.6340","235.6707"
|
||||
"2015/12/29","237.1900","2402438.0000","230.0600","237.7200","229.5470"
|
||||
"2015/12/28","228.9500","1900171.0000","231.4900","231.9800","225.5400"
|
||||
"2015/12/24","230.5700","710277.0000","230.5600","231.8800","228.2800"
|
||||
"2015/12/23","229.7000","1551031.0000","232.1800","233.4500","228.1300"
|
||||
"2015/12/22","229.9500","1958836.0000","234.9900","236.5500","229.6300"
|
||||
"2015/12/21","232.5600","1951581.0000","231.6900","235.8300","231.0800"
|
||||
"2015/12/18","230.4600","3008057.0000","232.8900","235.9000","229.2900"
|
||||
"2015/12/17","233.3900","3294460.0000","233.9400","237.7600","229.8149"
|
||||
"2015/12/16","234.5100","5100443.0000","222.1000","234.8800","220.7300"
|
||||
"2015/12/15","221.0900","2241686.0000","221.8200","222.2200","218.0000"
|
||||
"2015/12/14","218.5800","2827797.0000","217.5100","220.9200","214.8700"
|
||||
"2015/12/11","217.0200","3259114.0000","225.2400","225.7500","216.6400"
|
||||
"2015/12/10","227.0700","2070088.0000","224.7100","228.4900","223.6400"
|
||||
"2015/12/09","224.5200","3057036.0000","226.7000","227.5000","220.7200"
|
||||
"2015/12/08","226.7200","2682259.0000","227.5200","228.8000","224.2000"
|
||||
"2015/12/07","231.1300","3140864.0000","227.7000","235.6300","226.1500"
|
||||
"2015/12/04","230.3800","2572014.0000","232.4600","233.2700","227.6600"
|
||||
"2015/12/03","232.7100","2937233.0000","235.4800","237.4500","230.0000"
|
||||
"2015/12/02","231.9900","2980644.0000","237.0000","238.6000","231.2300"
|
||||
"2015/12/01","237.1900","3728562.0000","231.0600","238.0000","231.0500"
|
||||
"2015/11/30","230.2600","2591205.0000","231.7900","234.2800","229.0800"
|
||||
"2015/11/27","231.6100","1949353.0000","231.0600","232.2500","227.0100"
|
||||
"2015/11/25","229.6400","3986945.0000","221.3400","230.8250","220.3750"
|
||||
"2015/11/24","218.2500","2478389.0000","215.3700","221.0000","215.0000"
|
||||
"2015/11/23","217.7500","2525196.0000","217.3500","219.1800","214.6798"
|
||||
"2015/11/20","220.0100","4394199.0000","223.4900","225.0000","213.5800"
|
||||
"2015/11/19","221.8000","2499593.0000","220.5400","226.1900","220.3000"
|
||||
"2015/11/18","221.0700","2810200.0000","214.5000","221.3800","212.5200"
|
||||
"2015/11/17","214.0000","2148326.0000","215.2000","216.0000","211.4000"
|
||||
"2015/11/16","214.3100","2920362.0000","206.0900","214.9800","205.8000"
|
||||
"2015/11/13","207.1900","3423139.0000","212.9500","212.9900","206.5200"
|
||||
"2015/11/12","212.9400","2913511.0000","217.8500","219.0000","212.6600"
|
||||
"2015/11/11","219.0800","3337501.0000","217.7700","219.4800","213.6300"
|
||||
"2015/11/10","216.5000","4612408.0000","223.4800","223.7000","216.0800"
|
||||
"2015/11/09","225.3300","3846179.0000","232.9900","232.9900","224.3100"
|
||||
"2015/11/06","232.3600","2444264.0000","230.7000","233.3590","229.5000"
|
||||
"2015/11/05","231.7700","4494944.0000","230.5800","234.5843","229.1900"
|
||||
"2015/11/04","231.6300","12713530.0000","227.0000","232.7400","225.2000"
|
||||
"2015/11/03","208.3500","8065091.0000","213.8500","214.4400","207.7500"
|
||||
"2015/11/02","213.7900","3924514.0000","208.9200","215.8000","207.2200"
|
||||
"2015/10/30","206.9300","4432433.0000","210.4000","211.6300","203.8900"
|
||||
"2015/10/29","211.6300","1794743.0000","211.7500","213.7481","210.6400"
|
||||
"2015/10/28","212.9600","2726880.0000","211.3100","213.4500","208.3000"
|
||||
"2015/10/27","210.3500","3512832.0000","214.8400","217.1000","207.5100"
|
||||
"2015/10/26","215.2600","3388227.0000","211.3800","215.8800","210.0000"
|
||||
"2015/10/23","209.0900","4226411.0000","215.0000","215.3500","207.6900"
|
||||
"2015/10/22","211.7200","2818801.0000","211.5600","215.7500","209.4000"
|
||||
"2015/10/21","210.0900","4177956.0000","211.9900","214.8100","208.8000"
|
||||
"2015/10/20","213.0300","14877020.0000","227.7200","228.6000","202.0000"
|
||||
"2015/10/19","228.1000","2506836.0000","226.5000","231.1500","224.9400"
|
||||
"2015/10/16","227.0100","4327574.0000","223.0400","230.4805","222.8700"
|
||||
"2015/10/15","221.3100","2835920.0000","216.4300","221.7300","213.7000"
|
||||
|
@@ -0,0 +1,115 @@
|
||||
from praisonaiagents import Agent, Task, PraisonAIAgents
|
||||
import os
|
||||
import requests
|
||||
from typing import Any, Dict, List, Optional
|
||||
from pydantic import BaseModel, Field
|
||||
|
||||
class EXASearchTool(BaseModel):
|
||||
"""Wrapper for EXA Search API."""
|
||||
search_url: str = "https://api.exa.ai/search"
|
||||
headers: Dict = {
|
||||
"accept": "application/json",
|
||||
"content-type": "application/json",
|
||||
}
|
||||
max_results: Optional[int] = None
|
||||
|
||||
def run(self, query: str) -> str:
|
||||
"""Run query through EXA and return concatenated results.
|
||||
|
||||
Args:
|
||||
query (str): The search query to use
|
||||
|
||||
Returns:
|
||||
str: The concatenated search results
|
||||
"""
|
||||
payload = {
|
||||
"query": query,
|
||||
"type": "magic",
|
||||
}
|
||||
|
||||
headers = self.headers.copy()
|
||||
headers["x-api-key"] = os.environ['EXA_API_KEY']
|
||||
|
||||
response = requests.post(self.search_url, json=payload, headers=headers)
|
||||
results = response.json()
|
||||
|
||||
if 'results' in results:
|
||||
return self._parse_results(results['results'])
|
||||
return ""
|
||||
|
||||
def results(self, query: str, max_results: Optional[int] = None) -> List[Dict[str, Any]]:
|
||||
"""Run query through EXA and return metadata.
|
||||
|
||||
Args:
|
||||
query (str): The search query to use
|
||||
max_results (Optional[int]): Maximum number of results to return
|
||||
|
||||
Returns:
|
||||
List[Dict[str, Any]]: List of result dictionaries
|
||||
"""
|
||||
payload = {
|
||||
"query": query,
|
||||
"type": "magic",
|
||||
}
|
||||
|
||||
headers = self.headers.copy()
|
||||
headers["x-api-key"] = os.environ['EXA_API_KEY']
|
||||
|
||||
response = requests.post(self.search_url, json=payload, headers=headers)
|
||||
results = response.json()
|
||||
|
||||
if 'results' in results:
|
||||
return results['results'][:max_results] if max_results else results['results']
|
||||
return []
|
||||
|
||||
def _parse_results(self, results: List[Dict[str, Any]]) -> str:
|
||||
"""Parse results into a readable string format.
|
||||
|
||||
Args:
|
||||
results (List[Dict[str, Any]]): List of result dictionaries
|
||||
|
||||
Returns:
|
||||
str: Formatted string of results
|
||||
"""
|
||||
strings = []
|
||||
for result in results:
|
||||
try:
|
||||
strings.append('\n'.join([
|
||||
f"Title: {result['title']}",
|
||||
f"Score: {result['score']}",
|
||||
f"Url: {result['url']}",
|
||||
f"ID: {result['id']}",
|
||||
"---"
|
||||
]))
|
||||
except KeyError:
|
||||
continue
|
||||
|
||||
content = '\n'.join(strings)
|
||||
return f"\nSearch results: {content}\n"
|
||||
|
||||
# Create an agent with the tool
|
||||
agent = Agent(
|
||||
name="SearchAgent",
|
||||
role="Research Assistant",
|
||||
goal="Search for information about 'AI Agents Framework'",
|
||||
backstory="I am an AI assistant that can search GitHub.",
|
||||
tools=[EXASearchTool],
|
||||
self_reflect=False
|
||||
)
|
||||
|
||||
# Create tasks to demonstrate both tools
|
||||
task = Task(
|
||||
name="search_task",
|
||||
description="Search for information about 'AI Agents Framework'",
|
||||
expected_output="Information about AI Agents Framework",
|
||||
agent=agent
|
||||
)
|
||||
|
||||
# Create and start the workflow
|
||||
agents = PraisonAIAgents(
|
||||
agents=[agent],
|
||||
tasks=[task],
|
||||
verbose=True
|
||||
)
|
||||
|
||||
agents.start()
|
||||
Generated
+2168
-1
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,36 @@
|
||||
from praisonaiagents import Agent, Task, PraisonAIAgents
|
||||
|
||||
# Create Video Analysis Agent
|
||||
video_agent = Agent(
|
||||
name="VideoAnalyst",
|
||||
role="Video Analysis Specialist",
|
||||
goal="Analyze images and videos to extract meaningful information",
|
||||
backstory="""You are an expert in computer vision and image analysis.
|
||||
You excel at describing images, detecting objects, and understanding visual content.""",
|
||||
llm="gpt-4o-mini",
|
||||
self_reflect=False
|
||||
)
|
||||
|
||||
# Task with Video File
|
||||
task1 = Task(
|
||||
name="analyze_video",
|
||||
description="""Watch this video and provide:
|
||||
1. A summary of the main events
|
||||
2. Key objects and people visible
|
||||
3. Any text or important information shown
|
||||
4. The overall context and setting""",
|
||||
expected_output="Comprehensive analysis of the video content",
|
||||
agent=video_agent,
|
||||
images=["video.mp4"]
|
||||
)
|
||||
|
||||
# Create PraisonAIAgents instance
|
||||
agents = PraisonAIAgents(
|
||||
agents=[video_agent],
|
||||
tasks=[task1],
|
||||
process="sequential",
|
||||
verbose=1
|
||||
)
|
||||
|
||||
# Run all tasks
|
||||
agents.start()
|
||||
@@ -0,0 +1,5 @@
|
||||
from praisonaiagents import Agent, Tools
|
||||
from praisonaiagents.tools import duckduckgo
|
||||
|
||||
agent = Agent(instructions="You are a Web Search Agent", tools=[duckduckgo])
|
||||
agent.start("Search about AI 2024")
|
||||
@@ -0,0 +1,16 @@
|
||||
from praisonaiagents import Agent, Task, PraisonAIAgents
|
||||
from praisonaiagents.tools import wiki_search, wiki_summary, wiki_page, wiki_random, wiki_language
|
||||
|
||||
agent = Agent(
|
||||
instructions="You are a Wikipedia Agent",
|
||||
tools=[wiki_search, wiki_summary, wiki_page, wiki_random, wiki_language],
|
||||
self_reflect=True,
|
||||
min_reflect=3,
|
||||
max_reflect=5,
|
||||
)
|
||||
agent.start(
|
||||
"What is the history of AI?"
|
||||
"First search the history of AI"
|
||||
"Read the page of the history of AI"
|
||||
"Get the summary of the page"
|
||||
)
|
||||
@@ -0,0 +1,124 @@
|
||||
---
|
||||
title: "AI Agents"
|
||||
description: "Overview of all available PraisonAI agents and their capabilities"
|
||||
icon: "robot"
|
||||
---
|
||||
|
||||
PraisonAI provides a diverse set of specialized agents for various tasks. Each agent is designed with specific capabilities and tools to handle different types of tasks effectively.
|
||||
|
||||
```mermaid
|
||||
graph LR
|
||||
%% Define the main flow
|
||||
Start([▶ Start]) --> Agent1
|
||||
Agent1 --> Process[⚙ Process]
|
||||
Process --> Agent2
|
||||
Agent2 --> Output([✓ Output])
|
||||
Process -.-> Agent1
|
||||
|
||||
%% Define subgraphs for agents and their tasks
|
||||
subgraph Agent1[ ]
|
||||
Task1[📋 Task]
|
||||
AgentIcon1[🤖 AI Agent]
|
||||
Tools1[🔧 Tools]
|
||||
|
||||
Task1 --- AgentIcon1
|
||||
AgentIcon1 --- Tools1
|
||||
end
|
||||
|
||||
subgraph Agent2[ ]
|
||||
Task2[📋 Task]
|
||||
AgentIcon2[🤖 AI Agent]
|
||||
Tools2[🔧 Tools]
|
||||
|
||||
Task2 --- AgentIcon2
|
||||
AgentIcon2 --- Tools2
|
||||
end
|
||||
|
||||
classDef input fill:#8B0000,stroke:#7C90A0,color:#fff
|
||||
classDef process fill:#189AB4,stroke:#7C90A0,color:#fff
|
||||
classDef tools fill:#2E8B57,stroke:#7C90A0,color:#fff
|
||||
classDef transparent fill:none,stroke:none
|
||||
|
||||
class Start,Output,Task1,Task2 input
|
||||
class Process,AgentIcon1,AgentIcon2 process
|
||||
class Tools1,Tools2 tools
|
||||
class Agent1,Agent2 transparent
|
||||
```
|
||||
|
||||
## Data & Analysis
|
||||
|
||||
<CardGroup cols={2}>
|
||||
<Card title="Data Analyst" icon="chart-line" href="/agents/data-analyst">
|
||||
Analyze data from various sources, create visualizations, and generate insights.
|
||||
</Card>
|
||||
<Card title="Finance" icon="money-bill-trend-up" href="/agents/finance">
|
||||
Track stocks, analyze financial data, and provide investment recommendations.
|
||||
</Card>
|
||||
<Card title="Research" icon="magnifying-glass-chart" href="/agents/research">
|
||||
Conduct comprehensive research and analysis across various topics.
|
||||
</Card>
|
||||
<Card title="Wikipedia" icon="book" href="/agents/wikipedia">
|
||||
Search and extract information from Wikipedia articles.
|
||||
</Card>
|
||||
</CardGroup>
|
||||
|
||||
## Media & Content
|
||||
|
||||
<CardGroup cols={2}>
|
||||
<Card title="Image Analysis" icon="image" href="/agents/image">
|
||||
Analyze and understand visual content from images.
|
||||
</Card>
|
||||
<Card title="Image to Text" icon="text" href="/agents/image-to-text">
|
||||
Convert images to textual descriptions and extract text content.
|
||||
</Card>
|
||||
<Card title="Video" icon="video" href="/agents/video">
|
||||
Analyze video content and extract meaningful information.
|
||||
</Card>
|
||||
<Card title="Markdown" icon="markdown" href="/agents/markdown">
|
||||
Generate and format content in Markdown syntax.
|
||||
</Card>
|
||||
</CardGroup>
|
||||
|
||||
## Search & Recommendations
|
||||
|
||||
<CardGroup cols={2}>
|
||||
<Card title="Web Search" icon="globe" href="/agents/websearch">
|
||||
Perform intelligent web searches and gather information.
|
||||
</Card>
|
||||
<Card title="Recommendation" icon="thumbs-up" href="/agents/recommendation">
|
||||
Generate personalized recommendations based on preferences.
|
||||
</Card>
|
||||
<Card title="Shopping" icon="shop" href="/agents/shopping">
|
||||
Compare prices and find the best deals across stores.
|
||||
</Card>
|
||||
<Card title="Planning" icon="calendar" href="/agents/planning">
|
||||
Create travel plans and detailed itineraries.
|
||||
</Card>
|
||||
</CardGroup>
|
||||
|
||||
## Development
|
||||
|
||||
<CardGroup cols={2}>
|
||||
<Card title="Programming" icon="code" href="/agents/programming">
|
||||
Write, analyze, and debug code across multiple languages.
|
||||
</Card>
|
||||
<Card title="Single Agent" icon="circle-1" href="/agents/single">
|
||||
Simple, focused agent for basic tasks without external tools.
|
||||
</Card>
|
||||
</CardGroup>
|
||||
|
||||
## Getting Started
|
||||
|
||||
Each agent can be easily initialized and customized for your specific needs. Here's a basic example:
|
||||
|
||||
```python
|
||||
from praisonaiagents import Agent
|
||||
|
||||
# Create an agent with specific instructions
|
||||
agent = Agent(instructions="Your task-specific instructions")
|
||||
|
||||
# Start the agent with a task
|
||||
response = agent.start("Your task description")
|
||||
```
|
||||
|
||||
For more detailed information about each agent, click on the respective cards above.
|
||||
@@ -0,0 +1,120 @@
|
||||
---
|
||||
title: "Data Analyst Agent"
|
||||
sidebarTitle: "Data Analyst"
|
||||
description: "Learn how to create AI agents for data analysis and insights generation."
|
||||
icon: "chart-line"
|
||||
---
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
In[Data Source] --> Reader[Data Reader]
|
||||
Reader --> Analyzer[Data Analyzer]
|
||||
Analyzer --> Generator[Insights Generator]
|
||||
Generator --> Out[Output]
|
||||
|
||||
style In fill:#8B0000,color:#fff
|
||||
style Reader fill:#2E8B57,color:#fff
|
||||
style Analyzer fill:#2E8B57,color:#fff
|
||||
style Generator fill:#2E8B57,color:#fff
|
||||
style Out fill:#8B0000,color:#fff
|
||||
```
|
||||
|
||||
A workflow demonstrating how the Data Analyst Agent can read data from various sources, analyze it, and generate insights.
|
||||
|
||||
## Quick Start
|
||||
|
||||
<Steps>
|
||||
<Step title="Install Package">
|
||||
First, install the PraisonAI Agents package:
|
||||
```bash
|
||||
pip install praisonaiagents
|
||||
```
|
||||
</Step>
|
||||
|
||||
<Step title="Set API Key">
|
||||
Set your OpenAI API key as an environment variable:
|
||||
```bash
|
||||
export OPENAI_API_KEY=your_api_key_here
|
||||
```
|
||||
</Step>
|
||||
|
||||
<Step title="Create Script">
|
||||
Create a new file `data_analysis.py`:
|
||||
```python
|
||||
from praisonaiagents import Agent, Tools
|
||||
from praisonaiagents.tools import (
|
||||
read_csv, read_excel, write_csv, write_excel,
|
||||
filter_data, get_summary, group_by, pivot_table
|
||||
)
|
||||
|
||||
agent = Agent(
|
||||
instructions="You are a Data Analyst Agent",
|
||||
tools=[
|
||||
read_csv, read_excel, write_csv, write_excel,
|
||||
filter_data, get_summary, group_by, pivot_table
|
||||
]
|
||||
)
|
||||
|
||||
# Start analysis with a specific task
|
||||
agent.start(f"""
|
||||
Read the data from the csv file {os.path.join(os.path.dirname(__file__), "tesla-stock-price.csv")}
|
||||
Analyse the data and give me the insights
|
||||
read_csv to read the file
|
||||
""")
|
||||
```
|
||||
</Step>
|
||||
</Steps>
|
||||
|
||||
## Understanding Data Analysis Workflow
|
||||
|
||||
The Data Analyst Agent is designed to perform comprehensive data analysis tasks using a suite of specialized tools. Here's how it works:
|
||||
|
||||
1. **Data Reading**: The agent can read data from various sources:
|
||||
- CSV files using `read_csv`
|
||||
- Excel files using `read_excel`
|
||||
|
||||
2. **Data Analysis**: Multiple analysis tools are available:
|
||||
- `filter_data`: Filter datasets based on conditions
|
||||
- `get_summary`: Generate statistical summaries
|
||||
- `group_by`: Group data by specific columns
|
||||
- `pivot_table`: Create pivot tables for analysis
|
||||
|
||||
3. **Data Export**: Results can be exported to:
|
||||
- CSV format using `write_csv`
|
||||
- Excel format using `write_excel`
|
||||
|
||||
## Features
|
||||
|
||||
<CardGroup cols={2}>
|
||||
<Card title="Multiple Data Sources" icon="table">
|
||||
Support for both CSV and Excel file formats.
|
||||
</Card>
|
||||
<Card title="Analysis Tools" icon="calculator">
|
||||
Comprehensive suite of analysis tools including filtering, summarization, and pivoting.
|
||||
</Card>
|
||||
<Card title="Data Export" icon="file-export">
|
||||
Export capabilities to various formats.
|
||||
</Card>
|
||||
<Card title="Automated Insights" icon="lightbulb">
|
||||
Automatic generation of data insights and patterns.
|
||||
</Card>
|
||||
</CardGroup>
|
||||
|
||||
## Example Usage
|
||||
|
||||
```python
|
||||
# Example: Analyzing stock data
|
||||
agent.start("""
|
||||
1. Read 'stock_data.csv'
|
||||
2. Filter data for the last 30 days
|
||||
3. Calculate daily returns
|
||||
4. Generate summary statistics
|
||||
5. Export results to 'analysis_results.xlsx'
|
||||
""")
|
||||
```
|
||||
|
||||
## Next Steps
|
||||
|
||||
- Learn about [Prompt Chaining](/features/promptchaining) for complex analysis workflows
|
||||
- Explore [Evaluator Optimizer](/features/evaluator-optimiser) for improving analysis accuracy
|
||||
- Check out other specialized agents like the [Finance Agent](/agents/finance) for specific use cases
|
||||
@@ -0,0 +1,97 @@
|
||||
---
|
||||
title: "Finance Agent"
|
||||
sidebarTitle: "Finance"
|
||||
description: "Learn how to create AI agents for financial analysis and investment recommendations."
|
||||
icon: "money-bill-trend-up"
|
||||
---
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
In[Request] --> Price[Stock Price]
|
||||
Price --> Info[Stock Info]
|
||||
Info --> History[Historical Data]
|
||||
History --> Out[Investment Advice]
|
||||
|
||||
style In fill:#8B0000,color:#fff
|
||||
style Price fill:#2E8B57,color:#fff
|
||||
style Info fill:#2E8B57,color:#fff
|
||||
style History fill:#2E8B57,color:#fff
|
||||
style Out fill:#8B0000,color:#fff
|
||||
```
|
||||
|
||||
A workflow demonstrating how the Finance Agent can analyze stock market data and provide investment recommendations.
|
||||
|
||||
## Quick Start
|
||||
|
||||
<Steps>
|
||||
<Step title="Install Package">
|
||||
First, install the PraisonAI Agents package:
|
||||
```bash
|
||||
pip install praisonaiagents
|
||||
```
|
||||
</Step>
|
||||
|
||||
<Step title="Set API Key">
|
||||
Set your OpenAI API key as an environment variable:
|
||||
```bash
|
||||
export OPENAI_API_KEY=your_api_key_here
|
||||
```
|
||||
</Step>
|
||||
|
||||
<Step title="Create Script">
|
||||
Create a new file `finance_analysis.py`:
|
||||
```python
|
||||
from praisonaiagents import Agent, Tools
|
||||
from praisonaiagents.tools import get_stock_price, get_stock_info, get_historical_data
|
||||
|
||||
agent = Agent(
|
||||
instructions="You are a Research Agent",
|
||||
tools=[get_stock_price, get_stock_info, get_historical_data]
|
||||
)
|
||||
agent.start("Understand current stock price and historical data of Apple and Google. Tell me if I can invest in them")
|
||||
```
|
||||
</Step>
|
||||
</Steps>
|
||||
|
||||
## Understanding Financial Analysis
|
||||
|
||||
The Finance Agent specializes in stock market analysis and investment recommendations using three key components:
|
||||
|
||||
1. **Real-time Price Data**: Uses `get_stock_price` to fetch current market prices
|
||||
2. **Company Information**: Retrieves company details using `get_stock_info`
|
||||
3. **Historical Analysis**: Analyzes trends with `get_historical_data`
|
||||
|
||||
## Features
|
||||
|
||||
<CardGroup cols={2}>
|
||||
<Card title="Real-time Data" icon="clock">
|
||||
Access to current stock market prices and information.
|
||||
</Card>
|
||||
<Card title="Company Analysis" icon="building">
|
||||
Detailed company information and fundamentals.
|
||||
</Card>
|
||||
<Card title="Historical Trends" icon="chart-line">
|
||||
Analysis of historical price movements and patterns.
|
||||
</Card>
|
||||
<Card title="Investment Advice" icon="money-bill">
|
||||
AI-powered investment recommendations.
|
||||
</Card>
|
||||
</CardGroup>
|
||||
|
||||
## Example Usage
|
||||
|
||||
```python
|
||||
# Example: Analyzing specific stocks
|
||||
agent.start("""
|
||||
1. Get current prices for AAPL and GOOGL
|
||||
2. Retrieve company information
|
||||
3. Analyze 6-month historical data
|
||||
4. Provide investment recommendations
|
||||
""")
|
||||
```
|
||||
|
||||
## Next Steps
|
||||
|
||||
- Learn about [Prompt Chaining](/features/promptchaining) for complex financial analysis
|
||||
- Explore [Evaluator Optimizer](/features/evaluator-optimiser) for improving recommendation accuracy
|
||||
- Check out the [Data Analyst Agent](/agents/data-analyst) for detailed data analysis capabilities
|
||||
@@ -0,0 +1,140 @@
|
||||
---
|
||||
title: "Image to Text Agent"
|
||||
sidebarTitle: "Image to Text"
|
||||
description: "Learn how to create AI agents for converting images to textual descriptions and extracting text from images."
|
||||
icon: "text"
|
||||
---
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
In[Image Input] --> OCR[Text Extractor]
|
||||
OCR --> Analyzer[Content Analyzer]
|
||||
Analyzer --> Generator[Description Generator]
|
||||
Generator --> Out[Text Output]
|
||||
|
||||
style In fill:#8B0000,color:#fff
|
||||
style OCR fill:#2E8B57,color:#fff
|
||||
style Analyzer fill:#2E8B57,color:#fff
|
||||
style Generator fill:#2E8B57,color:#fff
|
||||
style Out fill:#8B0000,color:#fff
|
||||
```
|
||||
|
||||
A workflow demonstrating how the Image-to-Text Agent can extract text from images and generate comprehensive descriptions.
|
||||
|
||||
## Quick Start
|
||||
|
||||
<Steps>
|
||||
<Step title="Install Package">
|
||||
First, install the PraisonAI Agents package:
|
||||
```bash
|
||||
pip install praisonaiagents
|
||||
```
|
||||
</Step>
|
||||
|
||||
<Step title="Set API Key">
|
||||
Set your OpenAI API key as an environment variable:
|
||||
```bash
|
||||
export OPENAI_API_KEY=your_api_key_here
|
||||
```
|
||||
</Step>
|
||||
|
||||
<Step title="Create Script">
|
||||
Create a new file `image_to_text.py`:
|
||||
```python
|
||||
from praisonaiagents import Agent, Task, PraisonAIAgents
|
||||
|
||||
# Create Image-to-Text Agent
|
||||
image_text_agent = Agent(
|
||||
name="ImageTextConverter",
|
||||
role="Image Text Extraction Specialist",
|
||||
goal="Convert image content to textual descriptions and extract text",
|
||||
backstory="""You are an expert in OCR and image understanding.
|
||||
You excel at extracting text from images and generating detailed descriptions.""",
|
||||
llm="gpt-4o-mini",
|
||||
self_reflect=False
|
||||
)
|
||||
|
||||
# Create text extraction task
|
||||
extraction_task = Task(
|
||||
name="extract_text",
|
||||
description="Extract all text from this image and describe its layout.",
|
||||
expected_output="Extracted text and layout description",
|
||||
agent=image_text_agent,
|
||||
images=["document.jpg"]
|
||||
)
|
||||
|
||||
# Create description task
|
||||
description_task = Task(
|
||||
name="generate_description",
|
||||
description="Generate a detailed description of the image content.",
|
||||
expected_output="Comprehensive description of visual elements",
|
||||
agent=image_text_agent,
|
||||
images=["scene.jpg"]
|
||||
)
|
||||
|
||||
# Create PraisonAIAgents instance
|
||||
agents = PraisonAIAgents(
|
||||
agents=[image_text_agent],
|
||||
tasks=[extraction_task, description_task],
|
||||
process="sequential",
|
||||
verbose=1
|
||||
)
|
||||
|
||||
# Run analysis
|
||||
agents.start()
|
||||
```
|
||||
</Step>
|
||||
</Steps>
|
||||
|
||||
## Understanding Image-to-Text Conversion
|
||||
|
||||
The Image-to-Text Agent combines multiple capabilities to convert visual content into textual form:
|
||||
|
||||
1. **OCR Processing**: Extracts text from images using optical character recognition
|
||||
2. **Layout Analysis**: Understands the spatial arrangement of text and visual elements
|
||||
3. **Content Description**: Generates natural language descriptions of image content
|
||||
4. **Text Formatting**: Preserves text formatting and structure where possible
|
||||
|
||||
## Features
|
||||
|
||||
<CardGroup cols={2}>
|
||||
<Card title="Text Extraction" icon="text">
|
||||
Advanced OCR capabilities for text extraction.
|
||||
</Card>
|
||||
<Card title="Layout Understanding" icon="table-layout">
|
||||
Analysis of text and content layout.
|
||||
</Card>
|
||||
<Card title="Content Description" icon="pen-to-square">
|
||||
Detailed descriptions of visual content.
|
||||
</Card>
|
||||
<Card title="Format Preservation" icon="paragraph">
|
||||
Maintains text formatting and structure.
|
||||
</Card>
|
||||
</CardGroup>
|
||||
|
||||
## Example Usage
|
||||
|
||||
```python
|
||||
# Example: Processing a document image
|
||||
document_task = Task(
|
||||
name="process_document",
|
||||
description="Extract text and analyze document layout",
|
||||
expected_output="Extracted text with layout information",
|
||||
agent=image_text_agent,
|
||||
images=["business_document.jpg"]
|
||||
)
|
||||
|
||||
# Run single task
|
||||
agents = PraisonAIAgents(
|
||||
agents=[image_text_agent],
|
||||
tasks=[document_task],
|
||||
process="sequential"
|
||||
)
|
||||
agents.start()
|
||||
```
|
||||
|
||||
## Next Steps
|
||||
|
||||
- Learn about [Prompt Chaining](/features/promptchaining) for complex document processing
|
||||
- Explore [Evaluator Optimizer](/features/evaluator-optimiser) for improving text extraction accuracy
|
||||
- Check out the [Image Agent](/agents/image) for pure image analysis capabilities
|
||||
@@ -0,0 +1,139 @@
|
||||
---
|
||||
title: "Image Analysis Agent"
|
||||
sidebarTitle: "Image Analysis"
|
||||
description: "Learn how to create AI agents for image analysis and visual content understanding."
|
||||
icon: "image"
|
||||
---
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
In[Image Input] --> Analyzer[Image Analyzer]
|
||||
Analyzer --> Detector[Object Detector]
|
||||
Detector --> Generator[Description Generator]
|
||||
Generator --> Out[Analysis Output]
|
||||
|
||||
style In fill:#8B0000,color:#fff
|
||||
style Analyzer fill:#2E8B57,color:#fff
|
||||
style Detector fill:#2E8B57,color:#fff
|
||||
style Generator fill:#2E8B57,color:#fff
|
||||
style Out fill:#8B0000,color:#fff
|
||||
```
|
||||
|
||||
A workflow demonstrating how the Image Analysis Agent can process and analyze visual content, detect objects, and generate detailed descriptions.
|
||||
|
||||
## Quick Start
|
||||
|
||||
<Steps>
|
||||
<Step title="Install Package">
|
||||
First, install the PraisonAI Agents package:
|
||||
```bash
|
||||
pip install praisonaiagents
|
||||
```
|
||||
</Step>
|
||||
|
||||
<Step title="Set API Key">
|
||||
Set your OpenAI API key as an environment variable:
|
||||
```bash
|
||||
export OPENAI_API_KEY=your_api_key_here
|
||||
```
|
||||
</Step>
|
||||
|
||||
<Step title="Create Script">
|
||||
Create a new file `image_analysis.py`:
|
||||
```python
|
||||
from praisonaiagents import Agent, Task, PraisonAIAgents
|
||||
|
||||
# Create Image Analysis Agent
|
||||
image_agent = Agent(
|
||||
name="ImageAnalyst",
|
||||
role="Image Analysis Specialist",
|
||||
goal="Analyze images and videos to extract meaningful information",
|
||||
backstory="""You are an expert in computer vision and image analysis.
|
||||
You excel at describing images, detecting objects, and understanding visual content.""",
|
||||
llm="gpt-4o-mini",
|
||||
self_reflect=False
|
||||
)
|
||||
|
||||
# Create tasks for different types of analysis
|
||||
task1 = Task(
|
||||
name="analyze_landmark",
|
||||
description="Describe this famous landmark and its architectural features.",
|
||||
expected_output="Detailed description of the landmark's architecture and significance",
|
||||
agent=image_agent,
|
||||
images=["https://example.com/landmark.jpg"]
|
||||
)
|
||||
|
||||
task2 = Task(
|
||||
name="analyze_local_image",
|
||||
description="What objects can you see in this image? Describe their arrangement.",
|
||||
expected_output="Detailed description of objects and their spatial relationships",
|
||||
agent=image_agent,
|
||||
images=["local_image.jpg"]
|
||||
)
|
||||
|
||||
# Create PraisonAIAgents instance
|
||||
agents = PraisonAIAgents(
|
||||
agents=[image_agent],
|
||||
tasks=[task1, task2],
|
||||
process="sequential",
|
||||
verbose=1
|
||||
)
|
||||
|
||||
# Run analysis
|
||||
agents.start()
|
||||
```
|
||||
</Step>
|
||||
</Steps>
|
||||
|
||||
## Understanding Image Analysis
|
||||
|
||||
The Image Analysis Agent is designed to process and understand visual content through several key capabilities:
|
||||
|
||||
1. **Image Input**: Supports both URL and local file inputs
|
||||
2. **Object Detection**: Identifies and locates objects within images
|
||||
3. **Architectural Analysis**: Specialized in analyzing architectural features
|
||||
4. **Spatial Understanding**: Describes spatial relationships between objects
|
||||
|
||||
## Features
|
||||
|
||||
<CardGroup cols={2}>
|
||||
<Card title="Multiple Input Sources" icon="images">
|
||||
Support for both URL and local image files.
|
||||
</Card>
|
||||
<Card title="Object Detection" icon="magnifying-glass">
|
||||
Advanced object detection and recognition.
|
||||
</Card>
|
||||
<Card title="Architectural Analysis" icon="building">
|
||||
Specialized analysis of architectural features.
|
||||
</Card>
|
||||
<Card title="Detailed Descriptions" icon="pen">
|
||||
Generation of comprehensive visual descriptions.
|
||||
</Card>
|
||||
</CardGroup>
|
||||
|
||||
## Example Usage
|
||||
|
||||
```python
|
||||
# Example: Analyzing a landmark image
|
||||
landmark_task = Task(
|
||||
name="analyze_famous_landmark",
|
||||
description="Analyze this historical landmark",
|
||||
expected_output="Architectural details and historical significance",
|
||||
agent=image_agent,
|
||||
images=["https://example.com/landmark.jpg"]
|
||||
)
|
||||
|
||||
# Run single task
|
||||
agents = PraisonAIAgents(
|
||||
agents=[image_agent],
|
||||
tasks=[landmark_task],
|
||||
process="sequential"
|
||||
)
|
||||
agents.start()
|
||||
```
|
||||
|
||||
## Next Steps
|
||||
|
||||
- Learn about [Prompt Chaining](/features/promptchaining) for complex image analysis workflows
|
||||
- Explore [Evaluator Optimizer](/features/evaluator-optimiser) for improving analysis accuracy
|
||||
- Check out the [Video Agent](/agents/video) for video content analysis
|
||||
@@ -0,0 +1,120 @@
|
||||
---
|
||||
title: "Markdown Agent"
|
||||
sidebarTitle: "Markdown"
|
||||
description: "Learn how to create AI agents for generating and formatting content in Markdown."
|
||||
icon: "markdown"
|
||||
---
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
In[Content Request] --> Generator[Content Generator]
|
||||
Generator --> Formatter[Markdown Formatter]
|
||||
Formatter --> Validator[Format Validator]
|
||||
Validator --> Out[Markdown Output]
|
||||
|
||||
style In fill:#8B0000,color:#fff
|
||||
style Generator fill:#2E8B57,color:#fff
|
||||
style Formatter fill:#2E8B57,color:#fff
|
||||
style Validator fill:#2E8B57,color:#fff
|
||||
style Out fill:#8B0000,color:#fff
|
||||
```
|
||||
|
||||
A workflow demonstrating how the Markdown Agent can generate and format content in Markdown syntax.
|
||||
|
||||
## Quick Start
|
||||
|
||||
<Steps>
|
||||
<Step title="Install Package">
|
||||
First, install the PraisonAI Agents package:
|
||||
```bash
|
||||
pip install praisonaiagents
|
||||
```
|
||||
</Step>
|
||||
|
||||
<Step title="Set API Key">
|
||||
Set your OpenAI API key as an environment variable:
|
||||
```bash
|
||||
export OPENAI_API_KEY=your_api_key_here
|
||||
```
|
||||
</Step>
|
||||
|
||||
<Step title="Create Script">
|
||||
Create a new file `markdown_generator.py`:
|
||||
```python
|
||||
from praisonaiagents import Agent
|
||||
|
||||
# Create Markdown Agent
|
||||
markdown_agent = Agent(
|
||||
name="MarkdownWriter",
|
||||
role="Markdown Content Specialist",
|
||||
goal="Generate well-formatted content in Markdown syntax",
|
||||
instructions="You are a Markdown Agent, output in markdown format",
|
||||
llm="gpt-4o-mini",
|
||||
self_reflect=False
|
||||
)
|
||||
|
||||
# Generate content
|
||||
response = markdown_agent.start(
|
||||
"Write a blog post about artificial intelligence"
|
||||
)
|
||||
|
||||
# Save to file
|
||||
with open('blog_post.md', 'w') as f:
|
||||
f.write(response)
|
||||
```
|
||||
</Step>
|
||||
</Steps>
|
||||
|
||||
## Understanding Markdown Generation
|
||||
|
||||
The Markdown Agent specializes in creating properly formatted Markdown content:
|
||||
|
||||
1. **Content Generation**: Creates original content based on prompts
|
||||
2. **Markdown Formatting**: Applies proper Markdown syntax
|
||||
3. **Structure Validation**: Ensures correct formatting
|
||||
4. **Document Organization**: Creates well-structured documents
|
||||
|
||||
## Features
|
||||
|
||||
<CardGroup cols={2}>
|
||||
<Card title="Content Creation" icon="pen-to-square">
|
||||
Generates original, well-structured content.
|
||||
</Card>
|
||||
<Card title="Markdown Syntax" icon="code">
|
||||
Proper implementation of Markdown formatting.
|
||||
</Card>
|
||||
<Card title="Document Structure" icon="sitemap">
|
||||
Organized document hierarchy and sections.
|
||||
</Card>
|
||||
<Card title="Format Validation" icon="check">
|
||||
Ensures correct Markdown syntax usage.
|
||||
</Card>
|
||||
</CardGroup>
|
||||
|
||||
## Example Usage
|
||||
|
||||
```python
|
||||
# Example: Generate a technical documentation
|
||||
agent = Agent(
|
||||
instructions="You are a Markdown Agent, output in markdown format"
|
||||
)
|
||||
|
||||
# Generate API documentation
|
||||
response = agent.start("""
|
||||
Create technical documentation for a REST API with:
|
||||
- Introduction
|
||||
- Authentication
|
||||
- Endpoints
|
||||
- Examples
|
||||
""")
|
||||
|
||||
# Save documentation
|
||||
with open('api_docs.md', 'w') as f:
|
||||
f.write(response)
|
||||
```
|
||||
|
||||
## Next Steps
|
||||
|
||||
- Learn about [Prompt Chaining](/features/promptchaining) for complex document generation
|
||||
- Explore [Evaluator Optimizer](/features/evaluator-optimiser) for improving content quality
|
||||
- Check out the [Documentation Agent](/agents/documentation) for specialized documentation generation
|
||||
@@ -0,0 +1,109 @@
|
||||
---
|
||||
title: "Planning Agent"
|
||||
sidebarTitle: "Planning"
|
||||
description: "Learn how to create AI agents for trip planning and itinerary generation."
|
||||
icon: "calendar"
|
||||
---
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
In[Request] --> Search[Web Search]
|
||||
Search --> Analyzer[Options Analyzer]
|
||||
Analyzer --> Generator[Plan Generator]
|
||||
Generator --> Out[Itinerary]
|
||||
|
||||
style In fill:#8B0000,color:#fff
|
||||
style Search fill:#2E8B57,color:#fff
|
||||
style Analyzer fill:#2E8B57,color:#fff
|
||||
style Generator fill:#2E8B57,color:#fff
|
||||
style Out fill:#8B0000,color:#fff
|
||||
```
|
||||
|
||||
A workflow demonstrating how the Planning Agent can search for travel options and create detailed itineraries.
|
||||
|
||||
## Quick Start
|
||||
|
||||
<Steps>
|
||||
<Step title="Install Package">
|
||||
First, install the PraisonAI Agents package:
|
||||
```bash
|
||||
pip install praisonaiagents
|
||||
```
|
||||
</Step>
|
||||
|
||||
<Step title="Set API Key">
|
||||
Set your OpenAI API key as an environment variable:
|
||||
```bash
|
||||
export OPENAI_API_KEY=your_api_key_here
|
||||
```
|
||||
</Step>
|
||||
|
||||
<Step title="Create Script">
|
||||
Create a new file `travel_planner.py`:
|
||||
```python
|
||||
from praisonaiagents import Agent, Tools
|
||||
from praisonaiagents.tools import duckduckgo
|
||||
|
||||
# Create Planning Agent
|
||||
planning_agent = Agent(
|
||||
name="TravelPlanner",
|
||||
role="Travel Planning Specialist",
|
||||
goal="Create comprehensive travel plans and itineraries",
|
||||
instructions="You are a Planning Agent",
|
||||
tools=[duckduckgo]
|
||||
)
|
||||
|
||||
# Generate travel plan
|
||||
response = planning_agent.start(
|
||||
"I want to go to London next week, find me a good hotel and flight"
|
||||
)
|
||||
|
||||
# Save plan
|
||||
with open('travel_plan.txt', 'w') as f:
|
||||
f.write(response)
|
||||
```
|
||||
</Step>
|
||||
</Steps>
|
||||
|
||||
## Understanding Travel Planning
|
||||
|
||||
The Planning Agent combines multiple capabilities to create comprehensive travel plans:
|
||||
|
||||
1. **Web Search**: Uses DuckDuckGo to find current travel options
|
||||
2. **Options Analysis**: Evaluates and compares different choices
|
||||
3. **Plan Generation**: Creates detailed itineraries
|
||||
4. **Recommendations**: Provides personalized suggestions
|
||||
|
||||
## Features
|
||||
|
||||
<CardGroup cols={2}>
|
||||
<Card title="Flight Search" icon="plane">
|
||||
Finds and compares flight options.
|
||||
</Card>
|
||||
<Card title="Hotel Booking" icon="hotel">
|
||||
Recommends suitable accommodations.
|
||||
</Card>
|
||||
<Card title="Itinerary Creation" icon="calendar-days">
|
||||
Generates detailed travel schedules.
|
||||
</Card>
|
||||
<Card title="Real-time Data" icon="clock">
|
||||
Uses current pricing and availability.
|
||||
</Card>
|
||||
</CardGroup>
|
||||
|
||||
## Example Usage
|
||||
|
||||
```python
|
||||
# Example: Create a weekend trip plan
|
||||
from praisonaiagents import Agent, Tools
|
||||
from praisonaiagents.tools import duckduckgo
|
||||
|
||||
agent = Agent(instructions="You are a Planning Agent", tools=[duckduckgo])
|
||||
agent.start("I want to go London next week, find me a good hotel and flight")
|
||||
```
|
||||
|
||||
## Next Steps
|
||||
|
||||
- Learn about [Prompt Chaining](/features/promptchaining) for complex travel planning
|
||||
- Explore [Evaluator Optimizer](/features/evaluator-optimiser) for improving recommendations
|
||||
- Check out the [Research Agent](/agents/research) for detailed destination research
|
||||
@@ -0,0 +1,125 @@
|
||||
---
|
||||
title: "Programming Agent"
|
||||
sidebarTitle: "Programming"
|
||||
description: "Learn how to create AI agents for code development, analysis, and execution."
|
||||
icon: "code"
|
||||
---
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
In[Code Request] --> Analyzer[Code Analyzer]
|
||||
Analyzer --> Generator[Code Generator]
|
||||
Generator --> Executor[Code Executor]
|
||||
Executor --> Debugger[Code Debugger]
|
||||
Debugger --> Out[Output]
|
||||
|
||||
style In fill:#8B0000,color:#fff
|
||||
style Analyzer fill:#2E8B57,color:#fff
|
||||
style Generator fill:#2E8B57,color:#fff
|
||||
style Executor fill:#2E8B57,color:#fff
|
||||
style Debugger fill:#2E8B57,color:#fff
|
||||
style Out fill:#8B0000,color:#fff
|
||||
```
|
||||
|
||||
A workflow demonstrating how the Programming Agent can analyze, generate, execute, and debug code.
|
||||
|
||||
## Quick Start
|
||||
|
||||
<Steps>
|
||||
<Step title="Install Package">
|
||||
First, install the PraisonAI Agents package:
|
||||
```bash
|
||||
pip install praisonaiagents
|
||||
```
|
||||
</Step>
|
||||
|
||||
<Step title="Set API Key">
|
||||
Set your OpenAI API key as an environment variable:
|
||||
```bash
|
||||
export OPENAI_API_KEY=your_api_key_here
|
||||
```
|
||||
</Step>
|
||||
|
||||
<Step title="Create Script">
|
||||
Create a new file `code_assistant.py`:
|
||||
```python
|
||||
from praisonaiagents import Agent, Tools
|
||||
from praisonaiagents.tools import execute_code, analyze_code, format_code, lint_code, disassemble_code # Code Tools
|
||||
from praisonaiagents.tools import execute_command, list_processes, kill_process, get_system_info # Shell Tools
|
||||
from praisonaiagents.tools import duckduckgo # Web Search Tool
|
||||
|
||||
agent = Agent(
|
||||
instructions="You are a Programming Agent", self_reflect=True, min_reflect=5, max_reflect=10,
|
||||
tools=[execute_code, analyze_code, format_code, lint_code, disassemble_code, execute_command, list_processes, kill_process, get_system_info, duckduckgo]
|
||||
)
|
||||
agent.start(
|
||||
"Write a python script using yfinance to find the stock price of Tesla"
|
||||
"First check if required packages are installed"
|
||||
"Run it using execute_code"
|
||||
"execute_command if you want to run any terminal command"
|
||||
"search internet using duckduckgo if you want to know update python package information"
|
||||
"Analyse the output using analyze_code and fix error if required"
|
||||
"if no package is installed, install it"
|
||||
"then run the code"
|
||||
)
|
||||
```
|
||||
</Step>
|
||||
</Steps>
|
||||
|
||||
## Understanding Code Development
|
||||
|
||||
The Programming Agent combines multiple tools for comprehensive code development:
|
||||
|
||||
1. **Code Tools**:
|
||||
- `execute_code`: Run Python code
|
||||
- `analyze_code`: Analyze code structure
|
||||
- `format_code`: Format code to standards
|
||||
- `lint_code`: Check code quality
|
||||
- `disassemble_code`: View bytecode
|
||||
|
||||
2. **Shell Tools**:
|
||||
- `execute_command`: Run terminal commands
|
||||
- `list_processes`: View running processes
|
||||
- `kill_process`: Terminate processes
|
||||
- `get_system_info`: System information
|
||||
|
||||
3. **Web Tools**:
|
||||
- `duckduckgo`: Search for programming resources
|
||||
|
||||
## Features
|
||||
|
||||
<CardGroup cols={2}>
|
||||
<Card title="Code Execution" icon="play">
|
||||
Run and test code directly.
|
||||
</Card>
|
||||
<Card title="Code Analysis" icon="magnifying-glass-code">
|
||||
Analyze and improve code quality.
|
||||
</Card>
|
||||
<Card title="System Integration" icon="terminal">
|
||||
Execute system commands and manage processes.
|
||||
</Card>
|
||||
<Card title="Package Management" icon="box">
|
||||
Handle dependencies and installations.
|
||||
</Card>
|
||||
</CardGroup>
|
||||
|
||||
## Example Usage
|
||||
|
||||
```python
|
||||
# Example: Create and run a data analysis script
|
||||
response = agent.start("""
|
||||
1. Create a script that:
|
||||
- Uses pandas for data analysis
|
||||
- Reads a CSV file
|
||||
- Performs basic statistics
|
||||
- Creates a visualization
|
||||
2. Check and install required packages
|
||||
3. Execute and analyze the results
|
||||
""")
|
||||
```
|
||||
|
||||
## Next Steps
|
||||
|
||||
- Learn about [Prompt Chaining](/features/promptchaining) for complex development workflows
|
||||
- Explore [Evaluator Optimizer](/features/evaluator-optimiser) for improving code quality
|
||||
- Check out the [Data Analyst Agent](/agents/data-analyst) for specialized data analysis
|
||||
@@ -0,0 +1,109 @@
|
||||
---
|
||||
title: "Recommendation Agent"
|
||||
sidebarTitle: "Recommendation"
|
||||
description: "Learn how to create AI agents for personalized recommendations across various domains."
|
||||
icon: "thumbs-up"
|
||||
---
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
In[User Preferences] --> Search[Content Search]
|
||||
Search --> Analyzer[Preference Analyzer]
|
||||
Analyzer --> Generator[Recommendation Generator]
|
||||
Generator --> Out[Recommendations]
|
||||
|
||||
style In fill:#8B0000,color:#fff
|
||||
style Search fill:#2E8B57,color:#fff
|
||||
style Analyzer fill:#2E8B57,color:#fff
|
||||
style Generator fill:#2E8B57,color:#fff
|
||||
style Out fill:#8B0000,color:#fff
|
||||
```
|
||||
|
||||
A workflow demonstrating how the Recommendation Agent can analyze preferences and generate personalized recommendations.
|
||||
|
||||
## Quick Start
|
||||
|
||||
<Steps>
|
||||
<Step title="Install Package">
|
||||
First, install the PraisonAI Agents package:
|
||||
```bash
|
||||
pip install praisonaiagents
|
||||
```
|
||||
</Step>
|
||||
|
||||
<Step title="Set API Key">
|
||||
Set your OpenAI API key as an environment variable:
|
||||
```bash
|
||||
export OPENAI_API_KEY=your_api_key_here
|
||||
```
|
||||
</Step>
|
||||
|
||||
<Step title="Create Script">
|
||||
Create a new file `recommendation_system.py`:
|
||||
```python
|
||||
from praisonaiagents import Agent, Tools
|
||||
from praisonaiagents.tools import duckduckgo
|
||||
|
||||
# Create Recommendation Agent
|
||||
recommendation_agent = Agent(
|
||||
name="RecommendationEngine",
|
||||
role="Recommendation Specialist",
|
||||
goal="Generate personalized recommendations based on preferences",
|
||||
instructions="You are a Recommendation Agent",
|
||||
tools=[duckduckgo]
|
||||
)
|
||||
|
||||
# Get recommendations
|
||||
response = recommendation_agent.start(
|
||||
"Recommend me a good movie to watch in 2025"
|
||||
)
|
||||
|
||||
# Save recommendations
|
||||
with open('recommendations.txt', 'w') as f:
|
||||
f.write(response)
|
||||
```
|
||||
</Step>
|
||||
</Steps>
|
||||
|
||||
## Understanding Recommendation System
|
||||
|
||||
The Recommendation Agent uses multiple approaches to generate personalized suggestions:
|
||||
|
||||
1. **Content Search**: Uses DuckDuckGo to find current options
|
||||
2. **Preference Analysis**: Understands user preferences
|
||||
3. **Recommendation Generation**: Creates personalized suggestions
|
||||
4. **Content Filtering**: Filters based on relevance and quality
|
||||
|
||||
## Features
|
||||
|
||||
<CardGroup cols={2}>
|
||||
<Card title="Personalization" icon="user">
|
||||
Tailored recommendations based on preferences.
|
||||
</Card>
|
||||
<Card title="Real-time Data" icon="clock">
|
||||
Up-to-date content and information.
|
||||
</Card>
|
||||
<Card title="Multi-domain" icon="layer-group">
|
||||
Recommendations across various categories.
|
||||
</Card>
|
||||
<Card title="Content Filtering" icon="filter">
|
||||
Quality-based content selection.
|
||||
</Card>
|
||||
</CardGroup>
|
||||
|
||||
## Example Usage
|
||||
|
||||
```python
|
||||
# Example: Get personalized recommendations
|
||||
from praisonaiagents import Agent, Tools
|
||||
from praisonaiagents.tools import duckduckgo
|
||||
|
||||
agent = Agent(instructions="You are a Recommendation Agent", tools=[duckduckgo])
|
||||
agent.start("Recommend me a good movie to watch in 2025")
|
||||
```
|
||||
|
||||
## Next Steps
|
||||
|
||||
- Learn about [Prompt Chaining](/features/promptchaining) for complex recommendation systems
|
||||
- Explore [Evaluator Optimizer](/features/evaluator-optimiser) for improving recommendation accuracy
|
||||
- Check out the [Research Agent](/agents/research) for detailed content research
|
||||
@@ -0,0 +1,108 @@
|
||||
---
|
||||
title: "Research Agent"
|
||||
sidebarTitle: "Research"
|
||||
description: "Learn how to create AI agents for conducting comprehensive research and analysis."
|
||||
icon: "magnifying-glass-chart"
|
||||
---
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
In[Research Query] --> Search[Web Search]
|
||||
Search --> Analyzer[Content Analyzer]
|
||||
Analyzer --> Synthesizer[Information Synthesizer]
|
||||
Synthesizer --> Out[Research Report]
|
||||
|
||||
style In fill:#8B0000,color:#fff
|
||||
style Search fill:#2E8B57,color:#fff
|
||||
style Analyzer fill:#2E8B57,color:#fff
|
||||
style Synthesizer fill:#2E8B57,color:#fff
|
||||
style Out fill:#8B0000,color:#fff
|
||||
```
|
||||
|
||||
A workflow demonstrating how the Research Agent can gather, analyze, and synthesize information from various sources.
|
||||
|
||||
## Quick Start
|
||||
|
||||
<Steps>
|
||||
<Step title="Install Package">
|
||||
First, install the PraisonAI Agents package:
|
||||
```bash
|
||||
pip install praisonaiagents
|
||||
```
|
||||
</Step>
|
||||
|
||||
<Step title="Set API Key">
|
||||
Set your OpenAI API key as an environment variable:
|
||||
```bash
|
||||
export OPENAI_API_KEY=your_api_key_here
|
||||
```
|
||||
</Step>
|
||||
|
||||
<Step title="Create Script">
|
||||
Create a new file `research_assistant.py`:
|
||||
```python
|
||||
from praisonaiagents import Agent, Tools
|
||||
from praisonaiagents.tools import duckduckgo
|
||||
|
||||
# Create Research Agent
|
||||
research_agent = Agent(
|
||||
name="ResearchAssistant",
|
||||
role="Research Specialist",
|
||||
goal="Conduct comprehensive research and analysis",
|
||||
instructions="You are a Research Agent",
|
||||
tools=[duckduckgo]
|
||||
)
|
||||
|
||||
# Conduct research
|
||||
response = research_agent.start(
|
||||
"Research about AI developments in 2024"
|
||||
)
|
||||
|
||||
# Save research findings
|
||||
with open('research_report.md', 'w') as f:
|
||||
f.write(response)
|
||||
```
|
||||
</Step>
|
||||
</Steps>
|
||||
|
||||
## Understanding Research Process
|
||||
|
||||
The Research Agent employs a systematic approach to information gathering and analysis:
|
||||
|
||||
1. **Web Search**: Uses DuckDuckGo to find relevant sources
|
||||
2. **Content Analysis**: Evaluates source credibility and relevance
|
||||
3. **Information Synthesis**: Combines findings into coherent insights
|
||||
4. **Report Generation**: Creates structured research reports
|
||||
|
||||
## Features
|
||||
|
||||
<CardGroup cols={2}>
|
||||
<Card title="Web Research" icon="globe">
|
||||
Comprehensive online information gathering.
|
||||
</Card>
|
||||
<Card title="Content Analysis" icon="microscope">
|
||||
In-depth evaluation of sources.
|
||||
</Card>
|
||||
<Card title="Information Synthesis" icon="layer-group">
|
||||
Integration of multiple sources.
|
||||
</Card>
|
||||
<Card title="Report Generation" icon="file-lines">
|
||||
Structured research documentation.
|
||||
</Card>
|
||||
</CardGroup>
|
||||
|
||||
## Example Usage
|
||||
|
||||
```python
|
||||
from praisonaiagents import Agent, Tools
|
||||
from praisonaiagents.tools import duckduckgo
|
||||
|
||||
agent = Agent(instructions="You are a Research Agent", tools=[duckduckgo])
|
||||
agent.start("Research about AI 2024")
|
||||
```
|
||||
|
||||
## Next Steps
|
||||
|
||||
- Learn about [Prompt Chaining](/features/promptchaining) for complex research projects
|
||||
- Explore [Evaluator Optimizer](/features/evaluator-optimiser) for improving research quality
|
||||
- Check out the [Data Analyst Agent](/agents/data-analyst) for data-driven research
|
||||
@@ -0,0 +1,109 @@
|
||||
---
|
||||
title: "Shopping Agent"
|
||||
sidebarTitle: "Shopping"
|
||||
description: "Learn how to create AI agents for price comparison and shopping assistance."
|
||||
icon: "shop"
|
||||
---
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
In[Product Query] --> Search[Store Search]
|
||||
Search --> Analyzer[Price Analyzer]
|
||||
Analyzer --> Comparator[Price Comparator]
|
||||
Comparator --> Out[Price Report]
|
||||
|
||||
style In fill:#8B0000,color:#fff
|
||||
style Search fill:#2E8B57,color:#fff
|
||||
style Analyzer fill:#2E8B57,color:#fff
|
||||
style Comparator fill:#2E8B57,color:#fff
|
||||
style Out fill:#8B0000,color:#fff
|
||||
```
|
||||
|
||||
A workflow demonstrating how the Shopping Agent can search for products, compare prices, and provide shopping recommendations.
|
||||
|
||||
## Quick Start
|
||||
|
||||
<Steps>
|
||||
<Step title="Install Package">
|
||||
First, install the PraisonAI Agents package:
|
||||
```bash
|
||||
pip install praisonaiagents
|
||||
```
|
||||
</Step>
|
||||
|
||||
<Step title="Set API Key">
|
||||
Set your OpenAI API key as an environment variable:
|
||||
```bash
|
||||
export OPENAI_API_KEY=your_api_key_here
|
||||
```
|
||||
</Step>
|
||||
|
||||
<Step title="Create Script">
|
||||
Create a new file `shopping_assistant.py`:
|
||||
```python
|
||||
from praisonaiagents import Agent, Tools
|
||||
from praisonaiagents.tools import duckduckgo
|
||||
|
||||
# Create Shopping Agent
|
||||
shopping_agent = Agent(
|
||||
name="ShoppingAssistant",
|
||||
role="Shopping Specialist",
|
||||
goal="Find the best prices and deals across stores",
|
||||
instructions="You are a Shopping Agent",
|
||||
tools=[duckduckgo]
|
||||
)
|
||||
|
||||
# Search for product prices
|
||||
response = shopping_agent.start(
|
||||
"I want to buy iPhone 16 Pro Max, check 5 stores and give me price in table"
|
||||
)
|
||||
|
||||
# Save price comparison
|
||||
with open('price_comparison.md', 'w') as f:
|
||||
f.write(response)
|
||||
```
|
||||
</Step>
|
||||
</Steps>
|
||||
|
||||
## Understanding Shopping Assistant
|
||||
|
||||
The Shopping Agent combines multiple capabilities for effective price comparison:
|
||||
|
||||
1. **Store Search**: Uses DuckDuckGo to find retailers
|
||||
2. **Price Analysis**: Gathers pricing information
|
||||
3. **Price Comparison**: Compares prices across stores
|
||||
4. **Deal Finding**: Identifies special offers and discounts
|
||||
|
||||
## Features
|
||||
|
||||
<CardGroup cols={2}>
|
||||
<Card title="Price Comparison" icon="scale-balanced">
|
||||
Compare prices across multiple stores.
|
||||
</Card>
|
||||
<Card title="Deal Detection" icon="tag">
|
||||
Find special offers and discounts.
|
||||
</Card>
|
||||
<Card title="Store Analysis" icon="store">
|
||||
Evaluate retailer reliability.
|
||||
</Card>
|
||||
<Card title="Price Tracking" icon="chart-line">
|
||||
Monitor price changes over time.
|
||||
</Card>
|
||||
</CardGroup>
|
||||
|
||||
## Example Usage
|
||||
|
||||
```python
|
||||
# Example: Compare product prices
|
||||
from praisonaiagents import Agent, Tools
|
||||
from praisonaiagents.tools import duckduckgo
|
||||
|
||||
agent = Agent(instructions="You are a Shopping Agent", tools=[duckduckgo])
|
||||
agent.start("I want to buy iPhone 16 Pro Max, check 5 stores and give me price in table")
|
||||
```
|
||||
|
||||
## Next Steps
|
||||
|
||||
- Learn about [Prompt Chaining](/features/promptchaining) for complex shopping research
|
||||
- Explore [Evaluator Optimizer](/features/evaluator-optimiser) for improving price accuracy
|
||||
- Check out the [Research Agent](/agents/research) for detailed product research
|
||||
@@ -0,0 +1,102 @@
|
||||
---
|
||||
title: "Single Agent"
|
||||
sidebarTitle: "Single"
|
||||
description: "Learn how to create a basic single-purpose AI agent for simple tasks."
|
||||
icon: "circle-1"
|
||||
---
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
In[Input] --> Agent[Single Agent]
|
||||
Agent --> Out[Output]
|
||||
|
||||
style In fill:#8B0000,color:#fff
|
||||
style Agent fill:#2E8B57,color:#fff
|
||||
style Out fill:#8B0000,color:#fff
|
||||
```
|
||||
|
||||
A workflow demonstrating how to create and use a simple single-purpose agent.
|
||||
|
||||
## Quick Start
|
||||
|
||||
<Steps>
|
||||
<Step title="Install Package">
|
||||
First, install the PraisonAI Agents package:
|
||||
```bash
|
||||
pip install praisonaiagents
|
||||
```
|
||||
</Step>
|
||||
|
||||
<Step title="Set API Key">
|
||||
Set your OpenAI API key as an environment variable:
|
||||
```bash
|
||||
export OPENAI_API_KEY=your_api_key_here
|
||||
```
|
||||
</Step>
|
||||
|
||||
<Step title="Create Script">
|
||||
Create a new file `simple_agent.py`:
|
||||
```python
|
||||
from praisonaiagents import Agent
|
||||
|
||||
agent = Agent(instructions="You are a Markdown Agent, output in markdown format")
|
||||
agent.start("Write a blog post about AI")
|
||||
```
|
||||
</Step>
|
||||
</Steps>
|
||||
|
||||
## Understanding Single Agent
|
||||
|
||||
The Single Agent is the simplest form of PraisonAI agent:
|
||||
|
||||
1. **Simple Setup**: Minimal configuration required
|
||||
2. **Single Purpose**: Focused on one specific task
|
||||
3. **Direct Execution**: Straightforward input-output flow
|
||||
4. **No Dependencies**: No external tools required
|
||||
|
||||
## Features
|
||||
|
||||
<CardGroup cols={2}>
|
||||
<Card title="Simple Setup" icon="square-1">
|
||||
Minimal configuration needed.
|
||||
</Card>
|
||||
<Card title="Focused Task" icon="bullseye">
|
||||
Single-purpose execution.
|
||||
</Card>
|
||||
<Card title="Quick Start" icon="bolt">
|
||||
Rapid implementation.
|
||||
</Card>
|
||||
<Card title="No Tools" icon="toolbox">
|
||||
No external dependencies.
|
||||
</Card>
|
||||
</CardGroup>
|
||||
|
||||
## Example Usage
|
||||
|
||||
```python
|
||||
# Example: Create a content generation agent
|
||||
from praisonaiagents import Agent
|
||||
|
||||
# Create content agent
|
||||
agent = Agent(
|
||||
instructions="You are a Content Generation Agent, create engaging content"
|
||||
)
|
||||
|
||||
# Generate content
|
||||
response = agent.start("""
|
||||
Write a short story about:
|
||||
- A future world
|
||||
- With advanced AI
|
||||
- And human collaboration
|
||||
""")
|
||||
|
||||
# Save the story
|
||||
with open('ai_story.txt', 'w') as f:
|
||||
f.write(response)
|
||||
```
|
||||
|
||||
## Next Steps
|
||||
|
||||
- Learn about [Prompt Chaining](/features/promptchaining) for more complex workflows
|
||||
- Explore [Evaluator Optimizer](/features/evaluator-optimiser) for improving output quality
|
||||
- Check out other specialized agents like the [Markdown Agent](/agents/markdown) for specific use cases
|
||||
@@ -0,0 +1,149 @@
|
||||
---
|
||||
title: "Video Agent"
|
||||
sidebarTitle: "Video"
|
||||
description: "Learn how to create AI agents for video analysis and content understanding."
|
||||
icon: "video"
|
||||
---
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
In[Video Input] --> Analyzer[Content Analyzer]
|
||||
Analyzer --> Detector[Object Detector]
|
||||
Detector --> Transcriber[Text Transcriber]
|
||||
Transcriber --> Out[Analysis Report]
|
||||
|
||||
style In fill:#8B0000,color:#fff
|
||||
style Analyzer fill:#2E8B57,color:#fff
|
||||
style Detector fill:#2E8B57,color:#fff
|
||||
style Transcriber fill:#2E8B57,color:#fff
|
||||
style Out fill:#8B0000,color:#fff
|
||||
```
|
||||
|
||||
A workflow demonstrating how the Video Agent can analyze video content, detect objects, and extract meaningful information.
|
||||
|
||||
## Quick Start
|
||||
|
||||
<Steps>
|
||||
<Step title="Install Package">
|
||||
First, install the PraisonAI Agents package:
|
||||
```bash
|
||||
pip install praisonaiagents
|
||||
```
|
||||
</Step>
|
||||
|
||||
<Step title="Set API Key">
|
||||
Set your OpenAI API key as an environment variable:
|
||||
```bash
|
||||
export OPENAI_API_KEY=your_api_key_here
|
||||
```
|
||||
</Step>
|
||||
|
||||
<Step title="Create Script">
|
||||
Create a new file `video_analyzer.py`:
|
||||
```python
|
||||
from praisonaiagents import Agent, Task, PraisonAIAgents
|
||||
|
||||
# Create Video Analysis Agent
|
||||
video_agent = Agent(
|
||||
name="VideoAnalyst",
|
||||
role="Video Analysis Specialist",
|
||||
goal="Analyze videos to extract meaningful information",
|
||||
backstory="""You are an expert in computer vision and video analysis.
|
||||
You excel at describing content, detecting objects, and understanding context.""",
|
||||
llm="gpt-4o-mini",
|
||||
self_reflect=False
|
||||
)
|
||||
|
||||
# Create video analysis task
|
||||
analysis_task = Task(
|
||||
name="analyze_video",
|
||||
description="""Analyze this video and provide:
|
||||
1. Summary of main events
|
||||
2. Key objects and people
|
||||
3. Text and important information
|
||||
4. Context and setting""",
|
||||
expected_output="Comprehensive video analysis",
|
||||
agent=video_agent,
|
||||
images=["video.mp4"]
|
||||
)
|
||||
|
||||
# Create PraisonAIAgents instance
|
||||
agents = PraisonAIAgents(
|
||||
agents=[video_agent],
|
||||
tasks=[analysis_task],
|
||||
process="sequential",
|
||||
verbose=1
|
||||
)
|
||||
|
||||
# Run analysis
|
||||
agents.start()
|
||||
```
|
||||
</Step>
|
||||
</Steps>
|
||||
|
||||
## Understanding Video Analysis
|
||||
|
||||
The Video Agent combines multiple capabilities for comprehensive video understanding:
|
||||
|
||||
1. **Content Analysis**: Analyzes video scenes and events
|
||||
2. **Object Detection**: Identifies objects and people
|
||||
3. **Text Extraction**: Captures text shown in videos
|
||||
4. **Context Understanding**: Interprets settings and situations
|
||||
|
||||
## Features
|
||||
|
||||
<CardGroup cols={2}>
|
||||
<Card title="Scene Analysis" icon="film">
|
||||
Detailed analysis of video scenes.
|
||||
</Card>
|
||||
<Card title="Object Detection" icon="cube">
|
||||
Identification of objects and people.
|
||||
</Card>
|
||||
<Card title="Text Extraction" icon="closed-captioning">
|
||||
Capture of text and captions.
|
||||
</Card>
|
||||
<Card title="Context Analysis" icon="sitemap">
|
||||
Understanding of video context.
|
||||
</Card>
|
||||
</CardGroup>
|
||||
|
||||
## Example Usage
|
||||
|
||||
```python
|
||||
# Example: Analyze a presentation video
|
||||
from praisonaiagents import Agent, Task, PraisonAIAgents
|
||||
|
||||
video_agent = Agent(
|
||||
name="VideoAnalyst",
|
||||
role="Video Analysis Specialist",
|
||||
goal="Extract information from presentation videos",
|
||||
llm="gpt-4o-mini"
|
||||
)
|
||||
|
||||
# Create presentation analysis task
|
||||
presentation_task = Task(
|
||||
name="analyze_presentation",
|
||||
description="""Analyze this presentation video:
|
||||
1. Extract key points
|
||||
2. Capture slide content
|
||||
3. Note speaker's main arguments
|
||||
4. Summarize Q&A session""",
|
||||
expected_output="Detailed presentation summary",
|
||||
agent=video_agent,
|
||||
images=["presentation.mp4"]
|
||||
)
|
||||
|
||||
# Run analysis
|
||||
agents = PraisonAIAgents(
|
||||
agents=[video_agent],
|
||||
tasks=[presentation_task],
|
||||
process="sequential"
|
||||
)
|
||||
agents.start()
|
||||
```
|
||||
|
||||
## Next Steps
|
||||
|
||||
- Learn about [Prompt Chaining](/features/promptchaining) for complex video analysis
|
||||
- Explore [Evaluator Optimizer](/features/evaluator-optimiser) for improving analysis accuracy
|
||||
- Check out the [Image Agent](/agents/image) for still image analysis
|
||||
@@ -0,0 +1,124 @@
|
||||
---
|
||||
title: "Web Search Agent"
|
||||
sidebarTitle: "Web Search"
|
||||
description: "Learn how to create AI agents for intelligent web searching and information gathering."
|
||||
icon: "globe"
|
||||
---
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
In[Search Query] --> Search[Web Search]
|
||||
Search --> Filter[Content Filter]
|
||||
Filter --> Summarizer[Content Summarizer]
|
||||
Summarizer --> Out[Search Results]
|
||||
|
||||
style In fill:#8B0000,color:#fff
|
||||
style Search fill:#2E8B57,color:#fff
|
||||
style Filter fill:#2E8B57,color:#fff
|
||||
style Summarizer fill:#2E8B57,color:#fff
|
||||
style Out fill:#8B0000,color:#fff
|
||||
```
|
||||
|
||||
A workflow demonstrating how the Web Search Agent can perform intelligent searches and process web content.
|
||||
|
||||
## Quick Start
|
||||
|
||||
<Steps>
|
||||
<Step title="Install Package">
|
||||
First, install the PraisonAI Agents package:
|
||||
```bash
|
||||
pip install praisonaiagents
|
||||
```
|
||||
</Step>
|
||||
|
||||
<Step title="Set API Key">
|
||||
Set your OpenAI API key as an environment variable:
|
||||
```bash
|
||||
export OPENAI_API_KEY=your_api_key_here
|
||||
```
|
||||
</Step>
|
||||
|
||||
<Step title="Create Script">
|
||||
Create a new file `web_search.py`:
|
||||
```python
|
||||
from praisonaiagents import Agent, Tools
|
||||
from praisonaiagents.tools import duckduckgo
|
||||
|
||||
# Create Web Search Agent
|
||||
search_agent = Agent(
|
||||
name="WebSearcher",
|
||||
role="Web Search Specialist",
|
||||
goal="Perform intelligent web searches and gather information",
|
||||
instructions="You are a Web Search Agent",
|
||||
tools=[duckduckgo]
|
||||
)
|
||||
|
||||
# Perform search
|
||||
response = search_agent.start(
|
||||
"Search about AI developments in 2024"
|
||||
)
|
||||
|
||||
# Save search results
|
||||
with open('search_results.md', 'w') as f:
|
||||
f.write(response)
|
||||
```
|
||||
</Step>
|
||||
</Steps>
|
||||
|
||||
## Understanding Web Search
|
||||
|
||||
The Web Search Agent employs sophisticated search strategies:
|
||||
|
||||
1. **Query Processing**: Optimizes search queries
|
||||
2. **Content Filtering**: Filters relevant results
|
||||
3. **Information Extraction**: Extracts key information
|
||||
4. **Result Summarization**: Summarizes findings
|
||||
|
||||
## Features
|
||||
|
||||
<CardGroup cols={2}>
|
||||
<Card title="Smart Search" icon="magnifying-glass">
|
||||
Intelligent query processing.
|
||||
</Card>
|
||||
<Card title="Content Filtering" icon="filter">
|
||||
Relevance-based filtering.
|
||||
</Card>
|
||||
<Card title="Information Extraction" icon="scissors">
|
||||
Key information extraction.
|
||||
</Card>
|
||||
<Card title="Result Summary" icon="list">
|
||||
Concise result summaries.
|
||||
</Card>
|
||||
</CardGroup>
|
||||
|
||||
## Example Usage
|
||||
|
||||
```python
|
||||
# Example: Perform topic research
|
||||
from praisonaiagents import Agent, Tools
|
||||
from praisonaiagents.tools import duckduckgo
|
||||
|
||||
agent = Agent(
|
||||
instructions="You are a Web Search Agent",
|
||||
tools=[duckduckgo]
|
||||
)
|
||||
|
||||
# Research specific topic
|
||||
response = agent.start("""
|
||||
Search for information about quantum computing:
|
||||
- Recent breakthroughs
|
||||
- Leading companies
|
||||
- Current applications
|
||||
- Future predictions
|
||||
""")
|
||||
|
||||
# Save research results
|
||||
with open('quantum_computing_research.md', 'w') as f:
|
||||
f.write(response)
|
||||
```
|
||||
|
||||
## Next Steps
|
||||
|
||||
- Learn about [Prompt Chaining](/features/promptchaining) for complex search workflows
|
||||
- Explore [Evaluator Optimizer](/features/evaluator-optimiser) for improving search relevance
|
||||
- Check out the [Research Agent](/agents/research) for comprehensive research capabilities
|
||||
@@ -0,0 +1,139 @@
|
||||
---
|
||||
title: "Wikipedia Agent"
|
||||
sidebarTitle: "Wikipedia"
|
||||
description: "Learn how to create AI agents for searching and extracting information from Wikipedia."
|
||||
icon: "book"
|
||||
---
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
In[Query] --> Search[Wiki Search]
|
||||
Search --> Page[Page Retrieval]
|
||||
Page --> Summary[Content Summary]
|
||||
Summary --> Out[Knowledge Output]
|
||||
|
||||
style In fill:#8B0000,color:#fff
|
||||
style Search fill:#2E8B57,color:#fff
|
||||
style Page fill:#2E8B57,color:#fff
|
||||
style Summary fill:#2E8B57,color:#fff
|
||||
style Out fill:#8B0000,color:#fff
|
||||
```
|
||||
|
||||
A workflow demonstrating how the Wikipedia Agent can search, retrieve, and summarize Wikipedia content.
|
||||
|
||||
## Quick Start
|
||||
|
||||
<Steps>
|
||||
<Step title="Install Package">
|
||||
First, install the PraisonAI Agents package:
|
||||
```bash
|
||||
pip install praisonaiagents
|
||||
```
|
||||
</Step>
|
||||
|
||||
<Step title="Set API Key">
|
||||
Set your OpenAI API key as an environment variable:
|
||||
```bash
|
||||
export OPENAI_API_KEY=your_api_key_here
|
||||
```
|
||||
</Step>
|
||||
|
||||
<Step title="Create Script">
|
||||
Create a new file `wikipedia_assistant.py`:
|
||||
```python
|
||||
from praisonaiagents import Agent, Task, PraisonAIAgents
|
||||
from praisonaiagents.tools import (
|
||||
wiki_search,
|
||||
wiki_summary,
|
||||
wiki_page,
|
||||
wiki_random,
|
||||
wiki_language
|
||||
)
|
||||
|
||||
# Create Wikipedia Agent
|
||||
wiki_agent = Agent(
|
||||
name="WikipediaAssistant",
|
||||
role="Wikipedia Research Specialist",
|
||||
goal="Extract and summarize Wikipedia content",
|
||||
instructions="You are a Wikipedia Agent",
|
||||
tools=[
|
||||
wiki_search,
|
||||
wiki_summary,
|
||||
wiki_page,
|
||||
wiki_random,
|
||||
wiki_language
|
||||
],
|
||||
self_reflect=True,
|
||||
min_reflect=3,
|
||||
max_reflect=5
|
||||
)
|
||||
|
||||
# Research a topic
|
||||
response = wiki_agent.start("""
|
||||
What is the history of AI?
|
||||
First search the history of AI
|
||||
Read the page of the history of AI
|
||||
Get the summary of the page
|
||||
""")
|
||||
|
||||
# Save research results
|
||||
with open('ai_history.md', 'w') as f:
|
||||
f.write(response)
|
||||
```
|
||||
</Step>
|
||||
</Steps>
|
||||
|
||||
## Understanding Wikipedia Research
|
||||
|
||||
The Wikipedia Agent provides comprehensive Wikipedia access through multiple tools:
|
||||
|
||||
1. **Wiki Search**: `wiki_search` for finding relevant articles
|
||||
2. **Page Access**: `wiki_page` for retrieving full articles
|
||||
3. **Summarization**: `wiki_summary` for concise overviews
|
||||
4. **Random Articles**: `wiki_random` for discovering content
|
||||
5. **Language Support**: `wiki_language` for multilingual access
|
||||
|
||||
## Features
|
||||
|
||||
<CardGroup cols={2}>
|
||||
<Card title="Article Search" icon="magnifying-glass">
|
||||
Find relevant Wikipedia articles.
|
||||
</Card>
|
||||
<Card title="Content Retrieval" icon="book-open">
|
||||
Access complete article content.
|
||||
</Card>
|
||||
<Card title="Summarization" icon="compress">
|
||||
Generate concise article summaries.
|
||||
</Card>
|
||||
<Card title="Multilingual" icon="language">
|
||||
Access content in multiple languages.
|
||||
</Card>
|
||||
</CardGroup>
|
||||
|
||||
## Example Usage
|
||||
|
||||
```python
|
||||
# Example: Research a scientific topic
|
||||
from praisonaiagents import Agent
|
||||
from praisonaiagents.tools import wiki_search, wiki_summary, wiki_page, wiki_random, wiki_language
|
||||
|
||||
agent = Agent(
|
||||
instructions="You are a Wikipedia Agent",
|
||||
tools=[wiki_search, wiki_summary, wiki_page, wiki_random, wiki_language],
|
||||
self_reflect=True,
|
||||
min_reflect=3,
|
||||
max_reflect=5,
|
||||
)
|
||||
agent.start(
|
||||
"What is the history of AI?"
|
||||
"First search the history of AI"
|
||||
"Read the page of the history of AI"
|
||||
"Get the summary of the page"
|
||||
)
|
||||
```
|
||||
|
||||
## Next Steps
|
||||
|
||||
- Learn about [Prompt Chaining](/features/promptchaining) for complex Wikipedia research
|
||||
- Explore [Evaluator Optimizer](/features/evaluator-optimiser) for improving research quality
|
||||
- Check out the [Research Agent](/agents/research) for broader research capabilities
|
||||
Loaded 100 of 256 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user