mirror of
https://github.com/coaidev/coai.git
synced 2025-05-20 05:20:15 +09:00
feat: support detail debugging (#118)
This commit is contained in:
parent
14dc10025f
commit
92fcbab39e
@ -95,7 +95,7 @@ _🚀 **Next Generation AI One-Stop Solution**_
|
||||
- [x] Chat Completions (support *vision*, *tools_calling* and *function_calling*)
|
||||
- [x] Image Generation
|
||||
- [x] Azure OpenAI
|
||||
- [x] Anthropic Claude (claude-2, claude-2.1, claude-instant)
|
||||
- [x] Anthropic Claude (support *vision*)
|
||||
- [x] Slack Claude (deprecated)
|
||||
- [x] Sparkdesk (support *function_calling*)
|
||||
- [x] Google Gemini (PaLM2)
|
||||
|
@ -15,6 +15,7 @@ export type GeneralState = {
|
||||
docs: string;
|
||||
file: string;
|
||||
pwa_manifest: string;
|
||||
debug_mode: boolean;
|
||||
};
|
||||
|
||||
export type MailState = {
|
||||
@ -122,6 +123,7 @@ export const initialSystemState: SystemProps = {
|
||||
docs: "",
|
||||
file: "",
|
||||
pwa_manifest: "",
|
||||
debug_mode: false,
|
||||
},
|
||||
site: {
|
||||
close_register: false,
|
||||
|
@ -692,6 +692,8 @@
|
||||
"backend": "后端域名",
|
||||
"backendTip": "后端域名(docker 安装默认路径为 /api),用于接收回调和存储等,默认为空",
|
||||
"backendPlaceholder": "后端回调域名,默认为空,接受回调必填(如 {{backend}})",
|
||||
"debugMode": "调试模式",
|
||||
"debugModeTip": "调试模式,开启后日志将输出详细的请求参数等的日志,用于排查问题",
|
||||
"mailHost": "发件域名",
|
||||
"mailPort": "SMTP 端口",
|
||||
"mailUser": "用户名",
|
||||
|
@ -570,7 +570,9 @@
|
||||
"image_storeTip": "Images generated by the OpenAI channel DALL-E will be stored on the server to prevent invalidation of the images",
|
||||
"image_storeNoBackend": "No backend domain configured, cannot enable image storage",
|
||||
"closeRelay": "Turn off Staging API",
|
||||
"closeRelayTip": "Turn off the staging API, the staging API will not be available after turning off"
|
||||
"closeRelayTip": "Turn off the staging API, the staging API will not be available after turning off",
|
||||
"debugMode": "debugging mode",
|
||||
"debugModeTip": "Debug mode, after turning on, the log will output detailed request parameters and other logs for troubleshooting"
|
||||
},
|
||||
"user": "Users",
|
||||
"invitation-code": "Invitation Code",
|
||||
|
@ -570,7 +570,9 @@
|
||||
"image_storeTip": "OpenAIチャンネルDALL - Eによって生成された画像は、画像の無効化を防ぐためにサーバーに保存されます",
|
||||
"image_storeNoBackend": "バックエンドドメインが設定されていません。画像ストレージを有効にできません",
|
||||
"closeRelay": "ステージングAPIをオフにする",
|
||||
"closeRelayTip": "ステージングAPIをオフにすると、オフにするとステージングAPIは使用できなくなります"
|
||||
"closeRelayTip": "ステージングAPIをオフにすると、オフにするとステージングAPIは使用できなくなります",
|
||||
"debugMode": "試験調整モード",
|
||||
"debugModeTip": "デバッグモード、オンにすると、ログは詳細な要求パラメータとトラブルシューティングのための他のログを出力します"
|
||||
},
|
||||
"user": "ユーザー管理",
|
||||
"invitation-code": "招待コード",
|
||||
|
@ -570,7 +570,9 @@
|
||||
"image_storeTip": "Изображения, сгенерированные каналом OpenAI DALL-E, будут храниться на сервере, чтобы предотвратить недействительность изображений",
|
||||
"image_storeNoBackend": "Нет настроенного внутреннего домена, невозможно включить хранение изображений",
|
||||
"closeRelay": "Отключить Staging API",
|
||||
"closeRelayTip": "Отключите промежуточный API, промежуточный API будет недоступен после отключения"
|
||||
"closeRelayTip": "Отключите промежуточный API, промежуточный API будет недоступен после отключения",
|
||||
"debugMode": "Режим отладки",
|
||||
"debugModeTip": "Режим отладки, после включения журнал выведет подробные параметры запроса и другие журналы для устранения неполадок"
|
||||
},
|
||||
"user": "Управление пользователями",
|
||||
"invitation-code": "Код приглашения",
|
||||
|
@ -236,6 +236,22 @@ function General({ data, dispatch, onChange }: CompProps<GeneralState>) {
|
||||
</Button>
|
||||
</JSONEditorProvider>
|
||||
</ParagraphItem>
|
||||
<ParagraphItem>
|
||||
<Label>
|
||||
{t("admin.system.debugMode")}
|
||||
<Tips
|
||||
className={`inline-block`}
|
||||
content={t("admin.system.debugModeTip")}
|
||||
/>
|
||||
</Label>
|
||||
<Switch
|
||||
checked={data.debug_mode}
|
||||
onCheckedChange={(value) => {
|
||||
dispatch({ type: "update:general.debug_mode", value });
|
||||
}}
|
||||
/>
|
||||
</ParagraphItem>
|
||||
<ParagraphSpace />
|
||||
<ParagraphFooter>
|
||||
<div className={`grow`} />
|
||||
<RootDialog />
|
||||
|
@ -31,6 +31,7 @@ type generalState struct {
|
||||
File string `json:"file" mapstructure:"file"`
|
||||
Docs string `json:"docs" mapstructure:"docs"`
|
||||
PWAManifest string `json:"pwa_manifest" mapstructure:"pwamanifest"`
|
||||
DebugMode bool `json:"debug_mode" mapstructure:"debugmode"`
|
||||
}
|
||||
|
||||
type siteState struct {
|
||||
@ -94,6 +95,7 @@ func NewSystemConfig() *SystemConfig {
|
||||
|
||||
func (c *SystemConfig) Load() {
|
||||
globals.NotifyUrl = c.GetBackend()
|
||||
globals.DebugMode = c.General.DebugMode
|
||||
|
||||
globals.CloseRegistration = c.Site.CloseRegister
|
||||
globals.CloseRelay = c.Site.CloseRelay
|
||||
|
@ -11,6 +11,7 @@ const AnonymousMaxThread = 1
|
||||
|
||||
var AllowedOrigins []string
|
||||
|
||||
var DebugMode bool
|
||||
var NotifyUrl = ""
|
||||
var ArticlePermissionGroup []string
|
||||
var GenerationPermissionGroup []string
|
||||
|
60
utils/net.go
60
utils/net.go
@ -74,8 +74,16 @@ func fillHeaders(req *http.Request, headers map[string]string) {
|
||||
}
|
||||
|
||||
func Http(uri string, method string, ptr interface{}, headers map[string]string, body io.Reader, config []globals.ProxyConfig) (err error) {
|
||||
if globals.DebugMode {
|
||||
globals.Debug(fmt.Sprintf("[http] %s %s\nheaders: \n%s\nbody: \n%s", method, uri, Marshal(headers), Marshal(body)))
|
||||
}
|
||||
|
||||
req, err := http.NewRequest(method, uri, body)
|
||||
if err != nil {
|
||||
if globals.DebugMode {
|
||||
globals.Debug(fmt.Sprintf("[http] failed to create request: %s", err))
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
fillHeaders(req, headers)
|
||||
@ -83,20 +91,40 @@ func Http(uri string, method string, ptr interface{}, headers map[string]string,
|
||||
client := newClient(config)
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
if globals.DebugMode {
|
||||
globals.Debug(fmt.Sprintf("[http] failed to send request: %s", err))
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
defer resp.Body.Close()
|
||||
|
||||
if err = json.NewDecoder(resp.Body).Decode(ptr); err != nil {
|
||||
if globals.DebugMode {
|
||||
globals.Debug(fmt.Sprintf("[http] failed to decode response: %s\nresponse: %s", err, resp.Body))
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
if globals.DebugMode {
|
||||
globals.Debug(fmt.Sprintf("[http] response: %s", Marshal(ptr)))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func HttpRaw(uri string, method string, headers map[string]string, body io.Reader, config []globals.ProxyConfig) (data []byte, err error) {
|
||||
if globals.DebugMode {
|
||||
globals.Debug(fmt.Sprintf("[http] %s %s\nheaders: \n%s\nbody: \n%s", method, uri, Marshal(headers), Marshal(body)))
|
||||
}
|
||||
|
||||
req, err := http.NewRequest(method, uri, body)
|
||||
if err != nil {
|
||||
if globals.DebugMode {
|
||||
globals.Debug(fmt.Sprintf("[http] failed to create request: %s", err))
|
||||
}
|
||||
|
||||
return nil, err
|
||||
}
|
||||
fillHeaders(req, headers)
|
||||
@ -104,14 +132,26 @@ func HttpRaw(uri string, method string, headers map[string]string, body io.Reade
|
||||
client := newClient(config)
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
if globals.DebugMode {
|
||||
globals.Debug(fmt.Sprintf("[http] failed to send request: %s", err))
|
||||
}
|
||||
|
||||
return nil, err
|
||||
}
|
||||
|
||||
defer resp.Body.Close()
|
||||
|
||||
if data, err = io.ReadAll(resp.Body); err != nil {
|
||||
if globals.DebugMode {
|
||||
globals.Debug(fmt.Sprintf("[http] failed to read response: %s", err))
|
||||
}
|
||||
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if globals.DebugMode {
|
||||
globals.Debug(fmt.Sprintf("[http] response: %s", string(data)))
|
||||
}
|
||||
return data, nil
|
||||
}
|
||||
|
||||
@ -159,9 +199,17 @@ func EventSource(method string, uri string, headers map[string]string, body inte
|
||||
|
||||
http.DefaultTransport.(*http.Transport).TLSClientConfig = &tls.Config{InsecureSkipVerify: true}
|
||||
|
||||
if globals.DebugMode {
|
||||
globals.Debug(fmt.Sprintf("[http-stream] %s %s\nheaders: \n%s\nbody: \n%s", method, uri, Marshal(headers), Marshal(body)))
|
||||
}
|
||||
|
||||
client := newClient(config)
|
||||
req, err := http.NewRequest(method, uri, ConvertBody(body))
|
||||
if err != nil {
|
||||
if globals.DebugMode {
|
||||
globals.Debug(fmt.Sprintf("[http-stream] failed to create request: %s", err))
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
@ -169,12 +217,20 @@ func EventSource(method string, uri string, headers map[string]string, body inte
|
||||
|
||||
res, err := client.Do(req)
|
||||
if err != nil {
|
||||
if globals.DebugMode {
|
||||
globals.Debug(fmt.Sprintf("[http-stream] failed to send request: %s", err))
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
defer res.Body.Close()
|
||||
|
||||
if res.StatusCode >= 400 {
|
||||
if globals.DebugMode {
|
||||
globals.Debug(fmt.Sprintf("[http-stream] request failed with status: %s\nresponse: %s", res.Status, res.Body))
|
||||
}
|
||||
|
||||
if content, err := io.ReadAll(res.Body); err == nil {
|
||||
if form, err := Unmarshal[map[string]interface{}](content); err == nil {
|
||||
data := MarshalWithIndent(form, 2)
|
||||
@ -197,6 +253,10 @@ func EventSource(method string, uri string, headers map[string]string, body inte
|
||||
|
||||
data := string(buf[:n])
|
||||
for _, item := range strings.Split(data, "\n") {
|
||||
if globals.DebugMode {
|
||||
globals.Debug(fmt.Sprintf("[http-stream] response: %s", item))
|
||||
}
|
||||
|
||||
segment := strings.TrimSpace(item)
|
||||
if len(segment) > 0 {
|
||||
if err := callback(segment); err != nil {
|
||||
|
@ -45,9 +45,17 @@ func EventScanner(props *EventScannerProps, config ...globals.ProxyConfig) *Even
|
||||
}
|
||||
}()
|
||||
|
||||
if globals.DebugMode {
|
||||
globals.Debug(fmt.Sprintf("[sse] event source: %s %s\nheaders: %v\nbody: %v", props.Method, props.Uri, Marshal(props.Headers), Marshal(props.Body)))
|
||||
}
|
||||
|
||||
client := newClient(config)
|
||||
req, err := http.NewRequest(props.Method, props.Uri, ConvertBody(props.Body))
|
||||
if err != nil {
|
||||
if globals.DebugMode {
|
||||
globals.Debug(fmt.Sprintf("[sse] failed to create request: %s", err))
|
||||
}
|
||||
|
||||
return &EventScannerError{Error: err}
|
||||
}
|
||||
|
||||
@ -55,6 +63,10 @@ func EventScanner(props *EventScannerProps, config ...globals.ProxyConfig) *Even
|
||||
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
if globals.DebugMode {
|
||||
globals.Debug(fmt.Sprintf("[sse] failed to send request: %s", err))
|
||||
}
|
||||
|
||||
return &EventScannerError{Error: err}
|
||||
}
|
||||
|
||||
@ -62,9 +74,14 @@ func EventScanner(props *EventScannerProps, config ...globals.ProxyConfig) *Even
|
||||
|
||||
if resp.StatusCode >= 400 {
|
||||
// for error response
|
||||
body := getErrorBody(resp)
|
||||
if globals.DebugMode {
|
||||
globals.Debug(fmt.Sprintf("[sse] request failed with status: %s\nresponse: %s", resp.Status, body))
|
||||
}
|
||||
|
||||
return &EventScannerError{
|
||||
Error: fmt.Errorf("request failed with status code: %d", resp.StatusCode),
|
||||
Body: getErrorBody(resp),
|
||||
Body: body,
|
||||
}
|
||||
}
|
||||
|
||||
@ -91,11 +108,16 @@ func EventScanner(props *EventScannerProps, config ...globals.ProxyConfig) *Even
|
||||
|
||||
for scanner.Scan() {
|
||||
raw := scanner.Text()
|
||||
|
||||
if len(raw) <= 5 || !strings.HasPrefix(raw, "data:") {
|
||||
// for only `data:` partial raw or unexpected chunk
|
||||
continue
|
||||
}
|
||||
|
||||
if globals.DebugMode {
|
||||
globals.Debug(fmt.Sprintf("[sse] chunk: %s", raw))
|
||||
}
|
||||
|
||||
chunk := strings.TrimSpace(strings.TrimPrefix(raw, "data:"))
|
||||
if chunk == "[DONE]" || strings.HasPrefix(chunk, "[DONE]") {
|
||||
// for done signal
|
||||
|
@ -2,6 +2,7 @@ package utils
|
||||
|
||||
import (
|
||||
"chat/globals"
|
||||
"fmt"
|
||||
"github.com/pkoukk/tiktoken-go"
|
||||
"strings"
|
||||
)
|
||||
@ -55,6 +56,9 @@ func NumTokensFromMessages(messages []globals.Message, model string) (tokens int
|
||||
// return len([]rune(data)) * weight
|
||||
|
||||
// use the recall method instead (default encoder model is gpt-3.5-turbo-0613)
|
||||
if globals.DebugMode {
|
||||
globals.Debug(fmt.Sprintf("[tiktoken] error encoding messages: %s (model: %s), using default model instead", err, model))
|
||||
}
|
||||
return NumTokensFromMessages(messages, globals.GPT3Turbo0613)
|
||||
}
|
||||
|
||||
@ -65,6 +69,10 @@ func NumTokensFromMessages(messages []globals.Message, model string) (tokens int
|
||||
tokensPerMessage
|
||||
}
|
||||
tokens += 3 // every reply is primed with <|start|>assistant<|message|>
|
||||
|
||||
if globals.DebugMode {
|
||||
globals.Debug(fmt.Sprintf("[tiktoken] num tokens from messages: %d (tokens per message: %d, model: %s)", tokens, tokensPerMessage, model))
|
||||
}
|
||||
return tokens
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user