fastapi_django_main_live / controllers /conversation_logger.py
GitHub Action
🚀 Auto-deploy from GitHub Actions
55cbdc2
raw
history blame
22.3 kB
"""
会話履歴自動記録システム
=======================
GitHub Copilotとの会話を自動的にSQLiteに保存するためのフックシステム
使用方法:
1. このモジュールをインポート
2. log_conversation()を呼び出すだけで自動保存
3. セッション管理も自動化
"""
import uuid
import datetime
import json
import os
import traceback
import sqlite3
import subprocess
from typing import Optional, Dict, List
from controllers.conversation_history import ConversationManager
class ConversationLogger:
def __init__(self):
"""会話ログシステムの初期化"""
self.conversation_manager = ConversationManager()
self.current_session_id = self.generate_session_id()
self.session_start_time = datetime.datetime.now()
print(f"🎯 会話ログシステム開始 - セッションID: {self.current_session_id[:8]}")
def generate_session_id(self) -> str:
"""新しいセッションIDを生成"""
return str(uuid.uuid4())
def start_new_session(self, session_name: str = None) -> str:
"""新しいセッションを開始"""
self.current_session_id = self.generate_session_id()
self.session_start_time = datetime.datetime.now()
if session_name:
# セッション名を更新
try:
conn = sqlite3.connect(self.conversation_manager.db_path)
cursor = conn.cursor()
cursor.execute('''
UPDATE sessions
SET session_name = ?
WHERE session_id = ?
''', (session_name, self.current_session_id))
conn.commit()
conn.close()
except Exception as e:
print(f"⚠️ セッション名更新エラー: {e}")
print(f"🆕 新しいセッション開始: {self.current_session_id[:8]}")
return self.current_session_id
def log_conversation(self,
user_message: str,
assistant_response: str,
context_info: str = "",
files_involved: List[str] = None,
tools_used: List[str] = None,
tags: List[str] = None,
project_name: str = "ContBK統合システム") -> Optional[int]:
"""
会話を自動記録
Args:
user_message: ユーザーからのメッセージ
assistant_response: アシスタントの応答
context_info: コンテキスト情報
files_involved: 関連ファイルのリスト
tools_used: 使用ツールのリスト
tags: タグのリスト
project_name: プロジェクト名
Returns:
会話ID (保存に成功した場合)
"""
try:
# リストを文字列に変換
files_str = ", ".join(files_involved) if files_involved else ""
tools_str = ", ".join(tools_used) if tools_used else ""
tags_str = ", ".join(tags) if tags else ""
# 会話を保存
conversation_id = self.conversation_manager.save_conversation(
session_id=self.current_session_id,
user_message=user_message,
assistant_response=assistant_response,
context_info=context_info,
files_involved=files_str,
tools_used=tools_str,
tags=tags_str
)
print(f"✅ 会話を記録しました (ID: {conversation_id})")
return conversation_id
except Exception as e:
print(f"❌ 会話記録エラー: {e}")
print(traceback.format_exc())
return None
def log_tool_usage(self, tool_name: str, parameters: Dict, result: str):
"""ツール使用ログを記録"""
tool_info = {
"tool": tool_name,
"parameters": parameters,
"result": result[:500], # 結果は500文字まで
"timestamp": datetime.datetime.now().isoformat()
}
# 直前の会話にツール情報を追加
try:
conn = sqlite3.connect(self.conversation_manager.db_path)
cursor = conn.cursor()
# 最新の会話を取得
cursor.execute('''
SELECT id, tools_used FROM conversations
WHERE session_id = ?
ORDER BY timestamp DESC
LIMIT 1
''', (self.current_session_id,))
row = cursor.fetchone()
if row:
conversation_id, existing_tools = row
# 既存のツール情報に追加
updated_tools = existing_tools + f", {tool_name}" if existing_tools else tool_name
cursor.execute('''
UPDATE conversations
SET tools_used = ?, updated_at = CURRENT_TIMESTAMP
WHERE id = ?
''', (updated_tools, conversation_id))
conn.commit()
conn.close()
print(f"🔧 ツール使用を記録: {tool_name}")
except Exception as e:
print(f"⚠️ ツール使用記録エラー: {e}")
def get_session_summary(self) -> Dict:
"""現在のセッションの要約を取得"""
try:
conversations = self.conversation_manager.get_conversations(
session_id=self.current_session_id
)
return {
"session_id": self.current_session_id,
"start_time": self.session_start_time.isoformat(),
"conversation_count": len(conversations),
"duration_minutes": (datetime.datetime.now() - self.session_start_time).total_seconds() / 60,
"latest_conversation": conversations[0] if conversations else None
}
except Exception as e:
print(f"⚠️ セッション要約取得エラー: {e}")
return {}
def export_session(self, session_id: str = None) -> str:
"""セッションをJSON形式でエクスポート"""
target_session = session_id or self.current_session_id
try:
conversations = self.conversation_manager.get_conversations(
session_id=target_session
)
export_data = {
"session_id": target_session,
"export_time": datetime.datetime.now().isoformat(),
"conversation_count": len(conversations),
"conversations": conversations
}
filename = f"session_export_{target_session[:8]}_{datetime.datetime.now().strftime('%Y%m%d_%H%M%S')}.json"
with open(filename, 'w', encoding='utf-8') as f:
json.dump(export_data, f, ensure_ascii=False, indent=2)
print(f"📥 セッションエクスポート完了: {filename}")
return filename
except Exception as e:
print(f"❌ セッションエクスポートエラー: {e}")
return ""
def create_github_issue(self,
title: str = None,
session_id: str = None,
labels: List[str] = None,
assignee: str = None) -> bool:
"""
GitHub Issueを作成
Args:
title: Issue のタイトル(未指定の場合は自動生成)
session_id: 対象セッションID(未指定の場合は現在のセッション)
labels: 付与するラベル
assignee: アサイニー
Returns:
作成成功の可否
"""
try:
target_session = session_id or self.current_session_id
# 会話履歴を取得
conversations = self.conversation_manager.get_conversations(
session_id=target_session
)
if not conversations:
print("⚠️ 会話履歴が見つかりません")
return False
# タイトルを自動生成(未指定の場合)
if not title:
first_conversation = conversations[-1] # 最初の会話
title = f"開発セッション: {first_conversation.get('user_message', '')[:50]}..."
# Issue本文を生成
issue_body = self._generate_issue_body(conversations, target_session)
# GitHub CLI を使用してIssue作成
cmd = [
'gh', 'issue', 'create',
'--title', title,
'--body', issue_body
]
# ラベルを追加
if labels:
for label in labels:
cmd.extend(['--label', label])
# アサイニーを追加
if assignee:
cmd.extend(['--assignee', assignee])
# コマンド実行
result = subprocess.run(cmd, capture_output=True, text=True, cwd='/workspaces/fastapi_django_main_live')
if result.returncode == 0:
issue_url = result.stdout.strip()
print(f"✅ GitHub Issue作成成功: {issue_url}")
# セッションにIssue URLを記録
self._update_session_issue_url(target_session, issue_url)
return True
else:
print(f"❌ GitHub Issue作成失敗: {result.stderr}")
return False
except Exception as e:
print(f"❌ GitHub Issue作成エラー: {e}")
print(traceback.format_exc())
return False
def _generate_issue_body(self, conversations: List[Dict], session_id: str) -> str:
"""Issue本文を生成"""
# セッション情報
session_info = self.get_session_summary()
body_parts = [
"# 開発セッション記録",
"",
"## 📊 セッション情報",
f"- **セッションID**: `{session_id[:8]}`",
f"- **開始時刻**: {self.session_start_time.strftime('%Y-%m-%d %H:%M:%S')}",
f"- **会話数**: {len(conversations)}",
f"- **継続時間**: {session_info.get('duration_minutes', 0):.1f}分",
"",
"## 🗣️ 会話履歴",
""
]
# 会話履歴を追加(最新10件まで)
recent_conversations = conversations[:10] if len(conversations) > 10 else conversations
for i, conv in enumerate(reversed(recent_conversations), 1):
body_parts.extend([
f"### {i}. {conv.get('timestamp', '')}",
"",
"**👤 User:**",
"```",
conv.get('user_message', ''),
"```",
"",
"**🤖 Assistant:**",
"```",
conv.get('assistant_response', '')[:1000] + ('...' if len(conv.get('assistant_response', '')) > 1000 else ''),
"```",
""
])
# コンテキスト情報があれば追加
if conv.get('context_info'):
body_parts.extend([
"**📝 Context:**",
"```",
conv.get('context_info', ''),
"```",
""
])
# 関連ファイルがあれば追加
if conv.get('files_involved'):
body_parts.extend([
"**📁 Files:**",
f"`{conv.get('files_involved', '')}`",
""
])
# 使用ツールがあれば追加
if conv.get('tools_used'):
body_parts.extend([
"**🔧 Tools:**",
f"`{conv.get('tools_used', '')}`",
""
])
body_parts.append("---")
body_parts.append("")
# 要約とタグ
all_files = set()
all_tools = set()
all_tags = set()
for conv in conversations:
if conv.get('files_involved'):
all_files.update(conv.get('files_involved', '').split(', '))
if conv.get('tools_used'):
all_tools.update(conv.get('tools_used', '').split(', '))
if conv.get('tags'):
all_tags.update(conv.get('tags', '').split(', '))
body_parts.extend([
"## 📋 セッション要約",
"",
"### 関連ファイル",
"",
])
for file in sorted(all_files):
if file.strip():
body_parts.append(f"- `{file.strip()}`")
body_parts.extend([
"",
"### 使用ツール",
"",
])
for tool in sorted(all_tools):
if tool.strip():
body_parts.append(f"- `{tool.strip()}`")
if all_tags:
body_parts.extend([
"",
"### タグ",
"",
])
for tag in sorted(all_tags):
if tag.strip():
body_parts.append(f"- `{tag.strip()}`")
body_parts.extend([
"",
"---",
f"*自動生成: {datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')}*"
])
return "\n".join(body_parts)
def _update_session_issue_url(self, session_id: str, issue_url: str):
"""セッションにIssue URLを記録"""
try:
conn = sqlite3.connect(self.conversation_manager.db_path)
cursor = conn.cursor()
# sessions テーブルにissue_url カラムを追加(存在しない場合)
cursor.execute('''
ALTER TABLE sessions ADD COLUMN issue_url TEXT
''')
except sqlite3.OperationalError:
# カラムが既に存在する場合
pass
try:
cursor.execute('''
INSERT OR REPLACE INTO sessions (session_id, issue_url)
VALUES (?, ?)
''', (session_id, issue_url))
conn.commit()
conn.close()
except Exception as e:
print(f"⚠️ Issue URL記録エラー: {e}")
def create_issue_for_current_session(self,
title: str = None,
labels: List[str] = None) -> bool:
"""現在のセッションのGitHub Issueを作成"""
default_labels = [] # デフォルトラベルを空に
if labels:
default_labels.extend(labels)
return self.create_github_issue(
title=title,
session_id=self.current_session_id,
labels=default_labels
)
def create_quick_issue(title: str,
user_msg: str,
assistant_msg: str,
labels: List[str] = None):
"""
会話内容から直接GitHub Issueを作成
使用例:
create_quick_issue(
title="ContBK統合システム開発",
user_msg="このやりとりをGit Issueへ登録したい",
assistant_msg="GitHub Issue作成機能を実装しました",
labels=["development", "enhancement"]
)
"""
# 一時的に会話を記録
conversation_logger.log_conversation(
user_message=user_msg,
assistant_response=assistant_msg,
context_info="GitHub Issue直接作成",
tags=["quick-issue"] + (labels or [])
)
# すぐにIssue作成
return conversation_logger.create_issue_for_current_session(
title=title,
labels=labels or ["development", "conversation-log"]
)
# グローバルログインスタンス
conversation_logger = ConversationLogger()
def log_this_conversation(user_msg: str, assistant_msg: str,
context: str = "", files: List[str] = None,
tools: List[str] = None, tags: List[str] = None):
"""
簡単な会話ログ記録関数
使用例:
log_this_conversation(
user_msg="ContBK統合システムについて教えて",
assistant_msg="ContBK統合システムは...",
files=["controllers/contbk_example.py"],
tools=["create_file", "insert_edit_into_file"],
tags=["contbk", "gradio"]
)
"""
return conversation_logger.log_conversation(
user_message=user_msg,
assistant_response=assistant_msg,
context_info=context,
files_involved=files,
tools_used=tools,
tags=tags
)
def start_new_conversation_session(session_name: str = None):
"""新しい会話セッションを開始"""
return conversation_logger.start_new_session(session_name)
def create_quick_issue(title: str,
user_msg: str,
assistant_msg: str,
labels: List[str] = None):
"""
会話内容から直接GitHub Issueを作成
使用例:
create_quick_issue(
title="ContBK統合システム開発",
user_msg="このやりとりをGit Issueへ登録したい",
assistant_msg="GitHub Issue作成機能を実装しました",
labels=["development", "enhancement"]
)
"""
# 一時的に会話を記録
conversation_logger.log_conversation(
user_message=user_msg,
assistant_response=assistant_msg,
context_info="GitHub Issue直接作成",
tags=["quick-issue"] + (labels or [])
)
# すぐにIssue作成
return conversation_logger.create_issue_for_current_session(
title=title,
labels=labels or [] # デフォルトラベルを空に
)
def create_github_issue_for_session(title: str = None,
labels: List[str] = None,
session_id: str = None):
"""
現在のセッションまたは指定セッションのGitHub Issueを作成
使用例:
create_github_issue_for_session(
title="ContBK統合システム開発セッション",
labels=["enhancement", "contbk"]
)
"""
return conversation_logger.create_github_issue(
title=title,
session_id=session_id,
labels=labels or ["development", "conversation-log"]
)
def create_issue_now(title: str = "開発セッション記録"):
"""ワンクリックでGitHub Issue作成"""
return conversation_logger.create_issue_for_current_session(title=title)
def get_current_session_info():
"""現在のセッション情報を取得"""
return conversation_logger.get_session_summary()
# 自動ログ記録のデコレーター
def auto_log_conversation(tags: List[str] = None):
"""
関数の実行を自動的にログに記録するデコレーター
使用例:
@auto_log_conversation(tags=["gradio", "interface"])
def create_interface():
# 関数の処理
pass
"""
def decorator(func):
def wrapper(*args, **kwargs):
start_time = datetime.datetime.now()
try:
result = func(*args, **kwargs)
# 成功した場合のログ
conversation_logger.log_conversation(
user_message=f"関数実行: {func.__name__}",
assistant_response=f"関数 {func.__name__} が正常に実行されました",
context_info=f"実行時間: {(datetime.datetime.now() - start_time).total_seconds():.2f}秒",
tools_used=[func.__name__],
tags=tags or ["自動実行"]
)
return result
except Exception as e:
# エラーの場合のログ
conversation_logger.log_conversation(
user_message=f"関数実行エラー: {func.__name__}",
assistant_response=f"エラーが発生しました: {str(e)}",
context_info=f"実行時間: {(datetime.datetime.now() - start_time).total_seconds():.2f}秒",
tools_used=[func.__name__],
tags=(tags or []) + ["エラー"]
)
raise
return wrapper
return decorator
if __name__ == "__main__":
# テスト実行
print("🧪 会話ログシステムテスト")
# サンプル会話を記録
log_this_conversation(
user_msg="GitHub Issue作成機能のテストです",
assistant_msg="GitHub Issue作成機能が正常に動作しています!",
context="GitHub Issue機能追加",
files=["controllers/conversation_logger.py"],
tools=["create_github_issue", "gh"],
tags=["github", "issue", "automation"]
)
# セッション情報表示
session_info = get_current_session_info()
print(f"📊 セッション情報: {session_info}")
# GitHub Issue作成テスト(コメントアウト)
# create_issue_now("テスト用GitHub Issue")
print("✅ テスト完了")