You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
304 lines
11 KiB
Python
304 lines
11 KiB
Python
from datetime import datetime
|
|
from typing import List, Optional
|
|
from uuid import UUID
|
|
from enum import Enum
|
|
from pydantic import Field, field_validator, BaseModel
|
|
from fastapi import UploadFile
|
|
|
|
from src.models import DefaultBase, Pagination
|
|
|
|
equipment_keywords = ["boiler", "turbine", "generator", "condenser", "pump", "valve", "motor", "transformer", "compressor", "fan", "heater", "cooler", "pipe", "tubes", "panel", "switchgear", "relay", "breaker", "bearing", "gearbox", "chiller", "evaporator", "conveyor", "filter", "separator", "reactor", "furnace", "burner", "nozzle", "rotor", "stator", "shaft", "seal", "coupling", "damper", "duct", "expander", "economizer", "superheater", "deaerator", "feedwater", "drum", "tank", "vessel", "silo", "hopper", "agitator", "mixer", "blower", "injector", "strainer", "screen", "scrubber", "stack", "chimney", "insulator", "busbar", "rectifier", "inverter", "panel", "switch", "sensor", "transmitter", "controller", "PLC", "DCS", "SCADA", "soot_blower", "economizer"]
|
|
|
|
class FlowType(str, Enum):
|
|
LLM_ONLY = "llm_only"
|
|
ORIGINAL = "rag_retrieval_first"
|
|
LLM_FIRST = "rag_llm_first"
|
|
BATCH_SUMMARIZE = "rag_batch_summarize"
|
|
AGENTIC = "rag_agentic"
|
|
|
|
class ChatMessageBase(DefaultBase):
|
|
role: str = Field(..., description="Role of the message sender (e.g., 'user', 'assistant')")
|
|
content: str = Field(..., description="Content of the chat message")
|
|
created_at: Optional[datetime] = Field(None, nullable=True)
|
|
updated_at: Optional[datetime] = Field(None, nullable=True)
|
|
created_by: Optional[str] = Field(None, nullable=True)
|
|
updated_by: Optional[str] = Field(None, nullable=True)
|
|
|
|
class ChatMessageCreate(ChatMessageBase):
|
|
pass
|
|
|
|
class ChatMessageUpdate(ChatMessageBase):
|
|
pass
|
|
|
|
class ChatMessageRead(ChatMessageBase):
|
|
id: UUID = Field(..., description="Unique identifier for the chat message")
|
|
|
|
class ChatMessagePagination(Pagination):
|
|
items: List[ChatMessageRead] = Field([], description="List of chat messages with pagination support")
|
|
|
|
class ChatMessageRead(ChatMessageBase):
|
|
id: UUID = Field(..., description="Unique identifier for the chat message")
|
|
|
|
class ChatMessagePagination(Pagination):
|
|
items: List[ChatMessageRead] = Field([], description="List of chat messages with pagination support")
|
|
|
|
class FileAttachment(DefaultBase):
|
|
filename: str
|
|
url: str
|
|
size: Optional[int] = None
|
|
content_type: Optional[str] = None
|
|
|
|
class ChatMessage(DefaultBase):
|
|
role: str
|
|
content: str
|
|
attachments: Optional[List[FileAttachment]] = Field(default_factory=list, description="Optional list of attached files")
|
|
|
|
class ChatRequest(DefaultBase):
|
|
conversation_id: Optional[UUID] = None
|
|
message_id: Optional[UUID] = None
|
|
message: Optional[str] = None
|
|
equipment_id: Optional[UUID] = None
|
|
attachments: Optional[List[UploadFile]] = None
|
|
flow_type: Optional[FlowType] = Field(default=FlowType.ORIGINAL, description="Type of processing flow to use")
|
|
questions_batch: Optional[List[str]] = Field(default=None, description="List of questions for batch processing (only used with batch_summarize flow)")
|
|
model: Optional[str] = Field(default=None, description="LLM model name to use")
|
|
context_state: Optional[dict] = Field(default=None, description="Current context state (symptoms, failure modes, etc.)")
|
|
enable_background_analysis: Optional[bool] = Field(default=True, description="Toggle to enable/disable background RCFA analysis")
|
|
|
|
class Performance(DefaultBase):
|
|
prompt_tokens: Optional[int] = None
|
|
response_tokens: Optional[int] = None
|
|
tokens_used: Optional[int] = None
|
|
response_time: Optional[float] = None
|
|
response_length: Optional[int] = None
|
|
|
|
class ChatResponse(DefaultBase):
|
|
conversation_id: UUID
|
|
message: str
|
|
user_message: str
|
|
context: Optional[List] = None
|
|
attachments: Optional[List] = None
|
|
sources: Optional[List] = None
|
|
sources_filepath: Optional[List] = None
|
|
timestamp: str
|
|
response_timestamp: str
|
|
chat_model: str
|
|
time_taken: Optional[float] = None # float, seconds
|
|
prompt_tokens: Optional[float] = None
|
|
response_tokens: Optional[float] = None
|
|
tokens_used: Optional[float] = None
|
|
|
|
class ChatHistory(DefaultBase):
|
|
id: str
|
|
user_id: str
|
|
message: str
|
|
attachments: Optional[List] = None # Store as comma-separated text array
|
|
attachments_filepath: Optional[List] = None # Store as comma-separated text array
|
|
response: str
|
|
context: Optional[List] = None
|
|
sources: Optional[List] = None
|
|
sources_filepath: Optional[List] = None # Store as comma-separated text array
|
|
time_taken: Optional[float] = None
|
|
prompt_tokens: Optional[float] = None
|
|
response_tokens: Optional[float] = None
|
|
tokens_used: Optional[float] = None
|
|
timestamp: Optional[datetime] = None
|
|
response_timestamp: Optional[datetime] = None
|
|
conversation_id: str
|
|
chat_model: Optional[str] = None
|
|
embedding_model: Optional[str] = None
|
|
ocr_model: Optional[str] = None
|
|
feedback: Optional[str] = None
|
|
feedback_comment: Optional[str] = None
|
|
feedback_screenshot: Optional[str] = None
|
|
last_location_tag: Optional[str] = None
|
|
context_info: Optional[dict] = None
|
|
references: Optional[List[dict]] = None
|
|
updated_at: Optional[datetime] = None
|
|
created_at: Optional[datetime] = None
|
|
|
|
@field_validator('user_id', 'conversation_id', mode='before')
|
|
@classmethod
|
|
def convert_uuid_to_str(cls, v):
|
|
return str(v) if v else None
|
|
|
|
class ChatHistoryMetadata(BaseModel):
|
|
rcfa_phase: str
|
|
rcfa_state: dict
|
|
title: str
|
|
|
|
class ChatHistoryResponse(BaseModel):
|
|
messages: List[ChatHistory]
|
|
metadata: ChatHistoryMetadata
|
|
|
|
class Conversation(DefaultBase):
|
|
user_id: str
|
|
conversation_id: str
|
|
conversation_title: str
|
|
created_at: Optional[datetime] = None
|
|
updated_at: Optional[datetime] = None
|
|
is_exported: bool = False
|
|
exported_at: Optional[datetime] = None
|
|
report_name: Optional[str] = None
|
|
report_content: Optional[str] = None
|
|
rcfa_phase: Optional[str] = None
|
|
rcfa_state: Optional[dict] = None
|
|
|
|
@field_validator('user_id', 'conversation_id', mode='before')
|
|
@classmethod
|
|
def convert_uuid_to_str(cls, v):
|
|
return str(v) if v else None
|
|
|
|
class ConversationExportUpdate(BaseModel):
|
|
is_exported: bool = True
|
|
report_name: str
|
|
report_content: str
|
|
|
|
class ConversationUpdate(DefaultBase):
|
|
conversation_title: str = Field(..., description="New title for the conversation")
|
|
|
|
class ConversationDataPagination(Pagination):
|
|
items: List[Conversation] = Field([], description="List of conversations with pagination support")
|
|
|
|
class IntentDetection(BaseModel):
|
|
intent: str = Field(
|
|
description="Identifikasi intensi dari masukkan pengguna dengan pendekatan 'Intent Classification'. Identifikasi masukkan pengguna berdasarkan dengan enum.",
|
|
enum=[
|
|
"DefinisiKegagalan",
|
|
"DefinisiEquipment",
|
|
"DeskripsiDokumen",
|
|
"Mendeskripsikan",
|
|
"JelaskanGambar",
|
|
"GejalaKegagalan",
|
|
"LokasiKegagalan",
|
|
"TindakanMitigasi",
|
|
"StrategiPerawatan",
|
|
"JenisSensor",
|
|
"StandarAmbangBatas",
|
|
"TipsDiagnostik",
|
|
"RingkasanKeputusan",
|
|
"RincianManfaatTahunan",
|
|
"AnalisisEkonomi",
|
|
"AnalisisKejadianUtama",
|
|
"AkibatJikaTidakDiatasi",
|
|
"EstimasiBiayaPenanggulangan",
|
|
"InformasiLaporan",
|
|
"Lainnya",
|
|
"FileAttachment" # Added intent for file attachment
|
|
]
|
|
)
|
|
equipment_name: str = Field(
|
|
description="Nama equipment yang dibahas atau dimasukkan oleh pengguna. Jika tidak ada nama equipment yang relevan, berikan string kosong dengan respon ''.",
|
|
enum=equipment_keywords
|
|
)
|
|
function_call: str = Field(
|
|
description="Kebutuhan untuk melakukan function call jika masukkan pengguna terkait data reliability atau sensor equipment. Data reliability equipment terdiri dari nilai reliability, MTTR, MTBF, MDT, failure rate, next failure, dan jumlah failure historis equipment. Sedangkan data sensor terdiri dari nama sensor, status sensor, dan value sensor per equipment. Identifikasi hasil berdasarkan enum",
|
|
enum=["Reliability", "MTTR", "MTBF", "Sensor", "MDT"]
|
|
)
|
|
confidence: float = Field(description="Level kepercayaan hasil dari identifikasi (0-1).")
|
|
location_tag: float = Field(description="Unique indentifier equipment.")
|
|
|
|
class ClassifierResponse(BaseModel):
|
|
intent_detection: IntentDetection
|
|
response: str
|
|
|
|
class UpdateFeedback(BaseModel):
|
|
update: str # "good" | "bad"
|
|
comment: Optional[str] = None
|
|
screenshot: Optional[str] = None # base64 compressed image
|
|
|
|
class EvaluateRequest(DefaultBase):
|
|
response_id: UUID
|
|
user_id: UUID
|
|
user_message: str
|
|
ai_response: str
|
|
context: Optional[List[str]] = None
|
|
ground_truth: str
|
|
|
|
class EvaluateResponse(DefaultBase):
|
|
faithfullness: float
|
|
answer_relevance: float
|
|
context_recall: float
|
|
context_relevancy: float
|
|
|
|
class RootCauseRequest(BaseModel):
|
|
equipment_type: Optional[str] = Field(None, description="Tipe dari equipment, contoh: centrifugal_pump")
|
|
problem: Optional[str] = Field(None, description="Masalah spesifik yang dialami, contoh: high_vibration")
|
|
|
|
class RootCauseResponse(BaseModel):
|
|
equipment_type: str
|
|
problem_observed: Optional[str] = None
|
|
possible_causes_to_check: Optional[List[str]] = None
|
|
available_problems: Optional[List[str]] = None
|
|
available_equipment_types: Optional[List[str]] = None
|
|
instruction_for_llm: str
|
|
error: Optional[str] = None
|
|
class ModelRead(BaseModel):
|
|
name: str
|
|
display_name: str
|
|
description: Optional[str] = None
|
|
provider: str
|
|
|
|
class AdminModelRead(BaseModel):
|
|
name: str
|
|
display_name: str
|
|
model: str
|
|
model_server: str
|
|
api_key: str
|
|
provider: str
|
|
description: Optional[str] = None
|
|
stream: bool
|
|
enabled: bool
|
|
is_default: bool
|
|
generate_cfg: Optional[dict] = None
|
|
|
|
class ModelConfigCreate(BaseModel):
|
|
name: str
|
|
display_name: str
|
|
model: str
|
|
model_server: str
|
|
api_key: Optional[str] = "not-needed"
|
|
provider: Optional[str] = "openai"
|
|
description: Optional[str] = None
|
|
stream: Optional[bool] = True
|
|
enabled: Optional[bool] = True
|
|
generate_cfg: Optional[dict] = None
|
|
|
|
class ModelConfigUpdate(BaseModel):
|
|
display_name: str
|
|
model: str
|
|
model_server: str
|
|
api_key: Optional[str] = "not-needed"
|
|
provider: Optional[str] = "openai"
|
|
description: Optional[str] = None
|
|
stream: Optional[bool] = True
|
|
enabled: Optional[bool] = True
|
|
generate_cfg: Optional[dict] = None
|
|
|
|
class MemoryRead(DefaultBase):
|
|
"""A private, user-owned long-term memory shown in the Memory Lab."""
|
|
|
|
id: UUID
|
|
conversation_id: Optional[UUID] = None
|
|
source_type: str
|
|
title: Optional[str] = None
|
|
summary: str
|
|
excerpt: Optional[str] = None
|
|
location_tag: Optional[str] = None
|
|
equipment: Optional[str] = None
|
|
confidence: Optional[float] = None
|
|
created_at: Optional[datetime] = None
|
|
|
|
|
|
class MemoryLabSnapshot(DefaultBase):
|
|
"""Safe developer-facing view of the current user's private memories."""
|
|
|
|
items: List[MemoryRead] = Field(default_factory=list)
|
|
total: int = 0
|
|
retrieval_limit: int = 50
|
|
explicit_only: bool = True
|
|
user_private: bool = True
|
|
secrets_blocked: bool = True
|
|
|
|
|