Files
gt-ai-os-community/apps/tenant-backend/app/services/conversation_summarizer.py
HackWeasel 310491a557 GT AI OS Community v2.0.33 - Add NVIDIA NIM and Nemotron agents
- Updated python_coding_microproject.csv to use NVIDIA NIM Kimi K2
- Updated kali_linux_shell_simulator.csv to use NVIDIA NIM Kimi K2
  - Made more general-purpose (flexible targets, expanded tools)
- Added nemotron-mini-agent.csv for fast local inference via Ollama
- Added nemotron-agent.csv for advanced reasoning via Ollama
- Added wiki page: Projects for NVIDIA NIMs and Nemotron
2025-12-12 17:47:14 -05:00

200 lines
7.1 KiB
Python

"""
Conversation Summarization Service for GT 2.0
Automatically generates meaningful conversation titles using a specialized
summarization agent with llama-3.1-8b-instant.
"""
import json
import logging
from typing import List, Optional, Dict, Any
from app.core.config import get_settings
from app.core.resource_client import ResourceClusterClient
logger = logging.getLogger(__name__)
settings = get_settings()
class ConversationSummarizer:
"""Service for generating conversation summaries and titles"""
def __init__(self, tenant_id: str, user_id: str):
self.tenant_id = tenant_id
self.user_id = user_id
self.resource_client = ResourceClusterClient()
self.summarization_model = "llama-3.1-8b-instant"
async def generate_conversation_title(self, messages: List[Dict[str, Any]]) -> str:
"""
Generate a concise conversation title based on the conversation content.
Args:
messages: List of message dictionaries from the conversation
Returns:
Generated conversation title (3-6 words)
"""
try:
# Extract conversation context for summarization
conversation_text = self._prepare_conversation_context(messages)
if not conversation_text.strip():
return "New Conversation"
# Generate title using specialized summarization prompt
title = await self._call_summarization_agent(conversation_text)
# Validate and clean the generated title
clean_title = self._clean_title(title)
logger.info(f"Generated conversation title: '{clean_title}' from {len(messages)} messages")
return clean_title
except Exception as e:
logger.error(f"Error generating conversation title: {e}")
return self._fallback_title(messages)
def _prepare_conversation_context(self, messages: List[Dict[str, Any]]) -> str:
"""Prepare conversation context for summarization"""
if not messages:
return ""
# Limit to first few exchanges for title generation
context_messages = messages[:6] # First 3 user-agent exchanges
context_parts = []
for msg in context_messages:
role = "User" if msg.get("role") == "user" else "Agent"
# Truncate very long messages for context
content = msg.get("content", "")
content = content[:200] + "..." if len(content) > 200 else content
context_parts.append(f"{role}: {content}")
return "\n".join(context_parts)
async def _call_summarization_agent(self, conversation_text: str) -> str:
"""Call the resource cluster AI inference for summarization"""
summarization_prompt = f"""You are a conversation title generator. Your job is to create concise, descriptive titles for conversations.
Given this conversation:
---
{conversation_text}
---
Generate a title that:
- Is 3-6 words maximum
- Captures the main topic or purpose
- Is clear and descriptive
- Uses title case
- Does NOT include quotes or special characters
Examples of good titles:
- "Python Code Review"
- "Database Migration Help"
- "React Component Design"
- "System Architecture Discussion"
Title:"""
request_data = {
"messages": [
{
"role": "user",
"content": summarization_prompt
}
],
"model": self.summarization_model,
"temperature": 0.3, # Lower temperature for consistent, focused titles
"max_tokens": 20, # Short response for title generation
"stream": False
}
try:
# Use the resource client instead of direct HTTP calls
result = await self.resource_client.call_inference_endpoint(
tenant_id=self.tenant_id,
user_id=self.user_id,
endpoint="chat/completions",
data=request_data
)
if result and "choices" in result and len(result["choices"]) > 0:
title = result["choices"][0]["message"]["content"].strip()
return title
else:
logger.error("Invalid response format from summarization API")
return ""
except Exception as e:
logger.error(f"Error calling summarization agent: {e}")
return ""
def _clean_title(self, raw_title: str) -> str:
"""Clean and validate the generated title"""
if not raw_title:
return "New Conversation"
# Remove quotes, extra whitespace, and special characters
cleaned = raw_title.strip().strip('"\'').strip()
# Remove common prefixes that AI might add
prefixes_to_remove = [
"Title:", "title:", "TITLE:",
"Conversation:", "conversation:",
"Topic:", "topic:",
"Subject:", "subject:"
]
for prefix in prefixes_to_remove:
if cleaned.startswith(prefix):
cleaned = cleaned[len(prefix):].strip()
# Limit length and ensure it's reasonable
if len(cleaned) > 50:
cleaned = cleaned[:47] + "..."
# Ensure it's not empty after cleaning
if not cleaned or len(cleaned.split()) > 8:
return "New Conversation"
return cleaned
def _fallback_title(self, messages: List[Dict[str, Any]]) -> str:
"""Generate fallback title when AI summarization fails"""
if not messages:
return "New Conversation"
# Try to use the first user message for context
first_user_msg = next((msg for msg in messages if msg.get("role") == "user"), None)
if first_user_msg and first_user_msg.get("content"):
# Extract first few words from the user's message
words = first_user_msg["content"].strip().split()[:4]
if len(words) >= 2:
fallback = " ".join(words).capitalize()
# Remove common question words for cleaner titles
for word in ["How", "What", "Can", "Could", "Please", "Help"]:
if fallback.startswith(word + " "):
fallback = fallback[len(word):].strip()
break
return fallback if fallback else "New Conversation"
return "New Conversation"
async def generate_conversation_title(messages: List[Dict[str, Any]], tenant_id: str, user_id: str) -> str:
"""
Convenience function to generate a conversation title.
Args:
messages: List of message dictionaries from the conversation
tenant_id: Tenant identifier
user_id: User identifier
Returns:
Generated conversation title
"""
summarizer = ConversationSummarizer(tenant_id, user_id)
return await summarizer.generate_conversation_title(messages)