mirror of
https://github.com/MervinPraison/PraisonAI.git
synced 2026-11-08 08:11:07 -10:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1d8b814fcd | ||
|
|
6e8a5b98a8 | ||
|
|
59d0ff8c95 | ||
|
|
b2109faa06 | ||
|
|
024eaed456 | ||
|
|
4fd3a572cf | ||
|
|
baaf8b6256 | ||
|
|
fe4550d2bc | ||
|
|
db09a94425 | ||
|
|
2db36dc932 | ||
|
|
8c0e4277a4 | ||
|
|
41448617d5 | ||
|
|
49ea23c676 | ||
|
|
bb0dc63680 | ||
|
|
7774f2c565 | ||
|
|
5533fd3476 | ||
|
|
262a90a235 | ||
|
|
60928dcb90 | ||
|
|
c8552e1158 | ||
|
|
c57d7db9bb | ||
|
|
236abc2c83 | ||
|
|
76c5f8fe3f | ||
|
|
82750020d2 |
No files matched your search
+1
-1
@@ -1,6 +1,6 @@
|
||||
FROM python:3.11-slim
|
||||
WORKDIR /app
|
||||
COPY . .
|
||||
RUN pip install flask praisonai==2.0.50 gunicorn markdown
|
||||
RUN pip install flask praisonai==2.0.56 gunicorn markdown
|
||||
EXPOSE 8080
|
||||
CMD ["gunicorn", "-b", "0.0.0.0:8080", "api:app"]
|
||||
@@ -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
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
from praisonaiagents import Agent
|
||||
|
||||
# Detailed LLM configuration
|
||||
llm_config = {
|
||||
"model": "gemini/gemini-1.5-flash-latest", # Model name without provider prefix
|
||||
|
||||
# Core settings
|
||||
"temperature": 0.7, # Controls randomness (like temperature)
|
||||
"timeout": 30, # Timeout in seconds
|
||||
"top_p": 0.9, # Nucleus sampling parameter
|
||||
"max_tokens": 1000, # Max tokens in response
|
||||
|
||||
# Advanced parameters
|
||||
"presence_penalty": 0.1, # Penalize repetition of topics (-2.0 to 2.0)
|
||||
"frequency_penalty": 0.1, # Penalize token repetition (-2.0 to 2.0)
|
||||
|
||||
# API settings (optional)
|
||||
"api_key": None, # Your API key (or use environment variable)
|
||||
"base_url": None, # Custom API endpoint if needed
|
||||
|
||||
# Response formatting
|
||||
"response_format": { # Force specific response format
|
||||
"type": "text" # Options: "text", "json_object"
|
||||
},
|
||||
|
||||
# Additional controls
|
||||
"seed": 42, # For reproducible responses
|
||||
"stop_phrases": ["##", "END"], # Custom stop sequences
|
||||
}
|
||||
|
||||
agent = Agent(
|
||||
instructions="You are a helpful Assistant specialized in scientific explanations. "
|
||||
"Provide clear, accurate, and engaging responses.",
|
||||
llm=llm_config, # Pass the detailed configuration
|
||||
verbose=True, # Enable detailed output
|
||||
markdown=True, # Format responses in markdown
|
||||
self_reflect=True, # Enable self-reflection
|
||||
max_reflect=3, # Maximum reflection iterations
|
||||
min_reflect=1 # Minimum reflection iterations
|
||||
)
|
||||
|
||||
# Test the agent
|
||||
response = agent.start("Why is the sky blue? Please explain in simple terms.")
|
||||
|
||||
print(response)
|
||||
@@ -0,0 +1,18 @@
|
||||
import asyncio
|
||||
from praisonaiagents import Agent
|
||||
|
||||
async def main():
|
||||
agent = Agent(
|
||||
instructions="You are a helpful assistant",
|
||||
llm="gemini/gemini-1.5-flash-8b",
|
||||
self_reflect=True,
|
||||
verbose=True
|
||||
)
|
||||
|
||||
# Use achat instead of start/chat for async operation
|
||||
response = await agent.achat("Why sky is Blue in 1000 words?")
|
||||
print(response)
|
||||
|
||||
if __name__ == "__main__":
|
||||
# Run the async main function
|
||||
asyncio.run(main())
|
||||
@@ -0,0 +1,10 @@
|
||||
from praisonaiagents import Agent
|
||||
|
||||
agent = Agent(
|
||||
instructions="You are a helpful assistant",
|
||||
llm="gemini/gemini-1.5-flash-8b",
|
||||
self_reflect=True,
|
||||
verbose=True
|
||||
)
|
||||
|
||||
agent.start("Why sky is Blue?")
|
||||
+24
-3
@@ -12,6 +12,14 @@ from praisonaiagents.main import (
|
||||
)
|
||||
from duckduckgo_search import DDGS
|
||||
from pydantic import BaseModel
|
||||
import logging
|
||||
|
||||
# Configure logging with more detail
|
||||
logging.basicConfig(
|
||||
level=logging.DEBUG,
|
||||
format='%(asctime)s - %(levelname)s - %(name)s:%(lineno)d - %(message)s'
|
||||
)
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
console = Console()
|
||||
|
||||
@@ -48,7 +56,7 @@ def sync_search_tool(query: str) -> List[Dict]:
|
||||
error_logs.append(error_msg)
|
||||
return []
|
||||
|
||||
async def async_search_tool(query: str) -> List[Dict]:
|
||||
async def async_search_tool(query: str) -> Dict:
|
||||
"""
|
||||
Asynchronous search using DuckDuckGo.
|
||||
Args:
|
||||
@@ -56,23 +64,36 @@ async def async_search_tool(query: str) -> List[Dict]:
|
||||
Returns:
|
||||
list: Search results
|
||||
"""
|
||||
logger.debug(f"Starting async_search_tool with query: {query}")
|
||||
display_tool_call(f"Running async search for: {query}", console)
|
||||
await asyncio.sleep(1) # Simulate network delay
|
||||
try:
|
||||
results = []
|
||||
ddgs = DDGS()
|
||||
logger.debug("Performing DuckDuckGo search")
|
||||
for result in ddgs.text(keywords=query, max_results=5):
|
||||
results.append({
|
||||
"title": result.get("title", ""),
|
||||
"url": result.get("href", ""),
|
||||
"snippet": result.get("body", "")
|
||||
})
|
||||
return results
|
||||
|
||||
logger.debug(f"Search completed, found {len(results)} results")
|
||||
return {
|
||||
"query": query,
|
||||
"results": results,
|
||||
"total_results": len(results)
|
||||
}
|
||||
except Exception as e:
|
||||
error_msg = f"Error during async search: {e}"
|
||||
logger.error(f"Error in async_search_tool: {e}", exc_info=True)
|
||||
display_error(error_msg, console)
|
||||
error_logs.append(error_msg)
|
||||
return []
|
||||
return {
|
||||
"query": query,
|
||||
"results": [],
|
||||
"total_results": 0
|
||||
}
|
||||
|
||||
# 3. Define both sync and async callbacks
|
||||
def sync_callback(output: TaskOutput):
|
||||
|
||||
@@ -4,6 +4,13 @@ from typing import List, Dict
|
||||
from praisonaiagents import Agent, Task, PraisonAIAgents, TaskOutput
|
||||
from duckduckgo_search import DDGS
|
||||
from pydantic import BaseModel
|
||||
import logging
|
||||
|
||||
# Configure logging
|
||||
logging.basicConfig(
|
||||
level=logging.DEBUG,
|
||||
format='%(asctime)s - %(levelname)s - %(message)s'
|
||||
)
|
||||
|
||||
# 1. Define output model for structured results
|
||||
class SearchResult(BaseModel):
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
from praisonaiagents import Agent
|
||||
|
||||
agent = Agent(
|
||||
instructions="You are a helpful assistant",
|
||||
llm="gpt-4o-mini"
|
||||
)
|
||||
|
||||
agent.start("Why sky is Blue?")
|
||||
@@ -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,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)
|
||||
+182
-33
@@ -1,53 +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[str]
|
||||
soft_skills: 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
|
||||
)
|
||||
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
|
||||
)
|
||||
|
||||
# Single comprehensive analysis task
|
||||
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
|
||||
)
|
||||
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
|
||||
)
|
||||
|
||||
# Create and run the agent
|
||||
agents = PraisonAIAgents(
|
||||
agents=[cv_analyzer],
|
||||
tasks=[cv_analysis_task]
|
||||
)
|
||||
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()
|
||||
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
|
||||
|
||||
# Start the analysis by passing CV content
|
||||
result = agents.start(cv_content)
|
||||
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()
|
||||
|
||||
print(result)
|
||||
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,9 @@
|
||||
# pip install praisonaiagents
|
||||
# export OPENAI_BASE_URL=http://localhost:11434/v1
|
||||
# ollama pull deepseek-r1
|
||||
|
||||
from praisonaiagents import Agent
|
||||
|
||||
agent = Agent(instructions="You are helpful Assisant", llm="deepseek-r1")
|
||||
|
||||
agent.start("Why sky is Blue?")
|
||||
@@ -0,0 +1,62 @@
|
||||
import streamlit as st
|
||||
from praisonaiagents import Agent
|
||||
|
||||
def init_agent():
|
||||
config = {
|
||||
"vector_store": {
|
||||
"provider": "chroma",
|
||||
"config": {
|
||||
"collection_name": "praison",
|
||||
"path": ".praison"
|
||||
}
|
||||
},
|
||||
"llm": {
|
||||
"provider": "ollama",
|
||||
"config": {
|
||||
"model": "deepseek-r1:latest",
|
||||
"temperature": 0,
|
||||
"max_tokens": 8000,
|
||||
"ollama_base_url": "http://localhost:11434",
|
||||
},
|
||||
},
|
||||
"embedder": {
|
||||
"provider": "ollama",
|
||||
"config": {
|
||||
"model": "nomic-embed-text:latest",
|
||||
"ollama_base_url": "http://localhost:11434",
|
||||
"embedding_dims": 1536
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
return Agent(
|
||||
name="Knowledge Agent",
|
||||
instructions="You answer questions based on the provided knowledge.",
|
||||
knowledge=["kag-research-paper.pdf"],
|
||||
knowledge_config=config,
|
||||
user_id="user1",
|
||||
llm="deepseek-r1"
|
||||
)
|
||||
|
||||
st.title("Knowledge Agent Chat")
|
||||
|
||||
if "agent" not in st.session_state:
|
||||
st.session_state.agent = init_agent()
|
||||
st.session_state.messages = []
|
||||
|
||||
if "messages" in st.session_state:
|
||||
for message in st.session_state.messages:
|
||||
with st.chat_message(message["role"]):
|
||||
st.markdown(message["content"])
|
||||
|
||||
prompt = st.chat_input("Ask a question...")
|
||||
|
||||
if prompt:
|
||||
st.session_state.messages.append({"role": "user", "content": prompt})
|
||||
with st.chat_message("user"):
|
||||
st.markdown(prompt)
|
||||
|
||||
with st.chat_message("assistant"):
|
||||
response = st.session_state.agent.start(prompt)
|
||||
st.markdown(response)
|
||||
st.session_state.messages.append({"role": "assistant", "content": response})
|
||||
@@ -0,0 +1,54 @@
|
||||
from praisonaiagents import Agent, Task, PraisonAIAgents
|
||||
|
||||
config = {
|
||||
"vector_store": {
|
||||
"provider": "chroma",
|
||||
"config": {
|
||||
"collection_name": "praison",
|
||||
"path": ".praison"
|
||||
}
|
||||
},
|
||||
"llm": {
|
||||
"provider": "ollama",
|
||||
"config": {
|
||||
"model": "deepseek-r1:latest",
|
||||
"temperature": 0,
|
||||
"max_tokens": 8000,
|
||||
"ollama_base_url": "http://localhost:11434",
|
||||
},
|
||||
},
|
||||
"embedder": {
|
||||
"provider": "ollama",
|
||||
"config": {
|
||||
"model": "nomic-embed-text:latest",
|
||||
"ollama_base_url": "http://localhost:11434",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
# Create an agent
|
||||
rag_agent = Agent(
|
||||
name="RAG Agent",
|
||||
role="Information Specialist",
|
||||
goal="Retrieve knowledge efficiently",
|
||||
llm="deepseek-r1"
|
||||
)
|
||||
|
||||
# Define a task for the agent
|
||||
rag_task = Task(
|
||||
name="RAG Task",
|
||||
description="What is KAG?",
|
||||
expected_output="Answer to the question",
|
||||
agent=rag_agent,
|
||||
context=[config] # Vector Database provided as context
|
||||
)
|
||||
|
||||
# Build Agents
|
||||
agents = PraisonAIAgents(
|
||||
agents=[rag_agent],
|
||||
tasks=[rag_task],
|
||||
user_id="user1"
|
||||
)
|
||||
|
||||
# Start Agents
|
||||
agents.start()
|
||||
@@ -0,0 +1,62 @@
|
||||
import streamlit as st
|
||||
from praisonaiagents import Agent
|
||||
|
||||
def init_agent():
|
||||
config = {
|
||||
"vector_store": {
|
||||
"provider": "chroma",
|
||||
"config": {
|
||||
"collection_name": "praison",
|
||||
"path": ".praison"
|
||||
}
|
||||
},
|
||||
"llm": {
|
||||
"provider": "ollama",
|
||||
"config": {
|
||||
"model": "deepseek-r1:latest",
|
||||
"temperature": 0,
|
||||
"max_tokens": 8000,
|
||||
"ollama_base_url": "http://localhost:11434",
|
||||
},
|
||||
},
|
||||
"embedder": {
|
||||
"provider": "ollama",
|
||||
"config": {
|
||||
"model": "nomic-embed-text:latest",
|
||||
"ollama_base_url": "http://localhost:11434",
|
||||
"embedding_dims": 1536
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
return Agent(
|
||||
name="Knowledge Agent",
|
||||
instructions="You answer questions based on the provided knowledge.",
|
||||
knowledge=["kag-research-paper.pdf"],
|
||||
knowledge_config=config,
|
||||
user_id="user1",
|
||||
llm="deepseek-r1"
|
||||
)
|
||||
|
||||
st.title("Knowledge Agent Chat")
|
||||
|
||||
if "agent" not in st.session_state:
|
||||
st.session_state.agent = init_agent()
|
||||
st.session_state.messages = []
|
||||
|
||||
if "messages" in st.session_state:
|
||||
for message in st.session_state.messages:
|
||||
with st.chat_message(message["role"]):
|
||||
st.markdown(message["content"])
|
||||
|
||||
prompt = st.chat_input("Ask a question...")
|
||||
|
||||
if prompt:
|
||||
st.session_state.messages.append({"role": "user", "content": prompt})
|
||||
with st.chat_message("user"):
|
||||
st.markdown(prompt)
|
||||
|
||||
with st.chat_message("assistant"):
|
||||
response = st.session_state.agent.start(prompt)
|
||||
st.markdown(response)
|
||||
st.session_state.messages.append({"role": "assistant", "content": response})
|
||||
@@ -0,0 +1,39 @@
|
||||
from praisonaiagents import Agent
|
||||
|
||||
config = {
|
||||
"vector_store": {
|
||||
"provider": "chroma",
|
||||
"config": {
|
||||
"collection_name": "praison",
|
||||
"path": ".praison"
|
||||
}
|
||||
},
|
||||
"llm": {
|
||||
"provider": "ollama",
|
||||
"config": {
|
||||
"model": "deepseek-r1:latest",
|
||||
"temperature": 0,
|
||||
"max_tokens": 8000,
|
||||
"ollama_base_url": "http://localhost:11434",
|
||||
},
|
||||
},
|
||||
"embedder": {
|
||||
"provider": "ollama",
|
||||
"config": {
|
||||
"model": "nomic-embed-text:latest",
|
||||
"ollama_base_url": "http://localhost:11434",
|
||||
"embedding_dims": 1536
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
agent = Agent(
|
||||
name="Knowledge Agent",
|
||||
instructions="You answer questions based on the provided knowledge.",
|
||||
knowledge=["kag-research-paper.pdf"], # Indexing
|
||||
knowledge_config=config,
|
||||
user_id="user1",
|
||||
llm="deepseek-r1"
|
||||
)
|
||||
|
||||
agent.start("What is KAG in one line?") # Retrieval
|
||||
@@ -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!")
|
||||
File renamed without changes.
@@ -1,6 +1,7 @@
|
||||
from praisonaiagents import Agent, Task, PraisonAIAgents
|
||||
import logging
|
||||
import os
|
||||
import json
|
||||
|
||||
# Configure logging
|
||||
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
|
||||
@@ -8,11 +9,29 @@ logger = logging.getLogger(__name__)
|
||||
|
||||
# Define the configuration for the Knowledge instance
|
||||
config = {
|
||||
"version": "v1.1",
|
||||
"vector_store": {
|
||||
"provider": "chroma",
|
||||
"config": {
|
||||
"collection_name": "knowledge_test",
|
||||
"path": ".praison",
|
||||
"collection_name": "praison",
|
||||
"path": os.path.abspath("./.praison"),
|
||||
"host": None,
|
||||
"port": None
|
||||
}
|
||||
},
|
||||
"embedder": {
|
||||
"provider": "openai",
|
||||
"config": {
|
||||
"model": "text-embedding-3-small",
|
||||
"embedding_dims": 1536
|
||||
}
|
||||
},
|
||||
"llm": {
|
||||
"provider": "openai",
|
||||
"config": {
|
||||
"model": "gpt-4o-mini",
|
||||
"temperature": 0,
|
||||
"max_tokens": 1000
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -23,17 +42,20 @@ knowledge_agent = Agent(
|
||||
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?",
|
||||
description="KAG",
|
||||
expected_output="Answer to the question",
|
||||
agent=knowledge_agent
|
||||
agent=knowledge_agent,
|
||||
context=[
|
||||
{
|
||||
"embedding_db_config": json.dumps(config["vector_store"])
|
||||
}
|
||||
]
|
||||
)
|
||||
|
||||
# Create and start the agents
|
||||
|
||||
@@ -4,7 +4,7 @@ config = {
|
||||
"vector_store": {
|
||||
"provider": "chroma",
|
||||
"config": {
|
||||
"collection_name": "custom_knowledge",
|
||||
"collection_name": "praison",
|
||||
"path": ".praison",
|
||||
}
|
||||
}
|
||||
@@ -14,7 +14,8 @@ agent = Agent(
|
||||
name="Knowledge Agent",
|
||||
instructions="You answer questions based on the provided knowledge.",
|
||||
knowledge=["large.pdf"],
|
||||
knowledge_config=config
|
||||
knowledge_config=config,
|
||||
user_id="user1"
|
||||
)
|
||||
|
||||
agent.start("What is KAG in one line?")
|
||||
@@ -0,0 +1,44 @@
|
||||
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 = {
|
||||
"version": "v1.1",
|
||||
"vector_store": {
|
||||
"provider": "chroma",
|
||||
"config": {
|
||||
"collection_name": "praison",
|
||||
"path": os.path.abspath("./.praison"),
|
||||
"host": None,
|
||||
"port": None
|
||||
}
|
||||
},
|
||||
"embedder": {
|
||||
"provider": "openai",
|
||||
"config": {
|
||||
"model": "text-embedding-3-small",
|
||||
"embedding_dims": 1536
|
||||
}
|
||||
},
|
||||
"llm": {
|
||||
"provider": "openai",
|
||||
"config": {
|
||||
"model": "gpt-4o-mini",
|
||||
"temperature": 0,
|
||||
"max_tokens": 1000
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
knowledge = Knowledge(config)
|
||||
|
||||
# Search for memories based on a query
|
||||
query = "KAG"
|
||||
logger.info(f"Searching for memories with query: {query}")
|
||||
search_results = knowledge.search(query, user_id="user1")
|
||||
logger.info(f"Search results: {search_results}")
|
||||
print(f"\nSearch results for '{query}':")
|
||||
print(search_results)
|
||||
@@ -0,0 +1,220 @@
|
||||
from mem0 import Memory
|
||||
import logging
|
||||
import json
|
||||
import os
|
||||
import time
|
||||
from datetime import datetime
|
||||
from typing import Dict, Any, Optional
|
||||
|
||||
# Configure logging
|
||||
logging.basicConfig(
|
||||
level=logging.INFO,
|
||||
format='%(asctime)s - %(levelname)s - %(message)s'
|
||||
)
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
class MemoryManager:
|
||||
def __init__(self):
|
||||
"""Initialize Mem0 Memory manager with configuration"""
|
||||
# Define the complete configuration with only supported fields
|
||||
config = {
|
||||
"version": "v1.1",
|
||||
"custom_prompt": None,
|
||||
"vector_store": {
|
||||
"provider": "chroma",
|
||||
"config": {
|
||||
"collection_name": "praison",
|
||||
"path": os.path.abspath("./.praison/storage"),
|
||||
"host": None,
|
||||
"port": None
|
||||
}
|
||||
},
|
||||
"embedder": {
|
||||
"provider": "openai",
|
||||
"config": {
|
||||
"model": "text-embedding-3-small",
|
||||
"embedding_dims": 1536
|
||||
}
|
||||
},
|
||||
"llm": {
|
||||
"provider": "openai",
|
||||
"config": {
|
||||
"model": "gpt-4o-mini",
|
||||
"temperature": 0,
|
||||
"max_tokens": 1000
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# Ensure storage directory exists
|
||||
storage_path = os.path.abspath("./.praison/storage")
|
||||
if os.path.exists(storage_path):
|
||||
logger.info(f"Clearing existing storage at {storage_path}")
|
||||
import shutil
|
||||
shutil.rmtree(storage_path)
|
||||
os.makedirs(storage_path, exist_ok=True)
|
||||
logger.info(f"Created storage path: {storage_path}")
|
||||
|
||||
# Initialize memory
|
||||
self.memory = Memory.from_config(config)
|
||||
logger.info("Memory manager initialized")
|
||||
|
||||
def pretty_print(self, data: Any) -> None:
|
||||
"""Helper function to print memory data in a readable format"""
|
||||
if isinstance(data, (dict, list)):
|
||||
print(json.dumps(data, indent=2))
|
||||
else:
|
||||
print(data)
|
||||
|
||||
def extract_memory_id(self, result: Any) -> Optional[str]:
|
||||
"""Extract memory ID from the result, handling different formats"""
|
||||
try:
|
||||
if isinstance(result, dict):
|
||||
# v1.1 format
|
||||
memories = result.get('results', [])
|
||||
return memories[0]['id'] if memories else None
|
||||
elif isinstance(result, list):
|
||||
# v1.0 format
|
||||
return result[0]['id'] if result else None
|
||||
return None
|
||||
except (KeyError, IndexError) as e:
|
||||
logger.warning(f"Could not extract memory ID from result: {e}")
|
||||
return None
|
||||
|
||||
def prepare_metadata(self, metadata: Optional[Dict]) -> Dict:
|
||||
"""Prepare metadata by converting values to acceptable types"""
|
||||
if not metadata:
|
||||
return {}
|
||||
|
||||
clean_metadata = {}
|
||||
for key, value in metadata.items():
|
||||
if isinstance(value, (str, int, float, bool)):
|
||||
clean_metadata[key] = value
|
||||
elif isinstance(value, list):
|
||||
clean_metadata[key] = ','.join(map(str, value))
|
||||
elif isinstance(value, dict):
|
||||
clean_metadata[key] = json.dumps(value)
|
||||
else:
|
||||
clean_metadata[key] = str(value)
|
||||
return clean_metadata
|
||||
|
||||
def verify_memory_addition(self, user_id: str, max_retries: int = 3) -> bool:
|
||||
"""Verify that memory was added successfully"""
|
||||
for attempt in range(max_retries):
|
||||
try:
|
||||
time.sleep(0.5) # Brief pause to allow indexing
|
||||
memories = self.memory.get_all(user_id=user_id)
|
||||
if len(memories.get('results', [])) > 0:
|
||||
return True
|
||||
logger.warning(f"Memory not found on attempt {attempt + 1}")
|
||||
except Exception as e:
|
||||
logger.warning(f"Verification attempt {attempt + 1} failed: {e}")
|
||||
if attempt < max_retries - 1:
|
||||
time.sleep(1)
|
||||
return False
|
||||
|
||||
def add_memory(self, text: str, user_id: Optional[str] = None, metadata: Optional[Dict] = None) -> Dict:
|
||||
"""Add a new memory with error handling and verification"""
|
||||
try:
|
||||
logger.info(f"Adding memory for user {user_id}")
|
||||
clean_metadata = self.prepare_metadata(metadata)
|
||||
logger.debug(f"Prepared metadata: {clean_metadata}")
|
||||
|
||||
messages = [{"role": "user", "content": text}]
|
||||
result = self.memory.add(
|
||||
messages=messages,
|
||||
user_id=user_id,
|
||||
metadata=clean_metadata
|
||||
)
|
||||
|
||||
if self.verify_memory_addition(user_id):
|
||||
logger.info("Memory added and verified successfully")
|
||||
else:
|
||||
logger.warning("Memory addition could not be verified")
|
||||
|
||||
return result
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to add memory: {str(e)}")
|
||||
raise
|
||||
|
||||
def get_all_memories(self, user_id: Optional[str] = None) -> Dict:
|
||||
"""Retrieve all memories for a user"""
|
||||
try:
|
||||
logger.info(f"Retrieving all memories for user {user_id}")
|
||||
memories = self.memory.get_all(user_id=user_id)
|
||||
count = len(memories.get('results', []))
|
||||
logger.info(f"Retrieved {count} memories")
|
||||
return memories
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to retrieve memories: {str(e)}")
|
||||
raise
|
||||
|
||||
def search_memories(self, query: str, user_id: Optional[str] = None, limit: int = 5) -> Dict:
|
||||
"""Search memories with a query"""
|
||||
try:
|
||||
logger.info(f"Searching memories with query: {query}")
|
||||
results = self.memory.search(
|
||||
query=query,
|
||||
user_id=user_id,
|
||||
limit=limit
|
||||
)
|
||||
count = len(results.get('results', []))
|
||||
logger.info(f"Found {count} matching memories")
|
||||
return results
|
||||
except Exception as e:
|
||||
logger.error(f"Search failed: {str(e)}")
|
||||
raise
|
||||
|
||||
def main():
|
||||
try:
|
||||
# Initialize memory manager
|
||||
manager = MemoryManager()
|
||||
|
||||
# Add a test memory
|
||||
print("\n1. Adding a new memory:")
|
||||
metadata = {
|
||||
"category": "hobbies",
|
||||
"timestamp": datetime.now().isoformat(),
|
||||
"tags": "tennis,learning",
|
||||
"priority": 1,
|
||||
"source": "user_input"
|
||||
}
|
||||
|
||||
result = manager.add_memory(
|
||||
text="I am working on improving my tennis skills. Suggest some online courses.",
|
||||
user_id="alice",
|
||||
metadata=metadata
|
||||
)
|
||||
manager.pretty_print(result)
|
||||
|
||||
# Wait briefly for indexing
|
||||
time.sleep(1)
|
||||
|
||||
print("\n2. Retrieving all memories:")
|
||||
all_memories = manager.get_all_memories(user_id="alice")
|
||||
manager.pretty_print(all_memories)
|
||||
|
||||
print("\n3. Searching memories:")
|
||||
search_results = manager.search_memories(
|
||||
query="What are Alice's hobbies?",
|
||||
user_id="alice",
|
||||
limit=5
|
||||
)
|
||||
manager.pretty_print(search_results)
|
||||
|
||||
# Print summary
|
||||
print("\nMemory Store Summary:")
|
||||
total_memories = len(all_memories.get('results', []))
|
||||
print(f"Total memories stored: {total_memories}")
|
||||
if total_memories > 0:
|
||||
print("Available memories:")
|
||||
for mem in all_memories['results']:
|
||||
print(f"- {mem.get('memory', 'No content')}")
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Main process failed: {str(e)}", exc_info=True)
|
||||
raise
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,143 @@
|
||||
from mem0 import Memory
|
||||
import logging
|
||||
import json
|
||||
import os
|
||||
from typing import Dict, Any, Optional
|
||||
|
||||
# Configure logging
|
||||
logging.basicConfig(
|
||||
level=logging.INFO,
|
||||
format='%(asctime)s - %(levelname)s - %(message)s'
|
||||
)
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
class MemorySearcher:
|
||||
def __init__(self):
|
||||
"""Initialize Mem0 Memory searcher with configuration"""
|
||||
# Define the configuration
|
||||
config = {
|
||||
"version": "v1.1",
|
||||
"vector_store": {
|
||||
"provider": "chroma",
|
||||
"config": {
|
||||
"collection_name": "praison",
|
||||
"path": os.path.abspath("./.praison/storage"),
|
||||
"host": None,
|
||||
"port": None
|
||||
}
|
||||
},
|
||||
"embedder": {
|
||||
"provider": "openai",
|
||||
"config": {
|
||||
"model": "text-embedding-3-small",
|
||||
"embedding_dims": 1536
|
||||
}
|
||||
},
|
||||
"llm": {
|
||||
"provider": "openai",
|
||||
"config": {
|
||||
"model": "gpt-4o-mini",
|
||||
"temperature": 0,
|
||||
"max_tokens": 1000
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# Initialize memory
|
||||
self.memory = Memory.from_config(config)
|
||||
logger.info("Memory searcher initialized")
|
||||
|
||||
def pretty_print(self, data: Any) -> None:
|
||||
"""Helper function to print data in a readable format"""
|
||||
if isinstance(data, (dict, list)):
|
||||
print(json.dumps(data, indent=2))
|
||||
else:
|
||||
print(data)
|
||||
|
||||
def get_all_memories(self, user_id: Optional[str] = None) -> Dict:
|
||||
"""Retrieve all memories for a user"""
|
||||
try:
|
||||
logger.info(f"Retrieving all memories for user {user_id}")
|
||||
memories = self.memory.get_all(user_id=user_id)
|
||||
count = len(memories.get('results', []))
|
||||
logger.info(f"Retrieved {count} memories")
|
||||
return memories
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to retrieve memories: {str(e)}")
|
||||
raise
|
||||
|
||||
def search_memories(self, query: str, user_id: Optional[str] = None, limit: int = 5) -> Dict:
|
||||
"""Search memories with a query"""
|
||||
try:
|
||||
logger.info(f"Searching memories with query: {query}")
|
||||
results = self.memory.search(
|
||||
query=query,
|
||||
user_id=user_id,
|
||||
limit=limit
|
||||
)
|
||||
count = len(results.get('results', []))
|
||||
logger.info(f"Found {count} matching memories")
|
||||
return results
|
||||
except Exception as e:
|
||||
logger.error(f"Search failed: {str(e)}")
|
||||
raise
|
||||
|
||||
def list_unique_users(self) -> list:
|
||||
"""List all unique users in the memory store"""
|
||||
try:
|
||||
all_memories = self.memory.get_all()
|
||||
users = set()
|
||||
for memory in all_memories.get('results', []):
|
||||
if 'user_id' in memory:
|
||||
users.add(memory['user_id'])
|
||||
return sorted(list(users))
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to list users: {str(e)}")
|
||||
raise
|
||||
|
||||
def main():
|
||||
try:
|
||||
# Initialize memory searcher
|
||||
searcher = MemorySearcher()
|
||||
|
||||
# Get list of users
|
||||
print("\n1. Available users in the memory store:")
|
||||
users = searcher.list_unique_users()
|
||||
searcher.pretty_print(users)
|
||||
|
||||
if not users:
|
||||
print("No users found in the memory store. Please add some memories first.")
|
||||
return
|
||||
|
||||
# Example user (using first user found)
|
||||
example_user = users[0]
|
||||
|
||||
print(f"\n2. All memories for user '{example_user}':")
|
||||
all_memories = searcher.get_all_memories(user_id=example_user)
|
||||
searcher.pretty_print(all_memories)
|
||||
|
||||
print(f"\n3. Searching memories for user '{example_user}':")
|
||||
search_results = searcher.search_memories(
|
||||
query="What are their hobbies?",
|
||||
user_id=example_user,
|
||||
limit=5
|
||||
)
|
||||
searcher.pretty_print(search_results)
|
||||
|
||||
# Print summary
|
||||
print("\nMemory Store Summary:")
|
||||
total_memories = len(all_memories.get('results', []))
|
||||
print(f"Total memories for {example_user}: {total_memories}")
|
||||
if total_memories > 0:
|
||||
print("Available memories:")
|
||||
for mem in all_memories['results']:
|
||||
print(f"- {mem.get('memory', 'No content')}")
|
||||
if 'metadata' in mem:
|
||||
print(f" Metadata: {mem['metadata']}")
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Main process failed: {str(e)}", exc_info=True)
|
||||
raise
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,26 @@
|
||||
from mem0 import Memory
|
||||
import os
|
||||
import json
|
||||
|
||||
# Basic configuration
|
||||
config = {
|
||||
"vector_store": {
|
||||
"provider": "chroma",
|
||||
"config": {
|
||||
"collection_name": "praison",
|
||||
"path": ".praison",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# Initialize memory
|
||||
memory = Memory.from_config(config)
|
||||
|
||||
# Search Alice's hobbies
|
||||
search_results = memory.search(
|
||||
query="KAG",
|
||||
user_id="user1",
|
||||
limit=5
|
||||
)
|
||||
|
||||
print(search_results)
|
||||
@@ -0,0 +1,46 @@
|
||||
from mem0 import Memory
|
||||
import os
|
||||
import json
|
||||
|
||||
# Basic configuration
|
||||
config = {
|
||||
"version": "v1.1",
|
||||
"vector_store": {
|
||||
"provider": "chroma",
|
||||
"config": {
|
||||
"collection_name": "praison",
|
||||
"path": os.path.abspath("./.praison/storage")
|
||||
}
|
||||
},
|
||||
"embedder": {
|
||||
"provider": "openai",
|
||||
"config": {
|
||||
"model": "text-embedding-3-small"
|
||||
}
|
||||
},
|
||||
"llm": {
|
||||
"provider": "openai",
|
||||
"config": {
|
||||
"model": "gpt-4o-mini"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# Initialize memory
|
||||
memory = Memory.from_config(config)
|
||||
|
||||
# Search Alice's hobbies
|
||||
search_results = memory.search(
|
||||
query="What are Alice's hobbies?",
|
||||
user_id="alice",
|
||||
limit=5
|
||||
)
|
||||
|
||||
# Print results in a readable format
|
||||
print("\nAlice's Memories:")
|
||||
for memory in search_results['results']:
|
||||
print(f"\nMemory: {memory['memory']}")
|
||||
print(f"Score: {memory['score']}")
|
||||
if 'metadata' in memory:
|
||||
print("Metadata:")
|
||||
print(json.dumps(memory['metadata'], indent=2))
|
||||
@@ -9,7 +9,6 @@ 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,
|
||||
@@ -38,7 +37,6 @@ __all__ = [
|
||||
'TaskOutput',
|
||||
'ReflectionOutput',
|
||||
'AutoAgents',
|
||||
'Memory',
|
||||
'display_interaction',
|
||||
'display_self_reflection',
|
||||
'display_instruction',
|
||||
|
||||
@@ -192,10 +192,26 @@ class Agent:
|
||||
reflect_llm: Optional[str] = None,
|
||||
user_id: Optional[str] = None
|
||||
):
|
||||
# Add check at start if memory is requested
|
||||
if memory is not None:
|
||||
try:
|
||||
from ..memory.memory import Memory
|
||||
MEMORY_AVAILABLE = True
|
||||
except ImportError:
|
||||
raise ImportError(
|
||||
"Memory features requested in Agent but memory dependencies not installed. "
|
||||
"Please install with: pip install \"praisonaiagents[memory]\""
|
||||
)
|
||||
|
||||
# Handle backward compatibility for required fields
|
||||
if all(x is None for x in [name, role, goal, backstory, instructions]):
|
||||
raise ValueError("At least one of name, role, goal, backstory, or instructions must be provided")
|
||||
|
||||
# Configure logging to suppress unwanted outputs
|
||||
logging.getLogger("litellm").setLevel(logging.WARNING)
|
||||
logging.getLogger("httpx").setLevel(logging.WARNING)
|
||||
logging.getLogger("httpcore").setLevel(logging.WARNING)
|
||||
|
||||
# If instructions are provided, use them to set role, goal, and backstory
|
||||
if instructions:
|
||||
self.name = name or "Agent"
|
||||
@@ -215,7 +231,34 @@ class Agent:
|
||||
|
||||
self.instructions = instructions
|
||||
# Check for model name in environment variable if not provided
|
||||
self.llm = llm or os.getenv('OPENAI_MODEL_NAME', 'gpt-4o')
|
||||
self._using_custom_llm = False
|
||||
|
||||
# If the user passes a dictionary (for advanced configuration)
|
||||
if isinstance(llm, dict) and "model" in llm:
|
||||
try:
|
||||
from ..llm.llm import LLM
|
||||
self.llm_instance = LLM(**llm) # Pass all dict items as kwargs
|
||||
self._using_custom_llm = True
|
||||
except ImportError as e:
|
||||
raise ImportError(
|
||||
"LLM features requested but dependencies not installed. "
|
||||
"Please install with: pip install \"praisonaiagents[llm]\""
|
||||
) from e
|
||||
# If the user passes a string with a slash (provider/model)
|
||||
elif isinstance(llm, str) and "/" in llm:
|
||||
try:
|
||||
from ..llm.llm import LLM
|
||||
# Pass the entire string so LiteLLM can parse provider/model
|
||||
self.llm_instance = LLM(model=llm)
|
||||
self._using_custom_llm = True
|
||||
except ImportError as e:
|
||||
raise ImportError(
|
||||
"LLM features requested but dependencies not installed. "
|
||||
"Please install with: pip install \"praisonaiagents[llm]\""
|
||||
) from e
|
||||
# Otherwise, fall back to OpenAI environment/name
|
||||
else:
|
||||
self.llm = llm or os.getenv('OPENAI_MODEL_NAME', 'gpt-4o')
|
||||
self.tools = tools if tools else [] # Store original tools
|
||||
self.function_calling_llm = function_calling_llm
|
||||
self.max_iter = max_iter
|
||||
@@ -256,14 +299,18 @@ Your Goal: {self.goal}
|
||||
# Store user_id
|
||||
self.user_id = user_id
|
||||
|
||||
# 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)
|
||||
# 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."""
|
||||
@@ -479,185 +526,216 @@ Your Goal: {self.goal}
|
||||
# Append found knowledge to the prompt
|
||||
prompt = f"{prompt}\n\nKnowledge: {knowledge_content}"
|
||||
|
||||
if self.use_system_prompt:
|
||||
system_prompt = f"""{self.backstory}\n
|
||||
if self._using_custom_llm:
|
||||
try:
|
||||
# Pass everything to LLM class
|
||||
response_text = self.llm_instance.get_response(
|
||||
prompt=prompt,
|
||||
system_prompt=f"{self.backstory}\n\nYour Role: {self.role}\n\nYour Goal: {self.goal}" if self.use_system_prompt else None,
|
||||
chat_history=self.chat_history,
|
||||
temperature=temperature,
|
||||
tools=tools,
|
||||
output_json=output_json,
|
||||
output_pydantic=output_pydantic,
|
||||
verbose=self.verbose,
|
||||
markdown=self.markdown,
|
||||
self_reflect=self.self_reflect,
|
||||
max_reflect=self.max_reflect,
|
||||
min_reflect=self.min_reflect,
|
||||
console=self.console,
|
||||
agent_name=self.name,
|
||||
agent_role=self.role,
|
||||
agent_tools=[t.__name__ if hasattr(t, '__name__') else str(t) for t in self.tools],
|
||||
execute_tool_fn=self.execute_tool # Pass tool execution function
|
||||
)
|
||||
|
||||
self.chat_history.append({"role": "user", "content": prompt})
|
||||
self.chat_history.append({"role": "assistant", "content": response_text})
|
||||
|
||||
return response_text
|
||||
except Exception as e:
|
||||
display_error(f"Error in LLM chat: {e}")
|
||||
return None
|
||||
else:
|
||||
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: {json.dumps(output_json.model_json_schema())}"
|
||||
elif output_pydantic:
|
||||
system_prompt += f"\nReturn ONLY a JSON object that matches this Pydantic model: {json.dumps(output_pydantic.model_json_schema())}"
|
||||
else:
|
||||
system_prompt = None
|
||||
"""
|
||||
if output_json:
|
||||
system_prompt += f"\nReturn ONLY a JSON object that matches this Pydantic model: {json.dumps(output_json.model_json_schema())}"
|
||||
elif output_pydantic:
|
||||
system_prompt += f"\nReturn ONLY a JSON object that matches this Pydantic model: {json.dumps(output_pydantic.model_json_schema())}"
|
||||
else:
|
||||
system_prompt = None
|
||||
|
||||
messages = []
|
||||
if system_prompt:
|
||||
messages.append({"role": "system", "content": system_prompt})
|
||||
messages.extend(self.chat_history)
|
||||
messages = []
|
||||
if system_prompt:
|
||||
messages.append({"role": "system", "content": system_prompt})
|
||||
messages.extend(self.chat_history)
|
||||
|
||||
# Modify prompt if output_json or output_pydantic is specified
|
||||
original_prompt = prompt
|
||||
if output_json or output_pydantic:
|
||||
if isinstance(prompt, str):
|
||||
prompt += "\nReturn ONLY a valid JSON object. No other text or explanation."
|
||||
elif isinstance(prompt, list):
|
||||
# For multimodal prompts, append to the text content
|
||||
for item in prompt:
|
||||
if item["type"] == "text":
|
||||
item["text"] += "\nReturn ONLY a valid JSON object. No other text or explanation."
|
||||
break
|
||||
# Modify prompt if output_json or output_pydantic is specified
|
||||
original_prompt = prompt
|
||||
if output_json or output_pydantic:
|
||||
if isinstance(prompt, str):
|
||||
prompt += "\nReturn ONLY a valid JSON object. No other text or explanation."
|
||||
elif isinstance(prompt, list):
|
||||
# For multimodal prompts, append to the text content
|
||||
for item in prompt:
|
||||
if item["type"] == "text":
|
||||
item["text"] += "\nReturn ONLY a valid JSON object. No other text or explanation."
|
||||
break
|
||||
|
||||
if isinstance(prompt, list):
|
||||
# If we receive a multimodal prompt list, place it directly in the user message
|
||||
messages.append({"role": "user", "content": prompt})
|
||||
else:
|
||||
messages.append({"role": "user", "content": prompt})
|
||||
if isinstance(prompt, list):
|
||||
# If we receive a multimodal prompt list, place it directly in the user message
|
||||
messages.append({"role": "user", "content": prompt})
|
||||
else:
|
||||
messages.append({"role": "user", "content": prompt})
|
||||
|
||||
final_response_text = None
|
||||
reflection_count = 0
|
||||
start_time = time.time()
|
||||
final_response_text = None
|
||||
reflection_count = 0
|
||||
start_time = time.time()
|
||||
|
||||
while True:
|
||||
try:
|
||||
if self.verbose:
|
||||
# Handle both string and list prompts for instruction display
|
||||
display_text = prompt
|
||||
if isinstance(prompt, list):
|
||||
# Extract text content from multimodal prompt
|
||||
display_text = next((item["text"] for item in prompt if item["type"] == "text"), "")
|
||||
|
||||
if display_text and str(display_text).strip():
|
||||
# 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:
|
||||
return None
|
||||
|
||||
tool_calls = getattr(response.choices[0].message, 'tool_calls', None)
|
||||
response_text = response.choices[0].message.content.strip()
|
||||
|
||||
if tool_calls:
|
||||
messages.append({
|
||||
"role": "assistant",
|
||||
"content": response_text,
|
||||
"tool_calls": tool_calls
|
||||
})
|
||||
|
||||
for tool_call in tool_calls:
|
||||
function_name = tool_call.function.name
|
||||
arguments = json.loads(tool_call.function.arguments)
|
||||
|
||||
if self.verbose:
|
||||
display_tool_call(f"Agent {self.name} is calling function '{function_name}' with arguments: {arguments}", console=self.console)
|
||||
|
||||
tool_result = self.execute_tool(function_name, arguments)
|
||||
|
||||
if tool_result:
|
||||
if self.verbose:
|
||||
display_tool_call(f"Function '{function_name}' returned: {tool_result}", console=self.console)
|
||||
messages.append({
|
||||
"role": "tool",
|
||||
"tool_call_id": tool_call.id,
|
||||
"content": json.dumps(tool_result)
|
||||
})
|
||||
else:
|
||||
messages.append({
|
||||
"role": "tool",
|
||||
"tool_call_id": tool_call.id,
|
||||
"content": "Function returned an empty output"
|
||||
})
|
||||
while True:
|
||||
try:
|
||||
if self.verbose:
|
||||
# Handle both string and list prompts for instruction display
|
||||
display_text = prompt
|
||||
if isinstance(prompt, list):
|
||||
# Extract text content from multimodal prompt
|
||||
display_text = next((item["text"] for item in prompt if item["type"] == "text"), "")
|
||||
|
||||
response = self._chat_completion(messages, temperature=temperature)
|
||||
if display_text and str(display_text).strip():
|
||||
# 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:
|
||||
return None
|
||||
|
||||
tool_calls = getattr(response.choices[0].message, 'tool_calls', None)
|
||||
response_text = response.choices[0].message.content.strip()
|
||||
|
||||
# Handle output_json or output_pydantic if specified
|
||||
if output_json or output_pydantic:
|
||||
# Add to chat history and return raw response
|
||||
self.chat_history.append({"role": "user", "content": original_prompt})
|
||||
self.chat_history.append({"role": "assistant", "content": response_text})
|
||||
if self.verbose:
|
||||
display_interaction(original_prompt, response_text, markdown=self.markdown,
|
||||
generation_time=time.time() - start_time, console=self.console)
|
||||
return response_text
|
||||
if tool_calls:
|
||||
messages.append({
|
||||
"role": "assistant",
|
||||
"content": response_text,
|
||||
"tool_calls": tool_calls
|
||||
})
|
||||
|
||||
for tool_call in tool_calls:
|
||||
function_name = tool_call.function.name
|
||||
arguments = json.loads(tool_call.function.arguments)
|
||||
|
||||
if not self.self_reflect:
|
||||
self.chat_history.append({"role": "user", "content": original_prompt})
|
||||
self.chat_history.append({"role": "assistant", "content": response_text})
|
||||
if self.verbose:
|
||||
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
|
||||
if self.verbose:
|
||||
display_tool_call(f"Agent {self.name} is calling function '{function_name}' with arguments: {arguments}", console=self.console)
|
||||
|
||||
reflection_prompt = f"""
|
||||
tool_result = self.execute_tool(function_name, arguments)
|
||||
|
||||
if tool_result:
|
||||
if self.verbose:
|
||||
display_tool_call(f"Function '{function_name}' returned: {tool_result}", console=self.console)
|
||||
messages.append({
|
||||
"role": "tool",
|
||||
"tool_call_id": tool_call.id,
|
||||
"content": json.dumps(tool_result)
|
||||
})
|
||||
else:
|
||||
messages.append({
|
||||
"role": "tool",
|
||||
"tool_call_id": tool_call.id,
|
||||
"content": "Function returned an empty output"
|
||||
})
|
||||
|
||||
response = self._chat_completion(messages, temperature=temperature)
|
||||
if not response:
|
||||
return None
|
||||
response_text = response.choices[0].message.content.strip()
|
||||
|
||||
# Handle output_json or output_pydantic if specified
|
||||
if output_json or output_pydantic:
|
||||
# Add to chat history and return raw response
|
||||
self.chat_history.append({"role": "user", "content": original_prompt})
|
||||
self.chat_history.append({"role": "assistant", "content": response_text})
|
||||
if self.verbose:
|
||||
display_interaction(original_prompt, response_text, markdown=self.markdown,
|
||||
generation_time=time.time() - start_time, console=self.console)
|
||||
return response_text
|
||||
|
||||
if not self.self_reflect:
|
||||
self.chat_history.append({"role": "user", "content": original_prompt})
|
||||
self.chat_history.append({"role": "assistant", "content": response_text})
|
||||
if self.verbose:
|
||||
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
|
||||
|
||||
reflection_prompt = f"""
|
||||
Reflect on your previous response: '{response_text}'.
|
||||
Identify any flaws, improvements, or actions.
|
||||
Provide a "satisfactory" status ('yes' or 'no').
|
||||
Output MUST be JSON with 'reflection' and 'satisfactory'.
|
||||
"""
|
||||
logging.debug(f"{self.name} reflection attempt {reflection_count+1}, sending prompt: {reflection_prompt}")
|
||||
messages.append({"role": "user", "content": reflection_prompt})
|
||||
"""
|
||||
logging.debug(f"{self.name} reflection attempt {reflection_count+1}, sending prompt: {reflection_prompt}")
|
||||
messages.append({"role": "user", "content": reflection_prompt})
|
||||
|
||||
try:
|
||||
reflection_response = client.beta.chat.completions.parse(
|
||||
model=self.reflect_llm if self.reflect_llm else self.llm,
|
||||
messages=messages,
|
||||
temperature=temperature,
|
||||
response_format=ReflectionOutput
|
||||
)
|
||||
try:
|
||||
reflection_response = client.beta.chat.completions.parse(
|
||||
model=self.reflect_llm if self.reflect_llm else self.llm,
|
||||
messages=messages,
|
||||
temperature=temperature,
|
||||
response_format=ReflectionOutput
|
||||
)
|
||||
|
||||
reflection_output = reflection_response.choices[0].message.parsed
|
||||
reflection_output = reflection_response.choices[0].message.parsed
|
||||
|
||||
if self.verbose:
|
||||
display_self_reflection(f"Agent {self.name} self reflection (using {self.reflect_llm if self.reflect_llm else self.llm}): reflection='{reflection_output.reflection}' satisfactory='{reflection_output.satisfactory}'", console=self.console)
|
||||
|
||||
messages.append({"role": "assistant", "content": f"Self Reflection: {reflection_output.reflection} Satisfactory?: {reflection_output.satisfactory}"})
|
||||
|
||||
# Only consider satisfactory after minimum reflections
|
||||
if reflection_output.satisfactory == "yes" and reflection_count >= self.min_reflect - 1:
|
||||
if self.verbose:
|
||||
display_self_reflection("Agent marked the response as satisfactory after meeting minimum reflections", console=self.console)
|
||||
self.chat_history.append({"role": "user", "content": prompt})
|
||||
self.chat_history.append({"role": "assistant", "content": response_text})
|
||||
display_interaction(prompt, response_text, markdown=self.markdown, generation_time=time.time() - start_time, console=self.console)
|
||||
return response_text
|
||||
display_self_reflection(f"Agent {self.name} self reflection (using {self.reflect_llm if self.reflect_llm else self.llm}): reflection='{reflection_output.reflection}' satisfactory='{reflection_output.satisfactory}'", console=self.console)
|
||||
|
||||
# Check if we've hit max reflections
|
||||
if reflection_count >= self.max_reflect - 1:
|
||||
if self.verbose:
|
||||
display_self_reflection("Maximum reflection count reached, returning current response", console=self.console)
|
||||
self.chat_history.append({"role": "user", "content": prompt})
|
||||
self.chat_history.append({"role": "assistant", "content": response_text})
|
||||
display_interaction(prompt, response_text, markdown=self.markdown, generation_time=time.time() - start_time, console=self.console)
|
||||
return response_text
|
||||
messages.append({"role": "assistant", "content": f"Self Reflection: {reflection_output.reflection} Satisfactory?: {reflection_output.satisfactory}"})
|
||||
|
||||
logging.debug(f"{self.name} reflection count {reflection_count + 1}, continuing reflection process")
|
||||
messages.append({"role": "user", "content": "Now regenerate your response using the reflection you made"})
|
||||
response = self._chat_completion(messages, temperature=temperature, tools=None, stream=True)
|
||||
response_text = response.choices[0].message.content.strip()
|
||||
reflection_count += 1
|
||||
continue # Continue the loop for more reflections
|
||||
# Only consider satisfactory after minimum reflections
|
||||
if reflection_output.satisfactory == "yes" and reflection_count >= self.min_reflect - 1:
|
||||
if self.verbose:
|
||||
display_self_reflection("Agent marked the response as satisfactory after meeting minimum reflections", console=self.console)
|
||||
self.chat_history.append({"role": "user", "content": prompt})
|
||||
self.chat_history.append({"role": "assistant", "content": response_text})
|
||||
display_interaction(prompt, response_text, markdown=self.markdown, generation_time=time.time() - start_time, console=self.console)
|
||||
return response_text
|
||||
|
||||
# Check if we've hit max reflections
|
||||
if reflection_count >= self.max_reflect - 1:
|
||||
if self.verbose:
|
||||
display_self_reflection("Maximum reflection count reached, returning current response", console=self.console)
|
||||
self.chat_history.append({"role": "user", "content": prompt})
|
||||
self.chat_history.append({"role": "assistant", "content": response_text})
|
||||
display_interaction(prompt, response_text, markdown=self.markdown, generation_time=time.time() - start_time, console=self.console)
|
||||
return response_text
|
||||
|
||||
logging.debug(f"{self.name} reflection count {reflection_count + 1}, continuing reflection process")
|
||||
messages.append({"role": "user", "content": "Now regenerate your response using the reflection you made"})
|
||||
response = self._chat_completion(messages, temperature=temperature, tools=None, stream=True)
|
||||
response_text = response.choices[0].message.content.strip()
|
||||
reflection_count += 1
|
||||
continue # Continue the loop for more reflections
|
||||
|
||||
except Exception as e:
|
||||
display_error(f"Error in parsing self-reflection json {e}. Retrying", console=self.console)
|
||||
logging.error("Reflection parsing failed.", exc_info=True)
|
||||
messages.append({"role": "assistant", "content": f"Self Reflection failed."})
|
||||
reflection_count += 1
|
||||
continue # Continue even after error to try again
|
||||
|
||||
except Exception as e:
|
||||
display_error(f"Error in parsing self-reflection json {e}. Retrying", console=self.console)
|
||||
logging.error("Reflection parsing failed.", exc_info=True)
|
||||
messages.append({"role": "assistant", "content": f"Self Reflection failed."})
|
||||
reflection_count += 1
|
||||
continue # Continue even after error to try again
|
||||
|
||||
except Exception as e:
|
||||
display_error(f"Error in chat: {e}", console=self.console)
|
||||
return None
|
||||
display_error(f"Error in chat: {e}", console=self.console)
|
||||
return None
|
||||
|
||||
def clean_json_output(self, output: str) -> str:
|
||||
"""Clean and extract JSON from response text."""
|
||||
@@ -669,98 +747,153 @@ Output MUST be JSON with 'reflection' and 'satisfactory'.
|
||||
cleaned = cleaned[len("```"):].strip()
|
||||
if cleaned.endswith("```"):
|
||||
cleaned = cleaned[:-3].strip()
|
||||
return cleaned
|
||||
return cleaned
|
||||
|
||||
async def achat(self, prompt, temperature=0.2, tools=None, output_json=None, output_pydantic=None):
|
||||
"""Async version of chat method"""
|
||||
async def achat(self, prompt: str, temperature=0.2, tools=None, output_json=None, output_pydantic=None):
|
||||
"""Async version of chat method. TODO: Requires Syncing with chat method."""
|
||||
try:
|
||||
# Build system prompt
|
||||
system_prompt = self.system_prompt
|
||||
if output_json:
|
||||
system_prompt += f"\nReturn ONLY a JSON object that matches this Pydantic model: {json.dumps(output_json.model_json_schema())}"
|
||||
elif output_pydantic:
|
||||
system_prompt += f"\nReturn ONLY a JSON object that matches this Pydantic model: {json.dumps(output_pydantic.model_json_schema())}"
|
||||
# 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:
|
||||
if isinstance(search_results, dict) and 'results' in search_results:
|
||||
knowledge_content = "\n".join([result['memory'] for result in search_results['results']])
|
||||
else:
|
||||
knowledge_content = "\n".join(search_results)
|
||||
prompt = f"{prompt}\n\nKnowledge: {knowledge_content}"
|
||||
|
||||
# Build messages
|
||||
if isinstance(prompt, str):
|
||||
messages = [
|
||||
{"role": "system", "content": system_prompt},
|
||||
{"role": "user", "content": prompt + ("\nReturn ONLY a valid JSON object. No other text or explanation." if (output_json or output_pydantic) else "")}
|
||||
]
|
||||
if self._using_custom_llm:
|
||||
try:
|
||||
response_text = await self.llm_instance.get_response_async(
|
||||
prompt=prompt,
|
||||
system_prompt=f"{self.backstory}\n\nYour Role: {self.role}\n\nYour Goal: {self.goal}" if self.use_system_prompt else None,
|
||||
chat_history=self.chat_history,
|
||||
temperature=temperature,
|
||||
tools=tools,
|
||||
output_json=output_json,
|
||||
output_pydantic=output_pydantic,
|
||||
verbose=self.verbose,
|
||||
markdown=self.markdown,
|
||||
self_reflect=self.self_reflect,
|
||||
max_reflect=self.max_reflect,
|
||||
min_reflect=self.min_reflect,
|
||||
console=self.console,
|
||||
agent_name=self.name,
|
||||
agent_role=self.role,
|
||||
agent_tools=[t.__name__ if hasattr(t, '__name__') else str(t) for t in self.tools],
|
||||
execute_tool_fn=self.execute_tool_async
|
||||
)
|
||||
|
||||
self.chat_history.append({"role": "user", "content": prompt})
|
||||
self.chat_history.append({"role": "assistant", "content": response_text})
|
||||
|
||||
return response_text
|
||||
except Exception as e:
|
||||
display_error(f"Error in LLM chat: {e}")
|
||||
return None
|
||||
|
||||
# For OpenAI client
|
||||
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: {json.dumps(output_json.model_json_schema())}"
|
||||
elif output_pydantic:
|
||||
system_prompt += f"\nReturn ONLY a JSON object that matches this Pydantic model: {json.dumps(output_pydantic.model_json_schema())}"
|
||||
else:
|
||||
# For multimodal prompts
|
||||
messages = [
|
||||
{"role": "system", "content": system_prompt},
|
||||
{"role": "user", "content": prompt}
|
||||
]
|
||||
if output_json or output_pydantic:
|
||||
# Add JSON instruction to text content
|
||||
for item in messages[-1]["content"]:
|
||||
system_prompt = None
|
||||
|
||||
messages = []
|
||||
if system_prompt:
|
||||
messages.append({"role": "system", "content": system_prompt})
|
||||
messages.extend(self.chat_history)
|
||||
|
||||
# Modify prompt if output_json or output_pydantic is specified
|
||||
original_prompt = prompt
|
||||
if output_json or output_pydantic:
|
||||
if isinstance(prompt, str):
|
||||
prompt += "\nReturn ONLY a valid JSON object. No other text or explanation."
|
||||
elif isinstance(prompt, list):
|
||||
for item in prompt:
|
||||
if item["type"] == "text":
|
||||
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:
|
||||
for tool in tools:
|
||||
if isinstance(tool, str):
|
||||
tool_def = self._generate_tool_definition(tool)
|
||||
if tool_def:
|
||||
formatted_tools.append(tool_def)
|
||||
elif isinstance(tool, dict):
|
||||
formatted_tools.append(tool)
|
||||
elif hasattr(tool, "to_openai_tool"):
|
||||
formatted_tools.append(tool.to_openai_tool())
|
||||
elif callable(tool):
|
||||
formatted_tools.append(self._generate_tool_definition(tool.__name__))
|
||||
|
||||
# Create async OpenAI client
|
||||
async_client = AsyncOpenAI()
|
||||
|
||||
# Make the API call based on the type of request
|
||||
if tools:
|
||||
response = await async_client.chat.completions.create(
|
||||
model=self.llm,
|
||||
messages=messages,
|
||||
temperature=temperature,
|
||||
tools=formatted_tools
|
||||
)
|
||||
return await self._achat_completion(response, tools)
|
||||
elif output_json or output_pydantic:
|
||||
response = await async_client.chat.completions.create(
|
||||
model=self.llm,
|
||||
messages=messages,
|
||||
temperature=temperature,
|
||||
response_format={"type": "json_object"}
|
||||
)
|
||||
# Return the raw response
|
||||
return response.choices[0].message.content
|
||||
if isinstance(prompt, list):
|
||||
messages.append({"role": "user", "content": prompt})
|
||||
else:
|
||||
response = await async_client.chat.completions.create(
|
||||
model=self.llm,
|
||||
messages=messages,
|
||||
temperature=temperature
|
||||
)
|
||||
return response.choices[0].message.content
|
||||
messages.append({"role": "user", "content": prompt})
|
||||
|
||||
reflection_count = 0
|
||||
start_time = time.time()
|
||||
|
||||
while True:
|
||||
try:
|
||||
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:
|
||||
for tool in tools:
|
||||
if isinstance(tool, str):
|
||||
tool_def = self._generate_tool_definition(tool)
|
||||
if tool_def:
|
||||
formatted_tools.append(tool_def)
|
||||
elif isinstance(tool, dict):
|
||||
formatted_tools.append(tool)
|
||||
elif hasattr(tool, "to_openai_tool"):
|
||||
formatted_tools.append(tool.to_openai_tool())
|
||||
elif callable(tool):
|
||||
formatted_tools.append(self._generate_tool_definition(tool.__name__))
|
||||
|
||||
# Create async OpenAI client
|
||||
async_client = AsyncOpenAI()
|
||||
|
||||
# Make the API call based on the type of request
|
||||
if tools:
|
||||
response = await async_client.chat.completions.create(
|
||||
model=self.llm,
|
||||
messages=messages,
|
||||
temperature=temperature,
|
||||
tools=formatted_tools
|
||||
)
|
||||
return await self._achat_completion(response, tools)
|
||||
elif output_json or output_pydantic:
|
||||
response = await async_client.chat.completions.create(
|
||||
model=self.llm,
|
||||
messages=messages,
|
||||
temperature=temperature,
|
||||
response_format={"type": "json_object"}
|
||||
)
|
||||
# Return the raw response
|
||||
return response.choices[0].message.content
|
||||
else:
|
||||
response = await async_client.chat.completions.create(
|
||||
model=self.llm,
|
||||
messages=messages,
|
||||
temperature=temperature
|
||||
)
|
||||
return response.choices[0].message.content
|
||||
except Exception as e:
|
||||
display_error(f"Error in chat completion: {e}")
|
||||
return None
|
||||
except Exception as e:
|
||||
display_error(f"Error in chat completion: {e}")
|
||||
display_error(f"Error in achat: {e}")
|
||||
return None
|
||||
|
||||
async def _achat_completion(self, response, tools):
|
||||
@@ -821,10 +954,57 @@ Output MUST be JSON with 'reflection' and 'satisfactory'.
|
||||
display_error(f"Error in _achat_completion: {e}")
|
||||
return None
|
||||
|
||||
async def astart(self, prompt: str, **kwargs):
|
||||
"""Async version of start method"""
|
||||
return await self.achat(prompt, **kwargs)
|
||||
|
||||
def run(self):
|
||||
"""Alias for start() method"""
|
||||
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)
|
||||
return self.chat(prompt, **kwargs)
|
||||
|
||||
async def execute_tool_async(self, function_name: str, arguments: Dict[str, Any]) -> Any:
|
||||
"""Async version of execute_tool"""
|
||||
try:
|
||||
logging.info(f"Executing async tool: {function_name} with arguments: {arguments}")
|
||||
# Try to find the function in the agent's tools list first
|
||||
func = None
|
||||
for tool in self.tools:
|
||||
if (callable(tool) and getattr(tool, '__name__', '') == function_name):
|
||||
func = tool
|
||||
break
|
||||
|
||||
if func is None:
|
||||
logging.error(f"Function {function_name} not found in tools")
|
||||
return {"error": f"Function {function_name} not found in tools"}
|
||||
|
||||
try:
|
||||
if inspect.iscoroutinefunction(func):
|
||||
logging.debug(f"Executing async function: {function_name}")
|
||||
result = await func(**arguments)
|
||||
else:
|
||||
logging.debug(f"Executing sync function in executor: {function_name}")
|
||||
loop = asyncio.get_event_loop()
|
||||
result = await loop.run_in_executor(None, lambda: func(**arguments))
|
||||
|
||||
# Ensure result is JSON serializable
|
||||
logging.debug(f"Raw result from tool: {result}")
|
||||
if result is None:
|
||||
return {"result": None}
|
||||
try:
|
||||
json.dumps(result) # Test serialization
|
||||
return result
|
||||
except TypeError:
|
||||
logging.warning(f"Result not JSON serializable, converting to string: {result}")
|
||||
return {"result": str(result)}
|
||||
|
||||
except Exception as e:
|
||||
logging.error(f"Error executing {function_name}: {str(e)}", exc_info=True)
|
||||
return {"error": f"Error executing {function_name}: {str(e)}"}
|
||||
|
||||
except Exception as e:
|
||||
logging.error(f"Error in execute_tool_async: {str(e)}", exc_info=True)
|
||||
return {"error": f"Error in execute_tool_async: {str(e)}"}
|
||||
@@ -45,12 +45,24 @@ 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, memory=False, memory_config=None, embedder=None, user_id=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):
|
||||
# Add check at the start if memory is requested
|
||||
if memory:
|
||||
try:
|
||||
from ..memory.memory import Memory
|
||||
MEMORY_AVAILABLE = True
|
||||
except ImportError:
|
||||
raise ImportError(
|
||||
"Memory features requested but memory dependencies not installed. "
|
||||
"Please install with: pip install \"praisonaiagents[memory]\""
|
||||
)
|
||||
|
||||
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.user_id = user_id or "praison" # Optional user_id
|
||||
self.max_iter = max_iter # Add max_iter parameter
|
||||
|
||||
# Pass user_id to each agent
|
||||
for agent in agents:
|
||||
@@ -244,6 +256,24 @@ Expected Output: {task.expected_output}.
|
||||
context_results.append(
|
||||
f"Previous task {context_item.name if context_item.name else context_item.description} has no result yet."
|
||||
)
|
||||
elif isinstance(context_item, dict) and "vector_store" in context_item:
|
||||
from ..knowledge.knowledge import Knowledge
|
||||
try:
|
||||
# Handle both string and dict configs
|
||||
cfg = context_item["vector_store"]
|
||||
if isinstance(cfg, str):
|
||||
cfg = json.loads(cfg)
|
||||
|
||||
knowledge = Knowledge(config={"vector_store": cfg}, verbose=self.verbose)
|
||||
|
||||
# Only use user_id as filter
|
||||
db_results = knowledge.search(
|
||||
task.description,
|
||||
user_id=self.user_id if self.user_id else None
|
||||
)
|
||||
context_results.append(f"[DB Context]: {str(db_results)}")
|
||||
except Exception as e:
|
||||
context_results.append(f"[Vector DB Error]: {e}")
|
||||
|
||||
# Join unique context results
|
||||
unique_contexts = list(dict.fromkeys(context_results)) # Remove duplicates
|
||||
@@ -360,7 +390,15 @@ Context:
|
||||
task.status = "completed"
|
||||
# Run execute_callback for memory operations
|
||||
try:
|
||||
await task.execute_callback(task_output)
|
||||
try:
|
||||
# If a loop is already running, just create the task
|
||||
loop = asyncio.get_running_loop()
|
||||
loop.create_task(task.execute_callback(task_output))
|
||||
except RuntimeError:
|
||||
# Otherwise, create and set a new loop, and run the callback
|
||||
loop = asyncio.new_event_loop()
|
||||
asyncio.set_event_loop(loop)
|
||||
loop.create_task(task.execute_callback(task_output))
|
||||
except Exception as e:
|
||||
logger.error(f"Error executing memory callback for task {task_id}: {e}")
|
||||
logger.exception(e)
|
||||
@@ -369,7 +407,12 @@ Context:
|
||||
if task.callback:
|
||||
try:
|
||||
if asyncio.iscoroutinefunction(task.callback):
|
||||
await task.callback(task_output)
|
||||
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:
|
||||
@@ -402,7 +445,8 @@ Context:
|
||||
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":
|
||||
@@ -521,6 +565,24 @@ Expected Output: {task.expected_output}.
|
||||
context_results.append(
|
||||
f"Previous task {context_item.name if context_item.name else context_item.description} has no result yet."
|
||||
)
|
||||
elif isinstance(context_item, dict) and "vector_store" in context_item:
|
||||
from ..knowledge.knowledge import Knowledge
|
||||
try:
|
||||
# Handle both string and dict configs
|
||||
cfg = context_item["vector_store"]
|
||||
if isinstance(cfg, str):
|
||||
cfg = json.loads(cfg)
|
||||
|
||||
knowledge = Knowledge(config={"vector_store": cfg}, verbose=self.verbose)
|
||||
|
||||
# Only use user_id as filter
|
||||
db_results = knowledge.search(
|
||||
task.description,
|
||||
user_id=self.user_id if self.user_id else None
|
||||
)
|
||||
context_results.append(f"[DB Context]: {str(db_results)}")
|
||||
except Exception as e:
|
||||
context_results.append(f"[Vector DB Error]: {e}")
|
||||
|
||||
# Join unique context results
|
||||
unique_contexts = list(dict.fromkeys(context_results)) # Remove duplicates
|
||||
@@ -658,12 +720,15 @@ Context:
|
||||
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:
|
||||
try:
|
||||
# If a loop is already running, just create the task
|
||||
loop = asyncio.get_running_loop()
|
||||
loop.create_task(task.execute_callback(task_output))
|
||||
except RuntimeError:
|
||||
# Otherwise, create and set a new loop, and run the callback
|
||||
loop = asyncio.new_event_loop()
|
||||
asyncio.set_event_loop(loop)
|
||||
loop.run_until_complete(task.execute_callback(task_output))
|
||||
loop.create_task(task.execute_callback(task_output))
|
||||
except Exception as e:
|
||||
logger.error(f"Error executing memory callback for task {task_id}: {e}")
|
||||
logger.exception(e)
|
||||
@@ -710,7 +775,8 @@ Context:
|
||||
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":
|
||||
|
||||
@@ -84,8 +84,8 @@ class Knowledge:
|
||||
|
||||
@cached_property
|
||||
def config(self):
|
||||
# Generate unique collection name for each instance
|
||||
collection_name = f"test_{int(time.time())}_{str(uuid.uuid4())[:8]}"
|
||||
# Generate unique collection name for each instance (only if not provided in config)
|
||||
default_collection = f"test_{int(time.time())}_{str(uuid.uuid4())[:8]}"
|
||||
persist_dir = ".praison"
|
||||
|
||||
# Create persistent client config
|
||||
@@ -93,9 +93,11 @@ class Knowledge:
|
||||
"vector_store": {
|
||||
"provider": "chroma",
|
||||
"config": {
|
||||
"collection_name": collection_name,
|
||||
"collection_name": default_collection,
|
||||
"path": persist_dir,
|
||||
"client": self._deps['chromadb'].PersistentClient(path=persist_dir)
|
||||
"client": self._deps['chromadb'].PersistentClient(path=persist_dir),
|
||||
"host": None,
|
||||
"port": None
|
||||
}
|
||||
},
|
||||
"version": "v1.1",
|
||||
@@ -104,13 +106,29 @@ class Knowledge:
|
||||
|
||||
# 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)
|
||||
|
||||
# Merge version if provided
|
||||
if "version" in self._config:
|
||||
base_config["version"] = self._config["version"]
|
||||
|
||||
# Merge vector_store config
|
||||
if "vector_store" in self._config:
|
||||
if "provider" in self._config["vector_store"]:
|
||||
base_config["vector_store"]["provider"] = self._config["vector_store"]["provider"]
|
||||
|
||||
if "config" in self._config["vector_store"]:
|
||||
config_copy = self._config["vector_store"]["config"].copy()
|
||||
# Only exclude client as it's managed internally
|
||||
if "client" in config_copy:
|
||||
del config_copy["client"]
|
||||
base_config["vector_store"]["config"].update(config_copy)
|
||||
|
||||
# Merge embedder config if provided
|
||||
if "embedder" in self._config:
|
||||
base_config["embedder"] = self._config["embedder"]
|
||||
|
||||
# Merge llm config if provided
|
||||
if "llm" in self._config:
|
||||
base_config["llm"] = self._config["llm"]
|
||||
return base_config
|
||||
|
||||
@cached_property
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
import logging
|
||||
import warnings
|
||||
|
||||
# Suppress all relevant logs at module level
|
||||
logging.getLogger("litellm").setLevel(logging.ERROR)
|
||||
logging.getLogger("openai").setLevel(logging.ERROR)
|
||||
logging.getLogger("httpx").setLevel(logging.ERROR)
|
||||
logging.getLogger("httpcore").setLevel(logging.ERROR)
|
||||
logging.getLogger("pydantic").setLevel(logging.ERROR)
|
||||
|
||||
# Suppress pydantic warnings
|
||||
warnings.filterwarnings("ignore", category=UserWarning, module="pydantic")
|
||||
|
||||
# Configure logging to suppress all INFO messages
|
||||
logging.basicConfig(level=logging.WARNING)
|
||||
|
||||
# Import after suppressing warnings
|
||||
from .llm import LLM, LLMContextLengthExceededException
|
||||
|
||||
__all__ = ["LLM", "LLMContextLengthExceededException"]
|
||||
@@ -0,0 +1,823 @@
|
||||
import logging
|
||||
import os
|
||||
import warnings
|
||||
from typing import Any, Dict, List, Optional, Union, Literal, Callable
|
||||
from pydantic import BaseModel
|
||||
import time
|
||||
import json
|
||||
from ..main import (
|
||||
display_error,
|
||||
display_tool_call,
|
||||
display_instruction,
|
||||
display_interaction,
|
||||
display_generating,
|
||||
display_self_reflection,
|
||||
ReflectionOutput,
|
||||
)
|
||||
from rich.console import Console
|
||||
from rich.live import Live
|
||||
|
||||
class LLMContextLengthExceededException(Exception):
|
||||
"""Raised when LLM context length is exceeded"""
|
||||
def __init__(self, message: str):
|
||||
self.message = message
|
||||
super().__init__(self.message)
|
||||
|
||||
def _is_context_limit_error(self, error_message: str) -> bool:
|
||||
"""Check if error is related to context length"""
|
||||
context_limit_phrases = [
|
||||
"maximum context length",
|
||||
"context window is too long",
|
||||
"context length exceeded",
|
||||
"context_length_exceeded"
|
||||
]
|
||||
return any(phrase in error_message.lower() for phrase in context_limit_phrases)
|
||||
|
||||
class LLM:
|
||||
"""
|
||||
Easy to use wrapper for language models. Supports multiple providers like OpenAI,
|
||||
Anthropic, and others through LiteLLM.
|
||||
"""
|
||||
|
||||
# Default window sizes for different models (75% of actual to be safe)
|
||||
MODEL_WINDOWS = {
|
||||
# OpenAI
|
||||
"gpt-4": 6144, # 8,192 actual
|
||||
"gpt-4o": 96000, # 128,000 actual
|
||||
"gpt-4o-mini": 96000, # 128,000 actual
|
||||
"gpt-4-turbo": 96000, # 128,000 actual
|
||||
"o1-preview": 96000, # 128,000 actual
|
||||
"o1-mini": 96000, # 128,000 actual
|
||||
|
||||
# Anthropic
|
||||
"claude-3-5-sonnet": 12288, # 16,384 actual
|
||||
"claude-3-sonnet": 12288, # 16,384 actual
|
||||
"claude-3-opus": 96000, # 128,000 actual
|
||||
"claude-3-haiku": 96000, # 128,000 actual
|
||||
|
||||
# Gemini
|
||||
"gemini-2.0-flash": 786432, # 1,048,576 actual
|
||||
"gemini-1.5-pro": 1572864, # 2,097,152 actual
|
||||
"gemini-1.5-flash": 786432, # 1,048,576 actual
|
||||
"gemini-1.5-flash-8b": 786432, # 1,048,576 actual
|
||||
|
||||
# Deepseek
|
||||
"deepseek-chat": 96000, # 128,000 actual
|
||||
|
||||
# Groq
|
||||
"gemma2-9b-it": 6144, # 8,192 actual
|
||||
"gemma-7b-it": 6144, # 8,192 actual
|
||||
"llama3-70b-8192": 6144, # 8,192 actual
|
||||
"llama3-8b-8192": 6144, # 8,192 actual
|
||||
"mixtral-8x7b-32768": 24576, # 32,768 actual
|
||||
"llama-3.3-70b-versatile": 96000, # 128,000 actual
|
||||
"llama-3.3-70b-instruct": 96000, # 128,000 actual
|
||||
|
||||
# Other llama models
|
||||
"llama-3.1-70b-versatile": 98304, # 131,072 actual
|
||||
"llama-3.1-8b-instant": 98304, # 131,072 actual
|
||||
"llama-3.2-1b-preview": 6144, # 8,192 actual
|
||||
"llama-3.2-3b-preview": 6144, # 8,192 actual
|
||||
"llama-3.2-11b-text-preview": 6144, # 8,192 actual
|
||||
"llama-3.2-90b-text-preview": 6144 # 8,192 actual
|
||||
}
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
model: str,
|
||||
timeout: Optional[int] = None,
|
||||
temperature: Optional[float] = None,
|
||||
top_p: Optional[float] = None,
|
||||
n: Optional[int] = None,
|
||||
max_tokens: Optional[int] = None,
|
||||
presence_penalty: Optional[float] = None,
|
||||
frequency_penalty: Optional[float] = None,
|
||||
logit_bias: Optional[Dict[int, float]] = None,
|
||||
response_format: Optional[Dict[str, Any]] = None,
|
||||
seed: Optional[int] = None,
|
||||
logprobs: Optional[bool] = None,
|
||||
top_logprobs: Optional[int] = None,
|
||||
api_version: Optional[str] = None,
|
||||
stop_phrases: Optional[Union[str, List[str]]] = None,
|
||||
api_key: Optional[str] = None,
|
||||
base_url: Optional[str] = None,
|
||||
events: List[Any] = [],
|
||||
**extra_settings
|
||||
):
|
||||
try:
|
||||
import litellm
|
||||
# Set litellm options globally
|
||||
litellm.set_verbose = False
|
||||
litellm.success_callback = []
|
||||
litellm._async_success_callback = []
|
||||
litellm.callbacks = []
|
||||
# Additional logging suppression
|
||||
litellm.suppress_debug_messages = True
|
||||
logging.getLogger("litellm.utils").setLevel(logging.WARNING)
|
||||
logging.getLogger("litellm.main").setLevel(logging.WARNING)
|
||||
except ImportError:
|
||||
raise ImportError(
|
||||
"LiteLLM is required but not installed. "
|
||||
"Please install with: pip install 'praisonaiagents[llm]'"
|
||||
)
|
||||
|
||||
self.model = model
|
||||
self.timeout = timeout
|
||||
self.temperature = temperature
|
||||
self.top_p = top_p
|
||||
self.n = n
|
||||
self.max_tokens = max_tokens
|
||||
self.presence_penalty = presence_penalty
|
||||
self.frequency_penalty = frequency_penalty
|
||||
self.logit_bias = logit_bias
|
||||
self.response_format = response_format
|
||||
self.seed = seed
|
||||
self.logprobs = logprobs
|
||||
self.top_logprobs = top_logprobs
|
||||
self.api_version = api_version
|
||||
self.stop_phrases = stop_phrases
|
||||
self.api_key = api_key
|
||||
self.base_url = base_url
|
||||
self.events = events
|
||||
self.extra_settings = extra_settings
|
||||
self.console = Console()
|
||||
self.chat_history = []
|
||||
self.verbose = extra_settings.get('verbose', True)
|
||||
self.markdown = extra_settings.get('markdown', True)
|
||||
self.self_reflect = extra_settings.get('self_reflect', False)
|
||||
self.max_reflect = extra_settings.get('max_reflect', 3)
|
||||
self.min_reflect = extra_settings.get('min_reflect', 1)
|
||||
|
||||
# Enable error dropping for cleaner output
|
||||
litellm.drop_params = True
|
||||
self._setup_event_tracking(events)
|
||||
|
||||
def get_response(
|
||||
self,
|
||||
prompt: Union[str, List[Dict]],
|
||||
system_prompt: Optional[str] = None,
|
||||
chat_history: Optional[List[Dict]] = None,
|
||||
temperature: float = 0.2,
|
||||
tools: Optional[List[Any]] = None,
|
||||
output_json: Optional[BaseModel] = None,
|
||||
output_pydantic: Optional[BaseModel] = None,
|
||||
verbose: bool = True,
|
||||
markdown: bool = True,
|
||||
self_reflect: bool = False,
|
||||
max_reflect: int = 3,
|
||||
min_reflect: int = 1,
|
||||
console: Optional[Console] = None,
|
||||
agent_name: Optional[str] = None,
|
||||
agent_role: Optional[str] = None,
|
||||
agent_tools: Optional[List[str]] = None,
|
||||
execute_tool_fn: Optional[Callable] = None,
|
||||
**kwargs
|
||||
) -> str:
|
||||
"""Enhanced get_response with all OpenAI-like features"""
|
||||
try:
|
||||
import litellm
|
||||
|
||||
# Disable litellm debug messages
|
||||
litellm.set_verbose = False
|
||||
|
||||
# Build messages list
|
||||
messages = []
|
||||
if system_prompt:
|
||||
if output_json:
|
||||
system_prompt += f"\nReturn ONLY a JSON object that matches this Pydantic model: {json.dumps(output_json.model_json_schema())}"
|
||||
elif output_pydantic:
|
||||
system_prompt += f"\nReturn ONLY a JSON object that matches this Pydantic model: {json.dumps(output_pydantic.model_json_schema())}"
|
||||
messages.append({"role": "system", "content": system_prompt})
|
||||
|
||||
if chat_history:
|
||||
messages.extend(chat_history)
|
||||
|
||||
# Handle prompt modifications for JSON output
|
||||
original_prompt = prompt
|
||||
if output_json or output_pydantic:
|
||||
if isinstance(prompt, str):
|
||||
prompt += "\nReturn ONLY a valid JSON object. No other text or explanation."
|
||||
elif isinstance(prompt, list):
|
||||
for item in prompt:
|
||||
if item["type"] == "text":
|
||||
item["text"] += "\nReturn ONLY a valid JSON object. No other text or explanation."
|
||||
break
|
||||
|
||||
# Add prompt to messages
|
||||
if isinstance(prompt, list):
|
||||
messages.append({"role": "user", "content": prompt})
|
||||
else:
|
||||
messages.append({"role": "user", "content": prompt})
|
||||
|
||||
start_time = time.time()
|
||||
reflection_count = 0
|
||||
|
||||
while True:
|
||||
try:
|
||||
if 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():
|
||||
display_instruction(
|
||||
f"Agent {agent_name} is processing prompt: {display_text}",
|
||||
console=console,
|
||||
agent_name=agent_name,
|
||||
agent_role=agent_role,
|
||||
agent_tools=agent_tools
|
||||
)
|
||||
|
||||
# Get response from LiteLLM
|
||||
start_time = time.time()
|
||||
if verbose:
|
||||
with Live(display_generating("", start_time), console=console, refresh_per_second=4) as live:
|
||||
response_text = ""
|
||||
for chunk in litellm.completion(
|
||||
model=self.model,
|
||||
messages=messages,
|
||||
temperature=temperature,
|
||||
stream=True,
|
||||
**kwargs
|
||||
):
|
||||
if chunk and chunk.choices and chunk.choices[0].delta.content:
|
||||
content = chunk.choices[0].delta.content
|
||||
response_text += content
|
||||
live.update(display_generating(response_text, start_time))
|
||||
else:
|
||||
# Non-verbose mode, just collect the response
|
||||
response_text = ""
|
||||
for chunk in litellm.completion(
|
||||
model=self.model,
|
||||
messages=messages,
|
||||
temperature=temperature,
|
||||
stream=True,
|
||||
**kwargs
|
||||
):
|
||||
if chunk and chunk.choices and chunk.choices[0].delta.content:
|
||||
response_text += chunk.choices[0].delta.content
|
||||
|
||||
response_text = response_text.strip()
|
||||
|
||||
# Get final completion to check for tool calls
|
||||
final_response = litellm.completion(
|
||||
model=self.model,
|
||||
messages=messages,
|
||||
temperature=temperature,
|
||||
stream=False, # No streaming for tool call check
|
||||
**kwargs
|
||||
)
|
||||
|
||||
tool_calls = final_response["choices"][0]["message"].get("tool_calls")
|
||||
|
||||
# Handle tool calls
|
||||
if tool_calls and execute_tool_fn:
|
||||
messages.append({
|
||||
"role": "assistant",
|
||||
"content": response_text,
|
||||
"tool_calls": tool_calls
|
||||
})
|
||||
|
||||
for tool_call in tool_calls:
|
||||
function_name = tool_call["function"]["name"]
|
||||
arguments = json.loads(tool_call["function"]["arguments"])
|
||||
|
||||
if verbose:
|
||||
display_tool_call(f"Agent {agent_name} is calling function '{function_name}' with arguments: {arguments}", console=console)
|
||||
|
||||
tool_result = execute_tool_fn(function_name, arguments)
|
||||
|
||||
if tool_result:
|
||||
if verbose:
|
||||
display_tool_call(f"Function '{function_name}' returned: {tool_result}", console=console)
|
||||
messages.append({
|
||||
"role": "tool",
|
||||
"tool_call_id": tool_call["id"],
|
||||
"content": json.dumps(tool_result)
|
||||
})
|
||||
else:
|
||||
messages.append({
|
||||
"role": "tool",
|
||||
"tool_call_id": tool_call["id"],
|
||||
"content": "Function returned an empty output"
|
||||
})
|
||||
|
||||
# Get response after tool calls with streaming
|
||||
if verbose:
|
||||
with Live(display_generating("", start_time), console=console, refresh_per_second=4) as live:
|
||||
response_text = ""
|
||||
for chunk in litellm.completion(
|
||||
model=self.model,
|
||||
messages=messages,
|
||||
temperature=temperature,
|
||||
stream=True
|
||||
):
|
||||
if chunk and chunk.choices and chunk.choices[0].delta.content:
|
||||
content = chunk.choices[0].delta.content
|
||||
response_text += content
|
||||
live.update(display_generating(response_text, start_time))
|
||||
else:
|
||||
response_text = ""
|
||||
for chunk in litellm.completion(
|
||||
model=self.model,
|
||||
messages=messages,
|
||||
temperature=temperature,
|
||||
stream=True
|
||||
):
|
||||
if chunk and chunk.choices and chunk.choices[0].delta.content:
|
||||
response_text += chunk.choices[0].delta.content
|
||||
|
||||
response_text = response_text.strip()
|
||||
|
||||
# Handle output formatting
|
||||
if output_json or output_pydantic:
|
||||
self.chat_history.append({"role": "user", "content": original_prompt})
|
||||
self.chat_history.append({"role": "assistant", "content": response_text})
|
||||
if verbose:
|
||||
display_interaction(original_prompt, response_text, markdown=markdown,
|
||||
generation_time=time.time() - start_time, console=console)
|
||||
return response_text
|
||||
|
||||
if not self_reflect:
|
||||
if verbose:
|
||||
display_interaction(original_prompt, response_text, markdown=markdown,
|
||||
generation_time=time.time() - start_time, console=console)
|
||||
return response_text
|
||||
|
||||
# Handle self-reflection
|
||||
reflection_prompt = f"""
|
||||
Reflect on your previous response: '{response_text}'.
|
||||
Identify any flaws, improvements, or actions.
|
||||
Provide a "satisfactory" status ('yes' or 'no').
|
||||
Output MUST be JSON with 'reflection' and 'satisfactory'.
|
||||
"""
|
||||
|
||||
reflection_messages = messages + [
|
||||
{"role": "assistant", "content": response_text},
|
||||
{"role": "user", "content": reflection_prompt}
|
||||
]
|
||||
|
||||
# Get reflection response with streaming
|
||||
if verbose:
|
||||
with Live(display_generating("", start_time), console=console, refresh_per_second=4) as live:
|
||||
reflection_text = ""
|
||||
for chunk in litellm.completion(
|
||||
model=self.model,
|
||||
messages=reflection_messages,
|
||||
temperature=temperature,
|
||||
stream=True,
|
||||
response_format={"type": "json_object"}
|
||||
):
|
||||
if chunk and chunk.choices and chunk.choices[0].delta.content:
|
||||
content = chunk.choices[0].delta.content
|
||||
reflection_text += content
|
||||
live.update(display_generating(reflection_text, start_time))
|
||||
else:
|
||||
reflection_text = ""
|
||||
for chunk in litellm.completion(
|
||||
model=self.model,
|
||||
messages=reflection_messages,
|
||||
temperature=temperature,
|
||||
stream=True,
|
||||
response_format={"type": "json_object"}
|
||||
):
|
||||
if chunk and chunk.choices and chunk.choices[0].delta.content:
|
||||
reflection_text += chunk.choices[0].delta.content
|
||||
|
||||
try:
|
||||
reflection_data = json.loads(reflection_text)
|
||||
satisfactory = reflection_data.get("satisfactory", "no").lower() == "yes"
|
||||
|
||||
if verbose:
|
||||
display_self_reflection(
|
||||
f"Agent {agent_name} self reflection: reflection='{reflection_data['reflection']}' satisfactory='{reflection_data['satisfactory']}'",
|
||||
console=console
|
||||
)
|
||||
|
||||
if satisfactory and reflection_count >= min_reflect - 1:
|
||||
if verbose:
|
||||
display_interaction(prompt, response_text, markdown=markdown,
|
||||
generation_time=time.time() - start_time, console=console)
|
||||
return response_text
|
||||
|
||||
if reflection_count >= max_reflect - 1:
|
||||
if verbose:
|
||||
display_interaction(prompt, response_text, markdown=markdown,
|
||||
generation_time=time.time() - start_time, console=console)
|
||||
return response_text
|
||||
|
||||
reflection_count += 1
|
||||
messages.extend([
|
||||
{"role": "assistant", "content": response_text},
|
||||
{"role": "user", "content": reflection_prompt},
|
||||
{"role": "assistant", "content": reflection_text},
|
||||
{"role": "user", "content": "Now regenerate your response using the reflection you made"}
|
||||
])
|
||||
continue
|
||||
|
||||
except json.JSONDecodeError:
|
||||
reflection_count += 1
|
||||
if reflection_count >= max_reflect:
|
||||
return response_text
|
||||
continue
|
||||
|
||||
except Exception as e:
|
||||
display_error(f"Error in LLM response: {str(e)}")
|
||||
return None
|
||||
|
||||
except Exception as error:
|
||||
display_error(f"Error in get_response: {str(error)}")
|
||||
raise
|
||||
|
||||
async def get_response_async(
|
||||
self,
|
||||
prompt: Union[str, List[Dict]],
|
||||
system_prompt: Optional[str] = None,
|
||||
chat_history: Optional[List[Dict]] = None,
|
||||
temperature: float = 0.2,
|
||||
tools: Optional[List[Any]] = None,
|
||||
output_json: Optional[BaseModel] = None,
|
||||
output_pydantic: Optional[BaseModel] = None,
|
||||
verbose: bool = True,
|
||||
markdown: bool = True,
|
||||
self_reflect: bool = False,
|
||||
max_reflect: int = 3,
|
||||
min_reflect: int = 1,
|
||||
console: Optional[Console] = None,
|
||||
agent_name: Optional[str] = None,
|
||||
agent_role: Optional[str] = None,
|
||||
agent_tools: Optional[List[str]] = None,
|
||||
execute_tool_fn: Optional[Callable] = None,
|
||||
**kwargs
|
||||
) -> str:
|
||||
"""Async version of get_response with identical functionality."""
|
||||
try:
|
||||
import litellm
|
||||
litellm.set_verbose = False
|
||||
|
||||
# Build messages list
|
||||
messages = []
|
||||
if system_prompt:
|
||||
if output_json:
|
||||
system_prompt += f"\nReturn ONLY a JSON object that matches this Pydantic model: {json.dumps(output_json.model_json_schema())}"
|
||||
elif output_pydantic:
|
||||
system_prompt += f"\nReturn ONLY a JSON object that matches this Pydantic model: {json.dumps(output_pydantic.model_json_schema())}"
|
||||
messages.append({"role": "system", "content": system_prompt})
|
||||
|
||||
if chat_history:
|
||||
messages.extend(chat_history)
|
||||
|
||||
# Handle prompt modifications for JSON output
|
||||
original_prompt = prompt
|
||||
if output_json or output_pydantic:
|
||||
if isinstance(prompt, str):
|
||||
prompt += "\nReturn ONLY a valid JSON object. No other text or explanation."
|
||||
elif isinstance(prompt, list):
|
||||
for item in prompt:
|
||||
if item["type"] == "text":
|
||||
item["text"] += "\nReturn ONLY a valid JSON object. No other text or explanation."
|
||||
break
|
||||
|
||||
# Add prompt to messages
|
||||
if isinstance(prompt, list):
|
||||
messages.append({"role": "user", "content": prompt})
|
||||
else:
|
||||
messages.append({"role": "user", "content": prompt})
|
||||
|
||||
start_time = time.time()
|
||||
reflection_count = 0
|
||||
|
||||
# Format tools for LiteLLM
|
||||
formatted_tools = None
|
||||
if tools:
|
||||
logging.info(f"Starting tool formatting for {len(tools)} tools")
|
||||
formatted_tools = []
|
||||
for tool in tools:
|
||||
logging.info(f"Processing tool: {tool.__name__ if hasattr(tool, '__name__') else str(tool)}")
|
||||
if hasattr(tool, '__name__'):
|
||||
tool_name = tool.__name__
|
||||
tool_doc = tool.__doc__ or "No description available"
|
||||
# Get function signature
|
||||
import inspect
|
||||
sig = inspect.signature(tool)
|
||||
logging.debug(f"Tool signature: {sig}")
|
||||
params = {}
|
||||
required = []
|
||||
for name, param in sig.parameters.items():
|
||||
logging.debug(f"Processing parameter: {name} with annotation: {param.annotation}")
|
||||
param_type = "string"
|
||||
if param.annotation != inspect.Parameter.empty:
|
||||
if param.annotation == int:
|
||||
param_type = "integer"
|
||||
elif param.annotation == float:
|
||||
param_type = "number"
|
||||
elif param.annotation == bool:
|
||||
param_type = "boolean"
|
||||
elif param.annotation == Dict:
|
||||
param_type = "object"
|
||||
elif param.annotation == List:
|
||||
param_type = "array"
|
||||
elif hasattr(param.annotation, "__name__"):
|
||||
param_type = param.annotation.__name__.lower()
|
||||
params[name] = {"type": param_type}
|
||||
if param.default == inspect.Parameter.empty:
|
||||
required.append(name)
|
||||
|
||||
logging.debug(f"Generated parameters: {params}")
|
||||
logging.debug(f"Required parameters: {required}")
|
||||
|
||||
tool_def = {
|
||||
"type": "function",
|
||||
"function": {
|
||||
"name": tool_name,
|
||||
"description": tool_doc,
|
||||
"parameters": {
|
||||
"type": "object",
|
||||
"properties": params,
|
||||
"required": required
|
||||
}
|
||||
}
|
||||
}
|
||||
# Ensure tool definition is JSON serializable
|
||||
print(f"Generated tool definition: {tool_def}")
|
||||
try:
|
||||
json.dumps(tool_def) # Test serialization
|
||||
logging.info(f"Generated tool definition: {tool_def}")
|
||||
formatted_tools.append(tool_def)
|
||||
except TypeError as e:
|
||||
logging.error(f"Tool definition not JSON serializable: {e}")
|
||||
continue
|
||||
|
||||
# Validate final tools list
|
||||
if formatted_tools:
|
||||
try:
|
||||
json.dumps(formatted_tools) # Final serialization check
|
||||
logging.info(f"Final formatted tools: {json.dumps(formatted_tools, indent=2)}")
|
||||
except TypeError as e:
|
||||
logging.error(f"Final tools list not JSON serializable: {e}")
|
||||
formatted_tools = None
|
||||
|
||||
response_text = ""
|
||||
if verbose:
|
||||
# ----------------------------------------------------
|
||||
# 1) Make the streaming call WITHOUT tools
|
||||
# ----------------------------------------------------
|
||||
async for chunk in await litellm.acompletion(
|
||||
model=self.model,
|
||||
messages=messages,
|
||||
temperature=temperature,
|
||||
stream=True,
|
||||
**kwargs
|
||||
):
|
||||
if chunk and chunk.choices and chunk.choices[0].delta.content:
|
||||
response_text += chunk.choices[0].delta.content
|
||||
print("\033[K", end="\r")
|
||||
print(f"Generating... {time.time() - start_time:.1f}s", end="\r")
|
||||
else:
|
||||
# Non-verbose streaming call, still no tools
|
||||
async for chunk in await litellm.acompletion(
|
||||
model=self.model,
|
||||
messages=messages,
|
||||
temperature=temperature,
|
||||
stream=True,
|
||||
**kwargs
|
||||
):
|
||||
if chunk and chunk.choices and chunk.choices[0].delta.content:
|
||||
response_text += chunk.choices[0].delta.content
|
||||
|
||||
response_text = response_text.strip()
|
||||
|
||||
# ----------------------------------------------------
|
||||
# 2) If tool calls are needed, do a non-streaming call
|
||||
# ----------------------------------------------------
|
||||
if tools and execute_tool_fn:
|
||||
# Next call with tools if needed
|
||||
tool_response = await litellm.acompletion(
|
||||
model=self.model,
|
||||
messages=messages,
|
||||
temperature=temperature,
|
||||
stream=False,
|
||||
tools=formatted_tools, # We safely pass tools here
|
||||
**kwargs
|
||||
)
|
||||
# handle tool_calls from tool_response as usual...
|
||||
tool_calls = tool_response.choices[0].message.get("tool_calls")
|
||||
|
||||
if tool_calls:
|
||||
messages.append({
|
||||
"role": "assistant",
|
||||
"content": response_text,
|
||||
"tool_calls": tool_calls
|
||||
})
|
||||
|
||||
for tool_call in tool_calls:
|
||||
function_name = tool_call.function.name
|
||||
arguments = json.loads(tool_call.function.arguments)
|
||||
|
||||
if verbose:
|
||||
display_tool_call(f"Agent {agent_name} is calling function '{function_name}' with arguments: {arguments}", console=console)
|
||||
|
||||
tool_result = await execute_tool_fn(function_name, arguments)
|
||||
|
||||
if tool_result:
|
||||
if verbose:
|
||||
display_tool_call(f"Function '{function_name}' returned: {tool_result}", console=console)
|
||||
messages.append({
|
||||
"role": "tool",
|
||||
"tool_call_id": tool_call.id,
|
||||
"content": json.dumps(tool_result)
|
||||
})
|
||||
else:
|
||||
messages.append({
|
||||
"role": "tool",
|
||||
"tool_call_id": tool_call.id,
|
||||
"content": "Function returned an empty output"
|
||||
})
|
||||
|
||||
# Get response after tool calls with streaming
|
||||
response_text = ""
|
||||
if verbose:
|
||||
async for chunk in await litellm.acompletion(
|
||||
model=self.model,
|
||||
messages=messages,
|
||||
temperature=temperature,
|
||||
stream=True,
|
||||
tools=formatted_tools,
|
||||
**kwargs
|
||||
):
|
||||
if chunk and chunk.choices and chunk.choices[0].delta.content:
|
||||
content = chunk.choices[0].delta.content
|
||||
response_text += content
|
||||
print("\033[K", end="\r")
|
||||
print(f"Reflecting... {time.time() - start_time:.1f}s", end="\r")
|
||||
else:
|
||||
response_text = ""
|
||||
for chunk in litellm.completion(
|
||||
model=self.model,
|
||||
messages=messages,
|
||||
temperature=temperature,
|
||||
stream=True,
|
||||
**kwargs
|
||||
):
|
||||
if chunk and chunk.choices and chunk.choices[0].delta.content:
|
||||
response_text += chunk.choices[0].delta.content
|
||||
|
||||
response_text = response_text.strip()
|
||||
|
||||
# Handle output formatting
|
||||
if output_json or output_pydantic:
|
||||
self.chat_history.append({"role": "user", "content": original_prompt})
|
||||
self.chat_history.append({"role": "assistant", "content": response_text})
|
||||
if verbose:
|
||||
display_interaction(original_prompt, response_text, markdown=markdown,
|
||||
generation_time=time.time() - start_time, console=console)
|
||||
return response_text
|
||||
|
||||
if not self_reflect:
|
||||
if verbose:
|
||||
display_interaction(original_prompt, response_text, markdown=markdown,
|
||||
generation_time=time.time() - start_time, console=console)
|
||||
return response_text
|
||||
|
||||
# Handle self-reflection
|
||||
reflection_prompt = f"""
|
||||
Reflect on your previous response: '{response_text}'.
|
||||
Identify any flaws, improvements, or actions.
|
||||
Provide a "satisfactory" status ('yes' or 'no').
|
||||
Output MUST be JSON with 'reflection' and 'satisfactory'.
|
||||
"""
|
||||
|
||||
reflection_messages = messages + [
|
||||
{"role": "assistant", "content": response_text},
|
||||
{"role": "user", "content": reflection_prompt}
|
||||
]
|
||||
|
||||
# Get reflection response
|
||||
reflection_text = ""
|
||||
if verbose:
|
||||
async for chunk in await litellm.acompletion(
|
||||
model=self.model,
|
||||
messages=reflection_messages,
|
||||
temperature=temperature,
|
||||
stream=True,
|
||||
response_format={"type": "json_object"},
|
||||
**kwargs
|
||||
):
|
||||
if chunk and chunk.choices and chunk.choices[0].delta.content:
|
||||
content = chunk.choices[0].delta.content
|
||||
reflection_text += content
|
||||
print("\033[K", end="\r")
|
||||
print(f"Reflecting... {time.time() - start_time:.1f}s", end="\r")
|
||||
else:
|
||||
async for chunk in await litellm.acompletion(
|
||||
model=self.model,
|
||||
messages=reflection_messages,
|
||||
temperature=temperature,
|
||||
stream=True,
|
||||
response_format={"type": "json_object"},
|
||||
**kwargs
|
||||
):
|
||||
if chunk and chunk.choices and chunk.choices[0].delta.content:
|
||||
reflection_text += chunk.choices[0].delta.content
|
||||
|
||||
while True: # Add loop for reflection handling
|
||||
try:
|
||||
reflection_data = json.loads(reflection_text)
|
||||
satisfactory = reflection_data.get("satisfactory", "no").lower() == "yes"
|
||||
|
||||
if verbose:
|
||||
display_self_reflection(
|
||||
f"Agent {agent_name} self reflection: reflection='{reflection_data['reflection']}' satisfactory='{reflection_data['satisfactory']}'",
|
||||
console=console
|
||||
)
|
||||
|
||||
if satisfactory and reflection_count >= min_reflect - 1:
|
||||
if verbose:
|
||||
display_interaction(prompt, response_text, markdown=markdown,
|
||||
generation_time=time.time() - start_time, console=console)
|
||||
return response_text
|
||||
|
||||
if reflection_count >= max_reflect - 1:
|
||||
if verbose:
|
||||
display_interaction(prompt, response_text, markdown=markdown,
|
||||
generation_time=time.time() - start_time, console=console)
|
||||
return response_text
|
||||
|
||||
reflection_count += 1
|
||||
messages.extend([
|
||||
{"role": "assistant", "content": response_text},
|
||||
{"role": "user", "content": reflection_prompt},
|
||||
{"role": "assistant", "content": reflection_text},
|
||||
{"role": "user", "content": "Now regenerate your response using the reflection you made"}
|
||||
])
|
||||
continue # Now properly in a loop
|
||||
|
||||
except json.JSONDecodeError:
|
||||
reflection_count += 1
|
||||
if reflection_count >= max_reflect:
|
||||
return response_text
|
||||
continue # Now properly in a loop
|
||||
|
||||
except Exception as error:
|
||||
if LLMContextLengthExceededException(str(error))._is_context_limit_error(str(error)):
|
||||
raise LLMContextLengthExceededException(str(error))
|
||||
display_error(f"Error in get_response_async: {str(error)}")
|
||||
raise
|
||||
|
||||
def can_use_tools(self) -> bool:
|
||||
"""Check if this model can use tool functions"""
|
||||
try:
|
||||
import litellm
|
||||
allowed_params = litellm.get_supported_openai_params(model=self.model)
|
||||
return "response_format" in allowed_params
|
||||
except ImportError:
|
||||
raise ImportError(
|
||||
"LiteLLM is required but not installed. "
|
||||
"Please install it with: pip install 'praisonaiagents[llm]'"
|
||||
)
|
||||
except:
|
||||
return False
|
||||
|
||||
def can_use_stop_words(self) -> bool:
|
||||
"""Check if this model supports stop words"""
|
||||
try:
|
||||
import litellm
|
||||
allowed_params = litellm.get_supported_openai_params(model=self.model)
|
||||
return "stop" in allowed_params
|
||||
except ImportError:
|
||||
raise ImportError(
|
||||
"LiteLLM is required but not installed. "
|
||||
"Please install it with: pip install 'praisonaiagents[llm]'"
|
||||
)
|
||||
except:
|
||||
return False
|
||||
|
||||
def get_context_size(self) -> int:
|
||||
"""Get safe input size limit for this model"""
|
||||
for model_prefix, size in self.MODEL_WINDOWS.items():
|
||||
if self.model.startswith(model_prefix):
|
||||
return size
|
||||
return 4000 # Safe default
|
||||
|
||||
def _setup_event_tracking(self, events: List[Any]) -> None:
|
||||
"""Setup callback functions for tracking model usage"""
|
||||
try:
|
||||
import litellm
|
||||
except ImportError:
|
||||
raise ImportError(
|
||||
"LiteLLM is required but not installed. "
|
||||
"Please install it with: pip install 'praisonaiagents[llm]'"
|
||||
)
|
||||
|
||||
event_types = [type(event) for event in events]
|
||||
|
||||
# Remove old events of same type
|
||||
for event in litellm.success_callback[:]:
|
||||
if type(event) in event_types:
|
||||
litellm.success_callback.remove(event)
|
||||
|
||||
for event in litellm._async_success_callback[:]:
|
||||
if type(event) in event_types:
|
||||
litellm._async_success_callback.remove(event)
|
||||
|
||||
litellm.callbacks = events
|
||||
@@ -14,6 +14,15 @@ from rich.logging import RichHandler
|
||||
from rich.live import Live
|
||||
import asyncio
|
||||
|
||||
# # Configure root logger
|
||||
# logging.basicConfig(level=logging.WARNING)
|
||||
|
||||
# Suppress litellm logs
|
||||
logging.getLogger("litellm").handlers = []
|
||||
logging.getLogger("litellm.utils").handlers = []
|
||||
logging.getLogger("litellm").propagate = False
|
||||
logging.getLogger("litellm.utils").propagate = False
|
||||
|
||||
LOGLEVEL = os.environ.get('LOGLEVEL', 'INFO').upper()
|
||||
|
||||
logging.basicConfig(
|
||||
@@ -23,6 +32,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 = []
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@ try:
|
||||
CHROMADB_AVAILABLE = True
|
||||
except ImportError:
|
||||
CHROMADB_AVAILABLE = False
|
||||
logger.warning("To use memory features, please run: pip install \"praisonaiagents[memory]\"")
|
||||
pass
|
||||
|
||||
try:
|
||||
import mem0
|
||||
|
||||
@@ -5,6 +5,8 @@ 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]
|
||||
@@ -62,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}"
|
||||
|
||||
@@ -144,13 +147,17 @@ Return a JSON object with an 'items' array containing the items to process.
|
||||
next_task = None
|
||||
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:
|
||||
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": # If empty or explicit exit
|
||||
if not task_value or task_value == "exit":
|
||||
logging.info("Workflow exit condition met, ending workflow")
|
||||
current_task = None
|
||||
break
|
||||
@@ -322,7 +329,76 @@ 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
|
||||
@@ -346,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}"
|
||||
|
||||
@@ -396,7 +473,7 @@ 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
|
||||
# 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"
|
||||
@@ -422,13 +499,17 @@ Return a JSON object with an 'items' array containing the items to process.
|
||||
next_task = None
|
||||
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:
|
||||
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": # If empty or explicit exit
|
||||
if not task_value or task_value == "exit":
|
||||
logging.info("Workflow exit condition met, ending workflow")
|
||||
current_task = None
|
||||
break
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
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
|
||||
@@ -37,8 +37,21 @@ class Task:
|
||||
is_start: bool = False,
|
||||
loop_state: Optional[Dict[str, Union[str, int]]] = None,
|
||||
memory=None,
|
||||
quality_check=True
|
||||
quality_check=True,
|
||||
input_file: Optional[str] = None
|
||||
):
|
||||
# Add check if memory config is provided
|
||||
if memory is not None or (config and config.get('memory_config')):
|
||||
try:
|
||||
from ..memory.memory import Memory
|
||||
MEMORY_AVAILABLE = True
|
||||
except ImportError:
|
||||
raise ImportError(
|
||||
"Memory features requested in Task but memory dependencies not installed. "
|
||||
"Please install with: pip install \"praisonaiagents[memory]\""
|
||||
)
|
||||
|
||||
self.input_file = input_file
|
||||
self.id = str(uuid.uuid4()) if id is None else str(id)
|
||||
self.name = name
|
||||
self.description = description
|
||||
@@ -83,6 +96,47 @@ 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}')"
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
||||
|
||||
[project]
|
||||
name = "praisonaiagents"
|
||||
version = "0.0.41"
|
||||
version = "0.0.49"
|
||||
description = "Praison AI agents for completing complex tasks with Self Reflection Agents"
|
||||
authors = [
|
||||
{ name="Mervin Praison" }
|
||||
@@ -27,8 +27,15 @@ knowledge = [
|
||||
"chonkie"
|
||||
]
|
||||
|
||||
# Add LLM dependencies
|
||||
llm = [
|
||||
"litellm>=1.50.0",
|
||||
"pydantic>=2.4.2"
|
||||
]
|
||||
|
||||
# Combined features
|
||||
all = [
|
||||
"praisonaiagents[memory]",
|
||||
"praisonaiagents[knowledge]"
|
||||
"praisonaiagents[knowledge]",
|
||||
"praisonaiagents[llm]"
|
||||
]
|
||||
@@ -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,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.
|
Generated
+516
-4
@@ -6,6 +6,89 @@ resolution-markers = [
|
||||
"python_full_version < '3.12'",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "aiohappyeyeballs"
|
||||
version = "2.4.4"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/7f/55/e4373e888fdacb15563ef6fa9fa8c8252476ea071e96fb46defac9f18bf2/aiohappyeyeballs-2.4.4.tar.gz", hash = "sha256:5fdd7d87889c63183afc18ce9271f9b0a7d32c2303e394468dd45d514a757745", size = 21977 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/b9/74/fbb6559de3607b3300b9be3cc64e97548d55678e44623db17820dbd20002/aiohappyeyeballs-2.4.4-py3-none-any.whl", hash = "sha256:a980909d50efcd44795c4afeca523296716d50cd756ddca6af8c65b996e27de8", size = 14756 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "aiohttp"
|
||||
version = "3.11.11"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "aiohappyeyeballs" },
|
||||
{ name = "aiosignal" },
|
||||
{ name = "attrs" },
|
||||
{ name = "frozenlist" },
|
||||
{ name = "multidict" },
|
||||
{ name = "propcache" },
|
||||
{ name = "yarl" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/fe/ed/f26db39d29cd3cb2f5a3374304c713fe5ab5a0e4c8ee25a0c45cc6adf844/aiohttp-3.11.11.tar.gz", hash = "sha256:bb49c7f1e6ebf3821a42d81d494f538107610c3a705987f53068546b0e90303e", size = 7669618 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/34/ae/e8806a9f054e15f1d18b04db75c23ec38ec954a10c0a68d3bd275d7e8be3/aiohttp-3.11.11-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:ba74ec819177af1ef7f59063c6d35a214a8fde6f987f7661f4f0eecc468a8f76", size = 708624 },
|
||||
{ url = "https://files.pythonhosted.org/packages/c7/e0/313ef1a333fb4d58d0c55a6acb3cd772f5d7756604b455181049e222c020/aiohttp-3.11.11-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:4af57160800b7a815f3fe0eba9b46bf28aafc195555f1824555fa2cfab6c1538", size = 468507 },
|
||||
{ url = "https://files.pythonhosted.org/packages/a9/60/03455476bf1f467e5b4a32a465c450548b2ce724eec39d69f737191f936a/aiohttp-3.11.11-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ffa336210cf9cd8ed117011085817d00abe4c08f99968deef0013ea283547204", size = 455571 },
|
||||
{ url = "https://files.pythonhosted.org/packages/be/f9/469588603bd75bf02c8ffb8c8a0d4b217eed446b49d4a767684685aa33fd/aiohttp-3.11.11-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:81b8fe282183e4a3c7a1b72f5ade1094ed1c6345a8f153506d114af5bf8accd9", size = 1685694 },
|
||||
{ url = "https://files.pythonhosted.org/packages/88/b9/1b7fa43faf6c8616fa94c568dc1309ffee2b6b68b04ac268e5d64b738688/aiohttp-3.11.11-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3af41686ccec6a0f2bdc66686dc0f403c41ac2089f80e2214a0f82d001052c03", size = 1743660 },
|
||||
{ url = "https://files.pythonhosted.org/packages/2a/8b/0248d19dbb16b67222e75f6aecedd014656225733157e5afaf6a6a07e2e8/aiohttp-3.11.11-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:70d1f9dde0e5dd9e292a6d4d00058737052b01f3532f69c0c65818dac26dc287", size = 1785421 },
|
||||
{ url = "https://files.pythonhosted.org/packages/c4/11/f478e071815a46ca0a5ae974651ff0c7a35898c55063305a896e58aa1247/aiohttp-3.11.11-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:249cc6912405917344192b9f9ea5cd5b139d49e0d2f5c7f70bdfaf6b4dbf3a2e", size = 1675145 },
|
||||
{ url = "https://files.pythonhosted.org/packages/26/5d/284d182fecbb5075ae10153ff7374f57314c93a8681666600e3a9e09c505/aiohttp-3.11.11-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0eb98d90b6690827dcc84c246811feeb4e1eea683c0eac6caed7549be9c84665", size = 1619804 },
|
||||
{ url = "https://files.pythonhosted.org/packages/1b/78/980064c2ad685c64ce0e8aeeb7ef1e53f43c5b005edcd7d32e60809c4992/aiohttp-3.11.11-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:ec82bf1fda6cecce7f7b915f9196601a1bd1a3079796b76d16ae4cce6d0ef89b", size = 1654007 },
|
||||
{ url = "https://files.pythonhosted.org/packages/21/8d/9e658d63b1438ad42b96f94da227f2e2c1d5c6001c9e8ffcc0bfb22e9105/aiohttp-3.11.11-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:9fd46ce0845cfe28f108888b3ab17abff84ff695e01e73657eec3f96d72eef34", size = 1650022 },
|
||||
{ url = "https://files.pythonhosted.org/packages/85/fd/a032bf7f2755c2df4f87f9effa34ccc1ef5cea465377dbaeef93bb56bbd6/aiohttp-3.11.11-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:bd176afcf8f5d2aed50c3647d4925d0db0579d96f75a31e77cbaf67d8a87742d", size = 1732899 },
|
||||
{ url = "https://files.pythonhosted.org/packages/c5/0c/c2b85fde167dd440c7ba50af2aac20b5a5666392b174df54c00f888c5a75/aiohttp-3.11.11-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:ec2aa89305006fba9ffb98970db6c8221541be7bee4c1d027421d6f6df7d1ce2", size = 1755142 },
|
||||
{ url = "https://files.pythonhosted.org/packages/bc/78/91ae1a3b3b3bed8b893c5d69c07023e151b1c95d79544ad04cf68f596c2f/aiohttp-3.11.11-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:92cde43018a2e17d48bb09c79e4d4cb0e236de5063ce897a5e40ac7cb4878773", size = 1692736 },
|
||||
{ url = "https://files.pythonhosted.org/packages/77/89/a7ef9c4b4cdb546fcc650ca7f7395aaffbd267f0e1f648a436bec33c9b95/aiohttp-3.11.11-cp311-cp311-win32.whl", hash = "sha256:aba807f9569455cba566882c8938f1a549f205ee43c27b126e5450dc9f83cc62", size = 416418 },
|
||||
{ url = "https://files.pythonhosted.org/packages/fc/db/2192489a8a51b52e06627506f8ac8df69ee221de88ab9bdea77aa793aa6a/aiohttp-3.11.11-cp311-cp311-win_amd64.whl", hash = "sha256:ae545f31489548c87b0cced5755cfe5a5308d00407000e72c4fa30b19c3220ac", size = 442509 },
|
||||
{ url = "https://files.pythonhosted.org/packages/69/cf/4bda538c502f9738d6b95ada11603c05ec260807246e15e869fc3ec5de97/aiohttp-3.11.11-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:e595c591a48bbc295ebf47cb91aebf9bd32f3ff76749ecf282ea7f9f6bb73886", size = 704666 },
|
||||
{ url = "https://files.pythonhosted.org/packages/46/7b/87fcef2cad2fad420ca77bef981e815df6904047d0a1bd6aeded1b0d1d66/aiohttp-3.11.11-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:3ea1b59dc06396b0b424740a10a0a63974c725b1c64736ff788a3689d36c02d2", size = 464057 },
|
||||
{ url = "https://files.pythonhosted.org/packages/5a/a6/789e1f17a1b6f4a38939fbc39d29e1d960d5f89f73d0629a939410171bc0/aiohttp-3.11.11-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8811f3f098a78ffa16e0ea36dffd577eb031aea797cbdba81be039a4169e242c", size = 455996 },
|
||||
{ url = "https://files.pythonhosted.org/packages/b7/dd/485061fbfef33165ce7320db36e530cd7116ee1098e9c3774d15a732b3fd/aiohttp-3.11.11-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bd7227b87a355ce1f4bf83bfae4399b1f5bb42e0259cb9405824bd03d2f4336a", size = 1682367 },
|
||||
{ url = "https://files.pythonhosted.org/packages/e9/d7/9ec5b3ea9ae215c311d88b2093e8da17e67b8856673e4166c994e117ee3e/aiohttp-3.11.11-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d40f9da8cabbf295d3a9dae1295c69975b86d941bc20f0a087f0477fa0a66231", size = 1736989 },
|
||||
{ url = "https://files.pythonhosted.org/packages/d6/fb/ea94927f7bfe1d86178c9d3e0a8c54f651a0a655214cce930b3c679b8f64/aiohttp-3.11.11-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ffb3dc385f6bb1568aa974fe65da84723210e5d9707e360e9ecb51f59406cd2e", size = 1793265 },
|
||||
{ url = "https://files.pythonhosted.org/packages/40/7f/6de218084f9b653026bd7063cd8045123a7ba90c25176465f266976d8c82/aiohttp-3.11.11-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a8f5f7515f3552d899c61202d99dcb17d6e3b0de777900405611cd747cecd1b8", size = 1691841 },
|
||||
{ url = "https://files.pythonhosted.org/packages/77/e2/992f43d87831cbddb6b09c57ab55499332f60ad6fdbf438ff4419c2925fc/aiohttp-3.11.11-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3499c7ffbfd9c6a3d8d6a2b01c26639da7e43d47c7b4f788016226b1e711caa8", size = 1619317 },
|
||||
{ url = "https://files.pythonhosted.org/packages/96/74/879b23cdd816db4133325a201287c95bef4ce669acde37f8f1b8669e1755/aiohttp-3.11.11-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:8e2bf8029dbf0810c7bfbc3e594b51c4cc9101fbffb583a3923aea184724203c", size = 1641416 },
|
||||
{ url = "https://files.pythonhosted.org/packages/30/98/b123f6b15d87c54e58fd7ae3558ff594f898d7f30a90899718f3215ad328/aiohttp-3.11.11-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:b6212a60e5c482ef90f2d788835387070a88d52cf6241d3916733c9176d39eab", size = 1646514 },
|
||||
{ url = "https://files.pythonhosted.org/packages/d7/38/257fda3dc99d6978ab943141d5165ec74fd4b4164baa15e9c66fa21da86b/aiohttp-3.11.11-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:d119fafe7b634dbfa25a8c597718e69a930e4847f0b88e172744be24515140da", size = 1702095 },
|
||||
{ url = "https://files.pythonhosted.org/packages/0c/f4/ddab089053f9fb96654df5505c0a69bde093214b3c3454f6bfdb1845f558/aiohttp-3.11.11-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:6fba278063559acc730abf49845d0e9a9e1ba74f85f0ee6efd5803f08b285853", size = 1734611 },
|
||||
{ url = "https://files.pythonhosted.org/packages/c3/d6/f30b2bc520c38c8aa4657ed953186e535ae84abe55c08d0f70acd72ff577/aiohttp-3.11.11-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:92fc484e34b733704ad77210c7957679c5c3877bd1e6b6d74b185e9320cc716e", size = 1694576 },
|
||||
{ url = "https://files.pythonhosted.org/packages/bc/97/b0a88c3f4c6d0020b34045ee6d954058abc870814f6e310c4c9b74254116/aiohttp-3.11.11-cp312-cp312-win32.whl", hash = "sha256:9f5b3c1ed63c8fa937a920b6c1bec78b74ee09593b3f5b979ab2ae5ef60d7600", size = 411363 },
|
||||
{ url = "https://files.pythonhosted.org/packages/7f/23/cc36d9c398980acaeeb443100f0216f50a7cfe20c67a9fd0a2f1a5a846de/aiohttp-3.11.11-cp312-cp312-win_amd64.whl", hash = "sha256:1e69966ea6ef0c14ee53ef7a3d68b564cc408121ea56c0caa2dc918c1b2f553d", size = 437666 },
|
||||
{ url = "https://files.pythonhosted.org/packages/49/d1/d8af164f400bad432b63e1ac857d74a09311a8334b0481f2f64b158b50eb/aiohttp-3.11.11-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:541d823548ab69d13d23730a06f97460f4238ad2e5ed966aaf850d7c369782d9", size = 697982 },
|
||||
{ url = "https://files.pythonhosted.org/packages/92/d1/faad3bf9fa4bfd26b95c69fc2e98937d52b1ff44f7e28131855a98d23a17/aiohttp-3.11.11-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:929f3ed33743a49ab127c58c3e0a827de0664bfcda566108989a14068f820194", size = 460662 },
|
||||
{ url = "https://files.pythonhosted.org/packages/db/61/0d71cc66d63909dabc4590f74eba71f91873a77ea52424401c2498d47536/aiohttp-3.11.11-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:0882c2820fd0132240edbb4a51eb8ceb6eef8181db9ad5291ab3332e0d71df5f", size = 452950 },
|
||||
{ url = "https://files.pythonhosted.org/packages/07/db/6d04bc7fd92784900704e16b745484ef45b77bd04e25f58f6febaadf7983/aiohttp-3.11.11-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b63de12e44935d5aca7ed7ed98a255a11e5cb47f83a9fded7a5e41c40277d104", size = 1665178 },
|
||||
{ url = "https://files.pythonhosted.org/packages/54/5c/e95ade9ae29f375411884d9fd98e50535bf9fe316c9feb0f30cd2ac8f508/aiohttp-3.11.11-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:aa54f8ef31d23c506910c21163f22b124facb573bff73930735cf9fe38bf7dff", size = 1717939 },
|
||||
{ url = "https://files.pythonhosted.org/packages/6f/1c/1e7d5c5daea9e409ed70f7986001b8c9e3a49a50b28404498d30860edab6/aiohttp-3.11.11-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a344d5dc18074e3872777b62f5f7d584ae4344cd6006c17ba12103759d407af3", size = 1775125 },
|
||||
{ url = "https://files.pythonhosted.org/packages/5d/66/890987e44f7d2f33a130e37e01a164168e6aff06fce15217b6eaf14df4f6/aiohttp-3.11.11-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0b7fb429ab1aafa1f48578eb315ca45bd46e9c37de11fe45c7f5f4138091e2f1", size = 1677176 },
|
||||
{ url = "https://files.pythonhosted.org/packages/8f/dc/e2ba57d7a52df6cdf1072fd5fa9c6301a68e1cd67415f189805d3eeb031d/aiohttp-3.11.11-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c341c7d868750e31961d6d8e60ff040fb9d3d3a46d77fd85e1ab8e76c3e9a5c4", size = 1603192 },
|
||||
{ url = "https://files.pythonhosted.org/packages/6c/9e/8d08a57de79ca3a358da449405555e668f2c8871a7777ecd2f0e3912c272/aiohttp-3.11.11-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:ed9ee95614a71e87f1a70bc81603f6c6760128b140bc4030abe6abaa988f1c3d", size = 1618296 },
|
||||
{ url = "https://files.pythonhosted.org/packages/56/51/89822e3ec72db352c32e7fc1c690370e24e231837d9abd056490f3a49886/aiohttp-3.11.11-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:de8d38f1c2810fa2a4f1d995a2e9c70bb8737b18da04ac2afbf3971f65781d87", size = 1616524 },
|
||||
{ url = "https://files.pythonhosted.org/packages/2c/fa/e2e6d9398f462ffaa095e84717c1732916a57f1814502929ed67dd7568ef/aiohttp-3.11.11-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:a9b7371665d4f00deb8f32208c7c5e652059b0fda41cf6dbcac6114a041f1cc2", size = 1685471 },
|
||||
{ url = "https://files.pythonhosted.org/packages/ae/5f/6bb976e619ca28a052e2c0ca7b0251ccd893f93d7c24a96abea38e332bf6/aiohttp-3.11.11-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:620598717fce1b3bd14dd09947ea53e1ad510317c85dda2c9c65b622edc96b12", size = 1715312 },
|
||||
{ url = "https://files.pythonhosted.org/packages/79/c1/756a7e65aa087c7fac724d6c4c038f2faaa2a42fe56dbc1dd62a33ca7213/aiohttp-3.11.11-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:bf8d9bfee991d8acc72d060d53860f356e07a50f0e0d09a8dfedea1c554dd0d5", size = 1672783 },
|
||||
{ url = "https://files.pythonhosted.org/packages/73/ba/a6190ebb02176c7f75e6308da31f5d49f6477b651a3dcfaaaca865a298e2/aiohttp-3.11.11-cp313-cp313-win32.whl", hash = "sha256:9d73ee3725b7a737ad86c2eac5c57a4a97793d9f442599bea5ec67ac9f4bdc3d", size = 410229 },
|
||||
{ url = "https://files.pythonhosted.org/packages/b8/62/c9fa5bafe03186a0e4699150a7fed9b1e73240996d0d2f0e5f70f3fdf471/aiohttp-3.11.11-cp313-cp313-win_amd64.whl", hash = "sha256:c7a06301c2fb096bdb0bd25fe2011531c1453b9f2c163c8031600ec73af1cc99", size = 436081 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "aiosignal"
|
||||
version = "1.3.2"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "frozenlist" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/ba/b5/6d55e80f6d8a08ce22b982eafa278d823b541c925f11ee774b0b9c43473d/aiosignal-1.3.2.tar.gz", hash = "sha256:a8c255c66fafb1e499c9351d0bf32ff2d8a0321595ebac3b93713656d2436f54", size = 19424 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/ec/6a/bc7e17a3e87a2985d3e8f4da4cd0f481060eb78fb08596c42be62c90a4d9/aiosignal-1.3.2-py2.py3-none-any.whl", hash = "sha256:45cde58e409a301715980c2b01d0c28bdde3770d8290b5eb2173759d9acb31a5", size = 7597 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "annotated-types"
|
||||
version = "0.7.0"
|
||||
@@ -38,6 +121,15 @@ wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/39/e3/893e8757be2612e6c266d9bb58ad2e3651524b5b40cf56761e985a28b13e/asgiref-3.8.1-py3-none-any.whl", hash = "sha256:3e1e3ecc849832fe52ccf2cb6686b7a55f82bb1d6aee72a58826471390335e47", size = 23828 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "attrs"
|
||||
version = "24.3.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/48/c8/6260f8ccc11f0917360fc0da435c5c9c7504e3db174d5a12a1494887b045/attrs-24.3.0.tar.gz", hash = "sha256:8f5c07333d543103541ba7be0e2ce16eeee8130cb0b3f9238ab904ce1e85baff", size = 805984 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/89/aa/ab0f7891a01eeb2d2e338ae8fecbe57fcebea1a24dbb64d45801bfab481d/attrs-24.3.0-py3-none-any.whl", hash = "sha256:ac96cd038792094f438ad1f6ff80837353805ac950cd2aa0e0625ef19850c308", size = 63397 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "audioop-lts"
|
||||
version = "0.2.1"
|
||||
@@ -492,6 +584,60 @@ wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/fb/b4/31c461eef98b96b8ab736d97274548eaf2b2e349bf09e4de3902f7d53084/flatbuffers-24.12.23-py2.py3-none-any.whl", hash = "sha256:c418e0d48890f4142b92fd3e343e73a48f194e1f80075ddcc5793779b3585444", size = 30962 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "frozenlist"
|
||||
version = "1.5.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/8f/ed/0f4cec13a93c02c47ec32d81d11c0c1efbadf4a471e3f3ce7cad366cbbd3/frozenlist-1.5.0.tar.gz", hash = "sha256:81d5af29e61b9c8348e876d442253723928dce6433e0e76cd925cd83f1b4b817", size = 39930 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/79/43/0bed28bf5eb1c9e4301003b74453b8e7aa85fb293b31dde352aac528dafc/frozenlist-1.5.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:fd74520371c3c4175142d02a976aee0b4cb4a7cc912a60586ffd8d5929979b30", size = 94987 },
|
||||
{ url = "https://files.pythonhosted.org/packages/bb/bf/b74e38f09a246e8abbe1e90eb65787ed745ccab6eaa58b9c9308e052323d/frozenlist-1.5.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:2f3f7a0fbc219fb4455264cae4d9f01ad41ae6ee8524500f381de64ffaa077d5", size = 54584 },
|
||||
{ url = "https://files.pythonhosted.org/packages/2c/31/ab01375682f14f7613a1ade30149f684c84f9b8823a4391ed950c8285656/frozenlist-1.5.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f47c9c9028f55a04ac254346e92977bf0f166c483c74b4232bee19a6697e4778", size = 52499 },
|
||||
{ url = "https://files.pythonhosted.org/packages/98/a8/d0ac0b9276e1404f58fec3ab6e90a4f76b778a49373ccaf6a563f100dfbc/frozenlist-1.5.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0996c66760924da6e88922756d99b47512a71cfd45215f3570bf1e0b694c206a", size = 276357 },
|
||||
{ url = "https://files.pythonhosted.org/packages/ad/c9/c7761084fa822f07dac38ac29f841d4587570dd211e2262544aa0b791d21/frozenlist-1.5.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a2fe128eb4edeabe11896cb6af88fca5346059f6c8d807e3b910069f39157869", size = 287516 },
|
||||
{ url = "https://files.pythonhosted.org/packages/a1/ff/cd7479e703c39df7bdab431798cef89dc75010d8aa0ca2514c5b9321db27/frozenlist-1.5.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1a8ea951bbb6cacd492e3948b8da8c502a3f814f5d20935aae74b5df2b19cf3d", size = 283131 },
|
||||
{ url = "https://files.pythonhosted.org/packages/59/a0/370941beb47d237eca4fbf27e4e91389fd68699e6f4b0ebcc95da463835b/frozenlist-1.5.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:de537c11e4aa01d37db0d403b57bd6f0546e71a82347a97c6a9f0dcc532b3a45", size = 261320 },
|
||||
{ url = "https://files.pythonhosted.org/packages/b8/5f/c10123e8d64867bc9b4f2f510a32042a306ff5fcd7e2e09e5ae5100ee333/frozenlist-1.5.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9c2623347b933fcb9095841f1cc5d4ff0b278addd743e0e966cb3d460278840d", size = 274877 },
|
||||
{ url = "https://files.pythonhosted.org/packages/fa/79/38c505601ae29d4348f21706c5d89755ceded02a745016ba2f58bd5f1ea6/frozenlist-1.5.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:cee6798eaf8b1416ef6909b06f7dc04b60755206bddc599f52232606e18179d3", size = 269592 },
|
||||
{ url = "https://files.pythonhosted.org/packages/19/e2/39f3a53191b8204ba9f0bb574b926b73dd2efba2a2b9d2d730517e8f7622/frozenlist-1.5.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:f5f9da7f5dbc00a604fe74aa02ae7c98bcede8a3b8b9666f9f86fc13993bc71a", size = 265934 },
|
||||
{ url = "https://files.pythonhosted.org/packages/d5/c9/3075eb7f7f3a91f1a6b00284af4de0a65a9ae47084930916f5528144c9dd/frozenlist-1.5.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:90646abbc7a5d5c7c19461d2e3eeb76eb0b204919e6ece342feb6032c9325ae9", size = 283859 },
|
||||
{ url = "https://files.pythonhosted.org/packages/05/f5/549f44d314c29408b962fa2b0e69a1a67c59379fb143b92a0a065ffd1f0f/frozenlist-1.5.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:bdac3c7d9b705d253b2ce370fde941836a5f8b3c5c2b8fd70940a3ea3af7f4f2", size = 287560 },
|
||||
{ url = "https://files.pythonhosted.org/packages/9d/f8/cb09b3c24a3eac02c4c07a9558e11e9e244fb02bf62c85ac2106d1eb0c0b/frozenlist-1.5.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:03d33c2ddbc1816237a67f66336616416e2bbb6beb306e5f890f2eb22b959cdf", size = 277150 },
|
||||
{ url = "https://files.pythonhosted.org/packages/37/48/38c2db3f54d1501e692d6fe058f45b6ad1b358d82cd19436efab80cfc965/frozenlist-1.5.0-cp311-cp311-win32.whl", hash = "sha256:237f6b23ee0f44066219dae14c70ae38a63f0440ce6750f868ee08775073f942", size = 45244 },
|
||||
{ url = "https://files.pythonhosted.org/packages/ca/8c/2ddffeb8b60a4bce3b196c32fcc30d8830d4615e7b492ec2071da801b8ad/frozenlist-1.5.0-cp311-cp311-win_amd64.whl", hash = "sha256:0cc974cc93d32c42e7b0f6cf242a6bd941c57c61b618e78b6c0a96cb72788c1d", size = 51634 },
|
||||
{ url = "https://files.pythonhosted.org/packages/79/73/fa6d1a96ab7fd6e6d1c3500700963eab46813847f01ef0ccbaa726181dd5/frozenlist-1.5.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:31115ba75889723431aa9a4e77d5f398f5cf976eea3bdf61749731f62d4a4a21", size = 94026 },
|
||||
{ url = "https://files.pythonhosted.org/packages/ab/04/ea8bf62c8868b8eada363f20ff1b647cf2e93377a7b284d36062d21d81d1/frozenlist-1.5.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:7437601c4d89d070eac8323f121fcf25f88674627505334654fd027b091db09d", size = 54150 },
|
||||
{ url = "https://files.pythonhosted.org/packages/d0/9a/8e479b482a6f2070b26bda572c5e6889bb3ba48977e81beea35b5ae13ece/frozenlist-1.5.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:7948140d9f8ece1745be806f2bfdf390127cf1a763b925c4a805c603df5e697e", size = 51927 },
|
||||
{ url = "https://files.pythonhosted.org/packages/e3/12/2aad87deb08a4e7ccfb33600871bbe8f0e08cb6d8224371387f3303654d7/frozenlist-1.5.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:feeb64bc9bcc6b45c6311c9e9b99406660a9c05ca8a5b30d14a78555088b0b3a", size = 282647 },
|
||||
{ url = "https://files.pythonhosted.org/packages/77/f2/07f06b05d8a427ea0060a9cef6e63405ea9e0d761846b95ef3fb3be57111/frozenlist-1.5.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:683173d371daad49cffb8309779e886e59c2f369430ad28fe715f66d08d4ab1a", size = 289052 },
|
||||
{ url = "https://files.pythonhosted.org/packages/bd/9f/8bf45a2f1cd4aa401acd271b077989c9267ae8463e7c8b1eb0d3f561b65e/frozenlist-1.5.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7d57d8f702221405a9d9b40f9da8ac2e4a1a8b5285aac6100f3393675f0a85ee", size = 291719 },
|
||||
{ url = "https://files.pythonhosted.org/packages/41/d1/1f20fd05a6c42d3868709b7604c9f15538a29e4f734c694c6bcfc3d3b935/frozenlist-1.5.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:30c72000fbcc35b129cb09956836c7d7abf78ab5416595e4857d1cae8d6251a6", size = 267433 },
|
||||
{ url = "https://files.pythonhosted.org/packages/af/f2/64b73a9bb86f5a89fb55450e97cd5c1f84a862d4ff90d9fd1a73ab0f64a5/frozenlist-1.5.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:000a77d6034fbad9b6bb880f7ec073027908f1b40254b5d6f26210d2dab1240e", size = 283591 },
|
||||
{ url = "https://files.pythonhosted.org/packages/29/e2/ffbb1fae55a791fd6c2938dd9ea779509c977435ba3940b9f2e8dc9d5316/frozenlist-1.5.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:5d7f5a50342475962eb18b740f3beecc685a15b52c91f7d975257e13e029eca9", size = 273249 },
|
||||
{ url = "https://files.pythonhosted.org/packages/2e/6e/008136a30798bb63618a114b9321b5971172a5abddff44a100c7edc5ad4f/frozenlist-1.5.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:87f724d055eb4785d9be84e9ebf0f24e392ddfad00b3fe036e43f489fafc9039", size = 271075 },
|
||||
{ url = "https://files.pythonhosted.org/packages/ae/f0/4e71e54a026b06724cec9b6c54f0b13a4e9e298cc8db0f82ec70e151f5ce/frozenlist-1.5.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:6e9080bb2fb195a046e5177f10d9d82b8a204c0736a97a153c2466127de87784", size = 285398 },
|
||||
{ url = "https://files.pythonhosted.org/packages/4d/36/70ec246851478b1c0b59f11ef8ade9c482ff447c1363c2bd5fad45098b12/frozenlist-1.5.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:9b93d7aaa36c966fa42efcaf716e6b3900438632a626fb09c049f6a2f09fc631", size = 294445 },
|
||||
{ url = "https://files.pythonhosted.org/packages/37/e0/47f87544055b3349b633a03c4d94b405956cf2437f4ab46d0928b74b7526/frozenlist-1.5.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:52ef692a4bc60a6dd57f507429636c2af8b6046db8b31b18dac02cbc8f507f7f", size = 280569 },
|
||||
{ url = "https://files.pythonhosted.org/packages/f9/7c/490133c160fb6b84ed374c266f42800e33b50c3bbab1652764e6e1fc498a/frozenlist-1.5.0-cp312-cp312-win32.whl", hash = "sha256:29d94c256679247b33a3dc96cce0f93cbc69c23bf75ff715919332fdbb6a32b8", size = 44721 },
|
||||
{ url = "https://files.pythonhosted.org/packages/b1/56/4e45136ffc6bdbfa68c29ca56ef53783ef4c2fd395f7cbf99a2624aa9aaa/frozenlist-1.5.0-cp312-cp312-win_amd64.whl", hash = "sha256:8969190d709e7c48ea386db202d708eb94bdb29207a1f269bab1196ce0dcca1f", size = 51329 },
|
||||
{ url = "https://files.pythonhosted.org/packages/da/3b/915f0bca8a7ea04483622e84a9bd90033bab54bdf485479556c74fd5eaf5/frozenlist-1.5.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:7a1a048f9215c90973402e26c01d1cff8a209e1f1b53f72b95c13db61b00f953", size = 91538 },
|
||||
{ url = "https://files.pythonhosted.org/packages/c7/d1/a7c98aad7e44afe5306a2b068434a5830f1470675f0e715abb86eb15f15b/frozenlist-1.5.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:dd47a5181ce5fcb463b5d9e17ecfdb02b678cca31280639255ce9d0e5aa67af0", size = 52849 },
|
||||
{ url = "https://files.pythonhosted.org/packages/3a/c8/76f23bf9ab15d5f760eb48701909645f686f9c64fbb8982674c241fbef14/frozenlist-1.5.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:1431d60b36d15cda188ea222033eec8e0eab488f39a272461f2e6d9e1a8e63c2", size = 50583 },
|
||||
{ url = "https://files.pythonhosted.org/packages/1f/22/462a3dd093d11df623179d7754a3b3269de3b42de2808cddef50ee0f4f48/frozenlist-1.5.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6482a5851f5d72767fbd0e507e80737f9c8646ae7fd303def99bfe813f76cf7f", size = 265636 },
|
||||
{ url = "https://files.pythonhosted.org/packages/80/cf/e075e407fc2ae7328155a1cd7e22f932773c8073c1fc78016607d19cc3e5/frozenlist-1.5.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:44c49271a937625619e862baacbd037a7ef86dd1ee215afc298a417ff3270608", size = 270214 },
|
||||
{ url = "https://files.pythonhosted.org/packages/a1/58/0642d061d5de779f39c50cbb00df49682832923f3d2ebfb0fedf02d05f7f/frozenlist-1.5.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:12f78f98c2f1c2429d42e6a485f433722b0061d5c0b0139efa64f396efb5886b", size = 273905 },
|
||||
{ url = "https://files.pythonhosted.org/packages/ab/66/3fe0f5f8f2add5b4ab7aa4e199f767fd3b55da26e3ca4ce2cc36698e50c4/frozenlist-1.5.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ce3aa154c452d2467487765e3adc730a8c153af77ad84096bc19ce19a2400840", size = 250542 },
|
||||
{ url = "https://files.pythonhosted.org/packages/f6/b8/260791bde9198c87a465224e0e2bb62c4e716f5d198fc3a1dacc4895dbd1/frozenlist-1.5.0-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9b7dc0c4338e6b8b091e8faf0db3168a37101943e687f373dce00959583f7439", size = 267026 },
|
||||
{ url = "https://files.pythonhosted.org/packages/2e/a4/3d24f88c527f08f8d44ade24eaee83b2627793fa62fa07cbb7ff7a2f7d42/frozenlist-1.5.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:45e0896250900b5aa25180f9aec243e84e92ac84bd4a74d9ad4138ef3f5c97de", size = 257690 },
|
||||
{ url = "https://files.pythonhosted.org/packages/de/9a/d311d660420b2beeff3459b6626f2ab4fb236d07afbdac034a4371fe696e/frozenlist-1.5.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:561eb1c9579d495fddb6da8959fd2a1fca2c6d060d4113f5844b433fc02f2641", size = 253893 },
|
||||
{ url = "https://files.pythonhosted.org/packages/c6/23/e491aadc25b56eabd0f18c53bb19f3cdc6de30b2129ee0bc39cd387cd560/frozenlist-1.5.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:df6e2f325bfee1f49f81aaac97d2aa757c7646534a06f8f577ce184afe2f0a9e", size = 267006 },
|
||||
{ url = "https://files.pythonhosted.org/packages/08/c4/ab918ce636a35fb974d13d666dcbe03969592aeca6c3ab3835acff01f79c/frozenlist-1.5.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:140228863501b44b809fb39ec56b5d4071f4d0aa6d216c19cbb08b8c5a7eadb9", size = 276157 },
|
||||
{ url = "https://files.pythonhosted.org/packages/c0/29/3b7a0bbbbe5a34833ba26f686aabfe982924adbdcafdc294a7a129c31688/frozenlist-1.5.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:7707a25d6a77f5d27ea7dc7d1fc608aa0a478193823f88511ef5e6b8a48f9d03", size = 264642 },
|
||||
{ url = "https://files.pythonhosted.org/packages/ab/42/0595b3dbffc2e82d7fe658c12d5a5bafcd7516c6bf2d1d1feb5387caa9c1/frozenlist-1.5.0-cp313-cp313-win32.whl", hash = "sha256:31a9ac2b38ab9b5a8933b693db4939764ad3f299fcaa931a3e605bc3460e693c", size = 44914 },
|
||||
{ url = "https://files.pythonhosted.org/packages/17/c4/b7db1206a3fea44bf3b838ca61deb6f74424a8a5db1dd53ecb21da669be6/frozenlist-1.5.0-cp313-cp313-win_amd64.whl", hash = "sha256:11aabdd62b8b9c4b84081a3c246506d1cddd2dd93ff0ad53ede5defec7886b28", size = 51167 },
|
||||
{ url = "https://files.pythonhosted.org/packages/c6/c8/a5be5b7550c10858fcf9b0ea054baccab474da77d37f1e828ce043a3a5d4/frozenlist-1.5.0-py3-none-any.whl", hash = "sha256:d994863bba198a4a518b467bb971c56e1db3f180a25c6cf7bb1949c267f748c3", size = 11901 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fsspec"
|
||||
version = "2024.12.0"
|
||||
@@ -719,17 +865,18 @@ wheels = [
|
||||
|
||||
[[package]]
|
||||
name = "httpx"
|
||||
version = "0.28.1"
|
||||
version = "0.27.2"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "anyio" },
|
||||
{ name = "certifi" },
|
||||
{ name = "httpcore" },
|
||||
{ name = "idna" },
|
||||
{ name = "sniffio" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/b1/df/48c586a5fe32a0f01324ee087459e112ebb7224f646c0b5023f5e79e9956/httpx-0.28.1.tar.gz", hash = "sha256:75e98c5f16b0f35b567856f597f06ff2270a374470a5c2392242528e3e3e42fc", size = 141406 }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/78/82/08f8c936781f67d9e6b9eeb8a0c8b4e406136ea4c3d1f89a5db71d42e0e6/httpx-0.27.2.tar.gz", hash = "sha256:f7c2be1d2f3c3c3160d441802406b206c2b76f5947b11115e6df10c6c65e66c2", size = 144189 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl", hash = "sha256:d909fcccc110f8c7faf814ca82a9a4d816bc5a6dbfea25d6591d6985b8ba59ad", size = 73517 },
|
||||
{ url = "https://files.pythonhosted.org/packages/56/95/9377bcb415797e44274b51d46e3249eba641711cf3348050f76ee7b15ffc/httpx-0.27.2-py3-none-any.whl", hash = "sha256:7bb2708e112d8fdd7829cd4243970f0c223274051cb35ee80c03301ee29a3df0", size = 76395 },
|
||||
]
|
||||
|
||||
[package.optional-dependencies]
|
||||
@@ -806,6 +953,18 @@ wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/a4/ed/1f1afb2e9e7f38a545d628f864d562a5ae64fe6f7a10e28ffb9b185b4e89/importlib_resources-6.5.2-py3-none-any.whl", hash = "sha256:789cfdc3ed28c78b67a06acb8126751ced69a3d5f79c095a98298cd8a760ccec", size = 37461 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "jinja2"
|
||||
version = "3.1.5"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "markupsafe" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/af/92/b3130cbbf5591acf9ade8708c365f3238046ac7cb8ccba6e81abccb0ccff/jinja2-3.1.5.tar.gz", hash = "sha256:8fefff8dc3034e27bb80d67c671eb8a9bc424c0ef4c0826edbff304cceff43bb", size = 244674 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/bd/0f/2ba5fbcd631e3e88689309dbe978c5769e883e4b84ebfe7da30b43275c5a/jinja2-3.1.5-py3-none-any.whl", hash = "sha256:aba0f4dc9ed8013c424088f68a5c226f7d6097ed89b246d7749c2ec4175c6adb", size = 134596 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "jiter"
|
||||
version = "0.8.2"
|
||||
@@ -853,6 +1012,33 @@ wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/91/61/c80ef80ed8a0a21158e289ef70dac01e351d929a1c30cb0f49be60772547/jiter-0.8.2-cp313-cp313t-win_amd64.whl", hash = "sha256:3ac9f578c46f22405ff7f8b1f5848fb753cc4b8377fbec8470a7dc3997ca7566", size = 202374 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "jsonschema"
|
||||
version = "4.23.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "attrs" },
|
||||
{ name = "jsonschema-specifications" },
|
||||
{ name = "referencing" },
|
||||
{ name = "rpds-py" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/38/2e/03362ee4034a4c917f697890ccd4aec0800ccf9ded7f511971c75451deec/jsonschema-4.23.0.tar.gz", hash = "sha256:d71497fef26351a33265337fa77ffeb82423f3ea21283cd9467bb03999266bc4", size = 325778 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/69/4a/4f9dbeb84e8850557c02365a0eee0649abe5eb1d84af92a25731c6c0f922/jsonschema-4.23.0-py3-none-any.whl", hash = "sha256:fbadb6f8b144a8f8cf9f0b89ba94501d143e50411a1278633f56a7acf7fd5566", size = 88462 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "jsonschema-specifications"
|
||||
version = "2024.10.1"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "referencing" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/10/db/58f950c996c793472e336ff3655b13fbcf1e3b359dcf52dcf3ed3b52c352/jsonschema_specifications-2024.10.1.tar.gz", hash = "sha256:0f38b83639958ce1152d02a7f062902c41c8fd20d558b0c34344292d417ae272", size = 15561 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/d1/0f/8910b19ac0670a0f80ce1008e5e751c4a57e14d2c4c13a482aa6079fa9d6/jsonschema_specifications-2024.10.1-py3-none-any.whl", hash = "sha256:a09a0680616357d9a0ecf05c12ad234479f549239d0f5b55f3deea67475da9bf", size = 18459 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "kubernetes"
|
||||
version = "31.0.0"
|
||||
@@ -875,6 +1061,28 @@ wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/fb/a8/17f5e28cecdbd6d48127c22abdb794740803491f422a11905c4569d8e139/kubernetes-31.0.0-py2.py3-none-any.whl", hash = "sha256:bf141e2d380c8520eada8b351f4e319ffee9636328c137aa432bc486ca1200e1", size = 1857013 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "litellm"
|
||||
version = "1.59.1"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "aiohttp" },
|
||||
{ name = "click" },
|
||||
{ name = "httpx" },
|
||||
{ name = "importlib-metadata" },
|
||||
{ name = "jinja2" },
|
||||
{ name = "jsonschema" },
|
||||
{ name = "openai" },
|
||||
{ name = "pydantic" },
|
||||
{ name = "python-dotenv" },
|
||||
{ name = "tiktoken" },
|
||||
{ name = "tokenizers" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/92/98/80766e2820e140b4b03a4b3e997d25e522bc2ce1d3c79c98a7b856a84e1f/litellm-1.59.1.tar.gz", hash = "sha256:ca4fd7789cc493daa63fe0dd69e3351237708c48a9305ccbc685a1bcf9eecf98", size = 6374267 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/ff/3c/d2edad7c3cc85d83a4a6929c80ee258ae8875e2366366b9ab93eaf817cb3/litellm-1.59.1-py3-none-any.whl", hash = "sha256:69adf83f6942b9b62d3398cd8c1dc2e53b02e9b97bc5c45c427ed917629048e7", size = 6661803 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lxml"
|
||||
version = "5.3.0"
|
||||
@@ -998,6 +1206,54 @@ wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/8f/f1/b67a849dfbe3bc95fea6b7ba60ed47dbf5b5442131345e4c4f5d48c6216e/markitdown-0.0.1a3-py3-none-any.whl", hash = "sha256:6efcab2f05714675486dc2ddf912415734b1caa0343f73f75d852046f04e5f37", size = 16199 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "markupsafe"
|
||||
version = "3.0.2"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/b2/97/5d42485e71dfc078108a86d6de8fa46db44a1a9295e89c5d6d4a06e23a62/markupsafe-3.0.2.tar.gz", hash = "sha256:ee55d3edf80167e48ea11a923c7386f4669df67d7994554387f84e7d8b0a2bf0", size = 20537 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/6b/28/bbf83e3f76936960b850435576dd5e67034e200469571be53f69174a2dfd/MarkupSafe-3.0.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:9025b4018f3a1314059769c7bf15441064b2207cb3f065e6ea1e7359cb46db9d", size = 14353 },
|
||||
{ url = "https://files.pythonhosted.org/packages/6c/30/316d194b093cde57d448a4c3209f22e3046c5bb2fb0820b118292b334be7/MarkupSafe-3.0.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:93335ca3812df2f366e80509ae119189886b0f3c2b81325d39efdb84a1e2ae93", size = 12392 },
|
||||
{ url = "https://files.pythonhosted.org/packages/f2/96/9cdafba8445d3a53cae530aaf83c38ec64c4d5427d975c974084af5bc5d2/MarkupSafe-3.0.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2cb8438c3cbb25e220c2ab33bb226559e7afb3baec11c4f218ffa7308603c832", size = 23984 },
|
||||
{ url = "https://files.pythonhosted.org/packages/f1/a4/aefb044a2cd8d7334c8a47d3fb2c9f328ac48cb349468cc31c20b539305f/MarkupSafe-3.0.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a123e330ef0853c6e822384873bef7507557d8e4a082961e1defa947aa59ba84", size = 23120 },
|
||||
{ url = "https://files.pythonhosted.org/packages/8d/21/5e4851379f88f3fad1de30361db501300d4f07bcad047d3cb0449fc51f8c/MarkupSafe-3.0.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1e084f686b92e5b83186b07e8a17fc09e38fff551f3602b249881fec658d3eca", size = 23032 },
|
||||
{ url = "https://files.pythonhosted.org/packages/00/7b/e92c64e079b2d0d7ddf69899c98842f3f9a60a1ae72657c89ce2655c999d/MarkupSafe-3.0.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d8213e09c917a951de9d09ecee036d5c7d36cb6cb7dbaece4c71a60d79fb9798", size = 24057 },
|
||||
{ url = "https://files.pythonhosted.org/packages/f9/ac/46f960ca323037caa0a10662ef97d0a4728e890334fc156b9f9e52bcc4ca/MarkupSafe-3.0.2-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:5b02fb34468b6aaa40dfc198d813a641e3a63b98c2b05a16b9f80b7ec314185e", size = 23359 },
|
||||
{ url = "https://files.pythonhosted.org/packages/69/84/83439e16197337b8b14b6a5b9c2105fff81d42c2a7c5b58ac7b62ee2c3b1/MarkupSafe-3.0.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:0bff5e0ae4ef2e1ae4fdf2dfd5b76c75e5c2fa4132d05fc1b0dabcd20c7e28c4", size = 23306 },
|
||||
{ url = "https://files.pythonhosted.org/packages/9a/34/a15aa69f01e2181ed8d2b685c0d2f6655d5cca2c4db0ddea775e631918cd/MarkupSafe-3.0.2-cp311-cp311-win32.whl", hash = "sha256:6c89876f41da747c8d3677a2b540fb32ef5715f97b66eeb0c6b66f5e3ef6f59d", size = 15094 },
|
||||
{ url = "https://files.pythonhosted.org/packages/da/b8/3a3bd761922d416f3dc5d00bfbed11f66b1ab89a0c2b6e887240a30b0f6b/MarkupSafe-3.0.2-cp311-cp311-win_amd64.whl", hash = "sha256:70a87b411535ccad5ef2f1df5136506a10775d267e197e4cf531ced10537bd6b", size = 15521 },
|
||||
{ url = "https://files.pythonhosted.org/packages/22/09/d1f21434c97fc42f09d290cbb6350d44eb12f09cc62c9476effdb33a18aa/MarkupSafe-3.0.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:9778bd8ab0a994ebf6f84c2b949e65736d5575320a17ae8984a77fab08db94cf", size = 14274 },
|
||||
{ url = "https://files.pythonhosted.org/packages/6b/b0/18f76bba336fa5aecf79d45dcd6c806c280ec44538b3c13671d49099fdd0/MarkupSafe-3.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:846ade7b71e3536c4e56b386c2a47adf5741d2d8b94ec9dc3e92e5e1ee1e2225", size = 12348 },
|
||||
{ url = "https://files.pythonhosted.org/packages/e0/25/dd5c0f6ac1311e9b40f4af06c78efde0f3b5cbf02502f8ef9501294c425b/MarkupSafe-3.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1c99d261bd2d5f6b59325c92c73df481e05e57f19837bdca8413b9eac4bd8028", size = 24149 },
|
||||
{ url = "https://files.pythonhosted.org/packages/f3/f0/89e7aadfb3749d0f52234a0c8c7867877876e0a20b60e2188e9850794c17/MarkupSafe-3.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e17c96c14e19278594aa4841ec148115f9c7615a47382ecb6b82bd8fea3ab0c8", size = 23118 },
|
||||
{ url = "https://files.pythonhosted.org/packages/d5/da/f2eeb64c723f5e3777bc081da884b414671982008c47dcc1873d81f625b6/MarkupSafe-3.0.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:88416bd1e65dcea10bc7569faacb2c20ce071dd1f87539ca2ab364bf6231393c", size = 22993 },
|
||||
{ url = "https://files.pythonhosted.org/packages/da/0e/1f32af846df486dce7c227fe0f2398dc7e2e51d4a370508281f3c1c5cddc/MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:2181e67807fc2fa785d0592dc2d6206c019b9502410671cc905d132a92866557", size = 24178 },
|
||||
{ url = "https://files.pythonhosted.org/packages/c4/f6/bb3ca0532de8086cbff5f06d137064c8410d10779c4c127e0e47d17c0b71/MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:52305740fe773d09cffb16f8ed0427942901f00adedac82ec8b67752f58a1b22", size = 23319 },
|
||||
{ url = "https://files.pythonhosted.org/packages/a2/82/8be4c96ffee03c5b4a034e60a31294daf481e12c7c43ab8e34a1453ee48b/MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ad10d3ded218f1039f11a75f8091880239651b52e9bb592ca27de44eed242a48", size = 23352 },
|
||||
{ url = "https://files.pythonhosted.org/packages/51/ae/97827349d3fcffee7e184bdf7f41cd6b88d9919c80f0263ba7acd1bbcb18/MarkupSafe-3.0.2-cp312-cp312-win32.whl", hash = "sha256:0f4ca02bea9a23221c0182836703cbf8930c5e9454bacce27e767509fa286a30", size = 15097 },
|
||||
{ url = "https://files.pythonhosted.org/packages/c1/80/a61f99dc3a936413c3ee4e1eecac96c0da5ed07ad56fd975f1a9da5bc630/MarkupSafe-3.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:8e06879fc22a25ca47312fbe7c8264eb0b662f6db27cb2d3bbbc74b1df4b9b87", size = 15601 },
|
||||
{ url = "https://files.pythonhosted.org/packages/83/0e/67eb10a7ecc77a0c2bbe2b0235765b98d164d81600746914bebada795e97/MarkupSafe-3.0.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ba9527cdd4c926ed0760bc301f6728ef34d841f405abf9d4f959c478421e4efd", size = 14274 },
|
||||
{ url = "https://files.pythonhosted.org/packages/2b/6d/9409f3684d3335375d04e5f05744dfe7e9f120062c9857df4ab490a1031a/MarkupSafe-3.0.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f8b3d067f2e40fe93e1ccdd6b2e1d16c43140e76f02fb1319a05cf2b79d99430", size = 12352 },
|
||||
{ url = "https://files.pythonhosted.org/packages/d2/f5/6eadfcd3885ea85fe2a7c128315cc1bb7241e1987443d78c8fe712d03091/MarkupSafe-3.0.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:569511d3b58c8791ab4c2e1285575265991e6d8f8700c7be0e88f86cb0672094", size = 24122 },
|
||||
{ url = "https://files.pythonhosted.org/packages/0c/91/96cf928db8236f1bfab6ce15ad070dfdd02ed88261c2afafd4b43575e9e9/MarkupSafe-3.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:15ab75ef81add55874e7ab7055e9c397312385bd9ced94920f2802310c930396", size = 23085 },
|
||||
{ url = "https://files.pythonhosted.org/packages/c2/cf/c9d56af24d56ea04daae7ac0940232d31d5a8354f2b457c6d856b2057d69/MarkupSafe-3.0.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f3818cb119498c0678015754eba762e0d61e5b52d34c8b13d770f0719f7b1d79", size = 22978 },
|
||||
{ url = "https://files.pythonhosted.org/packages/2a/9f/8619835cd6a711d6272d62abb78c033bda638fdc54c4e7f4272cf1c0962b/MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:cdb82a876c47801bb54a690c5ae105a46b392ac6099881cdfb9f6e95e4014c6a", size = 24208 },
|
||||
{ url = "https://files.pythonhosted.org/packages/f9/bf/176950a1792b2cd2102b8ffeb5133e1ed984547b75db47c25a67d3359f77/MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:cabc348d87e913db6ab4aa100f01b08f481097838bdddf7c7a84b7575b7309ca", size = 23357 },
|
||||
{ url = "https://files.pythonhosted.org/packages/ce/4f/9a02c1d335caabe5c4efb90e1b6e8ee944aa245c1aaaab8e8a618987d816/MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:444dcda765c8a838eaae23112db52f1efaf750daddb2d9ca300bcae1039adc5c", size = 23344 },
|
||||
{ url = "https://files.pythonhosted.org/packages/ee/55/c271b57db36f748f0e04a759ace9f8f759ccf22b4960c270c78a394f58be/MarkupSafe-3.0.2-cp313-cp313-win32.whl", hash = "sha256:bcf3e58998965654fdaff38e58584d8937aa3096ab5354d493c77d1fdd66d7a1", size = 15101 },
|
||||
{ url = "https://files.pythonhosted.org/packages/29/88/07df22d2dd4df40aba9f3e402e6dc1b8ee86297dddbad4872bd5e7b0094f/MarkupSafe-3.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:e6a2a455bd412959b57a172ce6328d2dd1f01cb2135efda2e4576e8a23fa3b0f", size = 15603 },
|
||||
{ url = "https://files.pythonhosted.org/packages/62/6a/8b89d24db2d32d433dffcd6a8779159da109842434f1dd2f6e71f32f738c/MarkupSafe-3.0.2-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:b5a6b3ada725cea8a5e634536b1b01c30bcdcd7f9c6fff4151548d5bf6b3a36c", size = 14510 },
|
||||
{ url = "https://files.pythonhosted.org/packages/7a/06/a10f955f70a2e5a9bf78d11a161029d278eeacbd35ef806c3fd17b13060d/MarkupSafe-3.0.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:a904af0a6162c73e3edcb969eeeb53a63ceeb5d8cf642fade7d39e7963a22ddb", size = 12486 },
|
||||
{ url = "https://files.pythonhosted.org/packages/34/cf/65d4a571869a1a9078198ca28f39fba5fbb910f952f9dbc5220afff9f5e6/MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4aa4e5faecf353ed117801a068ebab7b7e09ffb6e1d5e412dc852e0da018126c", size = 25480 },
|
||||
{ url = "https://files.pythonhosted.org/packages/0c/e3/90e9651924c430b885468b56b3d597cabf6d72be4b24a0acd1fa0e12af67/MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c0ef13eaeee5b615fb07c9a7dadb38eac06a0608b41570d8ade51c56539e509d", size = 23914 },
|
||||
{ url = "https://files.pythonhosted.org/packages/66/8c/6c7cf61f95d63bb866db39085150df1f2a5bd3335298f14a66b48e92659c/MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d16a81a06776313e817c951135cf7340a3e91e8c1ff2fac444cfd75fffa04afe", size = 23796 },
|
||||
{ url = "https://files.pythonhosted.org/packages/bb/35/cbe9238ec3f47ac9a7c8b3df7a808e7cb50fe149dc7039f5f454b3fba218/MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:6381026f158fdb7c72a168278597a5e3a5222e83ea18f543112b2662a9b699c5", size = 25473 },
|
||||
{ url = "https://files.pythonhosted.org/packages/e6/32/7621a4382488aa283cc05e8984a9c219abad3bca087be9ec77e89939ded9/MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:3d79d162e7be8f996986c064d1c7c817f6df3a77fe3d6859f6f9e7be4b8c213a", size = 24114 },
|
||||
{ url = "https://files.pythonhosted.org/packages/0d/80/0985960e4b89922cb5a0bac0ed39c5b96cbc1a536a99f30e8c220a996ed9/MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:131a3c7689c85f5ad20f9f6fb1b866f402c445b220c19fe4308c0b147ccd2ad9", size = 24098 },
|
||||
{ url = "https://files.pythonhosted.org/packages/82/78/fedb03c7d5380df2427038ec8d973587e90561b2d90cd472ce9254cf348b/MarkupSafe-3.0.2-cp313-cp313t-win32.whl", hash = "sha256:ba8062ed2cf21c07a9e295d5b8a2a5ce678b913b45fdf68c32d95d6c1291e0b6", size = 15208 },
|
||||
{ url = "https://files.pythonhosted.org/packages/4f/65/6079a46068dfceaeabb5dcad6d674f5f5c61a6fa5673746f42a9f4c233b3/MarkupSafe-3.0.2-cp313-cp313t-win_amd64.whl", hash = "sha256:e444a31f8db13eb18ada366ab3cf45fd4b31e4db1236a4448f68778c1d1a5a2f", size = 15739 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "mdurl"
|
||||
version = "0.1.2"
|
||||
@@ -1098,6 +1354,60 @@ wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/43/e3/7d92a15f894aa0c9c4b49b8ee9ac9850d6e63b03c9c32c0367a13ae62209/mpmath-1.3.0-py3-none-any.whl", hash = "sha256:a0b2b9fe80bbcd81a6647ff13108738cfb482d481d826cc0e02f5b35e5c88d2c", size = 536198 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "multidict"
|
||||
version = "6.1.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/d6/be/504b89a5e9ca731cd47487e91c469064f8ae5af93b7259758dcfc2b9c848/multidict-6.1.0.tar.gz", hash = "sha256:22ae2ebf9b0c69d206c003e2f6a914ea33f0a932d4aa16f236afc049d9958f4a", size = 64002 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/93/13/df3505a46d0cd08428e4c8169a196131d1b0c4b515c3649829258843dde6/multidict-6.1.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:3efe2c2cb5763f2f1b275ad2bf7a287d3f7ebbef35648a9726e3b69284a4f3d6", size = 48570 },
|
||||
{ url = "https://files.pythonhosted.org/packages/f0/e1/a215908bfae1343cdb72f805366592bdd60487b4232d039c437fe8f5013d/multidict-6.1.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c7053d3b0353a8b9de430a4f4b4268ac9a4fb3481af37dfe49825bf45ca24156", size = 29316 },
|
||||
{ url = "https://files.pythonhosted.org/packages/70/0f/6dc70ddf5d442702ed74f298d69977f904960b82368532c88e854b79f72b/multidict-6.1.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:27e5fc84ccef8dfaabb09d82b7d179c7cf1a3fbc8a966f8274fcb4ab2eb4cadb", size = 29640 },
|
||||
{ url = "https://files.pythonhosted.org/packages/d8/6d/9c87b73a13d1cdea30b321ef4b3824449866bd7f7127eceed066ccb9b9ff/multidict-6.1.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0e2b90b43e696f25c62656389d32236e049568b39320e2735d51f08fd362761b", size = 131067 },
|
||||
{ url = "https://files.pythonhosted.org/packages/cc/1e/1b34154fef373371fd6c65125b3d42ff5f56c7ccc6bfff91b9b3c60ae9e0/multidict-6.1.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d83a047959d38a7ff552ff94be767b7fd79b831ad1cd9920662db05fec24fe72", size = 138507 },
|
||||
{ url = "https://files.pythonhosted.org/packages/fb/e0/0bc6b2bac6e461822b5f575eae85da6aae76d0e2a79b6665d6206b8e2e48/multidict-6.1.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d1a9dd711d0877a1ece3d2e4fea11a8e75741ca21954c919406b44e7cf971304", size = 133905 },
|
||||
{ url = "https://files.pythonhosted.org/packages/ba/af/73d13b918071ff9b2205fcf773d316e0f8fefb4ec65354bbcf0b10908cc6/multidict-6.1.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ec2abea24d98246b94913b76a125e855eb5c434f7c46546046372fe60f666351", size = 129004 },
|
||||
{ url = "https://files.pythonhosted.org/packages/74/21/23960627b00ed39643302d81bcda44c9444ebcdc04ee5bedd0757513f259/multidict-6.1.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4867cafcbc6585e4b678876c489b9273b13e9fff9f6d6d66add5e15d11d926cb", size = 121308 },
|
||||
{ url = "https://files.pythonhosted.org/packages/8b/5c/cf282263ffce4a596ed0bb2aa1a1dddfe1996d6a62d08842a8d4b33dca13/multidict-6.1.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:5b48204e8d955c47c55b72779802b219a39acc3ee3d0116d5080c388970b76e3", size = 132608 },
|
||||
{ url = "https://files.pythonhosted.org/packages/d7/3e/97e778c041c72063f42b290888daff008d3ab1427f5b09b714f5a8eff294/multidict-6.1.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:d8fff389528cad1618fb4b26b95550327495462cd745d879a8c7c2115248e399", size = 127029 },
|
||||
{ url = "https://files.pythonhosted.org/packages/47/ac/3efb7bfe2f3aefcf8d103e9a7162572f01936155ab2f7ebcc7c255a23212/multidict-6.1.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:a7a9541cd308eed5e30318430a9c74d2132e9a8cb46b901326272d780bf2d423", size = 137594 },
|
||||
{ url = "https://files.pythonhosted.org/packages/42/9b/6c6e9e8dc4f915fc90a9b7798c44a30773dea2995fdcb619870e705afe2b/multidict-6.1.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:da1758c76f50c39a2efd5e9859ce7d776317eb1dd34317c8152ac9251fc574a3", size = 134556 },
|
||||
{ url = "https://files.pythonhosted.org/packages/1d/10/8e881743b26aaf718379a14ac58572a240e8293a1c9d68e1418fb11c0f90/multidict-6.1.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:c943a53e9186688b45b323602298ab727d8865d8c9ee0b17f8d62d14b56f0753", size = 130993 },
|
||||
{ url = "https://files.pythonhosted.org/packages/45/84/3eb91b4b557442802d058a7579e864b329968c8d0ea57d907e7023c677f2/multidict-6.1.0-cp311-cp311-win32.whl", hash = "sha256:90f8717cb649eea3504091e640a1b8568faad18bd4b9fcd692853a04475a4b80", size = 26405 },
|
||||
{ url = "https://files.pythonhosted.org/packages/9f/0b/ad879847ecbf6d27e90a6eabb7eff6b62c129eefe617ea45eae7c1f0aead/multidict-6.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:82176036e65644a6cc5bd619f65f6f19781e8ec2e5330f51aa9ada7504cc1926", size = 28795 },
|
||||
{ url = "https://files.pythonhosted.org/packages/fd/16/92057c74ba3b96d5e211b553895cd6dc7cc4d1e43d9ab8fafc727681ef71/multidict-6.1.0-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:b04772ed465fa3cc947db808fa306d79b43e896beb677a56fb2347ca1a49c1fa", size = 48713 },
|
||||
{ url = "https://files.pythonhosted.org/packages/94/3d/37d1b8893ae79716179540b89fc6a0ee56b4a65fcc0d63535c6f5d96f217/multidict-6.1.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:6180c0ae073bddeb5a97a38c03f30c233e0a4d39cd86166251617d1bbd0af436", size = 29516 },
|
||||
{ url = "https://files.pythonhosted.org/packages/a2/12/adb6b3200c363062f805275b4c1e656be2b3681aada66c80129932ff0bae/multidict-6.1.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:071120490b47aa997cca00666923a83f02c7fbb44f71cf7f136df753f7fa8761", size = 29557 },
|
||||
{ url = "https://files.pythonhosted.org/packages/47/e9/604bb05e6e5bce1e6a5cf80a474e0f072e80d8ac105f1b994a53e0b28c42/multidict-6.1.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:50b3a2710631848991d0bf7de077502e8994c804bb805aeb2925a981de58ec2e", size = 130170 },
|
||||
{ url = "https://files.pythonhosted.org/packages/7e/13/9efa50801785eccbf7086b3c83b71a4fb501a4d43549c2f2f80b8787d69f/multidict-6.1.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b58c621844d55e71c1b7f7c498ce5aa6985d743a1a59034c57a905b3f153c1ef", size = 134836 },
|
||||
{ url = "https://files.pythonhosted.org/packages/bf/0f/93808b765192780d117814a6dfcc2e75de6dcc610009ad408b8814dca3ba/multidict-6.1.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:55b6d90641869892caa9ca42ff913f7ff1c5ece06474fbd32fb2cf6834726c95", size = 133475 },
|
||||
{ url = "https://files.pythonhosted.org/packages/d3/c8/529101d7176fe7dfe1d99604e48d69c5dfdcadb4f06561f465c8ef12b4df/multidict-6.1.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4b820514bfc0b98a30e3d85462084779900347e4d49267f747ff54060cc33925", size = 131049 },
|
||||
{ url = "https://files.pythonhosted.org/packages/ca/0c/fc85b439014d5a58063e19c3a158a889deec399d47b5269a0f3b6a2e28bc/multidict-6.1.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:10a9b09aba0c5b48c53761b7c720aaaf7cf236d5fe394cd399c7ba662d5f9966", size = 120370 },
|
||||
{ url = "https://files.pythonhosted.org/packages/db/46/d4416eb20176492d2258fbd47b4abe729ff3b6e9c829ea4236f93c865089/multidict-6.1.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:1e16bf3e5fc9f44632affb159d30a437bfe286ce9e02754759be5536b169b305", size = 125178 },
|
||||
{ url = "https://files.pythonhosted.org/packages/5b/46/73697ad7ec521df7de5531a32780bbfd908ded0643cbe457f981a701457c/multidict-6.1.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:76f364861c3bfc98cbbcbd402d83454ed9e01a5224bb3a28bf70002a230f73e2", size = 119567 },
|
||||
{ url = "https://files.pythonhosted.org/packages/cd/ed/51f060e2cb0e7635329fa6ff930aa5cffa17f4c7f5c6c3ddc3500708e2f2/multidict-6.1.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:820c661588bd01a0aa62a1283f20d2be4281b086f80dad9e955e690c75fb54a2", size = 129822 },
|
||||
{ url = "https://files.pythonhosted.org/packages/df/9e/ee7d1954b1331da3eddea0c4e08d9142da5f14b1321c7301f5014f49d492/multidict-6.1.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:0e5f362e895bc5b9e67fe6e4ded2492d8124bdf817827f33c5b46c2fe3ffaca6", size = 128656 },
|
||||
{ url = "https://files.pythonhosted.org/packages/77/00/8538f11e3356b5d95fa4b024aa566cde7a38aa7a5f08f4912b32a037c5dc/multidict-6.1.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:3ec660d19bbc671e3a6443325f07263be452c453ac9e512f5eb935e7d4ac28b3", size = 125360 },
|
||||
{ url = "https://files.pythonhosted.org/packages/be/05/5d334c1f2462d43fec2363cd00b1c44c93a78c3925d952e9a71caf662e96/multidict-6.1.0-cp312-cp312-win32.whl", hash = "sha256:58130ecf8f7b8112cdb841486404f1282b9c86ccb30d3519faf301b2e5659133", size = 26382 },
|
||||
{ url = "https://files.pythonhosted.org/packages/a3/bf/f332a13486b1ed0496d624bcc7e8357bb8053823e8cd4b9a18edc1d97e73/multidict-6.1.0-cp312-cp312-win_amd64.whl", hash = "sha256:188215fc0aafb8e03341995e7c4797860181562380f81ed0a87ff455b70bf1f1", size = 28529 },
|
||||
{ url = "https://files.pythonhosted.org/packages/22/67/1c7c0f39fe069aa4e5d794f323be24bf4d33d62d2a348acdb7991f8f30db/multidict-6.1.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:d569388c381b24671589335a3be6e1d45546c2988c2ebe30fdcada8457a31008", size = 48771 },
|
||||
{ url = "https://files.pythonhosted.org/packages/3c/25/c186ee7b212bdf0df2519eacfb1981a017bda34392c67542c274651daf23/multidict-6.1.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:052e10d2d37810b99cc170b785945421141bf7bb7d2f8799d431e7db229c385f", size = 29533 },
|
||||
{ url = "https://files.pythonhosted.org/packages/67/5e/04575fd837e0958e324ca035b339cea174554f6f641d3fb2b4f2e7ff44a2/multidict-6.1.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f90c822a402cb865e396a504f9fc8173ef34212a342d92e362ca498cad308e28", size = 29595 },
|
||||
{ url = "https://files.pythonhosted.org/packages/d3/b2/e56388f86663810c07cfe4a3c3d87227f3811eeb2d08450b9e5d19d78876/multidict-6.1.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b225d95519a5bf73860323e633a664b0d85ad3d5bede6d30d95b35d4dfe8805b", size = 130094 },
|
||||
{ url = "https://files.pythonhosted.org/packages/6c/ee/30ae9b4186a644d284543d55d491fbd4239b015d36b23fea43b4c94f7052/multidict-6.1.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:23bfd518810af7de1116313ebd9092cb9aa629beb12f6ed631ad53356ed6b86c", size = 134876 },
|
||||
{ url = "https://files.pythonhosted.org/packages/84/c7/70461c13ba8ce3c779503c70ec9d0345ae84de04521c1f45a04d5f48943d/multidict-6.1.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5c09fcfdccdd0b57867577b719c69e347a436b86cd83747f179dbf0cc0d4c1f3", size = 133500 },
|
||||
{ url = "https://files.pythonhosted.org/packages/4a/9f/002af221253f10f99959561123fae676148dd730e2daa2cd053846a58507/multidict-6.1.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bf6bea52ec97e95560af5ae576bdac3aa3aae0b6758c6efa115236d9e07dae44", size = 131099 },
|
||||
{ url = "https://files.pythonhosted.org/packages/82/42/d1c7a7301d52af79d88548a97e297f9d99c961ad76bbe6f67442bb77f097/multidict-6.1.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:57feec87371dbb3520da6192213c7d6fc892d5589a93db548331954de8248fd2", size = 120403 },
|
||||
{ url = "https://files.pythonhosted.org/packages/68/f3/471985c2c7ac707547553e8f37cff5158030d36bdec4414cb825fbaa5327/multidict-6.1.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:0c3f390dc53279cbc8ba976e5f8035eab997829066756d811616b652b00a23a3", size = 125348 },
|
||||
{ url = "https://files.pythonhosted.org/packages/67/2c/e6df05c77e0e433c214ec1d21ddd203d9a4770a1f2866a8ca40a545869a0/multidict-6.1.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:59bfeae4b25ec05b34f1956eaa1cb38032282cd4dfabc5056d0a1ec4d696d3aa", size = 119673 },
|
||||
{ url = "https://files.pythonhosted.org/packages/c5/cd/bc8608fff06239c9fb333f9db7743a1b2eafe98c2666c9a196e867a3a0a4/multidict-6.1.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:b2f59caeaf7632cc633b5cf6fc449372b83bbdf0da4ae04d5be36118e46cc0aa", size = 129927 },
|
||||
{ url = "https://files.pythonhosted.org/packages/44/8e/281b69b7bc84fc963a44dc6e0bbcc7150e517b91df368a27834299a526ac/multidict-6.1.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:37bb93b2178e02b7b618893990941900fd25b6b9ac0fa49931a40aecdf083fe4", size = 128711 },
|
||||
{ url = "https://files.pythonhosted.org/packages/12/a4/63e7cd38ed29dd9f1881d5119f272c898ca92536cdb53ffe0843197f6c85/multidict-6.1.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4e9f48f58c2c523d5a06faea47866cd35b32655c46b443f163d08c6d0ddb17d6", size = 125519 },
|
||||
{ url = "https://files.pythonhosted.org/packages/38/e0/4f5855037a72cd8a7a2f60a3952d9aa45feedb37ae7831642102604e8a37/multidict-6.1.0-cp313-cp313-win32.whl", hash = "sha256:3a37ffb35399029b45c6cc33640a92bef403c9fd388acce75cdc88f58bd19a81", size = 26426 },
|
||||
{ url = "https://files.pythonhosted.org/packages/7e/a5/17ee3a4db1e310b7405f5d25834460073a8ccd86198ce044dfaf69eac073/multidict-6.1.0-cp313-cp313-win_amd64.whl", hash = "sha256:e9aa71e15d9d9beaad2c6b9319edcdc0a49a43ef5c0a4c8265ca9ee7d6c67774", size = 28531 },
|
||||
{ url = "https://files.pythonhosted.org/packages/99/b7/b9e70fde2c0f0c9af4cc5277782a89b66d35948ea3369ec9f598358c3ac5/multidict-6.1.0-py3-none-any.whl", hash = "sha256:48e171e52d1c4d33888e529b999e5900356b9ae588c2f09a52dcefb158b27506", size = 10051 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "numpy"
|
||||
version = "2.2.1"
|
||||
@@ -1558,7 +1868,7 @@ wheels = [
|
||||
|
||||
[[package]]
|
||||
name = "praisonaiagents"
|
||||
version = "0.0.41"
|
||||
version = "0.0.49"
|
||||
source = { editable = "." }
|
||||
dependencies = [
|
||||
{ name = "openai" },
|
||||
@@ -1570,8 +1880,10 @@ dependencies = [
|
||||
all = [
|
||||
{ name = "chonkie" },
|
||||
{ name = "chromadb" },
|
||||
{ name = "litellm" },
|
||||
{ name = "markitdown" },
|
||||
{ name = "mem0ai" },
|
||||
{ name = "pydantic" },
|
||||
]
|
||||
knowledge = [
|
||||
{ name = "chonkie" },
|
||||
@@ -1579,6 +1891,10 @@ knowledge = [
|
||||
{ name = "markitdown" },
|
||||
{ name = "mem0ai" },
|
||||
]
|
||||
llm = [
|
||||
{ name = "litellm" },
|
||||
{ name = "pydantic" },
|
||||
]
|
||||
memory = [
|
||||
{ name = "chromadb" },
|
||||
]
|
||||
@@ -1588,15 +1904,75 @@ requires-dist = [
|
||||
{ name = "chonkie", marker = "extra == 'knowledge'" },
|
||||
{ name = "chromadb", marker = "extra == 'knowledge'", specifier = "==0.5.23" },
|
||||
{ name = "chromadb", marker = "extra == 'memory'", specifier = ">=0.5.23" },
|
||||
{ name = "litellm", marker = "extra == 'llm'", specifier = ">=1.50.0" },
|
||||
{ name = "markitdown", marker = "extra == 'knowledge'" },
|
||||
{ name = "mem0ai", marker = "extra == 'knowledge'", specifier = ">=0.1.0" },
|
||||
{ name = "openai" },
|
||||
{ name = "praisonaiagents", extras = ["knowledge"], marker = "extra == 'all'" },
|
||||
{ name = "praisonaiagents", extras = ["llm"], marker = "extra == 'all'" },
|
||||
{ name = "praisonaiagents", extras = ["memory"], marker = "extra == 'all'" },
|
||||
{ name = "pydantic" },
|
||||
{ name = "pydantic", marker = "extra == 'llm'", specifier = ">=2.4.2" },
|
||||
{ name = "rich" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "propcache"
|
||||
version = "0.2.1"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/20/c8/2a13f78d82211490855b2fb303b6721348d0787fdd9a12ac46d99d3acde1/propcache-0.2.1.tar.gz", hash = "sha256:3f77ce728b19cb537714499928fe800c3dda29e8d9428778fc7c186da4c09a64", size = 41735 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/bc/0f/2913b6791ebefb2b25b4efd4bb2299c985e09786b9f5b19184a88e5778dd/propcache-0.2.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:1ffc3cca89bb438fb9c95c13fc874012f7b9466b89328c3c8b1aa93cdcfadd16", size = 79297 },
|
||||
{ url = "https://files.pythonhosted.org/packages/cf/73/af2053aeccd40b05d6e19058419ac77674daecdd32478088b79375b9ab54/propcache-0.2.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:f174bbd484294ed9fdf09437f889f95807e5f229d5d93588d34e92106fbf6717", size = 45611 },
|
||||
{ url = "https://files.pythonhosted.org/packages/3c/09/8386115ba7775ea3b9537730e8cf718d83bbf95bffe30757ccf37ec4e5da/propcache-0.2.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:70693319e0b8fd35dd863e3e29513875eb15c51945bf32519ef52927ca883bc3", size = 45146 },
|
||||
{ url = "https://files.pythonhosted.org/packages/03/7a/793aa12f0537b2e520bf09f4c6833706b63170a211ad042ca71cbf79d9cb/propcache-0.2.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b480c6a4e1138e1aa137c0079b9b6305ec6dcc1098a8ca5196283e8a49df95a9", size = 232136 },
|
||||
{ url = "https://files.pythonhosted.org/packages/f1/38/b921b3168d72111769f648314100558c2ea1d52eb3d1ba7ea5c4aa6f9848/propcache-0.2.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d27b84d5880f6d8aa9ae3edb253c59d9f6642ffbb2c889b78b60361eed449787", size = 239706 },
|
||||
{ url = "https://files.pythonhosted.org/packages/14/29/4636f500c69b5edea7786db3c34eb6166f3384b905665ce312a6e42c720c/propcache-0.2.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:857112b22acd417c40fa4595db2fe28ab900c8c5fe4670c7989b1c0230955465", size = 238531 },
|
||||
{ url = "https://files.pythonhosted.org/packages/85/14/01fe53580a8e1734ebb704a3482b7829a0ef4ea68d356141cf0994d9659b/propcache-0.2.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cf6c4150f8c0e32d241436526f3c3f9cbd34429492abddbada2ffcff506c51af", size = 231063 },
|
||||
{ url = "https://files.pythonhosted.org/packages/33/5c/1d961299f3c3b8438301ccfbff0143b69afcc30c05fa28673cface692305/propcache-0.2.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:66d4cfda1d8ed687daa4bc0274fcfd5267873db9a5bc0418c2da19273040eeb7", size = 220134 },
|
||||
{ url = "https://files.pythonhosted.org/packages/00/d0/ed735e76db279ba67a7d3b45ba4c654e7b02bc2f8050671ec365d8665e21/propcache-0.2.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:c2f992c07c0fca81655066705beae35fc95a2fa7366467366db627d9f2ee097f", size = 220009 },
|
||||
{ url = "https://files.pythonhosted.org/packages/75/90/ee8fab7304ad6533872fee982cfff5a53b63d095d78140827d93de22e2d4/propcache-0.2.1-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:4a571d97dbe66ef38e472703067021b1467025ec85707d57e78711c085984e54", size = 212199 },
|
||||
{ url = "https://files.pythonhosted.org/packages/eb/ec/977ffaf1664f82e90737275873461695d4c9407d52abc2f3c3e24716da13/propcache-0.2.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:bb6178c241278d5fe853b3de743087be7f5f4c6f7d6d22a3b524d323eecec505", size = 214827 },
|
||||
{ url = "https://files.pythonhosted.org/packages/57/48/031fb87ab6081764054821a71b71942161619549396224cbb242922525e8/propcache-0.2.1-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:ad1af54a62ffe39cf34db1aa6ed1a1873bd548f6401db39d8e7cd060b9211f82", size = 228009 },
|
||||
{ url = "https://files.pythonhosted.org/packages/1a/06/ef1390f2524850838f2390421b23a8b298f6ce3396a7cc6d39dedd4047b0/propcache-0.2.1-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:e7048abd75fe40712005bcfc06bb44b9dfcd8e101dda2ecf2f5aa46115ad07ca", size = 231638 },
|
||||
{ url = "https://files.pythonhosted.org/packages/38/2a/101e6386d5a93358395da1d41642b79c1ee0f3b12e31727932b069282b1d/propcache-0.2.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:160291c60081f23ee43d44b08a7e5fb76681221a8e10b3139618c5a9a291b84e", size = 222788 },
|
||||
{ url = "https://files.pythonhosted.org/packages/db/81/786f687951d0979007e05ad9346cd357e50e3d0b0f1a1d6074df334b1bbb/propcache-0.2.1-cp311-cp311-win32.whl", hash = "sha256:819ce3b883b7576ca28da3861c7e1a88afd08cc8c96908e08a3f4dd64a228034", size = 40170 },
|
||||
{ url = "https://files.pythonhosted.org/packages/cf/59/7cc7037b295d5772eceb426358bb1b86e6cab4616d971bd74275395d100d/propcache-0.2.1-cp311-cp311-win_amd64.whl", hash = "sha256:edc9fc7051e3350643ad929df55c451899bb9ae6d24998a949d2e4c87fb596d3", size = 44404 },
|
||||
{ url = "https://files.pythonhosted.org/packages/4c/28/1d205fe49be8b1b4df4c50024e62480a442b1a7b818e734308bb0d17e7fb/propcache-0.2.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:081a430aa8d5e8876c6909b67bd2d937bfd531b0382d3fdedb82612c618bc41a", size = 79588 },
|
||||
{ url = "https://files.pythonhosted.org/packages/21/ee/fc4d893f8d81cd4971affef2a6cb542b36617cd1d8ce56b406112cb80bf7/propcache-0.2.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:d2ccec9ac47cf4e04897619c0e0c1a48c54a71bdf045117d3a26f80d38ab1fb0", size = 45825 },
|
||||
{ url = "https://files.pythonhosted.org/packages/4a/de/bbe712f94d088da1d237c35d735f675e494a816fd6f54e9db2f61ef4d03f/propcache-0.2.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:14d86fe14b7e04fa306e0c43cdbeebe6b2c2156a0c9ce56b815faacc193e320d", size = 45357 },
|
||||
{ url = "https://files.pythonhosted.org/packages/7f/14/7ae06a6cf2a2f1cb382586d5a99efe66b0b3d0c6f9ac2f759e6f7af9d7cf/propcache-0.2.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:049324ee97bb67285b49632132db351b41e77833678432be52bdd0289c0e05e4", size = 241869 },
|
||||
{ url = "https://files.pythonhosted.org/packages/cc/59/227a78be960b54a41124e639e2c39e8807ac0c751c735a900e21315f8c2b/propcache-0.2.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1cd9a1d071158de1cc1c71a26014dcdfa7dd3d5f4f88c298c7f90ad6f27bb46d", size = 247884 },
|
||||
{ url = "https://files.pythonhosted.org/packages/84/58/f62b4ffaedf88dc1b17f04d57d8536601e4e030feb26617228ef930c3279/propcache-0.2.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:98110aa363f1bb4c073e8dcfaefd3a5cea0f0834c2aab23dda657e4dab2f53b5", size = 248486 },
|
||||
{ url = "https://files.pythonhosted.org/packages/1c/07/ebe102777a830bca91bbb93e3479cd34c2ca5d0361b83be9dbd93104865e/propcache-0.2.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:647894f5ae99c4cf6bb82a1bb3a796f6e06af3caa3d32e26d2350d0e3e3faf24", size = 243649 },
|
||||
{ url = "https://files.pythonhosted.org/packages/ed/bc/4f7aba7f08f520376c4bb6a20b9a981a581b7f2e385fa0ec9f789bb2d362/propcache-0.2.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bfd3223c15bebe26518d58ccf9a39b93948d3dcb3e57a20480dfdd315356baff", size = 229103 },
|
||||
{ url = "https://files.pythonhosted.org/packages/fe/d5/04ac9cd4e51a57a96f78795e03c5a0ddb8f23ec098b86f92de028d7f2a6b/propcache-0.2.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:d71264a80f3fcf512eb4f18f59423fe82d6e346ee97b90625f283df56aee103f", size = 226607 },
|
||||
{ url = "https://files.pythonhosted.org/packages/e3/f0/24060d959ea41d7a7cc7fdbf68b31852331aabda914a0c63bdb0e22e96d6/propcache-0.2.1-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:e73091191e4280403bde6c9a52a6999d69cdfde498f1fdf629105247599b57ec", size = 221153 },
|
||||
{ url = "https://files.pythonhosted.org/packages/77/a7/3ac76045a077b3e4de4859a0753010765e45749bdf53bd02bc4d372da1a0/propcache-0.2.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:3935bfa5fede35fb202c4b569bb9c042f337ca4ff7bd540a0aa5e37131659348", size = 222151 },
|
||||
{ url = "https://files.pythonhosted.org/packages/e7/af/5e29da6f80cebab3f5a4dcd2a3240e7f56f2c4abf51cbfcc99be34e17f0b/propcache-0.2.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:f508b0491767bb1f2b87fdfacaba5f7eddc2f867740ec69ece6d1946d29029a6", size = 233812 },
|
||||
{ url = "https://files.pythonhosted.org/packages/8c/89/ebe3ad52642cc5509eaa453e9f4b94b374d81bae3265c59d5c2d98efa1b4/propcache-0.2.1-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:1672137af7c46662a1c2be1e8dc78cb6d224319aaa40271c9257d886be4363a6", size = 238829 },
|
||||
{ url = "https://files.pythonhosted.org/packages/e9/2f/6b32f273fa02e978b7577159eae7471b3cfb88b48563b1c2578b2d7ca0bb/propcache-0.2.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:b74c261802d3d2b85c9df2dfb2fa81b6f90deeef63c2db9f0e029a3cac50b518", size = 230704 },
|
||||
{ url = "https://files.pythonhosted.org/packages/5c/2e/f40ae6ff5624a5f77edd7b8359b208b5455ea113f68309e2b00a2e1426b6/propcache-0.2.1-cp312-cp312-win32.whl", hash = "sha256:d09c333d36c1409d56a9d29b3a1b800a42c76a57a5a8907eacdbce3f18768246", size = 40050 },
|
||||
{ url = "https://files.pythonhosted.org/packages/3b/77/a92c3ef994e47180862b9d7d11e37624fb1c00a16d61faf55115d970628b/propcache-0.2.1-cp312-cp312-win_amd64.whl", hash = "sha256:c214999039d4f2a5b2073ac506bba279945233da8c786e490d411dfc30f855c1", size = 44117 },
|
||||
{ url = "https://files.pythonhosted.org/packages/0f/2a/329e0547cf2def8857157f9477669043e75524cc3e6251cef332b3ff256f/propcache-0.2.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:aca405706e0b0a44cc6bfd41fbe89919a6a56999157f6de7e182a990c36e37bc", size = 77002 },
|
||||
{ url = "https://files.pythonhosted.org/packages/12/2d/c4df5415e2382f840dc2ecbca0eeb2293024bc28e57a80392f2012b4708c/propcache-0.2.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:12d1083f001ace206fe34b6bdc2cb94be66d57a850866f0b908972f90996b3e9", size = 44639 },
|
||||
{ url = "https://files.pythonhosted.org/packages/d0/5a/21aaa4ea2f326edaa4e240959ac8b8386ea31dedfdaa636a3544d9e7a408/propcache-0.2.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:d93f3307ad32a27bda2e88ec81134b823c240aa3abb55821a8da553eed8d9439", size = 44049 },
|
||||
{ url = "https://files.pythonhosted.org/packages/4e/3e/021b6cd86c0acc90d74784ccbb66808b0bd36067a1bf3e2deb0f3845f618/propcache-0.2.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ba278acf14471d36316159c94a802933d10b6a1e117b8554fe0d0d9b75c9d536", size = 224819 },
|
||||
{ url = "https://files.pythonhosted.org/packages/3c/57/c2fdeed1b3b8918b1770a133ba5c43ad3d78e18285b0c06364861ef5cc38/propcache-0.2.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4e6281aedfca15301c41f74d7005e6e3f4ca143584ba696ac69df4f02f40d629", size = 229625 },
|
||||
{ url = "https://files.pythonhosted.org/packages/9d/81/70d4ff57bf2877b5780b466471bebf5892f851a7e2ca0ae7ffd728220281/propcache-0.2.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5b750a8e5a1262434fb1517ddf64b5de58327f1adc3524a5e44c2ca43305eb0b", size = 232934 },
|
||||
{ url = "https://files.pythonhosted.org/packages/3c/b9/bb51ea95d73b3fb4100cb95adbd4e1acaf2cbb1fd1083f5468eeb4a099a8/propcache-0.2.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bf72af5e0fb40e9babf594308911436c8efde3cb5e75b6f206c34ad18be5c052", size = 227361 },
|
||||
{ url = "https://files.pythonhosted.org/packages/f1/20/3c6d696cd6fd70b29445960cc803b1851a1131e7a2e4ee261ee48e002bcd/propcache-0.2.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b2d0a12018b04f4cb820781ec0dffb5f7c7c1d2a5cd22bff7fb055a2cb19ebce", size = 213904 },
|
||||
{ url = "https://files.pythonhosted.org/packages/a1/cb/1593bfc5ac6d40c010fa823f128056d6bc25b667f5393781e37d62f12005/propcache-0.2.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:e800776a79a5aabdb17dcc2346a7d66d0777e942e4cd251defeb084762ecd17d", size = 212632 },
|
||||
{ url = "https://files.pythonhosted.org/packages/6d/5c/e95617e222be14a34c709442a0ec179f3207f8a2b900273720501a70ec5e/propcache-0.2.1-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:4160d9283bd382fa6c0c2b5e017acc95bc183570cd70968b9202ad6d8fc48dce", size = 207897 },
|
||||
{ url = "https://files.pythonhosted.org/packages/8e/3b/56c5ab3dc00f6375fbcdeefdede5adf9bee94f1fab04adc8db118f0f9e25/propcache-0.2.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:30b43e74f1359353341a7adb783c8f1b1c676367b011709f466f42fda2045e95", size = 208118 },
|
||||
{ url = "https://files.pythonhosted.org/packages/86/25/d7ef738323fbc6ebcbce33eb2a19c5e07a89a3df2fded206065bd5e868a9/propcache-0.2.1-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:58791550b27d5488b1bb52bc96328456095d96206a250d28d874fafe11b3dfaf", size = 217851 },
|
||||
{ url = "https://files.pythonhosted.org/packages/b3/77/763e6cef1852cf1ba740590364ec50309b89d1c818e3256d3929eb92fabf/propcache-0.2.1-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:0f022d381747f0dfe27e99d928e31bc51a18b65bb9e481ae0af1380a6725dd1f", size = 222630 },
|
||||
{ url = "https://files.pythonhosted.org/packages/4f/e9/0f86be33602089c701696fbed8d8c4c07b6ee9605c5b7536fd27ed540c5b/propcache-0.2.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:297878dc9d0a334358f9b608b56d02e72899f3b8499fc6044133f0d319e2ec30", size = 216269 },
|
||||
{ url = "https://files.pythonhosted.org/packages/cc/02/5ac83217d522394b6a2e81a2e888167e7ca629ef6569a3f09852d6dcb01a/propcache-0.2.1-cp313-cp313-win32.whl", hash = "sha256:ddfab44e4489bd79bda09d84c430677fc7f0a4939a73d2bba3073036f487a0a6", size = 39472 },
|
||||
{ url = "https://files.pythonhosted.org/packages/f4/33/d6f5420252a36034bc8a3a01171bc55b4bff5df50d1c63d9caa50693662f/propcache-0.2.1-cp313-cp313-win_amd64.whl", hash = "sha256:556fc6c10989f19a179e4321e5d678db8eb2924131e64652a51fe83e4c3db0e1", size = 43363 },
|
||||
{ url = "https://files.pythonhosted.org/packages/41/b6/c5319caea262f4821995dca2107483b94a3345d4607ad797c76cb9c36bcc/propcache-0.2.1-py3-none-any.whl", hash = "sha256:52277518d6aae65536e9cea52d4e7fd2f7a66f4aa2d30ed3f2fcea620ace3c54", size = 11818 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "protobuf"
|
||||
version = "5.29.3"
|
||||
@@ -1873,6 +2249,20 @@ wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/e5/00/27c6eb6fc764e2b3d26ddeab4aedab855c050c906ec018bdd669b18f3157/qdrant_client-1.12.2-py3-none-any.whl", hash = "sha256:a0ae500a46a679ff3521ba3f1f1cf3d72b57090a768cec65fc317066bcbac1e6", size = 267173 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "referencing"
|
||||
version = "0.36.1"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "attrs" },
|
||||
{ name = "rpds-py" },
|
||||
{ name = "typing-extensions", marker = "python_full_version < '3.13'" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/27/32/fd98246df7a0f309b58cae68b10b6b219ef2eb66747f00dfb34422687087/referencing-0.36.1.tar.gz", hash = "sha256:ca2e6492769e3602957e9b831b94211599d2aade9477f5d44110d2530cf9aade", size = 74661 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/cc/fa/9f193ef0c9074b659009f06d7cbacc6f25b072044815bcf799b76533dbb8/referencing-0.36.1-py3-none-any.whl", hash = "sha256:363d9c65f080d0d70bc41c721dce3c7f3e77fc09f269cd5c8813da18069a6794", size = 26777 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex"
|
||||
version = "2024.11.6"
|
||||
@@ -1967,6 +2357,66 @@ wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/19/71/39c7c0d87f8d4e6c020a393182060eaefeeae6c01dab6a84ec346f2567df/rich-13.9.4-py3-none-any.whl", hash = "sha256:6049d5e6ec054bf2779ab3358186963bac2ea89175919d699e378b99738c2a90", size = 242424 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rpds-py"
|
||||
version = "0.22.3"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/01/80/cce854d0921ff2f0a9fa831ba3ad3c65cee3a46711addf39a2af52df2cfd/rpds_py-0.22.3.tar.gz", hash = "sha256:e32fee8ab45d3c2db6da19a5323bc3362237c8b653c70194414b892fd06a080d", size = 26771 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/15/ad/8d1ddf78f2805a71253fcd388017e7b4a0615c22c762b6d35301fef20106/rpds_py-0.22.3-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:d20cfb4e099748ea39e6f7b16c91ab057989712d31761d3300d43134e26e165f", size = 359773 },
|
||||
{ url = "https://files.pythonhosted.org/packages/c8/75/68c15732293a8485d79fe4ebe9045525502a067865fa4278f178851b2d87/rpds_py-0.22.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:68049202f67380ff9aa52f12e92b1c30115f32e6895cd7198fa2a7961621fc5a", size = 349214 },
|
||||
{ url = "https://files.pythonhosted.org/packages/3c/4c/7ce50f3070083c2e1b2bbd0fb7046f3da55f510d19e283222f8f33d7d5f4/rpds_py-0.22.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fb4f868f712b2dd4bcc538b0a0c1f63a2b1d584c925e69a224d759e7070a12d5", size = 380477 },
|
||||
{ url = "https://files.pythonhosted.org/packages/9a/e9/835196a69cb229d5c31c13b8ae603bd2da9a6695f35fe4270d398e1db44c/rpds_py-0.22.3-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:bc51abd01f08117283c5ebf64844a35144a0843ff7b2983e0648e4d3d9f10dbb", size = 386171 },
|
||||
{ url = "https://files.pythonhosted.org/packages/f9/8e/33fc4eba6683db71e91e6d594a2cf3a8fbceb5316629f0477f7ece5e3f75/rpds_py-0.22.3-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0f3cec041684de9a4684b1572fe28c7267410e02450f4561700ca5a3bc6695a2", size = 422676 },
|
||||
{ url = "https://files.pythonhosted.org/packages/37/47/2e82d58f8046a98bb9497a8319604c92b827b94d558df30877c4b3c6ccb3/rpds_py-0.22.3-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7ef9d9da710be50ff6809fed8f1963fecdfecc8b86656cadfca3bc24289414b0", size = 446152 },
|
||||
{ url = "https://files.pythonhosted.org/packages/e1/78/79c128c3e71abbc8e9739ac27af11dc0f91840a86fce67ff83c65d1ba195/rpds_py-0.22.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:59f4a79c19232a5774aee369a0c296712ad0e77f24e62cad53160312b1c1eaa1", size = 381300 },
|
||||
{ url = "https://files.pythonhosted.org/packages/c9/5b/2e193be0e8b228c1207f31fa3ea79de64dadb4f6a4833111af8145a6bc33/rpds_py-0.22.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:1a60bce91f81ddaac922a40bbb571a12c1070cb20ebd6d49c48e0b101d87300d", size = 409636 },
|
||||
{ url = "https://files.pythonhosted.org/packages/c2/3f/687c7100b762d62186a1c1100ffdf99825f6fa5ea94556844bbbd2d0f3a9/rpds_py-0.22.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:e89391e6d60251560f0a8f4bd32137b077a80d9b7dbe6d5cab1cd80d2746f648", size = 556708 },
|
||||
{ url = "https://files.pythonhosted.org/packages/8c/a2/c00cbc4b857e8b3d5e7f7fc4c81e23afd8c138b930f4f3ccf9a41a23e9e4/rpds_py-0.22.3-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:e3fb866d9932a3d7d0c82da76d816996d1667c44891bd861a0f97ba27e84fc74", size = 583554 },
|
||||
{ url = "https://files.pythonhosted.org/packages/d0/08/696c9872cf56effdad9ed617ac072f6774a898d46b8b8964eab39ec562d2/rpds_py-0.22.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:1352ae4f7c717ae8cba93421a63373e582d19d55d2ee2cbb184344c82d2ae55a", size = 552105 },
|
||||
{ url = "https://files.pythonhosted.org/packages/18/1f/4df560be1e994f5adf56cabd6c117e02de7c88ee238bb4ce03ed50da9d56/rpds_py-0.22.3-cp311-cp311-win32.whl", hash = "sha256:b0b4136a252cadfa1adb705bb81524eee47d9f6aab4f2ee4fa1e9d3cd4581f64", size = 220199 },
|
||||
{ url = "https://files.pythonhosted.org/packages/b8/1b/c29b570bc5db8237553002788dc734d6bd71443a2ceac2a58202ec06ef12/rpds_py-0.22.3-cp311-cp311-win_amd64.whl", hash = "sha256:8bd7c8cfc0b8247c8799080fbff54e0b9619e17cdfeb0478ba7295d43f635d7c", size = 231775 },
|
||||
{ url = "https://files.pythonhosted.org/packages/75/47/3383ee3bd787a2a5e65a9b9edc37ccf8505c0a00170e3a5e6ea5fbcd97f7/rpds_py-0.22.3-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:27e98004595899949bd7a7b34e91fa7c44d7a97c40fcaf1d874168bb652ec67e", size = 352334 },
|
||||
{ url = "https://files.pythonhosted.org/packages/40/14/aa6400fa8158b90a5a250a77f2077c0d0cd8a76fce31d9f2b289f04c6dec/rpds_py-0.22.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:1978d0021e943aae58b9b0b196fb4895a25cc53d3956b8e35e0b7682eefb6d56", size = 342111 },
|
||||
{ url = "https://files.pythonhosted.org/packages/7d/06/395a13bfaa8a28b302fb433fb285a67ce0ea2004959a027aea8f9c52bad4/rpds_py-0.22.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:655ca44a831ecb238d124e0402d98f6212ac527a0ba6c55ca26f616604e60a45", size = 384286 },
|
||||
{ url = "https://files.pythonhosted.org/packages/43/52/d8eeaffab047e6b7b7ef7f00d5ead074a07973968ffa2d5820fa131d7852/rpds_py-0.22.3-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:feea821ee2a9273771bae61194004ee2fc33f8ec7db08117ef9147d4bbcbca8e", size = 391739 },
|
||||
{ url = "https://files.pythonhosted.org/packages/83/31/52dc4bde85c60b63719610ed6f6d61877effdb5113a72007679b786377b8/rpds_py-0.22.3-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:22bebe05a9ffc70ebfa127efbc429bc26ec9e9b4ee4d15a740033efda515cf3d", size = 427306 },
|
||||
{ url = "https://files.pythonhosted.org/packages/70/d5/1bab8e389c2261dba1764e9e793ed6830a63f830fdbec581a242c7c46bda/rpds_py-0.22.3-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3af6e48651c4e0d2d166dc1b033b7042ea3f871504b6805ba5f4fe31581d8d38", size = 442717 },
|
||||
{ url = "https://files.pythonhosted.org/packages/82/a1/a45f3e30835b553379b3a56ea6c4eb622cf11e72008229af840e4596a8ea/rpds_py-0.22.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e67ba3c290821343c192f7eae1d8fd5999ca2dc99994114643e2f2d3e6138b15", size = 385721 },
|
||||
{ url = "https://files.pythonhosted.org/packages/a6/27/780c942de3120bdd4d0e69583f9c96e179dfff082f6ecbb46b8d6488841f/rpds_py-0.22.3-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:02fbb9c288ae08bcb34fb41d516d5eeb0455ac35b5512d03181d755d80810059", size = 415824 },
|
||||
{ url = "https://files.pythonhosted.org/packages/94/0b/aa0542ca88ad20ea719b06520f925bae348ea5c1fdf201b7e7202d20871d/rpds_py-0.22.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:f56a6b404f74ab372da986d240e2e002769a7d7102cc73eb238a4f72eec5284e", size = 561227 },
|
||||
{ url = "https://files.pythonhosted.org/packages/0d/92/3ed77d215f82c8f844d7f98929d56cc321bb0bcfaf8f166559b8ec56e5f1/rpds_py-0.22.3-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:0a0461200769ab3b9ab7e513f6013b7a97fdeee41c29b9db343f3c5a8e2b9e61", size = 587424 },
|
||||
{ url = "https://files.pythonhosted.org/packages/09/42/cacaeb047a22cab6241f107644f230e2935d4efecf6488859a7dd82fc47d/rpds_py-0.22.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:8633e471c6207a039eff6aa116e35f69f3156b3989ea3e2d755f7bc41754a4a7", size = 555953 },
|
||||
{ url = "https://files.pythonhosted.org/packages/e6/52/c921dc6d5f5d45b212a456c1f5b17df1a471127e8037eb0972379e39dff4/rpds_py-0.22.3-cp312-cp312-win32.whl", hash = "sha256:593eba61ba0c3baae5bc9be2f5232430453fb4432048de28399ca7376de9c627", size = 221339 },
|
||||
{ url = "https://files.pythonhosted.org/packages/f2/c7/f82b5be1e8456600395366f86104d1bd8d0faed3802ad511ef6d60c30d98/rpds_py-0.22.3-cp312-cp312-win_amd64.whl", hash = "sha256:d115bffdd417c6d806ea9069237a4ae02f513b778e3789a359bc5856e0404cc4", size = 235786 },
|
||||
{ url = "https://files.pythonhosted.org/packages/d0/bf/36d5cc1f2c609ae6e8bf0fc35949355ca9d8790eceb66e6385680c951e60/rpds_py-0.22.3-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:ea7433ce7e4bfc3a85654aeb6747babe3f66eaf9a1d0c1e7a4435bbdf27fea84", size = 351657 },
|
||||
{ url = "https://files.pythonhosted.org/packages/24/2a/f1e0fa124e300c26ea9382e59b2d582cba71cedd340f32d1447f4f29fa4e/rpds_py-0.22.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:6dd9412824c4ce1aca56c47b0991e65bebb7ac3f4edccfd3f156150c96a7bf25", size = 341829 },
|
||||
{ url = "https://files.pythonhosted.org/packages/cf/c2/0da1231dd16953845bed60d1a586fcd6b15ceaeb965f4d35cdc71f70f606/rpds_py-0.22.3-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:20070c65396f7373f5df4005862fa162db5d25d56150bddd0b3e8214e8ef45b4", size = 384220 },
|
||||
{ url = "https://files.pythonhosted.org/packages/c7/73/a4407f4e3a00a9d4b68c532bf2d873d6b562854a8eaff8faa6133b3588ec/rpds_py-0.22.3-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:0b09865a9abc0ddff4e50b5ef65467cd94176bf1e0004184eb915cbc10fc05c5", size = 391009 },
|
||||
{ url = "https://files.pythonhosted.org/packages/a9/c3/04b7353477ab360fe2563f5f0b176d2105982f97cd9ae80a9c5a18f1ae0f/rpds_py-0.22.3-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3453e8d41fe5f17d1f8e9c383a7473cd46a63661628ec58e07777c2fff7196dc", size = 426989 },
|
||||
{ url = "https://files.pythonhosted.org/packages/8d/e6/e4b85b722bcf11398e17d59c0f6049d19cd606d35363221951e6d625fcb0/rpds_py-0.22.3-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f5d36399a1b96e1a5fdc91e0522544580dbebeb1f77f27b2b0ab25559e103b8b", size = 441544 },
|
||||
{ url = "https://files.pythonhosted.org/packages/27/fc/403e65e56f65fff25f2973216974976d3f0a5c3f30e53758589b6dc9b79b/rpds_py-0.22.3-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:009de23c9c9ee54bf11303a966edf4d9087cd43a6003672e6aa7def643d06518", size = 385179 },
|
||||
{ url = "https://files.pythonhosted.org/packages/57/9b/2be9ff9700d664d51fd96b33d6595791c496d2778cb0b2a634f048437a55/rpds_py-0.22.3-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:1aef18820ef3e4587ebe8b3bc9ba6e55892a6d7b93bac6d29d9f631a3b4befbd", size = 415103 },
|
||||
{ url = "https://files.pythonhosted.org/packages/bb/a5/03c2ad8ca10994fcf22dd2150dd1d653bc974fa82d9a590494c84c10c641/rpds_py-0.22.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:f60bd8423be1d9d833f230fdbccf8f57af322d96bcad6599e5a771b151398eb2", size = 560916 },
|
||||
{ url = "https://files.pythonhosted.org/packages/ba/2e/be4fdfc8b5b576e588782b56978c5b702c5a2307024120d8aeec1ab818f0/rpds_py-0.22.3-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:62d9cfcf4948683a18a9aff0ab7e1474d407b7bab2ca03116109f8464698ab16", size = 587062 },
|
||||
{ url = "https://files.pythonhosted.org/packages/67/e0/2034c221937709bf9c542603d25ad43a68b4b0a9a0c0b06a742f2756eb66/rpds_py-0.22.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:9253fc214112405f0afa7db88739294295f0e08466987f1d70e29930262b4c8f", size = 555734 },
|
||||
{ url = "https://files.pythonhosted.org/packages/ea/ce/240bae07b5401a22482b58e18cfbabaa392409b2797da60223cca10d7367/rpds_py-0.22.3-cp313-cp313-win32.whl", hash = "sha256:fb0ba113b4983beac1a2eb16faffd76cb41e176bf58c4afe3e14b9c681f702de", size = 220663 },
|
||||
{ url = "https://files.pythonhosted.org/packages/cb/f0/d330d08f51126330467edae2fa4efa5cec8923c87551a79299380fdea30d/rpds_py-0.22.3-cp313-cp313-win_amd64.whl", hash = "sha256:c58e2339def52ef6b71b8f36d13c3688ea23fa093353f3a4fee2556e62086ec9", size = 235503 },
|
||||
{ url = "https://files.pythonhosted.org/packages/f7/c4/dbe1cc03df013bf2feb5ad00615038050e7859f381e96fb5b7b4572cd814/rpds_py-0.22.3-cp313-cp313t-macosx_10_12_x86_64.whl", hash = "sha256:f82a116a1d03628a8ace4859556fb39fd1424c933341a08ea3ed6de1edb0283b", size = 347698 },
|
||||
{ url = "https://files.pythonhosted.org/packages/a4/3a/684f66dd6b0f37499cad24cd1c0e523541fd768576fa5ce2d0a8799c3cba/rpds_py-0.22.3-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:3dfcbc95bd7992b16f3f7ba05af8a64ca694331bd24f9157b49dadeeb287493b", size = 337330 },
|
||||
{ url = "https://files.pythonhosted.org/packages/82/eb/e022c08c2ce2e8f7683baa313476492c0e2c1ca97227fe8a75d9f0181e95/rpds_py-0.22.3-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:59259dc58e57b10e7e18ce02c311804c10c5a793e6568f8af4dead03264584d1", size = 380022 },
|
||||
{ url = "https://files.pythonhosted.org/packages/e4/21/5a80e653e4c86aeb28eb4fea4add1f72e1787a3299687a9187105c3ee966/rpds_py-0.22.3-cp313-cp313t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5725dd9cc02068996d4438d397e255dcb1df776b7ceea3b9cb972bdb11260a83", size = 390754 },
|
||||
{ url = "https://files.pythonhosted.org/packages/37/a4/d320a04ae90f72d080b3d74597074e62be0a8ecad7d7321312dfe2dc5a6a/rpds_py-0.22.3-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:99b37292234e61325e7a5bb9689e55e48c3f5f603af88b1642666277a81f1fbd", size = 423840 },
|
||||
{ url = "https://files.pythonhosted.org/packages/87/70/674dc47d93db30a6624279284e5631be4c3a12a0340e8e4f349153546728/rpds_py-0.22.3-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:27b1d3b3915a99208fee9ab092b8184c420f2905b7d7feb4aeb5e4a9c509b8a1", size = 438970 },
|
||||
{ url = "https://files.pythonhosted.org/packages/3f/64/9500f4d66601d55cadd21e90784cfd5d5f4560e129d72e4339823129171c/rpds_py-0.22.3-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f612463ac081803f243ff13cccc648578e2279295048f2a8d5eb430af2bae6e3", size = 383146 },
|
||||
{ url = "https://files.pythonhosted.org/packages/4d/45/630327addb1d17173adcf4af01336fd0ee030c04798027dfcb50106001e0/rpds_py-0.22.3-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:f73d3fef726b3243a811121de45193c0ca75f6407fe66f3f4e183c983573e130", size = 408294 },
|
||||
{ url = "https://files.pythonhosted.org/packages/5f/ef/8efb3373cee54ea9d9980b772e5690a0c9e9214045a4e7fa35046e399fee/rpds_py-0.22.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:3f21f0495edea7fdbaaa87e633a8689cd285f8f4af5c869f27bc8074638ad69c", size = 556345 },
|
||||
{ url = "https://files.pythonhosted.org/packages/54/01/151d3b9ef4925fc8f15bfb131086c12ec3c3d6dd4a4f7589c335bf8e85ba/rpds_py-0.22.3-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:1e9663daaf7a63ceccbbb8e3808fe90415b0757e2abddbfc2e06c857bf8c5e2b", size = 582292 },
|
||||
{ url = "https://files.pythonhosted.org/packages/30/89/35fc7a6cdf3477d441c7aca5e9bbf5a14e0f25152aed7f63f4e0b141045d/rpds_py-0.22.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:a76e42402542b1fae59798fab64432b2d015ab9d0c8c47ba7addddbaf7952333", size = 553855 },
|
||||
{ url = "https://files.pythonhosted.org/packages/8f/e0/830c02b2457c4bd20a8c5bb394d31d81f57fbefce2dbdd2e31feff4f7003/rpds_py-0.22.3-cp313-cp313t-win32.whl", hash = "sha256:69803198097467ee7282750acb507fba35ca22cc3b85f16cf45fb01cb9097730", size = 219100 },
|
||||
{ url = "https://files.pythonhosted.org/packages/f8/30/7ac943f69855c2db77407ae363484b915d861702dbba1aa82d68d57f42be/rpds_py-0.22.3-cp313-cp313t-win_amd64.whl", hash = "sha256:f5cf2a0c2bdadf3791b5c205d55a37a54025c6e18a71c71f82bb536cf9a454bf", size = 233794 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rsa"
|
||||
version = "4.9"
|
||||
@@ -2465,6 +2915,68 @@ wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/a7/ea/53d1fe468e63e092cf16e2c18d16f50c29851242f9dd12d6a66e0d7f0d02/XlsxWriter-3.2.0-py3-none-any.whl", hash = "sha256:ecfd5405b3e0e228219bcaf24c2ca0915e012ca9464a14048021d21a995d490e", size = 159925 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "yarl"
|
||||
version = "1.18.3"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "idna" },
|
||||
{ name = "multidict" },
|
||||
{ name = "propcache" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/b7/9d/4b94a8e6d2b51b599516a5cb88e5bc99b4d8d4583e468057eaa29d5f0918/yarl-1.18.3.tar.gz", hash = "sha256:ac1801c45cbf77b6c99242eeff4fffb5e4e73a800b5c4ad4fc0be5def634d2e1", size = 181062 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/40/93/282b5f4898d8e8efaf0790ba6d10e2245d2c9f30e199d1a85cae9356098c/yarl-1.18.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:8503ad47387b8ebd39cbbbdf0bf113e17330ffd339ba1144074da24c545f0069", size = 141555 },
|
||||
{ url = "https://files.pythonhosted.org/packages/6d/9c/0a49af78df099c283ca3444560f10718fadb8a18dc8b3edf8c7bd9fd7d89/yarl-1.18.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:02ddb6756f8f4517a2d5e99d8b2f272488e18dd0bfbc802f31c16c6c20f22193", size = 94351 },
|
||||
{ url = "https://files.pythonhosted.org/packages/5a/a1/205ab51e148fdcedad189ca8dd587794c6f119882437d04c33c01a75dece/yarl-1.18.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:67a283dd2882ac98cc6318384f565bffc751ab564605959df4752d42483ad889", size = 92286 },
|
||||
{ url = "https://files.pythonhosted.org/packages/ed/fe/88b690b30f3f59275fb674f5f93ddd4a3ae796c2b62e5bb9ece8a4914b83/yarl-1.18.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d980e0325b6eddc81331d3f4551e2a333999fb176fd153e075c6d1c2530aa8a8", size = 340649 },
|
||||
{ url = "https://files.pythonhosted.org/packages/07/eb/3b65499b568e01f36e847cebdc8d7ccb51fff716dbda1ae83c3cbb8ca1c9/yarl-1.18.3-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b643562c12680b01e17239be267bc306bbc6aac1f34f6444d1bded0c5ce438ca", size = 356623 },
|
||||
{ url = "https://files.pythonhosted.org/packages/33/46/f559dc184280b745fc76ec6b1954de2c55595f0ec0a7614238b9ebf69618/yarl-1.18.3-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c017a3b6df3a1bd45b9fa49a0f54005e53fbcad16633870104b66fa1a30a29d8", size = 354007 },
|
||||
{ url = "https://files.pythonhosted.org/packages/af/ba/1865d85212351ad160f19fb99808acf23aab9a0f8ff31c8c9f1b4d671fc9/yarl-1.18.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:75674776d96d7b851b6498f17824ba17849d790a44d282929c42dbb77d4f17ae", size = 344145 },
|
||||
{ url = "https://files.pythonhosted.org/packages/94/cb/5c3e975d77755d7b3d5193e92056b19d83752ea2da7ab394e22260a7b824/yarl-1.18.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ccaa3a4b521b780a7e771cc336a2dba389a0861592bbce09a476190bb0c8b4b3", size = 336133 },
|
||||
{ url = "https://files.pythonhosted.org/packages/19/89/b77d3fd249ab52a5c40859815765d35c91425b6bb82e7427ab2f78f5ff55/yarl-1.18.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:2d06d3005e668744e11ed80812e61efd77d70bb7f03e33c1598c301eea20efbb", size = 347967 },
|
||||
{ url = "https://files.pythonhosted.org/packages/35/bd/f6b7630ba2cc06c319c3235634c582a6ab014d52311e7d7c22f9518189b5/yarl-1.18.3-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:9d41beda9dc97ca9ab0b9888cb71f7539124bc05df02c0cff6e5acc5a19dcc6e", size = 346397 },
|
||||
{ url = "https://files.pythonhosted.org/packages/18/1a/0b4e367d5a72d1f095318344848e93ea70da728118221f84f1bf6c1e39e7/yarl-1.18.3-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:ba23302c0c61a9999784e73809427c9dbedd79f66a13d84ad1b1943802eaaf59", size = 350206 },
|
||||
{ url = "https://files.pythonhosted.org/packages/b5/cf/320fff4367341fb77809a2d8d7fe75b5d323a8e1b35710aafe41fdbf327b/yarl-1.18.3-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:6748dbf9bfa5ba1afcc7556b71cda0d7ce5f24768043a02a58846e4a443d808d", size = 362089 },
|
||||
{ url = "https://files.pythonhosted.org/packages/57/cf/aadba261d8b920253204085268bad5e8cdd86b50162fcb1b10c10834885a/yarl-1.18.3-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:0b0cad37311123211dc91eadcb322ef4d4a66008d3e1bdc404808992260e1a0e", size = 366267 },
|
||||
{ url = "https://files.pythonhosted.org/packages/54/58/fb4cadd81acdee6dafe14abeb258f876e4dd410518099ae9a35c88d8097c/yarl-1.18.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:0fb2171a4486bb075316ee754c6d8382ea6eb8b399d4ec62fde2b591f879778a", size = 359141 },
|
||||
{ url = "https://files.pythonhosted.org/packages/9a/7a/4c571597589da4cd5c14ed2a0b17ac56ec9ee7ee615013f74653169e702d/yarl-1.18.3-cp311-cp311-win32.whl", hash = "sha256:61b1a825a13bef4a5f10b1885245377d3cd0bf87cba068e1d9a88c2ae36880e1", size = 84402 },
|
||||
{ url = "https://files.pythonhosted.org/packages/ae/7b/8600250b3d89b625f1121d897062f629883c2f45339623b69b1747ec65fa/yarl-1.18.3-cp311-cp311-win_amd64.whl", hash = "sha256:b9d60031cf568c627d028239693fd718025719c02c9f55df0a53e587aab951b5", size = 91030 },
|
||||
{ url = "https://files.pythonhosted.org/packages/33/85/bd2e2729752ff4c77338e0102914897512e92496375e079ce0150a6dc306/yarl-1.18.3-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:1dd4bdd05407ced96fed3d7f25dbbf88d2ffb045a0db60dbc247f5b3c5c25d50", size = 142644 },
|
||||
{ url = "https://files.pythonhosted.org/packages/ff/74/1178322cc0f10288d7eefa6e4a85d8d2e28187ccab13d5b844e8b5d7c88d/yarl-1.18.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:7c33dd1931a95e5d9a772d0ac5e44cac8957eaf58e3c8da8c1414de7dd27c576", size = 94962 },
|
||||
{ url = "https://files.pythonhosted.org/packages/be/75/79c6acc0261e2c2ae8a1c41cf12265e91628c8c58ae91f5ff59e29c0787f/yarl-1.18.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:25b411eddcfd56a2f0cd6a384e9f4f7aa3efee14b188de13048c25b5e91f1640", size = 92795 },
|
||||
{ url = "https://files.pythonhosted.org/packages/6b/32/927b2d67a412c31199e83fefdce6e645247b4fb164aa1ecb35a0f9eb2058/yarl-1.18.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:436c4fc0a4d66b2badc6c5fc5ef4e47bb10e4fd9bf0c79524ac719a01f3607c2", size = 332368 },
|
||||
{ url = "https://files.pythonhosted.org/packages/19/e5/859fca07169d6eceeaa4fde1997c91d8abde4e9a7c018e371640c2da2b71/yarl-1.18.3-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e35ef8683211db69ffe129a25d5634319a677570ab6b2eba4afa860f54eeaf75", size = 342314 },
|
||||
{ url = "https://files.pythonhosted.org/packages/08/75/76b63ccd91c9e03ab213ef27ae6add2e3400e77e5cdddf8ed2dbc36e3f21/yarl-1.18.3-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:84b2deecba4a3f1a398df819151eb72d29bfeb3b69abb145a00ddc8d30094512", size = 341987 },
|
||||
{ url = "https://files.pythonhosted.org/packages/1a/e1/a097d5755d3ea8479a42856f51d97eeff7a3a7160593332d98f2709b3580/yarl-1.18.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:00e5a1fea0fd4f5bfa7440a47eff01d9822a65b4488f7cff83155a0f31a2ecba", size = 336914 },
|
||||
{ url = "https://files.pythonhosted.org/packages/0b/42/e1b4d0e396b7987feceebe565286c27bc085bf07d61a59508cdaf2d45e63/yarl-1.18.3-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d0e883008013c0e4aef84dcfe2a0b172c4d23c2669412cf5b3371003941f72bb", size = 325765 },
|
||||
{ url = "https://files.pythonhosted.org/packages/7e/18/03a5834ccc9177f97ca1bbb245b93c13e58e8225276f01eedc4cc98ab820/yarl-1.18.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:5a3f356548e34a70b0172d8890006c37be92995f62d95a07b4a42e90fba54272", size = 344444 },
|
||||
{ url = "https://files.pythonhosted.org/packages/c8/03/a713633bdde0640b0472aa197b5b86e90fbc4c5bc05b727b714cd8a40e6d/yarl-1.18.3-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:ccd17349166b1bee6e529b4add61727d3f55edb7babbe4069b5764c9587a8cc6", size = 340760 },
|
||||
{ url = "https://files.pythonhosted.org/packages/eb/99/f6567e3f3bbad8fd101886ea0276c68ecb86a2b58be0f64077396cd4b95e/yarl-1.18.3-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:b958ddd075ddba5b09bb0be8a6d9906d2ce933aee81100db289badbeb966f54e", size = 346484 },
|
||||
{ url = "https://files.pythonhosted.org/packages/8e/a9/84717c896b2fc6cb15bd4eecd64e34a2f0a9fd6669e69170c73a8b46795a/yarl-1.18.3-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:c7d79f7d9aabd6011004e33b22bc13056a3e3fb54794d138af57f5ee9d9032cb", size = 359864 },
|
||||
{ url = "https://files.pythonhosted.org/packages/1e/2e/d0f5f1bef7ee93ed17e739ec8dbcb47794af891f7d165fa6014517b48169/yarl-1.18.3-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:4891ed92157e5430874dad17b15eb1fda57627710756c27422200c52d8a4e393", size = 364537 },
|
||||
{ url = "https://files.pythonhosted.org/packages/97/8a/568d07c5d4964da5b02621a517532adb8ec5ba181ad1687191fffeda0ab6/yarl-1.18.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ce1af883b94304f493698b00d0f006d56aea98aeb49d75ec7d98cd4a777e9285", size = 357861 },
|
||||
{ url = "https://files.pythonhosted.org/packages/7d/e3/924c3f64b6b3077889df9a1ece1ed8947e7b61b0a933f2ec93041990a677/yarl-1.18.3-cp312-cp312-win32.whl", hash = "sha256:f91c4803173928a25e1a55b943c81f55b8872f0018be83e3ad4938adffb77dd2", size = 84097 },
|
||||
{ url = "https://files.pythonhosted.org/packages/34/45/0e055320daaabfc169b21ff6174567b2c910c45617b0d79c68d7ab349b02/yarl-1.18.3-cp312-cp312-win_amd64.whl", hash = "sha256:7e2ee16578af3b52ac2f334c3b1f92262f47e02cc6193c598502bd46f5cd1477", size = 90399 },
|
||||
{ url = "https://files.pythonhosted.org/packages/30/c7/c790513d5328a8390be8f47be5d52e141f78b66c6c48f48d241ca6bd5265/yarl-1.18.3-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:90adb47ad432332d4f0bc28f83a5963f426ce9a1a8809f5e584e704b82685dcb", size = 140789 },
|
||||
{ url = "https://files.pythonhosted.org/packages/30/aa/a2f84e93554a578463e2edaaf2300faa61c8701f0898725842c704ba5444/yarl-1.18.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:913829534200eb0f789d45349e55203a091f45c37a2674678744ae52fae23efa", size = 94144 },
|
||||
{ url = "https://files.pythonhosted.org/packages/c6/fc/d68d8f83714b221a85ce7866832cba36d7c04a68fa6a960b908c2c84f325/yarl-1.18.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:ef9f7768395923c3039055c14334ba4d926f3baf7b776c923c93d80195624782", size = 91974 },
|
||||
{ url = "https://files.pythonhosted.org/packages/56/4e/d2563d8323a7e9a414b5b25341b3942af5902a2263d36d20fb17c40411e2/yarl-1.18.3-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:88a19f62ff30117e706ebc9090b8ecc79aeb77d0b1f5ec10d2d27a12bc9f66d0", size = 333587 },
|
||||
{ url = "https://files.pythonhosted.org/packages/25/c9/cfec0bc0cac8d054be223e9f2c7909d3e8442a856af9dbce7e3442a8ec8d/yarl-1.18.3-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e17c9361d46a4d5addf777c6dd5eab0715a7684c2f11b88c67ac37edfba6c482", size = 344386 },
|
||||
{ url = "https://files.pythonhosted.org/packages/ab/5d/4c532190113b25f1364d25f4c319322e86232d69175b91f27e3ebc2caf9a/yarl-1.18.3-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1a74a13a4c857a84a845505fd2d68e54826a2cd01935a96efb1e9d86c728e186", size = 345421 },
|
||||
{ url = "https://files.pythonhosted.org/packages/23/d1/6cdd1632da013aa6ba18cee4d750d953104a5e7aac44e249d9410a972bf5/yarl-1.18.3-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:41f7ce59d6ee7741af71d82020346af364949314ed3d87553763a2df1829cc58", size = 339384 },
|
||||
{ url = "https://files.pythonhosted.org/packages/9a/c4/6b3c39bec352e441bd30f432cda6ba51681ab19bb8abe023f0d19777aad1/yarl-1.18.3-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f52a265001d830bc425f82ca9eabda94a64a4d753b07d623a9f2863fde532b53", size = 326689 },
|
||||
{ url = "https://files.pythonhosted.org/packages/23/30/07fb088f2eefdc0aa4fc1af4e3ca4eb1a3aadd1ce7d866d74c0f124e6a85/yarl-1.18.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:82123d0c954dc58db301f5021a01854a85bf1f3bb7d12ae0c01afc414a882ca2", size = 345453 },
|
||||
{ url = "https://files.pythonhosted.org/packages/63/09/d54befb48f9cd8eec43797f624ec37783a0266855f4930a91e3d5c7717f8/yarl-1.18.3-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:2ec9bbba33b2d00999af4631a3397d1fd78290c48e2a3e52d8dd72db3a067ac8", size = 341872 },
|
||||
{ url = "https://files.pythonhosted.org/packages/91/26/fd0ef9bf29dd906a84b59f0cd1281e65b0c3e08c6aa94b57f7d11f593518/yarl-1.18.3-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:fbd6748e8ab9b41171bb95c6142faf068f5ef1511935a0aa07025438dd9a9bc1", size = 347497 },
|
||||
{ url = "https://files.pythonhosted.org/packages/d9/b5/14ac7a256d0511b2ac168d50d4b7d744aea1c1aa20c79f620d1059aab8b2/yarl-1.18.3-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:877d209b6aebeb5b16c42cbb377f5f94d9e556626b1bfff66d7b0d115be88d0a", size = 359981 },
|
||||
{ url = "https://files.pythonhosted.org/packages/ca/b3/d493221ad5cbd18bc07e642894030437e405e1413c4236dd5db6e46bcec9/yarl-1.18.3-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:b464c4ab4bfcb41e3bfd3f1c26600d038376c2de3297760dfe064d2cb7ea8e10", size = 366229 },
|
||||
{ url = "https://files.pythonhosted.org/packages/04/56/6a3e2a5d9152c56c346df9b8fb8edd2c8888b1e03f96324d457e5cf06d34/yarl-1.18.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:8d39d351e7faf01483cc7ff7c0213c412e38e5a340238826be7e0e4da450fdc8", size = 360383 },
|
||||
{ url = "https://files.pythonhosted.org/packages/fd/b7/4b3c7c7913a278d445cc6284e59b2e62fa25e72758f888b7a7a39eb8423f/yarl-1.18.3-cp313-cp313-win32.whl", hash = "sha256:61ee62ead9b68b9123ec24bc866cbef297dd266175d53296e2db5e7f797f902d", size = 310152 },
|
||||
{ url = "https://files.pythonhosted.org/packages/f5/d5/688db678e987c3e0fb17867970700b92603cadf36c56e5fb08f23e822a0c/yarl-1.18.3-cp313-cp313-win_amd64.whl", hash = "sha256:578e281c393af575879990861823ef19d66e2b1d0098414855dd367e234f5b3c", size = 315723 },
|
||||
{ url = "https://files.pythonhosted.org/packages/f5/4b/a06e0ec3d155924f77835ed2d167ebd3b211a7b0853da1cf8d8414d784ef/yarl-1.18.3-py3-none-any.whl", hash = "sha256:b57f4f58099328dfb26c6a771d09fb20dbbae81d20cfb66141251ea063bd101b", size = 45109 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "youtube-transcript-api"
|
||||
version = "0.6.3"
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
from praisonaiagents import Agent, Task, PraisonAIAgents
|
||||
|
||||
# Define the configuration for the Knowledge instance
|
||||
config = {
|
||||
"vector_store": {
|
||||
"provider": "chroma",
|
||||
"config": {
|
||||
"collection_name": "praison",
|
||||
"path": ".praison"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# Create an agent
|
||||
rag_agent = Agent(
|
||||
name="RAG Agent",
|
||||
role="Information Specialist",
|
||||
goal="Retrieve knowledge efficiently",
|
||||
llm="gpt-4o-mini"
|
||||
)
|
||||
|
||||
# Define a task for the agent
|
||||
rag_task = Task(
|
||||
name="RAG Task",
|
||||
description="What is KAG?",
|
||||
expected_output="Answer to the question",
|
||||
agent=rag_agent,
|
||||
context=[config] # Vector Database provided as context
|
||||
)
|
||||
|
||||
# Build Agents
|
||||
agents = PraisonAIAgents(
|
||||
agents=[rag_agent],
|
||||
tasks=[rag_task],
|
||||
user_id="user1"
|
||||
)
|
||||
|
||||
# Start Agents
|
||||
agents.start()
|
||||
@@ -6,6 +6,45 @@ 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}>
|
||||
|
||||
@@ -110,7 +110,7 @@ Loads environment variables from .env file or system and sets them.</p>
|
||||
file.write("FROM python:3.11-slim\n")
|
||||
file.write("WORKDIR /app\n")
|
||||
file.write("COPY . .\n")
|
||||
file.write("RUN pip install flask praisonai==2.0.50 gunicorn markdown\n")
|
||||
file.write("RUN pip install flask praisonai==2.0.56 gunicorn markdown\n")
|
||||
file.write("EXPOSE 8080\n")
|
||||
file.write('CMD ["gunicorn", "-b", "0.0.0.0:8080", "api:app"]\n')
|
||||
|
||||
|
||||
@@ -0,0 +1,203 @@
|
||||
---
|
||||
title: "Code Analysis Agent"
|
||||
description: "Learn how to create AI agents for comprehensive code analysis and quality assessment."
|
||||
icon: "code-merge"
|
||||
---
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
In[In] --> Analyzer[Code Analyzer]
|
||||
Analyzer --> Quality[Quality Assessment]
|
||||
Quality --> Metrics[Core Metrics]
|
||||
Metrics --> Technical[Technical Review]
|
||||
Technical --> Recommendations[Recommendations]
|
||||
Recommendations --> Out[Out]
|
||||
|
||||
style In fill:#8B0000,color:#fff
|
||||
style Analyzer fill:#2E8B57,color:#fff
|
||||
style Quality fill:#2E8B57,color:#fff
|
||||
style Metrics fill:#2E8B57,color:#fff
|
||||
style Technical fill:#2E8B57,color:#fff
|
||||
style Recommendations fill:#2E8B57,color:#fff
|
||||
style Out fill:#8B0000,color:#fff
|
||||
```
|
||||
|
||||
## What is Code Analysis?
|
||||
|
||||
Code Analysis is a systematic process of evaluating source code to assess its quality, maintainability, performance, and security. This helps developers and organizations maintain high code standards and identify areas for improvement.
|
||||
|
||||
## Features
|
||||
|
||||
<CardGroup cols={2}>
|
||||
<Card title="Quality Assessment" icon="chart-simple">
|
||||
Comprehensive evaluation of code quality with numerical scoring.
|
||||
</Card>
|
||||
<Card title="Core Metrics Analysis" icon="gauge">
|
||||
Analysis of architecture, maintainability, performance, and security.
|
||||
</Card>
|
||||
<Card title="Technical Assessment" icon="code">
|
||||
Review of tech stack, complexity, and best practices adherence.
|
||||
</Card>
|
||||
<Card title="Risk Assessment" icon="shield">
|
||||
Identification of potential risks and security vulnerabilities.
|
||||
</Card>
|
||||
<Card title="Recommendations" icon="lightbulb">
|
||||
Actionable suggestions for improvements and enhancements.
|
||||
</Card>
|
||||
</CardGroup>
|
||||
|
||||
## Quick Start
|
||||
|
||||
<Steps>
|
||||
<Step title="Install Package">
|
||||
First, install the PraisonAI Agents package:
|
||||
```bash
|
||||
pip install praisonaiagents gitingest
|
||||
```
|
||||
</Step>
|
||||
|
||||
<Step title="Set API Key">
|
||||
Set your OpenAI API key as an environment variable in your terminal:
|
||||
```bash
|
||||
export OPENAI_API_KEY=your_api_key_here
|
||||
```
|
||||
</Step>
|
||||
|
||||
<Step title="Create a file">
|
||||
Create a new file `code_analysis.py` with the following code:
|
||||
```python
|
||||
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)
|
||||
```
|
||||
</Step>
|
||||
</Steps>
|
||||
|
||||
## Understanding the Output
|
||||
|
||||
The code analysis generates a comprehensive report with the following components:
|
||||
|
||||
- Overall Quality Score (0-100)
|
||||
- Core Metrics Analysis
|
||||
- Architecture and Design Score
|
||||
- Code Maintainability Score
|
||||
- Performance Score
|
||||
- Security Score
|
||||
- Test Coverage Percentage
|
||||
- Technical Assessment
|
||||
- Technology Stack
|
||||
- Complexity Metrics
|
||||
- Best Practices Review
|
||||
- Risk Assessment
|
||||
- Recommendations
|
||||
- Key Improvements
|
||||
- Architecture Suggestions
|
||||
- Security Enhancements
|
||||
|
||||
## Next Steps
|
||||
|
||||
<CardGroup>
|
||||
<Card title="Introduction" icon="book" href="/introduction">
|
||||
Learn more about PraisonAI and its core concepts
|
||||
</Card>
|
||||
<Card title="Quick Start" icon="bolt" href="/quickstart">
|
||||
Get started with the basics of PraisonAI
|
||||
</Card>
|
||||
<Card title="API Reference" icon="code" href="/api-reference">
|
||||
Explore the complete API documentation
|
||||
</Card>
|
||||
</CardGroup>
|
||||
@@ -0,0 +1,265 @@
|
||||
---
|
||||
title: "Hackathon Judge Agent"
|
||||
description: "Learn how to create AI agents for evaluating hackathon projects through video demonstrations."
|
||||
icon: "trophy"
|
||||
---
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
In[In] --> Judge[Hackathon Judge]
|
||||
Judge --> Scores[Project Scores]
|
||||
Scores --> Analysis[Detailed Analysis]
|
||||
Analysis --> Feedback[Feedback]
|
||||
Feedback --> Recommendations[Recommendations]
|
||||
Recommendations --> Out[Out]
|
||||
|
||||
style In fill:#8B0000,color:#fff
|
||||
style Judge fill:#2E8B57,color:#fff
|
||||
style Scores fill:#2E8B57,color:#fff
|
||||
style Analysis fill:#2E8B57,color:#fff
|
||||
style Feedback fill:#2E8B57,color:#fff
|
||||
style Recommendations fill:#2E8B57,color:#fff
|
||||
style Out fill:#8B0000,color:#fff
|
||||
```
|
||||
|
||||
## What is Hackathon Project Evaluation?
|
||||
|
||||
Hackathon Project Evaluation is an automated process for assessing hackathon projects through video demonstrations. It provides comprehensive scoring across multiple dimensions including innovation, technical complexity, and presentation quality, helping organizers make informed decisions and providing valuable feedback to participants.
|
||||
|
||||
## Features
|
||||
|
||||
<CardGroup cols={2}>
|
||||
<Card title="Project Scoring" icon="star">
|
||||
Comprehensive scoring system across multiple dimensions (0-100).
|
||||
</Card>
|
||||
<Card title="Technical Analysis" icon="microchip">
|
||||
Evaluation of technical complexity and implementation quality.
|
||||
</Card>
|
||||
<Card title="Innovation Assessment" icon="lightbulb">
|
||||
Analysis of creativity and unique project features.
|
||||
</Card>
|
||||
<Card title="Market Analysis" icon="chart-line">
|
||||
Assessment of market potential and scalability.
|
||||
</Card>
|
||||
<Card title="Detailed Feedback" icon="comments">
|
||||
Constructive feedback and specific recommendations for improvement.
|
||||
</Card>
|
||||
</CardGroup>
|
||||
|
||||
## Quick Start
|
||||
|
||||
<Steps>
|
||||
<Step title="Install Package">
|
||||
First, install the PraisonAI Agents package:
|
||||
```bash
|
||||
pip install praisonaiagents opencv-python moviepy
|
||||
```
|
||||
</Step>
|
||||
|
||||
<Step title="Set API Key">
|
||||
Set your OpenAI API key as an environment variable in your terminal:
|
||||
```bash
|
||||
export OPENAI_API_KEY=your_api_key_here
|
||||
```
|
||||
</Step>
|
||||
|
||||
<Step title="Create a file">
|
||||
Create a new file `hackathon_judge.py` with the following code:
|
||||
```python
|
||||
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}")
|
||||
```
|
||||
</Step>
|
||||
</Steps>
|
||||
|
||||
## Understanding the Output
|
||||
|
||||
The hackathon project evaluation generates a comprehensive report with the following components:
|
||||
|
||||
- Scoring Metrics (0-100)
|
||||
- Innovation Score
|
||||
- Technical Complexity
|
||||
- Presentation Quality
|
||||
- User Experience
|
||||
- Project Completeness
|
||||
- Overall Score
|
||||
- Qualitative Analysis
|
||||
- Key Strengths
|
||||
- Areas for Improvement
|
||||
- Notable Features
|
||||
- Technical Highlights
|
||||
- Strategic Assessment
|
||||
- Recommendations
|
||||
- Market Potential
|
||||
- Scalability Assessment
|
||||
|
||||
## Next Steps
|
||||
|
||||
<CardGroup>
|
||||
<Card title="Introduction" icon="book" href="/introduction">
|
||||
Learn more about PraisonAI and its core concepts
|
||||
</Card>
|
||||
<Card title="Quick Start" icon="bolt" href="/quickstart">
|
||||
Get started with the basics of PraisonAI
|
||||
</Card>
|
||||
<Card title="API Reference" icon="code" href="/api-reference">
|
||||
Explore the complete API documentation
|
||||
</Card>
|
||||
</CardGroup>
|
||||
@@ -12,7 +12,7 @@ icon: "images"
|
||||
<Step title="Install Package">
|
||||
First, install the PraisonAI Agents package:
|
||||
```bash
|
||||
pip install praisonaiagents
|
||||
pip install praisonaiagents opencv-python moviepy
|
||||
```
|
||||
</Step>
|
||||
<Step title="Set API Key">
|
||||
@@ -71,7 +71,7 @@ icon: "images"
|
||||
<Step title="Install Package">
|
||||
Install the PraisonAI package:
|
||||
```bash
|
||||
pip install praisonai
|
||||
pip install praisonai opencv-python moviepy
|
||||
```
|
||||
</Step>
|
||||
<Step title="Set API Key">
|
||||
|
||||
@@ -0,0 +1,352 @@
|
||||
---
|
||||
title: "RAG Agents"
|
||||
description: "Learn how to create AI agents that can efficiently interact with vector databases for knowledge retrieval and storage."
|
||||
icon: "database"
|
||||
---
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
In[Input] --> RAGAgent[("RAG Agent")]
|
||||
VDB[(Vector DB)] --> RAGAgent
|
||||
RAGAgent --> Task[Knowledge Task]
|
||||
Task --> |Query| VDB
|
||||
Task --> Out[Output]
|
||||
|
||||
style In fill:#8B0000,color:#fff
|
||||
style RAGAgent fill:#2E8B57,color:#fff,shape:circle
|
||||
style VDB fill:#4169E1,color:#fff,shape:cylinder
|
||||
style Task fill:#2E8B57,color:#fff
|
||||
style Out fill:#8B0000,color:#fff
|
||||
```
|
||||
|
||||
A knowledge-centric workflow where RAG (Retrieval Augmented Generation) agents interact with vector databases to store and retrieve information efficiently, enabling sophisticated question-answering and information retrieval capabilities.
|
||||
|
||||
## Quick Start
|
||||
|
||||
<Steps>
|
||||
<Step title="Install Package">
|
||||
Install PraisonAI Agents with knowledge support:
|
||||
```bash
|
||||
pip install "praisonaiagents[knowledge]"
|
||||
```
|
||||
</Step>
|
||||
|
||||
<Step title="Set API Key">
|
||||
Set your OpenAI API key:
|
||||
```bash
|
||||
export OPENAI_API_KEY=xxxxx
|
||||
```
|
||||
</Step>
|
||||
|
||||
<Step title="Create Script">
|
||||
Create a new file `app.py`:
|
||||
```python
|
||||
from praisonaiagents import Agent
|
||||
|
||||
agent = Agent(
|
||||
name="Knowledge Agent",
|
||||
instructions="You answer questions based on the provided knowledge.",
|
||||
knowledge=["small.pdf"], # Indexing
|
||||
)
|
||||
|
||||
agent.start("What is KAG in one line?") # Retrieval
|
||||
```
|
||||
</Step>
|
||||
</Steps>
|
||||
|
||||
## Data Indexing and Retrieval Agents
|
||||
|
||||
<Note>
|
||||
Indexing and Ingestion are relatively the same.
|
||||
</Note>
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
subgraph In[Input]
|
||||
PDF[PDF]
|
||||
TXT[TXT]
|
||||
MD[MD]
|
||||
end
|
||||
|
||||
subgraph Router[Vector Store]
|
||||
DB[(Vector DB)]
|
||||
end
|
||||
|
||||
subgraph Out[Agents]
|
||||
A1[Agent 1]
|
||||
A2[Agent 2]
|
||||
A3[Agent 3]
|
||||
end
|
||||
|
||||
In --> Router
|
||||
Router --> A1
|
||||
Router --> A2
|
||||
Router --> A3
|
||||
|
||||
style In fill:#8B0000,color:#fff
|
||||
style Router fill:#2E8B57,color:#fff
|
||||
style Out fill:#8B0000,color:#fff
|
||||
```
|
||||
|
||||
The simplest way to create a knowledge-based agent is without any configuration:
|
||||
|
||||
```python
|
||||
from praisonaiagents import Agent
|
||||
|
||||
agent = Agent(
|
||||
name="Knowledge Agent",
|
||||
instructions="You answer questions based on the provided knowledge.",
|
||||
knowledge=["small.pdf"] # Indexing
|
||||
)
|
||||
|
||||
agent.start("What is KAG in one line?") # Retrieval
|
||||
```
|
||||
|
||||
### Advanced Configuration
|
||||
|
||||
For more control over the knowledge base, you can specify a configuration:
|
||||
|
||||
```python
|
||||
from praisonaiagents import Agent
|
||||
|
||||
config = {
|
||||
"vector_store": {
|
||||
"provider": "chroma",
|
||||
"config": {
|
||||
"collection_name": "praison",
|
||||
"path": ".praison",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
agent = Agent(
|
||||
name="Knowledge Agent",
|
||||
instructions="You answer questions based on the provided knowledge.",
|
||||
knowledge=["small.pdf"], # Indexing
|
||||
knowledge_config=config # Configuration
|
||||
)
|
||||
|
||||
agent.start("What is KAG in one line?") # Retrieval
|
||||
```
|
||||
|
||||
### Multi-Agent Knowledge System
|
||||
|
||||
For more complex scenarios, you can create a knowledge-based system with multiple agents:
|
||||
|
||||
```python
|
||||
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": "praison",
|
||||
"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"], # Indexing
|
||||
knowledge_config=config, # Configuration
|
||||
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 # Agent
|
||||
)
|
||||
|
||||
# Create and start the agents
|
||||
agents = PraisonAIAgents(
|
||||
agents=[knowledge_agent],
|
||||
tasks=[knowledge_task],
|
||||
process="sequential",
|
||||
user_id="user1" # User ID
|
||||
)
|
||||
|
||||
# Start execution
|
||||
result = agents.start() # Retrieval
|
||||
```
|
||||
|
||||
## Retrieval Agents
|
||||
|
||||
<Note>
|
||||
Retrieval is the process of querying the vector database for information.
|
||||
Considering there is data already in the Vector Database.
|
||||
</Note>
|
||||
|
||||
<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 in your terminal:
|
||||
```bash
|
||||
export OPENAI_API_KEY=your_api_key_here
|
||||
```
|
||||
</Step>
|
||||
|
||||
<Step title="Create a file">
|
||||
Create a new file `rag_agent.py` with the basic setup:
|
||||
```python
|
||||
from praisonaiagents import Agent, Task, PraisonAIAgents
|
||||
|
||||
# Define the configuration for the Knowledge instance
|
||||
config = {
|
||||
"vector_store": {
|
||||
"provider": "chroma",
|
||||
"config": {
|
||||
"collection_name": "praison",
|
||||
"path": ".praison"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# Create an agent
|
||||
rag_agent = Agent(
|
||||
name="RAG Agent",
|
||||
role="Information Specialist",
|
||||
goal="Retrieve knowledge efficiently",
|
||||
llm="gpt-4o-mini"
|
||||
)
|
||||
|
||||
# Define a task for the agent
|
||||
rag_task = Task(
|
||||
name="RAG Task",
|
||||
description="What is KAG?",
|
||||
expected_output="Answer to the question",
|
||||
agent=rag_agent,
|
||||
context=[config] # Retrieval : Vector Database provided as context
|
||||
)
|
||||
|
||||
# Build Agents
|
||||
agents = PraisonAIAgents(
|
||||
agents=[rag_agent],
|
||||
tasks=[rag_task],
|
||||
user_id="user1"
|
||||
)
|
||||
|
||||
# Start Agents
|
||||
agents.start()
|
||||
```
|
||||
</Step>
|
||||
|
||||
<Step title="Start Agents">
|
||||
Type this in your terminal to run your agents:
|
||||
```bash
|
||||
python rag_agent.py
|
||||
```
|
||||
</Step>
|
||||
</Steps>
|
||||
|
||||
<Note>
|
||||
**Requirements**
|
||||
- Python 3.10 or higher
|
||||
- OpenAI API key. Generate OpenAI API key [here](https://platform.openai.com/api-keys). Use Other models using [this guide](/models).
|
||||
- ChromaDB or other supported vector database
|
||||
</Note>
|
||||
|
||||
### Adding Knowledge to RAG Agents
|
||||
|
||||
```python
|
||||
from praisonaiagents import Agent
|
||||
|
||||
config = {
|
||||
"vector_store": {
|
||||
"provider": "chroma",
|
||||
"config": {
|
||||
"collection_name": "praison",
|
||||
"path": ".praison",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
agent = Agent(
|
||||
name="Knowledge Agent",
|
||||
instructions="You answer questions based on the provided knowledge.",
|
||||
knowledge=["small.pdf"], # Indexing
|
||||
knowledge_config=config # Configuration
|
||||
)
|
||||
|
||||
agent.start("What is KAG in one line?") # Retrieval
|
||||
```
|
||||
|
||||
## Understanding RAG Agents
|
||||
|
||||
<Card title="What are RAG Agents?" icon="question">
|
||||
RAG (Retrieval Augmented Generation) agents enable:
|
||||
- Efficient knowledge retrieval
|
||||
- Semantic search capabilities
|
||||
- Persistent knowledge storage
|
||||
- Context-aware responses
|
||||
</Card>
|
||||
|
||||
## Features
|
||||
|
||||
<CardGroup cols={2}>
|
||||
<Card title="RAG Architecture" icon="database">
|
||||
Store and manage vector embeddings efficiently.
|
||||
</Card>
|
||||
<Card title="Semantic Search" icon="magnifying-glass">
|
||||
Find relevant information using semantic similarity.
|
||||
</Card>
|
||||
<Card title="Knowledge Integration" icon="brain">
|
||||
Seamlessly integrate with existing knowledge bases.
|
||||
</Card>
|
||||
<Card title="Context Management" icon="layer-group">
|
||||
Handle complex contextual queries and responses.
|
||||
</Card>
|
||||
</CardGroup>
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
<CardGroup cols={2}>
|
||||
<Card title="RAG Issues" icon="triangle-exclamation">
|
||||
If RAG system isn't working:
|
||||
- Check database configuration
|
||||
- Verify connection settings
|
||||
- Enable verbose mode for debugging
|
||||
</Card>
|
||||
|
||||
<Card title="Query Issues" icon="gauge-high">
|
||||
If queries aren't returning expected results:
|
||||
- Check embedding quality
|
||||
- Verify search parameters
|
||||
- Monitor similarity thresholds
|
||||
</Card>
|
||||
</CardGroup>
|
||||
|
||||
## Next Steps
|
||||
|
||||
<CardGroup cols={2}>
|
||||
<Card title="AutoAgents" icon="robot" href="./autoagents">
|
||||
Learn about automatically created and managed AI agents
|
||||
</Card>
|
||||
<Card title="Mini Agents" icon="microchip" href="./mini">
|
||||
Explore lightweight, focused AI agents
|
||||
</Card>
|
||||
</CardGroup>
|
||||
|
||||
<Note>
|
||||
For optimal results, ensure your vector database is properly configured and indexed for your specific use case.
|
||||
</Note>
|
||||
@@ -0,0 +1,138 @@
|
||||
---
|
||||
title: "Repetitive Agents"
|
||||
description: "Learn how to create AI agents that can efficiently handle repetitive tasks through automated loops."
|
||||
icon: "repeat"
|
||||
---
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
In[Input] --> LoopAgent[("Looping Agent")]
|
||||
LoopAgent --> Task[Task]
|
||||
Task --> |Next iteration| LoopAgent
|
||||
Task --> |Done| Out[Output]
|
||||
|
||||
style In fill:#8B0000,color:#fff
|
||||
style LoopAgent fill:#2E8B57,color:#fff,shape:circle
|
||||
style Task fill:#2E8B57,color:#fff
|
||||
style Out fill:#8B0000,color:#fff
|
||||
```
|
||||
|
||||
A workflow optimization pattern where agents handle repetitive tasks through automated loops, processing multiple instances efficiently while maintaining consistency.
|
||||
|
||||
## 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 in your terminal:
|
||||
```bash
|
||||
export OPENAI_API_KEY=your_api_key_here
|
||||
```
|
||||
</Step>
|
||||
|
||||
<Step title="Create a file">
|
||||
Create a new file `repetitive_agent.py` with the basic setup:
|
||||
```python
|
||||
from praisonaiagents import Agent, Task, PraisonAIAgents
|
||||
|
||||
agent = Agent(
|
||||
instructions="You are a loop agent that creating a loop of tasks."
|
||||
)
|
||||
|
||||
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()
|
||||
```
|
||||
</Step>
|
||||
|
||||
<Step title="Start Agents">
|
||||
Type this in your terminal to run your agents:
|
||||
```bash
|
||||
python repetitive_agent.py
|
||||
```
|
||||
</Step>
|
||||
</Steps>
|
||||
|
||||
<Note>
|
||||
**Requirements**
|
||||
- Python 3.10 or higher
|
||||
- OpenAI API key. Generate OpenAI API key [here](https://platform.openai.com/api-keys). Use Other models using [this guide](/models).
|
||||
</Note>
|
||||
|
||||
## Understanding Repetitive Agents
|
||||
|
||||
<Card title="What are Repetitive Agents?" icon="question">
|
||||
Repetitive agents enable:
|
||||
- Automated task loops
|
||||
- Batch processing
|
||||
- Consistent task execution
|
||||
- Efficient handling of multiple similar tasks
|
||||
</Card>
|
||||
|
||||
## Features
|
||||
|
||||
<CardGroup cols={2}>
|
||||
<Card title="Task Looping" icon="repeat">
|
||||
Process multiple tasks through automated loops.
|
||||
</Card>
|
||||
<Card title="Batch Processing" icon="layer-group">
|
||||
Handle multiple similar tasks efficiently.
|
||||
</Card>
|
||||
<Card title="Input Management" icon="file-csv">
|
||||
Process tasks from structured input files.
|
||||
</Card>
|
||||
<Card title="Progress Tracking" icon="chart-line">
|
||||
Monitor task completion and progress.
|
||||
</Card>
|
||||
</CardGroup>
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
<CardGroup cols={2}>
|
||||
<Card title="Loop Issues" icon="triangle-exclamation">
|
||||
If loops aren't working as expected:
|
||||
- Verify input file format
|
||||
- Check task configurations
|
||||
- Enable verbose mode for debugging
|
||||
</Card>
|
||||
|
||||
<Card title="Performance Issues" icon="gauge-high">
|
||||
If processing is slow:
|
||||
- Check batch sizes
|
||||
- Verify resource allocation
|
||||
- Monitor memory usage
|
||||
</Card>
|
||||
</CardGroup>
|
||||
|
||||
## Next Steps
|
||||
|
||||
<CardGroup cols={2}>
|
||||
<Card title="AutoAgents" icon="robot" href="./autoagents">
|
||||
Learn about automatically created and managed AI agents
|
||||
</Card>
|
||||
<Card title="Mini Agents" icon="microchip" href="./mini">
|
||||
Explore lightweight, focused AI agents
|
||||
</Card>
|
||||
</CardGroup>
|
||||
|
||||
<Note>
|
||||
For optimal results, ensure your input files are properly formatted and your task configurations are appropriate for your use case.
|
||||
</Note>
|
||||
+15
-2
@@ -108,7 +108,8 @@
|
||||
"features/autonomous-workflow",
|
||||
"features/parallelisation",
|
||||
"features/promptchaining",
|
||||
"features/evaluator-optimiser"
|
||||
"features/evaluator-optimiser",
|
||||
"features/repetitive"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -116,6 +117,7 @@
|
||||
"pages": [
|
||||
"features/autoagents",
|
||||
"features/selfreflection",
|
||||
"features/rag",
|
||||
"features/reasoning",
|
||||
"features/multimodal",
|
||||
"features/langchain",
|
||||
@@ -139,6 +141,7 @@
|
||||
"models/anthropic",
|
||||
"models/cohere",
|
||||
"models/mistral",
|
||||
"models/deepseek",
|
||||
"models/other"
|
||||
]
|
||||
},
|
||||
@@ -146,6 +149,8 @@
|
||||
"group": "Examples",
|
||||
"pages": [
|
||||
"examples/examples",
|
||||
"examples/code-analysis",
|
||||
"examples/hackathon-judge",
|
||||
"examples/predictive-maintenance",
|
||||
"examples/emergency-response",
|
||||
"examples/code-review",
|
||||
@@ -240,7 +245,15 @@
|
||||
"pages": [
|
||||
"ui/overview",
|
||||
"ui/gradio",
|
||||
"ui/streamlit",
|
||||
{
|
||||
"group": "Streamlit",
|
||||
"icon": "pen-paintbrush",
|
||||
"pages": [
|
||||
"ui/streamlit",
|
||||
"ui/streamlit/code-analysis-streamlit",
|
||||
"ui/streamlit/hackathon-judge-streamlit"
|
||||
]
|
||||
},
|
||||
"ui/ui",
|
||||
"ui/chat",
|
||||
"ui/code"
|
||||
|
||||
@@ -0,0 +1,253 @@
|
||||
---
|
||||
title: "DeepSeek Agents"
|
||||
|
||||
description: "Learn how to use Deepseek models with PraisonAI Agents for various applications."
|
||||
icon: "brain"
|
||||
---
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
In[Input] --> Ollama[("Ollama")]
|
||||
Ollama --> DS[("Deepseek")]
|
||||
DS --> Basic[Basic Agent]
|
||||
DS --> RAG[RAG Agent]
|
||||
DS --> UI[UI Agent]
|
||||
Basic --> Out1[Output]
|
||||
RAG --> Out2[Output]
|
||||
UI --> Out3[Output]
|
||||
|
||||
style In fill:#8B0000,color:#fff
|
||||
style Ollama fill:#4169E1,color:#fff,shape:circle
|
||||
style DS fill:#2E8B57,color:#fff,shape:circle
|
||||
style Basic fill:#2E8B57,color:#fff
|
||||
style RAG fill:#2E8B57,color:#fff
|
||||
style UI fill:#2E8B57,color:#fff
|
||||
style Out1 fill:#8B0000,color:#fff
|
||||
style Out2 fill:#8B0000,color:#fff
|
||||
style Out3 fill:#8B0000,color:#fff
|
||||
```
|
||||
|
||||
Learn how to use Deepseek models with PraisonAI Agents through Ollama integration for basic queries, RAG applications, and interactive UI implementations.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
<Steps>
|
||||
<Step title="Install Ollama">
|
||||
First, install Ollama on your system:
|
||||
```bash
|
||||
curl -fsSL https://ollama.com/install.sh | sh
|
||||
```
|
||||
</Step>
|
||||
|
||||
<Step title="Pull Deepseek Model">
|
||||
Pull the Deepseek model from Ollama:
|
||||
```bash
|
||||
ollama pull deepseek-r1
|
||||
```
|
||||
</Step>
|
||||
|
||||
<Step title="Install Package">
|
||||
Install PraisonAI Agents:
|
||||
```bash
|
||||
pip install "praisonaiagents[knowledge]" ollama streamlit
|
||||
```
|
||||
|
||||
<Note>
|
||||
Streamlit for UI is optional.
|
||||
Ollama is required for Local RAG Agents.
|
||||
praisonaiagents[knowledge] is for RAG Agents. praisonaiagents is for Basic Agents.
|
||||
</Note>
|
||||
</Step>
|
||||
|
||||
<Step title="Set Environment">
|
||||
Set Ollama as your base URL:
|
||||
```bash
|
||||
export OPENAI_BASE_URL=http://localhost:11434/v1
|
||||
export OPENAI_API_KEY=fake-key
|
||||
```
|
||||
</Step>
|
||||
</Steps>
|
||||
|
||||
## Basic Usage
|
||||
|
||||
The simplest way to use Deepseek with PraisonAI Agents:
|
||||
|
||||
```python
|
||||
from praisonaiagents import Agent
|
||||
|
||||
agent = Agent(instructions="You are helpful Assisant", llm="deepseek-r1")
|
||||
|
||||
agent.start("Why sky is Blue?")
|
||||
```
|
||||
|
||||
## RAG Implementation
|
||||
|
||||
Use Deepseek with RAG capabilities for knowledge-based interactions:
|
||||
|
||||
```python
|
||||
from praisonaiagents import Agent
|
||||
|
||||
config = {
|
||||
"vector_store": {
|
||||
"provider": "chroma",
|
||||
"config": {
|
||||
"collection_name": "praison",
|
||||
"path": ".praison"
|
||||
}
|
||||
},
|
||||
"llm": {
|
||||
"provider": "ollama",
|
||||
"config": {
|
||||
"model": "deepseek-r1:latest",
|
||||
"temperature": 0,
|
||||
"max_tokens": 8000,
|
||||
"ollama_base_url": "http://localhost:11434",
|
||||
},
|
||||
},
|
||||
"embedder": {
|
||||
"provider": "ollama",
|
||||
"config": {
|
||||
"model": "nomic-embed-text:latest",
|
||||
"ollama_base_url": "http://localhost:11434",
|
||||
"embedding_dims": 1536
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
agent = Agent(
|
||||
name="Knowledge Agent",
|
||||
instructions="You answer questions based on the provided knowledge.",
|
||||
knowledge=["kag-research-paper.pdf"], # Indexing
|
||||
knowledge_config=config,
|
||||
user_id="user1",
|
||||
llm="deepseek-r1"
|
||||
)
|
||||
|
||||
agent.start("What is KAG in one line?") # Retrieval
|
||||
```
|
||||
|
||||
## Interactive UI with Streamlit
|
||||
|
||||
Create an interactive chat interface using Streamlit:
|
||||
|
||||
```python
|
||||
import streamlit as st
|
||||
from praisonaiagents import Agent
|
||||
|
||||
def init_agent():
|
||||
config = {
|
||||
"vector_store": {
|
||||
"provider": "chroma",
|
||||
"config": {
|
||||
"collection_name": "praison",
|
||||
"path": ".praison"
|
||||
}
|
||||
},
|
||||
"llm": {
|
||||
"provider": "ollama",
|
||||
"config": {
|
||||
"model": "deepseek-r1:latest",
|
||||
"temperature": 0,
|
||||
"max_tokens": 8000,
|
||||
"ollama_base_url": "http://localhost:11434",
|
||||
},
|
||||
},
|
||||
"embedder": {
|
||||
"provider": "ollama",
|
||||
"config": {
|
||||
"model": "nomic-embed-text:latest",
|
||||
"ollama_base_url": "http://localhost:11434",
|
||||
"embedding_dims": 1536
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
return Agent(
|
||||
name="Knowledge Agent",
|
||||
instructions="You answer questions based on the provided knowledge.",
|
||||
knowledge=["kag-research-paper.pdf"],
|
||||
knowledge_config=config,
|
||||
user_id="user1",
|
||||
llm="deepseek-r1"
|
||||
)
|
||||
|
||||
st.title("Knowledge Agent Chat")
|
||||
|
||||
if "agent" not in st.session_state:
|
||||
st.session_state.agent = init_agent()
|
||||
st.session_state.messages = []
|
||||
|
||||
if "messages" in st.session_state:
|
||||
for message in st.session_state.messages:
|
||||
with st.chat_message(message["role"]):
|
||||
st.markdown(message["content"])
|
||||
|
||||
prompt = st.chat_input("Ask a question...")
|
||||
|
||||
if prompt:
|
||||
st.session_state.messages.append({"role": "user", "content": prompt})
|
||||
with st.chat_message("user"):
|
||||
st.markdown(prompt)
|
||||
|
||||
with st.chat_message("assistant"):
|
||||
response = st.session_state.agent.start(prompt)
|
||||
st.markdown(response)
|
||||
st.session_state.messages.append({"role": "assistant", "content": response})
|
||||
```
|
||||
|
||||
## Running the UI
|
||||
|
||||
<Steps>
|
||||
<Step title="Install Streamlit">
|
||||
Install Streamlit if you haven't already:
|
||||
```bash
|
||||
pip install streamlit
|
||||
```
|
||||
</Step>
|
||||
|
||||
<Step title="Save and Run">
|
||||
Save the UI code in a file (e.g., `app.py`) and run:
|
||||
```bash
|
||||
streamlit run app.py
|
||||
```
|
||||
</Step>
|
||||
</Steps>
|
||||
|
||||
## Features
|
||||
|
||||
<CardGroup cols={2}>
|
||||
<Card title="Local Deployment" icon="server">
|
||||
Run Deepseek models locally through Ollama.
|
||||
</Card>
|
||||
<Card title="RAG Capabilities" icon="database">
|
||||
Integrate with vector databases for knowledge retrieval.
|
||||
</Card>
|
||||
<Card title="Interactive UI" icon="desktop">
|
||||
Create chat interfaces with Streamlit integration.
|
||||
</Card>
|
||||
<Card title="Custom Configuration" icon="gear">
|
||||
Configure model parameters and embedding settings.
|
||||
</Card>
|
||||
</CardGroup>
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
<CardGroup cols={2}>
|
||||
<Card title="Ollama Issues" icon="triangle-exclamation">
|
||||
If Ollama isn't working:
|
||||
- Check if Ollama is running
|
||||
- Verify model is downloaded
|
||||
- Check port availability
|
||||
</Card>
|
||||
|
||||
<Card title="Performance Issues" icon="gauge-high">
|
||||
If responses are slow:
|
||||
- Check system resources
|
||||
- Adjust max_tokens
|
||||
- Monitor memory usage
|
||||
</Card>
|
||||
</CardGroup>
|
||||
|
||||
<Note>
|
||||
For optimal performance, ensure your system meets the minimum requirements for running Deepseek models locally through Ollama.
|
||||
</Note>
|
||||
+122
-7
@@ -1,12 +1,123 @@
|
||||
---
|
||||
title: "Google Gemini"
|
||||
title: "Google Gemini Agents"
|
||||
sidebarTitle: "Google Gemini"
|
||||
description: "Instructions for integrating Google's Gemini models with PraisonAI, including API setup and configuration details"
|
||||
icon: "google"
|
||||
---
|
||||
|
||||
# Add Google Gemini to Praison AI
|
||||
```mermaid
|
||||
flowchart LR
|
||||
In[Input] --> API[("Google API")]
|
||||
API --> Gemini[("Gemini")]
|
||||
Gemini --> Basic[Basic Agent]
|
||||
Gemini --> Multi[Multi-Agents]
|
||||
Gemini --> YAML[No-Code]
|
||||
Basic --> Out1[Output]
|
||||
Multi --> Out2[Output]
|
||||
YAML --> Out3[Output]
|
||||
|
||||
style In fill:#8B0000,color:#fff
|
||||
style API fill:#4169E1,color:#fff,shape:circle
|
||||
style Gemini fill:#2E8B57,color:#fff,shape:circle
|
||||
style Basic fill:#2E8B57,color:#fff
|
||||
style Multi fill:#2E8B57,color:#fff
|
||||
style YAML fill:#2E8B57,color:#fff
|
||||
style Out1 fill:#8B0000,color:#fff
|
||||
style Out2 fill:#8B0000,color:#fff
|
||||
style Out3 fill:#8B0000,color:#fff
|
||||
```
|
||||
|
||||
## Code
|
||||
## Prerequisites
|
||||
|
||||
<Steps>
|
||||
<Step title="Install Package">
|
||||
First, install PraisonAI Agents:
|
||||
```bash
|
||||
pip install "praisonaiagents[llm]"
|
||||
```
|
||||
|
||||
<Note>
|
||||
praisonaiagents[llm] includes all Google Gemini dependencies.
|
||||
For No-Code implementation, also install: pip install langchain-google-genai
|
||||
</Note>
|
||||
</Step>
|
||||
|
||||
<Step title="Set API Key">
|
||||
Set your Gemini API key:
|
||||
```bash
|
||||
export GEMINI_API_KEY=xxxxxxxxxxx
|
||||
```
|
||||
</Step>
|
||||
|
||||
<Step title="Code">
|
||||
```python
|
||||
from praisonaiagents import Agent
|
||||
|
||||
agent = Agent(
|
||||
instructions="You are a helpful assistant",
|
||||
llm="gemini/gemini-1.5-flash-8b",
|
||||
self_reflect=True,
|
||||
verbose=True
|
||||
)
|
||||
|
||||
agent.start("Why sky is Blue?")
|
||||
```
|
||||
</Step>
|
||||
</Steps>
|
||||
|
||||
## Code Implementation
|
||||
|
||||
### Basic Usage
|
||||
|
||||
The simplest way to use Gemini with PraisonAI Agents:
|
||||
|
||||
```python
|
||||
from praisonaiagents import Agent
|
||||
|
||||
agent = Agent(
|
||||
instructions="You are a helpful assistant",
|
||||
llm="gemini/gemini-1.5-flash-8b",
|
||||
self_reflect=True,
|
||||
verbose=True
|
||||
)
|
||||
|
||||
agent.start("Why sky is Blue?")
|
||||
```
|
||||
|
||||
### Multi-Agent Setup
|
||||
|
||||
Create multiple agents working together:
|
||||
|
||||
```python
|
||||
from praisonaiagents import Agent, Task, PraisonAIAgents
|
||||
|
||||
agent = Agent(
|
||||
instructions="You are a helpful assistant",
|
||||
llm="gemini/gemini-1.5-flash-8b",
|
||||
self_reflect=True,
|
||||
verbose=True
|
||||
)
|
||||
|
||||
task = Task(
|
||||
description="Why sky is Blue?",
|
||||
agent=agent,
|
||||
)
|
||||
|
||||
agents = PraisonAIAgents(
|
||||
agents=[agent],
|
||||
tasks=[task],
|
||||
)
|
||||
|
||||
agents.start()
|
||||
```
|
||||
|
||||
<Note>
|
||||
This uses Litellm to connect to Google Gemini.
|
||||
</Note>
|
||||
|
||||
## Alternative Setup
|
||||
|
||||
### Using Environment Variables
|
||||
|
||||
<AccordionGroup>
|
||||
<Accordion title="Google Gemini" defaultOpen>
|
||||
@@ -16,16 +127,18 @@ icon: "google"
|
||||
```
|
||||
</Accordion>
|
||||
</AccordionGroup>
|
||||
## No Code
|
||||
|
||||
## No-Code Implementation
|
||||
|
||||
### Setup
|
||||
```bash
|
||||
pip install langchain-google-genai
|
||||
```
|
||||
```bash
|
||||
export GOOGLE_API_KEY=xxxxxxxxxx
|
||||
```
|
||||
|
||||
### agents.yaml file
|
||||
### YAML Configuration
|
||||
|
||||
Create an `agents.yaml` file:
|
||||
|
||||
```yaml
|
||||
framework: crewai
|
||||
@@ -48,6 +161,8 @@ roles:
|
||||
- ''
|
||||
```
|
||||
|
||||
## Additional Resources
|
||||
|
||||
| PraisonAI Chat | PraisonAI Code | PraisonAI (Multi-Agents) |
|
||||
| --- | --- | --- |
|
||||
| [Litellm](https://litellm.vercel.app/docs/providers) | [Litellm](https://litellm.vercel.app/docs/providers) | [Models](../models.md) |
|
||||
@@ -12,6 +12,46 @@ export REDDIT_CLIENT_SECRET=xxxxxx
|
||||
export REDDIT_CLIENT_ID=xxxxxx
|
||||
```
|
||||
|
||||
[USER] in this format script:APP:v1.0(by/u/USERNAME)
|
||||
|
||||
```bash
|
||||
pip install praisonai langchain_community praw
|
||||
```
|
||||
|
||||
```bash
|
||||
export OPENAI_API_KEY="Enter your API key"
|
||||
```
|
||||
|
||||
## Code
|
||||
|
||||
### Single Agent
|
||||
|
||||
```python
|
||||
from praisonaiagents import Agent
|
||||
from langchain_community.tools.reddit_search.tool import RedditSearchRun
|
||||
|
||||
agent = Agent(name="RedditSearchAgent",instructions="Search Reddit for information", tools=[RedditSearchRun],)
|
||||
|
||||
agent.start("Search Reddit for information about the latest AI advancements in subreddit all")
|
||||
```
|
||||
|
||||
### Multi Agents
|
||||
|
||||
```python
|
||||
from praisonaiagents import Agent, Task, PraisonAIAgents
|
||||
from langchain_community.tools.reddit_search.tool import RedditSearchRun
|
||||
|
||||
agent = Agent(name="RedditSearchAgent",instructions="Search Reddit for information", tools=[RedditSearchRun],)
|
||||
|
||||
task = Task(description="Search Reddit for information about the latest AI news in subreddit all", agent=agent)
|
||||
|
||||
agents = PraisonAIAgents(agents=[agent],tasks=[task])
|
||||
|
||||
agents.start()
|
||||
```
|
||||
|
||||
## No Code
|
||||
|
||||
tools.py
|
||||
|
||||
```python
|
||||
|
||||
@@ -0,0 +1,333 @@
|
||||
---
|
||||
title: "Code Analysis Agent UI"
|
||||
sidebarTitle: "Code Analysis"
|
||||
description: "Build an interactive web interface for analyzing code quality and providing detailed recommendations using Streamlit and AI agents."
|
||||
icon: "laptop-code"
|
||||
---
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
Input[Input URL] --> Process[Process Code]
|
||||
Process --> Analyze[AI Analysis]
|
||||
Analyze --> Display[Display Results]
|
||||
Display --> Metrics[Show Metrics]
|
||||
Display --> Details[Show Details]
|
||||
|
||||
style Input fill:#8B0000,color:#fff
|
||||
style Process fill:#2E8B57,color:#fff
|
||||
style Analyze fill:#2E8B57,color:#fff
|
||||
style Display fill:#2E8B57,color:#fff
|
||||
style Metrics fill:#2E8B57,color:#fff
|
||||
style Details fill:#2E8B57,color:#fff
|
||||
```
|
||||
|
||||
## What is the Code Analysis Streamlit App?
|
||||
|
||||
The Code Analysis Streamlit App provides a user-friendly web interface for analyzing code repositories and generating comprehensive quality assessments. It combines AI-powered code analysis with an interactive dashboard to display detailed metrics, recommendations, and insights.
|
||||
|
||||
## Features
|
||||
|
||||
<CardGroup cols={2}>
|
||||
<Card title="Repository Analysis" icon="code-branch">
|
||||
Support for GitHub URLs and local code repositories.
|
||||
</Card>
|
||||
<Card title="Real-time Processing" icon="spinner">
|
||||
Live analysis and evaluation of code.
|
||||
</Card>
|
||||
<Card title="Interactive Metrics" icon="chart-column">
|
||||
Visual presentation of code quality metrics.
|
||||
</Card>
|
||||
<Card title="Detailed Reports" icon="file-lines">
|
||||
Comprehensive analysis of code structure and patterns.
|
||||
</Card>
|
||||
<Card title="Best Practices" icon="check-double">
|
||||
Evaluation against industry best practices.
|
||||
</Card>
|
||||
</CardGroup>
|
||||
|
||||
## Quick Start
|
||||
|
||||
<Steps>
|
||||
<Step title="Install Dependencies">
|
||||
Install the required packages:
|
||||
```bash
|
||||
pip install streamlit praisonaiagents gitingest
|
||||
```
|
||||
</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 the App">
|
||||
Create a new file `code_analysis_app.py` with the following code:
|
||||
```python
|
||||
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()
|
||||
```
|
||||
</Step>
|
||||
|
||||
<Step title="Run the App">
|
||||
Start the Streamlit app:
|
||||
```bash
|
||||
streamlit run code_analysis_app.py
|
||||
```
|
||||
</Step>
|
||||
</Steps>
|
||||
|
||||
## Understanding the Interface
|
||||
|
||||
The Streamlit app provides an intuitive interface with the following sections:
|
||||
|
||||
- **Input**: GitHub URL or local path input in the sidebar
|
||||
- **Overall Metrics**: Visual display of key quality scores
|
||||
- Overall Quality
|
||||
- Architecture Score
|
||||
- Maintainability Score
|
||||
- Performance Score
|
||||
- Security Score
|
||||
- Test Coverage
|
||||
- **Detailed Analysis**:
|
||||
- Code Metrics with Findings
|
||||
- Technology Stack Overview
|
||||
- Complexity Metrics
|
||||
- **Key Findings**:
|
||||
- Strengths
|
||||
- Best Practices
|
||||
- Areas for Improvement
|
||||
- Potential Risks
|
||||
- **Additional Information**:
|
||||
- Recommendations
|
||||
- Documentation Quality Assessment
|
||||
|
||||
## Next Steps
|
||||
|
||||
<CardGroup>
|
||||
<Card title="Streamlit Docs" icon="book" href="https://docs.streamlit.io">
|
||||
Learn more about Streamlit features
|
||||
</Card>
|
||||
<Card title="PraisonAI Docs" icon="bolt" href="/introduction">
|
||||
Explore PraisonAI capabilities
|
||||
</Card>
|
||||
<Card title="Examples" icon="code" href="/examples">
|
||||
View more example applications
|
||||
</Card>
|
||||
</CardGroup>
|
||||
@@ -0,0 +1,323 @@
|
||||
---
|
||||
title: "Hackathon Judge Agent UI"
|
||||
sidebarTitle: "Hackathon Judge"
|
||||
description: "Build an interactive web interface for evaluating hackathon projects using Streamlit and AI agents."
|
||||
icon: "desktop"
|
||||
---
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
Upload[Upload Video] --> Process[Process Video]
|
||||
Process --> Evaluate[AI Evaluation]
|
||||
Evaluate --> Display[Display Results]
|
||||
Display --> Scores[Show Scores]
|
||||
Display --> Feedback[Show Feedback]
|
||||
|
||||
style Upload fill:#8B0000,color:#fff
|
||||
style Process fill:#2E8B57,color:#fff
|
||||
style Evaluate fill:#2E8B57,color:#fff
|
||||
style Display fill:#2E8B57,color:#fff
|
||||
style Scores fill:#2E8B57,color:#fff
|
||||
style Feedback fill:#2E8B57,color:#fff
|
||||
```
|
||||
|
||||
## What is the Hackathon Judge Streamlit App?
|
||||
|
||||
The Hackathon Judge Streamlit App provides a user-friendly web interface for evaluating hackathon projects through video demonstrations. It combines the power of AI evaluation with an interactive dashboard to display comprehensive project assessments, scores, and feedback.
|
||||
|
||||
## Features
|
||||
|
||||
<CardGroup cols={2}>
|
||||
<Card title="Video Upload" icon="upload">
|
||||
Easy-to-use interface for uploading project demonstration videos.
|
||||
</Card>
|
||||
<Card title="Real-time Processing" icon="spinner">
|
||||
Live processing and evaluation of uploaded videos.
|
||||
</Card>
|
||||
<Card title="Interactive Dashboard" icon="chart-simple">
|
||||
Visual presentation of scores and metrics.
|
||||
</Card>
|
||||
<Card title="Detailed Feedback" icon="comments">
|
||||
Comprehensive display of evaluation results and recommendations.
|
||||
</Card>
|
||||
<Card title="Market Analysis" icon="briefcase">
|
||||
Visual presentation of market potential and scalability.
|
||||
</Card>
|
||||
</CardGroup>
|
||||
|
||||
## Quick Start
|
||||
|
||||
<Steps>
|
||||
<Step title="Install Dependencies">
|
||||
Install the required packages:
|
||||
```bash
|
||||
pip install streamlit praisonaiagents opencv-python moviepy
|
||||
```
|
||||
</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 the App">
|
||||
Create a new file `hackathon_judge_app.py` with the following code:
|
||||
```python
|
||||
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!")
|
||||
```
|
||||
</Step>
|
||||
|
||||
<Step title="Run the App">
|
||||
Start the Streamlit app:
|
||||
```bash
|
||||
streamlit run hackathon_judge_app.py
|
||||
```
|
||||
</Step>
|
||||
</Steps>
|
||||
|
||||
## Understanding the Interface
|
||||
|
||||
The Streamlit app provides an intuitive interface with the following sections:
|
||||
|
||||
- **Video Upload**: Drag and drop or browse to upload your project demo video
|
||||
- **Overall Score**: A prominent display of the project's overall rating
|
||||
- **Detailed Scores**:
|
||||
- Innovation Score
|
||||
- Technical Complexity
|
||||
- Presentation Quality
|
||||
- User Experience
|
||||
- Project Completeness
|
||||
- **Qualitative Feedback**:
|
||||
- Key Strengths
|
||||
- Areas for Improvement
|
||||
- Technical Highlights
|
||||
- Notable Features
|
||||
- Recommendations
|
||||
- **Market Analysis**:
|
||||
- Market Potential
|
||||
- Scalability Assessment
|
||||
|
||||
## Next Steps
|
||||
|
||||
<CardGroup>
|
||||
<Card title="Streamlit Docs" icon="book" href="https://docs.streamlit.io">
|
||||
Learn more about Streamlit features
|
||||
</Card>
|
||||
<Card title="PraisonAI Docs" icon="bolt" href="/introduction">
|
||||
Explore PraisonAI capabilities
|
||||
</Card>
|
||||
<Card title="Examples" icon="code" href="/examples">
|
||||
View more example applications
|
||||
</Card>
|
||||
</CardGroup>
|
||||
@@ -4,7 +4,7 @@ config = {
|
||||
"vector_store": {
|
||||
"provider": "chroma",
|
||||
"config": {
|
||||
"collection_name": "custom_knowledge",
|
||||
"collection_name": "praison",
|
||||
"path": ".praison",
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
from praisonaiagents import Agent, Task, PraisonAIAgents
|
||||
|
||||
# Define the configuration for the Knowledge instance
|
||||
config = {
|
||||
"vector_store": {
|
||||
"provider": "chroma",
|
||||
"config": {
|
||||
"collection_name": "praison",
|
||||
"path": ".praison"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# Create an agent
|
||||
rag_agent = Agent(
|
||||
name="RAG Agent",
|
||||
role="Information Specialist",
|
||||
goal="Retrieve knowledge efficiently",
|
||||
llm="gpt-4o-mini"
|
||||
)
|
||||
|
||||
# Define a task for the agent
|
||||
rag_task = Task(
|
||||
name="RAG Task",
|
||||
description="What is KAG?",
|
||||
expected_output="Answer to the question",
|
||||
agent=rag_agent,
|
||||
context=[config] # Vector Database provided as context
|
||||
)
|
||||
|
||||
# Build Agents
|
||||
agents = PraisonAIAgents(
|
||||
agents=[rag_agent],
|
||||
tasks=[rag_task],
|
||||
user_id="user1"
|
||||
)
|
||||
|
||||
# Start Agents
|
||||
agents.start()
|
||||
@@ -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()
|
||||
Binary file not shown.
@@ -0,0 +1,9 @@
|
||||
# pip install praisonaiagents
|
||||
# export OPENAI_BASE_URL=http://localhost:11434/v1
|
||||
# ollama pull deepseek-r1
|
||||
|
||||
from praisonaiagents import Agent
|
||||
|
||||
agent = Agent(instructions="You are helpful Assisant", llm="deepseek-r1")
|
||||
|
||||
agent.start("Why sky is Blue?")
|
||||
@@ -0,0 +1,62 @@
|
||||
import streamlit as st
|
||||
from praisonaiagents import Agent
|
||||
|
||||
def init_agent():
|
||||
config = {
|
||||
"vector_store": {
|
||||
"provider": "chroma",
|
||||
"config": {
|
||||
"collection_name": "praison",
|
||||
"path": ".praison"
|
||||
}
|
||||
},
|
||||
"llm": {
|
||||
"provider": "ollama",
|
||||
"config": {
|
||||
"model": "deepseek-r1:latest",
|
||||
"temperature": 0,
|
||||
"max_tokens": 8000,
|
||||
"ollama_base_url": "http://localhost:11434",
|
||||
},
|
||||
},
|
||||
"embedder": {
|
||||
"provider": "ollama",
|
||||
"config": {
|
||||
"model": "nomic-embed-text:latest",
|
||||
"ollama_base_url": "http://localhost:11434",
|
||||
"embedding_dims": 1536
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
return Agent(
|
||||
name="Knowledge Agent",
|
||||
instructions="You answer questions based on the provided knowledge.",
|
||||
knowledge=["kag-research-paper.pdf"],
|
||||
knowledge_config=config,
|
||||
user_id="user1",
|
||||
llm="deepseek-r1"
|
||||
)
|
||||
|
||||
st.title("Knowledge Agent Chat")
|
||||
|
||||
if "agent" not in st.session_state:
|
||||
st.session_state.agent = init_agent()
|
||||
st.session_state.messages = []
|
||||
|
||||
if "messages" in st.session_state:
|
||||
for message in st.session_state.messages:
|
||||
with st.chat_message(message["role"]):
|
||||
st.markdown(message["content"])
|
||||
|
||||
prompt = st.chat_input("Ask a question...")
|
||||
|
||||
if prompt:
|
||||
st.session_state.messages.append({"role": "user", "content": prompt})
|
||||
with st.chat_message("user"):
|
||||
st.markdown(prompt)
|
||||
|
||||
with st.chat_message("assistant"):
|
||||
response = st.session_state.agent.start(prompt)
|
||||
st.markdown(response)
|
||||
st.session_state.messages.append({"role": "assistant", "content": response})
|
||||
@@ -0,0 +1,39 @@
|
||||
from praisonaiagents import Agent
|
||||
|
||||
config = {
|
||||
"vector_store": {
|
||||
"provider": "chroma",
|
||||
"config": {
|
||||
"collection_name": "praison",
|
||||
"path": ".praison"
|
||||
}
|
||||
},
|
||||
"llm": {
|
||||
"provider": "ollama",
|
||||
"config": {
|
||||
"model": "deepseek-r1:latest",
|
||||
"temperature": 0,
|
||||
"max_tokens": 8000,
|
||||
"ollama_base_url": "http://localhost:11434",
|
||||
},
|
||||
},
|
||||
"embedder": {
|
||||
"provider": "ollama",
|
||||
"config": {
|
||||
"model": "nomic-embed-text:latest",
|
||||
"ollama_base_url": "http://localhost:11434",
|
||||
"embedding_dims": 1536
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
agent = Agent(
|
||||
name="Knowledge Agent",
|
||||
instructions="You answer questions based on the provided knowledge.",
|
||||
knowledge=["kag-research-paper.pdf"], # Indexing
|
||||
knowledge_config=config,
|
||||
user_id="user1",
|
||||
llm="deepseek-r1"
|
||||
)
|
||||
|
||||
agent.start("What is KAG in one line?") # Retrieval
|
||||
@@ -0,0 +1,45 @@
|
||||
from praisonaiagents import Agent
|
||||
|
||||
# Detailed LLM configuration
|
||||
llm_config = {
|
||||
"model": "gemini/gemini-1.5-flash-latest", # Model name without provider prefix
|
||||
|
||||
# Core settings
|
||||
"temperature": 0.7, # Controls randomness (like temperature)
|
||||
"timeout": 30, # Timeout in seconds
|
||||
"top_p": 0.9, # Nucleus sampling parameter
|
||||
"max_tokens": 1000, # Max tokens in response
|
||||
|
||||
# Advanced parameters
|
||||
"presence_penalty": 0.1, # Penalize repetition of topics (-2.0 to 2.0)
|
||||
"frequency_penalty": 0.1, # Penalize token repetition (-2.0 to 2.0)
|
||||
|
||||
# API settings (optional)
|
||||
"api_key": None, # Your API key (or use environment variable)
|
||||
"base_url": None, # Custom API endpoint if needed
|
||||
|
||||
# Response formatting
|
||||
"response_format": { # Force specific response format
|
||||
"type": "text" # Options: "text", "json_object"
|
||||
},
|
||||
|
||||
# Additional controls
|
||||
"seed": 42, # For reproducible responses
|
||||
"stop_phrases": ["##", "END"], # Custom stop sequences
|
||||
}
|
||||
|
||||
agent = Agent(
|
||||
instructions="You are a helpful Assistant specialized in scientific explanations. "
|
||||
"Provide clear, accurate, and engaging responses.",
|
||||
llm=llm_config, # Pass the detailed configuration
|
||||
verbose=True, # Enable detailed output
|
||||
markdown=True, # Format responses in markdown
|
||||
self_reflect=True, # Enable self-reflection
|
||||
max_reflect=3, # Maximum reflection iterations
|
||||
min_reflect=1 # Minimum reflection iterations
|
||||
)
|
||||
|
||||
# Test the agent
|
||||
response = agent.start("Why is the sky blue? Please explain in simple terms.")
|
||||
|
||||
print(response)
|
||||
@@ -0,0 +1,18 @@
|
||||
import asyncio
|
||||
from praisonaiagents import Agent
|
||||
|
||||
async def main():
|
||||
agent = Agent(
|
||||
instructions="You are a helpful assistant",
|
||||
llm="gemini/gemini-1.5-flash-8b",
|
||||
self_reflect=True,
|
||||
verbose=True
|
||||
)
|
||||
|
||||
# Use achat instead of start/chat for async operation
|
||||
response = await agent.achat("Why sky is Blue in 1000 words?")
|
||||
print(response)
|
||||
|
||||
if __name__ == "__main__":
|
||||
# Run the async main function
|
||||
asyncio.run(main())
|
||||
@@ -0,0 +1,10 @@
|
||||
from praisonaiagents import Agent
|
||||
|
||||
agent = Agent(
|
||||
instructions="You are a helpful assistant",
|
||||
llm="gemini/gemini-1.5-flash-8b",
|
||||
self_reflect=True,
|
||||
verbose=True
|
||||
)
|
||||
|
||||
agent.start("Why sky is Blue?")
|
||||
@@ -0,0 +1,9 @@
|
||||
# pip install praisonaiagents
|
||||
# export OPENAI_BASE_URL=http://localhost:11434/v1
|
||||
# ollama pull deepseek-r1
|
||||
|
||||
from praisonaiagents import Agent
|
||||
|
||||
agent = Agent(instructions="You are helpful Assisant", llm="deepseek-r1")
|
||||
|
||||
agent.start("Why sky is Blue?")
|
||||
@@ -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,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!")
|
||||
Binary file not shown.
+1
-1
@@ -3,7 +3,7 @@ class Praisonai < Formula
|
||||
|
||||
desc "AI tools for various AI applications"
|
||||
homepage "https://github.com/MervinPraison/PraisonAI"
|
||||
url "https://github.com/MervinPraison/PraisonAI/archive/refs/tags/2.0.50.tar.gz"
|
||||
url "https://github.com/MervinPraison/PraisonAI/archive/refs/tags/2.0.56.tar.gz"
|
||||
sha256 "1828fb9227d10f991522c3f24f061943a254b667196b40b1a3e4a54a8d30ce32" # Replace with actual SHA256 checksum
|
||||
license "MIT"
|
||||
|
||||
|
||||
+1
-1
@@ -56,7 +56,7 @@ class CloudDeployer:
|
||||
file.write("FROM python:3.11-slim\n")
|
||||
file.write("WORKDIR /app\n")
|
||||
file.write("COPY . .\n")
|
||||
file.write("RUN pip install flask praisonai==2.0.50 gunicorn markdown\n")
|
||||
file.write("RUN pip install flask praisonai==2.0.56 gunicorn markdown\n")
|
||||
file.write("EXPOSE 8080\n")
|
||||
file.write('CMD ["gunicorn", "-b", "0.0.0.0:8080", "api:app"]\n')
|
||||
|
||||
|
||||
+4
-4
@@ -1,6 +1,6 @@
|
||||
[project]
|
||||
name = "PraisonAI"
|
||||
version = "2.0.50"
|
||||
version = "2.0.56"
|
||||
description = "PraisonAI is an AI Agents Framework with Self Reflection. PraisonAI application combines PraisonAI Agents, AutoGen, and CrewAI into a low-code solution for building and managing multi-agent LLM systems, focusing on simplicity, customisation, and efficient human-agent collaboration."
|
||||
readme = "README.md"
|
||||
license = ""
|
||||
@@ -12,7 +12,7 @@ dependencies = [
|
||||
"rich>=13.7",
|
||||
"markdown>=3.5",
|
||||
"pyparsing>=3.0.0",
|
||||
"praisonaiagents>=0.0.41",
|
||||
"praisonaiagents>=0.0.49",
|
||||
"python-dotenv>=0.19.0",
|
||||
"instructor>=1.3.3",
|
||||
"PyYAML>=6.0",
|
||||
@@ -84,7 +84,7 @@ autogen = ["pyautogen>=0.2.19", "praisonai-tools>=0.0.7", "crewai"]
|
||||
|
||||
[tool.poetry]
|
||||
name = "PraisonAI"
|
||||
version = "2.0.50"
|
||||
version = "2.0.56"
|
||||
description = "PraisonAI is an AI Agents Framework with Self Reflection. PraisonAI application combines PraisonAI Agents, AutoGen, and CrewAI into a low-code solution for building and managing multi-agent LLM systems, focusing on simplicity, customisation, and efficient human–agent collaboration."
|
||||
authors = ["Mervin Praison"]
|
||||
license = ""
|
||||
@@ -102,7 +102,7 @@ python = ">=3.10,<3.13"
|
||||
rich = ">=13.7"
|
||||
markdown = ">=3.5"
|
||||
pyparsing = ">=3.0.0"
|
||||
praisonaiagents = ">=0.0.41"
|
||||
praisonaiagents = ">=0.0.49"
|
||||
python-dotenv = ">=0.19.0"
|
||||
instructor = ">=1.3.3"
|
||||
PyYAML = ">=6.0"
|
||||
|
||||
@@ -3060,7 +3060,7 @@ wheels = [
|
||||
|
||||
[[package]]
|
||||
name = "praisonai"
|
||||
version = "2.0.50"
|
||||
version = "2.0.56"
|
||||
source = { editable = "." }
|
||||
dependencies = [
|
||||
{ name = "instructor" },
|
||||
@@ -3197,7 +3197,7 @@ requires-dist = [
|
||||
{ name = "plotly", marker = "extra == 'realtime'", specifier = ">=5.24.0" },
|
||||
{ name = "praisonai-tools", marker = "extra == 'autogen'", specifier = ">=0.0.7" },
|
||||
{ name = "praisonai-tools", marker = "extra == 'crewai'", specifier = ">=0.0.7" },
|
||||
{ name = "praisonaiagents", specifier = ">=0.0.41" },
|
||||
{ name = "praisonaiagents", specifier = ">=0.0.49" },
|
||||
{ name = "pyautogen", marker = "extra == 'autogen'", specifier = ">=0.2.19" },
|
||||
{ name = "pydantic", marker = "extra == 'chat'", specifier = "<=2.10.1" },
|
||||
{ name = "pydantic", marker = "extra == 'code'", specifier = "<=2.10.1" },
|
||||
@@ -3250,16 +3250,16 @@ wheels = [
|
||||
|
||||
[[package]]
|
||||
name = "praisonaiagents"
|
||||
version = "0.0.41"
|
||||
version = "0.0.49"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "openai" },
|
||||
{ name = "pydantic" },
|
||||
{ name = "rich" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/d9/39/2e97f6f1ea30948ae93c15cfab67998c999fe859b26481e2dfbddbc5543c/praisonaiagents-0.0.41.tar.gz", hash = "sha256:f8760446ff2bae5957a695616bc23b990bf422054edc2d2d37f2336fd708475b", size = 75859 }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/3c/8a/521d13124d338c5b9d397214656b7f76377ef65c885bcb3859a1484997c5/praisonaiagents-0.0.49.tar.gz", hash = "sha256:257e8572866edb989ed8c3808afec66f65ccdd47f47b5e8916a319863a01cc28", size = 85081 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/63/7a/3da6a6076b2501246a0770d662c5d72158eaacfc10eb4b0938ae43b17d19/praisonaiagents-0.0.41-py3-none-any.whl", hash = "sha256:72dc3e1f5c939ab74898e952bba2b106e3f2b5bf4577f9ff96bc725e17d5b212", size = 93589 },
|
||||
{ url = "https://files.pythonhosted.org/packages/59/64/a80c2cbb760d4fa73383e661301cfacacb49598686fe0da79da3deed9d05/praisonaiagents-0.0.49-py3-none-any.whl", hash = "sha256:b5b1abb9dc668e0f238282c546b76ddbfc51a6d463c6cbc8cf8da4b829a14ff1", size = 103198 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
||||
Reference in new issue
Block a user