mirror of
https://github.com/DrizzleTime/Foxel.git
synced 2026-09-04 23:29:00 +08:00
refactor: imports and reorganize domain structure
- Updated import statements across multiple modules to use relative imports for better encapsulation. - Consolidated and organized the `__init__.py` files in various domain packages to expose necessary classes and functions. - Improved code readability and maintainability by grouping related imports and removing unused ones. - Ensured consistent import patterns across the domain, enhancing the overall structure of the codebase.
This commit is contained in:
+2
-2
@@ -15,7 +15,7 @@ from domain.agent import api as agent
|
|||||||
from domain.virtual_fs import api as virtual_fs
|
from domain.virtual_fs import api as virtual_fs
|
||||||
from domain.virtual_fs.mapping import s3_api, webdav_api
|
from domain.virtual_fs.mapping import s3_api, webdav_api
|
||||||
from domain.virtual_fs.search import search_api
|
from domain.virtual_fs.search import search_api
|
||||||
from domain.audit import router as audit
|
from domain.audit import api as audit
|
||||||
|
|
||||||
|
|
||||||
def include_routers(app: FastAPI):
|
def include_routers(app: FastAPI):
|
||||||
@@ -37,4 +37,4 @@ def include_routers(app: FastAPI):
|
|||||||
app.include_router(s3_api.router)
|
app.include_router(s3_api.router)
|
||||||
app.include_router(offline_downloads.router)
|
app.include_router(offline_downloads.router)
|
||||||
app.include_router(email.router)
|
app.include_router(email.router)
|
||||||
app.include_router(audit)
|
app.include_router(audit.router)
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
from tortoise import Tortoise
|
from tortoise import Tortoise
|
||||||
|
|
||||||
from domain.adapters.registry import runtime_registry
|
from domain.adapters import runtime_registry
|
||||||
|
|
||||||
TORTOISE_ORM = {
|
TORTOISE_ORM = {
|
||||||
"connections": {"default": "sqlite://data/db/db.sqlite3"},
|
"connections": {"default": "sqlite://data/db/db.sqlite3"},
|
||||||
|
|||||||
@@ -0,0 +1,7 @@
|
|||||||
|
"""
|
||||||
|
domain:业务域层
|
||||||
|
|
||||||
|
约定:跨包只从各子包 `__init__.py` 导入公开 API。
|
||||||
|
"""
|
||||||
|
|
||||||
|
__all__: list[str] = []
|
||||||
@@ -1 +1,24 @@
|
|||||||
|
from .providers import BaseAdapter
|
||||||
|
from .registry import (
|
||||||
|
RuntimeRegistry,
|
||||||
|
discover_adapters,
|
||||||
|
get_config_schema,
|
||||||
|
get_config_schemas,
|
||||||
|
normalize_adapter_type,
|
||||||
|
runtime_registry,
|
||||||
|
)
|
||||||
|
from .service import AdapterService
|
||||||
|
from .types import AdapterCreate, AdapterOut
|
||||||
|
|
||||||
|
__all__ = [
|
||||||
|
"BaseAdapter",
|
||||||
|
"RuntimeRegistry",
|
||||||
|
"discover_adapters",
|
||||||
|
"get_config_schema",
|
||||||
|
"get_config_schemas",
|
||||||
|
"normalize_adapter_type",
|
||||||
|
"runtime_registry",
|
||||||
|
"AdapterService",
|
||||||
|
"AdapterCreate",
|
||||||
|
"AdapterOut",
|
||||||
|
]
|
||||||
|
|||||||
@@ -4,10 +4,9 @@ from fastapi import APIRouter, Depends, Request
|
|||||||
|
|
||||||
from api.response import success
|
from api.response import success
|
||||||
from domain.audit import AuditAction, audit
|
from domain.audit import AuditAction, audit
|
||||||
from domain.adapters.service import AdapterService
|
from domain.auth import User, get_current_active_user
|
||||||
from domain.adapters.types import AdapterCreate
|
from .service import AdapterService
|
||||||
from domain.auth.service import get_current_active_user
|
from .types import AdapterCreate
|
||||||
from domain.auth.types import User
|
|
||||||
|
|
||||||
router = APIRouter(prefix="/api/adapters", tags=["adapters"])
|
router = APIRouter(prefix="/api/adapters", tags=["adapters"])
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ from importlib import import_module
|
|||||||
from typing import Callable, Dict
|
from typing import Callable, Dict
|
||||||
|
|
||||||
from models import StorageAdapter
|
from models import StorageAdapter
|
||||||
from domain.adapters.providers.base import BaseAdapter
|
from .providers.base import BaseAdapter
|
||||||
|
|
||||||
AdapterFactory = Callable[[StorageAdapter], BaseAdapter]
|
AdapterFactory = Callable[[StorageAdapter], BaseAdapter]
|
||||||
|
|
||||||
@@ -21,7 +21,7 @@ def normalize_adapter_type(value: str | None) -> str | None:
|
|||||||
|
|
||||||
def discover_adapters():
|
def discover_adapters():
|
||||||
"""扫描 domain.adapters.providers 包, 自动注册适配器类型、工厂与配置 schema。"""
|
"""扫描 domain.adapters.providers 包, 自动注册适配器类型、工厂与配置 schema。"""
|
||||||
from domain.adapters import providers as adapters_pkg
|
from . import providers as adapters_pkg
|
||||||
|
|
||||||
TYPE_MAP.clear()
|
TYPE_MAP.clear()
|
||||||
CONFIG_SCHEMAS.clear()
|
CONFIG_SCHEMAS.clear()
|
||||||
|
|||||||
@@ -2,13 +2,13 @@ from typing import Optional
|
|||||||
|
|
||||||
from fastapi import HTTPException
|
from fastapi import HTTPException
|
||||||
|
|
||||||
from domain.adapters.registry import (
|
from domain.auth import User
|
||||||
|
from .registry import (
|
||||||
get_config_schemas,
|
get_config_schemas,
|
||||||
normalize_adapter_type,
|
normalize_adapter_type,
|
||||||
runtime_registry,
|
runtime_registry,
|
||||||
)
|
)
|
||||||
from domain.adapters.types import AdapterCreate, AdapterOut
|
from .types import AdapterCreate, AdapterOut
|
||||||
from domain.auth.types import User
|
|
||||||
from models import StorageAdapter
|
from models import StorageAdapter
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,9 @@
|
|||||||
from .api import router
|
from .service import AgentService
|
||||||
|
from .types import AgentChatContext, AgentChatRequest, PendingToolCall
|
||||||
__all__ = ["router"]
|
|
||||||
|
|
||||||
|
__all__ = [
|
||||||
|
"AgentService",
|
||||||
|
"AgentChatContext",
|
||||||
|
"AgentChatRequest",
|
||||||
|
"PendingToolCall",
|
||||||
|
]
|
||||||
|
|||||||
+3
-4
@@ -4,11 +4,10 @@ from fastapi import APIRouter, Depends, Request
|
|||||||
from fastapi.responses import StreamingResponse
|
from fastapi.responses import StreamingResponse
|
||||||
|
|
||||||
from api.response import success
|
from api.response import success
|
||||||
from domain.agent.service import AgentService
|
|
||||||
from domain.agent.types import AgentChatRequest
|
|
||||||
from domain.audit import AuditAction, audit
|
from domain.audit import AuditAction, audit
|
||||||
from domain.auth.service import get_current_active_user
|
from domain.auth import User, get_current_active_user
|
||||||
from domain.auth.types import User
|
from .service import AgentService
|
||||||
|
from .types import AgentChatRequest
|
||||||
|
|
||||||
|
|
||||||
router = APIRouter(prefix="/api/agent", tags=["agent"])
|
router = APIRouter(prefix="/api/agent", tags=["agent"])
|
||||||
|
|||||||
+30
-8
@@ -6,11 +6,10 @@ from typing import Any, Dict, List, Optional, Tuple
|
|||||||
import httpx
|
import httpx
|
||||||
from fastapi import HTTPException
|
from fastapi import HTTPException
|
||||||
|
|
||||||
from domain.agent.tools import get_tool, openai_tools, tool_result_to_content
|
from domain.ai import AIProviderService, MissingModelError, chat_completion, chat_completion_stream
|
||||||
from domain.agent.types import AgentChatRequest, PendingToolCall
|
from domain.auth import User
|
||||||
from domain.ai.inference import MissingModelError, chat_completion, chat_completion_stream
|
from .tools import get_tool, openai_tools, tool_result_to_content
|
||||||
from domain.ai.service import AIProviderService
|
from .types import AgentChatRequest, PendingToolCall
|
||||||
from domain.auth.types import User
|
|
||||||
|
|
||||||
|
|
||||||
def _normalize_path(p: Optional[str]) -> Optional[str]:
|
def _normalize_path(p: Optional[str]) -> Optional[str]:
|
||||||
@@ -136,6 +135,11 @@ def _sse(event: str, data: Any) -> bytes:
|
|||||||
return f"event: {event}\ndata: {payload}\n\n".encode("utf-8")
|
return f"event: {event}\ndata: {payload}\n\n".encode("utf-8")
|
||||||
|
|
||||||
|
|
||||||
|
def _format_exc(exc: BaseException) -> str:
|
||||||
|
text = str(exc)
|
||||||
|
return text if text else exc.__class__.__name__
|
||||||
|
|
||||||
|
|
||||||
class AgentService:
|
class AgentService:
|
||||||
@classmethod
|
@classmethod
|
||||||
async def chat(cls, req: AgentChatRequest, user: Optional[User]) -> Dict[str, Any]:
|
async def chat(cls, req: AgentChatRequest, user: Optional[User]) -> Dict[str, Any]:
|
||||||
@@ -376,11 +380,11 @@ class AgentService:
|
|||||||
if isinstance(msg, dict):
|
if isinstance(msg, dict):
|
||||||
assistant_message = msg
|
assistant_message = msg
|
||||||
except MissingModelError as exc:
|
except MissingModelError as exc:
|
||||||
raise HTTPException(status_code=400, detail=str(exc)) from exc
|
raise HTTPException(status_code=400, detail=_format_exc(exc)) from exc
|
||||||
except httpx.HTTPStatusError as exc:
|
except httpx.HTTPStatusError as exc:
|
||||||
raise HTTPException(status_code=502, detail=f"对话请求失败: {exc}") from exc
|
raise HTTPException(status_code=502, detail=f"对话请求失败: {_format_exc(exc)}") from exc
|
||||||
except httpx.RequestError as exc:
|
except httpx.RequestError as exc:
|
||||||
raise HTTPException(status_code=502, detail=f"对话请求异常: {exc}") from exc
|
raise HTTPException(status_code=502, detail=f"对话请求异常: {_format_exc(exc)}") from exc
|
||||||
|
|
||||||
if not assistant_message:
|
if not assistant_message:
|
||||||
assistant_message = {"role": "assistant", "content": ""}
|
assistant_message = {"role": "assistant", "content": ""}
|
||||||
@@ -446,3 +450,21 @@ class AgentService:
|
|||||||
|
|
||||||
except asyncio.CancelledError:
|
except asyncio.CancelledError:
|
||||||
return
|
return
|
||||||
|
except HTTPException as exc:
|
||||||
|
detail = exc.detail
|
||||||
|
content = detail if isinstance(detail, str) else str(detail)
|
||||||
|
if not content.strip():
|
||||||
|
content = f"请求失败({exc.status_code})"
|
||||||
|
new_messages.append({"role": "assistant", "content": content})
|
||||||
|
payload: Dict[str, Any] = {"messages": new_messages}
|
||||||
|
if pending:
|
||||||
|
payload["pending_tool_calls"] = [p.model_dump() for p in pending]
|
||||||
|
yield _sse("done", payload)
|
||||||
|
return
|
||||||
|
except Exception as exc: # noqa: BLE001
|
||||||
|
new_messages.append({"role": "assistant", "content": f"服务端异常: {_format_exc(exc)}"})
|
||||||
|
payload: Dict[str, Any] = {"messages": new_messages}
|
||||||
|
if pending:
|
||||||
|
payload["pending_tool_calls"] = [p.model_dump() for p in pending]
|
||||||
|
yield _sse("done", payload)
|
||||||
|
return
|
||||||
|
|||||||
@@ -2,10 +2,9 @@ import json
|
|||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
from typing import Any, Awaitable, Callable, Dict, List, Optional
|
from typing import Any, Awaitable, Callable, Dict, List, Optional
|
||||||
|
|
||||||
from domain.processors.service import ProcessorService
|
from domain.processors import ProcessDirectoryRequest, ProcessRequest, ProcessorService
|
||||||
from domain.processors.types import ProcessDirectoryRequest, ProcessRequest
|
from domain.virtual_fs import VirtualFSService
|
||||||
from domain.virtual_fs.service import VirtualFSService
|
from domain.virtual_fs.search import VirtualFSSearchService
|
||||||
from domain.virtual_fs.search.search_service import VirtualFSSearchService
|
|
||||||
|
|
||||||
|
|
||||||
@dataclass(frozen=True)
|
@dataclass(frozen=True)
|
||||||
|
|||||||
+39
-6
@@ -1,28 +1,61 @@
|
|||||||
from .api import router_ai, router_vector_db
|
from .inference import (
|
||||||
|
MissingModelError,
|
||||||
|
chat_completion,
|
||||||
|
chat_completion_stream,
|
||||||
|
describe_image_base64,
|
||||||
|
get_text_embedding,
|
||||||
|
provider_service,
|
||||||
|
rerank_texts,
|
||||||
|
)
|
||||||
from .service import (
|
from .service import (
|
||||||
AIProviderService,
|
AIProviderService,
|
||||||
|
FILE_COLLECTION_NAME,
|
||||||
|
VECTOR_COLLECTION_NAME,
|
||||||
|
DEFAULT_VECTOR_DIMENSION,
|
||||||
VectorDBConfigManager,
|
VectorDBConfigManager,
|
||||||
VectorDBService,
|
VectorDBService,
|
||||||
DEFAULT_VECTOR_DIMENSION,
|
|
||||||
ABILITIES,
|
|
||||||
normalize_capabilities,
|
|
||||||
)
|
)
|
||||||
from .types import (
|
from .types import (
|
||||||
|
ABILITIES,
|
||||||
AIDefaultsUpdate,
|
AIDefaultsUpdate,
|
||||||
AIModelCreate,
|
AIModelCreate,
|
||||||
AIModelUpdate,
|
AIModelUpdate,
|
||||||
AIProviderCreate,
|
AIProviderCreate,
|
||||||
AIProviderUpdate,
|
AIProviderUpdate,
|
||||||
VectorDBConfigPayload,
|
VectorDBConfigPayload,
|
||||||
|
normalize_capabilities,
|
||||||
|
)
|
||||||
|
from .vector_providers import (
|
||||||
|
BaseVectorProvider,
|
||||||
|
MilvusLiteProvider,
|
||||||
|
MilvusServerProvider,
|
||||||
|
QdrantProvider,
|
||||||
|
get_provider_class,
|
||||||
|
get_provider_entry,
|
||||||
|
list_providers,
|
||||||
)
|
)
|
||||||
|
|
||||||
__all__ = [
|
__all__ = [
|
||||||
"router_ai",
|
"MissingModelError",
|
||||||
"router_vector_db",
|
"chat_completion",
|
||||||
|
"chat_completion_stream",
|
||||||
|
"describe_image_base64",
|
||||||
|
"get_text_embedding",
|
||||||
|
"provider_service",
|
||||||
|
"rerank_texts",
|
||||||
"AIProviderService",
|
"AIProviderService",
|
||||||
"VectorDBService",
|
"VectorDBService",
|
||||||
"VectorDBConfigManager",
|
"VectorDBConfigManager",
|
||||||
"DEFAULT_VECTOR_DIMENSION",
|
"DEFAULT_VECTOR_DIMENSION",
|
||||||
|
"VECTOR_COLLECTION_NAME",
|
||||||
|
"FILE_COLLECTION_NAME",
|
||||||
|
"BaseVectorProvider",
|
||||||
|
"MilvusLiteProvider",
|
||||||
|
"MilvusServerProvider",
|
||||||
|
"QdrantProvider",
|
||||||
|
"list_providers",
|
||||||
|
"get_provider_entry",
|
||||||
|
"get_provider_class",
|
||||||
"ABILITIES",
|
"ABILITIES",
|
||||||
"normalize_capabilities",
|
"normalize_capabilities",
|
||||||
"AIDefaultsUpdate",
|
"AIDefaultsUpdate",
|
||||||
|
|||||||
+4
-5
@@ -5,8 +5,9 @@ from fastapi import APIRouter, Depends, HTTPException, Path, Request
|
|||||||
|
|
||||||
from api.response import success
|
from api.response import success
|
||||||
from domain.audit import AuditAction, audit
|
from domain.audit import AuditAction, audit
|
||||||
from domain.ai.service import AIProviderService, VectorDBConfigManager, VectorDBService
|
from domain.auth import User, get_current_active_user
|
||||||
from domain.ai.types import (
|
from .service import AIProviderService, VectorDBConfigManager, VectorDBService
|
||||||
|
from .types import (
|
||||||
AIDefaultsUpdate,
|
AIDefaultsUpdate,
|
||||||
AIModelCreate,
|
AIModelCreate,
|
||||||
AIModelUpdate,
|
AIModelUpdate,
|
||||||
@@ -14,9 +15,7 @@ from domain.ai.types import (
|
|||||||
AIProviderUpdate,
|
AIProviderUpdate,
|
||||||
VectorDBConfigPayload,
|
VectorDBConfigPayload,
|
||||||
)
|
)
|
||||||
from domain.ai.vector_providers import get_provider_class, get_provider_entry, list_providers
|
from .vector_providers import get_provider_class, get_provider_entry, list_providers
|
||||||
from domain.auth.service import get_current_active_user
|
|
||||||
from domain.auth.types import User
|
|
||||||
|
|
||||||
router_ai = APIRouter(prefix="/api/ai", tags=["ai"])
|
router_ai = APIRouter(prefix="/api/ai", tags=["ai"])
|
||||||
router_vector_db = APIRouter(prefix="/api/vector-db", tags=["vector-db"])
|
router_vector_db = APIRouter(prefix="/api/vector-db", tags=["vector-db"])
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import httpx
|
|||||||
from typing import Any, AsyncIterator, Dict, List, Sequence, Tuple
|
from typing import Any, AsyncIterator, Dict, List, Sequence, Tuple
|
||||||
|
|
||||||
from models.database import AIModel, AIProvider
|
from models.database import AIModel, AIProvider
|
||||||
from domain.ai.service import AIProviderService
|
from .service import AIProviderService
|
||||||
|
|
||||||
|
|
||||||
provider_service = AIProviderService
|
provider_service = AIProviderService
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import httpx
|
|||||||
from tortoise.exceptions import DoesNotExist
|
from tortoise.exceptions import DoesNotExist
|
||||||
from tortoise.transactions import in_transaction
|
from tortoise.transactions import in_transaction
|
||||||
|
|
||||||
from domain.config.service import ConfigService
|
from domain.config import ConfigService
|
||||||
from models.database import AIDefaultModel, AIModel, AIProvider
|
from models.database import AIDefaultModel, AIModel, AIProvider
|
||||||
|
|
||||||
from .types import ABILITIES, normalize_capabilities
|
from .types import ABILITIES, normalize_capabilities
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
from domain.audit.decorator import audit
|
from .decorator import audit
|
||||||
from domain.audit.types import AuditAction
|
from .types import AuditAction
|
||||||
from domain.audit.api import router
|
|
||||||
|
|
||||||
__all__ = ["audit", "AuditAction", "router"]
|
__all__ = ["audit", "AuditAction"]
|
||||||
|
|||||||
+3
-4
@@ -4,10 +4,9 @@ from typing import Annotated, Optional
|
|||||||
from fastapi import APIRouter, Depends, HTTPException, Query
|
from fastapi import APIRouter, Depends, HTTPException, Query
|
||||||
|
|
||||||
from api import response
|
from api import response
|
||||||
from domain.audit.service import AuditService
|
from domain.auth import User, get_current_active_user
|
||||||
from domain.audit.types import AuditAction
|
from .service import AuditService
|
||||||
from domain.auth.service import get_current_active_user
|
from .types import AuditAction
|
||||||
from domain.auth.types import User
|
|
||||||
|
|
||||||
CurrentUser = Annotated[User, Depends(get_current_active_user)]
|
CurrentUser = Annotated[User, Depends(get_current_active_user)]
|
||||||
|
|
||||||
|
|||||||
@@ -7,11 +7,11 @@ import jwt
|
|||||||
from fastapi import Request
|
from fastapi import Request
|
||||||
from jwt.exceptions import InvalidTokenError
|
from jwt.exceptions import InvalidTokenError
|
||||||
|
|
||||||
from domain.audit.service import AuditService
|
from domain.auth import ALGORITHM
|
||||||
from domain.audit.types import AuditAction
|
from domain.config import ConfigService
|
||||||
from domain.auth.service import ALGORITHM
|
|
||||||
from domain.config.service import ConfigService
|
|
||||||
from models.database import UserAccount
|
from models.database import UserAccount
|
||||||
|
from .service import AuditService
|
||||||
|
from .types import AuditAction
|
||||||
|
|
||||||
|
|
||||||
def _extract_request(bound_args: Mapping[str, Any]) -> Request | None:
|
def _extract_request(bound_args: Mapping[str, Any]) -> Request | None:
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ from typing import Any, Dict, Optional
|
|||||||
|
|
||||||
from models.database import AuditLog
|
from models.database import AuditLog
|
||||||
|
|
||||||
from domain.audit.types import AuditAction
|
from .types import AuditAction
|
||||||
|
|
||||||
|
|
||||||
class AuditService:
|
class AuditService:
|
||||||
|
|||||||
@@ -0,0 +1,49 @@
|
|||||||
|
from .service import (
|
||||||
|
ALGORITHM,
|
||||||
|
AuthService,
|
||||||
|
authenticate_user_db,
|
||||||
|
create_access_token,
|
||||||
|
get_current_active_user,
|
||||||
|
get_current_user,
|
||||||
|
get_password_hash,
|
||||||
|
has_users,
|
||||||
|
register_user,
|
||||||
|
request_password_reset,
|
||||||
|
reset_password_with_token,
|
||||||
|
verify_password,
|
||||||
|
verify_password_reset_token,
|
||||||
|
)
|
||||||
|
from .types import (
|
||||||
|
PasswordResetConfirm,
|
||||||
|
PasswordResetRequest,
|
||||||
|
RegisterRequest,
|
||||||
|
Token,
|
||||||
|
TokenData,
|
||||||
|
UpdateMeRequest,
|
||||||
|
User,
|
||||||
|
UserInDB,
|
||||||
|
)
|
||||||
|
|
||||||
|
__all__ = [
|
||||||
|
"ALGORITHM",
|
||||||
|
"AuthService",
|
||||||
|
"authenticate_user_db",
|
||||||
|
"create_access_token",
|
||||||
|
"get_current_active_user",
|
||||||
|
"get_current_user",
|
||||||
|
"get_password_hash",
|
||||||
|
"has_users",
|
||||||
|
"register_user",
|
||||||
|
"request_password_reset",
|
||||||
|
"reset_password_with_token",
|
||||||
|
"verify_password",
|
||||||
|
"verify_password_reset_token",
|
||||||
|
"PasswordResetConfirm",
|
||||||
|
"PasswordResetRequest",
|
||||||
|
"RegisterRequest",
|
||||||
|
"Token",
|
||||||
|
"TokenData",
|
||||||
|
"UpdateMeRequest",
|
||||||
|
"User",
|
||||||
|
"UserInDB",
|
||||||
|
]
|
||||||
+2
-2
@@ -5,8 +5,8 @@ from fastapi.security import OAuth2PasswordRequestForm
|
|||||||
|
|
||||||
from api.response import success
|
from api.response import success
|
||||||
from domain.audit import AuditAction, audit
|
from domain.audit import AuditAction, audit
|
||||||
from domain.auth.service import AuthService, get_current_active_user
|
from .service import AuthService, get_current_active_user
|
||||||
from domain.auth.types import (
|
from .types import (
|
||||||
PasswordResetConfirm,
|
PasswordResetConfirm,
|
||||||
PasswordResetRequest,
|
PasswordResetRequest,
|
||||||
RegisterRequest,
|
RegisterRequest,
|
||||||
|
|||||||
@@ -11,7 +11,9 @@ from fastapi import Depends, HTTPException, status
|
|||||||
from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm
|
from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm
|
||||||
from jwt.exceptions import InvalidTokenError
|
from jwt.exceptions import InvalidTokenError
|
||||||
|
|
||||||
from domain.auth.types import (
|
from domain.config import ConfigService
|
||||||
|
from models.database import UserAccount
|
||||||
|
from .types import (
|
||||||
PasswordResetConfirm,
|
PasswordResetConfirm,
|
||||||
PasswordResetRequest,
|
PasswordResetRequest,
|
||||||
RegisterRequest,
|
RegisterRequest,
|
||||||
@@ -21,8 +23,6 @@ from domain.auth.types import (
|
|||||||
User,
|
User,
|
||||||
UserInDB,
|
UserInDB,
|
||||||
)
|
)
|
||||||
from models.database import UserAccount
|
|
||||||
from domain.config.service import ConfigService
|
|
||||||
|
|
||||||
ALGORITHM = "HS256"
|
ALGORITHM = "HS256"
|
||||||
ACCESS_TOKEN_EXPIRE_MINUTES = 60 * 24 * 365
|
ACCESS_TOKEN_EXPIRE_MINUTES = 60 * 24 * 365
|
||||||
@@ -324,7 +324,7 @@ class AuthService:
|
|||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def _send_password_reset_email(cls, user: UserAccount, token: str) -> None:
|
async def _send_password_reset_email(cls, user: UserAccount, token: str) -> None:
|
||||||
from domain.email.service import EmailService
|
from domain.email import EmailService
|
||||||
|
|
||||||
app_domain = await ConfigService.get("APP_DOMAIN", None)
|
app_domain = await ConfigService.get("APP_DOMAIN", None)
|
||||||
base_url = (app_domain or "http://localhost:5173").rstrip("/")
|
base_url = (app_domain or "http://localhost:5173").rstrip("/")
|
||||||
|
|||||||
@@ -1 +1,7 @@
|
|||||||
|
from .service import BackupService
|
||||||
|
from .types import BackupData
|
||||||
|
|
||||||
|
__all__ = [
|
||||||
|
"BackupService",
|
||||||
|
"BackupData",
|
||||||
|
]
|
||||||
|
|||||||
@@ -4,8 +4,8 @@ from fastapi import APIRouter, Depends, File, Request, UploadFile
|
|||||||
from fastapi.responses import JSONResponse
|
from fastapi.responses import JSONResponse
|
||||||
|
|
||||||
from domain.audit import AuditAction, audit
|
from domain.audit import AuditAction, audit
|
||||||
from domain.auth.service import get_current_active_user
|
from domain.auth import get_current_active_user
|
||||||
from domain.backup.service import BackupService
|
from .service import BackupService
|
||||||
|
|
||||||
router = APIRouter(
|
router = APIRouter(
|
||||||
prefix="/api/backup",
|
prefix="/api/backup",
|
||||||
|
|||||||
@@ -4,8 +4,8 @@ from datetime import datetime
|
|||||||
from fastapi import HTTPException
|
from fastapi import HTTPException
|
||||||
from tortoise.transactions import in_transaction
|
from tortoise.transactions import in_transaction
|
||||||
|
|
||||||
from domain.backup.types import BackupData
|
from domain.config import VERSION
|
||||||
from domain.config.service import VERSION
|
from .types import BackupData
|
||||||
from models.database import (
|
from models.database import (
|
||||||
AIDefaultModel,
|
AIDefaultModel,
|
||||||
AIModel,
|
AIModel,
|
||||||
|
|||||||
@@ -0,0 +1,10 @@
|
|||||||
|
from .service import ConfigService, VERSION
|
||||||
|
from .types import ConfigItem, LatestVersionInfo, SystemStatus
|
||||||
|
|
||||||
|
__all__ = [
|
||||||
|
"ConfigService",
|
||||||
|
"VERSION",
|
||||||
|
"ConfigItem",
|
||||||
|
"LatestVersionInfo",
|
||||||
|
"SystemStatus",
|
||||||
|
]
|
||||||
@@ -4,10 +4,9 @@ from fastapi import APIRouter, Depends, Form, Request
|
|||||||
|
|
||||||
from api.response import success
|
from api.response import success
|
||||||
from domain.audit import AuditAction, audit
|
from domain.audit import AuditAction, audit
|
||||||
from domain.auth.service import get_current_active_user
|
from domain.auth import User, get_current_active_user
|
||||||
from domain.auth.types import User
|
from .service import ConfigService
|
||||||
from domain.config.service import ConfigService
|
from .types import ConfigItem
|
||||||
from domain.config.types import ConfigItem
|
|
||||||
|
|
||||||
router = APIRouter(prefix="/api/config", tags=["config"])
|
router = APIRouter(prefix="/api/config", tags=["config"])
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ from typing import Any, Dict, Optional
|
|||||||
import httpx
|
import httpx
|
||||||
from dotenv import load_dotenv
|
from dotenv import load_dotenv
|
||||||
|
|
||||||
from domain.config.types import LatestVersionInfo, SystemStatus
|
from .types import LatestVersionInfo, SystemStatus
|
||||||
from models.database import Configuration, UserAccount
|
from models.database import Configuration, UserAccount
|
||||||
|
|
||||||
load_dotenv(dotenv_path=".env")
|
load_dotenv(dotenv_path=".env")
|
||||||
|
|||||||
@@ -0,0 +1,20 @@
|
|||||||
|
from .service import EmailService, EmailTemplateRenderer
|
||||||
|
from .types import (
|
||||||
|
EmailConfig,
|
||||||
|
EmailSecurity,
|
||||||
|
EmailSendPayload,
|
||||||
|
EmailTemplatePreviewPayload,
|
||||||
|
EmailTemplateUpdate,
|
||||||
|
EmailTestRequest,
|
||||||
|
)
|
||||||
|
|
||||||
|
__all__ = [
|
||||||
|
"EmailService",
|
||||||
|
"EmailTemplateRenderer",
|
||||||
|
"EmailConfig",
|
||||||
|
"EmailSecurity",
|
||||||
|
"EmailSendPayload",
|
||||||
|
"EmailTemplatePreviewPayload",
|
||||||
|
"EmailTemplateUpdate",
|
||||||
|
"EmailTestRequest",
|
||||||
|
]
|
||||||
+3
-4
@@ -2,10 +2,9 @@ from fastapi import APIRouter, Depends, HTTPException, Request
|
|||||||
|
|
||||||
from api.response import success
|
from api.response import success
|
||||||
from domain.audit import AuditAction, audit
|
from domain.audit import AuditAction, audit
|
||||||
from domain.auth.service import get_current_active_user
|
from domain.auth import User, get_current_active_user
|
||||||
from domain.auth.types import User
|
from .service import EmailService, EmailTemplateRenderer
|
||||||
from domain.email.service import EmailService, EmailTemplateRenderer
|
from .types import (
|
||||||
from domain.email.types import (
|
|
||||||
EmailTemplatePreviewPayload,
|
EmailTemplatePreviewPayload,
|
||||||
EmailTemplateUpdate,
|
EmailTemplateUpdate,
|
||||||
EmailTestRequest,
|
EmailTestRequest,
|
||||||
|
|||||||
@@ -7,8 +7,8 @@ from pathlib import Path
|
|||||||
from string import Template
|
from string import Template
|
||||||
from typing import Any, Dict, List, Optional
|
from typing import Any, Dict, List, Optional
|
||||||
|
|
||||||
from domain.config.service import ConfigService
|
from domain.config import ConfigService
|
||||||
from domain.email.types import EmailConfig, EmailSecurity, EmailSendPayload
|
from .types import EmailConfig, EmailSecurity, EmailSendPayload
|
||||||
|
|
||||||
|
|
||||||
class EmailTemplateRenderer:
|
class EmailTemplateRenderer:
|
||||||
@@ -104,7 +104,7 @@ class EmailService:
|
|||||||
template: str,
|
template: str,
|
||||||
context: Optional[Dict[str, Any]] = None,
|
context: Optional[Dict[str, Any]] = None,
|
||||||
):
|
):
|
||||||
from domain.tasks.task_queue import TaskProgress, task_queue_service
|
from domain.tasks import TaskProgress, task_queue_service
|
||||||
|
|
||||||
payload = EmailSendPayload(
|
payload = EmailSendPayload(
|
||||||
recipients=recipients,
|
recipients=recipients,
|
||||||
@@ -126,7 +126,7 @@ class EmailService:
|
|||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def send_from_task(cls, task_id: str, data: Dict[str, Any]):
|
async def send_from_task(cls, task_id: str, data: Dict[str, Any]):
|
||||||
from domain.tasks.task_queue import TaskProgress, task_queue_service
|
from domain.tasks import TaskProgress, task_queue_service
|
||||||
|
|
||||||
payload = EmailSendPayload(**data)
|
payload = EmailSendPayload(**data)
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,7 @@
|
|||||||
|
from .service import OfflineDownloadService
|
||||||
|
from .types import OfflineDownloadCreate
|
||||||
|
|
||||||
|
__all__ = [
|
||||||
|
"OfflineDownloadService",
|
||||||
|
"OfflineDownloadCreate",
|
||||||
|
]
|
||||||
@@ -4,10 +4,9 @@ from fastapi import APIRouter, Depends, Request
|
|||||||
|
|
||||||
from api.response import success
|
from api.response import success
|
||||||
from domain.audit import AuditAction, audit
|
from domain.audit import AuditAction, audit
|
||||||
from domain.auth.service import get_current_active_user
|
from domain.auth import User, get_current_active_user
|
||||||
from domain.auth.types import User
|
from .service import OfflineDownloadService
|
||||||
from domain.offline_downloads.service import OfflineDownloadService
|
from .types import OfflineDownloadCreate
|
||||||
from domain.offline_downloads.types import OfflineDownloadCreate
|
|
||||||
|
|
||||||
CurrentUser = Annotated[User, Depends(get_current_active_user)]
|
CurrentUser = Annotated[User, Depends(get_current_active_user)]
|
||||||
|
|
||||||
|
|||||||
@@ -7,11 +7,10 @@ import aiofiles
|
|||||||
import aiohttp
|
import aiohttp
|
||||||
from fastapi import Depends, HTTPException
|
from fastapi import Depends, HTTPException
|
||||||
|
|
||||||
from domain.auth.service import get_current_active_user
|
from domain.auth import User, get_current_active_user
|
||||||
from domain.auth.types import User
|
from domain.tasks import Task, TaskProgress, task_queue_service
|
||||||
from domain.offline_downloads.types import OfflineDownloadCreate
|
from domain.virtual_fs import VirtualFSService
|
||||||
from domain.virtual_fs.service import VirtualFSService
|
from .types import OfflineDownloadCreate
|
||||||
from domain.tasks.task_queue import Task, TaskProgress, task_queue_service
|
|
||||||
|
|
||||||
|
|
||||||
class OfflineDownloadService:
|
class OfflineDownloadService:
|
||||||
|
|||||||
@@ -4,9 +4,9 @@ Foxel 插件系统
|
|||||||
提供 .foxpkg 插件包的安装、管理和运行时加载功能。
|
提供 .foxpkg 插件包的安装、管理和运行时加载功能。
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from domain.plugins.loader import PluginLoader, PluginLoadError
|
from .loader import PluginLoadError, PluginLoader
|
||||||
from domain.plugins.service import PluginService
|
from .service import PluginService
|
||||||
from domain.plugins.startup import init_plugins, load_installed_plugins
|
from .startup import init_plugins, load_installed_plugins
|
||||||
|
|
||||||
__all__ = [
|
__all__ = [
|
||||||
"PluginLoader",
|
"PluginLoader",
|
||||||
|
|||||||
@@ -8,8 +8,8 @@ from fastapi import APIRouter, File, Request, UploadFile
|
|||||||
from fastapi.responses import FileResponse
|
from fastapi.responses import FileResponse
|
||||||
|
|
||||||
from domain.audit import AuditAction, audit
|
from domain.audit import AuditAction, audit
|
||||||
from domain.plugins.service import PluginService
|
from .service import PluginService
|
||||||
from domain.plugins.types import (
|
from .types import (
|
||||||
PluginInstallResult,
|
PluginInstallResult,
|
||||||
PluginOut,
|
PluginOut,
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ from typing import Any, Dict, List, Optional, Tuple
|
|||||||
|
|
||||||
from fastapi import APIRouter
|
from fastapi import APIRouter
|
||||||
|
|
||||||
from domain.plugins.types import (
|
from .types import (
|
||||||
ManifestProcessorConfig,
|
ManifestProcessorConfig,
|
||||||
ManifestRouteConfig,
|
ManifestRouteConfig,
|
||||||
PluginManifest,
|
PluginManifest,
|
||||||
@@ -344,7 +344,7 @@ class PluginLoader:
|
|||||||
supported_exts = getattr(module, "SUPPORTED_EXTS", [])
|
supported_exts = getattr(module, "SUPPORTED_EXTS", [])
|
||||||
|
|
||||||
# 注册到处理器注册表
|
# 注册到处理器注册表
|
||||||
from domain.processors.registry import CONFIG_SCHEMAS, TYPE_MAP
|
from domain.processors import CONFIG_SCHEMAS, TYPE_MAP
|
||||||
|
|
||||||
processor_type = processor_config.type
|
processor_type = processor_config.type
|
||||||
TYPE_MAP[processor_type] = factory
|
TYPE_MAP[processor_type] = factory
|
||||||
@@ -401,7 +401,7 @@ class PluginLoader:
|
|||||||
"""
|
"""
|
||||||
# 卸载处理器
|
# 卸载处理器
|
||||||
if manifest and manifest.backend and manifest.backend.processors:
|
if manifest and manifest.backend and manifest.backend.processors:
|
||||||
from domain.processors.registry import CONFIG_SCHEMAS, TYPE_MAP
|
from domain.processors import CONFIG_SCHEMAS, TYPE_MAP
|
||||||
|
|
||||||
for proc_config in manifest.backend.processors:
|
for proc_config in manifest.backend.processors:
|
||||||
proc_type = proc_config.type
|
proc_type = proc_config.type
|
||||||
|
|||||||
@@ -12,8 +12,8 @@ from typing import List, Optional, Union
|
|||||||
|
|
||||||
from fastapi import HTTPException
|
from fastapi import HTTPException
|
||||||
|
|
||||||
from domain.plugins.loader import PluginLoadError, PluginLoader
|
from .loader import PluginLoadError, PluginLoader
|
||||||
from domain.plugins.types import (
|
from .types import (
|
||||||
PluginInstallResult,
|
PluginInstallResult,
|
||||||
PluginManifest,
|
PluginManifest,
|
||||||
PluginOut,
|
PluginOut,
|
||||||
|
|||||||
@@ -7,8 +7,8 @@
|
|||||||
import logging
|
import logging
|
||||||
from typing import TYPE_CHECKING, List, Tuple
|
from typing import TYPE_CHECKING, List, Tuple
|
||||||
|
|
||||||
from domain.plugins.loader import PluginLoadError, PluginLoader
|
from .loader import PluginLoadError, PluginLoader
|
||||||
from domain.plugins.types import PluginManifest
|
from .types import PluginManifest
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from fastapi import FastAPI
|
from fastapi import FastAPI
|
||||||
@@ -113,4 +113,3 @@ async def init_plugins(app: "FastAPI") -> None:
|
|||||||
logger.warning(f" - {error}")
|
logger.warning(f" - {error}")
|
||||||
else:
|
else:
|
||||||
logger.info(f"插件加载完成,共 {loaded_count} 个插件")
|
logger.info(f"插件加载完成,共 {loaded_count} 个插件")
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,35 @@
|
|||||||
|
from .base import BaseProcessor
|
||||||
|
from .registry import (
|
||||||
|
CONFIG_SCHEMAS,
|
||||||
|
TYPE_MAP,
|
||||||
|
get_config_schema,
|
||||||
|
get_config_schemas,
|
||||||
|
get_last_discovery_errors,
|
||||||
|
get_module_path,
|
||||||
|
reload_processors,
|
||||||
|
)
|
||||||
|
from .service import (
|
||||||
|
ProcessorService,
|
||||||
|
get_processor,
|
||||||
|
list_processors,
|
||||||
|
reload_processor_modules,
|
||||||
|
)
|
||||||
|
from .types import ProcessDirectoryRequest, ProcessRequest, UpdateSourceRequest
|
||||||
|
|
||||||
|
__all__ = [
|
||||||
|
"BaseProcessor",
|
||||||
|
"CONFIG_SCHEMAS",
|
||||||
|
"TYPE_MAP",
|
||||||
|
"get_config_schema",
|
||||||
|
"get_config_schemas",
|
||||||
|
"get_last_discovery_errors",
|
||||||
|
"get_module_path",
|
||||||
|
"reload_processors",
|
||||||
|
"ProcessorService",
|
||||||
|
"get_processor",
|
||||||
|
"list_processors",
|
||||||
|
"reload_processor_modules",
|
||||||
|
"ProcessDirectoryRequest",
|
||||||
|
"ProcessRequest",
|
||||||
|
"UpdateSourceRequest",
|
||||||
|
]
|
||||||
@@ -4,10 +4,9 @@ from fastapi import APIRouter, Body, Depends, Request
|
|||||||
|
|
||||||
from api.response import success
|
from api.response import success
|
||||||
from domain.audit import AuditAction, audit
|
from domain.audit import AuditAction, audit
|
||||||
from domain.auth.service import get_current_active_user
|
from domain.auth import User, get_current_active_user
|
||||||
from domain.auth.types import User
|
from .service import ProcessorService
|
||||||
from domain.processors.service import ProcessorService
|
from .types import (
|
||||||
from domain.processors.types import (
|
|
||||||
ProcessDirectoryRequest,
|
ProcessDirectoryRequest,
|
||||||
ProcessRequest,
|
ProcessRequest,
|
||||||
UpdateSourceRequest,
|
UpdateSourceRequest,
|
||||||
|
|||||||
@@ -8,12 +8,14 @@ from fastapi.responses import Response
|
|||||||
from PIL import Image
|
from PIL import Image
|
||||||
|
|
||||||
from ..base import BaseProcessor
|
from ..base import BaseProcessor
|
||||||
from domain.ai.inference import describe_image_base64, get_text_embedding, provider_service
|
from domain.ai import (
|
||||||
from domain.ai.service import (
|
|
||||||
VectorDBService,
|
|
||||||
DEFAULT_VECTOR_DIMENSION,
|
DEFAULT_VECTOR_DIMENSION,
|
||||||
VECTOR_COLLECTION_NAME,
|
|
||||||
FILE_COLLECTION_NAME,
|
FILE_COLLECTION_NAME,
|
||||||
|
VECTOR_COLLECTION_NAME,
|
||||||
|
VectorDBService,
|
||||||
|
describe_image_base64,
|
||||||
|
get_text_embedding,
|
||||||
|
provider_service,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ from pathlib import Path
|
|||||||
from types import ModuleType
|
from types import ModuleType
|
||||||
from typing import Callable, Dict, Optional
|
from typing import Callable, Dict, Optional
|
||||||
|
|
||||||
from domain.processors.base import BaseProcessor
|
from .base import BaseProcessor
|
||||||
|
|
||||||
ProcessorFactory = Callable[[], BaseProcessor]
|
ProcessorFactory = Callable[[], BaseProcessor]
|
||||||
TYPE_MAP: Dict[str, ProcessorFactory] = {}
|
TYPE_MAP: Dict[str, ProcessorFactory] = {}
|
||||||
@@ -16,7 +16,7 @@ LAST_DISCOVERY_ERRORS: list[str] = []
|
|||||||
|
|
||||||
def discover_processors(force_reload: bool = False) -> list[str]:
|
def discover_processors(force_reload: bool = False) -> list[str]:
|
||||||
"""扫描并缓存可用的处理器模块。"""
|
"""扫描并缓存可用的处理器模块。"""
|
||||||
from domain.processors import builtin as processors_pkg
|
from . import builtin as processors_pkg
|
||||||
|
|
||||||
TYPE_MAP.clear()
|
TYPE_MAP.clear()
|
||||||
CONFIG_SCHEMAS.clear()
|
CONFIG_SCHEMAS.clear()
|
||||||
|
|||||||
@@ -3,20 +3,20 @@ from typing import List, Tuple
|
|||||||
|
|
||||||
from fastapi import HTTPException
|
from fastapi import HTTPException
|
||||||
from fastapi.concurrency import run_in_threadpool
|
from fastapi.concurrency import run_in_threadpool
|
||||||
from domain.processors.registry import (
|
from domain.tasks import task_queue_service
|
||||||
|
from domain.virtual_fs import VirtualFSService
|
||||||
|
from .registry import (
|
||||||
get,
|
get,
|
||||||
get_config_schema,
|
get_config_schema,
|
||||||
get_config_schemas,
|
get_config_schemas,
|
||||||
get_module_path,
|
get_module_path,
|
||||||
reload_processors,
|
reload_processors,
|
||||||
)
|
)
|
||||||
from domain.processors.types import (
|
from .types import (
|
||||||
ProcessDirectoryRequest,
|
ProcessDirectoryRequest,
|
||||||
ProcessRequest,
|
ProcessRequest,
|
||||||
UpdateSourceRequest,
|
UpdateSourceRequest,
|
||||||
)
|
)
|
||||||
from domain.virtual_fs.service import VirtualFSService
|
|
||||||
from domain.tasks.task_queue import task_queue_service
|
|
||||||
|
|
||||||
|
|
||||||
class ProcessorService:
|
class ProcessorService:
|
||||||
|
|||||||
@@ -0,0 +1 @@
|
|||||||
|
__all__: list[str] = []
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
from .service import ShareService
|
||||||
|
from .types import ShareCreate, ShareInfo, ShareInfoWithPassword, SharePassword
|
||||||
|
|
||||||
|
__all__ = [
|
||||||
|
"ShareService",
|
||||||
|
"ShareCreate",
|
||||||
|
"ShareInfo",
|
||||||
|
"ShareInfoWithPassword",
|
||||||
|
"SharePassword",
|
||||||
|
]
|
||||||
+3
-4
@@ -4,10 +4,9 @@ from fastapi import APIRouter, Depends, Request
|
|||||||
|
|
||||||
from api.response import success
|
from api.response import success
|
||||||
from domain.audit import AuditAction, audit
|
from domain.audit import AuditAction, audit
|
||||||
from domain.auth.service import get_current_active_user
|
from domain.auth import User, get_current_active_user
|
||||||
from domain.auth.types import User
|
from .service import ShareService
|
||||||
from domain.share.service import ShareService
|
from .types import (
|
||||||
from domain.share.types import (
|
|
||||||
ShareCreate,
|
ShareCreate,
|
||||||
ShareInfo,
|
ShareInfo,
|
||||||
ShareInfoWithPassword,
|
ShareInfoWithPassword,
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import bcrypt
|
|||||||
from fastapi import HTTPException, status
|
from fastapi import HTTPException, status
|
||||||
from fastapi.responses import Response
|
from fastapi.responses import Response
|
||||||
|
|
||||||
from domain.virtual_fs.service import VirtualFSService
|
from domain.virtual_fs import VirtualFSService
|
||||||
from models.database import ShareLink, UserAccount
|
from models.database import ShareLink, UserAccount
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,24 @@
|
|||||||
|
from .service import TaskService
|
||||||
|
from .task_queue import Task, TaskProgress, TaskStatus, task_queue_service
|
||||||
|
from .types import (
|
||||||
|
AutomationTaskBase,
|
||||||
|
AutomationTaskCreate,
|
||||||
|
AutomationTaskRead,
|
||||||
|
AutomationTaskUpdate,
|
||||||
|
TaskQueueSettings,
|
||||||
|
TaskQueueSettingsResponse,
|
||||||
|
)
|
||||||
|
|
||||||
|
__all__ = [
|
||||||
|
"TaskService",
|
||||||
|
"Task",
|
||||||
|
"TaskProgress",
|
||||||
|
"TaskStatus",
|
||||||
|
"task_queue_service",
|
||||||
|
"AutomationTaskBase",
|
||||||
|
"AutomationTaskCreate",
|
||||||
|
"AutomationTaskRead",
|
||||||
|
"AutomationTaskUpdate",
|
||||||
|
"TaskQueueSettings",
|
||||||
|
"TaskQueueSettingsResponse",
|
||||||
|
]
|
||||||
+3
-3
@@ -2,9 +2,9 @@ from fastapi import APIRouter, Depends, Request
|
|||||||
|
|
||||||
from api.response import success
|
from api.response import success
|
||||||
from domain.audit import AuditAction, audit
|
from domain.audit import AuditAction, audit
|
||||||
from domain.auth.service import get_current_active_user
|
from domain.auth import get_current_active_user
|
||||||
from domain.tasks.service import TaskService
|
from .service import TaskService
|
||||||
from domain.tasks.types import (
|
from .types import (
|
||||||
AutomationTaskCreate,
|
AutomationTaskCreate,
|
||||||
AutomationTaskUpdate,
|
AutomationTaskUpdate,
|
||||||
TaskQueueSettings,
|
TaskQueueSettings,
|
||||||
|
|||||||
@@ -3,17 +3,16 @@ from typing import Annotated, Any, Dict, Optional
|
|||||||
|
|
||||||
from fastapi import Depends, HTTPException
|
from fastapi import Depends, HTTPException
|
||||||
|
|
||||||
from domain.auth.service import get_current_active_user
|
from domain.auth import User, get_current_active_user
|
||||||
from domain.auth.types import User
|
from domain.config import ConfigService
|
||||||
from domain.config.service import ConfigService
|
from .task_queue import task_queue_service
|
||||||
from domain.tasks.types import (
|
from .types import (
|
||||||
AutomationTaskCreate,
|
AutomationTaskCreate,
|
||||||
AutomationTaskUpdate,
|
AutomationTaskUpdate,
|
||||||
TaskQueueSettings,
|
TaskQueueSettings,
|
||||||
TaskQueueSettingsResponse,
|
TaskQueueSettingsResponse,
|
||||||
)
|
)
|
||||||
from models.database import AutomationTask
|
from models.database import AutomationTask
|
||||||
from domain.tasks.task_queue import task_queue_service
|
|
||||||
|
|
||||||
|
|
||||||
class TaskService:
|
class TaskService:
|
||||||
|
|||||||
@@ -74,7 +74,7 @@ class TaskQueueService:
|
|||||||
|
|
||||||
try:
|
try:
|
||||||
# Local import to avoid circular dependency during module load.
|
# Local import to avoid circular dependency during module load.
|
||||||
from domain.virtual_fs.service import VirtualFSService
|
from domain.virtual_fs import VirtualFSService
|
||||||
|
|
||||||
if task.name == "process_file":
|
if task.name == "process_file":
|
||||||
params = task.task_info
|
params = task.task_info
|
||||||
@@ -88,7 +88,7 @@ class TaskQueueService:
|
|||||||
task.result = result
|
task.result = result
|
||||||
elif task.name == "automation_task" or self._is_processor_task(task.name):
|
elif task.name == "automation_task" or self._is_processor_task(task.name):
|
||||||
from models.database import AutomationTask
|
from models.database import AutomationTask
|
||||||
from domain.processors.service import get_processor
|
from domain.processors import get_processor
|
||||||
|
|
||||||
params = task.task_info
|
params = task.task_info
|
||||||
auto_task = await AutomationTask.get(id=params["task_id"])
|
auto_task = await AutomationTask.get(id=params["task_id"])
|
||||||
@@ -116,7 +116,7 @@ class TaskQueueService:
|
|||||||
await VirtualFSService.write_file(save_to, result)
|
await VirtualFSService.write_file(save_to, result)
|
||||||
task.result = "Automation task completed"
|
task.result = "Automation task completed"
|
||||||
elif task.name == "offline_http_download":
|
elif task.name == "offline_http_download":
|
||||||
from domain.offline_downloads.service import OfflineDownloadService
|
from domain.offline_downloads import OfflineDownloadService
|
||||||
|
|
||||||
result_path = await OfflineDownloadService.run_http_download(task)
|
result_path = await OfflineDownloadService.run_http_download(task)
|
||||||
task.result = {"path": result_path}
|
task.result = {"path": result_path}
|
||||||
@@ -124,7 +124,7 @@ class TaskQueueService:
|
|||||||
result = await VirtualFSService.run_cross_mount_transfer_task(task)
|
result = await VirtualFSService.run_cross_mount_transfer_task(task)
|
||||||
task.result = result
|
task.result = result
|
||||||
elif task.name == "send_email":
|
elif task.name == "send_email":
|
||||||
from domain.email.service import EmailService
|
from domain.email import EmailService
|
||||||
await EmailService.send_from_task(task.id, task.task_info)
|
await EmailService.send_from_task(task.id, task.task_info)
|
||||||
task.result = "Email sent"
|
task.result = "Email sent"
|
||||||
else:
|
else:
|
||||||
@@ -141,7 +141,7 @@ class TaskQueueService:
|
|||||||
|
|
||||||
def _is_processor_task(self, task_name: str) -> bool:
|
def _is_processor_task(self, task_name: str) -> bool:
|
||||||
try:
|
try:
|
||||||
from domain.processors.service import get_processor
|
from domain.processors import get_processor
|
||||||
|
|
||||||
return get_processor(task_name) is not None
|
return get_processor(task_name) is not None
|
||||||
except Exception:
|
except Exception:
|
||||||
@@ -180,7 +180,7 @@ class TaskQueueService:
|
|||||||
|
|
||||||
async def start_worker(self, concurrency: int | None = None):
|
async def start_worker(self, concurrency: int | None = None):
|
||||||
if concurrency is None:
|
if concurrency is None:
|
||||||
from domain.config.service import ConfigService
|
from domain.config import ConfigService
|
||||||
|
|
||||||
stored_value = await ConfigService.get("TASK_QUEUE_CONCURRENCY", self._concurrency)
|
stored_value = await ConfigService.get("TASK_QUEUE_CONCURRENCY", self._concurrency)
|
||||||
try:
|
try:
|
||||||
|
|||||||
@@ -0,0 +1,11 @@
|
|||||||
|
from .service import VirtualFSService
|
||||||
|
from .types import DirListing, MkdirRequest, MoveRequest, SearchResultItem, VfsEntry
|
||||||
|
|
||||||
|
__all__ = [
|
||||||
|
"VirtualFSService",
|
||||||
|
"DirListing",
|
||||||
|
"MkdirRequest",
|
||||||
|
"MoveRequest",
|
||||||
|
"SearchResultItem",
|
||||||
|
"VfsEntry",
|
||||||
|
]
|
||||||
@@ -4,10 +4,9 @@ from fastapi import APIRouter, Depends, File, Query, Request, UploadFile
|
|||||||
|
|
||||||
from api.response import success
|
from api.response import success
|
||||||
from domain.audit import AuditAction, audit
|
from domain.audit import AuditAction, audit
|
||||||
from domain.auth.service import get_current_active_user
|
from domain.auth import User, get_current_active_user
|
||||||
from domain.auth.types import User
|
from .service import VirtualFSService
|
||||||
from domain.virtual_fs.service import VirtualFSService
|
from .types import MkdirRequest, MoveRequest
|
||||||
from domain.virtual_fs.types import MkdirRequest, MoveRequest
|
|
||||||
|
|
||||||
router = APIRouter(prefix="/api/fs", tags=["virtual-fs"])
|
router = APIRouter(prefix="/api/fs", tags=["virtual-fs"])
|
||||||
|
|
||||||
|
|||||||
@@ -4,8 +4,8 @@ from typing import Any, AsyncIterator, Union
|
|||||||
from fastapi import HTTPException
|
from fastapi import HTTPException
|
||||||
from fastapi.responses import Response
|
from fastapi.responses import Response
|
||||||
|
|
||||||
from domain.tasks.service import TaskService
|
from domain.tasks import TaskService
|
||||||
from domain.virtual_fs.thumbnail import is_raw_filename, raw_bytes_to_jpeg
|
from .thumbnail import is_raw_filename, raw_bytes_to_jpeg
|
||||||
|
|
||||||
from .listing import VirtualFSListingMixin
|
from .listing import VirtualFSListingMixin
|
||||||
|
|
||||||
|
|||||||
@@ -3,9 +3,9 @@ from typing import Any, Dict, List, Tuple
|
|||||||
from fastapi import HTTPException
|
from fastapi import HTTPException
|
||||||
|
|
||||||
from api.response import page
|
from api.response import page
|
||||||
from domain.adapters.registry import runtime_registry
|
from domain.adapters import runtime_registry
|
||||||
from domain.ai.service import VectorDBService, VECTOR_COLLECTION_NAME, FILE_COLLECTION_NAME
|
from domain.ai import FILE_COLLECTION_NAME, VECTOR_COLLECTION_NAME, VectorDBService
|
||||||
from domain.virtual_fs.thumbnail import is_image_filename, is_video_filename
|
from .thumbnail import is_image_filename, is_video_filename
|
||||||
from models import StorageAdapter
|
from models import StorageAdapter
|
||||||
|
|
||||||
from .resolver import VirtualFSResolverMixin
|
from .resolver import VirtualFSResolverMixin
|
||||||
|
|||||||
@@ -0,0 +1 @@
|
|||||||
|
__all__: list[str] = []
|
||||||
|
|||||||
@@ -15,8 +15,8 @@ from fastapi import APIRouter, Request, Response
|
|||||||
from fastapi import HTTPException
|
from fastapi import HTTPException
|
||||||
|
|
||||||
from domain.audit import AuditAction, audit
|
from domain.audit import AuditAction, audit
|
||||||
from domain.config.service import ConfigService
|
from domain.config import ConfigService
|
||||||
from domain.virtual_fs.service import VirtualFSService
|
from domain.virtual_fs import VirtualFSService
|
||||||
|
|
||||||
|
|
||||||
router = APIRouter(prefix="/s3", tags=["s3"])
|
router = APIRouter(prefix="/s3", tags=["s3"])
|
||||||
|
|||||||
@@ -9,10 +9,9 @@ from fastapi import APIRouter, Request, Response, HTTPException, Depends
|
|||||||
import xml.etree.ElementTree as ET
|
import xml.etree.ElementTree as ET
|
||||||
|
|
||||||
from domain.audit import AuditAction, audit
|
from domain.audit import AuditAction, audit
|
||||||
from domain.auth.service import AuthService
|
from domain.auth import AuthService, User, UserInDB
|
||||||
from domain.auth.types import User, UserInDB
|
from domain.config import ConfigService
|
||||||
from domain.virtual_fs.service import VirtualFSService
|
from domain.virtual_fs import VirtualFSService
|
||||||
from domain.config.service import ConfigService
|
|
||||||
|
|
||||||
|
|
||||||
_WEBDAV_ENABLED_KEY = "WEBDAV_MAPPING_ENABLED"
|
_WEBDAV_ENABLED_KEY = "WEBDAV_MAPPING_ENABLED"
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ class VirtualFSProcessingMixin(VirtualFSTransferMixin):
|
|||||||
save_to: str | None = None,
|
save_to: str | None = None,
|
||||||
overwrite: bool = False,
|
overwrite: bool = False,
|
||||||
) -> Any:
|
) -> Any:
|
||||||
from domain.processors.service import get_processor
|
from domain.processors import get_processor
|
||||||
|
|
||||||
processor = get_processor(processor_type)
|
processor = get_processor(processor_type)
|
||||||
if not processor:
|
if not processor:
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ from typing import Tuple
|
|||||||
from fastapi import HTTPException
|
from fastapi import HTTPException
|
||||||
from fastapi.responses import Response
|
from fastapi.responses import Response
|
||||||
|
|
||||||
from domain.adapters.registry import runtime_registry
|
from domain.adapters import runtime_registry
|
||||||
from models import StorageAdapter
|
from models import StorageAdapter
|
||||||
|
|
||||||
from .common import VirtualFSCommonMixin
|
from .common import VirtualFSCommonMixin
|
||||||
|
|||||||
@@ -4,8 +4,8 @@ import re
|
|||||||
from fastapi import HTTPException, UploadFile
|
from fastapi import HTTPException, UploadFile
|
||||||
from fastapi.responses import Response
|
from fastapi.responses import Response
|
||||||
|
|
||||||
from domain.config.service import ConfigService
|
from domain.config import ConfigService
|
||||||
from domain.virtual_fs.thumbnail import (
|
from .thumbnail import (
|
||||||
get_or_create_thumb,
|
get_or_create_thumb,
|
||||||
is_image_filename,
|
is_image_filename,
|
||||||
is_raw_filename,
|
is_raw_filename,
|
||||||
|
|||||||
@@ -0,0 +1,3 @@
|
|||||||
|
from .search_service import VirtualFSSearchService
|
||||||
|
|
||||||
|
__all__ = ["VirtualFSSearchService"]
|
||||||
|
|||||||
@@ -1,9 +1,8 @@
|
|||||||
from fastapi import APIRouter, Depends, Query
|
from fastapi import APIRouter, Depends, Query
|
||||||
|
|
||||||
from api.response import success
|
from api.response import success
|
||||||
from domain.auth.service import get_current_active_user
|
from domain.auth import User, get_current_active_user
|
||||||
from domain.auth.types import User
|
from .search_service import VirtualFSSearchService
|
||||||
from domain.virtual_fs.search.search_service import VirtualFSSearchService
|
|
||||||
|
|
||||||
router = APIRouter(prefix="/api/fs/search", tags=["search"])
|
router = APIRouter(prefix="/api/fs/search", tags=["search"])
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
from typing import Any, Dict, List, Tuple
|
from typing import Any, Dict, List, Tuple
|
||||||
|
|
||||||
from domain.virtual_fs.types import SearchResultItem
|
from domain.ai import FILE_COLLECTION_NAME, VECTOR_COLLECTION_NAME, VectorDBService, get_text_embedding
|
||||||
from domain.ai.inference import get_text_embedding
|
from ..types import SearchResultItem
|
||||||
from domain.ai.service import VectorDBService, VECTOR_COLLECTION_NAME, FILE_COLLECTION_NAME
|
|
||||||
|
|
||||||
|
|
||||||
def _normalize_result(raw: Dict[str, Any], source: str, fallback_score: float = 0.0) -> SearchResultItem:
|
def _normalize_result(raw: Dict[str, Any], source: str, fallback_score: float = 0.0) -> SearchResultItem:
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import time
|
|||||||
|
|
||||||
from fastapi import HTTPException
|
from fastapi import HTTPException
|
||||||
|
|
||||||
from domain.config.service import ConfigService
|
from domain.config import ConfigService
|
||||||
|
|
||||||
from .processing import VirtualFSProcessingMixin
|
from .processing import VirtualFSProcessingMixin
|
||||||
|
|
||||||
|
|||||||
@@ -273,7 +273,7 @@ class VirtualFSTransferMixin(VirtualFSFileOpsMixin):
|
|||||||
"overwrite": overwrite,
|
"overwrite": overwrite,
|
||||||
}
|
}
|
||||||
|
|
||||||
from domain.tasks.task_queue import task_queue_service
|
from domain.tasks import task_queue_service
|
||||||
|
|
||||||
task = await task_queue_service.add_task("cross_mount_transfer", payload)
|
task = await task_queue_service.add_task("cross_mount_transfer", payload)
|
||||||
return {
|
return {
|
||||||
@@ -286,7 +286,7 @@ class VirtualFSTransferMixin(VirtualFSFileOpsMixin):
|
|||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def run_cross_mount_transfer_task(cls, task: "Task") -> Dict[str, Any]:
|
async def run_cross_mount_transfer_task(cls, task: "Task") -> Dict[str, Any]:
|
||||||
from domain.tasks.task_queue import task_queue_service
|
from domain.tasks import task_queue_service
|
||||||
|
|
||||||
params = task.task_info or {}
|
params = task.task_info or {}
|
||||||
operation = params.get("operation")
|
operation = params.get("operation")
|
||||||
|
|||||||
@@ -2,8 +2,8 @@ import os
|
|||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from contextlib import asynccontextmanager
|
from contextlib import asynccontextmanager
|
||||||
|
|
||||||
from domain.config.service import ConfigService, VERSION
|
from domain.adapters import runtime_registry
|
||||||
from domain.adapters.registry import runtime_registry
|
from domain.config import ConfigService, VERSION
|
||||||
from db.session import close_db, init_db
|
from db.session import close_db, init_db
|
||||||
from api.routers import include_routers
|
from api.routers import include_routers
|
||||||
from fastapi.middleware.cors import CORSMiddleware
|
from fastapi.middleware.cors import CORSMiddleware
|
||||||
@@ -19,7 +19,7 @@ from middleware.exception_handler import (
|
|||||||
)
|
)
|
||||||
import httpx
|
import httpx
|
||||||
from dotenv import load_dotenv
|
from dotenv import load_dotenv
|
||||||
from domain.tasks.task_queue import task_queue_service
|
from domain.tasks import task_queue_service
|
||||||
|
|
||||||
load_dotenv()
|
load_dotenv()
|
||||||
|
|
||||||
@@ -59,7 +59,7 @@ async def lifespan(app: FastAPI):
|
|||||||
await task_queue_service.start_worker()
|
await task_queue_service.start_worker()
|
||||||
|
|
||||||
# 加载已安装的插件
|
# 加载已安装的插件
|
||||||
from domain.plugins.startup import init_plugins
|
from domain.plugins import init_plugins
|
||||||
await init_plugins(app)
|
await init_plugins(app)
|
||||||
|
|
||||||
# 在所有路由加载完成后,挂载静态文件服务(放在最后以避免覆盖 API 路由)
|
# 在所有路由加载完成后,挂载静态文件服务(放在最后以避免覆盖 API 路由)
|
||||||
|
|||||||
+2
-2
@@ -13,8 +13,8 @@ PROJECT_ROOT = Path(__file__).resolve().parents[1]
|
|||||||
if str(PROJECT_ROOT) not in sys.path:
|
if str(PROJECT_ROOT) not in sys.path:
|
||||||
sys.path.insert(0, str(PROJECT_ROOT))
|
sys.path.insert(0, str(PROJECT_ROOT))
|
||||||
|
|
||||||
from domain.auth.service import get_password_hash
|
from domain.config import VERSION
|
||||||
from domain.config.service import VERSION
|
from domain.auth import get_password_hash
|
||||||
|
|
||||||
|
|
||||||
def _project_root() -> Path:
|
def _project_root() -> Path:
|
||||||
|
|||||||
Reference in New Issue
Block a user