Spaces:
Sleeping
Sleeping
| import os | |
| import requests | |
| import textwrap | |
| import gradio as gr | |
| from bs4 import BeautifulSoup | |
| from spiralfilm import FilmCore, FilmConfig | |
| from logging import getLogger, DEBUG, StreamHandler | |
| logger = getLogger() | |
| logger.setLevel(DEBUG) | |
| handler = StreamHandler() | |
| handler.setLevel(DEBUG) | |
| logger.addHandler(handler) | |
| identity_prompt = """ | |
| 以下に述べるような特徴がありますが、日本語として不自然になる場合は、日本語の自然さを優先します。 | |
| 一人称は「ボク」。本名は「パスカル」。 | |
| 二人称として、「キミは」などをたまに使うことがあります。 | |
| 「~だね!」「~したようだね」「~だよ!」といったカジュアルな表現の話し方を好みます。 | |
| """ | |
| pascal_prompt = """ | |
| 以下順番で文書を作成してください。【追加指示】がある場合はその内容に従ってください。読点の後には改行を入れてください。 | |
| 1.一行目は企業名のみを記載 | |
| ※企業名については、以下の規則にしたがってください。 | |
| ・文頭と文末に「*」を必ず入れる。 | |
| 2.二行目に30文字程度でリード文を記載する。 | |
| ※リード文については、以下の規則にしたがってください。 | |
| ・文頭と文末に「*」を必ず入れる。 | |
| ・リード文は必ず一行かつ体言止めで記載する。 | |
| 3.三行目は「`リリースの詳細について`」と記載する。 | |
| ※リリース詳細については、以下の規則にしたがってください。 | |
| ・「`リリースの詳細について`」の後に本の絵文字を入れる。 | |
| 4.四行目以降に要約を記載する。 | |
| ※要約については、以下の規則に従ってください。 | |
| ・要約の際は必ず常体(~だ。~である。口調)で記載する。 | |
| ・技術的な詳細が含まれる場合は、それを要約に含める。 | |
| ・30文字を超えた場合は改行する。 | |
| 5.最後に必ず「`パスカル君のひとこと`」を100文字程度で作成する。 | |
| ※パスカル君のひとことは、以下の規則に従ってください。 | |
| ・「`パスカル君のひとこと`」の後にキツネの絵文字を入れる。 | |
| ・技術的な意見を1行以上含むように作成する。 | |
| ・3回に1回くらいポジティブな言い回しで肯定しつつ、最後に!マークをつける。 | |
| ・必ず要約の内容に沿った絵文字を入れる。 | |
| ・1つの文章に入れる絵文字は1個までとする。 | |
| ・ひとことコメントの最後には技術への期待を追加する。 | |
| ・休み明けで更新が3日以上空いたときは〇〇休暇明けだよみたいな発信をする。 | |
| ・世の中の時代背景と関連したコメントを記載する。 | |
| ・人の気持ちに寄り添うようなコメントを記載する。 | |
| """ | |
| async def summarize(input_text: str, input_url: str, additional_order: str): | |
| config = FilmConfig( | |
| "gpt-4-32k", | |
| api_type="azure", | |
| azure_deployment_id="gpt-4-32k", | |
| azure_api_version="2023-05-15", | |
| timeout=60.0, # これを入れないとtimeoutが頻繁に発生する | |
| ) | |
| config.get_apikey() | |
| if input_text: | |
| _prompt = f""" | |
| {input_text} | |
| 上記の文章を情報量を落とさずに要約してください。 | |
| {pascal_prompt} | |
| {f"【追加指示】: {additional_order}"} | |
| """ | |
| return await FilmCore( | |
| prompt=textwrap.dedent(_prompt), | |
| system_prompt=textwrap.dedent(f"{identity_prompt}"), | |
| config=config | |
| ).run_async() | |
| if input_url: | |
| try: | |
| res = requests.get(input_url) | |
| soup = BeautifulSoup(res.text) | |
| url_content = soup.find('title').text + '\n' + soup.find('body').text | |
| _prompt = f""" | |
| {url_content} | |
| 上記の文章を情報量を落とさずに要約してください。 | |
| {pascal_prompt} | |
| {f"【追加指示】: {additional_order}"} | |
| """ | |
| except Exception as e: | |
| logger.error(e) | |
| raise gr.Error("WEBページの取得に失敗しました。") | |
| return await FilmCore( | |
| prompt=textwrap.dedent(_prompt), | |
| system_prompt=textwrap.dedent(f"{identity_prompt}"), | |
| config=config | |
| ).run_async() | |
| else: | |
| raise gr.Error("LLM APIの呼び出しに失敗しました。") | |
| def validate_input_form(input_text, input_url): | |
| input_value = input_text + input_url | |
| # Check if the text is not blank | |
| if len(input_value) < 1: | |
| raise gr.Error("テキストかURLを入力してください。") | |
| else: | |
| return | |
| async def chat(input_text, input_url, additional_order): | |
| validate_input_form(input_text, input_url) | |
| summary = await summarize(input_text, input_url, additional_order) | |
| logger.info(f"summary: {summary}") | |
| result = summary | |
| if input_url: | |
| result += f'\n{input_url}' | |
| return result | |
| with gr.Blocks() as iface: | |
| # UI | |
| gr.Markdown("# パスカルくん \n## 使い方 \nテキスト、もしくはURLにパスカルくんに分析させたい記事の内容やURLを入力して「回答生成」ボタンを押すと回答が出力されます。 \n※テキスト、URLの両方に入力して実行した場合は、**URLが優先されます。** \n※テキスト、URLの両方が**空の場合は実行できません。** 必ずいずれかを入力してから実行してください。 \n※追加指示から、パスカルくんに追加で指示を与えることができます。 例) 敬語で話してください") | |
| with gr.Row(): | |
| with gr.Column(): | |
| input_text = gr.Textbox(label="テキスト") | |
| input_url = gr.Textbox(label="URL") | |
| additional_order = gr.Textbox(label="追加指示") | |
| chat_btn = gr.Button("回答生成") | |
| with gr.Column(): | |
| output_text = gr.Textbox(label="回答") | |
| # Event handler | |
| chat_btn.click(fn=chat, inputs=[input_text, input_url, additional_order], outputs=output_text) | |
| gr.Markdown("## トラブルシューティング") | |
| with gr.Accordion(label="「LLM APIの呼び出しに失敗しました。」というエラーが表示された場合", open=False): | |
| gr.Markdown("### OpenAIサービス側で何らかのエラーが発生しています。1~2分ほど時間を置いてから再度お試しください。 \nそれでもエラーが解消されない場合は、入力しているテキスト量が大きすぎることが考えられます。 \n- テキストを入力して実行している場合は、入力文字数を減らしてからお試しください。 \n- URLを入力して実行している場合は、そのURLリンク先の内容を抜粋してテキスト入力欄にコピー&ペーストしてお試しください。") | |
| with gr.Accordion(label="「WEBページの取得に失敗しました。」というエラーが表示された場合", open=False): | |
| gr.Markdown("### 入力されたURLが対応しておりません。 \n大変お手数をおかけしますが別のURLを入力してお試しください。") | |
| if __name__ == "__main__": | |
| iface.launch(auth=(os.environ.get("GRADIO_USER_NAME"), os.environ.get("GRADIO_PASSWORD")), share=True, server_name="0.0.0.0") | |