Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
A
agentchat
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Boards
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
李伟@五瓣科技
agentchat
Commits
786b69d4
Commit
786b69d4
authored
Jun 02, 2025
by
Wade
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
update grap param
parent
ddcc501a
Changes
3
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
266 additions
and
107 deletions
+266
-107
README.md
README.md
+9
-0
main.go
main.go
+27
-1
graph.go
plugins/graphrag/graph.go
+230
-106
No files found.
README.md
View file @
786b69d4
...
...
@@ -19,3 +19,12 @@ curl -X POST http://localhost:8000/indexDocuments \
curl -X POST http://localhost:8000/indexGraph
\
-H "Content-Type: application/json"
\
-d '{"user_id": "user456", "username": "Bob", "content": "What is the capital of UK?", "metadata": {}}'
{"result": "Document indexed successfully"}
main.go
View file @
786b69d4
...
...
@@ -33,6 +33,16 @@ type Input struct {
// DocumentInput 结构体用于文档索引接口
type
DocumentInput
struct
{
// UserID string `json:"user_id"`
// Username string `json:"username"`
Content
string
`json:"content"`
Metadata
map
[
string
]
interface
{}
`json:"metadata,omitempty"`
}
// GraphInput 结构体用于文档索引接口
type
GraphInput
struct
{
UserID
string
`json:"user_id"`
Username
string
`json:"username"`
Content
string
`json:"content"`
Metadata
map
[
string
]
interface
{}
`json:"metadata,omitempty"`
}
...
...
@@ -113,10 +123,26 @@ func main() {
_
=
graphRetriever
genkit
.
DefineFlow
(
g
,
"indexGraph"
,
func
(
ctx
context
.
Context
,
input
*
DocumentInput
)
(
string
,
error
)
{
genkit
.
DefineFlow
(
g
,
"indexGraph"
,
func
(
ctx
context
.
Context
,
input
*
GraphInput
)
(
string
,
error
)
{
opt
:=
graphrag
.
IndexReqOption
{
UserId
:
input
.
UserID
,
UserName
:
input
.
Username
,
}
if
_
,
ok
:=
input
.
Metadata
[
graphrag
.
DocNameKey
];
!
ok
{
// Generate random docName.
docName
,
err
:=
graphrag
.
GenerateRandomDocName
(
8
)
if
err
!=
nil
{
return
""
,
fmt
.
Errorf
(
"generate random docName for document %w"
,
err
)
}
input
.
Metadata
[
graphrag
.
DocNameKey
]
=
docName
}
doc
:=
ai
.
DocumentFromText
(
input
.
Content
,
input
.
Metadata
)
err
:=
graphIndexer
.
Index
(
ctx
,
&
ai
.
IndexerRequest
{
Documents
:
[]
*
ai
.
Document
{
doc
},
Options
:
&
opt
,
})
if
err
!=
nil
{
return
""
,
fmt
.
Errorf
(
"index document: %w"
,
err
)
...
...
plugins/graphrag/graph.go
View file @
786b69d4
...
...
@@ -139,50 +139,48 @@ func (c *Client) AddDocument(spaceID string, req DocumentRequest) (*http.Respons
return
resp
,
nil
}
// SyncDocumentsRequest defines the request body for the sync documents endpoint.
type
SyncDocumentsRequest
struct
{
DocIDs
[]
string
`json:"doc_ids"`
DocIDs
[]
string
`json:"doc_ids"`
}
// SyncDocuments sends a POST request to sync documents for the given spaceID.
func
(
c
*
Client
)
SyncDocuments
(
spaceID
string
,
docIDs
[]
string
)
(
success
bool
,
err
error
)
{
url
:=
fmt
.
Sprintf
(
"%s/knowledge/%s/document/sync"
,
c
.
BaseURL
,
spaceID
)
reqBody
:=
SyncDocumentsRequest
{
DocIDs
:
docIDs
,
}
body
,
err
:=
json
.
Marshal
(
reqBody
)
if
err
!=
nil
{
return
false
,
fmt
.
Errorf
(
"failed to marshal request: %w"
,
err
)
}
httpReq
,
err
:=
http
.
NewRequest
(
"POST"
,
url
,
bytes
.
NewBuffer
(
body
))
if
err
!=
nil
{
return
false
,
fmt
.
Errorf
(
"failed to create request: %w"
,
err
)
}
httpReq
.
Header
.
Set
(
"Accept"
,
"application/json"
)
httpReq
.
Header
.
Set
(
"Content-Type"
,
"application/json"
)
client
:=
&
http
.
Client
{}
resp
,
err
:=
client
.
Do
(
httpReq
)
if
err
!=
nil
{
return
false
,
fmt
.
Errorf
(
"failed to send request: %w"
,
err
)
}
defer
resp
.
Body
.
Close
()
respBody
,
err
:=
io
.
ReadAll
(
resp
.
Body
)
if
err
!=
nil
{
return
false
,
fmt
.
Errorf
(
"failed to read response body: %w"
,
err
)
}
if
resp
.
StatusCode
!=
http
.
StatusOK
{
return
false
,
fmt
.
Errorf
(
"request failed with status %d: %s"
,
resp
.
StatusCode
,
string
(
respBody
))
}
return
success
,
nil
}
url
:=
fmt
.
Sprintf
(
"%s/knowledge/%s/document/sync"
,
c
.
BaseURL
,
spaceID
)
reqBody
:=
SyncDocumentsRequest
{
DocIDs
:
docIDs
,
}
body
,
err
:=
json
.
Marshal
(
reqBody
)
if
err
!=
nil
{
return
false
,
fmt
.
Errorf
(
"failed to marshal request: %w"
,
err
)
}
httpReq
,
err
:=
http
.
NewRequest
(
"POST"
,
url
,
bytes
.
NewBuffer
(
body
))
if
err
!=
nil
{
return
false
,
fmt
.
Errorf
(
"failed to create request: %w"
,
err
)
}
httpReq
.
Header
.
Set
(
"Accept"
,
"application/json"
)
httpReq
.
Header
.
Set
(
"Content-Type"
,
"application/json"
)
client
:=
&
http
.
Client
{}
resp
,
err
:=
client
.
Do
(
httpReq
)
if
err
!=
nil
{
return
false
,
fmt
.
Errorf
(
"failed to send request: %w"
,
err
)
}
defer
resp
.
Body
.
Close
()
respBody
,
err
:=
io
.
ReadAll
(
resp
.
Body
)
if
err
!=
nil
{
return
false
,
fmt
.
Errorf
(
"failed to read response body: %w"
,
err
)
}
if
resp
.
StatusCode
!=
http
.
StatusOK
{
return
false
,
fmt
.
Errorf
(
"request failed with status %d: %s"
,
resp
.
StatusCode
,
string
(
respBody
))
}
return
success
,
nil
}
// SyncBatchDocument 同步批量处理文档
func
(
c
*
Client
)
SyncBatchDocument
(
spaceID
string
,
req
[]
SyncBatchRequest
)
(
*
http
.
Response
,
error
)
{
...
...
@@ -328,7 +326,7 @@ func Retriever(g *genkit.Genkit, spaceID string) ai.Retriever {
}
// generateRandomDocName generates a random alphanumeric string of the specified length.
func
g
enerateRandomDocName
(
length
int
)
(
string
,
error
)
{
func
G
enerateRandomDocName
(
length
int
)
(
string
,
error
)
{
const
charset
=
"abcdefghijklmnopqrstuvwxyz0123456789"
var
result
strings
.
Builder
result
.
Grow
(
length
)
...
...
@@ -346,21 +344,26 @@ func generateRandomDocName(length int) (string, error) {
// ParseJSONResponse parses a JSON byte slice and extracts the success boolean and data fields as a string.
func
ParseJSONResponse
(
jsonBytes
[]
byte
)
(
success
bool
,
data
string
,
err
error
)
{
// Define struct to capture only the needed fields
type
jsonResponse
struct
{
Success
bool
`json:"success"`
Data
int
`json:"data"`
// Use string to capture JSON string data
}
var
resp
jsonResponse
if
err
:=
json
.
Unmarshal
(
jsonBytes
,
&
resp
);
err
!=
nil
{
return
false
,
""
,
fmt
.
Errorf
(
"failed to unmarshal JSON: %w"
,
err
)
}
return
resp
.
Success
,
fmt
.
Sprintf
(
"%d"
,
resp
.
Data
),
nil
// Define struct to capture only the needed fields
type
jsonResponse
struct
{
Success
bool
`json:"success"`
Data
int
`json:"data"`
// Use string to capture JSON string data
}
var
resp
jsonResponse
if
err
:=
json
.
Unmarshal
(
jsonBytes
,
&
resp
);
err
!=
nil
{
return
false
,
""
,
fmt
.
Errorf
(
"failed to unmarshal JSON: %w"
,
err
)
}
return
resp
.
Success
,
fmt
.
Sprintf
(
"%d"
,
resp
.
Data
),
nil
}
type
IndexReqOption
struct
{
UserId
string
UserName
string
}
const
DocNameKey
=
"doc_name"
// Index implements the Indexer.Index method.
func
(
ds
*
docStore
)
Index
(
ctx
context
.
Context
,
req
*
ai
.
IndexerRequest
)
error
{
...
...
@@ -368,28 +371,27 @@ func (ds *docStore) Index(ctx context.Context, req *ai.IndexerRequest) error {
return
nil
}
userid
:=
""
usernmae
:=
""
for
_
,
doc
:=
range
req
.
Documents
{
if
v
,
ok
:=
doc
.
Metadata
[
"user_id"
];
ok
{
if
str
,
isString
:=
v
.
(
string
);
isString
{
userid
=
str
}
}
if
v
,
ok
:=
doc
.
Metadata
[
"username"
];
ok
{
if
str
,
isString
:=
v
.
(
string
);
isString
{
usernmae
=
str
}
}
// Type-assert req.Options to IndexReqOption
opt
,
ok
:=
req
.
Options
.
(
*
IndexReqOption
)
if
!
ok
{
return
fmt
.
Errorf
(
"invalid options type: got %T, want *IndexReqOption"
,
req
.
Options
)
}
// Create knowledge space.
// Validate required fields
if
opt
.
UserId
==
""
{
return
fmt
.
Errorf
(
"UserId is required in IndexReqOption"
)
}
if
opt
.
UserName
==
""
{
return
fmt
.
Errorf
(
"UserName is required in IndexReqOption"
)
}
// Create knowledge space
spaceReq
:=
SpaceRequest
{
Name
:
useri
d
,
Name
:
opt
.
UserI
d
,
VectorType
:
"KnowledgeGraph"
,
DomainType
:
"Normal"
,
Desc
:
usernma
e
,
Owner
:
useri
d
,
Desc
:
opt
.
UserNam
e
,
Owner
:
opt
.
UserI
d
,
}
resp
,
err
:=
ds
.
client
.
AddSpace
(
spaceReq
)
if
err
!=
nil
{
...
...
@@ -403,37 +405,25 @@ func (ds *docStore) Index(ctx context.Context, req *ai.IndexerRequest) error {
fmt
.
Println
(
"space ok"
)
spaceId
:=
useri
d
spaceId
:=
opt
.
UserI
d
// Index each document
.
// Index each document
for
i
,
doc
:=
range
req
.
Documents
{
// Use DocName from options, fall back to random name if empty
docName
:=
""
if
v
,
ok
:=
doc
.
Metadata
[
"doc_name"
];
ok
{
if
v
,
ok
:=
doc
.
Metadata
[
DocNameKey
];
ok
{
if
str
,
isString
:=
v
.
(
string
);
isString
{
docName
=
str
}
else
{
// Generate random docName.
var
err
error
docName
,
err
=
generateRandomDocName
(
8
)
if
err
!=
nil
{
return
fmt
.
Errorf
(
"generate random docName for document %d: %w"
,
i
+
1
,
err
)
}
return
fmt
.
Errorf
(
"must provide doc_name str value in metadata"
)
}
}
else
{
// Generate random docName.
var
err
error
docName
,
err
=
generateRandomDocName
(
8
)
if
err
!=
nil
{
return
fmt
.
Errorf
(
"generate random docName for document %d: %w"
,
i
+
1
,
err
)
}
return
fmt
.
Errorf
(
"must provide doc_name key in metadata"
)
}
fmt
.
Println
(
"docName: "
,
docName
)
// Add document
.
// Add document
var
sb
strings
.
Builder
for
_
,
p
:=
range
doc
.
Content
{
if
p
.
IsText
()
{
...
...
@@ -441,49 +431,183 @@ func (ds *docStore) Index(ctx context.Context, req *ai.IndexerRequest) error {
}
}
text
:=
sb
.
String
()
fmt
.
Println
(
"text: "
,
text
)
fmt
.
Println
(
"text: "
,
text
)
docReq
:=
DocumentRequest
{
DocName
:
docName
,
Source
:
"api"
,
DocType
:
"TEXT"
,
Content
:
text
,
Labels
:
""
,
// Questions: []string{},
DocName
:
docName
,
Source
:
"api"
,
DocType
:
"TEXT"
,
Content
:
text
,
Labels
:
""
,
Metadata
:
doc
.
Metadata
,
}
resp
,
err
:=
ds
.
client
.
AddDocument
(
spaceId
,
docReq
)
if
err
!=
nil
{
return
fmt
.
Errorf
(
"add document %d: %w"
,
i
+
1
,
err
)
}
body
,
_
:=
io
.
ReadAll
(
resp
.
Body
)
body
,
err
:=
io
.
ReadAll
(
resp
.
Body
)
if
err
!=
nil
{
resp
.
Body
.
Close
()
return
fmt
.
Errorf
(
"read add document response %d: %w"
,
i
+
1
,
err
)
}
defer
resp
.
Body
.
Close
()
if
resp
.
StatusCode
!=
http
.
StatusOK
{
if
resp
.
StatusCode
!=
http
.
StatusOK
{
return
fmt
.
Errorf
(
"add document %d failed with status %d: %s"
,
i
+
1
,
resp
.
StatusCode
,
string
(
body
))
}
// Parse AddDocument response
ok
,
idx
,
err
:=
ParseJSONResponse
(
body
)
if
err
!=
nil
{
return
fmt
.
Errorf
(
"
ParseJSONR
esponse %d: %w"
,
i
+
1
,
err
)
return
fmt
.
Errorf
(
"
parse add document r
esponse %d: %w"
,
i
+
1
,
err
)
}
if
!
ok
{
return
fmt
.
Errorf
(
"ParseJSONResponse body %d: %w"
,
i
+
1
,
err
)
if
!
ok
{
return
fmt
.
Errorf
(
"add document %d failed: response success=false, data=%s"
,
i
+
1
,
idx
)
}
fmt
.
Println
(
"document ok"
,
string
(
body
),
idx
)
ok
,
err
=
ds
.
client
.
SyncDocuments
(
spaceId
,[]
string
{
idx
})
fmt
.
Println
(
"document ok"
,
string
(
body
),
idx
)
if
err
!=
nil
{
return
err
// Sync document
syncOk
,
err
:=
ds
.
client
.
SyncDocuments
(
spaceId
,
[]
string
{
idx
})
if
err
!=
nil
{
return
fmt
.
Errorf
(
"sync document %d: %w"
,
i
+
1
,
err
)
}
if
syncOk
{
return
fmt
.
Errorf
(
"sync document %d failed."
,
i
+
1
,
)
}
fmt
.
Println
(
"sync ok"
,
syncOk
)
}
return
nil
}
// type IndexReqOption struct{
// UserId string
// UserName string
// DocName string
// }
// // Index implements the Indexer.Index method.
// func (ds *docStore) Index(ctx context.Context, req *ai.IndexerRequest) error {
// if len(req.Documents) == 0 {
// return nil
// }
// req.Options
// userid := ""
// usernmae := ""
// for _, doc := range req.Documents {
// if v, ok := doc.Metadata["user_id"]; ok {
// if str, isString := v.(string); isString {
// userid = str
// }
// }
// if v, ok := doc.Metadata["username"]; ok {
// if str, isString := v.(string); isString {
// usernmae = str
// }
// }
// }
// // Create knowledge space.
// spaceReq := SpaceRequest{
// Name: userid,
// VectorType: "KnowledgeGraph",
// DomainType: "Normal",
// Desc: usernmae,
// Owner: userid,
// }
// resp, err := ds.client.AddSpace(spaceReq)
// if err != nil {
// return fmt.Errorf("add space: %w", err)
// }
// defer resp.Body.Close()
// if resp.StatusCode != http.StatusOK {
// body, _ := io.ReadAll(resp.Body)
// return fmt.Errorf("add space failed with status %d: %s", resp.StatusCode, string(body))
// }
// fmt.Println("space ok")
// spaceId := userid
// // Index each document.
// for i, doc := range req.Documents {
// docName := ""
// if v, ok := doc.Metadata["doc_name"]; ok {
// if str, isString := v.(string); isString {
// docName = str
// } else {
// // Generate random docName.
// var err error
// docName, err = generateRandomDocName(8)
// if err != nil {
// return fmt.Errorf("generate random docName for document %d: %w", i+1, err)
// }
// }
// } else {
// // Generate random docName.
// var err error
// docName, err = generateRandomDocName(8)
// if err != nil {
// return fmt.Errorf("generate random docName for document %d: %w", i+1, err)
// }
// }
// fmt.Println("docName: ", docName)
// // Add document.
// var sb strings.Builder
// for _, p := range doc.Content {
// if p.IsText() {
// sb.WriteString(p.Text)
// }
// }
// text := sb.String()
// fmt.Println("text: ",text)
// docReq := DocumentRequest{
// DocName: docName,
// Source: "api",
// DocType: "TEXT",
// Content: text,
// Labels: "",
// // Questions: []string{},
// Metadata: doc.Metadata,
// }
// resp, err := ds.client.AddDocument(spaceId, docReq)
// if err != nil {
// return fmt.Errorf("add document %d: %w", i+1, err)
// }
// body, _ := io.ReadAll(resp.Body)
// defer resp.Body.Close()
// if resp.StatusCode != http.StatusOK {
// return fmt.Errorf("add document %d failed with status %d: %s", i+1, resp.StatusCode, string(body))
// }
// ok, idx, err := ParseJSONResponse(body)
// if err != nil {
// return fmt.Errorf("ParseJSONResponse %d: %w", i+1, err)
// }
// if !ok{
// return fmt.Errorf("ParseJSONResponse body %d: %w", i+1, err)
// }
// fmt.Println("document ok",string(body),idx)
// ok ,err =ds.client.SyncDocuments(spaceId,[]string{idx})
// if err != nil{
// return err
// }
// }
// return nil
// }
// RetrieverOptions for Knowledge retrieval.
type
RetrieverOptions
struct
{
Count
int
`json:"count,omitempty"`
// Max documents to retrieve.
...
...
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