File size: 3,745 Bytes
6ab316e
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
import sys
import os
import secrets
import hmac
import hashlib
import time
from fastapi import FastAPI, HTTPException, Request
from fastapi.responses import HTMLResponse, Response
from fastapi.staticfiles import StaticFiles
from pydantic import BaseModel
from typing import Optional, List

sys.path.append(os.path.dirname(os.path.abspath(__file__)))

from agent import AgentContext, AgentContextType, UserMessage
import initialize
from python.helpers import runtime, dotenv, files, git
from python.helpers.print_style import PrintStyle

app = FastAPI(title="Skilled-Agent API")

# CSRF Logic from run_ui.py
CSRF_SECRET = secrets.token_bytes(32)
TOKEN_TTL = 3600

def generate_csrf_token():
    nonce = secrets.token_hex(16)
    timestamp = str(int(time.time()))
    data = f"{nonce}:{timestamp}"
    sig = hmac.new(CSRF_SECRET, data.encode(), hashlib.sha256).hexdigest()
    return f"{data}.{sig}"

class ChatRequest(BaseModel):
    message: str
    chat_id: Optional[str] = None
    attachments: Optional[List[str]] = None

class ChatResponse(BaseModel):
    response: str
    chat_id: str

@app.on_event("startup")
async def startup_event():
    PrintStyle().print("Initializing Skilled-Agent API...")
    runtime.initialize()
    dotenv.load_dotenv()
    
    # Run migrations if necessary
    if hasattr(initialize, "initialize_migration"):
        initialize.initialize_migration()
    
    # Initialize chats
    init_chats = initialize.initialize_chats()
    init_chats.result_sync()

    # Initialize MCP
    initialize.initialize_mcp()
    
    # Start job loop
    initialize.initialize_job_loop()
    
    # Preload
    initialize.initialize_preload()
    
    PrintStyle().print("Skilled-Agent API started.")

@app.get("/", response_class=HTMLResponse)
async def serve_index():
    PrintStyle().print("Serving index.html")
    gitinfo = None
    try:
        gitinfo = git.get_git_info()
    except Exception as e:
        gitinfo = {"version": "unknown", "commit_time": "unknown"}
    
    index_content = files.read_file("webui/index.html")
    index_content = files.replace_placeholders_text(
        _content=index_content,
        version_no=gitinfo["version"],
        version_time=gitinfo["commit_time"]
    )

    csrf_token = generate_csrf_token()
    runtime_id = runtime.get_runtime_id()
    meta_tags = f'''<meta name="csrf-token" content="{csrf_token}">
    <meta name="runtime-id" content="{runtime_id}">'''
    index_content = index_content.replace("</head>", f"{meta_tags}</head>")
    return index_content

@app.post("/chat", response_model=ChatResponse)
async def chat(request: ChatRequest):
    context = None
    if request.chat_id:
        context = AgentContext.get(request.chat_id)
        if not context:
            raise HTTPException(status_code=404, detail=f"Chat session {request.chat_id} not found")
    else:
        config = initialize.initialize_agent()
        context = AgentContext(config=config, type=AgentContextType.BACKGROUND)

    if not request.message:
        raise HTTPException(status_code=400, detail="Message is required")

    try:
        PrintStyle().print(f"Processing message for chat {context.id}...")
        task = context.communicate(
            UserMessage(
                message=request.message,
                attachments=request.attachments or []
            )
        )
        result = await task.result()
        return ChatResponse(response=result, chat_id=context.id)
    except Exception as e:
        PrintStyle().error(f"Error in chat: {e}")
        raise HTTPException(status_code=500, detail=str(e))

@app.get("/health")
async def health():
    return {"status": "healthy"}

# Mount static files
app.mount("/", StaticFiles(directory="webui"), name="static")