Implemented module to query Wolfram Alpha
This commit is contained in:
parent
0880d53894
commit
3ba2dfba4a
6 changed files with 215 additions and 0 deletions
|
@ -66,6 +66,8 @@
|
||||||
<ID>ReturnCount:ExceptionSanitizer.kt$ExceptionSanitizer$fun ModuleException.sanitize(vararg sanitize: String): ModuleException</ID>
|
<ID>ReturnCount:ExceptionSanitizer.kt$ExceptionSanitizer$fun ModuleException.sanitize(vararg sanitize: String): ModuleException</ID>
|
||||||
<ID>SwallowedException:GoogleSearchTest.kt$GoogleSearchTest$e: ModuleException</ID>
|
<ID>SwallowedException:GoogleSearchTest.kt$GoogleSearchTest$e: ModuleException</ID>
|
||||||
<ID>SwallowedException:StockQuoteTest.kt$StockQuoteTest$e: ModuleException</ID>
|
<ID>SwallowedException:StockQuoteTest.kt$StockQuoteTest$e: ModuleException</ID>
|
||||||
|
<ID>SwallowedException:WolframAlpha.kt$WolframAlpha.Companion$ioe: IOException</ID>
|
||||||
|
<ID>SwallowedException:WolframAlphaTest.kt$WolframAlphaTest$e: ModuleException</ID>
|
||||||
<ID>ThrowsCount:GoogleSearch.kt$GoogleSearch.Companion$@JvmStatic @Throws(ModuleException::class) fun searchGoogle(query: String, apiKey: String?, cseKey: String?): List<Message></ID>
|
<ID>ThrowsCount:GoogleSearch.kt$GoogleSearch.Companion$@JvmStatic @Throws(ModuleException::class) fun searchGoogle(query: String, apiKey: String?, cseKey: String?): List<Message></ID>
|
||||||
<ID>ThrowsCount:StockQuote.kt$StockQuote.Companion$@JvmStatic @Throws(ModuleException::class) fun getQuote(symbol: String, apiKey: String?): List<Message></ID>
|
<ID>ThrowsCount:StockQuote.kt$StockQuote.Companion$@JvmStatic @Throws(ModuleException::class) fun getQuote(symbol: String, apiKey: String?): List<Message></ID>
|
||||||
<ID>ThrowsCount:StockQuote.kt$StockQuote.Companion$@Throws(ModuleException::class) private fun getJsonResponse(response: String, debugMessage: String): JSONObject</ID>
|
<ID>ThrowsCount:StockQuote.kt$StockQuote.Companion$@Throws(ModuleException::class) private fun getJsonResponse(response: String, debugMessage: String): JSONObject</ID>
|
||||||
|
|
|
@ -63,3 +63,9 @@ tell-max-size=50
|
||||||
# Get Alpha Vantage Stock Quote API key from: https://www.alphavantage.co/support/#api-key
|
# Get Alpha Vantage Stock Quote API key from: https://www.alphavantage.co/support/#api-key
|
||||||
#
|
#
|
||||||
#alphavantage-api-key=
|
#alphavantage-api-key=
|
||||||
|
|
||||||
|
#
|
||||||
|
# Get Wolfram Alpa API key from: https://developer.wolframalpha.com/portal/
|
||||||
|
#
|
||||||
|
#wolfram-api-key=
|
||||||
|
#wolfram-units=imperial
|
||||||
|
|
|
@ -79,6 +79,7 @@ import net.thauvin.erik.mobibot.modules.RockPaperScissors
|
||||||
import net.thauvin.erik.mobibot.modules.StockQuote
|
import net.thauvin.erik.mobibot.modules.StockQuote
|
||||||
import net.thauvin.erik.mobibot.modules.War
|
import net.thauvin.erik.mobibot.modules.War
|
||||||
import net.thauvin.erik.mobibot.modules.Weather2
|
import net.thauvin.erik.mobibot.modules.Weather2
|
||||||
|
import net.thauvin.erik.mobibot.modules.WolframAlpha
|
||||||
import net.thauvin.erik.mobibot.modules.WorldTime
|
import net.thauvin.erik.mobibot.modules.WorldTime
|
||||||
import net.thauvin.erik.semver.Version
|
import net.thauvin.erik.semver.Version
|
||||||
import org.pircbotx.Configuration
|
import org.pircbotx.Configuration
|
||||||
|
@ -426,6 +427,7 @@ class Mobibot(nickname: String, val channel: String, logsDirPath: String, p: Pro
|
||||||
addons.add(Weather2())
|
addons.add(Weather2())
|
||||||
addons.add(WorldTime())
|
addons.add(WorldTime())
|
||||||
addons.add(War())
|
addons.add(War())
|
||||||
|
addons.add(WolframAlpha())
|
||||||
|
|
||||||
// Sort the addons
|
// Sort the addons
|
||||||
addons.names.sort()
|
addons.names.sort()
|
||||||
|
|
133
src/main/kotlin/net/thauvin/erik/mobibot/modules/WolframAlpha.kt
Normal file
133
src/main/kotlin/net/thauvin/erik/mobibot/modules/WolframAlpha.kt
Normal file
|
@ -0,0 +1,133 @@
|
||||||
|
/*
|
||||||
|
* WolframAlpha.kt
|
||||||
|
*
|
||||||
|
* Copyright (c) 2004-2022, Erik C. Thauvin (erik@thauvin.net)
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* Redistributions of source code must retain the above copyright notice, this
|
||||||
|
* list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* Neither the name of this project nor the names of its contributors may be
|
||||||
|
* used to endorse or promote products derived from this software without
|
||||||
|
* specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||||
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||||
|
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||||
|
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package net.thauvin.erik.mobibot.modules
|
||||||
|
|
||||||
|
import net.thauvin.erik.mobibot.Utils
|
||||||
|
import net.thauvin.erik.mobibot.Utils.encodeUrl
|
||||||
|
import net.thauvin.erik.mobibot.Utils.reader
|
||||||
|
import net.thauvin.erik.mobibot.Utils.sendMessage
|
||||||
|
import org.pircbotx.hooks.types.GenericMessageEvent
|
||||||
|
import org.slf4j.Logger
|
||||||
|
import org.slf4j.LoggerFactory
|
||||||
|
import java.io.IOException
|
||||||
|
import java.net.URL
|
||||||
|
|
||||||
|
class WolframAlpha : ThreadedModule() {
|
||||||
|
private val logger: Logger = LoggerFactory.getLogger(WolframAlpha::class.java)
|
||||||
|
|
||||||
|
override val name = "WolframAlpha"
|
||||||
|
|
||||||
|
private fun getUnits(unit: String?): String {
|
||||||
|
println("--> $unit")
|
||||||
|
return if (unit?.lowercase() == METRIC) {
|
||||||
|
METRIC
|
||||||
|
} else {
|
||||||
|
IMPERIAL
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun run(channel: String, cmd: String, args: String, event: GenericMessageEvent) {
|
||||||
|
if (args.isNotBlank()) {
|
||||||
|
try {
|
||||||
|
val query = args.trim().split("units=", limit = 2, ignoreCase = true)
|
||||||
|
event.sendMessage(
|
||||||
|
queryWolfram(
|
||||||
|
query[0].trim(),
|
||||||
|
units = if (query.size == 2) {
|
||||||
|
getUnits(query[1].trim())
|
||||||
|
} else {
|
||||||
|
getUnits(properties[WOLFRAM_UNITS_PROP])
|
||||||
|
},
|
||||||
|
apiKey = properties[WOLFRAM_API_KEY_PROP]
|
||||||
|
)
|
||||||
|
)
|
||||||
|
} catch (e: ModuleException) {
|
||||||
|
if (logger.isWarnEnabled) logger.warn(e.debugMessage, e)
|
||||||
|
e.message?.let {
|
||||||
|
event.sendMessage(it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
helpResponse(event)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
/**
|
||||||
|
* The Wolfram Alpha API Key property.
|
||||||
|
*/
|
||||||
|
const val WOLFRAM_API_KEY_PROP = "wolfram-api-key"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The Wolfram units properties
|
||||||
|
*/
|
||||||
|
const val WOLFRAM_UNITS_PROP = "wolfram-units"
|
||||||
|
const val METRIC = "metric"
|
||||||
|
const val IMPERIAL = "imperial"
|
||||||
|
|
||||||
|
// Wolfram command
|
||||||
|
private const val WOLFRAM_CMD = "wolfram"
|
||||||
|
|
||||||
|
// Wolfram Alpha API URL
|
||||||
|
private const val API_URL = "http://api.wolframalpha.com/v1/spoken?appid="
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
@Throws(ModuleException::class)
|
||||||
|
fun queryWolfram(query: String, units: String = IMPERIAL, apiKey: String?): String {
|
||||||
|
if (!apiKey.isNullOrEmpty()) {
|
||||||
|
try {
|
||||||
|
return URL("${API_URL}${apiKey}&units=${units}&i=" + query.encodeUrl()).reader()
|
||||||
|
} catch (ioe: IOException) {
|
||||||
|
throw ModuleException(
|
||||||
|
"wolfram($query): IOE",
|
||||||
|
"Looks like Wolfram Alpha isn't able to answer that.",
|
||||||
|
)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
throw ModuleException("wolfram($query): No API Key", "No Wolfram Alpha API key specified.")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
init {
|
||||||
|
commands.add(WOLFRAM_CMD)
|
||||||
|
with(help) {
|
||||||
|
add("To get answers from Wolfram Alpha:")
|
||||||
|
add(Utils.helpFormat("%c $WOLFRAM_CMD <query> [units=(${METRIC}|${IMPERIAL})]"))
|
||||||
|
add("For example:")
|
||||||
|
add(Utils.helpFormat("%c $WOLFRAM_CMD days until christmas"))
|
||||||
|
add(Utils.helpFormat("%c $WOLFRAM_CMD distance earth moon units=metric"))
|
||||||
|
}
|
||||||
|
initProperties(WOLFRAM_API_KEY_PROP, WOLFRAM_UNITS_PROP)
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,68 @@
|
||||||
|
/*
|
||||||
|
* WolframAlphaTest.kt
|
||||||
|
*
|
||||||
|
* Copyright (c) 2004-2022, Erik C. Thauvin (erik@thauvin.net)
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* Redistributions of source code must retain the above copyright notice, this
|
||||||
|
* list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* Neither the name of this project nor the names of its contributors may be
|
||||||
|
* used to endorse or promote products derived from this software without
|
||||||
|
* specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||||
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||||
|
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||||
|
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package net.thauvin.erik.mobibot.modules
|
||||||
|
|
||||||
|
import assertk.assertThat
|
||||||
|
import assertk.assertions.contains
|
||||||
|
import assertk.assertions.isFailure
|
||||||
|
import assertk.assertions.isInstanceOf
|
||||||
|
import net.thauvin.erik.mobibot.ExceptionSanitizer.sanitize
|
||||||
|
import net.thauvin.erik.mobibot.LocalProperties
|
||||||
|
import org.testng.annotations.Test
|
||||||
|
|
||||||
|
class WolframAlphaTest : LocalProperties() {
|
||||||
|
@Test
|
||||||
|
@Throws(ModuleException::class)
|
||||||
|
fun queryWolframTest() {
|
||||||
|
val apiKey = getProperty(WolframAlpha.WOLFRAM_API_KEY_PROP)
|
||||||
|
try {
|
||||||
|
assertThat(WolframAlpha.queryWolfram("SFO to SEA", apiKey = apiKey), "SFO to SEA").contains("miles")
|
||||||
|
|
||||||
|
assertThat(
|
||||||
|
WolframAlpha.queryWolfram("SFO to LAX", WolframAlpha.METRIC, apiKey),
|
||||||
|
"SFO to LA"
|
||||||
|
).contains("kilometers")
|
||||||
|
|
||||||
|
assertThat { WolframAlpha.queryWolfram("1 gallon to liter", apiKey = "") }
|
||||||
|
.isFailure()
|
||||||
|
.isInstanceOf(ModuleException::class.java)
|
||||||
|
} catch (e: ModuleException) {
|
||||||
|
// Avoid displaying api key in CI logs
|
||||||
|
if ("true" == System.getenv("CI")) {
|
||||||
|
throw e.sanitize(apiKey)
|
||||||
|
} else {
|
||||||
|
throw e
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -80,6 +80,10 @@
|
||||||
<li>Performing Google searches
|
<li>Performing Google searches
|
||||||
<div><code>mobibot: google mobitopia on irc</code></div>
|
<div><code>mobibot: google mobitopia on irc</code></div>
|
||||||
</li>
|
</li>
|
||||||
|
<li>Getting answers from <a href="https://wolframalpha.com/">Wolfram Alpha</a>
|
||||||
|
<div><code>mobibot: wolfram days until christmas</code></div>
|
||||||
|
<div><code>mobibot: wolfram 1 gallon to liter</code></div>
|
||||||
|
</li>
|
||||||
<li>Displaying weather information
|
<li>Displaying weather information
|
||||||
<div><code>mobibot: weather san francisco</code></div>
|
<div><code>mobibot: weather san francisco</code></div>
|
||||||
<div><code>mobibot: weather 94123 </code></div>
|
<div><code>mobibot: weather 94123 </code></div>
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue