Download apps/core/api/ninja_llm_api.py from jun2024/fc: direct link, hf CLI and curl.
- Browser
- Download file 6.67 kB
-
https://huggingface.co/spaces/jun2024/fc/resolve/main/apps/core/api/ninja_llm_api.py
- Command line
-
hf download hf://spaces/jun2024/fc/apps/core/api/ninja_llm_api.py
-
curl -L -o ninja_llm_api.py https://huggingface.co/spaces/jun2024/fc/resolve/main/apps/core/api/ninja_llm_api.py
6.67 kB
| """API endpoints.""" | |
| """ | |
| LLM Ninja API | |
| 使用 Ninja 框架的 LLM API 接口,集成到主 API 结构中. | |
| """ | |
| import logging | |
| from typing import Any, ClassVar | |
| from django.db import transaction | |
| from ninja import Router | |
| from ninja.schema import Schema | |
| from apps.core.exceptions import PermissionDenied | |
| from apps.core.infrastructure.throttling import rate_limit_from_settings | |
| from apps.core.security.auth import JWTOrSessionAuth | |
| from .llm_common import achat_with_context as achat_with_context_impl | |
| from .llm_common import get_conversation_history as get_conversation_history_impl | |
| logger = logging.getLogger(__name__) | |
| # 创建 LLM 路由 | |
| llm_router = Router(tags=["LLM 服务"], auth=JWTOrSessionAuth()) | |
| # ============================================================ | |
| # 请求/响应 Schema | |
| # ============================================================ | |
| class ChatRequest(Schema): | |
| """对话请求""" | |
| message: str | |
| session_id: str | None = None | |
| user_id: str | None = None | |
| system_prompt: str | None = None | |
| class ChatResponse(Schema): | |
| """对话响应""" | |
| response: str | |
| session_id: str | |
| class ConversationMessage(Schema): | |
| """对话消息""" | |
| role: str | |
| content: str | |
| created_at: str | |
| metadata: ClassVar[dict[str, Any]] = {} | |
| class ConversationHistoryResponse(Schema): | |
| """对话历史响应""" | |
| session_id: str | |
| messages: list[ConversationMessage] | |
| class PromptTemplateSyncResponse(Schema): | |
| """Prompt 模板同步响应""" | |
| synced_count: int | |
| def sync_prompt_templates_impl(*, overwrite: bool = True) -> dict[str, int]: | |
| """ | |
| 将代码内置 Prompt 模板同步到数据库。 | |
| 该函数保留模块级命名,兼容旧测试对 `sync_prompt_templates_impl` 的 monkeypatch。 | |
| """ | |
| from apps.core.llm.prompts import PromptManager | |
| from apps.core.models import PromptTemplate | |
| templates = list(PromptManager._templates.values()) | |
| synced_count = 0 | |
| with transaction.atomic(): | |
| for item in templates: | |
| defaults = { | |
| "title": (item.description or item.name)[:200], | |
| "template": item.template, | |
| "description": item.description, | |
| "variables": item.variables, | |
| "category": (item.name.split("_", maxsplit=1)[0] or "general"), | |
| "is_active": True, | |
| "version": "1.0", | |
| } | |
| if overwrite: | |
| PromptTemplate.objects.update_or_create(name=item.name, defaults=defaults) | |
| synced_count += 1 | |
| continue | |
| _, created = PromptTemplate.objects.get_or_create(name=item.name, defaults=defaults) | |
| if created: | |
| synced_count += 1 | |
| return {"synced_count": synced_count} | |
| # ============================================================ | |
| # API 端点 | |
| # ============================================================ | |
| async def chat_with_context(request: Any, payload: ChatRequest) -> Any: | |
| """ | |
| 带上下文的对话 | |
| 支持多轮对话和上下文记忆功能. | |
| """ | |
| user = getattr(request, "user", None) | |
| if not user or not getattr(user, "is_authenticated", False): | |
| user = getattr(request, "auth", None) | |
| user_id = str(getattr(user, "id", "") or "") | |
| from apps.core.interfaces import ServiceLocator | |
| result = await achat_with_context_impl( | |
| message=payload.message, | |
| session_id=payload.session_id, | |
| user_id=user_id, | |
| system_prompt=payload.system_prompt, | |
| conversation_service_factory=ServiceLocator.get_conversation_service, | |
| ) | |
| return ChatResponse( | |
| response=result["response"], | |
| session_id=result["session_id"], | |
| ) | |
| async def chat_with_context_stream(request: Any, payload: ChatRequest) -> Any: | |
| from django.http import StreamingHttpResponse | |
| from apps.core.interfaces import ServiceLocator | |
| from apps.core.services.llm_stream_service import build_chat_stream | |
| user = getattr(request, "user", None) | |
| if not user or not getattr(user, "is_authenticated", False): | |
| user = getattr(request, "auth", None) | |
| user_id = str(getattr(user, "id", "") or "") | |
| stream = build_chat_stream( | |
| message=payload.message, | |
| session_id=payload.session_id, | |
| user_id=user_id, | |
| system_prompt=payload.system_prompt, | |
| conversation_service_factory=ServiceLocator.get_conversation_service, | |
| llm_service_factory=ServiceLocator.get_llm_service, | |
| ) | |
| resp = StreamingHttpResponse(stream, content_type="text/event-stream") | |
| resp["Cache-Control"] = "no-cache" | |
| return resp | |
| def get_conversation_history(request: Any, session_id: str) -> Any: | |
| """ | |
| 获取对话历史 | |
| 返回指定会话的对话记录. | |
| """ | |
| user = getattr(request, "user", None) | |
| if not user or not getattr(user, "is_authenticated", False): | |
| user = getattr(request, "auth", None) | |
| user_id = str(getattr(user, "id", "") or "") | |
| is_admin = bool( | |
| getattr(user, "is_admin", False) or getattr(user, "is_superuser", False) or getattr(user, "is_staff", False) | |
| ) | |
| result = get_conversation_history_impl(session_id=session_id, user_id=(None if is_admin else user_id), limit=50) | |
| messages = [ | |
| ConversationMessage( # type: ignore[call-arg] | |
| role=m["role"], | |
| content=m["content"], | |
| created_at=m["created_at"], | |
| metadata=m.get("metadata") or {}, | |
| ) | |
| for m in result["messages"] | |
| ] | |
| return ConversationHistoryResponse(session_id=session_id, messages=messages) | |
| def sync_prompt_templates(request: Any) -> Any: | |
| """ | |
| 同步代码内置 Prompt 模板到数据库(仅管理员)。 | |
| """ | |
| user = getattr(request, "user", None) | |
| if not user or not getattr(user, "is_authenticated", False): | |
| user = getattr(request, "auth", None) | |
| is_admin = bool(getattr(user, "is_superuser", False) or getattr(user, "is_staff", False)) | |
| if not is_admin: | |
| raise PermissionDenied(message="需要管理员权限", code="PERMISSION_DENIED") | |
| result = sync_prompt_templates_impl(overwrite=True) | |
| return PromptTemplateSyncResponse(synced_count=int(result.get("synced_count", 0))) | |