2 Module : Gargantext.Core.Viz.Phylo.API
4 Copyright : (c) CNRS, 2017-Present
5 License : AGPL + CECILL v3
6 Maintainer : team@gargantext.org
7 Stability : experimental
13 module Gargantext.Core.Viz.Phylo.API.Tools
17 import Data.Aeson (Value, decodeFileStrict, eitherDecode, encode)
19 import Data.Maybe (catMaybes)
21 import Data.Text (Text, pack)
22 import Data.Time.Calendar (fromGregorian, diffGregorianDurationClip, cdMonths, diffDays, showGregorian)
23 import Data.Time.Clock.POSIX(posixSecondsToUTCTime)
24 import Gargantext.API.Ngrams.Prelude (getTermList)
25 import Gargantext.API.Ngrams.Tools (getRepo')
26 import Gargantext.API.Ngrams.Types (NgramsTerm(..))
27 import Gargantext.API.Node.Corpus.Export (getContextNgrams)
28 import Gargantext.API.Prelude (GargNoServer)
29 import Gargantext.Core.Text.Context (TermList)
30 import Gargantext.Core.Types (Context)
31 import Gargantext.Core.Types.Main (ListType(MapTerm))
32 import Gargantext.Core.Viz.Phylo (TimeUnit(..), Date, Document(..), Config(..), Phylo)
33 import Gargantext.Core.Viz.Phylo.PhyloExport (toPhyloExport, dotToFile)
34 import Gargantext.Core.Viz.Phylo.PhyloMaker (toPhylo, toPhyloStep)
35 import Gargantext.Core.Viz.Phylo.PhyloTools ({-printIOMsg, printIOComment,-} setConfig)
36 import Gargantext.Database.Admin.Types.Hyperdata.Document (HyperdataDocument(..))
37 import Gargantext.Database.Admin.Types.Hyperdata (HyperdataPhylo(..))
38 import Gargantext.Database.Admin.Types.Node (CorpusId, ContextId, PhyloId)
39 import Gargantext.Database.Query.Table.Node (defaultList, getNodeWith)
40 import Gargantext.Database.Query.Table.NodeContext (selectDocNodes)
41 import Gargantext.Database.Schema.Context
42 import Gargantext.Database.Schema.Node
43 import Gargantext.Database.Schema.Ngrams (NgramsType(..))
44 import Gargantext.Prelude
45 import Prelude as Prelude
46 import System.Process as Shell
47 import qualified Data.ByteString.Lazy as Lazy
48 import qualified Data.List as List
49 import qualified Data.Map as Map
50 import qualified Data.Set as Set
53 --------------------------------------------------------------------
54 getPhyloData :: PhyloId -> GargNoServer (Maybe Phylo)
55 getPhyloData phyloId = do
56 nodePhylo <- getNodeWith phyloId (Proxy :: Proxy HyperdataPhylo)
57 pure $ _hp_data $ _node_hyperdata nodePhylo
59 putPhylo :: PhyloId -> GargNoServer Phylo
62 savePhylo :: PhyloId -> GargNoServer ()
65 --------------------------------------------------------------------
66 phylo2dot2json :: Phylo -> IO Value
67 phylo2dot2json phylo = do
70 file_from = "/tmp/fromPhylo.json"
71 file_dot = "/tmp/tmp.dot"
72 file_to_json = "/tmp/toPhylo.json"
74 _ <- dotToFile file_from (toPhyloExport phylo)
75 _ <- Shell.callProcess "/usr/bin/dot" ["-Tdot", "-o", file_dot, file_from]
76 _ <- Shell.callProcess "/usr/bin/dot" ["-Txdot_json", "-o", file_to_json, file_dot]
78 maybeValue <- decodeFileStrict file_to_json
80 _ <- Shell.callProcess "/bin/rm" ["-rf", file_from, file_to_json, file_dot]
83 Nothing -> panic "[G.C.V.Phylo.API.phylo2dot2json] Error no file"
88 flowPhyloAPI :: Config -> CorpusId -> GargNoServer Phylo
89 flowPhyloAPI config cId = do
90 (mapList, corpus) <- corpusIdtoDocuments (timeUnit config) cId
91 phyloWithCliques <- pure $ toPhyloStep corpus mapList config
92 -- writePhylo phyloWithCliquesFile phyloWithCliques
93 pure $ toPhylo (setConfig config phyloWithCliques)
95 --------------------------------------------------------------------
96 corpusIdtoDocuments :: TimeUnit -> CorpusId -> GargNoServer (TermList, [Document])
97 corpusIdtoDocuments timeUnit corpusId = do
98 docs <- selectDocNodes corpusId
100 lId <- defaultList corpusId
101 repo <- getRepo' [lId]
103 ngs_terms <- getContextNgrams corpusId lId MapTerm NgramsTerms repo
104 ngs_sources <- getContextNgrams corpusId lId MapTerm Sources repo
106 termList <- getTermList lId MapTerm NgramsTerms
109 Nothing -> panic "[G.C.V.Phylo.API] no termList found"
110 Just termList' -> pure (termList', docs')
114 -> context2phyloDocument timeUnit doc (ngs_terms, ngs_sources)
118 context2phyloDocument :: TimeUnit
119 -> Context HyperdataDocument
120 -> (Map ContextId (Set NgramsTerm), Map ContextId (Set NgramsTerm))
122 context2phyloDocument timeUnit context (ngs_terms, ngs_sources) = do
123 let contextId = _context_id context
124 (date, date') <- context2date context timeUnit
125 text <- Map.lookup contextId ngs_terms
126 sources <- Map.lookup contextId ngs_sources
127 pure $ Document date date'
132 toText x = Set.toList $ Set.map unNgramsTerm x
135 context2date :: Context HyperdataDocument -> TimeUnit -> Maybe (Date, Text)
136 context2date context timeUnit = do
137 let hyperdata = _context_hyperdata context
138 year <- _hd_publication_year hyperdata
139 month <- _hd_publication_month hyperdata
140 day <- _hd_publication_day hyperdata
141 pure (toPhyloDate year month day timeUnit, toPhyloDate' year month day timeUnit)
147 toMonths :: Integer -> Int -> Int -> Date
148 toMonths y m d = fromIntegral $ cdMonths
149 $ diffGregorianDurationClip (fromGregorian y m d)
150 (fromGregorian 0000 0 0)
153 toDays :: Integer -> Int -> Int -> Date
154 toDays y m d = fromIntegral
155 $ diffDays (fromGregorian y m d) (fromGregorian 0000 0 0)
158 toPhyloDate :: Int -> Int -> Int -> TimeUnit -> Date
159 toPhyloDate y m d tu = case tu of
161 Month _ _ _ -> toMonths (Prelude.toInteger y) m d
162 Week _ _ _ -> div (toDays (Prelude.toInteger y) m d) 7
163 Day _ _ _ -> toDays (Prelude.toInteger y) m d
164 _ -> panic "[G.C.V.Phylo.API] toPhyloDate"
166 toPhyloDate' :: Int -> Int -> Int -> TimeUnit -> Text
167 toPhyloDate' y m d tu = case tu of
168 Epoch _ _ _ -> pack $ show $ posixSecondsToUTCTime $ fromIntegral y
169 Year _ _ _ -> pack $ showGregorian $ fromGregorian (toInteger y) m d
170 Month _ _ _ -> pack $ showGregorian $ fromGregorian (toInteger y) m d
171 Week _ _ _ -> pack $ showGregorian $ fromGregorian (toInteger y) m d
172 Day _ _ _ -> pack $ showGregorian $ fromGregorian (toInteger y) m d
176 writePhylo :: [Char] -> Phylo -> IO ()
177 writePhylo path phylo = Lazy.writeFile path $ encode phylo
180 readPhylo :: [Char] -> IO Phylo
182 phyloJson <- (eitherDecode <$> readJson path) :: IO (Either String Phylo)
187 Right phylo -> pure phylo
190 -- | To read and decode a Json file
191 readJson :: FilePath -> IO Lazy.ByteString
192 readJson path = Lazy.readFile path