Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
86.84% covered (warning)
86.84%
33 / 38
66.67% covered (warning)
66.67%
2 / 3
CRAP
0.00% covered (danger)
0.00%
0 / 1
TextCat
86.84% covered (warning)
86.84%
33 / 38
66.67% covered (warning)
66.67%
2 / 3
17.66
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 detect
86.11% covered (warning)
86.11%
31 / 36
0.00% covered (danger)
0.00%
0 / 1
15.60
 build
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
1<?php
2
3namespace CirrusSearch\LanguageDetector;
4
5use CirrusSearch\CirrusConfigNames;
6use CirrusSearch\LogChannel;
7use CirrusSearch\SearchConfig;
8use MediaWiki\Logger\LoggerFactory;
9
10/**
11 * Try to detect language with TextCat text categorizer
12 */
13class TextCat implements Detector {
14
15    /**
16     * @var SearchConfig
17     */
18    private $config;
19
20    public function __construct( SearchConfig $config ) {
21        $this->config = $config;
22    }
23
24    /**
25     * Detect language
26     *
27     * @param string $text Text to detect language
28     * @return string|null Preferred language, or null if none found
29     */
30    public function detect( $text ) {
31        $dirs = $this->config->getElement( CirrusConfigNames::TextcatModel );
32        if ( !$dirs ) {
33            return null;
34        }
35        if ( !is_array( $dirs ) ) { // backward compatibility
36            $dirs = [ $dirs ];
37        }
38        foreach ( $dirs as $dir ) {
39            if ( !is_dir( $dir ) ) {
40                LoggerFactory::getInstance( LogChannel::DEFAULT )->warning(
41                    "Bad directory for TextCat model: {dir}",
42                    [ "dir" => $dir ]
43                );
44            }
45        }
46
47        $textcat = new \TextCat( $dirs );
48
49        $textcatConfig = $this->config->getElement( CirrusConfigNames::TextcatConfig );
50        if ( $textcatConfig ) {
51            if ( isset( $textcatConfig['maxNgrams'] ) ) {
52                $textcat->setMaxNgrams( intval( $textcatConfig['maxNgrams'] ) );
53            }
54            if ( isset( $textcatConfig['maxReturnedLanguages'] ) ) {
55                $textcat->setMaxReturnedLanguages( intval( $textcatConfig['maxReturnedLanguages'] ) );
56            }
57            if ( isset( $textcatConfig['resultsRatio'] ) ) {
58                $textcat->setResultsRatio( floatval( $textcatConfig['resultsRatio'] ) );
59            }
60            if ( isset( $textcatConfig['minInputLength'] ) ) {
61                $textcat->setMinInputLength( intval( $textcatConfig['minInputLength'] ) );
62            }
63            if ( isset( $textcatConfig['maxProportion'] ) ) {
64                $textcat->setMaxProportion( floatval( $textcatConfig['maxProportion'] ) );
65            }
66            if ( isset( $textcatConfig['langBoostScore'] ) ) {
67                $textcat->setLangBoostScore( floatval( $textcatConfig['langBoostScore'] ) );
68            }
69
70            if ( isset( $textcatConfig['numBoostedLangs'] ) &&
71                $this->config->getElement( CirrusConfigNames::TextcatLanguages )
72            ) {
73                $textcat->setBoostedLangs( array_slice(
74                    $this->config->getElement( CirrusConfigNames::TextcatLanguages ),
75                    0, $textcatConfig['numBoostedLangs'] ) );
76            }
77        }
78        $languages = $textcat->classify( $text, $this->config->getElement( CirrusConfigNames::TextcatLanguages ) );
79        if ( $languages ) {
80            // For now, just return the best option
81            // TODO: think what else we could do
82            reset( $languages );
83            return key( $languages );
84        }
85
86        return null;
87    }
88
89    /**
90     * @param SearchConfig $config
91     * @return Detector
92     */
93    public static function build( SearchConfig $config ) {
94        return new self( $config );
95    }
96}