feat(ai): gRPC clients 扩展 + server interceptors + proto_gen + 测试 + nextstep 文档
This commit is contained in:
@@ -5,20 +5,59 @@
|
||||
客户端:
|
||||
- ContentClient: 查询知识点/教材/题库(content 服务 gRPC 50054)
|
||||
- DataAnaClient: 查询学情/薄弱点/趋势(data-ana 服务 gRPC 50055)
|
||||
- IamClient: 查询 DataScope(iam 服务 gRPC 50052,P4 补全后启用)
|
||||
- IamClient: 查询 DataScope(iam 服务 gRPC 50052)
|
||||
|
||||
全并行模式:下游不可用时返回 mock 数据或抛 AI_DOWNSTREAM_UNAVAILABLE 降级。
|
||||
生产环境使用 *Grpc 类(真实 gRPC 调用);
|
||||
单元测试使用 *Mock 类(仅返回固定数据,不依赖外部服务)。
|
||||
"""
|
||||
|
||||
from .content_client import ContentClient, ContentClientMock
|
||||
from .data_ana_client import DataAnaClient, DataAnaClientMock
|
||||
from .iam_client import IamClient, IamClientMock
|
||||
from .content_client import (
|
||||
ContentClient,
|
||||
ContentClientGrpc,
|
||||
ContentClientMock,
|
||||
CreatedQuestion,
|
||||
KnowledgePoint,
|
||||
QuestionInput,
|
||||
)
|
||||
from .data_ana_client import (
|
||||
ClassPerformance,
|
||||
DataAnaClient,
|
||||
DataAnaClientGrpc,
|
||||
DataAnaClientMock,
|
||||
LearningTrend,
|
||||
StudentScore,
|
||||
StudentWeakness,
|
||||
TrendPoint,
|
||||
WeakPoint,
|
||||
)
|
||||
from .iam_client import (
|
||||
DataScope,
|
||||
IamClient,
|
||||
IamClientGrpc,
|
||||
IamClientMock,
|
||||
)
|
||||
|
||||
__all__ = [
|
||||
# content
|
||||
"ContentClient",
|
||||
"ContentClientGrpc",
|
||||
"ContentClientMock",
|
||||
"CreatedQuestion",
|
||||
"KnowledgePoint",
|
||||
"QuestionInput",
|
||||
# data-ana
|
||||
"ClassPerformance",
|
||||
"DataAnaClient",
|
||||
"DataAnaClientGrpc",
|
||||
"DataAnaClientMock",
|
||||
"LearningTrend",
|
||||
"StudentScore",
|
||||
"StudentWeakness",
|
||||
"TrendPoint",
|
||||
"WeakPoint",
|
||||
# iam
|
||||
"DataScope",
|
||||
"IamClient",
|
||||
"IamClientGrpc",
|
||||
"IamClientMock",
|
||||
]
|
||||
|
||||
@@ -1,20 +1,22 @@
|
||||
"""Content 服务 gRPC 客户端.
|
||||
|
||||
用于:
|
||||
- 查询知识点前置依赖(GetPrerequisites)
|
||||
- 查询学习路径(GetLearningPath)
|
||||
- 创建题目入库(CreateQuestions - P5 mock,content 服务待补全)
|
||||
- 查询知识点前置依赖(KnowledgeGraphService.GetPrerequisites)
|
||||
- 查询学习路径(KnowledgeGraphService.GetLearningPath)
|
||||
- 创建题目入库(QuestionService.BatchCreateQuestions)
|
||||
|
||||
全并行模式:下游不可用时使用 mock 数据降级。
|
||||
真实 gRPC 调用:未连接或调用失败时抛 AIError(不再降级到 mock 数据)。
|
||||
"""
|
||||
|
||||
from abc import ABC, abstractmethod
|
||||
from dataclasses import dataclass
|
||||
from typing import Any
|
||||
|
||||
import grpc
|
||||
import structlog
|
||||
|
||||
from ..errors import AIError, ErrorCode
|
||||
from ..proto_gen import content_pb2, content_pb2_grpc
|
||||
from .base_client import BaseGrpcClient
|
||||
|
||||
logger = structlog.get_logger()
|
||||
|
||||
@@ -29,7 +31,7 @@ class KnowledgePoint:
|
||||
|
||||
@dataclass
|
||||
class QuestionInput:
|
||||
"""题目入库输入(对应 ConfirmLessonPlan 调用 content.CreateQuestions)."""
|
||||
"""题目入库输入(对应 ConfirmLessonPlan 调用 content.BatchCreateQuestions)."""
|
||||
|
||||
question: str
|
||||
answer: str
|
||||
@@ -83,7 +85,7 @@ class ContentClient(ABC):
|
||||
|
||||
|
||||
class ContentClientMock(ContentClient):
|
||||
"""Content 客户端 Mock 实现(全并行模式)."""
|
||||
"""Content 客户端 Mock 实现(仅用于单元测试)."""
|
||||
|
||||
def __init__(self) -> None:
|
||||
self._available = True
|
||||
@@ -92,15 +94,8 @@ class ContentClientMock(ContentClient):
|
||||
self,
|
||||
knowledge_point_id: str,
|
||||
) -> list[KnowledgePoint]:
|
||||
logger.info(
|
||||
"content_mock_get_prerequisites",
|
||||
knowledge_point_id=knowledge_point_id,
|
||||
)
|
||||
return [
|
||||
KnowledgePoint(
|
||||
id="kp_base_001",
|
||||
title="基础概念(mock)",
|
||||
),
|
||||
KnowledgePoint(id="kp_base_001", title="基础概念(mock)"),
|
||||
]
|
||||
|
||||
async def get_learning_path(
|
||||
@@ -108,15 +103,9 @@ class ContentClientMock(ContentClient):
|
||||
student_id: str,
|
||||
subject_id: str,
|
||||
) -> list[KnowledgePoint]:
|
||||
logger.info(
|
||||
"content_mock_get_learning_path",
|
||||
student_id=student_id,
|
||||
subject_id=subject_id,
|
||||
)
|
||||
return [
|
||||
KnowledgePoint(id="kp_001", title="知识点1(mock)"),
|
||||
KnowledgePoint(id="kp_002", title="知识点2(mock)"),
|
||||
KnowledgePoint(id="kp_003", title="知识点3(mock)"),
|
||||
]
|
||||
|
||||
async def create_questions(
|
||||
@@ -124,16 +113,8 @@ class ContentClientMock(ContentClient):
|
||||
questions: list[QuestionInput],
|
||||
user_id: str = "",
|
||||
) -> list[CreatedQuestion]:
|
||||
logger.info(
|
||||
"content_mock_create_questions",
|
||||
count=len(questions),
|
||||
user_id=user_id,
|
||||
)
|
||||
return [
|
||||
CreatedQuestion(
|
||||
id=f"q_mock_{i:04d}",
|
||||
question=q.question,
|
||||
)
|
||||
CreatedQuestion(id=f"q_mock_{i:04d}", question=q.question)
|
||||
for i, q in enumerate(questions)
|
||||
]
|
||||
|
||||
@@ -141,84 +122,125 @@ class ContentClientMock(ContentClient):
|
||||
return self._available
|
||||
|
||||
|
||||
class ContentClientGrpc(ContentClient):
|
||||
"""Content 服务 gRPC 客户端实现.
|
||||
|
||||
全并行模式:gRPC 调用失败时降级到 mock 数据。
|
||||
"""
|
||||
class ContentClientGrpc(BaseGrpcClient, ContentClient):
|
||||
"""Content 服务 gRPC 客户端实现(真实调用,不降级到 mock)."""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
endpoint: str = "localhost:50054",
|
||||
request_id: str = "",
|
||||
) -> None:
|
||||
self._endpoint = endpoint
|
||||
self._request_id = request_id
|
||||
self._channel: Any = None
|
||||
self._mock = ContentClientMock()
|
||||
super().__init__(endpoint, request_id)
|
||||
self._kg_stub: content_pb2_grpc.KnowledgeGraphServiceStub | None = None
|
||||
self._q_stub: content_pb2_grpc.QuestionServiceStub | None = None
|
||||
|
||||
async def connect(self) -> None:
|
||||
"""建立 gRPC 连接."""
|
||||
import grpc
|
||||
|
||||
self._channel = grpc.aio.insecure_channel(self._endpoint)
|
||||
logger.info("content_client_connected", endpoint=self._endpoint)
|
||||
|
||||
async def close(self) -> None:
|
||||
"""关闭 gRPC 连接."""
|
||||
if self._channel is not None:
|
||||
await self._channel.close()
|
||||
self._channel = None
|
||||
"""建立 gRPC 连接并初始化 stub."""
|
||||
await super().connect()
|
||||
self._kg_stub = content_pb2_grpc.KnowledgeGraphServiceStub(self.channel)
|
||||
self._q_stub = content_pb2_grpc.QuestionServiceStub(self.channel)
|
||||
|
||||
def is_available(self) -> bool:
|
||||
return self._channel is not None
|
||||
return self._channel is not None and self._kg_stub is not None
|
||||
|
||||
async def get_prerequisites(
|
||||
self,
|
||||
knowledge_point_id: str,
|
||||
) -> list[KnowledgePoint]:
|
||||
"""查询知识点前置依赖(KnowledgeGraphService.GetPrerequisites)."""
|
||||
if not self.is_available():
|
||||
logger.warning("content_client_not_connected_using_mock")
|
||||
return await self._mock.get_prerequisites(knowledge_point_id)
|
||||
try:
|
||||
# 动态导入 proto 生成代码(如果存在)
|
||||
# 全并行模式:proto 未生成时降级到 mock
|
||||
return await self._mock.get_prerequisites(knowledge_point_id)
|
||||
except Exception as exc: # noqa: BLE001
|
||||
logger.warning(
|
||||
"content_get_prerequisites_failed_degraded",
|
||||
error=str(exc),
|
||||
raise AIError(
|
||||
ErrorCode.AI_DOWNSTREAM_UNAVAILABLE,
|
||||
"content client not connected",
|
||||
)
|
||||
return await self._mock.get_prerequisites(knowledge_point_id)
|
||||
assert self._kg_stub is not None # noqa: S101 - narrowing for type checker
|
||||
request = content_pb2.GetPrerequisitesRequest(
|
||||
knowledge_point_id=knowledge_point_id,
|
||||
depth=1,
|
||||
)
|
||||
try:
|
||||
response: content_pb2.KnowledgePointsResponse = await self._kg_stub.GetPrerequisites(
|
||||
request
|
||||
)
|
||||
except grpc.aio.AioRpcError as exc:
|
||||
raise AIError(
|
||||
ErrorCode.AI_DOWNSTREAM_UNAVAILABLE,
|
||||
f"content.GetPrerequisites failed: {exc.details()}",
|
||||
) from exc
|
||||
return [KnowledgePoint(id=p.id, title=p.title) for p in response.points]
|
||||
|
||||
async def get_learning_path(
|
||||
self,
|
||||
student_id: str,
|
||||
subject_id: str,
|
||||
) -> list[KnowledgePoint]:
|
||||
"""查询学习路径(KnowledgeGraphService.GetLearningPath)."""
|
||||
if not self.is_available():
|
||||
return await self._mock.get_learning_path(student_id, subject_id)
|
||||
try:
|
||||
return await self._mock.get_learning_path(student_id, subject_id)
|
||||
except Exception as exc: # noqa: BLE001
|
||||
logger.warning(
|
||||
"content_get_learning_path_failed_degraded",
|
||||
error=str(exc),
|
||||
raise AIError(
|
||||
ErrorCode.AI_DOWNSTREAM_UNAVAILABLE,
|
||||
"content client not connected",
|
||||
)
|
||||
return await self._mock.get_learning_path(student_id, subject_id)
|
||||
assert self._kg_stub is not None # noqa: S101
|
||||
request = content_pb2.GetLearningPathRequest(
|
||||
student_id=student_id,
|
||||
subject_id=subject_id,
|
||||
)
|
||||
try:
|
||||
response: content_pb2.LearningPath = await self._kg_stub.GetLearningPath(request)
|
||||
except grpc.aio.AioRpcError as exc:
|
||||
raise AIError(
|
||||
ErrorCode.AI_DOWNSTREAM_UNAVAILABLE,
|
||||
f"content.GetLearningPath failed: {exc.details()}",
|
||||
) from exc
|
||||
return [KnowledgePoint(id=p.id, title=p.title) for p in response.points]
|
||||
|
||||
async def create_questions(
|
||||
self,
|
||||
questions: list[QuestionInput],
|
||||
user_id: str = "",
|
||||
) -> list[CreatedQuestion]:
|
||||
"""批量创建题目入库(QuestionService.BatchCreateQuestions)."""
|
||||
if not self.is_available():
|
||||
logger.warning("content_client_not_connected_using_mock")
|
||||
return await self._mock.create_questions(questions, user_id)
|
||||
try:
|
||||
return await self._mock.create_questions(questions, user_id)
|
||||
except Exception as exc: # noqa: BLE001
|
||||
raise AIError(
|
||||
ErrorCode.AI_DOWNSTREAM_UNAVAILABLE,
|
||||
f"content.CreateQuestions failed: {exc}",
|
||||
"content client not connected",
|
||||
)
|
||||
assert self._q_stub is not None # noqa: S101
|
||||
proto_questions = [
|
||||
content_pb2.CreateQuestionRequest(
|
||||
knowledge_point_id=(q.knowledge_point_ids[0] if q.knowledge_point_ids else ""),
|
||||
type=q.question_type,
|
||||
content=q.question,
|
||||
answer=q.answer,
|
||||
explanation=q.explanation,
|
||||
difficulty=_parse_difficulty(q.difficulty),
|
||||
source="ai_workflow",
|
||||
created_by=user_id,
|
||||
)
|
||||
for q in questions
|
||||
]
|
||||
request = content_pb2.BatchCreateQuestionsRequest(questions=proto_questions)
|
||||
try:
|
||||
response: content_pb2.BatchCreateQuestionsResponse = (
|
||||
await self._q_stub.BatchCreateQuestions(request)
|
||||
)
|
||||
except grpc.aio.AioRpcError as exc:
|
||||
raise AIError(
|
||||
ErrorCode.AI_DOWNSTREAM_UNAVAILABLE,
|
||||
f"content.BatchCreateQuestions failed: {exc.details()}",
|
||||
) from exc
|
||||
# 按 ids 顺序返回,过滤掉失败的索引
|
||||
results: list[CreatedQuestion] = []
|
||||
failed_indices = {f.index for f in response.failed}
|
||||
for i, q in enumerate(questions):
|
||||
if i in failed_indices:
|
||||
continue
|
||||
if i < len(response.ids):
|
||||
results.append(CreatedQuestion(id=response.ids[i], question=q.question))
|
||||
return results
|
||||
|
||||
|
||||
def _parse_difficulty(difficulty: str) -> int:
|
||||
"""将字符串难度映射为 proto int32 difficulty."""
|
||||
mapping = {"easy": 1, "medium": 2, "hard": 3, "简单": 1, "中等": 2, "困难": 3}
|
||||
return mapping.get(difficulty.lower() if difficulty else "", 2)
|
||||
|
||||
@@ -1,19 +1,23 @@
|
||||
"""Data-ana 服务 gRPC 客户端.
|
||||
|
||||
用于:
|
||||
- 查询班级学情(GetClassPerformance)
|
||||
- 查询学生薄弱点(GetStudentWeakness)
|
||||
- 查询学习趋势(GetLearningTrend)
|
||||
- 查询班级学情(AnalyticsService.GetClassPerformance)
|
||||
- 查询学生薄弱点(AnalyticsService.GetStudentWeakness)
|
||||
- 查询学习趋势(AnalyticsService.GetLearningTrend)
|
||||
|
||||
全并行模式:下游不可用时使用 mock 数据降级。
|
||||
真实 gRPC 调用:未连接或调用失败时抛 AIError(不再降级到 mock 数据)。
|
||||
"""
|
||||
|
||||
from abc import ABC, abstractmethod
|
||||
from dataclasses import dataclass, field
|
||||
from typing import Any
|
||||
|
||||
import grpc
|
||||
import structlog
|
||||
|
||||
from ..errors import AIError, ErrorCode
|
||||
from ..proto_gen import analytics_pb2, analytics_pb2_grpc
|
||||
from .base_client import BaseGrpcClient
|
||||
|
||||
logger = structlog.get_logger()
|
||||
|
||||
|
||||
@@ -109,7 +113,7 @@ class DataAnaClient(ABC):
|
||||
|
||||
|
||||
class DataAnaClientMock(DataAnaClient):
|
||||
"""Data-ana 客户端 Mock 实现(全并行模式)."""
|
||||
"""Data-ana 客户端 Mock 实现(仅用于单元测试)."""
|
||||
|
||||
def __init__(self) -> None:
|
||||
self._available = True
|
||||
@@ -121,11 +125,6 @@ class DataAnaClientMock(DataAnaClient):
|
||||
start_date: int = 0,
|
||||
end_date: int = 0,
|
||||
) -> ClassPerformance:
|
||||
logger.info(
|
||||
"data_ana_mock_class_performance",
|
||||
class_id=class_id,
|
||||
subject_id=subject_id,
|
||||
)
|
||||
return ClassPerformance(
|
||||
class_id=class_id,
|
||||
average_score=78.5,
|
||||
@@ -133,7 +132,6 @@ class DataAnaClientMock(DataAnaClient):
|
||||
scores=[
|
||||
StudentScore(student_id="s_001", score=85.0, grade="A"),
|
||||
StudentScore(student_id="s_002", score=72.0, grade="B"),
|
||||
StudentScore(student_id="s_003", score=65.0, grade="C"),
|
||||
],
|
||||
)
|
||||
|
||||
@@ -142,11 +140,6 @@ class DataAnaClientMock(DataAnaClient):
|
||||
student_id: str,
|
||||
subject_id: str,
|
||||
) -> StudentWeakness:
|
||||
logger.info(
|
||||
"data_ana_mock_student_weakness",
|
||||
student_id=student_id,
|
||||
subject_id=subject_id,
|
||||
)
|
||||
return StudentWeakness(
|
||||
student_id=student_id,
|
||||
weak_points=[
|
||||
@@ -155,11 +148,6 @@ class DataAnaClientMock(DataAnaClient):
|
||||
title="函数概念(mock)",
|
||||
mastery=0.45,
|
||||
),
|
||||
WeakPoint(
|
||||
knowledge_point_id="kp_005",
|
||||
title="三角函数(mock)",
|
||||
mastery=0.52,
|
||||
),
|
||||
],
|
||||
)
|
||||
|
||||
@@ -169,16 +157,11 @@ class DataAnaClientMock(DataAnaClient):
|
||||
start_date: int = 0,
|
||||
end_date: int = 0,
|
||||
) -> LearningTrend:
|
||||
logger.info(
|
||||
"data_ana_mock_learning_trend",
|
||||
student_id=student_id,
|
||||
)
|
||||
return LearningTrend(
|
||||
student_id=student_id,
|
||||
points=[
|
||||
TrendPoint(date=20260101, score=65.0),
|
||||
TrendPoint(date=20260201, score=70.0),
|
||||
TrendPoint(date=20260301, score=75.0),
|
||||
],
|
||||
)
|
||||
|
||||
@@ -186,37 +169,24 @@ class DataAnaClientMock(DataAnaClient):
|
||||
return self._available
|
||||
|
||||
|
||||
class DataAnaClientGrpc(DataAnaClient):
|
||||
"""Data-ana 服务 gRPC 客户端实现.
|
||||
|
||||
全并行模式:gRPC 调用失败时降级到 mock 数据。
|
||||
"""
|
||||
class DataAnaClientGrpc(BaseGrpcClient, DataAnaClient):
|
||||
"""Data-ana 服务 gRPC 客户端实现(真实调用,不降级到 mock)."""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
endpoint: str = "localhost:50055",
|
||||
request_id: str = "",
|
||||
) -> None:
|
||||
self._endpoint = endpoint
|
||||
self._request_id = request_id
|
||||
self._channel: Any = None
|
||||
self._mock = DataAnaClientMock()
|
||||
super().__init__(endpoint, request_id)
|
||||
self._stub: analytics_pb2_grpc.AnalyticsServiceStub | None = None
|
||||
|
||||
async def connect(self) -> None:
|
||||
"""建立 gRPC 连接."""
|
||||
import grpc
|
||||
|
||||
self._channel = grpc.aio.insecure_channel(self._endpoint)
|
||||
logger.info("data_ana_client_connected", endpoint=self._endpoint)
|
||||
|
||||
async def close(self) -> None:
|
||||
"""关闭 gRPC 连接."""
|
||||
if self._channel is not None:
|
||||
await self._channel.close()
|
||||
self._channel = None
|
||||
"""建立 gRPC 连接并初始化 stub."""
|
||||
await super().connect()
|
||||
self._stub = analytics_pb2_grpc.AnalyticsServiceStub(self.channel)
|
||||
|
||||
def is_available(self) -> bool:
|
||||
return self._channel is not None
|
||||
return self._channel is not None and self._stub is not None
|
||||
|
||||
async def get_class_performance(
|
||||
self,
|
||||
@@ -225,39 +195,74 @@ class DataAnaClientGrpc(DataAnaClient):
|
||||
start_date: int = 0,
|
||||
end_date: int = 0,
|
||||
) -> ClassPerformance:
|
||||
"""查询班级学情(AnalyticsService.GetClassPerformance)."""
|
||||
if not self.is_available():
|
||||
return await self._mock.get_class_performance(
|
||||
class_id, subject_id, start_date, end_date,
|
||||
raise AIError(
|
||||
ErrorCode.AI_DOWNSTREAM_UNAVAILABLE,
|
||||
"data-ana client not connected",
|
||||
)
|
||||
assert self._stub is not None # noqa: S101
|
||||
request = analytics_pb2.GetClassPerformanceRequest(
|
||||
class_id=class_id,
|
||||
subject_id=subject_id,
|
||||
start_date=start_date,
|
||||
end_date=end_date,
|
||||
)
|
||||
try:
|
||||
# 全并行模式:proto 未生成时降级到 mock
|
||||
return await self._mock.get_class_performance(
|
||||
class_id, subject_id, start_date, end_date,
|
||||
)
|
||||
except Exception as exc: # noqa: BLE001
|
||||
logger.warning(
|
||||
"data_ana_class_performance_failed_degraded",
|
||||
error=str(exc),
|
||||
)
|
||||
return await self._mock.get_class_performance(
|
||||
class_id, subject_id, start_date, end_date,
|
||||
)
|
||||
response: analytics_pb2.ClassPerformance = await self._stub.GetClassPerformance(request)
|
||||
except grpc.aio.AioRpcError as exc:
|
||||
raise AIError(
|
||||
ErrorCode.AI_DOWNSTREAM_UNAVAILABLE,
|
||||
f"data-ana.GetClassPerformance failed: {exc.details()}",
|
||||
) from exc
|
||||
return ClassPerformance(
|
||||
class_id=response.class_id,
|
||||
average_score=response.average_score,
|
||||
pass_rate=response.pass_rate,
|
||||
scores=[
|
||||
StudentScore(
|
||||
student_id=s.student_id,
|
||||
score=s.score,
|
||||
grade=s.grade,
|
||||
)
|
||||
for s in response.scores
|
||||
],
|
||||
)
|
||||
|
||||
async def get_student_weakness(
|
||||
self,
|
||||
student_id: str,
|
||||
subject_id: str,
|
||||
) -> StudentWeakness:
|
||||
"""查询学生薄弱点(AnalyticsService.GetStudentWeakness)."""
|
||||
if not self.is_available():
|
||||
return await self._mock.get_student_weakness(student_id, subject_id)
|
||||
try:
|
||||
return await self._mock.get_student_weakness(student_id, subject_id)
|
||||
except Exception as exc: # noqa: BLE001
|
||||
logger.warning(
|
||||
"data_ana_student_weakness_failed_degraded",
|
||||
error=str(exc),
|
||||
raise AIError(
|
||||
ErrorCode.AI_DOWNSTREAM_UNAVAILABLE,
|
||||
"data-ana client not connected",
|
||||
)
|
||||
return await self._mock.get_student_weakness(student_id, subject_id)
|
||||
assert self._stub is not None # noqa: S101
|
||||
request = analytics_pb2.GetStudentWeaknessRequest(
|
||||
student_id=student_id,
|
||||
subject_id=subject_id,
|
||||
)
|
||||
try:
|
||||
response: analytics_pb2.StudentWeakness = await self._stub.GetStudentWeakness(request)
|
||||
except grpc.aio.AioRpcError as exc:
|
||||
raise AIError(
|
||||
ErrorCode.AI_DOWNSTREAM_UNAVAILABLE,
|
||||
f"data-ana.GetStudentWeakness failed: {exc.details()}",
|
||||
) from exc
|
||||
return StudentWeakness(
|
||||
student_id=response.student_id,
|
||||
weak_points=[
|
||||
WeakPoint(
|
||||
knowledge_point_id=p.knowledge_point_id,
|
||||
title=p.title,
|
||||
mastery=p.mastery,
|
||||
)
|
||||
for p in response.weak_points
|
||||
],
|
||||
)
|
||||
|
||||
async def get_learning_trend(
|
||||
self,
|
||||
@@ -265,19 +270,26 @@ class DataAnaClientGrpc(DataAnaClient):
|
||||
start_date: int = 0,
|
||||
end_date: int = 0,
|
||||
) -> LearningTrend:
|
||||
"""查询学习趋势(AnalyticsService.GetLearningTrend)."""
|
||||
if not self.is_available():
|
||||
return await self._mock.get_learning_trend(
|
||||
student_id, start_date, end_date,
|
||||
raise AIError(
|
||||
ErrorCode.AI_DOWNSTREAM_UNAVAILABLE,
|
||||
"data-ana client not connected",
|
||||
)
|
||||
assert self._stub is not None # noqa: S101
|
||||
request = analytics_pb2.GetLearningTrendRequest(
|
||||
student_id=student_id,
|
||||
start_date=start_date,
|
||||
end_date=end_date,
|
||||
)
|
||||
try:
|
||||
return await self._mock.get_learning_trend(
|
||||
student_id, start_date, end_date,
|
||||
)
|
||||
except Exception as exc: # noqa: BLE001
|
||||
logger.warning(
|
||||
"data_ana_learning_trend_failed_degraded",
|
||||
error=str(exc),
|
||||
)
|
||||
return await self._mock.get_learning_trend(
|
||||
student_id, start_date, end_date,
|
||||
)
|
||||
response: analytics_pb2.LearningTrend = await self._stub.GetLearningTrend(request)
|
||||
except grpc.aio.AioRpcError as exc:
|
||||
raise AIError(
|
||||
ErrorCode.AI_DOWNSTREAM_UNAVAILABLE,
|
||||
f"data-ana.GetLearningTrend failed: {exc.details()}",
|
||||
) from exc
|
||||
return LearningTrend(
|
||||
student_id=response.student_id,
|
||||
points=[TrendPoint(date=p.date, score=p.score) for p in response.points],
|
||||
)
|
||||
|
||||
@@ -1,17 +1,22 @@
|
||||
"""IAM 服务 gRPC 客户端.
|
||||
|
||||
用于:
|
||||
- 查询用户有效数据范围(GetEffectiveDataScope - ISSUE-07: P4 补全,ai 用 mock)
|
||||
- 查询用户有效数据范围(IamService.GetEffectiveDataScope)
|
||||
|
||||
全并行模式:IAM 不可用时使用 mock 数据降级。
|
||||
真实 gRPC 调用:未连接或调用失败时抛 AIError(不再降级到 mock 数据)。
|
||||
"""
|
||||
|
||||
from abc import ABC, abstractmethod
|
||||
from dataclasses import dataclass
|
||||
from typing import Any
|
||||
|
||||
import grpc
|
||||
import structlog
|
||||
|
||||
from ..errors import AIError, ErrorCode
|
||||
from ..proto_gen import iam_pb2, iam_pb2_grpc
|
||||
from .base_client import BaseGrpcClient
|
||||
|
||||
logger = structlog.get_logger()
|
||||
|
||||
|
||||
@@ -56,10 +61,7 @@ class IamClient(ABC):
|
||||
self,
|
||||
user_id: str,
|
||||
) -> DataScope:
|
||||
"""查询用户有效数据范围.
|
||||
|
||||
ISSUE-07: IAM P4 补全 GetEffectiveDataScope RPC 后启用真实调用。
|
||||
"""
|
||||
"""查询用户有效数据范围."""
|
||||
...
|
||||
|
||||
@abstractmethod
|
||||
@@ -69,7 +71,7 @@ class IamClient(ABC):
|
||||
|
||||
|
||||
class IamClientMock(IamClient):
|
||||
"""IAM 客户端 Mock 实现(全并行模式)."""
|
||||
"""IAM 客户端 Mock 实现(仅用于单元测试)."""
|
||||
|
||||
def __init__(self) -> None:
|
||||
self._available = True
|
||||
@@ -78,7 +80,6 @@ class IamClientMock(IamClient):
|
||||
self,
|
||||
user_id: str,
|
||||
) -> DataScope:
|
||||
logger.info("iam_mock_get_data_scope", user_id=user_id)
|
||||
return DataScope(
|
||||
user_id=user_id,
|
||||
school_id="school_mock_001",
|
||||
@@ -93,43 +94,68 @@ class IamClientMock(IamClient):
|
||||
return self._available
|
||||
|
||||
|
||||
class IamClientGrpc(IamClient):
|
||||
"""IAM 服务 gRPC 客户端实现.
|
||||
|
||||
ISSUE-07: IAM P4 补全 GetEffectiveDataScope RPC 后启用。
|
||||
全并行模式:当前使用 mock 数据。
|
||||
"""
|
||||
class IamClientGrpc(BaseGrpcClient, IamClient):
|
||||
"""IAM 服务 gRPC 客户端实现(真实调用,不降级到 mock)."""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
endpoint: str = "localhost:50052",
|
||||
request_id: str = "",
|
||||
) -> None:
|
||||
self._endpoint = endpoint
|
||||
self._request_id = request_id
|
||||
self._channel: Any = None
|
||||
self._mock = IamClientMock()
|
||||
super().__init__(endpoint, request_id)
|
||||
self._stub: iam_pb2_grpc.IamServiceStub | None = None
|
||||
|
||||
async def connect(self) -> None:
|
||||
"""建立 gRPC 连接."""
|
||||
import grpc
|
||||
|
||||
self._channel = grpc.aio.insecure_channel(self._endpoint)
|
||||
logger.info("iam_client_connected", endpoint=self._endpoint)
|
||||
|
||||
async def close(self) -> None:
|
||||
"""关闭 gRPC 连接."""
|
||||
if self._channel is not None:
|
||||
await self._channel.close()
|
||||
self._channel = None
|
||||
"""建立 gRPC 连接并初始化 stub."""
|
||||
await super().connect()
|
||||
self._stub = iam_pb2_grpc.IamServiceStub(self.channel)
|
||||
|
||||
def is_available(self) -> bool:
|
||||
return self._channel is not None
|
||||
return self._channel is not None and self._stub is not None
|
||||
|
||||
async def get_effective_data_scope(
|
||||
self,
|
||||
user_id: str,
|
||||
) -> DataScope:
|
||||
# ISSUE-07: IAM P4 补全 GetEffectiveDataScope 后启用真实调用
|
||||
# 全并行模式:当前使用 mock
|
||||
return await self._mock.get_effective_data_scope(user_id)
|
||||
"""查询用户有效数据范围(IamService.GetEffectiveDataScope).
|
||||
|
||||
Proto 返回 EffectiveDataScope{user_id, level, scope_ids, school_id}:
|
||||
- level=SELF → class_ids=[], 仅本人
|
||||
- level=CLASS → class_ids=scope_ids
|
||||
- level=GRADE → grade_ids=scope_ids
|
||||
- level=SCHOOL → school_id 取响应的 school_id
|
||||
- level=ALL → is_admin=True
|
||||
"""
|
||||
if not self.is_available():
|
||||
raise AIError(
|
||||
ErrorCode.AI_DOWNSTREAM_UNAVAILABLE,
|
||||
"iam client not connected",
|
||||
)
|
||||
assert self._stub is not None # noqa: S101
|
||||
request = iam_pb2.GetEffectiveDataScopeRequest(user_id=user_id)
|
||||
try:
|
||||
response: iam_pb2.EffectiveDataScope = await self._stub.GetEffectiveDataScope(request)
|
||||
except grpc.aio.AioRpcError as exc:
|
||||
raise AIError(
|
||||
ErrorCode.AI_DOWNSTREAM_UNAVAILABLE,
|
||||
f"iam.GetEffectiveDataScope failed: {exc.details()}",
|
||||
) from exc
|
||||
# 将 proto EffectiveDataScope 映射为内部 DataScope
|
||||
class_ids: list[str] = []
|
||||
grade_ids: list[str] = []
|
||||
is_admin = False
|
||||
level = response.level.upper() if response.level else "SELF"
|
||||
if level == "CLASS":
|
||||
class_ids = list(response.scope_ids)
|
||||
elif level == "GRADE":
|
||||
grade_ids = list(response.scope_ids)
|
||||
elif level == "ALL":
|
||||
is_admin = True
|
||||
return DataScope(
|
||||
user_id=response.user_id or user_id,
|
||||
school_id=response.school_id,
|
||||
class_ids=class_ids,
|
||||
grade_ids=grade_ids,
|
||||
role="admin" if is_admin else "teacher",
|
||||
is_admin=is_admin,
|
||||
)
|
||||
|
||||
@@ -1,13 +1,15 @@
|
||||
"""gRPC 拦截器.
|
||||
"""gRPC 拦截器(异步版本,适配 grpc.aio.server).
|
||||
|
||||
提供:
|
||||
- LoggingInterceptor: 请求/响应日志 + 延迟统计
|
||||
- ErrorInterceptor: 异常捕获 → gRPC status code 映射
|
||||
- AuthInterceptor: 从 metadata 提取用户上下文
|
||||
|
||||
注意:grpc.aio.server 的 interceptors 必须继承 grpc.aio.ServerInterceptor,
|
||||
且 intercept_service 必须是 async 方法。同步 grpc.ServerInterceptor 会触发 ValueError。
|
||||
"""
|
||||
|
||||
import time
|
||||
from collections.abc import Callable
|
||||
from typing import Any
|
||||
|
||||
import grpc
|
||||
@@ -20,66 +22,72 @@ from ..middleware.error_handler import grpc_error_mapper
|
||||
logger = structlog.get_logger()
|
||||
|
||||
|
||||
class LoggingInterceptor(grpc.ServerInterceptor):
|
||||
"""请求日志 + 延迟统计."""
|
||||
async def _async_wrapper(
|
||||
handler: Any,
|
||||
request: Any,
|
||||
context: grpc.aio.ServicerContext,
|
||||
) -> Any:
|
||||
"""调用 async 或 sync handler 并返回响应."""
|
||||
return await handler(request, context)
|
||||
|
||||
def intercept_service(
|
||||
|
||||
class LoggingInterceptor(grpc.aio.ServerInterceptor):
|
||||
"""请求日志 + 延迟统计(异步)."""
|
||||
|
||||
async def intercept_service(
|
||||
self,
|
||||
continuation: Callable[[grpc.HandlerCallDetails], grpc.RpcMethodHandler],
|
||||
continuation: Any,
|
||||
handler_call_details: grpc.HandlerCallDetails,
|
||||
) -> grpc.RpcMethodHandler:
|
||||
method = handler_call_details.method
|
||||
start = time.monotonic()
|
||||
|
||||
def log_wrapper(handler: grpc.RpcMethodHandler) -> grpc.RpcMethodHandler:
|
||||
original_behavior = handler.unary_unary
|
||||
|
||||
def new_behavior(request: Any, context: grpc.ServicerContext) -> Any:
|
||||
latency_ms = int((time.monotonic() - start) * 1000)
|
||||
try:
|
||||
response = original_behavior(request, context) # type: ignore[misc]
|
||||
logger.info(
|
||||
"grpc_request",
|
||||
method=method,
|
||||
latency_ms=latency_ms,
|
||||
status="ok",
|
||||
)
|
||||
return response
|
||||
except Exception as exc:
|
||||
logger.error(
|
||||
"grpc_request_error",
|
||||
method=method,
|
||||
latency_ms=latency_ms,
|
||||
error=str(exc),
|
||||
)
|
||||
raise
|
||||
|
||||
handler.unary_unary = new_behavior # type: ignore[method-assign]
|
||||
return handler
|
||||
|
||||
handler = continuation(handler_call_details)
|
||||
if handler is None:
|
||||
return None
|
||||
return log_wrapper(handler)
|
||||
|
||||
|
||||
class ErrorInterceptor(grpc.ServerInterceptor):
|
||||
"""异常捕获 → gRPC status code 映射."""
|
||||
|
||||
def intercept_service(
|
||||
self,
|
||||
continuation: Callable[[grpc.HandlerCallDetails], grpc.RpcMethodHandler],
|
||||
handler_call_details: grpc.HandlerCallDetails,
|
||||
) -> grpc.RpcMethodHandler:
|
||||
handler = continuation(handler_call_details)
|
||||
handler = await continuation(handler_call_details)
|
||||
if handler is None:
|
||||
return None
|
||||
|
||||
original_behavior = handler.unary_unary
|
||||
|
||||
def new_behavior(request: Any, context: grpc.ServicerContext) -> Any:
|
||||
async def new_behavior(request: Any, context: grpc.aio.ServicerContext) -> Any:
|
||||
latency_ms = int((time.monotonic() - start) * 1000)
|
||||
try:
|
||||
return original_behavior(request, context) # type: ignore[misc]
|
||||
response = await _async_wrapper(original_behavior, request, context)
|
||||
logger.info(
|
||||
"grpc_request",
|
||||
method=method,
|
||||
latency_ms=latency_ms,
|
||||
status="ok",
|
||||
)
|
||||
return response
|
||||
except Exception as exc:
|
||||
logger.error(
|
||||
"grpc_request_error",
|
||||
method=method,
|
||||
latency_ms=latency_ms,
|
||||
error=str(exc),
|
||||
)
|
||||
raise
|
||||
|
||||
handler.unary_unary = new_behavior # type: ignore[method-assign]
|
||||
return handler
|
||||
|
||||
|
||||
class ErrorInterceptor(grpc.aio.ServerInterceptor):
|
||||
"""异常捕获 → gRPC status code 映射(异步)."""
|
||||
|
||||
async def intercept_service(
|
||||
self,
|
||||
continuation: Any,
|
||||
handler_call_details: grpc.HandlerCallDetails,
|
||||
) -> grpc.RpcMethodHandler:
|
||||
handler = await continuation(handler_call_details)
|
||||
if handler is None:
|
||||
return None
|
||||
|
||||
original_behavior = handler.unary_unary
|
||||
|
||||
async def new_behavior(request: Any, context: grpc.aio.ServicerContext) -> Any:
|
||||
try:
|
||||
return await _async_wrapper(original_behavior, request, context)
|
||||
except AIError as exc:
|
||||
code, msg, grpc_status = grpc_error_mapper(exc)
|
||||
logger.warning(
|
||||
@@ -88,7 +96,7 @@ class ErrorInterceptor(grpc.ServerInterceptor):
|
||||
error_code=code,
|
||||
message=msg,
|
||||
)
|
||||
context.abort(_grpc_status(grpc_status), f"{code}: {msg}")
|
||||
await context.abort(_grpc_status(grpc_status), f"{code}: {msg}")
|
||||
except Exception as exc:
|
||||
code, msg, grpc_status = grpc_error_mapper(exc)
|
||||
logger.error(
|
||||
@@ -96,31 +104,33 @@ class ErrorInterceptor(grpc.ServerInterceptor):
|
||||
method=handler_call_details.method,
|
||||
error=str(exc),
|
||||
)
|
||||
context.abort(_grpc_status(grpc_status), f"{code}: {msg}")
|
||||
await context.abort(_grpc_status(grpc_status), f"{code}: {msg}")
|
||||
|
||||
handler.unary_unary = new_behavior # type: ignore[method-assign]
|
||||
return handler
|
||||
|
||||
|
||||
class AuthInterceptor(grpc.ServerInterceptor):
|
||||
"""从 gRPC metadata 提取用户上下文,存入 context."""
|
||||
class AuthInterceptor(grpc.aio.ServerInterceptor):
|
||||
"""从 gRPC metadata 提取用户上下文,存入 context(异步)."""
|
||||
|
||||
def intercept_service(
|
||||
async def intercept_service(
|
||||
self,
|
||||
continuation: Callable[[grpc.HandlerCallDetails], grpc.RpcMethodHandler],
|
||||
continuation: Any,
|
||||
handler_call_details: grpc.HandlerCallDetails,
|
||||
) -> grpc.RpcMethodHandler:
|
||||
handler = continuation(handler_call_details)
|
||||
handler = await continuation(handler_call_details)
|
||||
if handler is None:
|
||||
return None
|
||||
|
||||
original_behavior = handler.unary_unary
|
||||
|
||||
def new_behavior(request: Any, context: grpc.ServicerContext) -> Any:
|
||||
ctx = extract_user_context_from_metadata(handler_call_details.invocation_metadata)
|
||||
async def new_behavior(request: Any, context: grpc.aio.ServicerContext) -> Any:
|
||||
ctx = extract_user_context_from_metadata(
|
||||
handler_call_details.invocation_metadata,
|
||||
)
|
||||
# 将 UserContext 存入 context 供 servicer 使用
|
||||
context.user_context = ctx # type: ignore[attr-defined]
|
||||
return original_behavior(request, context) # type: ignore[misc]
|
||||
return await _async_wrapper(original_behavior, request, context)
|
||||
|
||||
handler.unary_unary = new_behavior # type: ignore[method-assign]
|
||||
return handler
|
||||
@@ -149,6 +159,6 @@ def _grpc_status(code: int) -> grpc.StatusCode:
|
||||
return status_map.get(code, grpc.StatusCode.UNKNOWN)
|
||||
|
||||
|
||||
def get_user_context(context: grpc.ServicerContext) -> UserContext:
|
||||
def get_user_context(context: grpc.aio.ServicerContext) -> UserContext:
|
||||
"""从 ServicerContext 提取 UserContext(AuthInterceptor 注入)."""
|
||||
return getattr(context, "user_context", UserContext())
|
||||
|
||||
@@ -39,16 +39,10 @@ class GrpcServer:
|
||||
async def start(self) -> None:
|
||||
"""启动 gRPC server.
|
||||
|
||||
注意:grpc.aio.server 的 interceptors 需要 grpc.aio.ServerInterceptor 基类,
|
||||
当前拦截器使用同步 grpc.ServerInterceptor 基类会报 ValueError。
|
||||
此处 try/except 降级为无拦截器启动,避免阻塞服务启动。
|
||||
使用 grpc.aio.ServerInterceptor 异步拦截器(Logging/Auth/Error)。
|
||||
"""
|
||||
interceptors = [LoggingInterceptor(), AuthInterceptor(), ErrorInterceptor()]
|
||||
try:
|
||||
self._server = grpc.aio.server(interceptors=interceptors)
|
||||
except (ValueError, TypeError):
|
||||
logger.warning("grpc_interceptors_incompatible_start_without")
|
||||
self._server = grpc.aio.server()
|
||||
self._server = grpc.aio.server(interceptors=interceptors)
|
||||
ai_pb2_grpc.add_AiServiceServicer_to_server(self._servicer, self._server)
|
||||
self._server.add_insecure_port(f"[::]:{self._port}")
|
||||
await self._server.start()
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
- 评估三道防线(RuleValidator + LLMJudge + QualityGate)
|
||||
- 用量记录(Redis)+ Kafka 事件发布 + 配额管理
|
||||
- 安全层(PII + 输入清洗 + 输出审核)
|
||||
- 下游 gRPC 客户端(content/data-ana/iam,全并行用 Mock)
|
||||
- 下游 gRPC 客户端(content/data-ana/iam,真实 gRPC 调用)
|
||||
- 备课工作流(4 步编排 + Redis 状态存储)
|
||||
- 限流(Redis 三维度令牌桶)
|
||||
- OpenTelemetry + Prometheus
|
||||
@@ -30,7 +30,7 @@ from opentelemetry.sdk.trace.export import BatchSpanProcessor
|
||||
from prometheus_client import make_asgi_app
|
||||
from redis.asyncio import Redis
|
||||
|
||||
from .clients import ContentClientMock, DataAnaClientMock, IamClientMock
|
||||
from .clients import ContentClientGrpc, DataAnaClientGrpc, IamClientGrpc
|
||||
from .config import settings
|
||||
from .grpc_server import create_grpc_server
|
||||
from .middleware import (
|
||||
@@ -130,10 +130,11 @@ _rate_limiter = RateLimiter(
|
||||
school_limit=settings.redis_rate_limit_school_per_min,
|
||||
)
|
||||
|
||||
# 下游客户端(全并行模式用 Mock,ISSUE-07)
|
||||
_content_client = ContentClientMock()
|
||||
_data_ana_client = DataAnaClientMock()
|
||||
_iam_client = IamClientMock()
|
||||
# 下游 gRPC 客户端(真实 gRPC 调用,lifespan 中连接)
|
||||
# 连接失败时降级(不阻断启动),但调用未连接的客户端方法会抛 AIError
|
||||
_content_client = ContentClientGrpc(endpoint=settings.content_grpc_endpoint)
|
||||
_data_ana_client = DataAnaClientGrpc(endpoint=settings.data_ana_grpc_endpoint)
|
||||
_iam_client = IamClientGrpc(endpoint=settings.iam_grpc_endpoint)
|
||||
|
||||
_state_store = WorkflowStateStore(
|
||||
redis=None,
|
||||
@@ -179,6 +180,22 @@ async def lifespan(app: FastAPI) -> AsyncGenerator[None, None]:
|
||||
logger.warning("redis_connect_failed_degraded", error=str(exc))
|
||||
_redis = None
|
||||
|
||||
# 下游 gRPC 客户端连接(每个独立 try,单个失败不阻断其他)
|
||||
downstream_clients = [
|
||||
("content", _content_client),
|
||||
("data_ana", _data_ana_client),
|
||||
("iam", _iam_client),
|
||||
]
|
||||
for name, client in downstream_clients:
|
||||
try:
|
||||
await client.connect()
|
||||
except Exception as exc: # noqa: BLE001
|
||||
logger.warning(
|
||||
"downstream_client_connect_failed",
|
||||
client=name,
|
||||
error=str(exc),
|
||||
)
|
||||
|
||||
await _kafka_producer.start()
|
||||
await _grpc_server.start()
|
||||
|
||||
@@ -188,6 +205,9 @@ async def lifespan(app: FastAPI) -> AsyncGenerator[None, None]:
|
||||
grpc_port=settings.grpc_port,
|
||||
dev_mode=settings.is_dev,
|
||||
llm_available=settings.llm_available,
|
||||
content_connected=_content_client.is_available(),
|
||||
data_ana_connected=_data_ana_client.is_available(),
|
||||
iam_connected=_iam_client.is_available(),
|
||||
)
|
||||
if not settings.llm_available:
|
||||
logger.warning("ai_service_llm_degraded_no_api_key")
|
||||
@@ -198,6 +218,15 @@ async def lifespan(app: FastAPI) -> AsyncGenerator[None, None]:
|
||||
logger.info("ai_service_stopping")
|
||||
await _grpc_server.stop()
|
||||
await _kafka_producer.stop()
|
||||
for name, client in reversed(downstream_clients):
|
||||
try:
|
||||
await client.close()
|
||||
except Exception as exc: # noqa: BLE001
|
||||
logger.warning(
|
||||
"downstream_client_close_failed",
|
||||
client=name,
|
||||
error=str(exc),
|
||||
)
|
||||
if _redis is not None:
|
||||
await _redis.aclose()
|
||||
logger.info("redis_closed")
|
||||
|
||||
@@ -1,14 +1,46 @@
|
||||
"""protobuf 生成代码(勿手动编辑).
|
||||
|
||||
由 grpc_tools.protoc 从 packages/shared-proto/proto/ai.proto 生成。
|
||||
重新生成命令:
|
||||
由 grpc_tools.protoc 从 packages/shared-proto/proto/ 生成。
|
||||
重新生成命令(在 services/ai 目录下):
|
||||
uv run python -m grpc_tools.protoc \\
|
||||
-I ../../packages/shared-proto/proto \\
|
||||
--python_out=src/ai/proto_gen \\
|
||||
--grpc_python_out=src/ai/proto_gen \\
|
||||
../../packages/shared-proto/proto/ai.proto
|
||||
../../packages/shared-proto/proto/ai.proto \\
|
||||
../../packages/shared-proto/proto/content.proto \\
|
||||
../../packages/shared-proto/proto/analytics.proto \\
|
||||
../../packages/shared-proto/proto/iam.proto
|
||||
|
||||
注意:生成的 *_pb2_grpc.py 文件使用绝对导入(如 `import content_pb2 as content__pb2`),
|
||||
本文件通过 sys.path 注入确保这些绝对导入可用。
|
||||
"""
|
||||
|
||||
from . import ai_pb2, ai_pb2_grpc
|
||||
import os
|
||||
import sys
|
||||
|
||||
__all__ = ["ai_pb2", "ai_pb2_grpc"]
|
||||
# 将本目录加入 sys.path,使生成的 *_pb2_grpc.py 中的绝对导入(如 `import content_pb2`)可用
|
||||
_PB_DIR = os.path.dirname(os.path.abspath(__file__))
|
||||
if _PB_DIR not in sys.path:
|
||||
sys.path.insert(0, _PB_DIR)
|
||||
|
||||
from . import ( # noqa: E402
|
||||
ai_pb2,
|
||||
ai_pb2_grpc,
|
||||
analytics_pb2,
|
||||
analytics_pb2_grpc,
|
||||
content_pb2,
|
||||
content_pb2_grpc,
|
||||
iam_pb2,
|
||||
iam_pb2_grpc,
|
||||
)
|
||||
|
||||
__all__ = [
|
||||
"ai_pb2",
|
||||
"ai_pb2_grpc",
|
||||
"analytics_pb2",
|
||||
"analytics_pb2_grpc",
|
||||
"content_pb2",
|
||||
"content_pb2_grpc",
|
||||
"iam_pb2",
|
||||
"iam_pb2_grpc",
|
||||
]
|
||||
|
||||
102
services/ai/src/ai/proto_gen/analytics_pb2.py
Normal file
102
services/ai/src/ai/proto_gen/analytics_pb2.py
Normal file
File diff suppressed because one or more lines are too long
591
services/ai/src/ai/proto_gen/analytics_pb2_grpc.py
Normal file
591
services/ai/src/ai/proto_gen/analytics_pb2_grpc.py
Normal file
@@ -0,0 +1,591 @@
|
||||
# Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT!
|
||||
"""Client and server classes corresponding to protobuf-defined services."""
|
||||
import grpc
|
||||
import warnings
|
||||
|
||||
import analytics_pb2 as analytics__pb2
|
||||
|
||||
GRPC_GENERATED_VERSION = '1.82.1'
|
||||
GRPC_VERSION = grpc.__version__
|
||||
_version_not_supported = False
|
||||
|
||||
try:
|
||||
from grpc._utilities import first_version_is_lower
|
||||
_version_not_supported = first_version_is_lower(GRPC_VERSION, GRPC_GENERATED_VERSION)
|
||||
except ImportError:
|
||||
_version_not_supported = True
|
||||
|
||||
if _version_not_supported:
|
||||
raise RuntimeError(
|
||||
f'The grpc package installed is at version {GRPC_VERSION},'
|
||||
+ ' but the generated code in analytics_pb2_grpc.py depends on'
|
||||
+ f' grpcio>={GRPC_GENERATED_VERSION}.'
|
||||
+ f' Please upgrade your grpc module to grpcio>={GRPC_GENERATED_VERSION}'
|
||||
+ f' or downgrade your generated code using grpcio-tools<={GRPC_VERSION}.'
|
||||
)
|
||||
|
||||
|
||||
class AnalyticsServiceStub:
|
||||
"""AnalyticsService 数据分析服务契约(D6 智能洞察领域).
|
||||
P4 启用 gRPC server 端口 50055,HTTP 3006 保留作 Gateway 直连降级.
|
||||
所有 RPC 返回 ActionState 信封(success/data/error/details.degraded).
|
||||
"""
|
||||
|
||||
def __init__(self, channel):
|
||||
"""Constructor.
|
||||
|
||||
Args:
|
||||
channel: A grpc.Channel.
|
||||
"""
|
||||
self.GetClassPerformance = channel.unary_unary(
|
||||
'/next_edu_cloud.analytics.v1.AnalyticsService/GetClassPerformance',
|
||||
request_serializer=analytics__pb2.GetClassPerformanceRequest.SerializeToString,
|
||||
response_deserializer=analytics__pb2.ClassPerformance.FromString,
|
||||
_registered_method=True)
|
||||
self.GetStudentWeakness = channel.unary_unary(
|
||||
'/next_edu_cloud.analytics.v1.AnalyticsService/GetStudentWeakness',
|
||||
request_serializer=analytics__pb2.GetStudentWeaknessRequest.SerializeToString,
|
||||
response_deserializer=analytics__pb2.StudentWeakness.FromString,
|
||||
_registered_method=True)
|
||||
self.GetLearningTrend = channel.unary_unary(
|
||||
'/next_edu_cloud.analytics.v1.AnalyticsService/GetLearningTrend',
|
||||
request_serializer=analytics__pb2.GetLearningTrendRequest.SerializeToString,
|
||||
response_deserializer=analytics__pb2.LearningTrend.FromString,
|
||||
_registered_method=True)
|
||||
self.GetTeacherDashboard = channel.unary_unary(
|
||||
'/next_edu_cloud.analytics.v1.AnalyticsService/GetTeacherDashboard',
|
||||
request_serializer=analytics__pb2.GetTeacherDashboardRequest.SerializeToString,
|
||||
response_deserializer=analytics__pb2.TeacherDashboard.FromString,
|
||||
_registered_method=True)
|
||||
self.GetStudentDashboard = channel.unary_unary(
|
||||
'/next_edu_cloud.analytics.v1.AnalyticsService/GetStudentDashboard',
|
||||
request_serializer=analytics__pb2.GetStudentDashboardRequest.SerializeToString,
|
||||
response_deserializer=analytics__pb2.StudentDashboard.FromString,
|
||||
_registered_method=True)
|
||||
self.GetParentDashboard = channel.unary_unary(
|
||||
'/next_edu_cloud.analytics.v1.AnalyticsService/GetParentDashboard',
|
||||
request_serializer=analytics__pb2.GetParentDashboardRequest.SerializeToString,
|
||||
response_deserializer=analytics__pb2.ParentDashboard.FromString,
|
||||
_registered_method=True)
|
||||
self.GetAdminDashboard = channel.unary_unary(
|
||||
'/next_edu_cloud.analytics.v1.AnalyticsService/GetAdminDashboard',
|
||||
request_serializer=analytics__pb2.GetAdminDashboardRequest.SerializeToString,
|
||||
response_deserializer=analytics__pb2.AdminDashboard.FromString,
|
||||
_registered_method=True)
|
||||
self.GetWarnings = channel.unary_unary(
|
||||
'/next_edu_cloud.analytics.v1.AnalyticsService/GetWarnings',
|
||||
request_serializer=analytics__pb2.GetWarningsRequest.SerializeToString,
|
||||
response_deserializer=analytics__pb2.WarningList.FromString,
|
||||
_registered_method=True)
|
||||
self.TriggerWarning = channel.unary_unary(
|
||||
'/next_edu_cloud.analytics.v1.AnalyticsService/TriggerWarning',
|
||||
request_serializer=analytics__pb2.TriggerWarningRequest.SerializeToString,
|
||||
response_deserializer=analytics__pb2.TriggerWarningResponse.FromString,
|
||||
_registered_method=True)
|
||||
self.GetMasteryDistribution = channel.unary_unary(
|
||||
'/next_edu_cloud.analytics.v1.AnalyticsService/GetMasteryDistribution',
|
||||
request_serializer=analytics__pb2.GetMasteryDistributionRequest.SerializeToString,
|
||||
response_deserializer=analytics__pb2.MasteryDistribution.FromString,
|
||||
_registered_method=True)
|
||||
self.GetStudentMastery = channel.unary_unary(
|
||||
'/next_edu_cloud.analytics.v1.AnalyticsService/GetStudentMastery',
|
||||
request_serializer=analytics__pb2.GetStudentMasteryRequest.SerializeToString,
|
||||
response_deserializer=analytics__pb2.StudentMastery.FromString,
|
||||
_registered_method=True)
|
||||
self.SubscribeMasteryUpdate = channel.unary_stream(
|
||||
'/next_edu_cloud.analytics.v1.AnalyticsService/SubscribeMasteryUpdate',
|
||||
request_serializer=analytics__pb2.SubscribeMasteryUpdateRequest.SerializeToString,
|
||||
response_deserializer=analytics__pb2.MasteryUpdateEvent.FromString,
|
||||
_registered_method=True)
|
||||
|
||||
|
||||
class AnalyticsServiceServicer:
|
||||
"""AnalyticsService 数据分析服务契约(D6 智能洞察领域).
|
||||
P4 启用 gRPC server 端口 50055,HTTP 3006 保留作 Gateway 直连降级.
|
||||
所有 RPC 返回 ActionState 信封(success/data/error/details.degraded).
|
||||
"""
|
||||
|
||||
def GetClassPerformance(self, request, context):
|
||||
"""班级成绩分析(平均分/及格率/参考人数).
|
||||
"""
|
||||
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
|
||||
context.set_details('Method not implemented!')
|
||||
raise NotImplementedError('Method not implemented!')
|
||||
|
||||
def GetStudentWeakness(self, request, context):
|
||||
"""学生薄弱知识点(mastery_level < 0.6).
|
||||
"""
|
||||
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
|
||||
context.set_details('Method not implemented!')
|
||||
raise NotImplementedError('Method not implemented!')
|
||||
|
||||
def GetLearningTrend(self, request, context):
|
||||
"""学习趋势(历史成绩曲线).
|
||||
"""
|
||||
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
|
||||
context.set_details('Method not implemented!')
|
||||
raise NotImplementedError('Method not implemented!')
|
||||
|
||||
def GetTeacherDashboard(self, request, context):
|
||||
"""教师仪表盘聚合(班级概览 + 待办 + 预警).
|
||||
"""
|
||||
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
|
||||
context.set_details('Method not implemented!')
|
||||
raise NotImplementedError('Method not implemented!')
|
||||
|
||||
def GetStudentDashboard(self, request, context):
|
||||
"""学生仪表盘(个人学情 + 排名 + 薄弱点).
|
||||
"""
|
||||
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
|
||||
context.set_details('Method not implemented!')
|
||||
raise NotImplementedError('Method not implemented!')
|
||||
|
||||
def GetParentDashboard(self, request, context):
|
||||
"""家长仪表盘(孩子学情概览).
|
||||
"""
|
||||
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
|
||||
context.set_details('Method not implemented!')
|
||||
raise NotImplementedError('Method not implemented!')
|
||||
|
||||
def GetAdminDashboard(self, request, context):
|
||||
"""管理员仪表盘(全校统计 + AI 用量).
|
||||
"""
|
||||
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
|
||||
context.set_details('Method not implemented!')
|
||||
raise NotImplementedError('Method not implemented!')
|
||||
|
||||
def GetWarnings(self, request, context):
|
||||
"""预警列表查询(按班级/严重度/时间过滤).
|
||||
"""
|
||||
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
|
||||
context.set_details('Method not implemented!')
|
||||
raise NotImplementedError('Method not implemented!')
|
||||
|
||||
def TriggerWarning(self, request, context):
|
||||
"""手动触发预警(管理员/教师主动标记关注).
|
||||
"""
|
||||
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
|
||||
context.set_details('Method not implemented!')
|
||||
raise NotImplementedError('Method not implemented!')
|
||||
|
||||
def GetMasteryDistribution(self, request, context):
|
||||
"""班级掌握度分布(mastered/progressing/weak 三档).
|
||||
"""
|
||||
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
|
||||
context.set_details('Method not implemented!')
|
||||
raise NotImplementedError('Method not implemented!')
|
||||
|
||||
def GetStudentMastery(self, request, context):
|
||||
"""学生知识点掌握度明细.
|
||||
"""
|
||||
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
|
||||
context.set_details('Method not implemented!')
|
||||
raise NotImplementedError('Method not implemented!')
|
||||
|
||||
def SubscribeMasteryUpdate(self, request, context):
|
||||
"""订阅掌握度更新(server-streaming,P5+ AI 个性化推荐实时推送通道).
|
||||
"""
|
||||
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
|
||||
context.set_details('Method not implemented!')
|
||||
raise NotImplementedError('Method not implemented!')
|
||||
|
||||
|
||||
def add_AnalyticsServiceServicer_to_server(servicer, server):
|
||||
rpc_method_handlers = {
|
||||
'GetClassPerformance': grpc.unary_unary_rpc_method_handler(
|
||||
servicer.GetClassPerformance,
|
||||
request_deserializer=analytics__pb2.GetClassPerformanceRequest.FromString,
|
||||
response_serializer=analytics__pb2.ClassPerformance.SerializeToString,
|
||||
),
|
||||
'GetStudentWeakness': grpc.unary_unary_rpc_method_handler(
|
||||
servicer.GetStudentWeakness,
|
||||
request_deserializer=analytics__pb2.GetStudentWeaknessRequest.FromString,
|
||||
response_serializer=analytics__pb2.StudentWeakness.SerializeToString,
|
||||
),
|
||||
'GetLearningTrend': grpc.unary_unary_rpc_method_handler(
|
||||
servicer.GetLearningTrend,
|
||||
request_deserializer=analytics__pb2.GetLearningTrendRequest.FromString,
|
||||
response_serializer=analytics__pb2.LearningTrend.SerializeToString,
|
||||
),
|
||||
'GetTeacherDashboard': grpc.unary_unary_rpc_method_handler(
|
||||
servicer.GetTeacherDashboard,
|
||||
request_deserializer=analytics__pb2.GetTeacherDashboardRequest.FromString,
|
||||
response_serializer=analytics__pb2.TeacherDashboard.SerializeToString,
|
||||
),
|
||||
'GetStudentDashboard': grpc.unary_unary_rpc_method_handler(
|
||||
servicer.GetStudentDashboard,
|
||||
request_deserializer=analytics__pb2.GetStudentDashboardRequest.FromString,
|
||||
response_serializer=analytics__pb2.StudentDashboard.SerializeToString,
|
||||
),
|
||||
'GetParentDashboard': grpc.unary_unary_rpc_method_handler(
|
||||
servicer.GetParentDashboard,
|
||||
request_deserializer=analytics__pb2.GetParentDashboardRequest.FromString,
|
||||
response_serializer=analytics__pb2.ParentDashboard.SerializeToString,
|
||||
),
|
||||
'GetAdminDashboard': grpc.unary_unary_rpc_method_handler(
|
||||
servicer.GetAdminDashboard,
|
||||
request_deserializer=analytics__pb2.GetAdminDashboardRequest.FromString,
|
||||
response_serializer=analytics__pb2.AdminDashboard.SerializeToString,
|
||||
),
|
||||
'GetWarnings': grpc.unary_unary_rpc_method_handler(
|
||||
servicer.GetWarnings,
|
||||
request_deserializer=analytics__pb2.GetWarningsRequest.FromString,
|
||||
response_serializer=analytics__pb2.WarningList.SerializeToString,
|
||||
),
|
||||
'TriggerWarning': grpc.unary_unary_rpc_method_handler(
|
||||
servicer.TriggerWarning,
|
||||
request_deserializer=analytics__pb2.TriggerWarningRequest.FromString,
|
||||
response_serializer=analytics__pb2.TriggerWarningResponse.SerializeToString,
|
||||
),
|
||||
'GetMasteryDistribution': grpc.unary_unary_rpc_method_handler(
|
||||
servicer.GetMasteryDistribution,
|
||||
request_deserializer=analytics__pb2.GetMasteryDistributionRequest.FromString,
|
||||
response_serializer=analytics__pb2.MasteryDistribution.SerializeToString,
|
||||
),
|
||||
'GetStudentMastery': grpc.unary_unary_rpc_method_handler(
|
||||
servicer.GetStudentMastery,
|
||||
request_deserializer=analytics__pb2.GetStudentMasteryRequest.FromString,
|
||||
response_serializer=analytics__pb2.StudentMastery.SerializeToString,
|
||||
),
|
||||
'SubscribeMasteryUpdate': grpc.unary_stream_rpc_method_handler(
|
||||
servicer.SubscribeMasteryUpdate,
|
||||
request_deserializer=analytics__pb2.SubscribeMasteryUpdateRequest.FromString,
|
||||
response_serializer=analytics__pb2.MasteryUpdateEvent.SerializeToString,
|
||||
),
|
||||
}
|
||||
generic_handler = grpc.method_handlers_generic_handler(
|
||||
'next_edu_cloud.analytics.v1.AnalyticsService', rpc_method_handlers)
|
||||
server.add_generic_rpc_handlers((generic_handler,))
|
||||
server.add_registered_method_handlers('next_edu_cloud.analytics.v1.AnalyticsService', rpc_method_handlers)
|
||||
|
||||
|
||||
# This class is part of an EXPERIMENTAL API.
|
||||
class AnalyticsService:
|
||||
"""AnalyticsService 数据分析服务契约(D6 智能洞察领域).
|
||||
P4 启用 gRPC server 端口 50055,HTTP 3006 保留作 Gateway 直连降级.
|
||||
所有 RPC 返回 ActionState 信封(success/data/error/details.degraded).
|
||||
"""
|
||||
|
||||
@staticmethod
|
||||
def GetClassPerformance(request,
|
||||
target,
|
||||
options=(),
|
||||
channel_credentials=None,
|
||||
call_credentials=None,
|
||||
insecure=False,
|
||||
compression=None,
|
||||
wait_for_ready=None,
|
||||
timeout=None,
|
||||
metadata=None):
|
||||
return grpc.experimental.unary_unary(
|
||||
request,
|
||||
target,
|
||||
'/next_edu_cloud.analytics.v1.AnalyticsService/GetClassPerformance',
|
||||
analytics__pb2.GetClassPerformanceRequest.SerializeToString,
|
||||
analytics__pb2.ClassPerformance.FromString,
|
||||
options,
|
||||
channel_credentials,
|
||||
insecure,
|
||||
call_credentials,
|
||||
compression,
|
||||
wait_for_ready,
|
||||
timeout,
|
||||
metadata,
|
||||
_registered_method=True)
|
||||
|
||||
@staticmethod
|
||||
def GetStudentWeakness(request,
|
||||
target,
|
||||
options=(),
|
||||
channel_credentials=None,
|
||||
call_credentials=None,
|
||||
insecure=False,
|
||||
compression=None,
|
||||
wait_for_ready=None,
|
||||
timeout=None,
|
||||
metadata=None):
|
||||
return grpc.experimental.unary_unary(
|
||||
request,
|
||||
target,
|
||||
'/next_edu_cloud.analytics.v1.AnalyticsService/GetStudentWeakness',
|
||||
analytics__pb2.GetStudentWeaknessRequest.SerializeToString,
|
||||
analytics__pb2.StudentWeakness.FromString,
|
||||
options,
|
||||
channel_credentials,
|
||||
insecure,
|
||||
call_credentials,
|
||||
compression,
|
||||
wait_for_ready,
|
||||
timeout,
|
||||
metadata,
|
||||
_registered_method=True)
|
||||
|
||||
@staticmethod
|
||||
def GetLearningTrend(request,
|
||||
target,
|
||||
options=(),
|
||||
channel_credentials=None,
|
||||
call_credentials=None,
|
||||
insecure=False,
|
||||
compression=None,
|
||||
wait_for_ready=None,
|
||||
timeout=None,
|
||||
metadata=None):
|
||||
return grpc.experimental.unary_unary(
|
||||
request,
|
||||
target,
|
||||
'/next_edu_cloud.analytics.v1.AnalyticsService/GetLearningTrend',
|
||||
analytics__pb2.GetLearningTrendRequest.SerializeToString,
|
||||
analytics__pb2.LearningTrend.FromString,
|
||||
options,
|
||||
channel_credentials,
|
||||
insecure,
|
||||
call_credentials,
|
||||
compression,
|
||||
wait_for_ready,
|
||||
timeout,
|
||||
metadata,
|
||||
_registered_method=True)
|
||||
|
||||
@staticmethod
|
||||
def GetTeacherDashboard(request,
|
||||
target,
|
||||
options=(),
|
||||
channel_credentials=None,
|
||||
call_credentials=None,
|
||||
insecure=False,
|
||||
compression=None,
|
||||
wait_for_ready=None,
|
||||
timeout=None,
|
||||
metadata=None):
|
||||
return grpc.experimental.unary_unary(
|
||||
request,
|
||||
target,
|
||||
'/next_edu_cloud.analytics.v1.AnalyticsService/GetTeacherDashboard',
|
||||
analytics__pb2.GetTeacherDashboardRequest.SerializeToString,
|
||||
analytics__pb2.TeacherDashboard.FromString,
|
||||
options,
|
||||
channel_credentials,
|
||||
insecure,
|
||||
call_credentials,
|
||||
compression,
|
||||
wait_for_ready,
|
||||
timeout,
|
||||
metadata,
|
||||
_registered_method=True)
|
||||
|
||||
@staticmethod
|
||||
def GetStudentDashboard(request,
|
||||
target,
|
||||
options=(),
|
||||
channel_credentials=None,
|
||||
call_credentials=None,
|
||||
insecure=False,
|
||||
compression=None,
|
||||
wait_for_ready=None,
|
||||
timeout=None,
|
||||
metadata=None):
|
||||
return grpc.experimental.unary_unary(
|
||||
request,
|
||||
target,
|
||||
'/next_edu_cloud.analytics.v1.AnalyticsService/GetStudentDashboard',
|
||||
analytics__pb2.GetStudentDashboardRequest.SerializeToString,
|
||||
analytics__pb2.StudentDashboard.FromString,
|
||||
options,
|
||||
channel_credentials,
|
||||
insecure,
|
||||
call_credentials,
|
||||
compression,
|
||||
wait_for_ready,
|
||||
timeout,
|
||||
metadata,
|
||||
_registered_method=True)
|
||||
|
||||
@staticmethod
|
||||
def GetParentDashboard(request,
|
||||
target,
|
||||
options=(),
|
||||
channel_credentials=None,
|
||||
call_credentials=None,
|
||||
insecure=False,
|
||||
compression=None,
|
||||
wait_for_ready=None,
|
||||
timeout=None,
|
||||
metadata=None):
|
||||
return grpc.experimental.unary_unary(
|
||||
request,
|
||||
target,
|
||||
'/next_edu_cloud.analytics.v1.AnalyticsService/GetParentDashboard',
|
||||
analytics__pb2.GetParentDashboardRequest.SerializeToString,
|
||||
analytics__pb2.ParentDashboard.FromString,
|
||||
options,
|
||||
channel_credentials,
|
||||
insecure,
|
||||
call_credentials,
|
||||
compression,
|
||||
wait_for_ready,
|
||||
timeout,
|
||||
metadata,
|
||||
_registered_method=True)
|
||||
|
||||
@staticmethod
|
||||
def GetAdminDashboard(request,
|
||||
target,
|
||||
options=(),
|
||||
channel_credentials=None,
|
||||
call_credentials=None,
|
||||
insecure=False,
|
||||
compression=None,
|
||||
wait_for_ready=None,
|
||||
timeout=None,
|
||||
metadata=None):
|
||||
return grpc.experimental.unary_unary(
|
||||
request,
|
||||
target,
|
||||
'/next_edu_cloud.analytics.v1.AnalyticsService/GetAdminDashboard',
|
||||
analytics__pb2.GetAdminDashboardRequest.SerializeToString,
|
||||
analytics__pb2.AdminDashboard.FromString,
|
||||
options,
|
||||
channel_credentials,
|
||||
insecure,
|
||||
call_credentials,
|
||||
compression,
|
||||
wait_for_ready,
|
||||
timeout,
|
||||
metadata,
|
||||
_registered_method=True)
|
||||
|
||||
@staticmethod
|
||||
def GetWarnings(request,
|
||||
target,
|
||||
options=(),
|
||||
channel_credentials=None,
|
||||
call_credentials=None,
|
||||
insecure=False,
|
||||
compression=None,
|
||||
wait_for_ready=None,
|
||||
timeout=None,
|
||||
metadata=None):
|
||||
return grpc.experimental.unary_unary(
|
||||
request,
|
||||
target,
|
||||
'/next_edu_cloud.analytics.v1.AnalyticsService/GetWarnings',
|
||||
analytics__pb2.GetWarningsRequest.SerializeToString,
|
||||
analytics__pb2.WarningList.FromString,
|
||||
options,
|
||||
channel_credentials,
|
||||
insecure,
|
||||
call_credentials,
|
||||
compression,
|
||||
wait_for_ready,
|
||||
timeout,
|
||||
metadata,
|
||||
_registered_method=True)
|
||||
|
||||
@staticmethod
|
||||
def TriggerWarning(request,
|
||||
target,
|
||||
options=(),
|
||||
channel_credentials=None,
|
||||
call_credentials=None,
|
||||
insecure=False,
|
||||
compression=None,
|
||||
wait_for_ready=None,
|
||||
timeout=None,
|
||||
metadata=None):
|
||||
return grpc.experimental.unary_unary(
|
||||
request,
|
||||
target,
|
||||
'/next_edu_cloud.analytics.v1.AnalyticsService/TriggerWarning',
|
||||
analytics__pb2.TriggerWarningRequest.SerializeToString,
|
||||
analytics__pb2.TriggerWarningResponse.FromString,
|
||||
options,
|
||||
channel_credentials,
|
||||
insecure,
|
||||
call_credentials,
|
||||
compression,
|
||||
wait_for_ready,
|
||||
timeout,
|
||||
metadata,
|
||||
_registered_method=True)
|
||||
|
||||
@staticmethod
|
||||
def GetMasteryDistribution(request,
|
||||
target,
|
||||
options=(),
|
||||
channel_credentials=None,
|
||||
call_credentials=None,
|
||||
insecure=False,
|
||||
compression=None,
|
||||
wait_for_ready=None,
|
||||
timeout=None,
|
||||
metadata=None):
|
||||
return grpc.experimental.unary_unary(
|
||||
request,
|
||||
target,
|
||||
'/next_edu_cloud.analytics.v1.AnalyticsService/GetMasteryDistribution',
|
||||
analytics__pb2.GetMasteryDistributionRequest.SerializeToString,
|
||||
analytics__pb2.MasteryDistribution.FromString,
|
||||
options,
|
||||
channel_credentials,
|
||||
insecure,
|
||||
call_credentials,
|
||||
compression,
|
||||
wait_for_ready,
|
||||
timeout,
|
||||
metadata,
|
||||
_registered_method=True)
|
||||
|
||||
@staticmethod
|
||||
def GetStudentMastery(request,
|
||||
target,
|
||||
options=(),
|
||||
channel_credentials=None,
|
||||
call_credentials=None,
|
||||
insecure=False,
|
||||
compression=None,
|
||||
wait_for_ready=None,
|
||||
timeout=None,
|
||||
metadata=None):
|
||||
return grpc.experimental.unary_unary(
|
||||
request,
|
||||
target,
|
||||
'/next_edu_cloud.analytics.v1.AnalyticsService/GetStudentMastery',
|
||||
analytics__pb2.GetStudentMasteryRequest.SerializeToString,
|
||||
analytics__pb2.StudentMastery.FromString,
|
||||
options,
|
||||
channel_credentials,
|
||||
insecure,
|
||||
call_credentials,
|
||||
compression,
|
||||
wait_for_ready,
|
||||
timeout,
|
||||
metadata,
|
||||
_registered_method=True)
|
||||
|
||||
@staticmethod
|
||||
def SubscribeMasteryUpdate(request,
|
||||
target,
|
||||
options=(),
|
||||
channel_credentials=None,
|
||||
call_credentials=None,
|
||||
insecure=False,
|
||||
compression=None,
|
||||
wait_for_ready=None,
|
||||
timeout=None,
|
||||
metadata=None):
|
||||
return grpc.experimental.unary_stream(
|
||||
request,
|
||||
target,
|
||||
'/next_edu_cloud.analytics.v1.AnalyticsService/SubscribeMasteryUpdate',
|
||||
analytics__pb2.SubscribeMasteryUpdateRequest.SerializeToString,
|
||||
analytics__pb2.MasteryUpdateEvent.FromString,
|
||||
options,
|
||||
channel_credentials,
|
||||
insecure,
|
||||
call_credentials,
|
||||
compression,
|
||||
wait_for_ready,
|
||||
timeout,
|
||||
metadata,
|
||||
_registered_method=True)
|
||||
113
services/ai/src/ai/proto_gen/content_pb2.py
Normal file
113
services/ai/src/ai/proto_gen/content_pb2.py
Normal file
File diff suppressed because one or more lines are too long
1087
services/ai/src/ai/proto_gen/content_pb2_grpc.py
Normal file
1087
services/ai/src/ai/proto_gen/content_pb2_grpc.py
Normal file
File diff suppressed because it is too large
Load Diff
96
services/ai/src/ai/proto_gen/iam_pb2.py
Normal file
96
services/ai/src/ai/proto_gen/iam_pb2.py
Normal file
File diff suppressed because one or more lines are too long
719
services/ai/src/ai/proto_gen/iam_pb2_grpc.py
Normal file
719
services/ai/src/ai/proto_gen/iam_pb2_grpc.py
Normal file
@@ -0,0 +1,719 @@
|
||||
# Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT!
|
||||
"""Client and server classes corresponding to protobuf-defined services."""
|
||||
import grpc
|
||||
import warnings
|
||||
|
||||
import iam_pb2 as iam__pb2
|
||||
|
||||
GRPC_GENERATED_VERSION = '1.82.1'
|
||||
GRPC_VERSION = grpc.__version__
|
||||
_version_not_supported = False
|
||||
|
||||
try:
|
||||
from grpc._utilities import first_version_is_lower
|
||||
_version_not_supported = first_version_is_lower(GRPC_VERSION, GRPC_GENERATED_VERSION)
|
||||
except ImportError:
|
||||
_version_not_supported = True
|
||||
|
||||
if _version_not_supported:
|
||||
raise RuntimeError(
|
||||
f'The grpc package installed is at version {GRPC_VERSION},'
|
||||
+ ' but the generated code in iam_pb2_grpc.py depends on'
|
||||
+ f' grpcio>={GRPC_GENERATED_VERSION}.'
|
||||
+ f' Please upgrade your grpc module to grpcio>={GRPC_GENERATED_VERSION}'
|
||||
+ f' or downgrade your generated code using grpcio-tools<={GRPC_VERSION}.'
|
||||
)
|
||||
|
||||
|
||||
class IamServiceStub:
|
||||
"""IamService 定义身份与访问管理契约
|
||||
双入口策略(president §2.16):REST 供 gateway 透传 + admin-portal 直连,
|
||||
gRPC 供 BFF 聚合调用。同一 Application Service 同时被两种 Controller 调用。
|
||||
gRPC 端口 50052,P2 即启用(I1 裁决)。
|
||||
"""
|
||||
|
||||
def __init__(self, channel):
|
||||
"""Constructor.
|
||||
|
||||
Args:
|
||||
channel: A grpc.Channel.
|
||||
"""
|
||||
self.Register = channel.unary_unary(
|
||||
'/next_edu_cloud.iam.v1.IamService/Register',
|
||||
request_serializer=iam__pb2.RegisterRequest.SerializeToString,
|
||||
response_deserializer=iam__pb2.AuthResponse.FromString,
|
||||
_registered_method=True)
|
||||
self.Login = channel.unary_unary(
|
||||
'/next_edu_cloud.iam.v1.IamService/Login',
|
||||
request_serializer=iam__pb2.LoginRequest.SerializeToString,
|
||||
response_deserializer=iam__pb2.AuthResponse.FromString,
|
||||
_registered_method=True)
|
||||
self.RefreshToken = channel.unary_unary(
|
||||
'/next_edu_cloud.iam.v1.IamService/RefreshToken',
|
||||
request_serializer=iam__pb2.RefreshTokenRequest.SerializeToString,
|
||||
response_deserializer=iam__pb2.TokenPair.FromString,
|
||||
_registered_method=True)
|
||||
self.Logout = channel.unary_unary(
|
||||
'/next_edu_cloud.iam.v1.IamService/Logout',
|
||||
request_serializer=iam__pb2.LogoutRequest.SerializeToString,
|
||||
response_deserializer=iam__pb2.LogoutResponse.FromString,
|
||||
_registered_method=True)
|
||||
self.GetUserInfo = channel.unary_unary(
|
||||
'/next_edu_cloud.iam.v1.IamService/GetUserInfo',
|
||||
request_serializer=iam__pb2.GetUserInfoRequest.SerializeToString,
|
||||
response_deserializer=iam__pb2.UserInfo.FromString,
|
||||
_registered_method=True)
|
||||
self.GetUserProfile = channel.unary_unary(
|
||||
'/next_edu_cloud.iam.v1.IamService/GetUserProfile',
|
||||
request_serializer=iam__pb2.GetUserProfileRequest.SerializeToString,
|
||||
response_deserializer=iam__pb2.UserInfo.FromString,
|
||||
_registered_method=True)
|
||||
self.UpdateProfile = channel.unary_unary(
|
||||
'/next_edu_cloud.iam.v1.IamService/UpdateProfile',
|
||||
request_serializer=iam__pb2.UpdateProfileRequest.SerializeToString,
|
||||
response_deserializer=iam__pb2.UserInfo.FromString,
|
||||
_registered_method=True)
|
||||
self.ChangePassword = channel.unary_unary(
|
||||
'/next_edu_cloud.iam.v1.IamService/ChangePassword',
|
||||
request_serializer=iam__pb2.ChangePasswordRequest.SerializeToString,
|
||||
response_deserializer=iam__pb2.ChangePasswordResponse.FromString,
|
||||
_registered_method=True)
|
||||
self.BatchGetUsers = channel.unary_unary(
|
||||
'/next_edu_cloud.iam.v1.IamService/BatchGetUsers',
|
||||
request_serializer=iam__pb2.BatchGetUsersRequest.SerializeToString,
|
||||
response_deserializer=iam__pb2.BatchGetUsersResponse.FromString,
|
||||
_registered_method=True)
|
||||
self.GetEffectivePermissions = channel.unary_unary(
|
||||
'/next_edu_cloud.iam.v1.IamService/GetEffectivePermissions',
|
||||
request_serializer=iam__pb2.GetEffectivePermissionsRequest.SerializeToString,
|
||||
response_deserializer=iam__pb2.EffectivePermissionsResponse.FromString,
|
||||
_registered_method=True)
|
||||
self.GetEffectiveAccess = channel.unary_unary(
|
||||
'/next_edu_cloud.iam.v1.IamService/GetEffectiveAccess',
|
||||
request_serializer=iam__pb2.GetEffectiveAccessRequest.SerializeToString,
|
||||
response_deserializer=iam__pb2.EffectiveAccessResponse.FromString,
|
||||
_registered_method=True)
|
||||
self.GetEffectiveDataScope = channel.unary_unary(
|
||||
'/next_edu_cloud.iam.v1.IamService/GetEffectiveDataScope',
|
||||
request_serializer=iam__pb2.GetEffectiveDataScopeRequest.SerializeToString,
|
||||
response_deserializer=iam__pb2.EffectiveDataScope.FromString,
|
||||
_registered_method=True)
|
||||
self.GetViewports = channel.unary_unary(
|
||||
'/next_edu_cloud.iam.v1.IamService/GetViewports',
|
||||
request_serializer=iam__pb2.GetViewportsRequest.SerializeToString,
|
||||
response_deserializer=iam__pb2.ViewportsResponse.FromString,
|
||||
_registered_method=True)
|
||||
self.GetPublicKey = channel.unary_unary(
|
||||
'/next_edu_cloud.iam.v1.IamService/GetPublicKey',
|
||||
request_serializer=iam__pb2.GetPublicKeyRequest.SerializeToString,
|
||||
response_deserializer=iam__pb2.PublicKeyResponse.FromString,
|
||||
_registered_method=True)
|
||||
self.GetChildrenByParent = channel.unary_unary(
|
||||
'/next_edu_cloud.iam.v1.IamService/GetChildrenByParent',
|
||||
request_serializer=iam__pb2.GetChildrenByParentRequest.SerializeToString,
|
||||
response_deserializer=iam__pb2.ChildrenResponse.FromString,
|
||||
_registered_method=True)
|
||||
|
||||
|
||||
class IamServiceServicer:
|
||||
"""IamService 定义身份与访问管理契约
|
||||
双入口策略(president §2.16):REST 供 gateway 透传 + admin-portal 直连,
|
||||
gRPC 供 BFF 聚合调用。同一 Application Service 同时被两种 Controller 调用。
|
||||
gRPC 端口 50052,P2 即启用(I1 裁决)。
|
||||
"""
|
||||
|
||||
def Register(self, request, context):
|
||||
"""认证类
|
||||
"""
|
||||
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
|
||||
context.set_details('Method not implemented!')
|
||||
raise NotImplementedError('Method not implemented!')
|
||||
|
||||
def Login(self, request, context):
|
||||
"""Missing associated documentation comment in .proto file."""
|
||||
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
|
||||
context.set_details('Method not implemented!')
|
||||
raise NotImplementedError('Method not implemented!')
|
||||
|
||||
def RefreshToken(self, request, context):
|
||||
"""Missing associated documentation comment in .proto file."""
|
||||
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
|
||||
context.set_details('Method not implemented!')
|
||||
raise NotImplementedError('Method not implemented!')
|
||||
|
||||
def Logout(self, request, context):
|
||||
"""Missing associated documentation comment in .proto file."""
|
||||
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
|
||||
context.set_details('Method not implemented!')
|
||||
raise NotImplementedError('Method not implemented!')
|
||||
|
||||
def GetUserInfo(self, request, context):
|
||||
"""用户信息类
|
||||
"""
|
||||
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
|
||||
context.set_details('Method not implemented!')
|
||||
raise NotImplementedError('Method not implemented!')
|
||||
|
||||
def GetUserProfile(self, request, context):
|
||||
"""GetUserProfile 是 GetUserInfo 的语义别名(student-bff 期望的命名).
|
||||
返回结构与 GetUserInfo 完全相同,仅 RPC 名不同以兼容下游契约.
|
||||
"""
|
||||
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
|
||||
context.set_details('Method not implemented!')
|
||||
raise NotImplementedError('Method not implemented!')
|
||||
|
||||
def UpdateProfile(self, request, context):
|
||||
"""Missing associated documentation comment in .proto file."""
|
||||
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
|
||||
context.set_details('Method not implemented!')
|
||||
raise NotImplementedError('Method not implemented!')
|
||||
|
||||
def ChangePassword(self, request, context):
|
||||
"""Missing associated documentation comment in .proto file."""
|
||||
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
|
||||
context.set_details('Method not implemented!')
|
||||
raise NotImplementedError('Method not implemented!')
|
||||
|
||||
def BatchGetUsers(self, request, context):
|
||||
"""Missing associated documentation comment in .proto file."""
|
||||
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
|
||||
context.set_details('Method not implemented!')
|
||||
raise NotImplementedError('Method not implemented!')
|
||||
|
||||
def GetEffectivePermissions(self, request, context):
|
||||
"""权限与视口类
|
||||
"""
|
||||
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
|
||||
context.set_details('Method not implemented!')
|
||||
raise NotImplementedError('Method not implemented!')
|
||||
|
||||
def GetEffectiveAccess(self, request, context):
|
||||
"""Missing associated documentation comment in .proto file."""
|
||||
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
|
||||
context.set_details('Method not implemented!')
|
||||
raise NotImplementedError('Method not implemented!')
|
||||
|
||||
def GetEffectiveDataScope(self, request, context):
|
||||
"""GetEffectiveDataScope 解析用户可见数据范围(DataScope 6 级).
|
||||
data-ana gRPC 调用此 RPC 解析查询过滤范围(coord-cross-review §2 #3 裁决 P4 补全).
|
||||
"""
|
||||
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
|
||||
context.set_details('Method not implemented!')
|
||||
raise NotImplementedError('Method not implemented!')
|
||||
|
||||
def GetViewports(self, request, context):
|
||||
"""Missing associated documentation comment in .proto file."""
|
||||
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
|
||||
context.set_details('Method not implemented!')
|
||||
raise NotImplementedError('Method not implemented!')
|
||||
|
||||
def GetPublicKey(self, request, context):
|
||||
"""密钥与关系类
|
||||
"""
|
||||
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
|
||||
context.set_details('Method not implemented!')
|
||||
raise NotImplementedError('Method not implemented!')
|
||||
|
||||
def GetChildrenByParent(self, request, context):
|
||||
"""Missing associated documentation comment in .proto file."""
|
||||
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
|
||||
context.set_details('Method not implemented!')
|
||||
raise NotImplementedError('Method not implemented!')
|
||||
|
||||
|
||||
def add_IamServiceServicer_to_server(servicer, server):
|
||||
rpc_method_handlers = {
|
||||
'Register': grpc.unary_unary_rpc_method_handler(
|
||||
servicer.Register,
|
||||
request_deserializer=iam__pb2.RegisterRequest.FromString,
|
||||
response_serializer=iam__pb2.AuthResponse.SerializeToString,
|
||||
),
|
||||
'Login': grpc.unary_unary_rpc_method_handler(
|
||||
servicer.Login,
|
||||
request_deserializer=iam__pb2.LoginRequest.FromString,
|
||||
response_serializer=iam__pb2.AuthResponse.SerializeToString,
|
||||
),
|
||||
'RefreshToken': grpc.unary_unary_rpc_method_handler(
|
||||
servicer.RefreshToken,
|
||||
request_deserializer=iam__pb2.RefreshTokenRequest.FromString,
|
||||
response_serializer=iam__pb2.TokenPair.SerializeToString,
|
||||
),
|
||||
'Logout': grpc.unary_unary_rpc_method_handler(
|
||||
servicer.Logout,
|
||||
request_deserializer=iam__pb2.LogoutRequest.FromString,
|
||||
response_serializer=iam__pb2.LogoutResponse.SerializeToString,
|
||||
),
|
||||
'GetUserInfo': grpc.unary_unary_rpc_method_handler(
|
||||
servicer.GetUserInfo,
|
||||
request_deserializer=iam__pb2.GetUserInfoRequest.FromString,
|
||||
response_serializer=iam__pb2.UserInfo.SerializeToString,
|
||||
),
|
||||
'GetUserProfile': grpc.unary_unary_rpc_method_handler(
|
||||
servicer.GetUserProfile,
|
||||
request_deserializer=iam__pb2.GetUserProfileRequest.FromString,
|
||||
response_serializer=iam__pb2.UserInfo.SerializeToString,
|
||||
),
|
||||
'UpdateProfile': grpc.unary_unary_rpc_method_handler(
|
||||
servicer.UpdateProfile,
|
||||
request_deserializer=iam__pb2.UpdateProfileRequest.FromString,
|
||||
response_serializer=iam__pb2.UserInfo.SerializeToString,
|
||||
),
|
||||
'ChangePassword': grpc.unary_unary_rpc_method_handler(
|
||||
servicer.ChangePassword,
|
||||
request_deserializer=iam__pb2.ChangePasswordRequest.FromString,
|
||||
response_serializer=iam__pb2.ChangePasswordResponse.SerializeToString,
|
||||
),
|
||||
'BatchGetUsers': grpc.unary_unary_rpc_method_handler(
|
||||
servicer.BatchGetUsers,
|
||||
request_deserializer=iam__pb2.BatchGetUsersRequest.FromString,
|
||||
response_serializer=iam__pb2.BatchGetUsersResponse.SerializeToString,
|
||||
),
|
||||
'GetEffectivePermissions': grpc.unary_unary_rpc_method_handler(
|
||||
servicer.GetEffectivePermissions,
|
||||
request_deserializer=iam__pb2.GetEffectivePermissionsRequest.FromString,
|
||||
response_serializer=iam__pb2.EffectivePermissionsResponse.SerializeToString,
|
||||
),
|
||||
'GetEffectiveAccess': grpc.unary_unary_rpc_method_handler(
|
||||
servicer.GetEffectiveAccess,
|
||||
request_deserializer=iam__pb2.GetEffectiveAccessRequest.FromString,
|
||||
response_serializer=iam__pb2.EffectiveAccessResponse.SerializeToString,
|
||||
),
|
||||
'GetEffectiveDataScope': grpc.unary_unary_rpc_method_handler(
|
||||
servicer.GetEffectiveDataScope,
|
||||
request_deserializer=iam__pb2.GetEffectiveDataScopeRequest.FromString,
|
||||
response_serializer=iam__pb2.EffectiveDataScope.SerializeToString,
|
||||
),
|
||||
'GetViewports': grpc.unary_unary_rpc_method_handler(
|
||||
servicer.GetViewports,
|
||||
request_deserializer=iam__pb2.GetViewportsRequest.FromString,
|
||||
response_serializer=iam__pb2.ViewportsResponse.SerializeToString,
|
||||
),
|
||||
'GetPublicKey': grpc.unary_unary_rpc_method_handler(
|
||||
servicer.GetPublicKey,
|
||||
request_deserializer=iam__pb2.GetPublicKeyRequest.FromString,
|
||||
response_serializer=iam__pb2.PublicKeyResponse.SerializeToString,
|
||||
),
|
||||
'GetChildrenByParent': grpc.unary_unary_rpc_method_handler(
|
||||
servicer.GetChildrenByParent,
|
||||
request_deserializer=iam__pb2.GetChildrenByParentRequest.FromString,
|
||||
response_serializer=iam__pb2.ChildrenResponse.SerializeToString,
|
||||
),
|
||||
}
|
||||
generic_handler = grpc.method_handlers_generic_handler(
|
||||
'next_edu_cloud.iam.v1.IamService', rpc_method_handlers)
|
||||
server.add_generic_rpc_handlers((generic_handler,))
|
||||
server.add_registered_method_handlers('next_edu_cloud.iam.v1.IamService', rpc_method_handlers)
|
||||
|
||||
|
||||
# This class is part of an EXPERIMENTAL API.
|
||||
class IamService:
|
||||
"""IamService 定义身份与访问管理契约
|
||||
双入口策略(president §2.16):REST 供 gateway 透传 + admin-portal 直连,
|
||||
gRPC 供 BFF 聚合调用。同一 Application Service 同时被两种 Controller 调用。
|
||||
gRPC 端口 50052,P2 即启用(I1 裁决)。
|
||||
"""
|
||||
|
||||
@staticmethod
|
||||
def Register(request,
|
||||
target,
|
||||
options=(),
|
||||
channel_credentials=None,
|
||||
call_credentials=None,
|
||||
insecure=False,
|
||||
compression=None,
|
||||
wait_for_ready=None,
|
||||
timeout=None,
|
||||
metadata=None):
|
||||
return grpc.experimental.unary_unary(
|
||||
request,
|
||||
target,
|
||||
'/next_edu_cloud.iam.v1.IamService/Register',
|
||||
iam__pb2.RegisterRequest.SerializeToString,
|
||||
iam__pb2.AuthResponse.FromString,
|
||||
options,
|
||||
channel_credentials,
|
||||
insecure,
|
||||
call_credentials,
|
||||
compression,
|
||||
wait_for_ready,
|
||||
timeout,
|
||||
metadata,
|
||||
_registered_method=True)
|
||||
|
||||
@staticmethod
|
||||
def Login(request,
|
||||
target,
|
||||
options=(),
|
||||
channel_credentials=None,
|
||||
call_credentials=None,
|
||||
insecure=False,
|
||||
compression=None,
|
||||
wait_for_ready=None,
|
||||
timeout=None,
|
||||
metadata=None):
|
||||
return grpc.experimental.unary_unary(
|
||||
request,
|
||||
target,
|
||||
'/next_edu_cloud.iam.v1.IamService/Login',
|
||||
iam__pb2.LoginRequest.SerializeToString,
|
||||
iam__pb2.AuthResponse.FromString,
|
||||
options,
|
||||
channel_credentials,
|
||||
insecure,
|
||||
call_credentials,
|
||||
compression,
|
||||
wait_for_ready,
|
||||
timeout,
|
||||
metadata,
|
||||
_registered_method=True)
|
||||
|
||||
@staticmethod
|
||||
def RefreshToken(request,
|
||||
target,
|
||||
options=(),
|
||||
channel_credentials=None,
|
||||
call_credentials=None,
|
||||
insecure=False,
|
||||
compression=None,
|
||||
wait_for_ready=None,
|
||||
timeout=None,
|
||||
metadata=None):
|
||||
return grpc.experimental.unary_unary(
|
||||
request,
|
||||
target,
|
||||
'/next_edu_cloud.iam.v1.IamService/RefreshToken',
|
||||
iam__pb2.RefreshTokenRequest.SerializeToString,
|
||||
iam__pb2.TokenPair.FromString,
|
||||
options,
|
||||
channel_credentials,
|
||||
insecure,
|
||||
call_credentials,
|
||||
compression,
|
||||
wait_for_ready,
|
||||
timeout,
|
||||
metadata,
|
||||
_registered_method=True)
|
||||
|
||||
@staticmethod
|
||||
def Logout(request,
|
||||
target,
|
||||
options=(),
|
||||
channel_credentials=None,
|
||||
call_credentials=None,
|
||||
insecure=False,
|
||||
compression=None,
|
||||
wait_for_ready=None,
|
||||
timeout=None,
|
||||
metadata=None):
|
||||
return grpc.experimental.unary_unary(
|
||||
request,
|
||||
target,
|
||||
'/next_edu_cloud.iam.v1.IamService/Logout',
|
||||
iam__pb2.LogoutRequest.SerializeToString,
|
||||
iam__pb2.LogoutResponse.FromString,
|
||||
options,
|
||||
channel_credentials,
|
||||
insecure,
|
||||
call_credentials,
|
||||
compression,
|
||||
wait_for_ready,
|
||||
timeout,
|
||||
metadata,
|
||||
_registered_method=True)
|
||||
|
||||
@staticmethod
|
||||
def GetUserInfo(request,
|
||||
target,
|
||||
options=(),
|
||||
channel_credentials=None,
|
||||
call_credentials=None,
|
||||
insecure=False,
|
||||
compression=None,
|
||||
wait_for_ready=None,
|
||||
timeout=None,
|
||||
metadata=None):
|
||||
return grpc.experimental.unary_unary(
|
||||
request,
|
||||
target,
|
||||
'/next_edu_cloud.iam.v1.IamService/GetUserInfo',
|
||||
iam__pb2.GetUserInfoRequest.SerializeToString,
|
||||
iam__pb2.UserInfo.FromString,
|
||||
options,
|
||||
channel_credentials,
|
||||
insecure,
|
||||
call_credentials,
|
||||
compression,
|
||||
wait_for_ready,
|
||||
timeout,
|
||||
metadata,
|
||||
_registered_method=True)
|
||||
|
||||
@staticmethod
|
||||
def GetUserProfile(request,
|
||||
target,
|
||||
options=(),
|
||||
channel_credentials=None,
|
||||
call_credentials=None,
|
||||
insecure=False,
|
||||
compression=None,
|
||||
wait_for_ready=None,
|
||||
timeout=None,
|
||||
metadata=None):
|
||||
return grpc.experimental.unary_unary(
|
||||
request,
|
||||
target,
|
||||
'/next_edu_cloud.iam.v1.IamService/GetUserProfile',
|
||||
iam__pb2.GetUserProfileRequest.SerializeToString,
|
||||
iam__pb2.UserInfo.FromString,
|
||||
options,
|
||||
channel_credentials,
|
||||
insecure,
|
||||
call_credentials,
|
||||
compression,
|
||||
wait_for_ready,
|
||||
timeout,
|
||||
metadata,
|
||||
_registered_method=True)
|
||||
|
||||
@staticmethod
|
||||
def UpdateProfile(request,
|
||||
target,
|
||||
options=(),
|
||||
channel_credentials=None,
|
||||
call_credentials=None,
|
||||
insecure=False,
|
||||
compression=None,
|
||||
wait_for_ready=None,
|
||||
timeout=None,
|
||||
metadata=None):
|
||||
return grpc.experimental.unary_unary(
|
||||
request,
|
||||
target,
|
||||
'/next_edu_cloud.iam.v1.IamService/UpdateProfile',
|
||||
iam__pb2.UpdateProfileRequest.SerializeToString,
|
||||
iam__pb2.UserInfo.FromString,
|
||||
options,
|
||||
channel_credentials,
|
||||
insecure,
|
||||
call_credentials,
|
||||
compression,
|
||||
wait_for_ready,
|
||||
timeout,
|
||||
metadata,
|
||||
_registered_method=True)
|
||||
|
||||
@staticmethod
|
||||
def ChangePassword(request,
|
||||
target,
|
||||
options=(),
|
||||
channel_credentials=None,
|
||||
call_credentials=None,
|
||||
insecure=False,
|
||||
compression=None,
|
||||
wait_for_ready=None,
|
||||
timeout=None,
|
||||
metadata=None):
|
||||
return grpc.experimental.unary_unary(
|
||||
request,
|
||||
target,
|
||||
'/next_edu_cloud.iam.v1.IamService/ChangePassword',
|
||||
iam__pb2.ChangePasswordRequest.SerializeToString,
|
||||
iam__pb2.ChangePasswordResponse.FromString,
|
||||
options,
|
||||
channel_credentials,
|
||||
insecure,
|
||||
call_credentials,
|
||||
compression,
|
||||
wait_for_ready,
|
||||
timeout,
|
||||
metadata,
|
||||
_registered_method=True)
|
||||
|
||||
@staticmethod
|
||||
def BatchGetUsers(request,
|
||||
target,
|
||||
options=(),
|
||||
channel_credentials=None,
|
||||
call_credentials=None,
|
||||
insecure=False,
|
||||
compression=None,
|
||||
wait_for_ready=None,
|
||||
timeout=None,
|
||||
metadata=None):
|
||||
return grpc.experimental.unary_unary(
|
||||
request,
|
||||
target,
|
||||
'/next_edu_cloud.iam.v1.IamService/BatchGetUsers',
|
||||
iam__pb2.BatchGetUsersRequest.SerializeToString,
|
||||
iam__pb2.BatchGetUsersResponse.FromString,
|
||||
options,
|
||||
channel_credentials,
|
||||
insecure,
|
||||
call_credentials,
|
||||
compression,
|
||||
wait_for_ready,
|
||||
timeout,
|
||||
metadata,
|
||||
_registered_method=True)
|
||||
|
||||
@staticmethod
|
||||
def GetEffectivePermissions(request,
|
||||
target,
|
||||
options=(),
|
||||
channel_credentials=None,
|
||||
call_credentials=None,
|
||||
insecure=False,
|
||||
compression=None,
|
||||
wait_for_ready=None,
|
||||
timeout=None,
|
||||
metadata=None):
|
||||
return grpc.experimental.unary_unary(
|
||||
request,
|
||||
target,
|
||||
'/next_edu_cloud.iam.v1.IamService/GetEffectivePermissions',
|
||||
iam__pb2.GetEffectivePermissionsRequest.SerializeToString,
|
||||
iam__pb2.EffectivePermissionsResponse.FromString,
|
||||
options,
|
||||
channel_credentials,
|
||||
insecure,
|
||||
call_credentials,
|
||||
compression,
|
||||
wait_for_ready,
|
||||
timeout,
|
||||
metadata,
|
||||
_registered_method=True)
|
||||
|
||||
@staticmethod
|
||||
def GetEffectiveAccess(request,
|
||||
target,
|
||||
options=(),
|
||||
channel_credentials=None,
|
||||
call_credentials=None,
|
||||
insecure=False,
|
||||
compression=None,
|
||||
wait_for_ready=None,
|
||||
timeout=None,
|
||||
metadata=None):
|
||||
return grpc.experimental.unary_unary(
|
||||
request,
|
||||
target,
|
||||
'/next_edu_cloud.iam.v1.IamService/GetEffectiveAccess',
|
||||
iam__pb2.GetEffectiveAccessRequest.SerializeToString,
|
||||
iam__pb2.EffectiveAccessResponse.FromString,
|
||||
options,
|
||||
channel_credentials,
|
||||
insecure,
|
||||
call_credentials,
|
||||
compression,
|
||||
wait_for_ready,
|
||||
timeout,
|
||||
metadata,
|
||||
_registered_method=True)
|
||||
|
||||
@staticmethod
|
||||
def GetEffectiveDataScope(request,
|
||||
target,
|
||||
options=(),
|
||||
channel_credentials=None,
|
||||
call_credentials=None,
|
||||
insecure=False,
|
||||
compression=None,
|
||||
wait_for_ready=None,
|
||||
timeout=None,
|
||||
metadata=None):
|
||||
return grpc.experimental.unary_unary(
|
||||
request,
|
||||
target,
|
||||
'/next_edu_cloud.iam.v1.IamService/GetEffectiveDataScope',
|
||||
iam__pb2.GetEffectiveDataScopeRequest.SerializeToString,
|
||||
iam__pb2.EffectiveDataScope.FromString,
|
||||
options,
|
||||
channel_credentials,
|
||||
insecure,
|
||||
call_credentials,
|
||||
compression,
|
||||
wait_for_ready,
|
||||
timeout,
|
||||
metadata,
|
||||
_registered_method=True)
|
||||
|
||||
@staticmethod
|
||||
def GetViewports(request,
|
||||
target,
|
||||
options=(),
|
||||
channel_credentials=None,
|
||||
call_credentials=None,
|
||||
insecure=False,
|
||||
compression=None,
|
||||
wait_for_ready=None,
|
||||
timeout=None,
|
||||
metadata=None):
|
||||
return grpc.experimental.unary_unary(
|
||||
request,
|
||||
target,
|
||||
'/next_edu_cloud.iam.v1.IamService/GetViewports',
|
||||
iam__pb2.GetViewportsRequest.SerializeToString,
|
||||
iam__pb2.ViewportsResponse.FromString,
|
||||
options,
|
||||
channel_credentials,
|
||||
insecure,
|
||||
call_credentials,
|
||||
compression,
|
||||
wait_for_ready,
|
||||
timeout,
|
||||
metadata,
|
||||
_registered_method=True)
|
||||
|
||||
@staticmethod
|
||||
def GetPublicKey(request,
|
||||
target,
|
||||
options=(),
|
||||
channel_credentials=None,
|
||||
call_credentials=None,
|
||||
insecure=False,
|
||||
compression=None,
|
||||
wait_for_ready=None,
|
||||
timeout=None,
|
||||
metadata=None):
|
||||
return grpc.experimental.unary_unary(
|
||||
request,
|
||||
target,
|
||||
'/next_edu_cloud.iam.v1.IamService/GetPublicKey',
|
||||
iam__pb2.GetPublicKeyRequest.SerializeToString,
|
||||
iam__pb2.PublicKeyResponse.FromString,
|
||||
options,
|
||||
channel_credentials,
|
||||
insecure,
|
||||
call_credentials,
|
||||
compression,
|
||||
wait_for_ready,
|
||||
timeout,
|
||||
metadata,
|
||||
_registered_method=True)
|
||||
|
||||
@staticmethod
|
||||
def GetChildrenByParent(request,
|
||||
target,
|
||||
options=(),
|
||||
channel_credentials=None,
|
||||
call_credentials=None,
|
||||
insecure=False,
|
||||
compression=None,
|
||||
wait_for_ready=None,
|
||||
timeout=None,
|
||||
metadata=None):
|
||||
return grpc.experimental.unary_unary(
|
||||
request,
|
||||
target,
|
||||
'/next_edu_cloud.iam.v1.IamService/GetChildrenByParent',
|
||||
iam__pb2.GetChildrenByParentRequest.SerializeToString,
|
||||
iam__pb2.ChildrenResponse.FromString,
|
||||
options,
|
||||
channel_credentials,
|
||||
insecure,
|
||||
call_credentials,
|
||||
compression,
|
||||
wait_for_ready,
|
||||
timeout,
|
||||
metadata,
|
||||
_registered_method=True)
|
||||
Reference in New Issue
Block a user