module Gargantext.API.Server.Named.Ngrams ( -- * Server handlers apiNgramsTableCorpus , apiNgramsTableDoc , tableNgramsPostChartsAsync ) where import Control.Lens ((%%~)) import Data.Map.Strict qualified as Map import Data.Set qualified as Set import Gargantext.API.Admin.Auth (withNamedAccess) import Gargantext.API.Admin.Auth.Types (AuthenticatedUser, PathId (..)) import Gargantext.API.Admin.EnvTypes (Env) import Gargantext.API.Errors.Types (BackendInternalError) import Gargantext.API.Metrics qualified as Metrics import Gargantext.API.Ngrams import Gargantext.API.Ngrams.Types import Gargantext.API.Prelude (GargM) import Gargantext.API.Routes.Named.Table qualified as Named import Gargantext.API.Worker (serveWorkerAPI) import Gargantext.Core.NodeStory.Types (HasNodeStory) import Gargantext.Core.Types (DocId, ListId, ListType(..), NodeId, NodeType(..)) import Gargantext.Core.Types.Query (Limit(..), Offset(..)) import Gargantext.Core.Worker.Jobs.Types qualified as Jobs import Gargantext.Database.Admin.Config (userMaster) import Gargantext.Database.Query.Table.Ngrams ( selectNgramsByDoc ) import Gargantext.Database.Query.Table.Node (getNode) import Gargantext.Database.Query.Table.Node.Error (HasNodeError) import Gargantext.Database.Query.Table.Node.Select ( selectNodesWithUsername ) import Gargantext.Database.Schema.Node (node_id, node_parent_id, node_user_id) import Gargantext.Prelude import Gargantext.Utils.Jobs.Monad (JobHandle, MonadJobStatus(..), markFailedNoErr) import Servant.Server.Generic (AsServerT) apiNgramsTableCorpus :: NodeId -> Named.TableNgramsAPI (AsServerT (GargM Env BackendInternalError)) apiNgramsTableCorpus cId = Named.TableNgramsAPI { tableNgramsGetAPI = Named.TableNgramsApiGet $ getTableNgramsCorpus cId , tableNgramsPutAPI = Named.TableNgramsApiPut $ tableNgramsPut , recomputeScoresEp = Named.RecomputeScoresNgramsApiGet $ scoresRecomputeTableNgrams cId , tableNgramsGetVersionEp = Named.TableNgramsApiGetVersion $ getTableNgramsVersion cId , tableNgramsAsyncAPI = apiNgramsAsync cId } apiNgramsTableDoc :: AuthenticatedUser -> DocId -> Named.TableNgramsAPI (AsServerT (GargM Env BackendInternalError)) apiNgramsTableDoc uid dId = withNamedAccess uid (PathNode dId) $ Named.TableNgramsAPI { tableNgramsGetAPI = Named.TableNgramsApiGet $ getTableNgramsDoc dId , tableNgramsPutAPI = Named.TableNgramsApiPut tableNgramsPut , recomputeScoresEp = Named.RecomputeScoresNgramsApiGet $ scoresRecomputeTableNgrams dId , tableNgramsGetVersionEp = Named.TableNgramsApiGetVersion $ getTableNgramsVersion dId , tableNgramsAsyncAPI = apiNgramsAsync dId } getTableNgramsVersion :: ( HasNodeStory env err m , HasNodeError err ) => NodeId -> TabType -> ListId -> m Version getTableNgramsVersion _nId _tabType listId = currentVersion listId apiNgramsAsync :: NodeId -> Named.TableNgramsAsyncAPI (AsServerT (GargM Env BackendInternalError)) apiNgramsAsync nId = Named.TableNgramsAsyncAPI { updateTableNgramsChartsEp = serveWorkerAPI $ \p -> Jobs.NgramsPostCharts { Jobs._npc_node_id = nId , Jobs._npc_args = p } } tableNgramsPostChartsAsync :: ( HasNodeStory env err m , MonadJobStatus m ) => UpdateTableNgramsCharts -> JobHandle m -> m () tableNgramsPostChartsAsync utn jobHandle = do let tabType = utn ^. utn_tab_type let listId = utn ^. utn_list_id node <- getNode listId let _nId = node ^. node_id _uId = node ^. node_user_id mCId = node ^. node_parent_id -- printDebug "[tableNgramsPostChartsAsync] tabType" tabType -- printDebug "[tableNgramsPostChartsAsync] listId" listId case mCId of Nothing -> do -- printDebug "[tableNgramsPostChartsAsync] can't update charts, no parent, nId" nId markStarted 1 jobHandle markFailedNoErr jobHandle Just cId -> do case tabType of Authors -> do -- printDebug "[tableNgramsPostChartsAsync] Authors, updating Pie, cId" cId markStarted 1 jobHandle _ <- Metrics.updatePie cId (Just listId) tabType Nothing markComplete jobHandle Institutes -> do -- printDebug "[tableNgramsPostChartsAsync] Institutes, updating Tree, cId" cId -- printDebug "[tableNgramsPostChartsAsync] updating tree StopTerm, cId" cId markStarted 3 jobHandle _ <- Metrics.updateTree cId (Just listId) tabType StopTerm -- printDebug "[tableNgramsPostChartsAsync] updating tree CandidateTerm, cId" cId markProgress 1 jobHandle _ <- Metrics.updateTree cId (Just listId) tabType CandidateTerm -- printDebug "[tableNgramsPostChartsAsync] updating tree MapTerm, cId" cId markProgress 1 jobHandle _ <- Metrics.updateTree cId (Just listId) tabType MapTerm markComplete jobHandle Sources -> do -- printDebug "[tableNgramsPostChartsAsync] Sources, updating chart, cId" cId markStarted 1 jobHandle _ <- Metrics.updatePie cId (Just listId) tabType Nothing markComplete jobHandle Terms -> do -- printDebug "[tableNgramsPostChartsAsync] Terms, updating Metrics (Histo), cId" cId markStarted 6 jobHandle {- _ <- Metrics.updateChart cId listId tabType Nothing logRefSuccess _ <- Metrics.updatePie cId (Just listId) tabType Nothing logRefSuccess _ <- Metrics.updateScatter cId (Just listId) tabType Nothing logRefSuccess _ <- Metrics.updateTree cId (Just listId) tabType StopTerm logRefSuccess _ <- Metrics.updateTree cId (Just listId) tabType CandidateTerm logRefSuccess _ <- Metrics.updateTree cId (Just listId) tabType MapTerm -} markComplete jobHandle _otherTabType -> do -- printDebug "[tableNgramsPostChartsAsync] no update for tabType = " tabType markStarted 1 jobHandle markFailedNoErr jobHandle {- { _ne_list :: ListType If we merge the parents/children we can potentially create cycles! , _ne_parent :: Maybe NgramsTerm , _ne_children :: MSet NgramsTerm } -} scoresRecomputeTableNgrams :: forall env err m. ( HasNodeStory env err m, HasNodeError err ) => NodeId -> TabType -> ListId -> m Int scoresRecomputeTableNgrams nId tabType listId = do tableMap <- getNgramsTableMap listId ngramsType _ <- tableMap & v_data %%~ (setNgramsTableScores nId listId ngramsType) . Map.mapWithKey ngramsElementFromRepo pure $ 1 where ngramsType = ngramsTypeFromTabType tabType -- | Text search is deactivated for now for ngrams by doc only getTableNgramsDoc :: ( HasNodeStory env err m , HasNodeError err ) => DocId -> TabType -> ListId -> Limit -> Maybe Offset -> Maybe ListType -> Maybe MinSize -> Maybe MaxSize -> Maybe OrderBy -> Maybe Text -- full text search -> m (VersionedWithCount NgramsTable) getTableNgramsDoc dId tabType listId limit_ offset listType minSize maxSize orderBy _mt = do ns <- selectNodesWithUsername NodeList userMaster let ngramsType = ngramsTypeFromTabType tabType ngs <- selectNgramsByDoc (ns <> [listId]) dId ngramsType let searchQueryFn (NgramsTerm nt) = Set.member nt (Set.fromList ngs) searchQuery = NgramsSearchQuery { _nsq_limit = limit_ , _nsq_offset = offset , _nsq_listType = listType , _nsq_minSize = minSize , _nsq_maxSize = maxSize , _nsq_orderBy = orderBy , _nsq_searchQuery = searchQueryFn } getTableNgrams dId listId tabType searchQuery