diff --git a/.env.example b/.env.example index 8be95bb..ce0aab0 100644 --- a/.env.example +++ b/.env.example @@ -17,6 +17,11 @@ LLAMA_INDEX_DATABASE=langgraph # llama-index所使用的数据名称( LLAMA_INDEX_COLLECTION=llama_index # llama-index所使用的集合名称(不需要提前创建,会自动创建) LLAMA_INDEX_DIMENSION=1024 # llama-index所使用嵌入模型的向量维度 +REDIS_HOST=xxx.xxx.xxx.xxx # redis数据库连接ip地址 +REDIS_PORT=xxxx # redis数据库连接端口 +REDIS_PASSWORD=xxxx # redis数据库连接密码 +REDIS_DB=0 # redis数据库连接的库索引 + LLM_KEY_LOCAL=123 LLM_KEY_HUOSHAN=a0311f2a-ba85-4428-b158-xxxxxxxxxxxx # 火山引擎模型服务平台key LLM_KEY_BAILIAN=sk-51d13ba8ea044d128c66dxxxxxxxxxxxx # 阿里云百炼模型服务平台key diff --git a/app/config/env.py b/app/config/env.py index 55029a5..fda8272 100644 --- a/app/config/env.py +++ b/app/config/env.py @@ -25,6 +25,11 @@ class Settings(BaseSettings): llama_index_collection: str = Field(..., env="LLAMA_INDEX_COLLECTION") llama_index_dimension: str = Field(..., env="LLAMA_INDEX_DIMENSION") + redis_host: str = Field(..., env="REDIS_HOST") + redis_port: str = Field(..., env="REDIS_PORT") + redis_password: str = Field(..., env="REDIS_PASSWORD") + redis_db: str = Field(..., env="REDIS_DB") + llm_key_local: str = Field(..., env="LLM_KEY_LOCAL") llm_key_huoshan: str = Field(..., env="LLM_KEY_HUOSHAN") llm_key_bailian: str = Field(..., env="LLM_KEY_BAILIAN") diff --git a/app/controller/add_redis_route.py b/app/controller/add_redis_route.py new file mode 100644 index 0000000..a367ad9 --- /dev/null +++ b/app/controller/add_redis_route.py @@ -0,0 +1,14 @@ +from fastapi import FastAPI + +from app.utils.redis_utils import RedisClientDep + + +def add_redis_route(app: FastAPI): + @app.post("/redis_set/{key}") + async def redis_set(key: str, value: dict, redis_client: RedisClientDep): + await redis_client.hset(key, mapping=value) + return {"result": "success"} + + @app.get("/redis_get/{key}") + async def redis_get(key: str, redis_client: RedisClientDep): + return {"result": await redis_client.hgetall(key)} diff --git a/app/create_app.py b/app/create_app.py index 6cd75b8..7ed9bae 100644 --- a/app/create_app.py +++ b/app/create_app.py @@ -11,6 +11,7 @@ from app.middlewares.app_middlewares import add_app_middlewares from app.utils.db_utils import check_database_connection from app.utils.milvus_utils import milvus_service from app.utils.postgres_checkpointer import check_postgres_connection, close_postgres_connection +from app.utils.redis_utils import redis_utils def create_app(): @@ -21,12 +22,16 @@ def create_app(): asyncio.create_task(check_database_connection()), asyncio.create_task(check_postgres_connection()), asyncio.create_task(milvus_service.check_milvus_connection()), + asyncio.create_task(redis_utils.check_redis_connection()), ) async_engine = async_results[0] yield print("lifespan:销毁阶段") - await async_engine.dispose() - await close_postgres_connection() + await asyncio.gather( + async_engine.dispose(), + close_postgres_connection(), + redis_utils.close_redis_connection() + ) app = FastAPI( docs_url=None, # 禁用默认 Swagger diff --git a/app/server.py b/app/server.py index daaae50..4957add 100644 --- a/app/server.py +++ b/app/server.py @@ -14,6 +14,7 @@ from app.controller.add_langgraph_approve_route import add_langgraph_approve_rou from app.controller.add_langgraph_chat_route import add_langgraph_chat_route from app.controller.add_langgraph_route import add_langgraph_route from app.controller.add_lg_approve_route import add_lg_approve_route +from app.controller.add_redis_route import add_redis_route from app.controller.add_reimburse_route import add_reimburse_route from app.controller.add_sqlmodel_route import add_sqlmodel_route from app.controller.add_user_route import add_user_route @@ -72,6 +73,7 @@ add_hotel_route(app) add_file_route(app) add_knowledge_route(app) add_api_route(app) +add_redis_route(app) @app.get("/get_env") diff --git a/app/utils/redis_utils.py b/app/utils/redis_utils.py new file mode 100644 index 0000000..a795189 --- /dev/null +++ b/app/utils/redis_utils.py @@ -0,0 +1,65 @@ +import uuid +from contextlib import asynccontextmanager +from typing import Annotated + +import redis.asyncio as redis +from fastapi import Depends + +from app.config.env import env + + +class RedisUtils(): + def __init__(self): + self.redis_pool = None + + # 检查 Redis 连接,先创建连接池管理对象 + async def check_redis_connection(self): + self.redis_pool = redis.ConnectionPool( + host=env.redis_host, + port=env.redis_port, + password=env.redis_password, + db=env.redis_db, + encoding="utf-8", + decode_responses=True + ) + # 立即对redis做一次读写测试 + async with self.get_redis_connection() as redis_client: + try: + await redis_client.ping() + random_id = str(uuid.uuid4()) + await redis_client.set("__init__setup__", random_id) + cache_random_id = await redis_client.get("__init__setup__") + if cache_random_id != random_id: + raise Exception("Redis 连接失败,读写测试不一致") + print("✅ Redis connection successful:", f"redis://{env.redis_password}@${env.redis_host}:{env.redis_port}/{env.redis_db}") + except Exception as e: + print(f"❌ Database connection failed") + raise e + + # 获取一个Redis连接客户端 + @asynccontextmanager + async def get_redis_connection(self): + if not self.redis_pool: + raise Exception("Redis 连接池未初始化") + redis_client = redis.Redis(connection_pool=self.redis_pool) + try: + yield redis_client + finally: + await redis_client.close() + + # 清理Redis连接池 + async def close_redis_connection(self): + if self.redis_pool: + await self.redis_pool.disconnect() + + +redis_utils = RedisUtils() + + +# 作用:用于在接口中注入得到会话实例对象session,在接口执行完毕之后,自动执行close动作关闭会话 +async def get_redis_client() -> redis.Redis: + async with redis_utils.get_redis_connection() as redis_client: + yield redis_client + + +RedisClientDep = Annotated[redis.Redis, Depends(get_redis_client)] diff --git a/poetry.lock b/poetry.lock index 79f7d97..6631f85 100644 --- a/poetry.lock +++ b/poetry.lock @@ -236,6 +236,24 @@ type = "legacy" url = "https://pypi.tuna.tsinghua.edu.cn/simple" reference = "tsinghua" +[[package]] +name = "async-timeout" +version = "5.0.1" +description = "Timeout context manager for asyncio programs" +optional = false +python-versions = ">=3.8" +groups = ["main"] +markers = "python_version == \"3.11\" and python_full_version < \"3.11.3\"" +files = [ + {file = "async_timeout-5.0.1-py3-none-any.whl", hash = "sha256:39e3809566ff85354557ec2398b55e096c8364bacac9405a7a1fa429e77fe76c"}, + {file = "async_timeout-5.0.1.tar.gz", hash = "sha256:d9321a7a3d5a6a5e187e824d2fa0793ce379a202935782d555d6e9d2735677d3"}, +] + +[package.source] +type = "legacy" +url = "https://pypi.tuna.tsinghua.edu.cn/simple" +reference = "tsinghua" + [[package]] name = "asyncmy" version = "0.2.10" @@ -3839,6 +3857,31 @@ type = "legacy" url = "https://pypi.tuna.tsinghua.edu.cn/simple" reference = "tsinghua" +[[package]] +name = "redis" +version = "6.4.0" +description = "Python client for Redis database and key-value store" +optional = false +python-versions = ">=3.9" +groups = ["main"] +files = [ + {file = "redis-6.4.0-py3-none-any.whl", hash = "sha256:f0544fa9604264e9464cdf4814e7d4830f74b165d52f2a330a760a88dd248b7f"}, + {file = "redis-6.4.0.tar.gz", hash = "sha256:b01bc7282b8444e28ec36b261df5375183bb47a07eb9c603f284e89cbc5ef010"}, +] + +[package.dependencies] +async-timeout = {version = ">=4.0.3", markers = "python_full_version < \"3.11.3\""} + +[package.extras] +hiredis = ["hiredis (>=3.2.0)"] +jwt = ["pyjwt (>=2.9.0)"] +ocsp = ["cryptography (>=36.0.1)", "pyopenssl (>=20.0.1)", "requests (>=2.31.0)"] + +[package.source] +type = "legacy" +url = "https://pypi.tuna.tsinghua.edu.cn/simple" +reference = "tsinghua" + [[package]] name = "regex" version = "2024.11.6" @@ -5319,4 +5362,4 @@ reference = "tsinghua" [metadata] lock-version = "2.1" python-versions = "^3.11" -content-hash = "fbb45d7f436c48a7873e4ed94f6bd5561ceb6eaec4a51be64692a011ed1b85fe" +content-hash = "1f622d83d59d30ff671aa0b57fdca715cec3ab58d72de055130163967454f533" diff --git a/pyproject.toml b/pyproject.toml index 581afd2..60a0377 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -30,6 +30,7 @@ llama-index-vector-stores-milvus = "0.8.7" llama-index-llms-openai-like = "0.4.0" pymilvus = "2.6.1" aiofiles = "^24.1.0" +redis = "^6.4.0" [tool.poetry.group.dev.dependencies]