openfree commited on
Commit
268c625
Β·
verified Β·
1 Parent(s): 02ce531

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +606 -0
app.py ADDED
@@ -0,0 +1,606 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from fastapi import FastAPI, WebSocket, HTTPException, WebSocketDisconnect
2
+ from fastapi.responses import JSONResponse, HTMLResponse
3
+ from fastapi.staticfiles import StaticFiles
4
+ from fastapi.middleware.cors import CORSMiddleware
5
+ from pydantic import BaseModel, Field
6
+ import uvicorn
7
+ import json
8
+ import os
9
+ import asyncio
10
+ from datetime import datetime
11
+ from typing import List, Dict, Optional, Any
12
+ import logging
13
+ import uuid
14
+
15
+ # λͺ¨λ“ˆμ΄ μ‘΄μž¬ν•˜μ§€ μ•ŠμœΌλ©΄ ν˜„μž¬ λ””λ ‰ν† λ¦¬μ—μ„œ κ°€μ Έμ˜€λ„λ‘ μ‹œλ„
16
+ try:
17
+ from recursive_thinking_ai import EnhancedRecursiveThinkingChat
18
+ except ModuleNotFoundError:
19
+ # ν˜„μž¬ 디렉토리에 recursive_thinking_ai.py 파일이 μžˆμ–΄μ•Ό 함
20
+ import sys
21
+ sys.path.append('.')
22
+ from recursive_thinking_ai import EnhancedRecursiveThinkingChat
23
+
24
+ # Set up logging
25
+ logging.basicConfig(
26
+ level=logging.INFO,
27
+ format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
28
+ )
29
+ logger = logging.getLogger(__name__)
30
+
31
+ app = FastAPI(
32
+ title="Chain of Recursive Thoughts",
33
+ description="API for Enhanced Recursive Thinking Chat",
34
+ version="1.0.0"
35
+ )
36
+
37
+ # Add CORS middleware
38
+ app.add_middleware(
39
+ CORSMiddleware,
40
+ allow_origins=["*"], # In production, replace with specific origins
41
+ allow_credentials=True,
42
+ allow_methods=["*"],
43
+ allow_headers=["*"],
44
+ )
45
+
46
+ # Create a dictionary to store chat instances
47
+ chat_instances = {}
48
+
49
+ # ν™˜κ²½ λ³€μˆ˜μ—μ„œ API ν‚€ κ°€μ Έμ˜€κΈ°
50
+ API_KEY = os.getenv("OPENROUTE_API")
51
+ if not API_KEY:
52
+ logger.warning("OPENROUTE_API ν™˜κ²½ λ³€μˆ˜κ°€ μ„€μ •λ˜μ§€ μ•Šμ•˜μŠ΅λ‹ˆλ‹€. 일뢀 κΈ°λŠ₯이 λ™μž‘ν•˜μ§€ μ•Šμ„ 수 μžˆμŠ΅λ‹ˆλ‹€.")
53
+
54
+ # Pydantic models for request/response validation
55
+ class ChatConfig(BaseModel):
56
+ # api_key ν•­λͺ©μ€ μ œκ±°ν•˜κ³ , λͺ¨λΈκ³Ό temperature만 받도둝 μˆ˜μ •
57
+ model: str = "mistralai/mistral-small-3.1-24b-instruct:free"
58
+ temperature: Optional[float] = Field(default=0.7, ge=0.0, le=1.0)
59
+
60
+ class MessageRequest(BaseModel):
61
+ session_id: str
62
+ message: str
63
+ thinking_rounds: Optional[int] = Field(default=None, ge=1, le=10)
64
+ alternatives_per_round: Optional[int] = Field(default=3, ge=1, le=5)
65
+ temperature: Optional[float] = Field(default=None, ge=0.0, le=1.0)
66
+
67
+ class SaveRequest(BaseModel):
68
+ session_id: str
69
+ filename: Optional[str] = None
70
+ full_log: bool = False
71
+
72
+ class SessionInfo(BaseModel):
73
+ session_id: str
74
+ message_count: int
75
+ created_at: str
76
+ model: str
77
+
78
+ class SessionResponse(BaseModel):
79
+ sessions: List[SessionInfo]
80
+
81
+ class InitResponse(BaseModel):
82
+ session_id: str
83
+ status: str
84
+
85
+ # κ°„λ‹¨ν•œ HTML μΈν„°νŽ˜μ΄μŠ€ 제곡 (API ν‚€ μž…λ ₯ 폼을 μ œκ±°ν•¨)
86
+ @app.get("/", response_class=HTMLResponse)
87
+ async def root():
88
+ """Root endpoint with a simple HTML interface"""
89
+ html_content = f"""
90
+ <!DOCTYPE html>
91
+ <html>
92
+ <head>
93
+ <title>RecThink API</title>
94
+ <style>
95
+ body {{
96
+ font-family: Arial, sans-serif;
97
+ max-width: 800px;
98
+ margin: 0 auto;
99
+ padding: 20px;
100
+ line-height: 1.6;
101
+ }}
102
+ h1 {{
103
+ color: #333;
104
+ border-bottom: 1px solid #eee;
105
+ padding-bottom: 10px;
106
+ }}
107
+ .container {{
108
+ background-color: #f9f9f9;
109
+ border-radius: 5px;
110
+ padding: 20px;
111
+ margin-top: 20px;
112
+ }}
113
+ label {{
114
+ display: block;
115
+ margin-bottom: 5px;
116
+ font-weight: bold;
117
+ }}
118
+ input, textarea, select {{
119
+ width: 100%;
120
+ padding: 8px;
121
+ margin-bottom: 10px;
122
+ border: 1px solid #ddd;
123
+ border-radius: 4px;
124
+ }}
125
+ button {{
126
+ background-color: #4CAF50;
127
+ color: white;
128
+ padding: 10px 15px;
129
+ border: none;
130
+ border-radius: 4px;
131
+ cursor: pointer;
132
+ }}
133
+ button:hover {{
134
+ background-color: #45a049;
135
+ }}
136
+ #response {{
137
+ white-space: pre-wrap;
138
+ background-color: #f5f5f5;
139
+ padding: 15px;
140
+ border-radius: 4px;
141
+ margin-top: 20px;
142
+ min-height: 100px;
143
+ }}
144
+ .log {{
145
+ margin-top: 20px;
146
+ font-size: 0.9em;
147
+ color: #666;
148
+ }}
149
+ </style>
150
+ </head>
151
+ <body>
152
+ <h1>RecThink API μΈν„°νŽ˜μ΄μŠ€</h1>
153
+ <div class="container">
154
+ <div id="init-form">
155
+ <h2>1. μ±„νŒ… μ΄ˆκΈ°ν™”</h2>
156
+
157
+ <!-- API ν‚€ μž…λ ₯λž€ 제거 -->
158
+ <label for="model">λͺ¨λΈ:</label>
159
+ <input type="text" id="model" value="mistralai/mistral-small-3.1-24b-instruct:free">
160
+
161
+ <label for="temperature">μ˜¨λ„ (Temperature):</label>
162
+ <input type="number" id="temperature" min="0" max="1" step="0.1" value="0.7">
163
+
164
+ <button onclick="initializeChat()">μ΄ˆκΈ°ν™”</button>
165
+ </div>
166
+
167
+ <div id="chat-form" style="display: none;">
168
+ <h2>2. λ©”μ‹œμ§€ 전솑</h2>
169
+ <p>μ„Έμ…˜ ID: <span id="session-id"></span></p>
170
+
171
+ <label for="message">λ©”μ‹œμ§€:</label>
172
+ <textarea id="message" rows="4" placeholder="λ©”μ‹œμ§€λ₯Ό μž…λ ₯ν•˜μ„Έμš”"></textarea>
173
+
174
+ <label for="thinking-rounds">사고 λΌμš΄λ“œ (선택사항):</label>
175
+ <input type="number" id="thinking-rounds" min="1" max="10" placeholder="μžλ™ κ²°μ •">
176
+
177
+ <label for="alternatives">λŒ€μ•ˆ 개수 (선택사항):</label>
178
+ <input type="number" id="alternatives" min="1" max="5" value="3">
179
+
180
+ <button onclick="sendMessage()">전솑</button>
181
+ <button onclick="resetChat()" style="background-color: #f44336;">μ΄ˆκΈ°ν™”</button>
182
+ </div>
183
+
184
+ <div id="response-container" style="display: none;">
185
+ <h2>3. 응닡</h2>
186
+ <div id="response">응닡이 여기에 ν‘œμ‹œλ©λ‹ˆλ‹€...</div>
187
+ <div class="log">
188
+ <h3>생각 κ³Όμ • 둜그:</h3>
189
+ <div id="thinking-log"></div>
190
+ </div>
191
+ </div>
192
+ </div>
193
+
194
+ <script>
195
+ let currentSessionId = null;
196
+
197
+ async function initializeChat() {{
198
+ const model = document.getElementById('model').value;
199
+ const temperature = parseFloat(document.getElementById('temperature').value);
200
+
201
+ try {{
202
+ const response = await fetch('/api/initialize', {{
203
+ method: 'POST',
204
+ headers: {{
205
+ 'Content-Type': 'application/json',
206
+ }},
207
+ body: JSON.stringify({{
208
+ model: model,
209
+ temperature: temperature
210
+ }}),
211
+ }});
212
+
213
+ const data = await response.json();
214
+
215
+ if (response.ok) {{
216
+ currentSessionId = data.session_id;
217
+ document.getElementById('session-id').textContent = currentSessionId;
218
+ document.getElementById('init-form').style.display = 'none';
219
+ document.getElementById('chat-form').style.display = 'block';
220
+ document.getElementById('response-container').style.display = 'block';
221
+ }} else {{
222
+ alert('μ΄ˆκΈ°ν™” μ‹€νŒ¨: ' + (data.detail || 'μ•Œ 수 μ—†λŠ” 였λ₯˜'));
223
+ }}
224
+ }} catch (error) {{
225
+ alert('였λ₯˜ λ°œμƒ: ' + error.message);
226
+ }}
227
+ }}
228
+
229
+ async function sendMessage() {{
230
+ if (!currentSessionId) {{
231
+ alert('λ¨Όμ € μ±„νŒ…μ„ μ΄ˆκΈ°ν™”ν•΄μ£Όμ„Έμš”');
232
+ return;
233
+ }}
234
+
235
+ const message = document.getElementById('message').value;
236
+ const thinkingRounds = document.getElementById('thinking-rounds').value;
237
+ const alternatives = document.getElementById('alternatives').value;
238
+
239
+ if (!message) {{
240
+ alert('λ©”μ‹œμ§€λ₯Ό μž…λ ₯ν•΄μ£Όμ„Έμš”');
241
+ return;
242
+ }}
243
+
244
+ document.getElementById('response').textContent = '처리 쀑...';
245
+ document.getElementById('thinking-log').textContent = '';
246
+
247
+ try {{
248
+ const response = await fetch('/api/send_message', {{
249
+ method: 'POST',
250
+ headers: {{
251
+ 'Content-Type': 'application/json',
252
+ }},
253
+ body: JSON.stringify({{
254
+ session_id: currentSessionId,
255
+ message: message,
256
+ thinking_rounds: thinkingRounds ? parseInt(thinkingRounds) : null,
257
+ alternatives_per_round: alternatives ? parseInt(alternatives) : 3
258
+ }}),
259
+ }});
260
+
261
+ const data = await response.json();
262
+
263
+ if (response.ok) {{
264
+ document.getElementById('response').textContent = data.response;
265
+
266
+ // Display thinking history
267
+ let thinkingLogHTML = '';
268
+ data.thinking_history.forEach(item => {{
269
+ const selected = item.selected ? ' βœ“ 선택됨' : '';
270
+ thinkingLogHTML += `<p><strong>λΌμš΄λ“œ ${'{'}item.round{'}'}${selected}:</strong> `;
271
+
272
+ if (item.explanation && item.selected) {{
273
+ thinkingLogHTML += `<br><em>선택 이유: ${'{'}item.explanation{'}'}</em>`;
274
+ }}
275
+ thinkingLogHTML += '</p>';
276
+ }});
277
+
278
+ document.getElementById('thinking-log').innerHTML = thinkingLogHTML;
279
+ }} else {{
280
+ document.getElementById('response').textContent = '였λ₯˜: ' + (data.detail || 'μ•Œ 수 μ—†λŠ” 였λ₯˜');
281
+ }}
282
+ }} catch (error) {{
283
+ document.getElementById('response').textContent = '였λ₯˜ λ°œμƒ: ' + error.message;
284
+ }}
285
+ }}
286
+
287
+ function resetChat() {{
288
+ currentSessionId = null;
289
+ document.getElementById('init-form').style.display = 'block';
290
+ document.getElementById('chat-form').style.display = 'none';
291
+ document.getElementById('response-container').style.display = 'none';
292
+ document.getElementById('message').value = '';
293
+ document.getElementById('thinking-rounds').value = '';
294
+ document.getElementById('alternatives').value = '3';
295
+ }}
296
+ </script>
297
+ </body>
298
+ </html>
299
+ """
300
+ return html_content
301
+
302
+ # Healthcheck endpoint
303
+ @app.get("/health")
304
+ async def health_check():
305
+ """Health check endpoint"""
306
+ return {"status": "healthy", "timestamp": datetime.now().isoformat()}
307
+
308
+ @app.post("/api/initialize", response_model=InitResponse)
309
+ async def initialize_chat(config: ChatConfig):
310
+ """Initialize a new chat session using environment API key"""
311
+ try:
312
+ # Generate a session ID
313
+ session_id = f"session_{datetime.now().strftime('%Y%m%d%H%M%S')}_{uuid.uuid4().hex[:8]}"
314
+
315
+ # ν™˜κ²½ λ³€μˆ˜κ°€ 없을 경우 μ—λŸ¬ 처리(λ˜λŠ” κ²½κ³ )
316
+ if not API_KEY:
317
+ raise HTTPException(status_code=400, detail="OPENROUTE_API ν™˜κ²½ λ³€μˆ˜κ°€ μ„€μ •λ˜μ§€ μ•Šμ•˜μŠ΅λ‹ˆλ‹€.")
318
+
319
+ # Initialize the chat instance
320
+ chat = EnhancedRecursiveThinkingChat(
321
+ api_key=API_KEY,
322
+ model=config.model,
323
+ temperature=config.temperature
324
+ )
325
+ chat_instances[session_id] = {
326
+ "chat": chat,
327
+ "created_at": datetime.now().isoformat(),
328
+ "model": config.model
329
+ }
330
+
331
+ return {"session_id": session_id, "status": "initialized"}
332
+ except Exception as e:
333
+ logger.error(f"Error initializing chat: {str(e)}")
334
+ raise HTTPException(status_code=500, detail=f"Failed to initialize chat: {str(e)}")
335
+
336
+ @app.post("/api/send_message")
337
+ async def send_message(request: MessageRequest):
338
+ """Send a message and get a response with thinking process"""
339
+ try:
340
+ if request.session_id not in chat_instances:
341
+ raise HTTPException(status_code=404, detail="Session not found")
342
+
343
+ chat = chat_instances[request.session_id]["chat"]
344
+
345
+ # Override class parameters if provided
346
+ original_thinking_fn = chat._determine_thinking_rounds
347
+ original_alternatives_fn = chat._generate_alternatives
348
+ original_temperature = getattr(chat, "temperature", 0.7)
349
+
350
+ if request.thinking_rounds is not None:
351
+ # Override the thinking rounds determination
352
+ chat._determine_thinking_rounds = lambda _: request.thinking_rounds
353
+
354
+ if request.alternatives_per_round is not None:
355
+ def modified_generate_alternatives(base_response, prompt, num_alternatives=3):
356
+ return original_alternatives_fn(base_response, prompt, request.alternatives_per_round)
357
+ chat._generate_alternatives = modified_generate_alternatives
358
+
359
+ # Override temperature if provided
360
+ if request.temperature is not None:
361
+ setattr(chat, "temperature", request.temperature)
362
+
363
+ # Process the message
364
+ logger.info(f"Processing message for session {request.session_id}")
365
+ start_time = datetime.now()
366
+ result = chat.think_and_respond(request.message, verbose=True)
367
+ processing_time = (datetime.now() - start_time).total_seconds()
368
+ logger.info(f"Message processed in {processing_time:.2f} seconds")
369
+
370
+ # Restore original functions and parameters
371
+ chat._determine_thinking_rounds = original_thinking_fn
372
+ chat._generate_alternatives = original_alternatives_fn
373
+ if request.temperature is not None:
374
+ setattr(chat, "temperature", original_temperature)
375
+
376
+ return {
377
+ "session_id": request.session_id,
378
+ "response": result["response"],
379
+ "thinking_rounds": result["thinking_rounds"],
380
+ "thinking_history": result["thinking_history"],
381
+ "processing_time": processing_time
382
+ }
383
+ except Exception as e:
384
+ logger.error(f"Error processing message: {str(e)}")
385
+ raise HTTPException(status_code=500, detail=f"Failed to process message: {str(e)}")
386
+
387
+ @app.post("/api/save")
388
+ async def save_conversation(request: SaveRequest):
389
+ """Save the conversation or full thinking log"""
390
+ try:
391
+ if request.session_id not in chat_instances:
392
+ raise HTTPException(status_code=404, detail="Session not found")
393
+
394
+ chat = chat_instances[request.session_id]["chat"]
395
+
396
+ # Generate default filename if not provided
397
+ filename = request.filename
398
+ if filename is None:
399
+ timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
400
+ log_type = "full_log" if request.full_log else "conversation"
401
+ filename = f"recthink_{log_type}_{timestamp}.json"
402
+
403
+ # Make sure the output directory exists
404
+ os.makedirs("logs", exist_ok=True)
405
+ file_path = os.path.join("logs", filename)
406
+
407
+ if request.full_log:
408
+ chat.save_full_log(file_path)
409
+ else:
410
+ chat.save_conversation(file_path)
411
+
412
+ return {"status": "saved", "filename": filename, "path": file_path}
413
+ except Exception as e:
414
+ logger.error(f"Error saving conversation: {str(e)}")
415
+ raise HTTPException(status_code=500, detail=f"Failed to save conversation: {str(e)}")
416
+
417
+ @app.get("/api/sessions", response_model=SessionResponse)
418
+ async def list_sessions():
419
+ """List all active chat sessions"""
420
+ sessions = []
421
+ for session_id, session_data in chat_instances.items():
422
+ chat = session_data["chat"]
423
+ message_count = len(chat.conversation_history) // 2 # Each message-response pair counts as 2
424
+
425
+ sessions.append(SessionInfo(
426
+ session_id=session_id,
427
+ message_count=message_count,
428
+ created_at=session_data["created_at"],
429
+ model=session_data["model"]
430
+ ))
431
+
432
+ return {"sessions": sessions}
433
+
434
+ @app.get("/api/sessions/{session_id}")
435
+ async def get_session(session_id: str):
436
+ """Get details for a specific chat session"""
437
+ if session_id not in chat_instances:
438
+ raise HTTPException(status_code=404, detail="Session not found")
439
+
440
+ session_data = chat_instances[session_id]
441
+ chat = session_data["chat"]
442
+
443
+ # Extract conversation history
444
+ conversation = []
445
+ for i in range(0, len(chat.conversation_history), 2):
446
+ if i+1 < len(chat.conversation_history):
447
+ conversation.append({
448
+ "user": chat.conversation_history[i],
449
+ "assistant": chat.conversation_history[i+1]
450
+ })
451
+
452
+ return {
453
+ "session_id": session_id,
454
+ "created_at": session_data["created_at"],
455
+ "model": session_data["model"],
456
+ "message_count": len(conversation),
457
+ "conversation": conversation
458
+ }
459
+
460
+ @app.delete("/api/sessions/{session_id}")
461
+ async def delete_session(session_id: str):
462
+ """Delete a chat session"""
463
+ if session_id not in chat_instances:
464
+ raise HTTPException(status_code=404, detail="Session not found")
465
+
466
+ del chat_instances[session_id]
467
+ return {"status": "deleted", "session_id": session_id}
468
+
469
+ # WebSocket connection manager
470
+ class ConnectionManager:
471
+ def __init__(self):
472
+ self.active_connections: Dict[str, WebSocket] = {}
473
+
474
+ async def connect(self, session_id: str, websocket: WebSocket):
475
+ await websocket.accept()
476
+ self.active_connections[session_id] = websocket
477
+
478
+ def disconnect(self, session_id: str):
479
+ if session_id in self.active_connections:
480
+ del self.active_connections[session_id]
481
+
482
+ async def send_json(self, session_id: str, data: dict):
483
+ if session_id in self.active_connections:
484
+ await self.active_connections[session_id].send_json(data)
485
+
486
+ manager = ConnectionManager()
487
+
488
+ # WebSocket for streaming thinking process
489
+ @app.websocket("/ws/{session_id}")
490
+ async def websocket_endpoint(websocket: WebSocket, session_id: str):
491
+ try:
492
+ await manager.connect(session_id, websocket)
493
+
494
+ if session_id not in chat_instances:
495
+ await websocket.send_json({"error": "Session not found"})
496
+ await websocket.close()
497
+ return
498
+
499
+ chat = chat_instances[session_id]["chat"]
500
+
501
+ # Set up a custom callback to stream thinking process
502
+ original_call_api = chat._call_api
503
+
504
+ async def stream_callback(chunk):
505
+ await manager.send_json(session_id, {"type": "chunk", "content": chunk})
506
+
507
+ # Override the _call_api method to also send updates via WebSocket
508
+ def ws_call_api(messages, temperature=0.7, stream=True):
509
+ result = original_call_api(messages, temperature, stream)
510
+ # Send the chunk via WebSocket if we're streaming
511
+ if stream:
512
+ asyncio.create_task(stream_callback(result))
513
+ return result
514
+
515
+ # Replace the method temporarily
516
+ chat._call_api = ws_call_api
517
+
518
+ # Wait for messages from the client
519
+ while True:
520
+ data = await websocket.receive_text()
521
+ message_data = json.loads(data)
522
+
523
+ if message_data["type"] == "message":
524
+ # Process the message
525
+ start_time = datetime.now()
526
+
527
+ try:
528
+ # Get parameters if they exist
529
+ thinking_rounds = message_data.get("thinking_rounds", None)
530
+ alternatives_per_round = message_data.get("alternatives_per_round", None)
531
+ temperature = message_data.get("temperature", None)
532
+
533
+ # Override if needed
534
+ original_thinking_fn = chat._determine_thinking_rounds
535
+ original_alternatives_fn = chat._generate_alternatives
536
+ original_temperature = getattr(chat, "temperature", 0.7)
537
+
538
+ if thinking_rounds is not None:
539
+ chat._determine_thinking_rounds = lambda _: thinking_rounds
540
+
541
+ if alternatives_per_round is not None:
542
+ def modified_generate_alternatives(base_response, prompt, num_alternatives=3):
543
+ return original_alternatives_fn(base_response, prompt, alternatives_per_round)
544
+ chat._generate_alternatives = modified_generate_alternatives
545
+
546
+ if temperature is not None:
547
+ setattr(chat, "temperature", temperature)
548
+
549
+ # Send a status message that we've started processing
550
+ await manager.send_json(session_id, {
551
+ "type": "status",
552
+ "status": "processing",
553
+ "message": "Starting recursive thinking process..."
554
+ })
555
+
556
+ # Process the message
557
+ result = chat.think_and_respond(message_data["content"], verbose=True)
558
+ processing_time = (datetime.now() - start_time).total_seconds()
559
+
560
+ # Restore original functions
561
+ chat._determine_thinking_rounds = original_thinking_fn
562
+ chat._generate_alternatives = original_alternatives_fn
563
+ if temperature is not None:
564
+ setattr(chat, "temperature", original_temperature)
565
+
566
+ # Send the final result
567
+ await manager.send_json(session_id, {
568
+ "type": "final",
569
+ "response": result["response"],
570
+ "thinking_rounds": result["thinking_rounds"],
571
+ "thinking_history": result["thinking_history"],
572
+ "processing_time": processing_time
573
+ })
574
+
575
+ except Exception as e:
576
+ error_msg = str(e)
577
+ logger.error(f"Error in WebSocket message processing: {error_msg}")
578
+ await manager.send_json(session_id, {
579
+ "type": "error",
580
+ "error": error_msg
581
+ })
582
+
583
+ except WebSocketDisconnect:
584
+ logger.info(f"WebSocket disconnected: {session_id}")
585
+ manager.disconnect(session_id)
586
+ except Exception as e:
587
+ error_msg = str(e)
588
+ logger.error(f"WebSocket error: {error_msg}")
589
+ try:
590
+ await websocket.send_json({"type": "error", "error": error_msg})
591
+ except:
592
+ pass
593
+ finally:
594
+ # Restore original method if needed
595
+ if 'chat' in locals() and 'original_call_api' in locals():
596
+ chat._call_api = original_call_api
597
+
598
+ # Make sure to disconnect
599
+ manager.disconnect(session_id)
600
+
601
+ # 포트 μ„€μ • - ν—ˆκΉ…νŽ˜μ΄μŠ€ μŠ€νŽ˜μ΄μŠ€μ—μ„œλŠ” 7860 포트λ₯Ό μ‚¬μš©ν•΄μ•Ό 함
602
+ if __name__ == "__main__":
603
+ # ν—ˆκΉ…νŽ˜μ΄μŠ€ μŠ€νŽ˜μ΄μŠ€μ—μ„œ μ‹€ν–‰μ‹œ 포트 7860 μ‚¬μš©
604
+ port = 7860
605
+ print(f"Starting server on port {port}")
606
+ uvicorn.run("app:app", host="0.0.0.0", port=port)