175 lines
5.8 KiB
Python
175 lines
5.8 KiB
Python
"""NPC chat routes backed by Azure AI service."""
|
|
import uuid
|
|
from typing import Any, Dict
|
|
|
|
from flask import Blueprint, request, session
|
|
from flask_restx import Api, Resource, fields
|
|
|
|
from models.user import User
|
|
from models.quest import Quest, db
|
|
from services.npc_chat_service import NpcChatService
|
|
|
|
npc_chat_bp = Blueprint('npc_chat', __name__, url_prefix='/api')
|
|
npc_chat_api = Api(npc_chat_bp, doc=False, prefix='/chat')
|
|
|
|
chat_start_model = npc_chat_api.model('ChatStartRequest', {
|
|
'character': fields.String(required=False, description='frodo|sam|gandalf'),
|
|
})
|
|
|
|
chat_message_model = npc_chat_api.model('ChatMessageRequest', {
|
|
'character': fields.String(required=False, description='frodo|sam|gandalf'),
|
|
'message': fields.String(required=True, description='User message'),
|
|
})
|
|
|
|
quest_creation_model = npc_chat_api.model('QuestCreationRequest', {
|
|
'character': fields.String(required=False, description='frodo|sam|gandalf - NPC who proposes the quest'),
|
|
'title': fields.String(required=True, description='Quest title'),
|
|
'description': fields.String(required=True, description='Quest description'),
|
|
'quest_type': fields.String(required=True, description='Quest type (The Journey, The Battle, The Fellowship, The Ring, Dark Magic)'),
|
|
'priority': fields.String(required=True, description='Quest priority (Critical, Important, Standard)'),
|
|
})
|
|
|
|
|
|
def _require_auth() -> bool:
|
|
return session.get('user_id') is not None
|
|
|
|
|
|
def _get_current_user() -> User:
|
|
user_id = session.get('user_id')
|
|
return User.query.get(user_id)
|
|
|
|
|
|
def _get_chat_scope_id() -> str:
|
|
scope_id = session.get('chat_scope_id')
|
|
if not scope_id:
|
|
scope_id = uuid.uuid4().hex
|
|
session['chat_scope_id'] = scope_id
|
|
return scope_id
|
|
|
|
|
|
@npc_chat_api.route('/start')
|
|
class ChatStart(Resource):
|
|
@npc_chat_api.expect(chat_start_model)
|
|
def post(self) -> tuple[Dict[str, Any], int]:
|
|
if not _require_auth():
|
|
return {'error': 'Authentication required'}, 401
|
|
|
|
user = _get_current_user()
|
|
if not user:
|
|
return {'error': 'User not found'}, 404
|
|
|
|
data = request.get_json() or {}
|
|
scope_id = _get_chat_scope_id()
|
|
payload = NpcChatService.start_conversation(
|
|
user_id=user.id,
|
|
username=user.username,
|
|
character=data.get('character'),
|
|
scope_id=scope_id,
|
|
)
|
|
return payload, 200
|
|
|
|
|
|
@npc_chat_api.route('/message')
|
|
class ChatMessage(Resource):
|
|
@npc_chat_api.expect(chat_message_model)
|
|
def post(self) -> tuple[Dict[str, Any], int]:
|
|
if not _require_auth():
|
|
return {'error': 'Authentication required'}, 401
|
|
|
|
user = _get_current_user()
|
|
if not user:
|
|
return {'error': 'User not found'}, 404
|
|
|
|
data = request.get_json() or {}
|
|
message = (data.get('message') or '').strip()
|
|
if not message:
|
|
return {'error': 'message is required'}, 400
|
|
|
|
scope_id = _get_chat_scope_id()
|
|
payload = NpcChatService.send_message(
|
|
user_id=user.id,
|
|
username=user.username,
|
|
character=data.get('character'),
|
|
user_message=message,
|
|
scope_id=scope_id,
|
|
)
|
|
return payload, 200
|
|
|
|
|
|
@npc_chat_api.route('/session')
|
|
class ChatSession(Resource):
|
|
def get(self) -> tuple[Dict[str, Any], int]:
|
|
if not _require_auth():
|
|
return {'error': 'Authentication required'}, 401
|
|
|
|
user = _get_current_user()
|
|
if not user:
|
|
return {'error': 'User not found'}, 404
|
|
|
|
character = request.args.get('character')
|
|
scope_id = _get_chat_scope_id()
|
|
payload = NpcChatService.get_session(user_id=user.id, character=character, scope_id=scope_id)
|
|
return payload, 200
|
|
|
|
|
|
@npc_chat_api.route('/reset')
|
|
class ChatReset(Resource):
|
|
@npc_chat_api.expect(chat_start_model)
|
|
def post(self) -> tuple[Dict[str, Any], int]:
|
|
if not _require_auth():
|
|
return {'error': 'Authentication required'}, 401
|
|
|
|
user = _get_current_user()
|
|
if not user:
|
|
return {'error': 'User not found'}, 404
|
|
|
|
data = request.get_json() or {}
|
|
scope_id = _get_chat_scope_id()
|
|
payload = NpcChatService.reset_session(user_id=user.id, character=data.get('character'), scope_id=scope_id)
|
|
return payload, 200
|
|
|
|
|
|
@npc_chat_api.route('/create_quest')
|
|
class ChatCreateQuest(Resource):
|
|
"""Create a quest from NPC chat interaction."""
|
|
|
|
@npc_chat_api.expect(quest_creation_model)
|
|
def post(self) -> tuple[Dict[str, Any], int]:
|
|
"""Create a quest proposed by an NPC.
|
|
|
|
This endpoint allows the frontend to persist a suggested quest
|
|
that was generated during NPC chat.
|
|
"""
|
|
if not _require_auth():
|
|
return {'error': 'Authentication required'}, 401
|
|
|
|
user = _get_current_user()
|
|
if not user:
|
|
return {'error': 'User not found'}, 404
|
|
|
|
data = request.get_json() or {}
|
|
|
|
# Validate required fields
|
|
required_fields = ['title', 'description', 'quest_type', 'priority']
|
|
if not all(data.get(field) for field in required_fields):
|
|
return {'error': 'Missing required fields: title, description, quest_type, priority'}, 400
|
|
|
|
# Create the quest
|
|
quest = Quest(
|
|
title=data.get('title'),
|
|
description=data.get('description'),
|
|
quest_type=data.get('quest_type'),
|
|
priority=data.get('priority'),
|
|
is_dark_magic=data.get('is_dark_magic', False),
|
|
assigned_to=user.id,
|
|
location_id=data.get('location_id'),
|
|
)
|
|
|
|
db.session.add(quest)
|
|
db.session.commit()
|
|
|
|
return {
|
|
'quest': quest.to_dict(),
|
|
'message': f'{data.get("character", "An NPC")} has created a quest for you!',
|
|
}, 201
|