ums.management.main

  1# Agenten Plattform
  2#
  3# (c) 2024 Magnus Bender
  4# 	Institute of Humanities-Centered Artificial Intelligence (CHAI)
  5# 	Universitaet Hamburg
  6# 	https://www.chai.uni-hamburg.de/~bender
  7#  
  8# source code released under the terms of GNU Public License Version 3
  9# https://www.gnu.org/licenses/gpl-3.0.txt
 10
 11import os
 12
 13from typing import List
 14from datetime import datetime
 15
 16from fastapi import FastAPI, Request, BackgroundTasks, HTTPException
 17from fastapi.responses import HTMLResponse
 18from fastapi.templating import Jinja2Templates
 19
 20from jinja2.runtime import Undefined as JinjaUndefined
 21
 22from ums.management.interface import Interface
 23from ums.management.db import DB, MessageDbRow
 24from ums.management.process import MessageProcessor
 25
 26from ums.utils import AgentMessage, AgentResponse, TEMPLATE_PATH
 27
 28class WebMain():
 29
 30	_TIME_FORMAT = "%H:%M:%S %d.%m.%Y"
 31
 32	def __init__(self):
 33		self._init_app()
 34		self._init_templates()
 35
 36		self.db = DB()
 37		self.msg_process = MessageProcessor(self.db)
 38
 39		self._add_routes()
 40		self._add_routers()
 41
 42
 43	def _init_app(self):
 44		self.app = FastAPI(
 45			title="Agenten Plattform",
 46			description="Agenten Plattform – Management",
 47			openapi_url="/api/schema.json",
 48			docs_url='/api',
 49			redoc_url=None
 50		)
 51
 52	def _init_templates(self):
 53		self.template = Jinja2Templates(
 54			directory=TEMPLATE_PATH,
 55			auto_reload=True
 56		)
 57		
 58		def timestamp2date(t:int|JinjaUndefined) -> str:
 59			return "" if isinstance(t, JinjaUndefined) \
 60				else datetime.fromtimestamp(t).strftime(self._TIME_FORMAT)
 61		self.template.env.globals["timestamp2date"] = timestamp2date
 62
 63		def date2timestamp(d:str|JinjaUndefined) -> int|str:
 64			return "" if isinstance(d, JinjaUndefined) \
 65				else int(datetime.strptime(d, self._TIME_FORMAT).timestamp())
 66		self.template.env.globals["date2timestamp"] = date2timestamp
 67
 68
 69	def _add_routers(self):
 70		interface_router = Interface(self.template, self.db)
 71		self.app.include_router(interface_router.router)
 72
 73	def _add_routes(self):
 74
 75		@self.app.get("/index", response_class=HTMLResponse, summary="Link list")
 76		def index(request: Request):
 77			return self.template.TemplateResponse(
 78				'index.html',
 79				{"request" : request}
 80			)
 81
 82		@self.app.post("/message", summary="Send a message to the management", tags=['agents'])
 83		def message(request: Request, message:AgentMessage, background_tasks: BackgroundTasks) -> AgentResponse:
 84
 85			receiver = request.headers['host']
 86			if ':' in receiver:
 87				receiver = receiver[:receiver.rindex(':')]
 88			
 89			sender = request.headers['x-forwarded-for']
 90
 91			return self.msg_process.new_message(sender, receiver, message, background_tasks)
 92		
 93		@self.app.get("/list", summary="Get list of messages (like table)", tags=["cli, agents"])
 94		def list(id:str|None=None, sender:str|None=None, recipient:str|None=None,
 95			processed:bool|None=None, solution:bool|None=None,
 96			time_after:int|None=None, time_before:int|None=None,
 97			limit:int=10, offset:int=0
 98		) -> List[MessageDbRow]:
 99
100			db_args = {
101				"limit" : limit,
102				"offset" : offset
103			}
104
105			for v,n in (
106				(id,'id'), (sender,'sender'), (recipient,'recipient'),
107				(processed,'processed'), (solution,'solution'),
108				(time_after, 'time_after'), (time_before, 'time_before') 
109			):
110				if not v is None:
111					db_args[n] = v
112
113			return [row for row in self.db.iterate(**db_args)]
114
115		@self.app.get("/list/single", summary="Get a single message", tags=["cli, agents"])
116		def status(count:int) -> MessageDbRow:
117			msg = self.db.by_count(count)
118			if msg is None:
119				raise HTTPException(status_code=404, detail="Message not found")
120			
121			return msg
122		
123if __name__ == "ums.management.main" and os.environ.get('SERVE', 'false').lower() == 'true':	
124	main = WebMain()
125	app = main.app
class WebMain:
 29class WebMain():
 30
 31	_TIME_FORMAT = "%H:%M:%S %d.%m.%Y"
 32
 33	def __init__(self):
 34		self._init_app()
 35		self._init_templates()
 36
 37		self.db = DB()
 38		self.msg_process = MessageProcessor(self.db)
 39
 40		self._add_routes()
 41		self._add_routers()
 42
 43
 44	def _init_app(self):
 45		self.app = FastAPI(
 46			title="Agenten Plattform",
 47			description="Agenten Plattform – Management",
 48			openapi_url="/api/schema.json",
 49			docs_url='/api',
 50			redoc_url=None
 51		)
 52
 53	def _init_templates(self):
 54		self.template = Jinja2Templates(
 55			directory=TEMPLATE_PATH,
 56			auto_reload=True
 57		)
 58		
 59		def timestamp2date(t:int|JinjaUndefined) -> str:
 60			return "" if isinstance(t, JinjaUndefined) \
 61				else datetime.fromtimestamp(t).strftime(self._TIME_FORMAT)
 62		self.template.env.globals["timestamp2date"] = timestamp2date
 63
 64		def date2timestamp(d:str|JinjaUndefined) -> int|str:
 65			return "" if isinstance(d, JinjaUndefined) \
 66				else int(datetime.strptime(d, self._TIME_FORMAT).timestamp())
 67		self.template.env.globals["date2timestamp"] = date2timestamp
 68
 69
 70	def _add_routers(self):
 71		interface_router = Interface(self.template, self.db)
 72		self.app.include_router(interface_router.router)
 73
 74	def _add_routes(self):
 75
 76		@self.app.get("/index", response_class=HTMLResponse, summary="Link list")
 77		def index(request: Request):
 78			return self.template.TemplateResponse(
 79				'index.html',
 80				{"request" : request}
 81			)
 82
 83		@self.app.post("/message", summary="Send a message to the management", tags=['agents'])
 84		def message(request: Request, message:AgentMessage, background_tasks: BackgroundTasks) -> AgentResponse:
 85
 86			receiver = request.headers['host']
 87			if ':' in receiver:
 88				receiver = receiver[:receiver.rindex(':')]
 89			
 90			sender = request.headers['x-forwarded-for']
 91
 92			return self.msg_process.new_message(sender, receiver, message, background_tasks)
 93		
 94		@self.app.get("/list", summary="Get list of messages (like table)", tags=["cli, agents"])
 95		def list(id:str|None=None, sender:str|None=None, recipient:str|None=None,
 96			processed:bool|None=None, solution:bool|None=None,
 97			time_after:int|None=None, time_before:int|None=None,
 98			limit:int=10, offset:int=0
 99		) -> List[MessageDbRow]:
100
101			db_args = {
102				"limit" : limit,
103				"offset" : offset
104			}
105
106			for v,n in (
107				(id,'id'), (sender,'sender'), (recipient,'recipient'),
108				(processed,'processed'), (solution,'solution'),
109				(time_after, 'time_after'), (time_before, 'time_before') 
110			):
111				if not v is None:
112					db_args[n] = v
113
114			return [row for row in self.db.iterate(**db_args)]
115
116		@self.app.get("/list/single", summary="Get a single message", tags=["cli, agents"])
117		def status(count:int) -> MessageDbRow:
118			msg = self.db.by_count(count)
119			if msg is None:
120				raise HTTPException(status_code=404, detail="Message not found")
121			
122			return msg
db
msg_process