openfree commited on
Commit
350f1fd
Β·
verified Β·
1 Parent(s): 1ea0a48

Delete app-backup.py

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