134 lines
5.9 KiB
Python
134 lines
5.9 KiB
Python
# -*- coding: utf-8 -*-
|
||
import re
|
||
from odoo import api, models, fields
|
||
|
||
# 游戏助手的展示昵称(前后端共用,落库消息的作者名)
|
||
GUIDE_NAME = '游戏助手'
|
||
|
||
|
||
def _plain(text):
|
||
"""去掉 HTML 标签,用于把 rule.desc(Html) 当作纯文本兜底。"""
|
||
if not text:
|
||
return ''
|
||
return re.sub(r'<[^>]+>', '', text).strip()
|
||
|
||
|
||
class GameChatChannel(models.Model):
|
||
_name = 'game.chat.channel'
|
||
_description = '世界聊天频道'
|
||
_order = 'sequence, id'
|
||
|
||
name = fields.Char(string='频道名', required=True)
|
||
channel_type = fields.Selection([
|
||
('world', '世界频道'),
|
||
('guild', '公会'),
|
||
('pm', '私聊'),
|
||
('guide', 'AI向导'),
|
||
], string='类型', default='world', index=True)
|
||
sequence = fields.Integer(string='排序', default=10)
|
||
creator_id = fields.Many2one('res.users', string='创建者')
|
||
member_ids = fields.Many2many('res.users', string='成员')
|
||
message_ids = fields.One2many('game.chat.message', 'channel_id', string='消息')
|
||
message_count = fields.Integer(string='消息数量', compute='_compute_message_count')
|
||
|
||
@api.depends('message_ids')
|
||
def _compute_message_count(self):
|
||
for rec in self:
|
||
rec.message_count = len(rec.message_ids)
|
||
|
||
def action_view_messages(self):
|
||
"""从频道列表跳转查看该频道全部消息。"""
|
||
self.ensure_one()
|
||
return {
|
||
'type': 'ir.actions.act_window',
|
||
'name': '频道消息',
|
||
'res_model': 'game.chat.message',
|
||
'view_mode': 'list,form',
|
||
'domain': [('channel_id', '=', self.id)],
|
||
'context': dict(self.env.context),
|
||
}
|
||
|
||
def generate_guide_reply(self, question):
|
||
"""内置游戏知识引擎(零外部依赖):按关键词检索 game.rule / game.rule.category 作答。
|
||
预留扩展点:若需接入真实 LLM,替换本方法实现、返回模型生成的文本即可,其余调用方不变。
|
||
"""
|
||
q = (question or '').strip()
|
||
if not q:
|
||
return '你好,我是游戏助手。你可以问我关于「属性」「等级」「货币」「制度」的问题~'
|
||
env = self.env
|
||
Rule = env['game.rule']
|
||
Cat = env['game.rule.category']
|
||
|
||
def rules_of(key):
|
||
c = Cat.search([('key', '=', key)], limit=1)
|
||
return Rule.search([('category_id', '=', c.id)], order='name') if c else []
|
||
|
||
def line(r):
|
||
return f'· {r.name}:{r.summary or _plain(r.desc)}'
|
||
|
||
# 问候
|
||
if re.search(r'(你好|您好|hi|hello|在吗|嗨|早上好|晚上好)', q, re.I):
|
||
return ('你好,我是游戏助手 🤖 随时为你解答宇森世界的玩法。\n'
|
||
'可以问我:属性怎么算?怎么升级?货币有什么用?有哪些制度?')
|
||
|
||
# 属性(关键词覆盖攻击/物攻/法攻/防御/暴击等;穿透/韧性已移除)
|
||
_attr_re = re.search(r'(属性|攻击|物攻|法攻|防御|物防|法防|血量|生命|法力|速度|攻速|暴击|爆伤|命中|闪避|格挡|抗性|吸血|幸运)', q)
|
||
if _attr_re:
|
||
rules = list(rules_of('attribute_basic')) + list(rules_of('attribute_advanced'))
|
||
if rules:
|
||
head = '【属性规则】不同属性决定你的战斗表现,核心属性如下:'
|
||
return head + '\n' + '\n'.join(line(r) for r in rules[:12]) + '\n\n想深入了解某项,直接问我它的名字~'
|
||
|
||
# 等级
|
||
if re.search(r'(等级|升级|经验|世界等级|角色等级|怎么变强|变强)', q):
|
||
for key in ('world', 'character'):
|
||
rules = rules_of(key)
|
||
if rules:
|
||
c = Cat.search([('key', '=', key)], limit=1)
|
||
head = f'【{c.name}】'
|
||
lines = [f'· {r.name}(Lv{r.level}):{r.summary or ""}' for r in rules[:6]]
|
||
return head + '\n' + '\n'.join(l for l in lines if l.strip())
|
||
|
||
# 货币
|
||
if re.search(r'(货币|金币|钱|元宝|钻石|充值|兑换|经济)', q):
|
||
rules = rules_of('currency')
|
||
if rules:
|
||
head = '【货币规则】游戏内货币与获取/消耗方式:'
|
||
return head + '\n' + '\n'.join(line(r) for r in rules[:8])
|
||
|
||
# 制度 / 规则
|
||
if re.search(r'(制度|规定|规则|条款|公约|不能|禁止|惩罚|封号)', q):
|
||
rules = rules_of('system')
|
||
if rules:
|
||
head = '【制度说明】请遵守以下基本规则:'
|
||
return head + '\n' + '\n'.join(line(r) for r in rules[:8])
|
||
|
||
# 兜底:给出可问的方向
|
||
cats = Cat.search(
|
||
[('key', 'in', ['world', 'character', 'currency', 'attribute', 'system'])],
|
||
order='sequence')
|
||
tips = '、'.join(c.name for c in cats) if cats else '属性、等级、货币、制度'
|
||
return ('我是游戏助手,这个问题我还在学习中 🤔\n'
|
||
f'你可以问我这些方向:{tips}。\n例如:「攻击和物防怎么算?」「怎么升级最快?」')
|
||
|
||
|
||
class GameChatMessage(models.Model):
|
||
_name = 'game.chat.message'
|
||
_description = '聊天消息'
|
||
_order = 'id desc'
|
||
|
||
channel_id = fields.Many2one('game.chat.channel', string='频道',
|
||
ondelete='cascade', required=True, index=True)
|
||
author_id = fields.Many2one('res.users', string='发送者')
|
||
author_name = fields.Char(string='昵称')
|
||
body = fields.Text(string='内容', required=True)
|
||
|
||
@api.model_create_multi
|
||
def create(self, vals_list):
|
||
"""创建消息时自动过滤敏感词。"""
|
||
sanitize = self.env['game.sensitive.word'].sanitize
|
||
for vals in vals_list:
|
||
if vals.get('body'):
|
||
vals['body'] = sanitize(vals['body'])
|
||
return super(GameChatMessage, self).create(vals_list)
|