infomankit 0.3.23__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- infoman/__init__.py +1 -0
- infoman/cli/README.md +378 -0
- infoman/cli/__init__.py +7 -0
- infoman/cli/commands/__init__.py +3 -0
- infoman/cli/commands/init.py +312 -0
- infoman/cli/scaffold.py +634 -0
- infoman/cli/templates/Makefile.template +132 -0
- infoman/cli/templates/app/__init__.py.template +3 -0
- infoman/cli/templates/app/app.py.template +4 -0
- infoman/cli/templates/app/models_base.py.template +18 -0
- infoman/cli/templates/app/models_entity_init.py.template +11 -0
- infoman/cli/templates/app/models_schemas_init.py.template +11 -0
- infoman/cli/templates/app/repository_init.py.template +11 -0
- infoman/cli/templates/app/routers_init.py.template +15 -0
- infoman/cli/templates/app/services_init.py.template +11 -0
- infoman/cli/templates/app/static_index.html.template +39 -0
- infoman/cli/templates/app/static_main.js.template +31 -0
- infoman/cli/templates/app/static_style.css.template +111 -0
- infoman/cli/templates/app/utils_init.py.template +11 -0
- infoman/cli/templates/config/.env.dev.template +43 -0
- infoman/cli/templates/config/.env.prod.template +43 -0
- infoman/cli/templates/config/README.md.template +28 -0
- infoman/cli/templates/docker/.dockerignore.template +60 -0
- infoman/cli/templates/docker/Dockerfile.template +47 -0
- infoman/cli/templates/docker/README.md.template +240 -0
- infoman/cli/templates/docker/docker-compose.yml.template +81 -0
- infoman/cli/templates/docker/mysql_custom.cnf.template +42 -0
- infoman/cli/templates/docker/mysql_init.sql.template +15 -0
- infoman/cli/templates/project/.env.example.template +1 -0
- infoman/cli/templates/project/.gitignore.template +60 -0
- infoman/cli/templates/project/Makefile.template +38 -0
- infoman/cli/templates/project/README.md.template +137 -0
- infoman/cli/templates/project/deploy.sh.template +97 -0
- infoman/cli/templates/project/main.py.template +10 -0
- infoman/cli/templates/project/manage.sh.template +97 -0
- infoman/cli/templates/project/pyproject.toml.template +47 -0
- infoman/cli/templates/project/service.sh.template +203 -0
- infoman/config/__init__.py +25 -0
- infoman/config/base.py +67 -0
- infoman/config/db_cache.py +237 -0
- infoman/config/db_relation.py +181 -0
- infoman/config/db_vector.py +39 -0
- infoman/config/jwt.py +16 -0
- infoman/config/llm.py +16 -0
- infoman/config/log.py +627 -0
- infoman/config/mq.py +26 -0
- infoman/config/settings.py +65 -0
- infoman/llm/__init__.py +0 -0
- infoman/llm/llm.py +297 -0
- infoman/logger/__init__.py +57 -0
- infoman/logger/context.py +191 -0
- infoman/logger/core.py +358 -0
- infoman/logger/filters.py +157 -0
- infoman/logger/formatters.py +138 -0
- infoman/logger/handlers.py +276 -0
- infoman/logger/metrics.py +160 -0
- infoman/performance/README.md +583 -0
- infoman/performance/__init__.py +19 -0
- infoman/performance/cli.py +215 -0
- infoman/performance/config.py +166 -0
- infoman/performance/reporter.py +519 -0
- infoman/performance/runner.py +303 -0
- infoman/performance/standards.py +222 -0
- infoman/service/__init__.py +8 -0
- infoman/service/app.py +67 -0
- infoman/service/core/__init__.py +0 -0
- infoman/service/core/auth.py +105 -0
- infoman/service/core/lifespan.py +132 -0
- infoman/service/core/monitor.py +57 -0
- infoman/service/core/response.py +37 -0
- infoman/service/exception/__init__.py +7 -0
- infoman/service/exception/error.py +274 -0
- infoman/service/exception/exception.py +25 -0
- infoman/service/exception/handler.py +238 -0
- infoman/service/infrastructure/__init__.py +8 -0
- infoman/service/infrastructure/base.py +212 -0
- infoman/service/infrastructure/db_cache/__init__.py +8 -0
- infoman/service/infrastructure/db_cache/manager.py +194 -0
- infoman/service/infrastructure/db_relation/__init__.py +41 -0
- infoman/service/infrastructure/db_relation/manager.py +300 -0
- infoman/service/infrastructure/db_relation/manager_pro.py +408 -0
- infoman/service/infrastructure/db_relation/mysql.py +52 -0
- infoman/service/infrastructure/db_relation/pgsql.py +54 -0
- infoman/service/infrastructure/db_relation/sqllite.py +25 -0
- infoman/service/infrastructure/db_vector/__init__.py +40 -0
- infoman/service/infrastructure/db_vector/manager.py +201 -0
- infoman/service/infrastructure/db_vector/qdrant.py +322 -0
- infoman/service/infrastructure/mq/__init__.py +15 -0
- infoman/service/infrastructure/mq/manager.py +178 -0
- infoman/service/infrastructure/mq/nats/__init__.py +0 -0
- infoman/service/infrastructure/mq/nats/nats_client.py +57 -0
- infoman/service/infrastructure/mq/nats/nats_event_router.py +25 -0
- infoman/service/launch.py +284 -0
- infoman/service/middleware/__init__.py +7 -0
- infoman/service/middleware/base.py +41 -0
- infoman/service/middleware/logging.py +51 -0
- infoman/service/middleware/rate_limit.py +301 -0
- infoman/service/middleware/request_id.py +21 -0
- infoman/service/middleware/white_list.py +24 -0
- infoman/service/models/__init__.py +8 -0
- infoman/service/models/base.py +441 -0
- infoman/service/models/type/embed.py +70 -0
- infoman/service/routers/__init__.py +18 -0
- infoman/service/routers/health_router.py +311 -0
- infoman/service/routers/monitor_router.py +44 -0
- infoman/service/utils/__init__.py +8 -0
- infoman/service/utils/cache/__init__.py +0 -0
- infoman/service/utils/cache/cache.py +192 -0
- infoman/service/utils/module_loader.py +10 -0
- infoman/service/utils/parse.py +10 -0
- infoman/service/utils/resolver/__init__.py +8 -0
- infoman/service/utils/resolver/base.py +47 -0
- infoman/service/utils/resolver/resp.py +102 -0
- infoman/service/vector/__init__.py +20 -0
- infoman/service/vector/base.py +56 -0
- infoman/service/vector/qdrant.py +125 -0
- infoman/service/vector/service.py +67 -0
- infoman/utils/__init__.py +2 -0
- infoman/utils/decorators/__init__.py +8 -0
- infoman/utils/decorators/cache.py +137 -0
- infoman/utils/decorators/retry.py +99 -0
- infoman/utils/decorators/safe_execute.py +99 -0
- infoman/utils/decorators/timing.py +99 -0
- infoman/utils/encryption/__init__.py +8 -0
- infoman/utils/encryption/aes.py +66 -0
- infoman/utils/encryption/ecc.py +108 -0
- infoman/utils/encryption/rsa.py +112 -0
- infoman/utils/file/__init__.py +0 -0
- infoman/utils/file/handler.py +22 -0
- infoman/utils/hash/__init__.py +0 -0
- infoman/utils/hash/hash.py +61 -0
- infoman/utils/http/__init__.py +8 -0
- infoman/utils/http/client.py +62 -0
- infoman/utils/http/info.py +94 -0
- infoman/utils/http/result.py +19 -0
- infoman/utils/notification/__init__.py +8 -0
- infoman/utils/notification/feishu.py +35 -0
- infoman/utils/text/__init__.py +8 -0
- infoman/utils/text/extractor.py +111 -0
- infomankit-0.3.23.dist-info/METADATA +632 -0
- infomankit-0.3.23.dist-info/RECORD +143 -0
- infomankit-0.3.23.dist-info/WHEEL +4 -0
- infomankit-0.3.23.dist-info/entry_points.txt +5 -0
|
@@ -0,0 +1,441 @@
|
|
|
1
|
+
#!/usr/bin/env python
|
|
2
|
+
# -*-coding:utf-8 -*-
|
|
3
|
+
"""
|
|
4
|
+
数据库模型基类 - 支持多 ORM 后端
|
|
5
|
+
|
|
6
|
+
设计原则:
|
|
7
|
+
1. 用户代码只依赖抽象基类
|
|
8
|
+
2. 运行时根据配置选择后端
|
|
9
|
+
3. 100% 向前兼容现有 Tortoise 代码
|
|
10
|
+
|
|
11
|
+
Version: 0.3.0
|
|
12
|
+
Author: Maxwell
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
from abc import ABC, abstractmethod
|
|
16
|
+
from typing import TypeVar, Generic, Optional, List, Any
|
|
17
|
+
from datetime import datetime
|
|
18
|
+
|
|
19
|
+
# ==================== 抽象接口层 ====================
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class BaseTimestampMixin(ABC):
|
|
23
|
+
"""时间戳混入抽象类 - ORM 无关"""
|
|
24
|
+
id: int
|
|
25
|
+
created_at: datetime
|
|
26
|
+
updated_at: datetime
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
T = TypeVar('T', bound=BaseTimestampMixin)
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
class BaseRepository(ABC, Generic[T]):
|
|
33
|
+
"""
|
|
34
|
+
仓储模式抽象类 - 隔离 ORM 实现细节
|
|
35
|
+
|
|
36
|
+
使用示例:
|
|
37
|
+
>>> repo = create_repository(User)
|
|
38
|
+
>>> user = await repo.get(1)
|
|
39
|
+
>>> users = await repo.filter(name="Alice")
|
|
40
|
+
"""
|
|
41
|
+
|
|
42
|
+
@abstractmethod
|
|
43
|
+
async def get(self, id: int) -> Optional[T]:
|
|
44
|
+
"""根据 ID 获取单条记录"""
|
|
45
|
+
pass
|
|
46
|
+
|
|
47
|
+
@abstractmethod
|
|
48
|
+
async def filter(self, **kwargs) -> List[T]:
|
|
49
|
+
"""根据条件筛选"""
|
|
50
|
+
pass
|
|
51
|
+
|
|
52
|
+
@abstractmethod
|
|
53
|
+
async def create(self, **kwargs) -> T:
|
|
54
|
+
"""创建记录"""
|
|
55
|
+
pass
|
|
56
|
+
|
|
57
|
+
@abstractmethod
|
|
58
|
+
async def update(self, id: int, **kwargs) -> T:
|
|
59
|
+
"""更新记录"""
|
|
60
|
+
pass
|
|
61
|
+
|
|
62
|
+
@abstractmethod
|
|
63
|
+
async def delete(self, id: int) -> bool:
|
|
64
|
+
"""删除记录"""
|
|
65
|
+
pass
|
|
66
|
+
|
|
67
|
+
@abstractmethod
|
|
68
|
+
async def all(self) -> List[T]:
|
|
69
|
+
"""获取所有记录"""
|
|
70
|
+
pass
|
|
71
|
+
|
|
72
|
+
@abstractmethod
|
|
73
|
+
async def count(self, **kwargs) -> int:
|
|
74
|
+
"""计数"""
|
|
75
|
+
pass
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
# ==================== Tortoise ORM 实现(向前兼容)====================
|
|
79
|
+
|
|
80
|
+
try:
|
|
81
|
+
from tortoise import fields
|
|
82
|
+
from tortoise.models import Model as TortoiseModel
|
|
83
|
+
|
|
84
|
+
class TimestampMixin(TortoiseModel, BaseTimestampMixin):
|
|
85
|
+
"""
|
|
86
|
+
Tortoise ORM 时间戳混入 - 保持现有 API 不变
|
|
87
|
+
|
|
88
|
+
使用示例(向前兼容):
|
|
89
|
+
>>> class User(TimestampMixin):
|
|
90
|
+
... name = fields.CharField(max_length=100)
|
|
91
|
+
>>> user = await User.create(name="Alice")
|
|
92
|
+
"""
|
|
93
|
+
|
|
94
|
+
class Meta:
|
|
95
|
+
abstract = True
|
|
96
|
+
|
|
97
|
+
id = fields.IntField(pk=True, null=False)
|
|
98
|
+
created_at = fields.DatetimeField(auto_now_add=True, description="创建时间")
|
|
99
|
+
updated_at = fields.DatetimeField(auto_now=True, description="更新时间")
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
class MySQLModel(TortoiseModel):
|
|
103
|
+
"""MySQL 模型基类(Tortoise)"""
|
|
104
|
+
class Meta:
|
|
105
|
+
abstract = True
|
|
106
|
+
app = 'mysql_models'
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
class PostgreSQLModel(TortoiseModel):
|
|
110
|
+
"""PostgreSQL 模型基类(Tortoise)"""
|
|
111
|
+
class Meta:
|
|
112
|
+
abstract = True
|
|
113
|
+
app = 'postgres_models'
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
class SQLiteModel(TortoiseModel):
|
|
117
|
+
"""SQLite 模型基类(Tortoise)"""
|
|
118
|
+
class Meta:
|
|
119
|
+
abstract = True
|
|
120
|
+
app = 'sqlite_models'
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
class TortoiseRepository(BaseRepository[T]):
|
|
124
|
+
"""
|
|
125
|
+
Tortoise ORM 仓储实现
|
|
126
|
+
|
|
127
|
+
使用示例:
|
|
128
|
+
>>> repo = TortoiseRepository(User)
|
|
129
|
+
>>> user = await repo.create(name="Alice")
|
|
130
|
+
"""
|
|
131
|
+
|
|
132
|
+
def __init__(self, model_class):
|
|
133
|
+
self.model = model_class
|
|
134
|
+
|
|
135
|
+
async def get(self, id: int) -> Optional[T]:
|
|
136
|
+
try:
|
|
137
|
+
return await self.model.get(id=id)
|
|
138
|
+
except Exception:
|
|
139
|
+
return None
|
|
140
|
+
|
|
141
|
+
async def filter(self, **kwargs) -> List[T]:
|
|
142
|
+
return await self.model.filter(**kwargs).all()
|
|
143
|
+
|
|
144
|
+
async def create(self, **kwargs) -> T:
|
|
145
|
+
return await self.model.create(**kwargs)
|
|
146
|
+
|
|
147
|
+
async def update(self, id: int, **kwargs) -> T:
|
|
148
|
+
instance = await self.model.get(id=id)
|
|
149
|
+
await instance.update_from_dict(kwargs).save()
|
|
150
|
+
return instance
|
|
151
|
+
|
|
152
|
+
async def delete(self, id: int) -> bool:
|
|
153
|
+
instance = await self.model.get(id=id)
|
|
154
|
+
await instance.delete()
|
|
155
|
+
return True
|
|
156
|
+
|
|
157
|
+
async def all(self) -> List[T]:
|
|
158
|
+
return await self.model.all()
|
|
159
|
+
|
|
160
|
+
async def count(self, **kwargs) -> int:
|
|
161
|
+
return await self.model.filter(**kwargs).count()
|
|
162
|
+
|
|
163
|
+
_TORTOISE_AVAILABLE = True
|
|
164
|
+
|
|
165
|
+
except ImportError:
|
|
166
|
+
# Tortoise 未安装,使用占位符
|
|
167
|
+
_TORTOISE_AVAILABLE = False
|
|
168
|
+
|
|
169
|
+
class TimestampMixin(BaseTimestampMixin): # type: ignore
|
|
170
|
+
"""占位符:需要安装 tortoise-orm"""
|
|
171
|
+
pass
|
|
172
|
+
|
|
173
|
+
class MySQLModel: # type: ignore
|
|
174
|
+
"""占位符:需要安装 tortoise-orm"""
|
|
175
|
+
pass
|
|
176
|
+
|
|
177
|
+
class PostgreSQLModel: # type: ignore
|
|
178
|
+
"""占位符:需要安装 tortoise-orm"""
|
|
179
|
+
pass
|
|
180
|
+
|
|
181
|
+
class SQLiteModel: # type: ignore
|
|
182
|
+
"""占位符:需要安装 tortoise-orm"""
|
|
183
|
+
pass
|
|
184
|
+
|
|
185
|
+
class TortoiseRepository(BaseRepository[T]): # type: ignore
|
|
186
|
+
"""占位符:需要安装 tortoise-orm"""
|
|
187
|
+
def __init__(self, model_class):
|
|
188
|
+
raise ImportError("需要安装 tortoise-orm: pip install infomankit[database]")
|
|
189
|
+
|
|
190
|
+
async def get(self, id: int) -> Optional[T]:
|
|
191
|
+
raise NotImplementedError
|
|
192
|
+
async def filter(self, **kwargs) -> List[T]:
|
|
193
|
+
raise NotImplementedError
|
|
194
|
+
async def create(self, **kwargs) -> T:
|
|
195
|
+
raise NotImplementedError
|
|
196
|
+
async def update(self, id: int, **kwargs) -> T:
|
|
197
|
+
raise NotImplementedError
|
|
198
|
+
async def delete(self, id: int) -> bool:
|
|
199
|
+
raise NotImplementedError
|
|
200
|
+
async def all(self) -> List[T]:
|
|
201
|
+
raise NotImplementedError
|
|
202
|
+
async def count(self, **kwargs) -> int:
|
|
203
|
+
raise NotImplementedError
|
|
204
|
+
|
|
205
|
+
|
|
206
|
+
# ==================== SQLAlchemy 实现(新增)====================
|
|
207
|
+
|
|
208
|
+
try:
|
|
209
|
+
from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column
|
|
210
|
+
from sqlalchemy import Integer, DateTime, func, select, delete as sql_delete
|
|
211
|
+
from sqlalchemy.ext.asyncio import AsyncSession
|
|
212
|
+
|
|
213
|
+
class AlchemyBase(DeclarativeBase):
|
|
214
|
+
"""
|
|
215
|
+
SQLAlchemy 基类
|
|
216
|
+
|
|
217
|
+
使用示例:
|
|
218
|
+
>>> class User(AlchemyBase, AlchemyTimestampMixin):
|
|
219
|
+
... __tablename__ = "users"
|
|
220
|
+
... name: Mapped[str] = mapped_column(String(100))
|
|
221
|
+
"""
|
|
222
|
+
pass
|
|
223
|
+
|
|
224
|
+
|
|
225
|
+
class AlchemyTimestampMixin(BaseTimestampMixin):
|
|
226
|
+
"""
|
|
227
|
+
SQLAlchemy 时间戳混入
|
|
228
|
+
|
|
229
|
+
提供自动管理的 id, created_at, updated_at 字段
|
|
230
|
+
"""
|
|
231
|
+
id: Mapped[int] = mapped_column(Integer, primary_key=True)
|
|
232
|
+
created_at: Mapped[datetime] = mapped_column(
|
|
233
|
+
DateTime,
|
|
234
|
+
server_default=func.now(),
|
|
235
|
+
comment="创建时间"
|
|
236
|
+
)
|
|
237
|
+
updated_at: Mapped[datetime] = mapped_column(
|
|
238
|
+
DateTime,
|
|
239
|
+
server_default=func.now(),
|
|
240
|
+
onupdate=func.now(),
|
|
241
|
+
comment="更新时间"
|
|
242
|
+
)
|
|
243
|
+
|
|
244
|
+
|
|
245
|
+
class SQLAlchemyRepository(BaseRepository[T]):
|
|
246
|
+
"""
|
|
247
|
+
SQLAlchemy 仓储实现
|
|
248
|
+
|
|
249
|
+
使用示例:
|
|
250
|
+
>>> session_maker = get_session_maker()
|
|
251
|
+
>>> repo = SQLAlchemyRepository(User, session_maker)
|
|
252
|
+
>>> user = await repo.create(name="Alice")
|
|
253
|
+
"""
|
|
254
|
+
|
|
255
|
+
def __init__(self, model_class, session_factory):
|
|
256
|
+
self.model = model_class
|
|
257
|
+
self.session_factory = session_factory
|
|
258
|
+
|
|
259
|
+
async def get(self, id: int) -> Optional[T]:
|
|
260
|
+
async with self.session_factory() as session:
|
|
261
|
+
stmt = select(self.model).where(self.model.id == id)
|
|
262
|
+
result = await session.execute(stmt)
|
|
263
|
+
return result.scalar_one_or_none()
|
|
264
|
+
|
|
265
|
+
async def filter(self, **kwargs) -> List[T]:
|
|
266
|
+
async with self.session_factory() as session:
|
|
267
|
+
stmt = select(self.model).filter_by(**kwargs)
|
|
268
|
+
result = await session.execute(stmt)
|
|
269
|
+
return list(result.scalars().all())
|
|
270
|
+
|
|
271
|
+
async def create(self, **kwargs) -> T:
|
|
272
|
+
async with self.session_factory() as session:
|
|
273
|
+
instance = self.model(**kwargs)
|
|
274
|
+
session.add(instance)
|
|
275
|
+
await session.commit()
|
|
276
|
+
await session.refresh(instance)
|
|
277
|
+
return instance
|
|
278
|
+
|
|
279
|
+
async def update(self, id: int, **kwargs) -> T:
|
|
280
|
+
async with self.session_factory() as session:
|
|
281
|
+
stmt = select(self.model).where(self.model.id == id)
|
|
282
|
+
result = await session.execute(stmt)
|
|
283
|
+
instance = result.scalar_one()
|
|
284
|
+
|
|
285
|
+
for key, value in kwargs.items():
|
|
286
|
+
setattr(instance, key, value)
|
|
287
|
+
|
|
288
|
+
await session.commit()
|
|
289
|
+
await session.refresh(instance)
|
|
290
|
+
return instance
|
|
291
|
+
|
|
292
|
+
async def delete(self, id: int) -> bool:
|
|
293
|
+
async with self.session_factory() as session:
|
|
294
|
+
stmt = sql_delete(self.model).where(self.model.id == id)
|
|
295
|
+
await session.execute(stmt)
|
|
296
|
+
await session.commit()
|
|
297
|
+
return True
|
|
298
|
+
|
|
299
|
+
async def all(self) -> List[T]:
|
|
300
|
+
async with self.session_factory() as session:
|
|
301
|
+
stmt = select(self.model)
|
|
302
|
+
result = await session.execute(stmt)
|
|
303
|
+
return list(result.scalars().all())
|
|
304
|
+
|
|
305
|
+
async def count(self, **kwargs) -> int:
|
|
306
|
+
async with self.session_factory() as session:
|
|
307
|
+
from sqlalchemy import func as sql_func
|
|
308
|
+
stmt = select(sql_func.count()).select_from(self.model).filter_by(**kwargs)
|
|
309
|
+
result = await session.execute(stmt)
|
|
310
|
+
return result.scalar()
|
|
311
|
+
|
|
312
|
+
_SQLALCHEMY_AVAILABLE = True
|
|
313
|
+
|
|
314
|
+
except ImportError:
|
|
315
|
+
# SQLAlchemy 未安装
|
|
316
|
+
_SQLALCHEMY_AVAILABLE = False
|
|
317
|
+
|
|
318
|
+
class AlchemyBase: # type: ignore
|
|
319
|
+
"""占位符:需要安装 sqlalchemy"""
|
|
320
|
+
pass
|
|
321
|
+
|
|
322
|
+
class AlchemyTimestampMixin(BaseTimestampMixin): # type: ignore
|
|
323
|
+
"""占位符:需要安装 sqlalchemy"""
|
|
324
|
+
pass
|
|
325
|
+
|
|
326
|
+
class SQLAlchemyRepository(BaseRepository[T]): # type: ignore
|
|
327
|
+
"""占位符:需要安装 sqlalchemy"""
|
|
328
|
+
def __init__(self, model_class, session_factory):
|
|
329
|
+
raise ImportError("需要安装 sqlalchemy: pip install infomankit[database-alchemy]")
|
|
330
|
+
|
|
331
|
+
async def get(self, id: int) -> Optional[T]:
|
|
332
|
+
raise NotImplementedError
|
|
333
|
+
async def filter(self, **kwargs) -> List[T]:
|
|
334
|
+
raise NotImplementedError
|
|
335
|
+
async def create(self, **kwargs) -> T:
|
|
336
|
+
raise NotImplementedError
|
|
337
|
+
async def update(self, id: int, **kwargs) -> T:
|
|
338
|
+
raise NotImplementedError
|
|
339
|
+
async def delete(self, id: int) -> bool:
|
|
340
|
+
raise NotImplementedError
|
|
341
|
+
async def all(self) -> List[T]:
|
|
342
|
+
raise NotImplementedError
|
|
343
|
+
async def count(self, **kwargs) -> int:
|
|
344
|
+
raise NotImplementedError
|
|
345
|
+
|
|
346
|
+
|
|
347
|
+
# ==================== 工厂函数(自动选择后端)====================
|
|
348
|
+
|
|
349
|
+
def create_repository(model_class, backend: str = "auto", session_factory=None) -> BaseRepository:
|
|
350
|
+
"""
|
|
351
|
+
创建仓储实例 - 自动选择后端
|
|
352
|
+
|
|
353
|
+
Args:
|
|
354
|
+
model_class: 模型类
|
|
355
|
+
backend: 'tortoise', 'sqlalchemy', 'auto'(默认)
|
|
356
|
+
session_factory: SQLAlchemy session factory(仅 SQLAlchemy 后端需要)
|
|
357
|
+
|
|
358
|
+
Returns:
|
|
359
|
+
BaseRepository 实例
|
|
360
|
+
|
|
361
|
+
Raises:
|
|
362
|
+
ValueError: 不支持的后端或无法自动检测
|
|
363
|
+
ImportError: 所需的 ORM 库未安装
|
|
364
|
+
|
|
365
|
+
Example:
|
|
366
|
+
>>> # 自动检测
|
|
367
|
+
>>> user_repo = create_repository(User)
|
|
368
|
+
>>> users = await user_repo.all()
|
|
369
|
+
|
|
370
|
+
>>> # 指定后端
|
|
371
|
+
>>> user_repo = create_repository(User, backend="tortoise")
|
|
372
|
+
>>> user = await user_repo.create(name="Alice")
|
|
373
|
+
"""
|
|
374
|
+
if backend == "auto":
|
|
375
|
+
# 自动检测模型类型
|
|
376
|
+
if hasattr(model_class, '_meta') and hasattr(model_class._meta, 'table'):
|
|
377
|
+
backend = "tortoise"
|
|
378
|
+
elif hasattr(model_class, '__table__'):
|
|
379
|
+
backend = "sqlalchemy"
|
|
380
|
+
else:
|
|
381
|
+
raise ValueError(
|
|
382
|
+
f"无法自动检测模型类型: {model_class}. "
|
|
383
|
+
f"请显式指定 backend='tortoise' 或 'sqlalchemy'"
|
|
384
|
+
)
|
|
385
|
+
|
|
386
|
+
if backend == "tortoise":
|
|
387
|
+
if not _TORTOISE_AVAILABLE:
|
|
388
|
+
raise ImportError(
|
|
389
|
+
"Tortoise ORM 未安装。请运行: pip install infomankit[database]"
|
|
390
|
+
)
|
|
391
|
+
return TortoiseRepository(model_class)
|
|
392
|
+
|
|
393
|
+
elif backend == "sqlalchemy":
|
|
394
|
+
if not _SQLALCHEMY_AVAILABLE:
|
|
395
|
+
raise ImportError(
|
|
396
|
+
"SQLAlchemy 未安装。请运行: pip install infomankit[database-alchemy]"
|
|
397
|
+
)
|
|
398
|
+
|
|
399
|
+
if session_factory is None:
|
|
400
|
+
# 尝试从全局管理器获取
|
|
401
|
+
try:
|
|
402
|
+
from infoman.service.infrastructure.db_relation.manager import hybrid_db_manager
|
|
403
|
+
session_factory = hybrid_db_manager.get_sqlalchemy_session_maker()
|
|
404
|
+
except Exception:
|
|
405
|
+
raise ValueError(
|
|
406
|
+
"SQLAlchemy 后端需要提供 session_factory 参数,"
|
|
407
|
+
"或确保 HybridDatabaseManager 已初始化"
|
|
408
|
+
)
|
|
409
|
+
|
|
410
|
+
return SQLAlchemyRepository(model_class, session_factory)
|
|
411
|
+
|
|
412
|
+
else:
|
|
413
|
+
raise ValueError(f"不支持的后端: {backend}. 仅支持 'tortoise', 'sqlalchemy', 'auto'")
|
|
414
|
+
|
|
415
|
+
|
|
416
|
+
# ==================== 向前兼容导出 ====================
|
|
417
|
+
|
|
418
|
+
__all__ = [
|
|
419
|
+
# 抽象基类
|
|
420
|
+
'BaseTimestampMixin',
|
|
421
|
+
'BaseRepository',
|
|
422
|
+
|
|
423
|
+
# Tortoise(向前兼容)
|
|
424
|
+
'TimestampMixin',
|
|
425
|
+
'MySQLModel',
|
|
426
|
+
'PostgreSQLModel',
|
|
427
|
+
'SQLiteModel',
|
|
428
|
+
'TortoiseRepository',
|
|
429
|
+
|
|
430
|
+
# SQLAlchemy(新增)
|
|
431
|
+
'AlchemyBase',
|
|
432
|
+
'AlchemyTimestampMixin',
|
|
433
|
+
'SQLAlchemyRepository',
|
|
434
|
+
|
|
435
|
+
# 工厂函数
|
|
436
|
+
'create_repository',
|
|
437
|
+
|
|
438
|
+
# 可用性标志
|
|
439
|
+
'_TORTOISE_AVAILABLE',
|
|
440
|
+
'_SQLALCHEMY_AVAILABLE',
|
|
441
|
+
]
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
# !/usr/bin/env python
|
|
2
|
+
# -*-coding:utf-8 -*-
|
|
3
|
+
|
|
4
|
+
"""
|
|
5
|
+
# Time :2025/6/21 14:08
|
|
6
|
+
# Author :Maxwell
|
|
7
|
+
# Description:
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
from enum import Enum
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class EmbedModelProperty(object):
|
|
14
|
+
def __init__(self, model_name, dem: int, max_length: int):
|
|
15
|
+
self.model_name = model_name
|
|
16
|
+
self.dem = dem
|
|
17
|
+
self.max_length = max_length
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class EmbedModel(Enum):
|
|
21
|
+
M3E = EmbedModelProperty("m3e", dem=768, max_length=512)
|
|
22
|
+
BGE_M3 = EmbedModelProperty("bge_m3", dem=1024, max_length=8192)
|
|
23
|
+
|
|
24
|
+
@classmethod
|
|
25
|
+
def get_by_name(cls, name):
|
|
26
|
+
if cls.M3E.value.model_name == name:
|
|
27
|
+
return cls.M3E
|
|
28
|
+
return cls.BGE_M3
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
class EmbedDataType(Enum):
|
|
32
|
+
CONVERSION = "C"
|
|
33
|
+
KNOWLEDGE = "K"
|
|
34
|
+
DIARY = "D"
|
|
35
|
+
FILE = "F"
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
class EmbedDataProperty(object):
|
|
39
|
+
def __init__(
|
|
40
|
+
self, collection_name_prefix: str, filed_id_name: str, data_type: EmbedDataType
|
|
41
|
+
):
|
|
42
|
+
self.collection_name_prefix = collection_name_prefix
|
|
43
|
+
self.filed_id_name = filed_id_name
|
|
44
|
+
self.data_type = data_type
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
class EmbedCollectionConfig(Enum):
|
|
48
|
+
CONVERSION = EmbedDataProperty(
|
|
49
|
+
"user_conversion", "conversion_id", EmbedDataType.CONVERSION
|
|
50
|
+
)
|
|
51
|
+
KNOWLEDGE = EmbedDataProperty(
|
|
52
|
+
"user_knowledge", "knowledge_id", EmbedDataType.KNOWLEDGE
|
|
53
|
+
)
|
|
54
|
+
DIARY = EmbedDataProperty("user_diary", "diary_id", EmbedDataType.DIARY)
|
|
55
|
+
FILE = EmbedDataProperty("user_file", "file_id", EmbedDataType.FILE)
|
|
56
|
+
|
|
57
|
+
@classmethod
|
|
58
|
+
def get_by_data_type(cls, data_type: EmbedDataType):
|
|
59
|
+
for one in EmbedCollectionConfig:
|
|
60
|
+
if data_type.name == one.name:
|
|
61
|
+
return one.value
|
|
62
|
+
return None
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
class EmbedCollection(object):
|
|
66
|
+
|
|
67
|
+
@classmethod
|
|
68
|
+
def collection_name(cls, data_type: EmbedDataType, llm: EmbedModel) -> str:
|
|
69
|
+
data_property = EmbedCollectionConfig.get_by_data_type(data_type)
|
|
70
|
+
return f"{data_property.collection_name_prefix}_{llm.value.model_name}"
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# !/usr/bin/env python
|
|
2
|
+
# -*-coding:utf-8 -*-
|
|
3
|
+
|
|
4
|
+
"""
|
|
5
|
+
# Time :2024/2/2 10:10
|
|
6
|
+
# Author :Maxwell
|
|
7
|
+
# Description:
|
|
8
|
+
"""
|
|
9
|
+
from fastapi import APIRouter
|
|
10
|
+
from infoman.service.routers.monitor_router import monitor_router
|
|
11
|
+
from infoman.service.routers.health_router import health_router
|
|
12
|
+
from infoman.config.settings import settings
|
|
13
|
+
|
|
14
|
+
api_router = APIRouter(prefix=settings.APP_BASE_URI)
|
|
15
|
+
api_router.include_router(
|
|
16
|
+
prefix="/api/monitor", router=monitor_router, tags=["服务状态"]
|
|
17
|
+
)
|
|
18
|
+
api_router.include_router(prefix="/api/health", router=health_router, tags=["服务状态"])
|