forked from zhouruizhe/gmTouringMiniApp
Initial commit: gmTouringMiniApp project
This commit is contained in:
@@ -0,0 +1,91 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import uuid
|
||||
|
||||
from .llm import LLMError, LLMService
|
||||
from .schemas import (
|
||||
ModelRecommendationSet,
|
||||
PlanRecommendationRequest,
|
||||
PlanningMode,
|
||||
RecommendationItem,
|
||||
RecommendationResponse,
|
||||
)
|
||||
|
||||
|
||||
class RecommendationService:
|
||||
def __init__(self, llm: LLMService) -> None:
|
||||
self.llm = llm
|
||||
|
||||
async def create(
|
||||
self, request: PlanRecommendationRequest
|
||||
) -> RecommendationResponse:
|
||||
generated = await self.llm.recommend(request)
|
||||
recommendations = self._canonicalize(request, generated)
|
||||
message = (
|
||||
"已保留全部自选点位并给出建议顺序;最终路线与时长由客户端核算。"
|
||||
if request.mode == PlanningMode.CUSTOM
|
||||
else "已从当前 POI 白名单给出推荐;最终路线与时长由客户端核算。"
|
||||
)
|
||||
return RecommendationResponse(
|
||||
request_id=str(uuid.uuid4()),
|
||||
mode=request.mode,
|
||||
assistant_message=message,
|
||||
recommendations=recommendations,
|
||||
generation_mode=self.llm.mode,
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def _canonicalize(
|
||||
request: PlanRecommendationRequest,
|
||||
generated: ModelRecommendationSet,
|
||||
) -> list[RecommendationItem]:
|
||||
allowed_ids = {candidate.id for candidate in request.candidates}
|
||||
generated_by_id = {}
|
||||
for item in generated.recommendations:
|
||||
if item.poi_id not in allowed_ids:
|
||||
raise LLMError("模型返回了 POI 白名单外的 ID")
|
||||
if item.poi_id in generated_by_id:
|
||||
raise LLMError("模型返回了重复 POI ID")
|
||||
generated_by_id[item.poi_id] = item
|
||||
|
||||
if request.mode == PlanningMode.CUSTOM:
|
||||
selected_ids = set(request.selected_poi_ids)
|
||||
ordered_ids = [
|
||||
item.poi_id
|
||||
for item in sorted(
|
||||
generated.recommendations,
|
||||
key=lambda item: item.order or 9,
|
||||
)
|
||||
if item.poi_id in selected_ids
|
||||
]
|
||||
# Selection belongs to the user, not the model. Keep all selected IDs
|
||||
# even if a real model omits one, and discard unselected suggestions.
|
||||
ordered_ids.extend(
|
||||
poi_id
|
||||
for poi_id in request.selected_poi_ids
|
||||
if poi_id not in ordered_ids
|
||||
)
|
||||
else:
|
||||
ordered_ids = [
|
||||
item.poi_id
|
||||
for item in sorted(
|
||||
generated.recommendations,
|
||||
key=lambda item: item.order or 9,
|
||||
)
|
||||
][:8]
|
||||
|
||||
if not ordered_ids:
|
||||
raise LLMError("模型未返回可用的 POI 推荐")
|
||||
return [
|
||||
RecommendationItem(
|
||||
poi_id=poi_id,
|
||||
reason=(
|
||||
generated_by_id[poi_id].reason
|
||||
if poi_id in generated_by_id
|
||||
else "这是你选择的点位,已由系统保留。"
|
||||
),
|
||||
order=index,
|
||||
)
|
||||
for index, poi_id in enumerate(ordered_ids, start=1)
|
||||
]
|
||||
|
||||
Reference in New Issue
Block a user