ai.get_from_ai のソースコード

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
r"""
get_from_ai.py - AIサービスからの応答取得スクリプト

このスクリプトは、指定されたINIファイルからプロンプトを読み込み、
Google GeminiまたはOpenAI APIを利用してAIからの応答を取得し、
その応答を指定されたファイルパスに書き出します。

コマンドライン引数でINIファイル、出力ファイル、使用するAPI、モデルを指定できます。

:doc:`get_from_ai_usage`
"""

import os
import sys
import argparse
import re
from pathlib import Path
from openai import OpenAI
import google.generativeai as genai


[ドキュメント] def read_ini(path): """ 寛容な key=value 形式のINIファイルを読み込みます。 この関数は、`key=value` の形式で設定を読み込みます。 値が `\"\"\"` または `\'\'\'` で始まる場合、次の同じ記号が現れるまでをマルチラインの値として扱います。 また、ファイルに `key=` のない最初の有効な行が `\"\"\"` または `\'\'\'` で始まる場合、 または単にテキストである場合、その内容を `PROMPT` キーのマルチライン値として扱います。 :param path: 読み込むINIファイルのパス。 :type path: str :returns: INIファイルから読み込まれた設定を格納した辞書。 :rtype: dict :raises FileNotFoundError: 指定されたINIファイルが見つからない場合に発生します。 """ if not os.path.isfile(path): raise FileNotFoundError(f"INIファイルが見つかりません: {path}") result = {} buf = [] current_key = None multi = None first_valid_line = True with open(path, encoding="utf-8") as f: for line in f: line = line.rstrip() if not line or line.startswith(("#", ";")): continue # multi-line mode if multi: if line.strip() == multi: result[current_key] = "\n".join(buf) buf = [] multi = None else: buf.append(line) continue # key=value line if "=" in line: k, v = map(str.strip, line.split("=", 1)) if v in ('"""', "'''"): multi = v current_key = k buf = [] else: result[k] = v first_valid_line = False else: # 最初の有効行で = がない → multiライン開始と仮定 if first_valid_line: if line in ('"""', "'''"): multi = line current_key = "PROMPT" buf = [] else: # 開始記号がない場合でも、multiラインとして扱う multi = '"""' # 仮の閉じ記号(どちらでもよい) current_key = "PROMPT" buf = [line] first_valid_line = False else: # それ以降の =なし行は無視またはログ出力 pass # ファイル末尾まで multi-line が閉じられなかった場合 if multi and buf: result[current_key] = "\n".join(buf) return result
[ドキュメント] def call_ai(prompt, api="gemini", model=None): """ 指定されたプロンプトを使用してAIサービス(Google GeminiまたはOpenAI)を呼び出します。 この関数は、`api` 引数の値に基づいてGoogle GeminiまたはOpenAIのAPIを利用します。 APIキーは環境変数 `GOOGLE_API_KEY` または `OPENAI_API_KEY` から読み込まれます。 モデルが指定されない場合、環境変数 `GOOGLE_MODEL` または `OPENAI_MODEL`、 あるいはデフォルトのモデル (`gemini-2.5-flash`, `gpt-4o`) が使用されます。 :param prompt: AIに渡すプロンプト文字列。 :type prompt: str :param api: 使用するAIサービスを指定します ('gemini', 'openai', 'openai5')。 :type api: str :param model: 使用するAIモデルの名前(オプション)。指定しない場合は環境変数またはデフォルトが使用されます。 :type model: str or None :returns: AIからの応答テキスト。 :rtype: str :raises ValueError: 環境変数が未設定の場合、または未対応のAPIが指定された場合に発生します。 """ if api == "gemini": key = os.getenv("GOOGLE_API_KEY") if not key: raise ValueError("環境変数 GOOGLE_API_KEY が未設定です。") genai.configure(api_key=key) model = model or os.getenv("GOOGLE_MODEL", "gemini-2.5-flash") print(f"🚀 Gemini [{model}] 実行中...") m = genai.GenerativeModel(model) resp = m.generate_content(prompt) return resp.text elif api in ("openai", "openai5"): key = os.getenv("OPENAI_API_KEY") if not key: raise ValueError("環境変数 OPENAI_API_KEY が未設定です。") model = model or os.getenv("OPENAI_MODEL", "gpt-4o") print(f"🚀 OpenAI [{model}] 実行中...") client = OpenAI(api_key=key) if api == "openai5": r = client.responses.create(model=model, input=prompt) return r.output_text else: r = client.chat.completions.create(model=model, messages=[{"role": "user", "content": prompt}]) return r.choices[0].message.content else: raise ValueError(f"未対応API: {api}")
[ドキュメント] def main(): """ スクリプトのメインエントリーポイント。 コマンドライン引数を解析し、INIファイルからプロンプトを読み込み、 指定されたAIサービスを呼び出して応答を取得し、その結果を指定された出力ファイルに書き込みます。 プロンプトがINIファイルに見つからない場合はエラーで終了します。 """ p = argparse.ArgumentParser(description="get_from_ai.iniからプロンプトを読み込み、AI応答をファイルに出力") p.add_argument("--inifile", "-i", default="get_from_ai.ini", help="プロンプトを含むINIファイル (default: get_from_ai.ini)") p.add_argument("--output_path", "-o", required=True, help="AI応答を書き込む出力ファイルパス") p.add_argument("--api", "-a", choices=["gemini", "openai", "openai5"], default="gemini", help="使用するAPI") p.add_argument("--model", "-m", default=None, help="モデル名を明示指定(任意)") args = p.parse_args() print() data = read_ini(args.inifile) print(f"keys in [{args.inifile}]:") for key in data.keys(): print(f" {key}") prompt = data.get("PROMPT") or data.get("PROMPT_TEMPLATE_JA") or data.get("PROMPT_TEMPLATE_EN") if not prompt: print("❌ INIにPROMPTが定義されていません", file=sys.stderr) sys.exit(1) print("Prompt:", prompt) print(f"Requesting to {args.api}/{args.model}...") response = call_ai(prompt, api=args.api, model=args.model) Path(args.output_path).write_text(response.strip(), encoding="utf-8") print(f"✅ 出力ファイルを生成しました: {args.output_path}")
if __name__ == "__main__": main()