Skip to content

Commit

Permalink
feat: add web diagnostic page
Browse files Browse the repository at this point in the history
  • Loading branch information
ahaostudy committed Jan 22, 2024
1 parent 4f47502 commit b967be5
Show file tree
Hide file tree
Showing 24 changed files with 16,421 additions and 172 deletions.
4 changes: 4 additions & 0 deletions .licenserc.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,10 @@ header:
- '**/**.mod'
- '**/**.sum'
- '**/.env'
- '**/**.html'
- '**/**.css'
- '**/**.js'
- '**/**.otf'

comment: on-failure

Expand Down
38 changes: 37 additions & 1 deletion bigmodel/bigmodel.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ package bigmodel
// BigModel interface
type BigModel interface {
// Chat Receive a query for large model calls and write the output results to the Result channel in real time
Chat(string) chan Result
Chat(messages []*Message) chan Result
}

type Result struct {
Expand All @@ -35,3 +35,39 @@ const (
TypeDone
TypeError
)

type Message struct {
Role string `json:"role"`
Content string `json:"content"`
}

const (
RoleUser = "user"
RoleAssistant = "assistant"
RoleSystem = "system"
)

func Messages(messages ...*Message) []*Message {
return messages
}

func UserMessage(msg string) *Message {
return &Message{
Role: RoleUser,
Content: msg,
}
}

func SystemMessage(msg string) *Message {
return &Message{
Role: RoleSystem,
Content: msg,
}
}

func AssistantMessage(msg string) *Message {
return &Message{
Role: RoleAssistant,
Content: msg,
}
}
13 changes: 4 additions & 9 deletions bigmodel/chatgpt.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,20 +75,15 @@ type chunk struct {
} `json:"choices"`
}

func (gpt *ChatGPT) Chat(prompt string) chan Result {
func (gpt *ChatGPT) Chat(messages []*Message) chan Result {
out := make(chan Result)

go func() {
req := utils.NewRequest(gpt.url)
req.SetData(map[string]interface{}{
"model": gpt.model,
"stream": true,
"messages": []map[string]string{
{
"role": "user",
"content": prompt,
},
},
"model": gpt.model,
"stream": true,
"messages": messages,
})
req.SetHeader("Authorization", "Bearer "+gpt.apiKey)
req.SetHeader("Content-Type", "application/json")
Expand Down
91 changes: 42 additions & 49 deletions diagnostic/diagnostic.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,33 +21,27 @@ package diagnostic

import (
"fmt"
"github.com/ahaostudy/code-diagnostic/bigmodel"
"log"
"os"
"runtime"
"runtime/debug"
"strings"

"github.com/ahaostudy/code-diagnostic/bigmodel"
"github.com/ahaostudy/code-diagnostic/parse"
"github.com/ahaostudy/code-diagnostic/web"
)

const (
defaultMaxStack = 1024
defaultWebPort = 5789
)

var root string

func init() {
wd, err := os.Getwd()
if err != nil {
log.Fatalln("get working path failed:", err.Error())
return
}
root = wd
}

type Diag struct {
BigModel bigmodel.BigModel

useChinese bool
useWeb bool
webPort int
}

func NewDiag(bm bigmodel.BigModel, opts ...Option) *Diag {
Expand All @@ -57,46 +51,64 @@ func NewDiag(bm bigmodel.BigModel, opts ...Option) *Diag {
for _, opt := range opts {
opt(d)
}
if d.webPort == 0 {
d.webPort = defaultWebPort
}
return d
}

func (diag *Diag) Diagnostic() {
if r := recover(); r != nil {
pnc := fmt.Sprintf("%s", r)
stack := string(debug.Stack())
log.Printf("diagnostic detected:\n\n\t%v\n\n\t%v",
pnc,
strings.ReplaceAll(stack, "\n", "\n\t"),
)
frames := getCallersFrames(defaultMaxStack)
funs := GetFuncList(frames)
diag.analyze(pnc, stack, funs)
diag.diagnostic(pnc, stack, frames)
}
}

func (diag *Diag) BreakPoint(pnc string) {
stack := string(debug.Stack())
frames := getCallersFrames(defaultMaxStack)
diag.diagnostic(pnc, stack, frames)
}

func (diag *Diag) diagnostic(pnc, stack string, frames *runtime.Frames) {
log.Printf("diagnostic detected:\n\n\t%v\n\n\t%v",
pnc,
strings.ReplaceAll(stack, "\n", "\n\t"),
)
frames := getCallersFrames(defaultMaxStack)
funs := GetFuncList(frames)
diag.analyze(pnc, stack, funs)
localFuns := parse.GetFuncList(frames)
if !diag.useWeb {
diag.analyze(pnc, stack, localFuns)
} else {
stackTraces := parse.StackTraces([]byte(stack))
funs := parse.GetFuncListWithStackTraces(stackTraces)
web.InitConfig(&web.Config{
Panic: pnc,
Stack: stack,
LocalFunctions: localFuns,
Functions: funs,
BigModel: diag.BigModel,
UseChinese: diag.useChinese,
})
if err := web.Run(diag.webPort); err != nil {
log.Fatalln("web run error:", err)
}
}
}

func (diag *Diag) analyze(pnc, stack string, funs []*Function) {
var prompt string
prompt += "The following error occurred in the current program: \n```\n" + pnc + "\n```\n\n"
prompt += "Here is its call stack: \n```\n" + stack + "```\n\n"
prompt += "The source code list is as follows:\n" + buildFuncListDescription(funs) + "\n"
func (diag *Diag) analyze(pnc, stack string, funs []*parse.Function) {
var msg string
msg += "The following error occurred in the current program: \n```\n" + pnc + "\n```\n\n"
msg += "Here is its call stack: \n```\n" + stack + "```\n\n"
msg += "The source code list is as follows:\n" + parse.BuildFuncListDescription(funs) + "\n"
if diag.useChinese {
prompt += "Please reply in Chinese to help analyze the cause of the error and solve it!"
msg += "Please reply in Chinese to help analyze the cause of the error and solve it!"
} else {
prompt += "Please help analyze the cause of the error and solve it!"
msg += "Please help analyze the cause of the error and solve it!"
}

answer := diag.BigModel.Chat(prompt)
answer := diag.BigModel.Chat(bigmodel.Messages(bigmodel.UserMessage(msg)))
for finish := false; !finish; {
ans := <-answer
switch ans.Type {
Expand All @@ -120,22 +132,3 @@ func getCallersFrames(max int) *runtime.Frames {
pc = pc[:n]
return runtime.CallersFrames(pc)
}

func buildFuncListDescription(funs []*Function) string {
fset := MakeFileFuncSet(funs)

var desc string
for file, fs := range fset {
desc += buildFileFunctionsDescription(file, fs)
}
return desc
}

func buildFileFunctionsDescription(file string, funs []*Function) string {
desc := file + ":\n```go\n"
for _, f := range funs {
desc += f.Source + "\n"
}
desc += "```\n"
return desc
}
101 changes: 0 additions & 101 deletions diagnostic/function.go

This file was deleted.

12 changes: 12 additions & 0 deletions diagnostic/option.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,3 +27,15 @@ func WithUseChinese() Option {
diag.useChinese = true
}
}

func WithUseWeb() Option {
return func(diag *Diag) {
diag.useWeb = true
}
}

func WithSpecifyWebPort(port int) Option {
return func(diag *Diag) {
diag.webPort = port
}
}
21 changes: 12 additions & 9 deletions example/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,11 @@
package main

import (
"os"

"github.com/ahaostudy/code-diagnostic/bigmodel"
"github.com/ahaostudy/code-diagnostic/diagnostic"
"github.com/ahaostudy/code-diagnostic/example/math"
"os"

"github.com/joho/godotenv"
)
Expand All @@ -48,17 +49,19 @@ func main() {
bigmodel.NewChatGPT(apiKey, bigmodel.WithSpecifyBaseURL(baseURL)),
// use chinese
diagnostic.WithUseChinese(),
// use web
diagnostic.WithUseWeb(),
)

a, b := 10, 0

// automatically capture and analyze program exceptions
defer diag.Diagnostic()
math.Div(a, b)

a, b := 10, 0
//math.Div(a, b)

_, err := math.DivError(a, b)
if err != nil {
// custom breakpoint analysis
diag.BreakPoint(err.Error())
}
// custom breakpoint analysis
//_, err := math.DivError(a, b)
//if err != nil {
// diag.BreakPoint(err.Error())
//}
}

0 comments on commit b967be5

Please sign in to comment.