mirror of
https://github.com/fsecada01/Pygentic-AI.git
synced 2025-06-19 05:26:04 +00:00
enhancements: reddit intelligence gathering now ingests multiple subreddits, as defined by the comma-delimited REDDIT_SUBREDDIT
env var; added validate_result
validator to swot agent; frontend fixes
This commit is contained in:
parent
ad10d98668
commit
f46479bcc4
@ -10,7 +10,7 @@ annotated-types==0.7.0
|
|||||||
# via
|
# via
|
||||||
# pydantic
|
# pydantic
|
||||||
# sqlmodel-crud-utilities
|
# sqlmodel-crud-utilities
|
||||||
anthropic==0.44.0
|
anthropic==0.45.0
|
||||||
# via pydantic-ai-slim
|
# via pydantic-ai-slim
|
||||||
anyio==4.8.0
|
anyio==4.8.0
|
||||||
# via
|
# via
|
||||||
@ -101,7 +101,7 @@ fastcrud==0.15.5
|
|||||||
# via -r core_requirements.in
|
# via -r core_requirements.in
|
||||||
flower==2.0.1
|
flower==2.0.1
|
||||||
# via -r core_requirements.in
|
# via -r core_requirements.in
|
||||||
google-auth==2.37.0
|
google-auth==2.38.0
|
||||||
# via pydantic-ai-slim
|
# via pydantic-ai-slim
|
||||||
googleapis-common-protos==1.66.0
|
googleapis-common-protos==1.66.0
|
||||||
# via opentelemetry-exporter-otlp-proto-http
|
# via opentelemetry-exporter-otlp-proto-http
|
||||||
|
@ -273,7 +273,7 @@ pygments==2.19.1
|
|||||||
# -c core_requirements.txt
|
# -c core_requirements.txt
|
||||||
# ipython
|
# ipython
|
||||||
# nbconvert
|
# nbconvert
|
||||||
pyinstrument==5.0.0
|
pyinstrument==5.0.1
|
||||||
# via fastapi-debug-toolbar
|
# via fastapi-debug-toolbar
|
||||||
python-dateutil==2.9.0.post0
|
python-dateutil==2.9.0.post0
|
||||||
# via
|
# via
|
||||||
|
@ -80,7 +80,7 @@ dependencies = [
|
|||||||
"aiomysql==0.2.0",
|
"aiomysql==0.2.0",
|
||||||
"amqp==5.3.1",
|
"amqp==5.3.1",
|
||||||
"annotated-types==0.7.0",
|
"annotated-types==0.7.0",
|
||||||
"anthropic==0.44.0",
|
"anthropic==0.45.0",
|
||||||
"anyio==4.8.0",
|
"anyio==4.8.0",
|
||||||
"appdirs==1.4.4",
|
"appdirs==1.4.4",
|
||||||
"asgiref==3.8.1",
|
"asgiref==3.8.1",
|
||||||
@ -108,7 +108,7 @@ dependencies = [
|
|||||||
"fastapi==0.115.7",
|
"fastapi==0.115.7",
|
||||||
"fastcrud==0.15.5",
|
"fastcrud==0.15.5",
|
||||||
"flower==2.0.1",
|
"flower==2.0.1",
|
||||||
"google-auth==2.37.0",
|
"google-auth==2.38.0",
|
||||||
"googleapis-common-protos==1.66.0",
|
"googleapis-common-protos==1.66.0",
|
||||||
"greenlet==3.1.1",
|
"greenlet==3.1.1",
|
||||||
"griffe==1.5.5",
|
"griffe==1.5.5",
|
||||||
@ -308,7 +308,7 @@ dev = [
|
|||||||
"pydantic-settings==2.7.1",
|
"pydantic-settings==2.7.1",
|
||||||
"pydantic==2.10.5",
|
"pydantic==2.10.5",
|
||||||
"pygments==2.19.1",
|
"pygments==2.19.1",
|
||||||
"pyinstrument==5.0.0",
|
"pyinstrument==5.0.1",
|
||||||
"python-dateutil==2.9.0.post0",
|
"python-dateutil==2.9.0.post0",
|
||||||
"python-dotenv==1.0.1",
|
"python-dotenv==1.0.1",
|
||||||
"python-json-logger==3.2.1",
|
"python-json-logger==3.2.1",
|
||||||
|
@ -1,12 +1,14 @@
|
|||||||
|
import asyncio
|
||||||
|
|
||||||
import httpx
|
import httpx
|
||||||
from bs4 import BeautifulSoup as soup
|
from bs4 import BeautifulSoup as soup
|
||||||
from pydantic_ai import RunContext
|
from pydantic_ai import ModelRetry, RunContext
|
||||||
|
|
||||||
from backend.core.consts import AI_MODEL
|
from backend.core.consts import AI_MODEL
|
||||||
from backend.core.core import SwotAgentDeps, SwotAnalysis, swot_agent
|
from backend.core.core import SwotAgentDeps, SwotAnalysis, swot_agent
|
||||||
from backend.core.utils import report_tool_usage
|
from backend.core.utils import report_tool_usage
|
||||||
from backend.logger import logger
|
from backend.logger import logger
|
||||||
from backend.utils import get_val
|
from backend.utils import get_val, set_event_loop, windows_sys_event_loop_check
|
||||||
|
|
||||||
|
|
||||||
@swot_agent.tool(prepare=report_tool_usage)
|
@swot_agent.tool(prepare=report_tool_usage)
|
||||||
@ -76,7 +78,7 @@ async def analyze_competition(
|
|||||||
async def get_reddit_insights(
|
async def get_reddit_insights(
|
||||||
ctx: RunContext[SwotAgentDeps],
|
ctx: RunContext[SwotAgentDeps],
|
||||||
query: str,
|
query: str,
|
||||||
subreddit_name: str | None = None,
|
subreddit_names: list[str] | None = None,
|
||||||
):
|
):
|
||||||
"""
|
"""
|
||||||
A tool to gain insights from a subreddit. Data is returned as string
|
A tool to gain insights from a subreddit. Data is returned as string
|
||||||
@ -84,25 +86,87 @@ async def get_reddit_insights(
|
|||||||
|
|
||||||
:param ctx: RunContext[SwotAgentDeps]
|
:param ctx: RunContext[SwotAgentDeps]
|
||||||
:param query: str
|
:param query: str
|
||||||
:param subreddit_name: str
|
:param subreddit_names: str
|
||||||
:return: str
|
:return: str
|
||||||
"""
|
"""
|
||||||
if not subreddit_name:
|
if not subreddit_names:
|
||||||
subreddit_name = get_val("REDDIT_SUBREDDIT", "python")
|
subreddit_names = get_val("REDDIT_SUBREDDIT", "python, ")
|
||||||
subreddit = ctx.deps.reddit_client.subreddit(subreddit_name)
|
subreddit_names = [x.strip() for x in subreddit_names.split(",")]
|
||||||
|
insights = []
|
||||||
|
if len(subreddit_names) <= 3:
|
||||||
|
for name in subreddit_names:
|
||||||
|
subreddit = ctx.deps.reddit_client.subreddit(name)
|
||||||
search_results = subreddit.search(query)
|
search_results = subreddit.search(query)
|
||||||
|
|
||||||
insights = []
|
|
||||||
for post in search_results:
|
for post in search_results:
|
||||||
insights.append(
|
insights.append(
|
||||||
f"Title: {post.title}\n"
|
f"Title: {post.title}\n"
|
||||||
f"URL: {post.url}\n"
|
f"URL: {post.url}\n"
|
||||||
f"Content: {post.selftext}\n",
|
f"Content: {post.selftext}\n",
|
||||||
)
|
)
|
||||||
|
else:
|
||||||
|
windows_sys_event_loop_check()
|
||||||
|
set_event_loop()
|
||||||
|
loop = asyncio.get_event_loop()
|
||||||
|
tasks = [
|
||||||
|
asyncio.ensure_future(
|
||||||
|
loop.run_in_executor(
|
||||||
|
None, ctx.deps.reddit_client.subreddit(name).search, query
|
||||||
|
)
|
||||||
|
)
|
||||||
|
for name in subreddit_names
|
||||||
|
]
|
||||||
|
results = await asyncio.gather(*tasks)
|
||||||
|
for result in results:
|
||||||
|
for post in result:
|
||||||
|
insights.append(
|
||||||
|
f"Title: {post.title}\n"
|
||||||
|
f"URL: {post.url}\n"
|
||||||
|
f"Content: {post.selftext}\n",
|
||||||
|
)
|
||||||
|
|
||||||
return "\n".join(insights)
|
return "\n".join(insights)
|
||||||
|
|
||||||
|
|
||||||
|
@swot_agent.result_validator
|
||||||
|
def validate_result(
|
||||||
|
_ctx: RunContext[SwotAgentDeps], value: SwotAnalysis
|
||||||
|
) -> SwotAnalysis:
|
||||||
|
"""
|
||||||
|
A validator for SWOT Analysis results; provides greater completeness and
|
||||||
|
quality control
|
||||||
|
:param _ctx: RunContext[SwotAgentDeps]
|
||||||
|
:param value: SwotAnalysis
|
||||||
|
:return: SwotAnalysis
|
||||||
|
"""
|
||||||
|
issues = []
|
||||||
|
min = 2
|
||||||
|
categories = {
|
||||||
|
k.title(): getattr(value, k)
|
||||||
|
for k in ("strengths", "weaknesses", "opportunities", "threats")
|
||||||
|
}
|
||||||
|
|
||||||
|
for cat_name, points in categories.items():
|
||||||
|
if len(points) < min:
|
||||||
|
issues.append(
|
||||||
|
f"{cat_name} should have at least {min} points. "
|
||||||
|
f"Current count is {len(points)}."
|
||||||
|
)
|
||||||
|
|
||||||
|
min_len_analysis = 100
|
||||||
|
if len(value.analysis) < min_len_analysis:
|
||||||
|
issues.append(
|
||||||
|
f"Analysis should have at least {min_len_analysis} "
|
||||||
|
f"characters. Current count is {len(value.analysis)}."
|
||||||
|
)
|
||||||
|
|
||||||
|
if issues:
|
||||||
|
logger.info(f"Validation issues: {issues}")
|
||||||
|
raise ModelRetry("\n".join(issues))
|
||||||
|
|
||||||
|
return value
|
||||||
|
|
||||||
|
|
||||||
async def run_agent(
|
async def run_agent(
|
||||||
url: str,
|
url: str,
|
||||||
deps: SwotAgentDeps = SwotAgentDeps(),
|
deps: SwotAgentDeps = SwotAgentDeps(),
|
||||||
|
@ -1,4 +1,6 @@
|
|||||||
|
import asyncio
|
||||||
import os
|
import os
|
||||||
|
import sys
|
||||||
|
|
||||||
from decouple import config
|
from decouple import config
|
||||||
|
|
||||||
@ -92,3 +94,24 @@ def get_val(val: str, default: str | int | bool | None = None, **kwargs):
|
|||||||
)
|
)
|
||||||
|
|
||||||
return val
|
return val
|
||||||
|
|
||||||
|
|
||||||
|
def windows_sys_event_loop_check():
|
||||||
|
"""
|
||||||
|
A function that sets the event loop policy to a Windows-specific one.
|
||||||
|
This is a workaround to a known bug involving capturing an existing
|
||||||
|
asyncio event loop on non-Linux platforms.
|
||||||
|
"""
|
||||||
|
if sys.platform == "win32":
|
||||||
|
asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy())
|
||||||
|
|
||||||
|
|
||||||
|
def set_event_loop():
|
||||||
|
"""
|
||||||
|
A utility function to capture the existing event loop if it's running.
|
||||||
|
If no event loop is running, then a new one is created and set.
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
asyncio.get_running_loop()
|
||||||
|
except RuntimeError:
|
||||||
|
asyncio.set_event_loop(asyncio.new_event_loop())
|
||||||
|
@ -25,7 +25,16 @@
|
|||||||
from {
|
from {
|
||||||
transform: rotate(0deg);
|
transform: rotate(0deg);
|
||||||
}
|
}
|
||||||
|
|
||||||
to {
|
to {
|
||||||
transform: rotate(360deg);
|
transform: rotate(360deg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width:768px) {
|
||||||
|
.cell.is-col-span-2 {
|
||||||
|
grid-column: span 1;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
id="result-container">
|
id="result-container">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<h2 class="subtitle is-2">Analysis Complete</h2>
|
<h2 class="subtitle is-2">Analysis Complete</h2>
|
||||||
<div class="fixed-grid has-2-cols">
|
<div class="fixed-grid has-1-cols-mobile">
|
||||||
<div class="grid">
|
<div class="grid">
|
||||||
{% for cat, val in result.dict().items() %}
|
{% for cat, val in result.dict().items() %}
|
||||||
{% if not loop.last %}
|
{% if not loop.last %}
|
||||||
|
@ -9,18 +9,25 @@
|
|||||||
<div class="box">
|
<div class="box">
|
||||||
{% if is_error %}
|
{% if is_error %}
|
||||||
{% set bg_color = 'danger' %}
|
{% set bg_color = 'danger' %}
|
||||||
{% set header_content, content = message.split('body:', 1) %}
|
{% set header_content = 'Error' %}
|
||||||
{% elif is_loading %}
|
|
||||||
{% set bg_color = 'success' %}
|
|
||||||
{% set content = message %}
|
{% set content = message %}
|
||||||
{% set header_content = 'Complete' %}
|
{% elif is_loading and "analysis complete" not in message.lower() %}
|
||||||
{% elif is_tool_message %}
|
{% set bg_color = 'warning' %}
|
||||||
{% set bg_color = 'dark'%}
|
|
||||||
{% set header_content, content = message.split(' ', 2)[2].split('...', 1) %}
|
|
||||||
{% else %}
|
|
||||||
{% set bg_color = 'info' %}
|
|
||||||
{% set content = message %}
|
{% set content = message %}
|
||||||
{% set header_content = 'In Progress' %}
|
{% set header_content = 'In Progress' %}
|
||||||
|
|
||||||
|
{% elif is_tool_message and "analysis complete" not in message.lower() %}
|
||||||
|
{% set bg_color = 'info '%}
|
||||||
|
{% set header_content, content = message.split(' ', 2)[2].split('...', 1) %}
|
||||||
|
|
||||||
|
{% elif "analyzing..." in message.lower() %}
|
||||||
|
{% set bg_color = 'link' %}
|
||||||
|
{% set content = 'message' %}
|
||||||
|
{% set header_content = "Starting"%}
|
||||||
|
{% else %}
|
||||||
|
{% set bg_color = 'success' %}
|
||||||
|
{% set content = message %}
|
||||||
|
{% set header_content = 'Done!' %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<StatusResult div_class={{ bg_color }}
|
<StatusResult div_class={{ bg_color }}
|
||||||
header_content={{ header_content }}>{{ message }}
|
header_content={{ header_content }}>{{ message }}
|
||||||
|
42
uv.lock
generated
42
uv.lock
generated
@ -282,7 +282,7 @@ requires-dist = [
|
|||||||
{ name = "aiomysql", specifier = "==0.2.0" },
|
{ name = "aiomysql", specifier = "==0.2.0" },
|
||||||
{ name = "amqp", specifier = "==5.3.1" },
|
{ name = "amqp", specifier = "==5.3.1" },
|
||||||
{ name = "annotated-types", specifier = "==0.7.0" },
|
{ name = "annotated-types", specifier = "==0.7.0" },
|
||||||
{ name = "anthropic", specifier = "==0.44.0" },
|
{ name = "anthropic", specifier = "==0.45.0" },
|
||||||
{ name = "anyio", specifier = "==4.8.0" },
|
{ name = "anyio", specifier = "==4.8.0" },
|
||||||
{ name = "appdirs", specifier = "==1.4.4" },
|
{ name = "appdirs", specifier = "==1.4.4" },
|
||||||
{ name = "asgiref", specifier = "==3.8.1" },
|
{ name = "asgiref", specifier = "==3.8.1" },
|
||||||
@ -310,7 +310,7 @@ requires-dist = [
|
|||||||
{ name = "fastapi-restful", specifier = "==0.6.0" },
|
{ name = "fastapi-restful", specifier = "==0.6.0" },
|
||||||
{ name = "fastcrud", specifier = "==0.15.5" },
|
{ name = "fastcrud", specifier = "==0.15.5" },
|
||||||
{ name = "flower", specifier = "==2.0.1" },
|
{ name = "flower", specifier = "==2.0.1" },
|
||||||
{ name = "google-auth", specifier = "==2.37.0" },
|
{ name = "google-auth", specifier = "==2.38.0" },
|
||||||
{ name = "googleapis-common-protos", specifier = "==1.66.0" },
|
{ name = "googleapis-common-protos", specifier = "==1.66.0" },
|
||||||
{ name = "greenlet", specifier = "==3.1.1" },
|
{ name = "greenlet", specifier = "==3.1.1" },
|
||||||
{ name = "griffe", specifier = "==1.5.5" },
|
{ name = "griffe", specifier = "==1.5.5" },
|
||||||
@ -510,7 +510,7 @@ dev = [
|
|||||||
{ name = "pydantic-extra-types", specifier = "==2.10.2" },
|
{ name = "pydantic-extra-types", specifier = "==2.10.2" },
|
||||||
{ name = "pydantic-settings", specifier = "==2.7.1" },
|
{ name = "pydantic-settings", specifier = "==2.7.1" },
|
||||||
{ name = "pygments", specifier = "==2.19.1" },
|
{ name = "pygments", specifier = "==2.19.1" },
|
||||||
{ name = "pyinstrument", specifier = "==5.0.0" },
|
{ name = "pyinstrument", specifier = "==5.0.1" },
|
||||||
{ name = "python-dateutil", specifier = "==2.9.0.post0" },
|
{ name = "python-dateutil", specifier = "==2.9.0.post0" },
|
||||||
{ name = "python-dotenv", specifier = "==1.0.1" },
|
{ name = "python-dotenv", specifier = "==1.0.1" },
|
||||||
{ name = "python-json-logger", specifier = "==3.2.1" },
|
{ name = "python-json-logger", specifier = "==3.2.1" },
|
||||||
@ -606,7 +606,7 @@ wheels = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "anthropic"
|
name = "anthropic"
|
||||||
version = "0.44.0"
|
version = "0.45.0"
|
||||||
source = { registry = "https://pypi.org/simple" }
|
source = { registry = "https://pypi.org/simple" }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
{ name = "anyio" },
|
{ name = "anyio" },
|
||||||
@ -617,9 +617,9 @@ dependencies = [
|
|||||||
{ name = "sniffio" },
|
{ name = "sniffio" },
|
||||||
{ name = "typing-extensions" },
|
{ name = "typing-extensions" },
|
||||||
]
|
]
|
||||||
sdist = { url = "https://files.pythonhosted.org/packages/eb/34/ed394012684f7d6e36bb36c8b7c82b438f0ef189d2afd3d0090b85801211/anthropic-0.44.0.tar.gz", hash = "sha256:dc5c91c8b0463f97513d2e79350511ef295a56910bac4fbbe9491016c71f2ef0", size = 196065 }
|
sdist = { url = "https://files.pythonhosted.org/packages/c6/d4/51d5ed9159e53d51012c7ffa2b578f1c76cc9bd2d0646695604a20129b3c/anthropic-0.45.0.tar.gz", hash = "sha256:4e8541dc355332090bfc51b84549c19b649a13a23dbd6bd68e1d012e08551025", size = 200523 }
|
||||||
wheels = [
|
wheels = [
|
||||||
{ url = "https://files.pythonhosted.org/packages/d3/ad/c3c7d199eedc0b6d4621deed8dc1ed252ce399400cd76f1da098f1f50e56/anthropic-0.44.0-py3-none-any.whl", hash = "sha256:7087ccfc8ed7b164f971e094495cd3aeabac1e435fa393480cc146c87946c21c", size = 208634 },
|
{ url = "https://files.pythonhosted.org/packages/63/a0/f8ad781d83ccd8184692ace3c557294b1ece7c0b071f912300276b7cdb4a/anthropic-0.45.0-py3-none-any.whl", hash = "sha256:f36aff71d2c232945e64d1970be68a91b05a2ef5e3afa6c1ff195c3303a95ad3", size = 222255 },
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -1196,16 +1196,16 @@ wheels = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "google-auth"
|
name = "google-auth"
|
||||||
version = "2.37.0"
|
version = "2.38.0"
|
||||||
source = { registry = "https://pypi.org/simple" }
|
source = { registry = "https://pypi.org/simple" }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
{ name = "cachetools" },
|
{ name = "cachetools" },
|
||||||
{ name = "pyasn1-modules" },
|
{ name = "pyasn1-modules" },
|
||||||
{ name = "rsa" },
|
{ name = "rsa" },
|
||||||
]
|
]
|
||||||
sdist = { url = "https://files.pythonhosted.org/packages/46/af/b25763b9d35dfc2c6f9c3ec34d8d3f1ba760af3a7b7e8d5c5f0579522c45/google_auth-2.37.0.tar.gz", hash = "sha256:0054623abf1f9c83492c63d3f47e77f0a544caa3d40b2d98e099a611c2dd5d00", size = 268878 }
|
sdist = { url = "https://files.pythonhosted.org/packages/c6/eb/d504ba1daf190af6b204a9d4714d457462b486043744901a6eeea711f913/google_auth-2.38.0.tar.gz", hash = "sha256:8285113607d3b80a3f1543b75962447ba8a09fe85783432a784fdeef6ac094c4", size = 270866 }
|
||||||
wheels = [
|
wheels = [
|
||||||
{ url = "https://files.pythonhosted.org/packages/8d/8d/4d5d5f9f500499f7bd4c93903b43e8d6976f3fc6f064637ded1a85d09b07/google_auth-2.37.0-py2.py3-none-any.whl", hash = "sha256:42664f18290a6be591be5329a96fe30184be1a1badb7292a7f686a9659de9ca0", size = 209829 },
|
{ url = "https://files.pythonhosted.org/packages/9d/47/603554949a37bca5b7f894d51896a9c534b9eab808e2520a748e081669d0/google_auth-2.38.0-py2.py3-none-any.whl", hash = "sha256:e7dae6694313f434a2727bf2906f27ad259bae090d7aa896590d86feec3d9d4a", size = 210770 },
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -2677,20 +2677,20 @@ wheels = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pyinstrument"
|
name = "pyinstrument"
|
||||||
version = "5.0.0"
|
version = "5.0.1"
|
||||||
source = { registry = "https://pypi.org/simple" }
|
source = { registry = "https://pypi.org/simple" }
|
||||||
sdist = { url = "https://files.pythonhosted.org/packages/3c/14/726f2e2553aca08f25b7166197d22a4426053d5fb423c53417342ac584b1/pyinstrument-5.0.0.tar.gz", hash = "sha256:144f98eb3086667ece461f66324bf1cc1ee0475b399ab3f9ded8449cc76b7c90", size = 262211 }
|
sdist = { url = "https://files.pythonhosted.org/packages/64/6e/85c2722e40cab4fd9df6bbe68a0d032e237cf8cfada71e5f067e4e433214/pyinstrument-5.0.1.tar.gz", hash = "sha256:f4fd0754d02959c113a4b1ebed02f4627b6e2c138719ddf43244fd95f201c8c9", size = 263162 }
|
||||||
wheels = [
|
wheels = [
|
||||||
{ url = "https://files.pythonhosted.org/packages/49/c9/b2ed3db062bca45decb7fdcab2ed2cba6b1afb32b21bbde7166aafe5ecd3/pyinstrument-5.0.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:79a54def2d4aa83a4ed37c6cffc5494ae5de140f0453169eb4f7c744cc249d3a", size = 128268 },
|
{ url = "https://files.pythonhosted.org/packages/0f/ae/f8f84ecd0dc2c4f0d84920cb4ffdbea52a66e4b4abc2110f18879b57f538/pyinstrument-5.0.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:f5065639dfedc3b8e537161f9aaa8c550c8717c935a962e9bf1e843bf0e8791f", size = 128900 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/0f/14/456f51598c2e8401b248c38591488c3815f38a4c0bca6babb3f81ab93a71/pyinstrument-5.0.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:9538f746f166a40c8802ebe5c3e905d50f3faa189869cd71c083b8a639e574bb", size = 120299 },
|
{ url = "https://files.pythonhosted.org/packages/23/2f/b742c46d86d4c1f74ec0819f091bbc2fad0bab786584a18d89d9178802f1/pyinstrument-5.0.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:b5d20802b0c2bd1ddb95b2e96ebd3e9757dbab1e935792c2629166f1eb267bb2", size = 121445 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/11/e8/abeecedfa5dc6e6651e569c8876f0a55b973c906ebeb90185504a792ddb2/pyinstrument-5.0.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2bbab65cae1483ad8a18429511d1eac9e3efec9f7961f2fd1bf90e1e2d69ef15", size = 143953 },
|
{ url = "https://files.pythonhosted.org/packages/d9/e0/297dc8454ed437aec0fbdc3cc1a6a5fdf6701935b91dd31caf38c5e3ff92/pyinstrument-5.0.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6e6f5655d580429e7992c37757cc5f6e74ca81b0f2768b833d9711631a8cb2f7", size = 144904 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/80/03/107d3889ea42a777b0231bf3b8e5da8f8370b5bed5a55d79bcf7607d2393/pyinstrument-5.0.0-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4351ad041d208c597e296a0e9c2e6e21cc96804608bcafa40cfa168f3c2b8f79", size = 142858 },
|
{ url = "https://files.pythonhosted.org/packages/8b/df/e4faff09fdbad7e685ceb0f96066d434fc8350382acf8df47577653f702b/pyinstrument-5.0.1-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b4c8c9ad93f62f0bf2ddc7fb6fce3a91c008d422873824e01c5e5e83467fd1fb", size = 143801 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/72/6c/0f4af16e529d0ea290cbc72f97e0403a118692f954b2abdaf5547e05e026/pyinstrument-5.0.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ceee5252f4580abec29bcc5c965453c217b0d387c412a5ffb8afdcda4e648feb", size = 144259 },
|
{ url = "https://files.pythonhosted.org/packages/b1/63/ed2955d980bbebf17155119e2687ac15e170b6221c4bb5f5c37f41323fe5/pyinstrument-5.0.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:db15d1854b360182d242da8de89761a0ffb885eea61cb8652e40b5b9a4ef44bc", size = 145204 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/18/c7/1a8100197b67c03a8a733d0ffbc881c35f23ccbaf0f0e470c03b0e639da5/pyinstrument-5.0.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:b3050a4e7033103a13cfff9802680e2070a9173e1a258fa3f15a80b4eb9ee278", size = 143951 },
|
{ url = "https://files.pythonhosted.org/packages/c4/18/31b8dcdade9767afc7a36a313d8cf9c5690b662e9755fe7bd0523125e06f/pyinstrument-5.0.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:c803f7b880394b7bba5939ff8a59d6962589e9a0140fc33c3a6a345c58846106", size = 144881 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/87/bb/9826f6a62f2fee88a54059e1ca36a9766dab6220f826c8745dc453c31e99/pyinstrument-5.0.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:3b1f44a34da7810938df615fb7cbc43cd879b42ca6b5cd72e655aee92149d012", size = 143722 },
|
{ url = "https://files.pythonhosted.org/packages/1f/14/cd19894eb03dd28093f564e8bcf7ae4edc8e315ce962c8155cf795fc0784/pyinstrument-5.0.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:84e37ffabcf26fe820d354a1f7e9fc26949f953addab89b590c5000b3ffa60d0", size = 144643 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/42/2c/9a5b0cc42296637e23f50881e36add73edde2e668d34095e3ddbd899a1e6/pyinstrument-5.0.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:fde075196c8a3b2be191b8da05b92ff909c78d308f82df56d01a8cfdd6da07b9", size = 144138 },
|
{ url = "https://files.pythonhosted.org/packages/80/54/3dd08f5a869d3b654ff7e4e4c9d2b34f8de73fb0f2f792fac5024a312e0f/pyinstrument-5.0.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:a0d23d3763ec95da0beb390c2f7df7cbe36ea62b6a4d5b89c4eaab81c1c649cf", size = 145070 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/66/96/85044622fae98feaabaf26dbee39a7151d9a7c8d020a870033cd90f326ca/pyinstrument-5.0.0-cp313-cp313-win32.whl", hash = "sha256:1a9b62a8b54e05e7723eb8b9595fadc43559b73290c87b3b1cb2dc5944559790", size = 121977 },
|
{ url = "https://files.pythonhosted.org/packages/5d/dc/ac8e798235a1dbccefc1b204a16709cef36f02c07587763ba8eb510fc8bc/pyinstrument-5.0.1-cp313-cp313-win32.whl", hash = "sha256:967f84bd82f14425543a983956ff9cfcf1e3762755ffcec8cd835c6be22a7a0a", size = 123030 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/dd/36/a6a44b5162a9d102b085ef7107299be766868679ab2c974a4888823c8a0f/pyinstrument-5.0.0-cp313-cp313-win_amd64.whl", hash = "sha256:2478d2c55f77ad8e281e67b0dfe7c2176304bb824c307e86e11890f5e68d7feb", size = 122766 },
|
{ url = "https://files.pythonhosted.org/packages/52/59/adcb3e85c9105c59382723a67f682012aa7f49027e270e721f2d59f63fcf/pyinstrument-5.0.1-cp313-cp313-win_amd64.whl", hash = "sha256:70b16b5915534d8df40dcf04a7cc78d3290464c06fa358a4bc324280af4c74e0", size = 123825 },
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
Loading…
x
Reference in New Issue
Block a user