d2jsp
Log InRegister
d2jsp Forums > Off-Topic > Computers & IT > Programming & Development > Chat Ai
Prev14567Next
Add Reply New Topic New Poll
Member
Posts: 10,812
Joined: Oct 15 2009
Gold: Locked
Warn: 20%
Mar 19 2016 03:08am
Quote (j0ltk0la @ Mar 19 2016 12:57am)
Confirmed


Code
azrad@azrad-MS-7693:~$ python
Python 2.7.6 (default, Jun 22 2015, 17:58:13)
[GCC 4.8.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import cleverbot
>>> cleverbot.Cleverbot().ask('who would use d2jsp and python for windows?')
u'Faget.'
>>>


Member
Posts: 62,215
Joined: Jun 3 2007
Gold: 9,039.20
Mar 19 2016 03:12am
Quote (Azrad @ Mar 19 2016 03:08am)
Code
azrad@azrad-MS-7693:~$ python
Python 2.7.6 (default, Jun 22 2015, 17:58:13)
[GCC 4.8.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import cleverbot
>>> cleverbot.Cleverbot().ask('who would use d2jsp and python for windows?')
u'Faget.'
>>>


Code

[root@fedora-512mb-nyc2-01 ~]# python
Python 2.7.10 (default, Sep 8 2015, 17:20:17)
[GCC 5.1.1 20150618 (Red Hat 5.1.1-4)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import cleverbot
>>> cl = cleverbot.Cleverbot()
>>> cl.ask('Why use linux when I have a VPS?')
u'I use it because someone gave it to me.'
>>>

Member
Posts: 13,425
Joined: Sep 29 2007
Gold: 0.00
Warn: 20%
Mar 19 2016 10:43am
Who uses root to run python scripts. Man y'all baddies.
Member
Posts: 161,550
Joined: Oct 18 2006
Gold: 4.03
Warn: 20%
Mar 20 2016 08:18am
topkek
Member
Posts: 13,425
Joined: Sep 29 2007
Gold: 0.00
Warn: 20%
Mar 21 2016 12:53pm
Been pondering over this some more.

Even if I use entire sentences, there is still no subject awareness to it. For example, you could be talking about repairing a computer and then respond to the AI with a generic sentence like "that may be difficult." When this happens if there is no type of subject segregation and that generic sentence can lead into other subjects rather than still being about computers.

The way I initially tried to solve this was to map an input sentence to an output markov chain list so that each input sentence could generate it's own output regarding that input. This still has the problem of the "that may be difficult." input potentially being linked to a list of chains that have no awareness of the original subject.

So my next idea might be to play around with a text-rank and page-rank algorithm kind of how google ranks their search results based on user input. For example the sentence "These computers are all destroyed and will have to be repaired." has a ranked keyword list of:

Code
[["repaired", 5.198454021461245], ["destroyed", 4.72890101697455], ["computers", 4.259348012487856]]


From there I could devise a way to generate responses based on these keywords. I could potentially take each unique keyword and maybe link it to a chain list.

This still poses a problem of generic sentences triggering a topic change, although I think if I implement some sort of short term memory where I store the last complex word keywords like above I can attempt to retain the topic from changing. This could possibly be done by comparing the length of the words and their weights that the ranking gave them.

For example if a user responded with "That may be terribly difficult" to the bots response, the ranking system would output

Code
[["terribly", 3.779489856987712], ["difficult", 3.779489856987712]]


From there I could either keep the original keywords, mangle these new keywords into the memory, or overwrite memory with these new keywords. I haven't decided the logic behind of when to wipe the memory, retain the memory, or mix the memory yet.

-----------------------------------------------

This topic is basically just me spouting random shit now, pay no concern.
Member
Posts: 13,425
Joined: Sep 29 2007
Gold: 0.00
Warn: 20%
Mar 24 2016 04:34pm
Playing around with this again. This time I used keywords to find responses in the database. No idea how well this will work in the end, but its partly completed. Just need to create a few more functions to help ease the training process.

Check that narly SQL query tho.

Code
Process started >>>
Initializing brain

Creating neural links
Debug: Linking keywords `["super", "cool", "test"]` to `This was a super cool test`
Debug: Adding keyword node `super`
Debug: Adding keyword node `cool`
Debug: Adding keyword node `test`
Debug: Adding response node `This was a super cool test`
Debug: Linking keywords `["test"]` to `This was a test`
Debug: Adding keyword node `test`
Debug: Keyword node `test` already learned
Debug: Adding response node `This was a test`
Debug: Linking keywords `["weird"]` to `This is weird`
Debug: Adding keyword node `weird`
Debug: Adding response node `This is weird`
Debug: Linking keywords `["cool", "test"]` to `Wow cool test`
Debug: Adding keyword node `cool`
Debug: Keyword node `cool` already learned
Debug: Adding keyword node `test`
Debug: Keyword node `test` already learned
Debug: Adding response node `Wow cool test`


Generating responses
Debug: Finding response for `That was a cool test`
Debug: Finding keywords for `That was a cool test`
This was a super cool test
Debug: Finding response for `That was a cool test`
Debug: Finding keywords for `That was a cool test`
Wow cool test
Debug: Finding response for `That was a cool test`
Debug: Finding keywords for `That was a cool test`
Wow cool test
Debug: Finding response for `That was a cool test`
Debug: Finding keywords for `That was a cool test`
This was a test
Debug: Finding response for `That was a cool test`
Debug: Finding keywords for `That was a cool test`
Wow cool test


Code
require "sqlite3"
require "graph-rank"

class Brain
def initialize(brain)
if !File.file?(brain)
@brain = SQLite3::Database.new brain
@brain.execute "Create Table Keywords (id INTEGER PRIMARY KEY AUTOINCREMENT, keyword TEXT NOT NULL UNIQUE);"
@brain.execute "Create Table Responses (id INTEGER PRIMARY KEY AUTOINCREMENT, response TEXT NOT NULL);"
@brain.execute "Create Table Brain (responseId INTEGER References Responses(id), keywordId INTEGER References Keywords(id));"

@brain.execute "Create Index KeywordsIndex on Keywords (id, keyword)"
@brain.execute "Create Index ResponsesIndex on Responses (id, response)"
@brain.execute "Create Index BrainIndex on Brain (responseId, keywordId)"
else
@brain = SQLite3::Database.open brain
end

@brain.execute "PRAGMA synchronous=OFF"
@brain.execute "PRAGMA count_changes=OFF"
@brain.execute "PRAGMA journal_mode=MEMORY"
@brain.execute "PRAGMA temp_store=MEMORY"
end

def addKeywordNode(keyword)
begin
puts "Debug: Adding keyword node `#{keyword}`"
@brain.execute("Insert Into Keywords Values (NULL, ?)", keyword)
rescue SQLite3::ConstraintException
end
end

def addResponseNode(response)
puts "Debug: Adding response node `#{response}`"
@brain.execute("Insert Into Responses Values (NULL, ?)", response)
end

def addNeuralLink(keywords, response)
puts "Debug: Linking keywords `#{keywords}` to `#{response}`"
keywordIds = []
keywords.each do |keyword|
self.addKeywordNode keyword
keywordId = @brain.execute("select id from Keywords where keyword = ?", keyword)
keywordIds.push keywordId.first.first
end

self.addResponseNode response
responseId = @brain.execute("select id from Responses where response = ?", response)

keywordIds.each do |keywordId|
@brain.execute("Insert Into Brain values (?, ?)", responseId, keywordId)
end
end

def findKeywords(input)
puts "Debug: Finding keywords for `#{input}`"
gr = GraphRank::Keywords.new
gr.run(input).map { |row| row[0] }
end

def findResponse(input)
puts "Debug: Finding response for `#{input}`"
keywords = self.findKeywords(input).map { |e| "'#{e}'" }.join(', ')
responses = @brain.execute <<-SQL
Select response
From Responses
Inner Join (Select responseId
From Brain
Where keywordId in (Select id
From Keywords
Where keyword in (#{keywords}))) q
on Responses.id=q.responseId
group by q.responseId
order by count(q.responseId) DESC;
SQL

responses.sample.first
end
end

puts "Initializing brain"
brain = Brain.new "newbrain1.db"

puts "\nCreating neural links\n"
brain.addNeuralLink(["super", "cool", "test"], "This was a super cool test")
brain.addNeuralLink(["test"], "This was a test")
brain.addNeuralLink(["weird"], "This is weird")
brain.addNeuralLink(["cool", "test"], "Wow cool test")

puts "\n\nGenerating responses\n"

5.times do
puts brain.findResponse "That was a cool test"
end


This post was edited by AbDuCt on Mar 24 2016 04:39pm
Member
Posts: 62,215
Joined: Jun 3 2007
Gold: 9,039.20
Mar 24 2016 05:33pm
Member
Posts: 13,425
Joined: Sep 29 2007
Gold: 0.00
Warn: 20%
Mar 24 2016 08:44pm
So it is working sort of but I am having troubles with it still. At the moment my sql query returns all responses and orders them by how many keywords they match. This is fine and all, but if I simply take the first response, unless a new response that matches better comes along. This means I will only ever respond that one response no matter what. What I attempted to do to combat this was sample (randomly select) a response out of all my returned responses. The problem with this is that this will randomly give me an output that can match really well, or be completely unrelated only being related by the minimum number of keywords it took to satisfy the SQL query.

To attempt to solve this I may edit the group by query to have a HAVING clause so that I can limit responses to the COUNT of how many keywords the response matches. This means if I search for 5 keywords, I can first limit responses to those that match all 5 keywords. If I don't return anything satisfactory I can decrement and search for responses that match any 4 keywords. This will continue on until I hit my floor of of 0 keywords in which a generic reply will be given.

Training this AI is still a pain in the ass. It specifically needs opposing statements to work, such as two people conversing but one person talking one sentence at a time alternating. I'll have to do some searching to see if I can find some material to train from. IRC is the first place that comes to mind.

Here is AI learning the color of the sky. See how cute she is?

Code
Initializing brain
Input > What color is the sky?
Response> The sky is blue.
Debug: Linking keywords `["color", "sky"]` to `The sky is blue.`
Output > The sky is blue.

^C

Initializing brain
Input > What color is the sky?
Output > The sky is blue.


This post was edited by AbDuCt on Mar 24 2016 08:45pm
Member
Posts: 62,215
Joined: Jun 3 2007
Gold: 9,039.20
Mar 24 2016 09:47pm
Idle on a few ircs, collect logs and build a learning library?
Member
Posts: 13,425
Joined: Sep 29 2007
Gold: 0.00
Warn: 20%
Mar 25 2016 11:44pm
Ran into a problem. It has to do with keywords and the SQL query.

Basically I can't map a query where the graph rank system returns no keywords. This happens more often than not when using short non influential sentences.

The other problem is that if the sentences do not contain many keywords the responses can get mixed up with different subjects. This problem does not persist for circumstances where there is lots of keywords for the input.

Although when the brain has little to no database built you get no responses if I try to match 100% of the keywords. To resolve this I start at requiring 100% of the keywords, then slowly reduce that number by 1 keyword match until responses are returned. With a large trained database this likely wont need to ever happen.

So the real problem is how to train the database when people are inputing tiny sentences like "hello" and "what is your name" since they either return 1 keyword or none at all.

Anyways the revised code. I'll have to think and test it out a bit more. It will work well for large specific sentences that generate lots of keywords, but short generic sentences will fail.

Code
require "sqlite3"
require "graph-rank"

class Brain
def initialize(brain)
if !File.file?(brain)
@brain = SQLite3::Database.new brain
@brain.execute "Create Table Keywords (id INTEGER PRIMARY KEY AUTOINCREMENT, keyword TEXT NOT NULL UNIQUE);"
@brain.execute "Create Table Responses (id INTEGER PRIMARY KEY AUTOINCREMENT, response TEXT NOT NULL UNIQUE);"
@brain.execute "Create Table Brain (responseId INTEGER References Responses(id), keywordId INTEGER References Keywords(id));"

@brain.execute "Create Index KeywordsIndex on Keywords (id, keyword)"
@brain.execute "Create Index ResponsesIndex on Responses (id, response)"
@brain.execute "Create Index BrainIndex on Brain (responseId, keywordId)"
else
@brain = SQLite3::Database.open brain
end

@brain.execute "PRAGMA synchronous=OFF"
@brain.execute "PRAGMA count_changes=OFF"
@brain.execute "PRAGMA journal_mode=MEMORY"
@brain.execute "PRAGMA temp_store=MEMORY"
end

def addKeywordNode(keyword)
begin
#puts "Debug: Adding keyword node `#{keyword}`"
@brain.execute("Insert Into Keywords Values (NULL, ?)", keyword)
rescue SQLite3::ConstraintException
#puts "Debug: Keyword node `#{keyword}` already learned"
end
end

def addResponseNode(response)
begin
#puts "Debug: Adding response node `#{response}`"
@brain.execute("Insert Into Responses Values (NULL, ?)", response)
rescue SQLite3::ConstraintException
#puts "Debug: Response node `#{keyword}` already learned"
end
end

def addNeuralLink(keywords, response)
puts "Debug: Linking keywords `#{keywords}` to `#{response}`"
keywordIds = []
keywords.each do |keyword|
self.addKeywordNode keyword
keywordId = @brain.execute("select id from Keywords where keyword = ?", keyword)
keywordIds.push keywordId.first.first
end

self.addResponseNode response
responseId = @brain.execute("select id from Responses where response = ?", response)

keywordIds.each do |keywordId|
@brain.execute("Insert Into Brain values (?, ?)", responseId, keywordId)
end
end

def findKeywords(input)
#puts "Debug: Finding keywords for `#{input}`"
gr = GraphRank::Keywords.new
gr.run(input).map { |row| row[0] }
end

def findResponse(input)
#puts "Debug: Finding response for `#{input}`"
keywords = self.findKeywords(input)
keywordsQuoted = keywords.map { |e| "'#{e}'" }.join(', ')
keywords.count.downto(0) do |keywordCount|
responses = @brain.execute <<-SQL
Select response
From Responses
Inner Join (Select responseId
From Brain
Where keywordId in (Select id
From Keywords
Where keyword in (#{keywordsQuoted}))) q
On Responses.id=q.responseId
Group By q.responseId Having count(q.responseId) > #{keywordCount}
Order By Count(q.responseId) DESC;
SQL

if !responses.empty?
return responses.sample.first
end
end

return "..."
end

def trainInput(input, response)
keywords = self.findKeywords input
self.addNeuralLink(keywords, response)
end
end

puts "Initializing brain"
brain = Brain.new "newbrain1.db"

while true
print "Input > "
input = gets.strip
#print "Response> "
#response = gets.strip
#brain.trainInput(input, response)
print "Output > "
output = brain.findResponse input
puts output
end


This post was edited by AbDuCt on Mar 25 2016 11:47pm
Go Back To Programming & Development Topic List
Prev14567Next
Add Reply New Topic New Poll