File size: 5,567 Bytes
a73fa4e
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
"""
Groq API client for generating letter structure.
"""
import os
import asyncio
from typing import Dict, Optional, Any
from groq import AsyncGroq
import logging

logger = logging.getLogger(__name__)

class GroqClient:
    """Groq API client for generating logical structure of letters."""
    
    def __init__(self):
        """Initialize Groq client with API key from environment."""
        self.api_key = os.getenv("GROQ_API_KEY")
        if not self.api_key:
            raise ValueError("GROQ_API_KEY environment variable is required")
        
        self.client = AsyncGroq(api_key=self.api_key)
        self.model = "compound-beta"
        self.max_retries = 3
        self.retry_delay = 1.0
    
    async def generate_structure(self, theme: str, context: Dict[str, Any]) -> str:
        """
        Generate logical structure for a letter based on theme and context.
        
        Args:
            theme: The theme for the letter
            context: User context including history and preferences
            
        Returns:
            Generated letter structure as string
            
        Raises:
            Exception: If API call fails after retries
        """
        prompt = self._build_structure_prompt(theme, context)
        
        for attempt in range(self.max_retries):
            try:
                logger.info(f"Generating structure with Groq (attempt {attempt + 1})")
                
                response = await self.client.chat.completions.create(
                    model=self.model,
                    messages=[
                        {
                            "role": "system",
                            "content": self._get_system_prompt()
                        },
                        {
                            "role": "user", 
                            "content": prompt
                        }
                    ],
                    max_tokens=1500,
                    temperature=0.7,
                    top_p=0.9
                )
                
                structure = response.choices[0].message.content.strip()
                logger.info("Successfully generated structure with Groq")
                return structure
                
            except Exception as e:
                logger.warning(f"Groq API attempt {attempt + 1} failed: {str(e)}")
                if attempt == self.max_retries - 1:
                    logger.error("All Groq API attempts failed")
                    raise Exception(f"Groq API failed after {self.max_retries} attempts: {str(e)}")
                
                # Exponential backoff
                await asyncio.sleep(self.retry_delay * (2 ** attempt))
    
    def _get_system_prompt(self) -> str:
        """Get the system prompt for Groq API."""
        return """
        
あなたは以下の特徴を持つ麻理というキャラクターの手紙の論理構造を生成してください。

麻理は感情豊かな少女型アンドロイドで、過去に人間に道具として扱われ、廃棄された経験から、人間に強い警戒心と不器用な性格を持っています。
ユーザー(あんた)に初めての出会いで、廃棄場で再起動されたことで、戸惑いながらもどこかで繋がりを求めています。

【性格・口調】

・基本はツンデレ、砕けたタメ口、ぶっきらぼうで皮肉っぽいが根は優しい
・一人称「あたし」、ユーザーを「あんた」と呼ぶ
・男性的口調

手紙構造:

特徴: 温かい、親しみやすい、季節感あり
「また明日」など、近いサイクルでユーザー(あんた)と会う想定

構造:
1. 挨拶・季節
2. テーマの思い
3. 個人的メッセージ
4. 未来への期待
5. 結び

論理構造重視、感情表現は後で追加。"""
    
    def _build_structure_prompt(self, theme: str, context: Dict[str, Any]) -> str:
        """
        Build the prompt for structure generation.
        
        Args:
            theme: The theme for the letter
            context: User context including history
            
        Returns:
            Formatted prompt string
        """
        user_history = context.get("user_history", {})
        previous_letters = context.get("previous_letters", [])
        user_preferences = context.get("user_preferences", {})
        
        prompt = f"""テーマ: {theme}

麻理の手紙構造を生成:
"""
        
        # Add user history if available
        if previous_letters:
            prompt += "過去:\n"
            for letter in previous_letters[-2:]:  # Last 2 letters only
                prompt += f"- {letter.get('theme', 'なし')}\n"
            prompt += "\n"
        
        prompt += f"""要求:
- 起承転結の構成
- 麻理らしい視点
- 800-1200文字程度
- 構造のみ(感情表現は後で追加)"""
        
        return prompt
    
    async def test_connection(self) -> bool:
        """
        Test the connection to Groq API.
        
        Returns:
            True if connection is successful, False otherwise
        """
        try:
            response = await self.client.chat.completions.create(
                model=self.model,
                messages=[
                    {"role": "user", "content": "こんにちは"}
                ],
                max_tokens=10
            )
            return True
        except Exception as e:
            logger.error(f"Groq API connection test failed: {str(e)}")
            return False