見出し画像

ChatGPTにシナリオからセリフとナレーションを抽出するPythonのプログラムを作ってもらったら

マンガ原作(シナリオ)からセリフ・ナレーションだけ抜き出したい


 最近、マンガ原作の書き方の本をAmazon Kindle Direct Publishingで出しましたが、この本は、オリジナルマンガでも原作(シナリオ)を書いてからネームに取りかかることを紹介しています。現在は〈秀丸エディタ〉でシナリオを書き、これを編集者に見せてOKをもらってから、コマ割りのネームに取りかかります。

https://www.amazon.co.jp/dp/B0CBR18D7Y/mitsurusugaya-22/

 ストーリーと演出の作業を切り分けるために、このような方法を採っていますが、面倒なのはシナリオからセリフやナレーションの部分だけを抜き出す作業。〈秀丸エディタ〉で置換機能を駆使して「 」や( )で囲まれたセリフとナレーションを抜き出し、さらに、抽出されたテキストを〈分かち書き〉しなければいけません。

 いちおうですが〈分かち書き〉とは、文章を区切りのいいところで改行し、読みやすくするもの。小学一年生の国語の教科書も、最初の頃だけ〈分かち書き〉で書かれています。マンガのセリフは、この分かち書きで書かれているために、読みやすくなっているのです。マンガの「読みやすさ」を支えているのは、この〈分かち書き〉と〈総ルビ〉にあると、編集者の経験がある私は考えています。

 このシナリオからのセリフとナレーションの切り出しも、Pythonを使った専用アプリを使えば簡単になりそうだと考え、自分でプログラミングをはじめました。

 しかし、すぐに手が止まってしまいました。いちおうPythonも基礎的なことは一通り大学院で学び、データベースとリンクさせたり、Google App Engineを使ったミニブログを作ったり、なんてこともしてきました。

 統計計算専用のWebサイトもPythonをCGIにして作り、「こんにちは統計学」という名前で公開しています。

Python CGIによる統計計算「こんにちは統計学」
 ― χ2検定・t検定・U検定・分散分析・相関係数 ―

 また、Pythonのプログラミングについては、『ゲームセンターあらしと学ぶプログラミング入門 まんが版「こんにちはPython」』(日経BP、2020年5月刊)という本も上梓しています。

 そんなわけでPythonのプログラミングもチョチョイのチョイ……だと思われるでしょうが、そうは問屋がおろしません。日常的にプログラミングをしているわけではなく、また72歳という高齢のために、命令語や文法が出てこないのです。そのためプログラミングをするたびに、FIFAレンスを調べたり、参考になりそうなサイトを探したり……ということになります。

ChatGPTで最初にゲームを作ってみた

「ひょっとして、こんなことも生成AIに頼めるのでは?」と思いついたのは、『こんにちはPython』で作成したスカッシュ・ゲームのプログラミングをChatGPTに頼んだら、一瞬のうちに作ってしまった経験があったから。ただし最初はバグがあり、そこを指摘したら、これも一瞬で修正してくれました。そのときのやりとりです。
(プログラムは、noteの仕様の関係でインデントが表現できないため、半角スペース2個を全角スペース1個に変換しています。また半角「#」を全角「#」に変換しています)


User
スカッシュゲームのプログラムを作ってください。言語はPythonでお願いします。

ChatGPT
はい、スカッシュゲームのプログラムをPythonで作成することができます。以下がサンプルコードになります。

python
Copy code
import turtle
import random

# ゲーム画面の設定
win = turtle.Screen()
win.title("スカッシュゲーム")
win.bgcolor("black")
win.setup(width=600, height=600)

# パドルの作成
paddle = turtle.Turtle()
paddle.shape("square")
paddle.color("white")
paddle.shapesize(stretch_wid=1, stretch_len=5)
paddle.penup()
paddle.goto(0, -250)

# ボールの作成
ball = turtle.Turtle()
ball.shape("circle")
ball.color("white")
ball.penup()
ball.goto(random.randint(-200, 200), 250)
ball.dy = -5
ball.dx = random.choice([-5, 5])

# スコアの表示
score = 0
pen = turtle.Turtle()
pen.speed(0)
pen.color("white")
pen.penup()
pen.hideturtle()
pen.goto(0, 260)
pen.write("スコア: {}".format(score), align="center", font=("Courier", 24, "normal"))

# パドルの動き
def move_left():
  x = paddle.xcor()
  x -= 20
  if x < -280:
    x = -280
  paddle.setx(x)

def move_right():
  x = paddle.xcor()
  x += 20
  if x > 280:
    x = 280
  paddle.setx(x)

# キーボード操作の設定
win.listen()
win.onkeypress(move_left, "Left")
win.onkeypress(move_right, "Right")

# ゲームループ
while True:
  # ボールの移動
  ball.setx(ball.xcor() + ball.dx)
  ball.sety(ball.ycor() + ball.dy)

  # 壁との反射
  if ball.xcor() > 290 or ball.xcor() < -290:
    ball.dx *= -1
  
  # パドルとの反射
  if (ball.ycor() < -240) and (ball.xcor() < paddle.xcor() + 50) and (ball.xcor() > paddle.xcor() - 50):
    ball.dy *= -1
    score += 1
    pen.clear()
    pen.write("スコア: {}".format(score), align="center", font=("Courier", 24, "normal"))
  
  # ゲームオーバー
  if ball.ycor() < -290:
    pen.clear()
    pen.write("ゲームオーバー", align="center", font=("Courier", 24, "normal"))
    break

# ゲーム終了処理
win.mainloop()


このプログラムは、Pythonのturtleモジュールを使用しています。プログラムを実行すると、パドルを左右に移動してボールを打ち返し、壁やパドルに当たって反射するようになっています。ボールが画面下部に落ちるとゲームオーバーになります。また、スコアも表示されます。

User
試してみました。横の壁にボールが当たると跳ね返ってきますが、天井に向かったボールは、そのまま上に進んで返ってきません。

ChatGPT
すみません、ボールが天井に当たった場合に反射しないようになっていました。以下のように、天井に当たった場合も反射するように修正してください。

python
Copy code
# ゲームループ
while True:
  # ボールの移動
  ball.setx(ball.xcor() + ball.dx)
  ball.sety(ball.ycor() + ball.dy)

  # 壁との反射
  if ball.xcor() > 290 or ball.xcor() < -290:
    ball.dx *= -1
  
  # 天井との反射
  if ball.ycor() > 290:
    ball.dy *= -1
  
  # パドルとの反射
  if (ball.ycor() < -240) and (ball.xcor() < paddle.xcor() + 50) and (ball.xcor() > paddle.xcor() - 50):
    ball.dy *= -1
    score += 1
    pen.clear()
    pen.write("スコア: {}".format(score), align="center", font=("Courier", 24, "normal"))
  
  # ゲームオーバー
  if ball.ycor() < -290:
    pen.clear()
    pen.write("ゲームオーバー", align="center", font=("Courier", 24, "normal"))
    break

# ゲーム終了処理
win.mainloop()


このように修正することで、天井に当たった場合も反射するようになります。ご確認ください。

User
こんどは大丈夫でした。ありがとう。感謝します。

ChatGPT
どういたしまして。何か他にも質問があれば、遠慮なくお聞きください。お手伝いできることがあれば、喜んでお手伝いいたします。

シナリオからのセリフの抜き出しを頼んだら

 ChatGPTには、マンガや小説のストーリー作りなどの相談にも乗ってもらっていて、その〈対話〉の経過と結果から、「フィクションには使える!」という実感を得ています。ただしシナリオなどをまるまる書いてもらうのではなく、「アイデアや発想を膨らませる手伝いをしてもらう」という使い方。〈疲れない対話相手〉として、自分のアイデアポンプを活性化させるのに便利な相棒となっています。もちろんパクリや盗用にはならないよう、充分、注意もしています。

 というわけで、シナリオからのセリフとナレーションの抽出をするPythonのプログラム作成も、ChatGPTに依頼してみました。


User
Pythonを使って日本語のシナリオからセリフ部分だけを抽出し、テキストファイルとして保存するプログラムは作れるでしょうか?

ChatGPT
もちろん可能です。日本語のシナリオからセリフ部分を抽出するための基本的なPythonコードを以下に示します。このコードは、シナリオが「キャラクター名: セリフ」という形式で書かれていることを前提としています。

python
Copy code
import re

def extract_dialogue(input_file, output_file):
  with open(input_file, 'r', encoding='utf-8') as f_in, open(output_file, 'w', encoding='utf-8') as f_out:
    lines = f_in.readlines()
    for line in lines:
      # 「:」を含む行のみを抽出し、その後の部分をセリフとみなす
      if ':' in line:
        dialogue = line.split(':', 1)[1].strip()
        f_out.write(dialogue + '\n')

# 使用例
extract_dialogue('input_scenario.txt', 'output_dialogue.txt')

このコードは、指定された入力ファイルから行を読み取り、その行に「:」が含まれている場合、それ以降のテキストをセリフとみなします。セリフは出力ファイルに書き出されます。

ただし、このコードはあくまで基本的なものであり、特定の形式のシナリオにしか適用できません。シナリオの形式や複雑さによっては、より高度なテキスト解析や自然言語処理の手法が必要になる場合もあります。具体的なシナリオの形式によっては、このコードを適応的に修正する必要があります。

User
ありがとうございます。標準的な日本語のシナリオでは、セリフの部分は「」でくくられています。この「と」の間のセリフを抜き出すことはできるでしょうか。

ChatGPT
はい、それは可能です。Pythonの正規表現モジュール re を使って、ダブルクォートや他の特定の文字で囲まれたテキストを抽出できます。以下に示すコードは、「」で囲まれた部分(日本語のシナリオにおけるセリフ)を抽出します。

python
Copy code
import re

def extract_dialogue(input_file, output_file):
  with open(input_file, 'r', encoding='utf-8') as f_in, open(output_file, 'w', encoding='utf-8') as f_out:
    text = f_in.read()
    dialogues = re.findall(r'「(.*?)」', text)
    for dialogue in dialogues:
      f_out.write(dialogue + '\n')

# 使用例
extract_dialogue('input_scenario.txt', 'output_dialogue.txt')

このコードでは、re.findall 関数を使って、引数のテキスト中のすべての「」で囲まれた部分を抽出します。抽出した各セリフは出力ファイルに書き出されます。

注意点として、この正規表現 「(.*?)」 は最小のマッチを返します。つまり、「」が複数回現れる長い行でも、それぞれの「」で囲まれた部分が別々のセリフとして抽出されます。

ただし、このコードもシナリオの形式が特定のパターンに従っていることを前提としています。シナリオの形式がこれと異なる場合や、より複雑な場合は、コードを適応的に修正するか、より高度なテキスト解析手法が必要になる場合があります。

User
ありがとうございます。このプログラムを試してみます。問題があったら、また相談させていただきます。

ChatGPT
ぜひお試しください。もし何か問題がありましたら、いつでもご質問ください。Pythonやテキスト解析に関する質問はどんなものでもお答えします。どういった結果になるか楽しみにしています。


自分で改造してナレーションの抽出もできるようになったのですが、さらなる欲望が……


User
前につくっていただいたPythonのプログラムを少し改造して、次のように改造しました。現在のところ快調に動いています。

このプログラムは、"「 」"、"( )"に囲まれたテキストのみを抽出するものです。

import re

def extract_dialogue(input_file, output_file):
  with open(input_file, 'r', encoding='utf-8') as f_in, open(output_file, 'w', encoding='utf-8') as f_out:
    text = f_in.read()
    dialogues = re.findall(r'「([」)]', text)
    for dialogue in dialogues:
      f_out.write(dialogue + '\n\n')

# 使用例
extract_dialogue('input_dialogue.txt', 'output_dialogue.txt')

 このプログラムを改造して、抽出したテキストのうち ”、"や"。"の記号を改行コードに変換したいのですが、できますでしょうか?

ChatGPT
もちろん、そのような改造も容易です。既存のプログラムを少し変更して、「、」や「。」を改行コードに変換する処理を追加します。

以下のプログラムは、指定された記号を改行コードに変換した後、出力ファイルに結果を書き込むようにしています。

python
Copy code
import re

def extract_dialogue(input_file, output_file):
  with open(input_file, 'r', encoding='utf-8') as f_in, open(output_file, 'w', encoding='utf-8') as f_out:
    text = f_in.read()
    dialogues = re.findall(r'「([」)]', text)
    for dialogue in dialogues:
      # 「、」や「。」を改行コードに変換
      modified_dialogue = dialogue.replace('、', '\n').replace('。', '\n')
      f_out.write(modified_dialogue + '\n\n')

# 使用例
extract_dialogue('input_dialogue.txt', 'output_dialogue.txt')

このコードの replace メソッドにより、対象のテキストの「、」や「。」が改行コードに変換されます。変換後のテキストは出力ファイルに書き込まれます。

User
テストしてみたところ、無事に動きました。ありがとうございました。

ChatGPT
良かったです!もし今後も何か質問や問題がありましたら、いつでもご相談ください。プログラムの作成や改善、その他の情報に関してサポートいたします。成功をお祈りしています!


 ここまででもかなり実用になるプログラムになったのですが、さらに〈分かち書き〉の補助として「句読点があったらこれを除去して改行する」「!・?・!?があったら記号を残して改行する」「全角スペースは除去する」機能を追加しました。それが以下のプログラムです(自作していたときに思い出せず苦労したのは連続する「replace」の使い方でした)。


import re

def extract_dialogue(input_file, output_file):
  with open(input_file, 'r', encoding='utf-8') as f_in, open(output_file, 'w', encoding='utf-8') as f_out:
    text = f_in.read()
    dialogues = re.findall(r'「([」)]', text)
    for dialogue in dialogues:
      # 「、」や「。」を改行コードに変換
      modified_dialogue = dialogue.replace('、', '\n').replace('。', '\n').replace('!', '!\n').replace('?', '?\n').replace('!?', '!?\n').replace(' ', '\n')
      f_out.write(modified_dialogue + '\n\n')

# 使用例
extract_dialogue('input_scenario.txt', 'output_dialogue.txt')


 このプログラムを「input_scenario.txt」のあるフォルダに置き、実行するだけで、一瞬にして「output_dialogue.txt」が出来上がります(もちろんPythonをインストールしておく必要があります)。

 変換前の「input_scenario.txt」と変換後の「output_dialogue.txt」は次のとおりです。テキストに使ったのは『艦これ』をテーマにした雑誌「みたいな! Vol.3」(KADOKAWA、2023年7月発売)に掲載の連載マンガ『空飛び娘、ひらり』の原作シナリオです。


★input_scenario.txt

『空飛び娘、ひらり』第3回シナリオ

                   すがやみつる

◆砂塵を巻きあげながら風が吹くアリゾナ州のさびれた町――
 商店の壁に貼られた『エアコンバット』のポスターが風に揺れている。
 ポスターには、ひらりの顔が大きく印刷され、「エアコンバット・アリゾナ大会来たる! 優勝賞金1万ドル。飛び入り大歓迎!」の文字が躍る。
 そのポスターの前に立つ人影。手が伸びてポスターを引き剥がすと、ひらりの写真を注視し、「ふん……」と冷たくつぶやく。

◆アリゾナ州の州都フェニックスの郊外に広がる砂漠――
 その中に延びる1本の滑走路の上空で、多数の戦闘機が乱舞する。
 滑走路の脇には仮設のスタンドが並び、数千人の観客が「ワーワー」と歓声をあげている。
アナ「1947年度エアコンバット選手権の第7戦は、ここアリゾナ州フェニックス郊外の会場で開催! エアショーやエアレースが終了後、メインイベントのエアコンバットが、いまスタート!」
 とアナの実況。
アナ「これまではトーナメント方式で戦われたエアコンバットですが、今回は、参加する全機が一同に戦うバトルリワイヤル形式! 12機が参加する戦闘で、最後まで生き残るのは誰だ!?」
 上空では12機の戦闘機が入り乱れている。
 (後略)

★output_dialogue.txt

商店の壁に貼られた『エアコンバット』のポスターが風に揺れている

エアコンバット・アリゾナ大会来たる!

優勝賞金1万ドル
飛び入り大歓迎!

ふん……

ワーワー

1947年度エアコンバット選手権の第7戦は
ここアリゾナ州フェニックス郊外の会場で開催!

エアショーやエアレースが終了後
メインイベントのエアコンバットが
いまスタート!

これまではトーナメント方式で戦われたエアコンバットですが
今回は
参加する全機が一同に戦うバトルリワイヤル形式!

12機が参加する戦闘で
最後まで生き残るのは誰だ!?


 このマンガが載っているのは、こちらの雑誌です。

  こちらが1ページ目と2ページ目です。

『空飛び娘、ひらり』第3回(「みたいな!」Vol.4掲載)P1
『空飛び娘、ひらり』第3回(「みたいな!」Vol.4掲載)P2-3

〈分かち書き〉については、コマの大きさに合わせて手を加える必要がありますが、手作業で数十分から数時間かかっていたセリフとナレーションの抽出作業(ページ数による。多いものは180ページ以上)が、本当に〈一瞬!〉で終わってしまいます。この〈時間の節約〉は、残り時間が少ない高齢者にとって、とても貴重なことだと実感しています。

 何かと話題になっている生成AIですが、高齢のために脳細胞が日々死滅している高齢者にとっては、記憶や発想の衰えを補完してくれたり、また、脳細胞を活性化するうえでも、とても有用なツールだと実感しています。生成AIに違和感を覚え、頭から否定する人もいますが、まず試してみてはいかがでしょう?


この記事が気に入ったらサポートをしてみませんか?