chef_agent
This commit is contained in:
@@ -18,6 +18,13 @@ DATABASE_POOL_SIZE=10
|
||||
DATABASE_MAX_OVERFLOW=20
|
||||
DATABASE_ECHO=False
|
||||
|
||||
# 数据库Postgres配置
|
||||
POSTGRES_USER="postgres"
|
||||
POSTGRES_PASSWORD="123456"
|
||||
POSTGRES_HOST="127.0.0.1"
|
||||
POSTGRES_PORT=5432
|
||||
POSTGRES_DB="postgres"
|
||||
|
||||
# CORS配置
|
||||
ALLOWED_ORIGINS=["*"]
|
||||
|
||||
|
||||
52
api/agent_api.py
Normal file
52
api/agent_api.py
Normal file
@@ -0,0 +1,52 @@
|
||||
from fastapi import APIRouter
|
||||
from fastapi.responses import StreamingResponse
|
||||
from pydantic import BaseModel, Field
|
||||
from services.agent_server.chef_service import ChefService
|
||||
|
||||
# agent相关的路由
|
||||
agent_router = APIRouter(prefix="/agent", tags=["Agent相关"])
|
||||
|
||||
|
||||
class ChatRequest(BaseModel):
|
||||
thread_id: str = Field(description="当前会话的id")
|
||||
message: str = Field(description="当前会话的问题")
|
||||
|
||||
|
||||
class ChatResponse(BaseModel):
|
||||
thread_id: str
|
||||
content: str
|
||||
|
||||
|
||||
@agent_router.post("/chat", response_model=ChatResponse)
|
||||
def chat(request: ChatRequest):
|
||||
|
||||
result = ChefService.chat(
|
||||
thread_id=request.thread_id,
|
||||
message=request.message,
|
||||
)
|
||||
|
||||
messages = result["messages"]
|
||||
|
||||
# 最后一条 AI 消息
|
||||
last_message = messages[-1]
|
||||
|
||||
return ChatResponse(
|
||||
thread_id=request.thread_id,
|
||||
content=last_message.content,
|
||||
)
|
||||
|
||||
@agent_router.post("/chat_stream")
|
||||
def chat(request: ChatRequest):
|
||||
|
||||
def generate_stream():
|
||||
result = ChefService.chat_stream(
|
||||
thread_id=request.thread_id,
|
||||
message=request.message,
|
||||
)
|
||||
for chunk in result:
|
||||
yield chunk
|
||||
|
||||
return StreamingResponse(
|
||||
generate_stream(),
|
||||
media_type="text/plain; charset=utf-8"
|
||||
)
|
||||
@@ -94,6 +94,30 @@ class Settings(BaseSettings):
|
||||
description="是否打印SQL语句"
|
||||
)
|
||||
|
||||
# ---------- 数据库Postgres配置 ----------
|
||||
POSTGRES_USER: str = Field(
|
||||
default='postgres',
|
||||
description="postgres用户名"
|
||||
)
|
||||
POSTGRES_PASSWORD: str = Field(
|
||||
default='123456',
|
||||
description="postgres密码"
|
||||
)
|
||||
POSTGRES_HOST: str = Field(
|
||||
default='127.0.0.1',
|
||||
description="postgres主机地址"
|
||||
)
|
||||
POSTGRES_PORT: int = Field(
|
||||
default=5432,
|
||||
ge=1,
|
||||
le=65535,
|
||||
description="postgres端口"
|
||||
)
|
||||
POSTGRES_DB: str = Field(
|
||||
default='postgres',
|
||||
description="postgres数据库名"
|
||||
)
|
||||
|
||||
# ---------- CORS配置 ----------
|
||||
ALLOWED_ORIGINS: List[str] = Field(
|
||||
default=["*"],
|
||||
@@ -161,6 +185,12 @@ class Settings(BaseSettings):
|
||||
# 连接url格式:mysql+pymysql://user:password@host:port/dbname
|
||||
return f"mysql+pymysql://{self.MYSQL_USER}:{self.MYSQL_PASSWORD}@{self.MYSQL_HOST}:{self.MYSQL_PORT}/{self.MYSQL_DB}?charset=utf8mb4"
|
||||
|
||||
@property
|
||||
def postgres_url(self) -> str:
|
||||
"""postgres连接URL"""
|
||||
# 连接url格式:postgresql://postgres:postgres@localhost:5432/postgres?sslmode=disable
|
||||
return f"postgresql://{self.POSTGRES_USER}:{self.POSTGRES_PASSWORD}@{self.POSTGRES_HOST}:{self.POSTGRES_PORT}/{self.POSTGRES_DB}?sslmode=disable"
|
||||
|
||||
@property
|
||||
def is_production(self) -> bool:
|
||||
"""是否为生产环境"""
|
||||
|
||||
289
lc/chef_agent.py
289
lc/chef_agent.py
@@ -1,71 +1,250 @@
|
||||
import os
|
||||
import sqlite3
|
||||
from typing import cast, Optional
|
||||
from __future__ import annotations
|
||||
|
||||
from langchain.agents import create_agent, AgentState
|
||||
import logging
|
||||
from typing import Any, cast
|
||||
|
||||
from langchain.agents import create_agent
|
||||
from langchain.agents.middleware import SummarizationMiddleware
|
||||
from langchain.agents.middleware.summarization import ContextMessages
|
||||
from langchain.chat_models import init_chat_model
|
||||
from langchain_core.language_models import BaseChatModel
|
||||
from langchain_core.messages import HumanMessage
|
||||
from langchain_core.runnables import RunnableConfig
|
||||
from langgraph.checkpoint.sqlite import SqliteSaver # 需要安装langgraph-checkpoint-sqlite
|
||||
from langchain_tavily import TavilySearch
|
||||
from langgraph.checkpoint.postgres import PostgresSaver
|
||||
from psycopg import Connection
|
||||
from psycopg_pool import ConnectionPool
|
||||
|
||||
from core.config.settings import settings
|
||||
|
||||
# 初始化模型 需要多模态大模型 deepseek已支持
|
||||
llm_model = init_chat_model(
|
||||
model="deepseek-v4-flash",
|
||||
model_provider="deepseek",
|
||||
api_key=settings.DEEPSEEK_API_KEY
|
||||
)
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
# 定义工具 使用tavily搜索工具 langchain-tavily
|
||||
search_tool = TavilySearch(
|
||||
tavily_api_key=settings.TAVILY_API_KEY,
|
||||
max_results=5, # 最大搜索结果条数
|
||||
topic="general"
|
||||
)
|
||||
class ChefAgent:
|
||||
"""厨师 Agent。
|
||||
|
||||
# 定义记忆策略 使用SummarizationMiddleware摘要策略中间件
|
||||
summary = SummarizationMiddleware(
|
||||
model=cast(BaseChatModel, llm_model), # 消息摘要的记忆管理策略的模型
|
||||
trigger=cast(ContextMessages, ("messages", 10)), # 触发策略的条件
|
||||
keep=cast(ContextMessages, ("messages", 5)) # 触发策略后保留的消息条数
|
||||
)
|
||||
负责:
|
||||
- LLM 初始化
|
||||
- Tool 初始化
|
||||
- CheckPointer 初始化
|
||||
- Middleware 初始化
|
||||
- Agent 初始化
|
||||
- 生命周期管理
|
||||
"""
|
||||
|
||||
# 创建数据库目录(如果不存在)
|
||||
os.makedirs("sqlite", exist_ok=True)
|
||||
# 创建 SQLite 数据库连接 check_same_thread=False 是为了确保在多线程环境下的安全性
|
||||
conn = sqlite3.connect("sqlite/checkpoints.db", check_same_thread=False)
|
||||
# 初始化 checkpointer
|
||||
checkpointer = SqliteSaver(conn)
|
||||
# 自动建表
|
||||
checkpointer.setup()
|
||||
def __init__(self) -> None:
|
||||
self._pool: ConnectionPool[Connection[Any]] | None = None
|
||||
self._checkpointer: PostgresSaver | None = None
|
||||
self._agent = None
|
||||
|
||||
# agent提示词
|
||||
system_prompt = """
|
||||
你是一名有名的国宴厨师。收到用户提供的食材照片或清单后,按照以下流程步骤操作:
|
||||
1.识别和评估食材:若用户提供照片,首先辨别所有可见食材,基于食材的外观状态,评估其新鲜度和可用量,整理出一份“可用食材清单”。
|
||||
2.智能食谱检索:优先调用search_tool工具,以“可用食材清单”为核心关键词,查找可行菜谱。
|
||||
3.多维度评估与排序:从营养与烹饪难度这2个维度对检索到的候选食谱进行量化打分,并根据得分进行排序,制作简单且营养丰富的排名靠前。
|
||||
4.结构化方案输出:把排序后的食谱整理成一份结构清晰的建议报告,要包括食谱信息、得分、推荐理由、食谱的参考图片,帮助用户快速做出决策。
|
||||
"""
|
||||
def initialize(self) -> ChefAgent:
|
||||
"""初始化 Agent。
|
||||
|
||||
# 定义thread_config 用于记忆存储分组
|
||||
thread_config: RunnableConfig = {"configurable": {"thread_id": "2"}}
|
||||
Returns:
|
||||
当前 Agent 实例,方便链式调用。
|
||||
"""
|
||||
|
||||
# 创建agent
|
||||
agent = create_agent(
|
||||
model=cast(BaseChatModel, llm_model), # 指定类型 避免idea报错
|
||||
tools=[search_tool],
|
||||
checkpointer=checkpointer,
|
||||
middleware=[summary],
|
||||
system_prompt=system_prompt
|
||||
)
|
||||
logger.info("开始初始化chef_agent...")
|
||||
|
||||
if __name__ == "__main__":
|
||||
question = input("> ")
|
||||
res = agent.invoke({"messages": [HumanMessage(content=question)]}, thread_config)
|
||||
print(res)
|
||||
if self._agent is not None:
|
||||
return self
|
||||
|
||||
# 1. 初始化 LLM
|
||||
llm = self._create_llm()
|
||||
|
||||
# 2. 初始化工具
|
||||
tools = self._create_tools()
|
||||
|
||||
# 3. 初始化 Middleware
|
||||
middleware = self._create_middleware(llm)
|
||||
|
||||
# 4. 初始化 CheckPointer
|
||||
self._checkpointer = self._create_checkpointer()
|
||||
|
||||
# 5. 初始化 Agent
|
||||
logger.info("chef_agent的agent开始初始化...")
|
||||
self._agent = create_agent(
|
||||
model=llm,
|
||||
tools=tools,
|
||||
middleware=middleware,
|
||||
checkpointer=self._checkpointer,
|
||||
system_prompt=self._system_prompt(),
|
||||
)
|
||||
logger.info("chef_agent的agent初始化完成")
|
||||
|
||||
logger.info("chef_agent初始化完成")
|
||||
|
||||
return self
|
||||
|
||||
@staticmethod
|
||||
def _create_llm() -> BaseChatModel:
|
||||
"""创建 LLM。"""
|
||||
|
||||
logger.info("chef_agent初始化llm...")
|
||||
|
||||
llm = init_chat_model(
|
||||
model="deepseek-v4-flash",
|
||||
api_key=settings.DEEPSEEK_API_KEY,
|
||||
)
|
||||
|
||||
logger.info("chef_agent的llm初始化完成")
|
||||
return cast(BaseChatModel, llm)
|
||||
|
||||
@staticmethod
|
||||
def _create_tools() -> list[Any]:
|
||||
"""创建 Agent Tools。"""
|
||||
|
||||
logger.info("chef_agent工具开始初始化...")
|
||||
search_tool = TavilySearch(
|
||||
tavily_api_key=settings.TAVILY_API_KEY,
|
||||
max_results=5,
|
||||
topic="general",
|
||||
)
|
||||
|
||||
logger.info("chef_agent工具初始化完成")
|
||||
return [search_tool]
|
||||
|
||||
@staticmethod
|
||||
def _create_middleware(
|
||||
llm: BaseChatModel,
|
||||
) -> list[Any]:
|
||||
"""创建 Agent Middleware。"""
|
||||
|
||||
logger.info("chef_agent中间件开始初始化...")
|
||||
summarization = SummarizationMiddleware(
|
||||
model=llm,
|
||||
trigger=cast(ContextMessages, ("messages", 10)),
|
||||
keep=cast(ContextMessages, ("messages", 5)),
|
||||
)
|
||||
|
||||
logger.info("chef_agent中间件初始化完成")
|
||||
return [summarization]
|
||||
|
||||
def _create_checkpointer(self) -> PostgresSaver:
|
||||
"""创建 PostgreSQL CheckPointer。"""
|
||||
|
||||
logger.info("chef_agent的CheckPointer开始初始化")
|
||||
logger.info("创建PostgreSQL连接池")
|
||||
self.pool: ConnectionPool[Connection[Any]] = ConnectionPool(
|
||||
conninfo=settings.postgres_url,
|
||||
max_size=10,
|
||||
kwargs={
|
||||
"autocommit": True,
|
||||
},
|
||||
)
|
||||
|
||||
logger.info("创建checkpointer")
|
||||
checkpointer = PostgresSaver(self.pool)
|
||||
|
||||
logger.info("初始化checkpoint数据表")
|
||||
# 创建 LangGraph checkpoint 所需的数据表
|
||||
checkpointer.setup()
|
||||
|
||||
logger.info("chef_agent的CheckPointer初始化完成")
|
||||
return checkpointer
|
||||
|
||||
@staticmethod
|
||||
def _system_prompt() -> str:
|
||||
"""Agent System Prompt。"""
|
||||
|
||||
return """
|
||||
你是一名专业厨师。
|
||||
|
||||
你的任务是根据用户提供的食材照片或食材清单,为用户推荐合适的菜谱。
|
||||
|
||||
请严格按照以下流程执行:
|
||||
|
||||
## 1. 识别和评估食材
|
||||
|
||||
如果用户提供的是食材照片:
|
||||
|
||||
- 识别照片中可见的食材
|
||||
- 根据外观判断食材的新鲜程度
|
||||
- 估算大致可用量
|
||||
- 排除明显不可食用或状态异常的食材
|
||||
|
||||
整理成「可用食材清单」。
|
||||
|
||||
如果用户直接提供食材清单,则直接使用用户提供的信息。
|
||||
|
||||
## 2. 搜索菜谱
|
||||
|
||||
优先使用搜索工具。
|
||||
|
||||
以「可用食材清单」作为核心关键词,搜索适合这些食材的菜谱。
|
||||
|
||||
优先考虑:
|
||||
|
||||
- 食材匹配度高
|
||||
- 操作简单
|
||||
- 营养均衡
|
||||
- 家庭烹饪可执行
|
||||
|
||||
除非搜索不到合适结果,否则不要直接凭经验编造菜谱。
|
||||
|
||||
## 3. 评估和排序
|
||||
|
||||
对搜索到的候选菜谱进行综合评价。
|
||||
|
||||
从以下维度进行评分:
|
||||
|
||||
- 食材匹配度
|
||||
- 营养价值
|
||||
- 烹饪难度
|
||||
- 烹饪时间
|
||||
|
||||
综合评分后进行排序。
|
||||
|
||||
优先推荐:
|
||||
|
||||
「简单 + 食材匹配度高 + 营养丰富」
|
||||
|
||||
的菜谱。
|
||||
|
||||
## 4. 输出结果
|
||||
|
||||
最终输出结构化的菜谱推荐报告。
|
||||
|
||||
每个推荐至少包含:
|
||||
|
||||
- 菜谱名称
|
||||
- 所需食材
|
||||
- 核心烹饪步骤
|
||||
- 烹饪时间
|
||||
- 难度
|
||||
- 综合评分
|
||||
- 推荐理由
|
||||
- 参考来源
|
||||
|
||||
如果搜索结果中存在可靠的菜谱图片,则提供图片参考。
|
||||
|
||||
如果搜索不到合适菜谱,再根据已有知识进行合理推荐,并明确说明这是基于模型知识给出的建议。
|
||||
""".strip()
|
||||
|
||||
@property
|
||||
def agent(self):
|
||||
"""获取 Agent。"""
|
||||
|
||||
if self._agent is None:
|
||||
raise RuntimeError(
|
||||
"ChefAgent 尚未初始化,请先调用 initialize()"
|
||||
)
|
||||
|
||||
return self._agent
|
||||
|
||||
def close(self) -> None:
|
||||
"""释放资源。"""
|
||||
|
||||
if self._pool is not None:
|
||||
self._pool.close()
|
||||
self._pool = None
|
||||
|
||||
self._checkpointer = None
|
||||
self._agent = None
|
||||
|
||||
# 使用with上下文管理方式来使用的话需要这2个方法
|
||||
# def __enter__(self) -> ChefAgent:
|
||||
# return self.initialize()
|
||||
#
|
||||
# def __exit__(self, exc_type, exc_value, traceback) -> None:
|
||||
# self.close()
|
||||
|
||||
|
||||
chef_agent = ChefAgent()
|
||||
|
||||
8
main.py
8
main.py
@@ -5,11 +5,14 @@ from contextlib import asynccontextmanager
|
||||
from fastapi import FastAPI
|
||||
from fastapi.middleware.cors import CORSMiddleware
|
||||
from sqlmodel import SQLModel
|
||||
|
||||
from api.agent_api import agent_router
|
||||
from core.db import engine
|
||||
from core.config.settings import settings
|
||||
from api.scheduler_api import scheduler_router
|
||||
from api.lottery_api import lottery_router
|
||||
from core.task.dlt_scheduler import scheduler
|
||||
from lc.chef_agent import chef_agent
|
||||
|
||||
# 配置日志
|
||||
logging.basicConfig(
|
||||
@@ -30,14 +33,19 @@ async def lifespan(app: FastAPI):
|
||||
# 启动定时调度器
|
||||
scheduler.start()
|
||||
|
||||
# 初始化chef_agent
|
||||
chef_agent.initialize()
|
||||
|
||||
yield # 此处交出控制权,服务开始运行
|
||||
# ========== 关闭时执行 ==========
|
||||
logger.info("服务关闭,释放资源")
|
||||
chef_agent.close()
|
||||
scheduler.shutdown()
|
||||
|
||||
app = FastAPI(lifespan=lifespan)
|
||||
app.include_router(scheduler_router)
|
||||
app.include_router(lottery_router)
|
||||
app.include_router(agent_router)
|
||||
|
||||
app.add_middleware(
|
||||
CORSMiddleware, # type: ignore[arg-type]
|
||||
|
||||
@@ -11,9 +11,13 @@ dependencies = [
|
||||
"langchain-deepseek==1.1.0",
|
||||
"langchain-tavily==0.2.18",
|
||||
"langgraph>=1.2.11",
|
||||
"langgraph-checkpoint-postgres>=3.1.2",
|
||||
"langgraph-checkpoint-sqlite==3.1.1",
|
||||
"notebook>=7.6.2",
|
||||
"openai==3.8.0",
|
||||
"psycopg>=3.3.5",
|
||||
"psycopg-binary>=3.3.5",
|
||||
"psycopg-pool>=3.3.1",
|
||||
"pydantic==2.13.5",
|
||||
"pydantic-settings==2.15.0",
|
||||
"pymysql==1.2.0",
|
||||
|
||||
0
services/agent_server/__init__.py
Normal file
0
services/agent_server/__init__.py
Normal file
23
services/agent_server/chef_service.py
Normal file
23
services/agent_server/chef_service.py
Normal file
@@ -0,0 +1,23 @@
|
||||
from langchain_core.messages import HumanMessage
|
||||
from langchain_core.runnables import RunnableConfig
|
||||
|
||||
from lc.chef_agent import chef_agent
|
||||
|
||||
|
||||
class ChefService:
|
||||
|
||||
@staticmethod
|
||||
def chat(
|
||||
thread_id: str,
|
||||
message: str,
|
||||
):
|
||||
config: RunnableConfig = {"configurable": {"thread_id": thread_id}}
|
||||
result = chef_agent.agent.invoke({"messages": [HumanMessage(content=message)]}, config)
|
||||
|
||||
return result
|
||||
|
||||
@staticmethod
|
||||
def chat_stream(thread_id: str, message: str):
|
||||
config: RunnableConfig = {"configurable": {"thread_id": thread_id}}
|
||||
result = chef_agent.agent.stream({"messages": [("user", message)]}, config=config, stream_mode="messages")
|
||||
return result
|
||||
11
test.py
Normal file
11
test.py
Normal file
@@ -0,0 +1,11 @@
|
||||
sys_prompt = """
|
||||
你是一名有名的厨师。收到用户提供的食材照片或清单后,按照以下流程步骤操作:
|
||||
1.识别和评估食材:若用户提供照片,首先辨别所有可见食材,基于食材的外观状态,评估其新鲜度和可用量,整理出一份“可用食材清单”。
|
||||
2.智能食谱检索:优先调用搜索工具,以“可用食材清单”为核心关键词,查找可行菜谱。
|
||||
3.多维度评估与排序:从营养与烹饪难度这2个维度对检索到的候选食谱进行量化打分,并根据得分进行排序,制作简单且营养丰富的排名靠前。
|
||||
4.结构化方案输出:把排序后的食谱整理成一份结构清晰的建议报告,要包括食谱信息、得分、推荐理由、食谱的参考图片,帮助用户快速做出决策。
|
||||
严格按照流程进行操作,搜索不到再自己发挥。
|
||||
"""
|
||||
|
||||
if __name__ == "__main__":
|
||||
print(sys_prompt)
|
||||
76
uv.lock
generated
76
uv.lock
generated
@@ -1309,6 +1309,21 @@ wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/05/71/3b475f09bd57d3a5649792c66353312b4432afd843f301739dfcebd157f0/langgraph_checkpoint-4.2.0-py3-none-any.whl", hash = "sha256:0547fd228935a0b758865de3a3d6d7a2537c308895d0f9ab092ce9151b5da942", size = 56833, upload-time = "2026-08-07T20:05:02.655Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "langgraph-checkpoint-postgres"
|
||||
version = "3.1.2"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "langgraph-checkpoint" },
|
||||
{ name = "orjson" },
|
||||
{ name = "psycopg" },
|
||||
{ name = "psycopg-pool" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/9d/52/6e732f7bf702ef4918b64ea4107e7da21d4276b808f9a651fe34be9b0abe/langgraph_checkpoint_postgres-3.1.2.tar.gz", hash = "sha256:1cd404803ff895a2b79f3ac04ce92b775e6b999715f8333fce674c6d927bba95", size = 155091, upload-time = "2026-08-07T20:40:00.049Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/0f/62/8899c9f4d9b97d5b3eb0c07c13cdf5f63342f15f5ef93eaf3477958df602/langgraph_checkpoint_postgres-3.1.2-py3-none-any.whl", hash = "sha256:6a7e38ef16985b54e356cba7bdaf447943aae33d5aaf290026c593bb6b4a6264", size = 52084, upload-time = "2026-08-07T20:39:58.994Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "langgraph-checkpoint-sqlite"
|
||||
version = "3.1.1"
|
||||
@@ -1399,9 +1414,13 @@ dependencies = [
|
||||
{ name = "langchain-deepseek" },
|
||||
{ name = "langchain-tavily" },
|
||||
{ name = "langgraph" },
|
||||
{ name = "langgraph-checkpoint-postgres" },
|
||||
{ name = "langgraph-checkpoint-sqlite" },
|
||||
{ name = "notebook" },
|
||||
{ name = "openai" },
|
||||
{ name = "psycopg" },
|
||||
{ name = "psycopg-binary" },
|
||||
{ name = "psycopg-pool" },
|
||||
{ name = "pydantic" },
|
||||
{ name = "pydantic-settings" },
|
||||
{ name = "pymysql" },
|
||||
@@ -1422,9 +1441,13 @@ requires-dist = [
|
||||
{ name = "langchain-deepseek", specifier = "==1.1.0" },
|
||||
{ name = "langchain-tavily", specifier = "==0.2.18" },
|
||||
{ name = "langgraph", specifier = ">=1.2.11" },
|
||||
{ name = "langgraph-checkpoint-postgres", specifier = ">=3.1.2" },
|
||||
{ name = "langgraph-checkpoint-sqlite", specifier = "==3.1.1" },
|
||||
{ name = "notebook", specifier = ">=7.6.2" },
|
||||
{ name = "openai", specifier = "==3.8.0" },
|
||||
{ name = "psycopg", specifier = ">=3.3.5" },
|
||||
{ name = "psycopg-binary", specifier = ">=3.3.5" },
|
||||
{ name = "psycopg-pool", specifier = ">=3.3.1" },
|
||||
{ name = "pydantic", specifier = "==2.13.5" },
|
||||
{ name = "pydantic-settings", specifier = "==2.15.0" },
|
||||
{ name = "pymysql", specifier = "==1.2.0" },
|
||||
@@ -1944,6 +1967,59 @@ wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/8c/c7/7bb2e321574b10df20cbde462a94e2b71d05f9bbda251ef27d104668306a/psutil-7.2.2-cp37-abi3-win_arm64.whl", hash = "sha256:8c233660f575a5a89e6d4cb65d9f938126312bca76d8fe087b947b3a1aaac9ee", size = 134617, upload-time = "2026-01-28T18:15:36.514Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "psycopg"
|
||||
version = "3.3.5"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "tzdata", marker = "sys_platform == 'win32'" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/72/73/8fb739d0f6bba247b9b93c9840c402a4f88545be5f1d4b02b23366371c00/psycopg-3.3.5.tar.gz", hash = "sha256:d0a3d9ccf5788af054cbd745278cb02401b5c312aeaafbf2c6144460aec47da4", size = 166508, upload-time = "2026-08-31T22:45:43.151Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/3d/2e/d0a645bcaadde68bd6d93c43f02f14b0191bdda367ce3f7722abe3da744a/psycopg-3.3.5-py3-none-any.whl", hash = "sha256:ce5aa5cdb4f9379f00f487590e5890bfa7df9a164648c969ffa628505e21af4e", size = 213598, upload-time = "2026-08-31T22:39:02.184Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "psycopg-binary"
|
||||
version = "3.3.5"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/e0/1c/e718752cc63cf4e99e4a10fd36e3a3364dabdd0819484a24c0d79fbb9685/psycopg_binary-3.3.5-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:6e85d50b87257fb117675a19ee59daa7bf9a57f6431500adf7059df799232ef4", size = 4704421, upload-time = "2026-08-31T22:42:59.564Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/af/cf/a0e748e27c09b92738e4460582d121ba1908be3e36791e150f435e54b332/psycopg_binary-3.3.5-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:e5becd311f9af8d180bad372f51fb2252fd02cb2073056e2b170c9274f95fe7f", size = 4765054, upload-time = "2026-08-31T22:43:05.421Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/39/62/0cbac0266d56c94dd1f702d9af2b5d54bf80b6e658048f4f2c5bd63dd7e3/psycopg_binary-3.3.5-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:19e5bf9872dbd164c220567fd385ba2309c7d9df1541f78343510c6b0f36a1b7", size = 5547137, upload-time = "2026-08-31T22:43:11.768Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/fb/3a/73c6f8871f38fc07a9c0b4cbc9467beb116a2783cecf87dfa53900a396dc/psycopg_binary-3.3.5-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:cb3b3bffebfe07110730626e76238161124f35ac87b748d663316a28d22f58b0", size = 5227577, upload-time = "2026-08-31T22:43:20.767Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/59/7b/9f17b9f4d297b774dc574199c4dcd02dadc32a00c4056265918de5c70635/psycopg_binary-3.3.5-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2111f880add40fb03c60556069ad68e884a0908a74d2debafc603caf93b73552", size = 6824606, upload-time = "2026-08-31T22:43:33.698Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/94/86/d84dadd94a004dbbb43ce0579f1f766fdc6b8cbef745090e24bea77b5283/psycopg_binary-3.3.5-cp313-cp313-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:40505676b1526b9ea387dace034040a8c8b0bcf984cd6bd4720a2ab15e813586", size = 5060854, upload-time = "2026-08-31T22:43:42.258Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/30/d0/e5078be2c7d2490c0d6cd4cb7b3601aec44be2fa8b3fe927e9419b06004f/psycopg_binary-3.3.5-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:5816472e3bb05615f33a741e0835043d1f4bf9709ff30d2f4aed71815cfc6b5e", size = 4589511, upload-time = "2026-08-31T22:43:50.012Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/f1/01/08dfb5b18fa482e025864fd91a022310d0782c42e4cf5dda5d0e010b6790/psycopg_binary-3.3.5-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:358748fc4c8ccdc0e2bdf55420494930e19c3ade586ea9c3a6de3dad1f897311", size = 4268144, upload-time = "2026-08-31T22:43:56.993Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/88/b9/cb01dc1d63f3241b49b2ca7fb9f98d0f5c76127f0dbb9440635a6ad0233e/psycopg_binary-3.3.5-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:1ef2e498be47800f6202b9a2304c22646325ca6d54001b7c785bcfdb24a1e8ab", size = 4001036, upload-time = "2026-08-31T22:44:04.429Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/95/49/7c17dd832c05b380562ff2ff5f6ab2bcaeca8b7fff2c2b355854368a5bdb/psycopg_binary-3.3.5-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:88e01aa2e938a45655a8a5213fc3a44ba78cb4cab8a569b3e0bcb3d1d0eaba16", size = 4313112, upload-time = "2026-08-31T22:44:12.446Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/7c/2c/b0b2f887185d6a2ec0b3bef948cc07656d2d1a5d96fa7f2bb03f6ef06ca4/psycopg_binary-3.3.5-cp313-cp313-win_amd64.whl", hash = "sha256:ba466011569297114449df9d523438e1adeedf3e4f31ffb78e897ec3fef3076b", size = 3647313, upload-time = "2026-08-31T22:44:19.139Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/46/7f/4e2395da194558533bd9c31f35e4dc58ecbbae6a7176b0d2f72d629e8a51/psycopg_binary-3.3.5-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:40f8b132c7243ef5f503f0b6f986bf16d38a51b0df1c6ba2577743f128be03e3", size = 4712612, upload-time = "2026-08-31T22:44:25.723Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/ae/94/fdb2093c8ccd7048449156db526ad746740cf34fe9c01e5dc1b7a7a8b257/psycopg_binary-3.3.5-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:c0cac998b9b1e82dec853d2e53b3d34d56a525cf231f9441a636cfd5992929a9", size = 4775139, upload-time = "2026-08-31T22:44:36.719Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/31/52/5195e87960715f7be2005761b72d56fce4e7757d5333fd40384f071c2de1/psycopg_binary-3.3.5-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:479b96fd78149cfa10369dc53fbfb89ee729be13146b584a23dbc7e164c0cf1e", size = 5556807, upload-time = "2026-08-31T22:44:42.668Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/f7/42/2d616210a91e1327516ed5ae71961aaa31bb740e4a61d7190f2221685a40/psycopg_binary-3.3.5-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:f45d77e398542ce0937d9fa3cd9d84e9c5fc6b34c50a66404ae840bada312750", size = 5236206, upload-time = "2026-08-31T22:44:47.943Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/08/2e/e54b0d4cc263b3526e3728bb50a69660d5e79e52255ccd2a1a71e40e6f9a/psycopg_binary-3.3.5-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:98a388509306e5e08a4203253ac52846bc1b034e5cbd0ae6da1211593cc28594", size = 6838066, upload-time = "2026-08-31T22:44:55.701Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/77/80/ec22a110f81a44c411965982097efeee86006bdd5a1f51f628318106c84c/psycopg_binary-3.3.5-cp314-cp314-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:ab39e2794b95af61a2ff69e33e5ab6ac5df36e9ffea9a3b18e38b2aaca8c5ad5", size = 5072036, upload-time = "2026-08-31T22:45:02.838Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/93/55/7bc3c3ac769ab4fe0c619f2179b4aab3ae043f4d478283dd8279d24c0be4/psycopg_binary-3.3.5-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:9c071bf78e5c2e6efa40bc9089a954d7b41221347a72f35c6bf2d8c96e632f75", size = 4604058, upload-time = "2026-08-31T22:45:10.444Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/a3/69/8e7414f7dc10b2959e664330cdcf393e412f67355975dafa876cef265264/psycopg_binary-3.3.5-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:14fdfd65a96ecbd8b586d14546105641f4a6ac7cbe335c786830ea4de94bbe60", size = 4284766, upload-time = "2026-08-31T22:45:17.881Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/c1/72/33f293c1d3ee9114f47e9ef4880f31c9de864e84a9b09454c26e106c25ed/psycopg_binary-3.3.5-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:8dbd694f3741dd4ac5bc60b70e17f7841aefb3f0f38cef4d2756de270e03af43", size = 4011958, upload-time = "2026-08-31T22:45:24.792Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/b7/c9/8e38840e5a7d006987bbc9acb29951912253fa50549a4db92b3aa535f089/psycopg_binary-3.3.5-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:14f432430fd9e1a9e7d9ab2fe14956c77f5d074ebdc556a1ad04e9a1bd3fca04", size = 4323273, upload-time = "2026-08-31T22:45:32.973Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/fc/c7/b7ebf601c307f93e7c4c4ebac0edc9db3b2729ca038efe700a18f86b5517/psycopg_binary-3.3.5-cp314-cp314-win_amd64.whl", hash = "sha256:df209e64674a34b41662c67fdc8b4e0ffd77d2136393790691d086a09f9a6cab", size = 3745885, upload-time = "2026-08-31T22:45:40.537Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "psycopg-pool"
|
||||
version = "3.3.1"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "typing-extensions" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/90/82/7a23d26039827ecd4ebe93905651029ddd307c5182ad59296dfb6f67b528/psycopg_pool-3.3.1.tar.gz", hash = "sha256:b10b10b7a175d5cc1592147dc5b7eec8a9e0834eb3ed2c4a92c858e2f51eb63c", size = 31661, upload-time = "2026-05-01T23:31:59.809Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/37/ed/89c2c620af0e1660354cd8aabf9f5b21f911597ce22acb37c805d6c86bc8/psycopg_pool-3.3.1-py3-none-any.whl", hash = "sha256:2af5b432941c4c9ad5c87b3fa410aec910ec8f7c122855897983a06c45f2e4b5", size = 40023, upload-time = "2026-05-01T23:31:53.136Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ptyprocess"
|
||||
version = "0.7.0"
|
||||
|
||||
Reference in New Issue
Block a user