ãã®èšäºã§ã¯ãäžé£ã®åçŽãªã³ãã³ãã䜿çšããŠããããäœæããæ¹æ³ã段éçã«èŠãŠãå°æ¥çã«ãã®æ©èœãæ¡åŒµããæ¹æ³ãèŠã€ããŸãã ãã®èšäºã¯ããã£ããããããäœæããããšã®ãªãã»ãšãã©ã®åå¿è ã«åœ¹ç«ã¡ãŸãã
ããããäœæããããšãã¯ãVKontakteã§äœ¿çšå¯èœãªãããã®äŸãæ€èšãããã®æ§é ãæ倧éã«åçŽåããããšãè©Šã¿ãŸããã
ããããäœæããããã«ãPython 3.5ïŒ3çªç®ã®pythonã®ä»ã®ããŒãžã§ã³ãããããé©åã§ãïŒãšè¿œå ã®Flaskããã³VKã©ã€ãã©ãªã䜿çšããŸããã ããããã€ã³ã¹ããŒã«ããå¿ èŠããããŸãã Flaskã®ã€ã³ã¹ããŒã«ã«é¢ãããã·ã¢èªã®èšäºãå€æ°ãããŸãã Pycharmããæã¡ã®å Žåã¯ãããããPycharmãšå ±ã«ã€ã³ã¹ããŒã«ãããŠããŸãã
APIèªäœããå§ããŸãããã ãããã«ã¯ãã°ã«ãŒãã¡ãã»ãŒãžã«äœ¿çšã§ããã³ãŒã«ããã¯APIã䜿çšããŸãã ãŸããæ¥ç¶ãããã¡ãã»ãŒãžãå«ãVKontakteã°ã«ãŒããäœæãããããã§ã«æã£ãŠããå¿ èŠããããŸãã
[ ã³ãã¥ããã£ç®¡ç] â[ APIã®æäœ]ã»ã¯ã·ã§ã³ã§ãã³ãã¥ããã£ã¡ãã»ãŒãžã«ã¢ã¯ã»ã¹ã§ããããŒãäœæããå¿ èŠããããŸãã
![ç»å](https://habrastorage.org/getpro/habr/post_images/ccd/e7d/68a/ccde7d68a82a18b99adc50e43bc4a097.jpg)
ã³ãŒã«ããã¯ã䜿çšããã«ã¯ãAPIããã€ãã³ãã®ãªã¯ãšã¹ããåä¿¡ããããããåŠçããã¬ã¹ãã³ã¹ãªã¯ãšã¹ããéä¿¡ããWebãµãŒããŒãå¿ èŠã§ãã ã€ãŸããéä¿¡ããããªã¯ãšã¹ãã«ã®ã¿å¿çããéä¿¡ããããŠã§ããµã€ãããäœæããŸãã
pythonã§èšè¿°ããŠããããã䜿çšã§ããæãç°¡åãªãã®ã¯pythonã®ãã¹ãã£ã³ã°ã§ãã Pythonã®ç¡æãã¹ãã£ã³ã°ã䜿çšããŸããã ããã§ç»é²ããFlaskã§Python 3.5çšã®ã¢ããªã±ãŒã·ã§ã³ãäœæããå¿ èŠããããŸãïŒWebã»ã¯ã·ã§ã³ã§äœæã§ããŸãïŒã åæãã¡ã€ã«ãäœæãããŸãïŒ
# A very simple Flask Hello World app for you to get started with... from flask import Flask app = Flask(__name__) @app.route('/') def hello_world(): return 'Hello from Flask!'
çŸåšãã¡ã€ã«ã«ããå¯äžã®æ©èœã¯ãç»é²æã«æå®ãããã¢ãã¬ã¹ã§ããŒãžãåããããšã«è²¬ä»»ããããŸãã username.pythonanywhere.comã®ãã©ãŠã¶ïŒããã¯ããŒã ã䜿çšïŒã«ã¢ã¯ã»ã¹ãããšããHello from FlaskïŒããšããããã¹ãã®ã¿ã衚瀺ãããŸãã
å°æ¥çã«ã¯ãã³ãŒãã¯ãããã¯ã§è¡šç€ºããããããã¯å šäœã®å®äºåŸã«ãã§ãã¯ããããšãå¯èœã«ãªãããã®ããã»ã¹ã§ã³ãŒããç°å¢ã«ãã£ãŠãšã©ãŒãšããŠããŒã¯ãããå¯èœæ§ããããŸãã æãããªãã§ããããã¯ãæåŸãŸã§çµããããã»ããããã§ãã
ãããã£ãŠã ãããã¯1ã§ãã
ãµã€ãã«éä¿¡ããããªã¯ãšã¹ããåŠçããã«ã¯ãããã¥ã¡ã³ãã®æåŸã«æ¬¡ã®ã³ãŒããè¿œå ããŸãã
@app.route('/', methods=['POST']) def processing(): return 'xxxxxxxx'
Xã®ä»£ããã«ãããµãŒããŒãè¿ãå¿ èŠã®ããæååããä»£å ¥ããŸãã ããã¯ãã³ãŒã«ããã¯APIã»ã¯ã·ã§ã³ã®ã°ã«ãŒã管çã«ãªã¹ããããŠããŸãã
ãã®æ©èœã«ãããã°ã«ãŒãã«éç¥ããããã«ãµã€ããæ¥ç¶ã§ããŸãã
ããã§äœæ¥ã確èªã§ããŸãã ã¢ããªã±ãŒã·ã§ã³ãåèµ·åããã ãã§ãã ãµã€ããæ°ããããŒã¿ã§äœæ¥ãéå§ã§ããããã«ãã¡ã€ã«ãå€æŽããŠä¿åããåŸã®ãã¹ãã£ã³ã°ã§ã¯ã[Web]ã¿ãã§ããããªããŒãããå¿ èŠããããŸãã ãã®ã³ãŒããè¿œå ããåŸãVKontakteã°ã«ãŒãã®ãµãŒããŒã¢ãã¬ã¹ããŒã«å¯Ÿå¿ããã¢ãã¬ã¹username.pythonanywhere.comãå ¥åãã[確èª]ãã¯ãªãã¯ããŸãã
ãµãŒããŒã¢ãã¬ã¹ãæ£åžžã«æ¥ç¶ãããããšã瀺ãç·è²ã®éç¥ã衚瀺ãããŸãã
[確èª]ãã¯ãªãã¯ãããšãVKontakteã¯ãµãŒããŒã«æ¥ç¶ãããããå®éã«ã°ã«ãŒãææè ã«å±ããŠããããšã確èªãããµãŒããŒãèŠæ±ã«å¿ããŠç¢ºèªã³ãŒããè¿ãã®ããåŸ æ©ãããŸãã
ãããã¯2
次ã®ã¹ãããã«é²ãããšãã§ããŸãã ã³ãã¥ããã£ã«ä»£ãã£ãŠã¡ãã»ãŒãžãæžã蟌ãæ©èœãè¿œå ããŸãã ãã¹ãã£ã³ã°ã«VKã©ã€ãã©ãªãã€ã³ã¹ããŒã«ããŸãã ãã³ã³ãœãŒã«ãã»ã¯ã·ã§ã³ã§ãbashã³ã³ãœãŒã«ãèµ·åããã³ãã³ãïŒãŸãã¯éžæããããŒãžã§ã³ã®pythonã«é©ããã³ãã³ãïŒãå®è¡ããŸãã
pip3.5 install --user vk
ã¢ãžã¥ãŒã«ã®ã€ã³ã¹ããŒã«æ¹æ³ã«ã€ããŠã¯ã ããã§èª¬æããŸã ã
åä¿¡ãªã¯ãšã¹ããåŠçããããã®é¢æ°ã®ã³ãŒããå€æŽããŸãã
@app.route('/', methods=['POST']) def processing(): # json POST- data = json.loads(request.data) # if 'type' not in data.keys(): return 'not vk' if data['type'] == 'confirmation': return confirmation_token elif data['type'] == 'message_new': session = vk.Session() api = vk.API(session, v=5.0) user_id = data['object']['user_id'] api.messages.send(access_token=token, user_id=str(user_id), message=', !') # , return 'ok'
VKontakteãµãŒããŒã«ã¯ãåŠçãæåãããšããã¡ãã»ãŒãžãå¿ èŠã§ãã ãšã©ãŒãçºçããå ŽåããŸãã¯ä»ã®åçãå°çããå ŽåããµãŒããŒã¯äžå®ã®ééã§ïŒåŠçãããŸã§ïŒçä¿¡ã¡ãã»ãŒãžã«é¢ããéç¥ãéä¿¡ãç¶ããŸãã
æ°ããã¡ãã»ãŒãžã«ã€ããŠéç¥ããçä¿¡èŠæ±ã®æ§é ã¯æ¬¡ã®ãšããã§ãã
{"type":"message_new","object":{"id":43, "date":1492522323, "out":0, "user_id":xxxxxxxx, "read_state":0, "title":" ... ", "body":""}, "group_id":xxxxxxxxxxx}
Vkontakteã¯ããµã€ãã«3ã€ã®ãªããžã§ã¯ããtypeãããobjectãããgroup_idããæž¡ããã¡ãã»ãŒãžã«é¢ããæ å ±ã¯ãobjectãå ã«ä¿åãããŸãã
ãã¹ãŠã®ãªã¯ãšã¹ãã¯VKontakteã®ããã¥ã¡ã³ãã«èšèŒãããŠããŸã
ãŸããæ°ãããã€ã³ããŒããããã¡ã€ã«ã®å é ã«è¿œå ããŸãã
from flask import Flask, request, json from settings import * import vk
åãsettings.pyãã©ã«ããŒã«æ°ãããã¡ã€ã«ãäœæããããã«å¿ èŠãªãã°ã€ã³ããŒã¿ãä¿åããŸãã
token = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx' confirmation_token = 'xxxxxxxx'
ãããã¯ããŒã¯ã³ã«çœ®ãæããå¿ èŠããããŸãã æåã¯èšäºã®åé ã§äœæãã2çªç®ã¯ã°ã«ãŒãããµãŒããŒã«æ¥ç¶ããããã®ç¢ºèªã³ãŒãã§ãã
ããã§ãããã¯çä¿¡ã¡ãã»ãŒãžã«æšæ¶ããã³ãŒããäžããã°ã«ãŒãã«å±ããŠããããšã確èªã§ããŸãã
ããã確èªããŠã¡ãââã»ãŒãžãæžã蟌ãããšãã§ããŸããCallbackAPIã»ã¯ã·ã§ã³ã®ã°ã«ãŒãèšå®ã§çä¿¡ã¡ãã»ãŒãžã«é¢ããéç¥ãæå¹ã«ããã ãã§ãã
ããããã¡ãã»ãŒãžãéä¿¡ããã«ã¯ãã¢ããªã±ãŒã·ã§ã³ãåèµ·åããå¿ èŠããããŸãã ãã®åŸããããã«å床æžã蟌ã¿ããã¹ãŠãæ£åžžã«è¡ãããå Žåã次ã®ã¹ãããã«é²ã¿ãŸãã
ãããã¯3
ãã¹ãŠãããŸããããã¡ãã»ãŒãžã«å¿ããŠããããããªãã«æšæ¶ããå Žåã次ã®ã¹ãããã«é²ã¿ãŸãã vkã©ã€ãã©ãªãšã®ãã¹ãŠã®å¯Ÿè©±ãå¥ã®ãã¡ã€ã«ã«å ¥ããŸãããvkapiãšåŒã³ãŸãã
import vk session = vk.Session() api = vk.API(session, v=5.0) def send_message(user_id, token, message, attachment=""): api.messages.send(access_token=token, user_id=str(user_id), message=message, attachment=attachment)
VKontakteã»ãã·ã§ã³ã®é¢æ°ãšåæåã¯1ã€ã ãã§ãããä»ã®ã»ãã·ã§ã³ãè¿œå ããŸãã æœåšçã«ãé¢æ°ã¯æ·»ä»ãã¡ã€ã«ãéä¿¡ããããšãã§ããŸãã åŸã§ãã®æ©äŒãå©çšããŸãã
次ã«ãã¡ãã»ãŒãžãã³ãã©ãã¡ã€ã«ãéå§ããŸãã çä¿¡ã¡ãã»ãŒãžãåŠçãã衚瀺ããããšãã«é©åãªã³ãã³ãã決å®ããå¿ èŠãªåçãçºè¡ããŸãã
ãã¡ã€ã«ãmessageHandler.pyãïŒ
import vkapi def get_answer(body): message = ", !" return message def create_answer(data, token): user_id = data['user_id'] message = get_answer(data['body'].lower()) vkapi.send_message(user_id, token, message)
æ°ãããã¡ã€ã«ãã¡ã€ã³ã®ãã¡ã€ã«ã«æ¥ç¶ããŸãã ã¡ã€ã³ãã¡ã€ã«ã®ãªã¯ãšã¹ãåŠçé¢æ°ãå€æŽããŸãã
@app.route('/', methods=['POST']) def processing(): data = json.loads(request.data) if 'type' not in data.keys(): return 'not vk' if data['type'] == 'confirmation': return confirmation_token elif data['type'] == 'message_new': messageHandler.create_answer(data['object'], token) return 'ok'
ãããŠãé©åãªã€ã³ããŒãããã¡ã€ã«ã®å é ã«è¿œå ããŸãã
import messageHandler
ã¢ããªã±ãŒã·ã§ã³ãåèµ·åããããšã§ãå®è¡ããããšã確èªã§ããŸãã
ãããã¯4
ããŒã ã®äœæãå§ããŸãããã ã³ãã³ãã®ã¯ã©ã¹ãäœæããŸãã
ãã¡ã€ã«ãcommand_system.pyãïŒ
command_list = [] class Command: def __init__(self): self.__keys = [] self.description = '' command_list.append(self) @property def keys(self): return self.__keys @keys.setter def keys(self, mas): for k in mas: self.__keys.append(k.lower()) def process(self): pass
ã¯ã©ã¹ã«ã¯keysããããã£ãããããã®ã³ãã³ãã«ã¢ã¯ã»ã¹ã§ããããŒãä¿åãããŸãã ããããã£ãèšå®ãããšãããã¹ãŠã®ããŒã¯å°æåã§ä¿åãããŸãããŸããã³ãã³ãã³ãŒã«ã®æåã«ã¬ãžã¹ã¿ã圱é¿ããªãããã«ãå°æåã«å€æããããŠãŒã¶ãŒã¡ãã»ãŒãžãšæ¯èŒããå¿ èŠããããŸãã
説æãã£ãŒã«ãã¯ããããã³ãã³ãã«é¢ããæ å ±ãçºè¡ããããã«äœ¿çšãããŸãã ããã»ã¹é¢æ°ãå®è¡ãããå¿çã¡ãã»ãŒãžãçæãããŸãã
åæåæã«ãã¹ãŠã®ã³ãã³ããä¿åãããäžè¬çãªãªã¹ãããããŸãã 圌ã¯æ宀ã®å€ã«ããŸãã ãã®ãªã¹ãã䜿çšããŠããŠãŒã¶ãŒãã¡ãã»ãŒãžã§èŠæ±ããã³ãã³ããèŠã€ããŸãã
ããã§ã¯ããããçšã®ããŒã ãããã€ãäœæããŸãããã ããŒãã®äŸ¿å®äžãã³ãã³ããåæåãããã¡ã€ã«ããcommandsããã©ã«ããŒã«é 眮ããŸãã
è€æ°ã®ãã¡ã€ã«ãäœæããŸãããã³ãã³ãã1ã€ã®ãã¡ã€ã«ã«é 眮ããããšãã§ããŸã
ãHello.pyã
import command_system def hello(): message = ', !\n -.' return message, '' hello_command = command_system.Command() hello_command.keys = ['', 'hello', '', '', ''] hello_command.description = ' ' hello_command.process = hello
ãCat.pyã
import command_system import vkapi import settings def cat(): # attachment = vkapi.get_random_wall_picture(-32015300, settings.access_token) message = ' :)\n .' return message, attachment cat_command = command_system.Command() cat_command.keys = ['', '', '', '', '', 'cat'] cat_command.description = ' ' cat_command.process = cat
ç«ãéãããŒã ã«ã¯ãã°ã«ãŒããŸãã¯ãŠãŒã¶ãŒã®å£ããã©ã³ãã ãªç»åãè¿ããvkapiããã¡ã€ã«ã®æ°ããããŒã¯ã³ãšæ°ããé¢æ°ãå¿ èŠã§ãã ãã®å Žåãç§ãã¡ã¯ç«ãšäžç·ã«å ¬è¡ã®å£ããã©ã³ãã ãªåçãåãåããŸãã
ããŒã¯ã³ãååŸããããšããå§ããŸãããã ãµãŒãã¹ã¢ã¯ã»ã¹ããŒãå¿ èŠã§ãã ãããè¡ãã«ã¯ãæ°ããã¹ã¿ã³ãã¢ãã³ã¢ããªã±ãŒã·ã§ã³ãäœæããŸãã åç §ã«ãã£ãŠäœæã§ããŸãã 次ã«ãã¢ããªã±ãŒã·ã§ã³ãäœæãããããã®èšå®ã«ç§»åããŠã[ãµãŒãã¹ã¢ã¯ã»ã¹ããŒ]ãã£ãŒã«ãã®å 容ãã³ããŒããå¿ èŠããããŸãã
ãããããŒã¯ã³ãã¡ã€ã«ã«è¿œå ããå¿ èŠããããŸãã
ãSettings.pyã
token = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx' confirmation_token = 'xxxxxxxx' access_token = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'
ããã§ã¯ãæ°ããvkapiã¡ãœããã®äœæã«ç§»ããŸãããã ããã§ã¯ã䜿çšããAPIã¡ãœããã®ç¯å²ãå°ãæ¡å€§ããŸãã
ãã®ã¡ãœããã¯æ¬¡ã®ããã«ãªããŸãã
def get_random_wall_picture(group_id, token): max_num = api.photos.get(owner_id=group_id, album_id='wall', count=0, access_token=token)['count'] num = random.randint(1, max_num) photo = api.photos.get(owner_id=str(group_id), album_id='wall', count=1, offset=num, access_token=token)['items'][0]['id'] attachment = 'photo' + str(group_id) + '_' + str(photo) return attachment
ãvkapiããã¡ã€ã«ã«è¿œå ããŸãã ãŸããå¿ èŠãªã€ã³ããŒãããvkapiããã¡ã€ã«ã®å é ã«è¿œå ããŸãã
import random
ãããŠæåŸã®ããŒã
ãInfo.pyã
import command_system def info(): message = '' for c in command_system.command_list: message += c.keys[0] + ' - ' + c.description + '\n' return message, '' info_command = command_system.Command() info_command.keys = ['', '', 'help'] info_command.desciption = ' ' info_command.process = info
æçµçãªãã¡ã€ã«éå±€ïŒ
![ç»å](https://habrastorage.org/getpro/habr/post_images/761/497/7fb/7614977fb3b17d9557f385f4e0f80b26.png)
botFlaskã¯ãçä¿¡èŠæ±ãåãå ¥ããã¡ã€ã³ãã¡ã€ã«ã§ãã
ã³ãã³ãã®èª¬æãçµãã£ãã®ã§ãã³ãã³ãã·ãŒãããã£ã±ãã«ãªã£ãŠããããšã確èªããå¿ èŠããããŸãããŸããcommand_listã¯ç¹å®ã®ã³ãã³ãã§ãã¡ã€ã«ãèµ·åãããšãã«ã®ã¿å ¥åãããããããŠãŒã¶ãŒãã¢ã¯ã»ã¹ããã³ãã³ããç解ã§ããŸãã
ãããã®èµ·åæã«ããcommandsããã©ã«ããŒãããã¹ãŠã®ãã¡ã€ã«ãèªåçã«èµ·åããŸãã
ãããè¡ãã«ã¯ãmessageHandler.pyãã¡ã€ã«ã«é¢æ°ãè¿œå ããŸãã
def load_modules(): # , files = os.listdir("mysite/commands") modules = filter(lambda x: x.endswith('.py'), files) for m in modules: importlib.import_module("commands." + m[0:-3])
ãã®é¢æ°ã§ã¯ãã³ãã³ãã䜿çšããŠãã£ã¬ã¯ããªãããã¡ã€ã«ã®ãªã¹ããããŒãããPythonãã¡ã€ã«ã®ã¿ããã£ã«ã¿ãŒåŠçããŠããã°ã©ã ã«ã€ã³ããŒãããŸããããã«ããããªã¹ãã«ã³ãã³ããå ¥åãããŸãã
ãã®é¢æ°ã®åŒã³åºããcreate_answerã«è¿œå ãããŸãã 次ã«ã察å¿ããå¿çãåŒã³åºãããã«get_answeré¢æ°ãå€æŽããŸãããã
ãã¡ã€ã«ã®æçµåœ¢åŒïŒ
import vkapi import os import importlib from command_system import command_list def load_modules(): # , files = os.listdir("mysite/commands") modules = filter(lambda x: x.endswith('.py'), files) for m in modules: importlib.import_module("commands." + m[0:-3]) def get_answer(body): # message = ", . '', " attachment = '' for c in command_list: if body in c.keys: message, attachment = c.process() return message, attachment def create_answer(data, token): load_modules() user_id = data['user_id'] message, attachment = get_answer(data['body'].lower()) vkapi.send_message(user_id, token, message, attachment)
ãããã®æºåãã§ããŸããïŒ ããã§ããããã®ããŒã¹ãäœæãããã®ããã®æ°ããããŒã ãè¿œå ããæ¹æ³ãããããŸããã
ãããã¯5
èšäºã®æ®ãã®éšåã§ã¯ãå¿ èŠã ãšæã1ã€ã®æ¹åã«ã€ããŠèª¬æããŸãã ãã ãããããã¯ãããªãã§åäœããŸãã
ããããã®ã³ãã³ãèªè
ãŠãŒã¶ãŒã1ã€ã®æåãééããå Žåãæãé¡äŒŒããã³ãã³ãã念é ã«çœ®ããŠããå¯èœæ§ãé«ãã§ãã ãããã£ãŠããããããŸã çããåºãããç§ã¯ããªããç解ããŠããŸããããšèšããªãã£ããããã§ãããã
ããããã®èªèã®ããã«ãDamerau-Levenshteinè·é¢ã䜿çšããŸãã æåãåé€ãæ¿å ¥ã眮æã移åããæäœããããè¡ããå¥ã®è¡ã«ç§»åã§ããåæ°ã瀺ããŠããŸãã
ãã®è·é¢ãèŠã€ããããã®ã¢ã«ãŽãªãºã ã¯ãäŸãã°ãŠã£ãããã£ã¢ã§èª¬æãããŠããŸãã
é¢æ°ãmessageHandler.pyãã¡ã€ã«ã«è¿œå ããŸãã
def damerau_levenshtein_distance(s1, s2): d = {} lenstr1 = len(s1) lenstr2 = len(s2) for i in range(-1, lenstr1 + 1): d[(i, -1)] = i + 1 for j in range(-1, lenstr2 + 1): d[(-1, j)] = j + 1 for i in range(lenstr1): for j in range(lenstr2): if s1[i] == s2[j]: cost = 0 else: cost = 1 d[(i, j)] = min( d[(i - 1, j)] + 1, # deletion d[(i, j - 1)] + 1, # insertion d[(i - 1, j - 1)] + cost, # substitution ) if i and j and s1[i] == s2[j - 1] and s1[i - 1] == s2[j]: d[(i, j)] = min(d[(i, j)], d[i - 2, j - 2] + cost) # transposition return d[lenstr1 - 1, lenstr2 - 1]
ãã®è·é¢ãèŠã€ããããã®ã¢ã«ãŽãªãºã ãå®è£ ãããŠãããå¿ èŠã«å¿ããŠå€æŽãŸãã¯æ¹åã§ããŸãã
ãããã®è¡ã«ãããšã1ã€ãå¥ã®å€ã«å€æããããã®æäœã®æ°ãäžããããŸãã get_answerã¡ãœãããå€æŽããŸãã
def get_answer(body): message = ", . '', " attachment = '' distance = len(body) command = None key = '' for c in command_list: for k in c.keys: d = damerau_levenshtein_distance(body, k) if d < distance: distance = d command = c key = k if distance == 0: message, attachment = c.process() return message, attachment if distance < len(body)*0.4: message, attachment = command.process() message = ' "%s"\n\n' % key + message return message, attachment
ãã®é¢æ°ã§ã¯ãã¡ãã»ãŒãžãšåããŒã®è·é¢ãèšç®ããŸãã äžèŽãäžæ£ç¢ºãªå Žåãéä¿¡ãããåã³ãã³ããããããã©ã®ããã«èªèããããèšè¿°ããŸãã è·é¢ãéä¿¡ãããã¡ãã»ãŒãžã®é·ãã®40ïŒ ãè¶ ããå ŽåããŠãŒã¶ãŒã誀解ããããŠãããšèŠãªããããã©ã«ãã¡ãã»ãŒãžãè¿ããŸãã
ããã ãã§ããïŒãã®èšäºãæžããŠããæç¹ã§ïŒåäœããã³ãŒãã¯githubã«æçš¿ãããŠããŸãã
VKçšã®ç¬èªã®ããããäœæããããšã«æ±ºããå Žåããã®èšäºãããªãã®äººçãå°ã楜ã«ããããšãé¡ã£ãŠããŸãã