File size: 3,557 Bytes
79860d3
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5d29fbb
 
 
 
 
77d1b2b
f44d1e5
79860d3
 
 
 
 
 
 
 
d807ca2
79860d3
 
 
d807ca2
 
79860d3
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
"""
api_models.py
-------------
Pydantic models for API request/response bodies (chat, indexing, logs).
"""

from __future__ import annotations
from typing import Optional, Any
from pydantic import BaseModel


# ---------------------------------------------------------------------------
# Chat
# ---------------------------------------------------------------------------

class ChatMessage(BaseModel):
    role: str          # "user" | "assistant" | "system"
    content: str


class ChatRequest(BaseModel):
    message: str
    history: list[ChatMessage] = []
    session_id: str = ""


class TokenUsage(BaseModel):
    """Token consumption for a single chat turn (all LLM calls combined)."""
    prompt_tokens:     int = 0
    completion_tokens: int = 0
    total_tokens:      int = 0
    call_count:        int = 0   # number of separate LLM API calls in this turn


class ChatResponse(BaseModel):
    answer:          str
    followups:       list[str]  = []
    session_id:      str        = ""
    tokens_used:     TokenUsage = TokenUsage()
    history_trimmed: bool       = False   # True when earlier messages were dropped per profile limit
    warming_up:      bool       = False   # True when the profile index is still building after restart
    latency_ms:      int        = 0       # Wall-clock time for this turn (ms); 0 when warming up


# ---------------------------------------------------------------------------
# Indexing
# ---------------------------------------------------------------------------

class IndexStatusResponse(BaseModel):
    slug: str
    status: str                    # "not_indexed" | "success" | "running" | "failed" | "empty"
    chunk_count: int = 0
    document_count: int = 0
    last_indexed: Optional[str] = None
    duration_seconds: Optional[float] = None
    last_error: Optional[str] = None


class IndexHistoryEntry(BaseModel):
    timestamp: str
    profile_slug: str
    status: str
    document_count: int = 0
    duration_seconds: float = 0.0
    error: Optional[str] = None


# ---------------------------------------------------------------------------
# Prompts
# ---------------------------------------------------------------------------

class PromptEntry(BaseModel):
    name: str
    short_name: str
    content: str


class PromptsResponse(BaseModel):
    prompts: dict[str, PromptEntry]
    is_default: bool = False


class UpdatePromptRequest(BaseModel):
    short_name: str
    content: str


# ---------------------------------------------------------------------------
# Documents
# ---------------------------------------------------------------------------

class DocumentInfo(BaseModel):
    filename: str
    size_bytes: int
    uploaded_at: Optional[str] = None


class DocumentListResponse(BaseModel):
    slug: str
    documents: list[DocumentInfo]


# ---------------------------------------------------------------------------
# Logs
# ---------------------------------------------------------------------------

class LogEntry(BaseModel):
    line: str


class LogsResponse(BaseModel):
    slug: Optional[str]
    log_type: str   # "app" | "indexing" | "chat" | "profile"
    lines: list[str]
    total_lines: int


# ---------------------------------------------------------------------------
# Generic
# ---------------------------------------------------------------------------

class SuccessResponse(BaseModel):
    success: bool = True
    message: str = "OK"


class ErrorResponse(BaseModel):
    success: bool = False
    error: str
    detail: Optional[Any] = None