LLMãšã®ã³ãã¥ãã±ãŒã·ã§ã³ãããå¹çåããPythonã©ã€ãã©ãªãPromptoGenãããªãªãŒã¹ããŸããð
TL;DR
Pythonã©ã€ãã©ãª ãPromptoGenã ããªãªãŒã¹ããŸãã ð
PromptoGenã¯ããLLMãšPythonã®éã®ã®ã£ãããã·ãŒã ã¬ã¹ã«ç¹ãããšã§ãå¹ççã§æªæ¥ãèŠæ®ããã³ãã¥ãã±ãŒã·ã§ã³ãå®çŸãããã ãšããããžã§ã³ã®å
ã
ãããŠå
·äœçãªLLMå®è£
ãžã®äŸåæ§ããªãããæœè±¡åãè¡ã ããšã§ã
ä»åŸã®LLMé²åã«ã€ããŠè¡ããããåºç€ãäœã OSSãããžã§ã¯ãã§ãã
ãã®èšäºã§ã¯ãPromptoGen ãããžã§ã¯ãã®ç޹ä»ãã©ã€ãã©ãªã®äœ¿ãæ¹ã玹ä»ããŸãã

ããã¥ã¡ã³ã: https://promptogen.zawakin.dev/ja
ãœãŒã¹ã³ãŒã:
å®éã«ã©ã€ãã©ãªã®å 容ã玹ä»ããŠãããŸãã
ð PromptoGen: LLMãšã®å¹ççã§æ¡åŒµå¯èœãªã³ãã¥ãã±ãŒã·ã§ã³ãå®çŸ
ð ããžã§ã³
"LLMãšPythonã®éã®ã®ã£ãããã·ãŒã ã¬ã¹ã«ç¹ãããšã§ãå¹ççã§æªæ¥ãèŠæ®ããã³ãã¥ãã±ãŒã·ã§ã³ãå®çŸããã"
ð¡ LLMã©ã€ãã©ãªã®äž»ãªèª²é¡:
- ããã³ãããšã³ãžãã¢ãªã³ã°ã®ãšã³ã·ã¹ãã ãäžè¶³: ããã³ããã®äœæãå ±æãå°é£ã«ãªã
- ç¹å®ã®LLMããŒãžã§ã³ãžã®åŒ·ãäŸåæ§: é«é »åºŠãªLLMã®æŽæ°ã«å¯ŸããŠè匱ã«ãªã
- å®è£ ãè€é: ã«ã¹ã¿ãã€ãºãå°é£ã«ãªã
ð¯ PromptoGenãéžã¶çç±ã¯ïŒ
- LLM I/OãšPythonãªããžã§ã¯ãéã®ã·ãŒã ã¬ã¹ãªå€æ: LLMãšã®ã€ã³ã¿ã©ã¯ã·ã§ã³ãåçåããŸã
- æè»ã§ãŠããŒã¯ãªã€ã³ã¿ãŒãã§ãŒã¹: ãŠãŒã¶ãŒã®ã«ã¹ã¿ãã€ãºãšæ¡åŒµæ§ãä¿èšŒããŸã
- å°æ¥ã®èšèš: LLMã®é²åã«å¯ŸããäŸåãæžå°ãããŠå°æ¥ã«åããŸã
ä»ã®ã©ã€ãã©ãªãšã®æ¯èŒ: å€ãã¯ç¹å®ã®LLMããŒãžã§ã³ã«çµã³ã€ããŠãããå°æ¥ã®é©å¿æ§ã«èª²é¡ããããŸããPydanticããŒã¿ã¯ã©ã¹ã©ã€ãã©ãªã ãã«äŸåããPromptoGenã¯ãLLMæååãšPythonãªããžã§ã¯ããšã®éãæ©æž¡ãããããšã«ç¹åããŠããŸãã
ð§° äž»ãªæ©èœ:
-
PromptããŒã¿ã¯ã©ã¹: LLMéä¿¡ãæšæºåããããã³ãããšã³ãžãã¢ãªã³ã°ããµããŒã -
TextLLMã€ã³ã¿ãŒãã§ãŒã¹: LLMã®è©³çްããã®ç¬ç« -
PromptFormatterã€ã³ã¿ãŒãã§ãŒã¹: ãŠãŒã¶ãŒã®ããã®é«ãã«ã¹ã¿ãã€ãºæ§
ð å©ç¹:
- ð§© ã¢ãžã¥ã©ãŒïŒæ¡åŒµå¯èœ: èªç±ã«çµã¿åãããã«ã¹ã¿ã ã³ã³ããŒãã³ãã远å
- ð¡ïž æªæ¥ã®å€æŽã«åŒ·ã: æ°ããã¢ãã«ã®ã¢ããããŒãã«åŒ·ãç«ã€
- ð§ ç¶æãããã: ç°ãªãLLMã®ããã®ãããã°ã埮調æŽã容æ
â ïž ãµããŒããããŠããªãæ©èœ:
- LLMãšã®çŽæ¥éä¿¡: çŽæ¥ã®LLMãšã®äŒè©±ãããå¹ççãªã€ã³ã¿ãŒãã§ãŒã¹ãåªå ããŸã
- ããã³ããã®ããŒãžã§ã³ç®¡ç: ã·ã³ãã«ã«ä¿ã€ãããããŒãžã§ã³ã®è€éãã远å ããããšãé¿ããŸã
- ç¹å®ã®LLMã®æé©å: åäžã®LLMã®ããã®æé©åãããLLMå šäœã®é©å¿æ§ã«çŠç¹ãåœãŠãŸã
ð 詳现ã«ã€ããŠ
PromptoGenãšã¯ãåç §ããŠãã ããã
ãªãªãŒã¹æ å ±
éæã以äžã®ã¢ã«ãŠã³ãã§ãç¥ããããŸãã
åäœç°å¢
Python 3.8 以äž
ã€ã³ã¹ããŒã«
pip install promptogen
ã€ã³ããŒã
import promptogen as pg
äœ¿ãæ¹
ãªã«ã¯ãšããããäœ¿ãæ¹ã玹ä»ããŠã¿ãŸãã
TextLLM: æè»ãªLLM飿º
pg.TextLLMãä»ãããšã§ãPromptoGenã¯å€çš®å€æ§ãªå€§èŠæš¡èšèªã¢ãã«(LLM)ãšã®é£æºãå®çŸããŸãã
TextLLMã€ã³ã¿ãŒãã§ã€ã¹ã®å®è£ äŸ
import promptogen as pg
class YourTextLLM(pg.TextLLM):
def __init__(self, model: str):
self.model = model
def generate(self, text: str) -> str:
# å
·äœçãªå®è£
ã¯ãã
return generate_by_your_text_llm(text, self.model)
text_llm = YourTextLLM(model="your-model")
print(text_llm.generate("Hello, I'm a human."))
# Hello! How can I assist you today as an AI?
ãã®ã€ã³ã¿ãŒãã§ã€ã¹ã®æ¡çšã«ãããPromptoGenã¯ç°ãªãLLMããã®ããŒãžã§ã³ãã¹ã ãŒãºã«çµã¿èŸŒãããšãå¯èœã«ãªããŸãããŠãŒã¶ãŒã¯LLMã«ãããªãäžè²«ããæ¹æ³ã§ãæ§ã ãªLLMãæŽ»çšã§ããããã«ãªããŸãã
ã€ãŸããLLMå®è£
ã§ã¯ãªã pg.TextLLM ã«äŸåããããã°ã©ã ãæžããšãã©ããªLLMã§ã pg.TextLLM ãå®è£
ãããããã°ãã®ããã°ã©ã ã䜿ããããšã«ãªããŸãã
OpenAI APIã䜿ã£ãTextLLMå®è£ äŸ
OpenAI APIã䜿ã£ãTextLLMå®è£ äŸ ãåç §ããŠãã ããã
Prompt: ããã³ãã
ããã³ããã®äœæ
PromptoGen ã§ã®äžçªã®åºæ¬èŠçŽ ã¯ ããã³ãã(Prompt) ã§ãã
äŸãã°ãããã¹ããå ¥åãšããèŠçŽãšããŒã¯ãŒããæœåºãããããªåœä»€ãLLMã«å¯ŸããŠè¡ãå ŽåãèããŠã¿ãŸãããã
PromptoGen ã«ãããŠããã®åœä»€ã¯ Prompt ããŒã¿ã¯ã©ã¹ã®ã€ã³ã¹ã¿ã³ã¹ãšããŠè¡šçŸãããŸãã
Prompt ã¯ã©ã¹ã¯æ¬¡ã®ãã©ã¡ãŒã¿ãæã¡ãŸãã
- ããã³ããå
- ããã³ãã説æ(åœä»€)
- å ¥åãã©ã¡ãŒã¿æ å ±
- åºåãã©ã¡ãŒã¿æ å ±
- å ¥åºåãã³ãã¬ãŒã
- å ¥åºåäŸ(few-shots examples)ã®é å
å ·äœçã«ã¯æ¬¡ã®ãããªå®çŸ©ãšãªããŸãã
import promptogen as pg
summarizer = pg.Prompt(
# ããã³ããå
name="Text Summarizer and Keyword Extractor",
# ããã³ãã説æ(åœä»€)
description="Summarize text and extract keywords.",
# å
¥åãã©ã¡ãŒã¿æ
å ±
input_parameters=[
pg.ParameterInfo(name="text", description="Text to summarize"),
],
# åºåãã©ã¡ãŒã¿æ
å ±
output_parameters=[
pg.ParameterInfo(name="summary", description="Summary of text"),
pg.ParameterInfo(name="keywords", description="Keywords extracted from text"),
],
# å
¥åºåãã³ãã¬ãŒã
template=pg.IOExample(
input={'text': "This is a sample text to summarize."},
output={
'summary': "This is a summary of the text.",
'keywords': ["sample", "text", "summarize"],
},
),
# å
¥åºåäŸ(few-shots examples)ã®é
å
examples=[
pg.IOExample(
input={
'text': "One sunny afternoon, ...(ç¥)"},
output={
'summary': "A group of friends enjoyed an afternoon playing sports and making memories at a local park.",
'keywords': ["friends", "park", "sports", "memories"],
},
)
],
)
ãã®ããã«æç¢ºãªå®çŸ©ãæã€ããšã§ãããã³ããã®ãšã³ã·ã¹ãã ã圢æãããããªããŸãã
åºæ¬çãªãŠãŒã¹ã±ãŒã¹ã§ã¯ããã®ããã«äžãã Prompt ãæåã§å®çŸ©ãããããåŸè¿°ãããã㪠Prompt èªåçæãLLMã«ããŠããã£ãããšã«æçŽããããŠäœ¿ãããšãå€ãã§ãã
ããã³ããã®ä¿å
import promptogen as pg
summarizer = pg.Prompt(
name="Text Summarizer and Keyword Extractor",
# ...(ç¥)
)
summarizer.to_json_file("summarizer.json")
ããã³ããã®èªã¿èŸŒã¿
import promptogen as pg
summarizer = pg.Prompt.from_json_file("summarizer.json")
PromptFormatter: ããã³ããã®ãã©ãŒããã
ããŠãPrompt ã¯ã©ã¹ã®ã€ã³ã¹ã¿ã³ã¹ãå®éã«LLMã«éä¿¡ããããã«ãæååã«å€æããå¿
èŠããããŸããPromptoGenã§ã¯ãpg.PromptFormatterã€ã³ã¿ãŒãã§ã€ã¹ãä»ããŠãããã³ãããä»»æã®åœ¢åŒã®æååã«å€æããããšãã§ããŸãã
PromptoGenã§ã¯æ§ã ãªåœ¢åŒããµããŒãããŠããŸãã
- KeyValue圢åŒ
key: value - JSON圢åŒ
{"key": "value"} - etc.
ããã³ãããã©ãŒãããåºæ¬æ§é
formatter.format_prompt ã¡ãœããã䜿çšããŠãããã³ãããšããã«å¯Ÿããå
¥åãæååã«å€æã§ããŸãã
key: value 圢åŒã®ããã³ããã®ãã©ãŒãããã䜿çšããã«ã¯ãpg.KeyValuePromptFormatterã䜿çšããŸãã
ãã©ã¡ãŒã¿æ
å ±ããã³ãã¬ãŒãã衚瀺ãããã©ãã㯠PromptFormatterConfig ã§èšå®ã§ããŸãã
ãã©ãŒããããããããã³ããæååã¯ã以äžã®ãããªåºæ¬çãªæ§é ãæã¡ãŸãã
import promptogen as pg
summarizer = pg.Prompt(
name="Text Summarizer and Keyword Extractor",
# ...
)
formatter = pg.KeyValuePromptFormatter()
input_value = {
"text": "In the realm of software engineering, ...(ç¥)",
}
print(formatter.format_prompt(summarizer, input_value))
Summarize text and extract keywords.
Input Parameters:
- text: Text to summarize
Output Parameters:
- summary: Summary of text
- keywords: Keywords extracted from text
Template:
Input:
text: "This is a sample text to summarize."
Output:
summary: "This is a summary of the text."
keywords: ['sample', 'text', 'summarize']
Example 1:
Input:
text: "One sunny afternoon, ...(ç¥)"
Output:
summary: "A group of friends enjoyed an afternoon playing sports and making memories at a local park."
keywords: ['friends', 'park', 'sports', 'memories']
--------
Input:
text: "In the realm of software engineering, ...(ç¥)"
Output:
å€§èŠæš¡èšèªã¢ãã«ããã®åºåã®ããŒã¹
ããã»ã©ã®ããã³ããæååãå ¥åãšããŠãå€§èŠæš¡èšèªã¢ãã«(GPT-3.5, GPT-4ãªã©)ããåºåãåŸãŸãã
summary: "This is a summary of the text."
keywords: ['sample', 'text', 'summarize']
formatter.parse ã䜿ã£ãŠãåºåãããŒã¹ããŠã¿ãŸããçµæã¯ dict åã®å€ãšãªããŸãã
import promptogen as pg
formatter = pg.KeyValuePromptFormatter()
raw_resp = """summary: "This is a summary of the text."
keywords: ['sample', 'text', 'summarize']"""
summarized_resp = formatter.parse(summarizer, raw_resp) # `dict`åã§è¿ã
print(summarized_resp)
{'summary': 'This is a summary of the text.', 'keywords': ['sample', 'text', 'summarize']}
PromptRunner: ããã³ããå®è¡ãå¹ççã«
pg.PromptRunnerã¯ãããã³ããã®å®è¡ãã·ã³ãã«ã«ããã€å¹ççã«ãµããŒãããŸãã
PromptRunnerã䜿ã£ãããã³ããå®è¡
import promptogen as pg
# `pg.TextLLM`ã€ã³ã¿ãŒãã§ã€ã¹ãå®è£
ããLLMãçšæ
text_llm = YourTextLLM(model="your-model")
formatter = pg.KeyValuePromptFormatter()
runner = pg.TextLLMPromptRunner(llm=text_llm, formatter=formatter)
summarizer = pg.Prompt(
name="Text Summarizer and Keyword Extractor",
# ...
)
input_value = {
"text": "In the realm of software engineering, ...",
}
output_value = runner.run_prompt(summarizer, input_value)
print(output_value)
pg.PromptRunnerã¯ãPromptoGenã䜿ã£ãããã³ããã®å®è¡ãããçŽæçã§å¹ççã«ããããã®ããŒãšãªãããŒã«ã§ãã
å¿çšäŸ
ããã€ãPromptoGenã䜿ã£ãå¿çšäŸãã¿ãŠã¿ãŸãããã
å¿çšäŸ1: ããã³ããå®è¡ã®ã€ã³ã¿ãŒã»ãã¿
ããã³ããå®è¡ã®ã€ã³ã¿ãŒã»ãã¿
TextLLMPromptRunner ã§ã¯ãããã³ããã®ååŠçãåŸåŠçãè¡ãããã«ãã€ã³ã¿ãŒã»ãã¿(PromptInterceptor)ããšããã€ã³ã¿ãŒãã§ã€ã¹ããããŸãã
PromptInterceptor ã䜿ãããšã§ãããã³ããã®å®è¡åã«å
¥åãæžãæããããããã³ããã®å®è¡åŸã«åºåãæžãæãããããããšãã§ããŸãã
äŸãã°ã ValueTranslatorInterceptor ã䜿ãã°ã ãŠãŒã¶ãŒã¯æ¥æ¬èªã§éä¿¡ããŠããããã«ã¿ããããå®éã®LLMãšã®éä¿¡ã¯è±èªã§è¡ã ããšãã§ããŸãã
å ¥åºå翻蚳ã€ã³ã¿ãŒã»ãã¿å®è£ äŸ
ãã®ãããªè€éãªåŠçã PromptoGen ã§ã¯æ°è¡å€æŽããã ãã§å®çŸã§ããŸããå®éã®ããã³ããå®è¡çšã®LLMãšã翻蚳çšã®LLMã¯ããããå¥ã®ãã®ã䜿ãããšãã§ããŸãã
import promptogen as pg
from promptogen.prompt_interceptor.translate_interceptor import ValueTranslatorInterceptor
formatter = pg.KeyValuePromptFormatter()
llm = YourTextLLM(model="your-model")
translator_llm = YourTextLLM(model="your-model-translator")
interceptors = [
ValueTranslatorInterceptor(llm=translator_llm, from_lang="Japanese", to_lang="English"),
]
prompt_runner = pg.TextLLMPromptRunner(llm=llm, formatter=formatter, interceptors=interceptors)
# ...(ç¥)
å¿çšäŸ2: ããã³ããèªåçæ
ããã³ããèªåçæ
pg.Prompt ããŒã¿ã¯ã©ã¹ã dict ã§è¡šããã®ã§ããããã³ãã説æããšãäœæèæ¯ããå
¥åãšããããã³ãããçæãããããšãã§ããŸãã
PromptoGen ã§ã¯ããã€ãäºåã«å®çŸ©ãããããã³ãããããããã®ãã¡ã®äžã€ã§ãã PromptCreatorPrompt ã¯æ¬¡ã®ãããªå³ã§è¡šãããå
¥åºåãã©ã¡ãŒã¿ãæã¡ãŸãã
ããã³ããèªåçæå®è£ äŸ
å®éã«ããã³ããèªåçæãè¡ãã³ãŒããèŠãŠã¿ãŸãããã
ä»åã¯ãæè(context)ãšè³ªå(question)ãå ¥åãšããåç(answer)ãåºåãã ãšããããã³ãããäœæããŸãã
import promptogen as pg
from promptogen.prompt_collection import PromptCreatorPrompt
llm = YourTextLLM(model="your-model")
formatter = pg.KeyValuePromptFormatter()
prompt_runner = pg.TextLLMPromptRunner(llm=llm, formatter=formatter)
prompt_creator_prompt = PromptCreatorPrompt()
def create_context_qa_prompt() -> pg.Prompt:
input_value = {
# ããã§ããã³ããã®èª¬æãå®çŸ©
"description": "Answer the question for the given context.",
# ããã§ããã³ããã®äœæèæ¯ãå®çŸ©
"background": "(context: str, question: str) -> (answer: str)",
}
resp = prompt_runner.run_prompt(prompt_creator_prompt, input_value=input_value)
return pg.Prompt.from_dict(resp["prompt"])
context_qa_prompt = create_context_qa_prompt()
input_value = {
"context": "倪éã¯è±åã«è±æãæž¡ããã",
"question": "倪éã¯èª°ã«è±æãæž¡ããïŒ",
}
output_value = prompt_runner.run_prompt(context_qa_prompt, input_value=input_value)
print(output_value)
{'answer': 'è±å'}
ãã®ããã«ãPromptoGenã§ã¯ãããã³ããã®èªåçæ ãš ããã³ããã®å®è¡ ãå¹ççã«è¡ãããšãã§ããŸãã
ïŒè©³çްã¯ããã³ããèªåçæãåç §ããŠãã ãããïŒ
ãã詳现ã«ç¥ãããæ¹ãž
ããã¥ã¡ã³ããåç §ããŠãã ããã
- å®éã«å§ããæ¹ïŒ ã¯ããã«
- å¿çšäŸãèŠããæ¹ïŒå¿çšäŸ
ãœãŒã¹ã³ãŒã
ã¹ã¿ãŒããŠãããããšåã³ãŸã
ãŸãšã
PromptoGenã¯ããå¹ççã§æ¡åŒµå¯èœãªãå€§èŠæš¡èšèªã¢ãã«(LLM)ãšã®ã³ãã¥ãã±ãŒã·ã§ã³ãå®çŸããã ãšããããžã§ã³ã®å ããããŠå ·äœçãªLLMå®è£ ãžã®äŸåæ§ããªãããæœè±¡åãè¡ã ããšã§ãä»åŸã®LLMé²åã«ã€ããŠè¡ããããåºç€ãäœã OSSãããžã§ã¯ãã§ãã
å€ãã®LLMé¢é£ã©ã€ãã©ãªãæ±ãã課é¡ã解決ããããã«ãPromptoGenã¯ä»¥äžã®ãããªç¹åŸŽãæã¡ãŸãã
-
ããã³ãããšã³ãžãã¢ãªã³ã°ã®ãšã³ã·ã¹ãã 圢æ:
pg.PromptããŒã¿ã¯ã©ã¹ -
LLMå®è£
ããã®ç¬ç«æ§ç¢ºä¿:
pg.TextLLMã€ã³ã¿ãŒãã§ã€ã¹ -
ã«ã¹ã¿ãã€ãºæ§ã®åäž:
pg.PromptFormatterã€ã³ã¿ãŒãã§ã€ã¹
æ¡åŒµæ§ãé«ããããPromptoGenã¯ããŸããŸãªå¿çšãå¯èœã§ãã
ãããã«
ãããŸã§èªãã§ããã ããããããšãããããŸããïŒ
ç§ã¯ãæ ªåŒäŒç€Ÿãã¬ããžã¯ãŒã¯ã®AIããŒã ã§ãæ®æ®µã¯Goã®ããã¯ãšã³ãéçºãå€§èŠæš¡èšèªã¢ãã«(LLM)ãæŽ»çšãããããã¯ãéçºãè¡ã£ãŠããŸãã
PromptoGenã¯ãç§ãå人éçºãšããŠå§ãããã®ã§ããããã¬ããžã¯ãŒã¯ã®ããã¬ããžã¹ãã³ãµãŒã·ããããšããå¶åºŠãçšããŠãæ¥åæéå ã«éçºãè¡ãããšãã§ããŸããã
ã©ã€ãã©ãªã®æ¹åãè¡ã£ãããæ¥è±ã®ããã¥ã¡ã³ãäœæãªã©ãè¡ããšãªããšãå人éçºãšããŠã¯æéãããããå ¬éããã«è³ããŸã§é£ããéšåããããŸãããããã¬ããžã¯ãŒã¯ã®å¶åºŠã䜿ãããšã§ãååãªæéã確ä¿ã§ãããããããè¯ãã©ã€ãã©ãªãäœãããšãã§ãããšæããŸãã
å®éã«ã瀟å ã«ãããŠããPromptoGenãçšããŠLLMãã³ãããŒã¯ãåã£ãŠã¿ããªã©ãPromptoGenã®æŽ»çšäŸããããä»åŸããã¬ããžã¯ãŒã¯ã®AIããŒã ã§æŽ»çšããŠãããããšèããŠããŸãã
ãŸãããã¬ããžã¯ãŒã¯ã§ã¯æ¡çšãç©æ¥µçã«è¡ã£ãŠããŸãã®ã§ãèå³ã®ããæ¹ã¯X(Twitter) DMãªã©ããã²ã声ãããã ããã
ç¹ã«ãMLOps ãªã©ã®åéã«èå³ã®ããããã¯ãšã³ããšã³ãžãã¢ã®æ¹ãããã°å€§æè¿ã§ãïŒïŒããã¯ãšã³ãïŒããã³ããšã³ãå šäœçã«åéããŠãŸãïŒïŒ
äžç·ã«éçºããŸãããïŒ
PromptoGenã¯ããŸã ãŸã æ¹åã®äœå°ããããŸããããããã®ã©ã€ãã©ãªã«èå³ãæã£ãŠããã ããæ¹ãããã£ããããŸãããããã²ãIssueãPull Requestãéã£ãŠããã ãããšå¬ããã§ãã
ãªãªãŒã¹æ å ±ã¯ PromptoGen (@PromptoGen) ã§ãç¥ããããŠããäºå®ã§ãã
ããããã·ã§ã¢ããã©ããŒãªã©ããããããé¡ãããŸãïŒ
ïŒäœè ããããããé¡ãããŸããâ zawakin(@zawawahoge) ïŒ
åèã«ãããããžã§ã¯ã
ãã¬ããžã¯ãŒã¯ã¯ãLIFE WITH ENABLEMENT ã§ããåã³ãå·¡ãæ¥ã ãå±ããããããã·ã§ã³ã«æ²ããåã人ãã¡ã®ã€ããŒãã«ã¡ã³ãïŒææã®åµåºãèœåã®åäžïŒãæ¯æŽããã¹ã¿ãŒãã¢ããã§ããæ¬ããã°ã§ã¯ããã¬ããžã¯ãŒã¯ã®æè¡æ å ±ãçºä¿¡ããŠããŸãã
Discussion