Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
N
n8n_ai_assistant
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Vũ Hoàng Anh
n8n_ai_assistant
Commits
62715bb0
Commit
62715bb0
authored
Jan 14, 2024
by
Domi
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
fix: chatdocs addon (better support for Bard)
parent
66213a6e
Changes
5
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
68 additions
and
29 deletions
+68
-29
ChatDocsPanel.vue
src/components/chatdocs/ChatDocsPanel.vue
+28
-7
helper.ts
src/components/chatdocs/helper.ts
+3
-3
pip.ts
src/content/pip.ts
+2
-7
manifest.ts
src/manifest.ts
+1
-1
dom.ts
src/utils/dom.ts
+34
-11
No files found.
src/components/chatdocs/ChatDocsPanel.vue
View file @
62715bb0
...
@@ -12,7 +12,13 @@ import IconPlayCircle from "../icons/IconPlayCircle.vue"
...
@@ -12,7 +12,13 @@ import IconPlayCircle from "../icons/IconPlayCircle.vue"
import
IconPause
from
"../icons/IconPause.vue"
import
IconPause
from
"../icons/IconPause.vue"
import
IconProgressActivity
from
"../icons/IconProgressActivity.vue"
import
IconProgressActivity
from
"../icons/IconProgressActivity.vue"
import
{
sitesConfig
}
from
"./helper"
import
{
sitesConfig
}
from
"./helper"
import
{
query
,
dispatchInput
,
click
,
waitFor
}
from
"@/utils/dom"
import
{
query
,
dispatchInput
,
click
,
waitFor
,
getInputValue
,
}
from
"@/utils/dom"
import
{
chatDocPrompt
}
from
"@/utils/prompt"
import
{
chatDocPrompt
}
from
"@/utils/prompt"
import
{
useI18n
}
from
"@/utils/i18n"
import
{
useI18n
}
from
"@/utils/i18n"
...
@@ -295,6 +301,8 @@ const autoSend = async () => {
...
@@ -295,6 +301,8 @@ const autoSend = async () => {
sendTask
.
key
=
key
sendTask
.
key
=
key
sendTask
.
status
=
"running"
sendTask
.
status
=
"running"
const
selector
=
config
.
selector
const
isWorking
=
()
=>
const
isWorking
=
()
=>
!
currentMessage
.
value
.
done
&&
!
currentMessage
.
value
.
done
&&
sendTask
.
status
==
"running"
&&
sendTask
.
status
==
"running"
&&
...
@@ -306,15 +314,28 @@ const autoSend = async () => {
...
@@ -306,15 +314,28 @@ const autoSend = async () => {
console
.
log
(
">>"
,
message
)
console
.
log
(
">>"
,
message
)
await
new
Promise
((
r
)
=>
setTimeout
(
r
,
100
))
await
new
Promise
((
r
)
=>
setTimeout
(
r
,
100
))
const
input
=
query
(
config
.
selector
.
input
)
as
HTMLInput
Element
const
input
=
query
(
selector
.
input
)
as
HTML
Element
if
(
!
input
)
{
if
(
!
input
)
{
throw
Error
(
"couldn't find input element for "
+
config
.
selector
.
input
)
throw
Error
(
"couldn't find input element for "
+
selector
.
input
)
}
}
await
dispatchInput
(
input
,
message
)
await
dispatchInput
(
input
,
message
)
await
new
Promise
((
r
)
=>
setTimeout
(
r
,
200
))
await
click
(
config
.
selector
.
send
)
await
new
Promise
((
r
)
=>
setTimeout
(
r
,
600
))
await
new
Promise
((
r
)
=>
setTimeout
(
r
,
600
))
await
waitFor
(
config
.
selector
.
wait
,
1000
*
30
)
await
click
(
selector
.
send
)
await
waitFor
(
async
(
i
)
=>
{
const
input
=
query
(
selector
.
input
)
as
HTMLElement
const
value
=
input
?
getInputValue
(
input
)
:
""
const
sented
=
value
.
length
<
100
if
(
!
sented
&&
i
%
3
==
0
)
{
await
click
(
selector
.
send
)
}
return
sented
},
{
interval
:
1000
*
2
}
)
await
new
Promise
((
r
)
=>
setTimeout
(
r
,
200
))
await
waitFor
(()
=>
query
(
selector
.
wait
)
!=
null
,
{})
await
new
Promise
((
r
)
=>
setTimeout
(
r
,
200
))
await
new
Promise
((
r
)
=>
setTimeout
(
r
,
200
))
await
nextMessage
()
await
nextMessage
()
...
@@ -491,7 +512,7 @@ const resetSent = () => {
...
@@ -491,7 +512,7 @@ const resetSent = () => {
v-if=
"sendTask.error"
v-if=
"sendTask.error"
:class=
"[
:class=
"[
'text-rose-600 bg-rose-200/10 border border-rose-600 px-3',
'text-rose-600 bg-rose-200/10 border border-rose-600 px-3',
'mb-4 rounded py-1',
'mb-4 rounded py-1
break-words
',
]"
]"
>
>
{{ sendTask.error }}
{{ sendTask.error }}
...
...
src/components/chatdocs/helper.ts
View file @
62715bb0
...
@@ -27,9 +27,9 @@ export const sitesConfig = [
...
@@ -27,9 +27,9 @@ export const sitesConfig = [
path
:
/chat/
,
path
:
/chat/
,
maxInputLength
:
4096
,
maxInputLength
:
4096
,
selector
:
{
selector
:
{
input
:
"input-area rich-textarea
p
"
,
input
:
"input-area rich-textarea
div
"
,
send
:
"input-area div[class*=send] button[class*=send]"
,
send
:
"input-area div[class*=send] button[class*=send]"
,
wait
:
"input-area div[class*=send] button[class*=send]
:not([hidden])
"
,
wait
:
"input-area div[class*=send] button[class*=send]"
,
},
},
},
},
{
{
...
@@ -54,7 +54,7 @@ export const sitesConfig = [
...
@@ -54,7 +54,7 @@ export const sitesConfig = [
},
},
},
},
{
{
host
:
chrome
.
runtime
.
id
+
'-'
,
host
:
chrome
.
runtime
.
id
+
"-"
,
path
:
/^
\/
dev.html/
,
path
:
/^
\/
dev.html/
,
maxInputLength
:
8000
,
maxInputLength
:
8000
,
maxInputToken
:
4096
,
maxInputToken
:
4096
,
...
...
src/content/pip.ts
View file @
62715bb0
...
@@ -3,6 +3,7 @@ import {
...
@@ -3,6 +3,7 @@ import {
querySome
,
querySome
,
copyStyleSheets
,
copyStyleSheets
,
getDomNonce
,
getDomNonce
,
getTrustedHTML
,
replaceHtmlNonce
,
replaceHtmlNonce
,
removePrerenderRules
,
removePrerenderRules
,
}
from
"@/utils/dom"
}
from
"@/utils/dom"
...
@@ -117,13 +118,7 @@ export async function copilotReopen({ url, width, height }: ReopenOptions) {
...
@@ -117,13 +118,7 @@ export async function copilotReopen({ url, width, height }: ReopenOptions) {
function
writeHtml
(
pipWindow
:
Window
,
html
:
string
)
{
function
writeHtml
(
pipWindow
:
Window
,
html
:
string
)
{
const
nonce
=
getDomNonce
(
document
)
const
nonce
=
getDomNonce
(
document
)
let
escaped
=
replaceHtmlNonce
(
html
,
nonce
)
let
escaped
=
replaceHtmlNonce
(
html
,
nonce
)
escaped
=
getTrustedHTML
(
escaped
)
if
(
window
.
trustedTypes
)
{
const
escapeHTMLPolicy
=
window
.
trustedTypes
.
createPolicy
(
"escapePolicy"
,
{
createHTML
:
(
string
:
string
)
=>
string
,
})
escaped
=
escapeHTMLPolicy
.
createHTML
(
escaped
)
}
pipWindow
.
document
.
open
()
pipWindow
.
document
.
open
()
pipWindow
.
document
.
write
(
escaped
)
pipWindow
.
document
.
write
(
escaped
)
...
...
src/manifest.ts
View file @
62715bb0
...
@@ -10,7 +10,7 @@ const manifest = {
...
@@ -10,7 +10,7 @@ const manifest = {
// short_name: "__MSG_short_name__",
// short_name: "__MSG_short_name__",
// no more than 132 characters
// no more than 132 characters
description
:
"__MSG_description__"
,
description
:
"__MSG_description__"
,
version
:
"1.2.
0
"
,
version
:
"1.2.
1
"
,
action
:
{
action
:
{
default_icon
:
{
default_icon
:
{
16
:
"logo.png"
,
16
:
"logo.png"
,
...
...
src/utils/dom.ts
View file @
62715bb0
...
@@ -157,38 +157,61 @@ export function removePrerenderRules(doc: Document) {
...
@@ -157,38 +157,61 @@ export function removePrerenderRules(doc: Document) {
}
}
}
}
export
async
function
dispatchInput
(
export
function
getTrustedHTML
(
html
:
string
)
{
input
:
HTMLInputElement
|
HTMLTextAreaElement
,
if
(
"window"
in
globalThis
)
{
value
:
string
const
policy
=
window
.
trustedTypes
.
createPolicy
(
"trustedPolicy"
,
{
)
{
createHTML
:
(
str
:
string
)
=>
str
,
})
return
policy
.
createHTML
(
html
)
}
return
html
}
export
async
function
dispatchInput
(
input
:
HTMLElement
,
value
:
string
)
{
if
([
"INPUT"
,
"TEXTAREA"
].
includes
(
input
.
nodeName
))
{
if
([
"INPUT"
,
"TEXTAREA"
].
includes
(
input
.
nodeName
))
{
input
.
value
=
value
;(
input
as
HTMLInputElement
)
.
value
=
value
}
else
if
(
input
.
contentEditable
)
{
}
else
if
(
input
.
contentEditable
)
{
input
.
innerText
=
value
const
html
=
value
.
replace
(
/
\n
/g
,
"<br />"
)
input
.
innerHTML
=
html
}
}
input
.
dispatchEvent
(
new
Event
(
"input"
,
{
bubbles
:
true
}))
input
.
dispatchEvent
(
new
Event
(
"input"
,
{
bubbles
:
true
}))
input
.
dispatchEvent
(
new
Event
(
"change"
,
{
bubbles
:
true
}))
input
.
dispatchEvent
(
new
Event
(
"change"
,
{
bubbles
:
true
}))
}
}
export
function
getInputValue
(
input
:
HTMLElement
)
{
if
([
"INPUT"
,
"TEXTAREA"
].
includes
(
input
.
nodeName
))
{
return
(
input
as
HTMLInputElement
).
value
}
else
if
(
input
.
contentEditable
)
{
const
value
=
input
.
innerText
return
value
}
return
""
}
export
async
function
click
(
target
:
string
)
{
export
async
function
click
(
target
:
string
)
{
const
el
=
query
(
target
)
as
HTMLElement
const
el
=
query
(
target
)
as
HTMLElement
el
.
click
()
el
.
click
()
}
}
export
async
function
waitFor
(
target
:
string
,
timeout
?:
number
)
{
export
async
function
waitFor
(
test
:
(
i
:
number
)
=>
PromiseLike
<
boolean
>
|
boolean
,
options
:
{
timeout
?:
number
;
interval
?:
number
}
)
{
let
success
=
false
let
success
=
false
let
count
=
0
let
count
=
0
const
t0
=
Date
.
now
()
const
t0
=
Date
.
now
()
const
timeout
=
options
.
timeout
||
1000
*
30
const
interval
=
options
.
interval
||
600
while
(
!
success
)
{
while
(
!
success
)
{
const
view
=
query
(
targe
t
)
const
result
=
await
test
(
coun
t
)
success
=
!!
view
success
=
!!
result
count
++
count
++
await
new
Promise
((
r
)
=>
setTimeout
(
r
,
200
))
await
new
Promise
((
r
)
=>
setTimeout
(
r
,
interval
))
if
(
timeout
&&
Date
.
now
()
-
t0
>
timeout
)
{
if
(
timeout
&&
Date
.
now
()
-
t0
>
timeout
)
{
throw
Error
(
`
click() timeout, target:
${
target
}
wait:
${
waitFor
}
`
)
throw
Error
(
`
waitFor timeout, test:
${
test
}
`
)
}
}
}
}
}
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment