Repository navigation
feat: log shows request conversion #2703
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,40 @@ | ||
| package common | ||
|
|
||
| import ( | ||
| "github.com/QuantumNous/new-api/dto" | ||
| "github.com/QuantumNous/new-api/types" | ||
| ) | ||
|
|
||
| func GuessRelayFormatFromRequest(req any) (types.RelayFormat, bool) { | ||
| switch req.(type) { | ||
| case *dto.GeneralOpenAIRequest, dto.GeneralOpenAIRequest: | ||
| return types.RelayFormatOpenAI, true | ||
| case *dto.OpenAIResponsesRequest, dto.OpenAIResponsesRequest: | ||
| return types.RelayFormatOpenAIResponses, true | ||
| case *dto.ClaudeRequest, dto.ClaudeRequest: | ||
| return types.RelayFormatClaude, true | ||
| case *dto.GeminiChatRequest, dto.GeminiChatRequest: | ||
| return types.RelayFormatGemini, true | ||
| case *dto.EmbeddingRequest, dto.EmbeddingRequest: | ||
| return types.RelayFormatEmbedding, true | ||
| case *dto.RerankRequest, dto.RerankRequest: | ||
| return types.RelayFormatRerank, true | ||
| case *dto.ImageRequest, dto.ImageRequest: | ||
| return types.RelayFormatOpenAIImage, true | ||
| case *dto.AudioRequest, dto.AudioRequest: | ||
| return types.RelayFormatOpenAIAudio, true | ||
| default: | ||
| return "", false | ||
| } | ||
| } | ||
|
|
||
| func AppendRequestConversionFromRequest(info *RelayInfo, req any) { | ||
| if info == nil { | ||
| return | ||
| } | ||
| format, ok := GuessRelayFormatFromRequest(req) | ||
| if !ok { | ||
| return | ||
| } | ||
| info.AppendRequestConversion(format) | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -70,9 +70,38 @@ func GenerateTextOtherInfo(ctx *gin.Context, relayInfo *relaycommon.RelayInfo, m | |
|
|
||
| other["admin_info"] = adminInfo | ||
| appendRequestPath(ctx, relayInfo, other) | ||
| appendRequestConversionChain(relayInfo, other) | ||
| return other | ||
| } | ||
|
|
||
| func appendRequestConversionChain(relayInfo *relaycommon.RelayInfo, other map[string]interface{}) { | ||
| if relayInfo == nil || other == nil { | ||
| return | ||
| } | ||
| if len(relayInfo.RequestConversionChain) == 0 { | ||
| return | ||
| } | ||
| chain := make([]string, 0, len(relayInfo.RequestConversionChain)) | ||
| for _, f := range relayInfo.RequestConversionChain { | ||
| switch f { | ||
| case types.RelayFormatOpenAI: | ||
| chain = append(chain, "OpenAI Compatible") | ||
| case types.RelayFormatClaude: | ||
| chain = append(chain, "Claude Messages") | ||
| case types.RelayFormatGemini: | ||
| chain = append(chain, "Google Gemini") | ||
| case types.RelayFormatOpenAIResponses: | ||
| chain = append(chain, "OpenAI Responses") | ||
| default: | ||
| chain = append(chain, string(f)) | ||
| } | ||
| } | ||
| if len(chain) == 0 { | ||
| return | ||
| } | ||
| other["request_conversion"] = chain | ||
| } | ||
|
Comment on lines
+73
to
+103
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Consider emitting locale-agnostic format identifiers. 🤖 Prompt for AI Agents |
||
|
|
||
| func GenerateWssOtherInfo(ctx *gin.Context, relayInfo *relaycommon.RelayInfo, usage *dto.RealtimeUsage, modelRatio, groupRatio, completionRatio, audioRatio, audioCompletionRatio, modelPrice, userGroupRatio float64) map[string]interface{} { | ||
| info := GenerateTextOtherInfo(ctx, relayInfo, modelRatio, groupRatio, completionRatio, 0, 0.0, modelPrice, userGroupRatio) | ||
| info["ws"] = true | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -306,6 +306,16 @@ export const useLogsData = () => { | |
|
|
||
| // Format logs data | ||
| const setLogsFormat = (logs) => { | ||
| const requestConversionDisplayValue = (conversionChain) => { | ||
| const chain = Array.isArray(conversionChain) | ||
| ? conversionChain.filter(Boolean) | ||
| : []; | ||
| if (chain.length <= 1) { | ||
| return t('原生格式'); | ||
| } | ||
| return `${chain.join(' -> ')}`; | ||
| }; | ||
|
Comment on lines
+309
to
+317
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🏁 Script executed: # First, verify the file exists and check the specific lines
fd "useUsageLogsData.jsx" --type fRepository: QuantumNous/new-api Length of output: 108 🏁 Script executed: # Examine the file around lines 309-317
if [ -f "web/src/hooks/usage-logs/useUsageLogsData.jsx" ]; then
echo "=== Lines 300-330 ===" && sed -n '300,330p' "web/src/hooks/usage-logs/useUsageLogsData.jsx"
echo ""
echo "=== Searching for request_conversion usage ===" && grep -n "request_conversion\|conversionChain\|requestConversionDisplayValue" "web/src/hooks/usage-logs/useUsageLogsData.jsx" | head -20
else
echo "File not found"
fiRepository: QuantumNous/new-api Length of output: 1308 🏁 Script executed: # Search for where other.request_conversion comes from (likely API response)
rg "request_conversion|requestConversionDisplayValue" web/src/hooks/usage-logs/ -A 2 -B 2Repository: QuantumNous/new-api Length of output: 893 🏁 Script executed: # Look for type definitions or API contracts related to request_conversion
fd -e "ts" -e "tsx" -e "d.ts" | xargs rg "request_conversion" 2>/dev/null | head -20Repository: QuantumNous/new-api Length of output: 304 🏁 Script executed: # Find and examine service/log_info_generate.go
fd "log_info_generate.go" --type fRepository: QuantumNous/new-api Length of output: 91 🏁 Script executed: # Look at the context around request_conversion assignment in the backend
if [ -f "service/log_info_generate.go" ]; then
# Find lines with request_conversion and show context
rg "request_conversion|chain" "service/log_info_generate.go" -B 5 -A 5 | head -60
else
echo "File not found"
fiRepository: QuantumNous/new-api Length of output: 1094 🏁 Script executed: # Also check model/log.go to understand when request_conversion is deleted
if [ -f "model/log.go" ]; then
rg "request_conversion" "model/log.go" -B 3 -A 3
else
echo "File not found"
fiRepository: QuantumNous/new-api Length of output: 284 🏁 Script executed: # Search for type definitions or comments about the conversion chain structure
rg "type.*[Cc]onversion|[Cc]onversion.*struct" --type go | head -20Repository: QuantumNous/new-api Length of output: 45 🏁 Script executed: # Verify if there are any tests or comments that clarify the expected behavior
rg "RequestConversionChain|request_conversion" --type go -B 2 -A 2 | grep -E "comment|//|len\(chain\)|len\(|if.*==" | head -30Repository: QuantumNous/new-api Length of output: 880 🏁 Script executed: # Check if there are any tests related to request_conversion formatting
fd -e "test.go" -e "_test.go" | xargs rg "request_conversion\|requestConversion" 2>/dev/nullRepository: QuantumNous/new-api Length of output: 47 🏁 Script executed: # Double-check the exact behavior: when is request_conversion NOT set vs when it IS set
sed -n '1,100p' "service/log_info_generate.go" | grep -A 50 "RequestConversionChain"Repository: QuantumNous/new-api Length of output: 872 🏁 Script executed: # Confirm the actual behavior when request_conversion is undefined/missing
sed -n '490,510p' "web/src/hooks/usage-logs/useUsageLogsData.jsx"Repository: QuantumNous/new-api Length of output: 661 Display single-step conversions instead of hiding them as native format. The condition Suggested fix- const requestConversionDisplayValue = (conversionChain) => {
- const chain = Array.isArray(conversionChain)
- ? conversionChain.filter(Boolean)
- : [];
- if (chain.length <= 1) {
- return t('原生格式');
- }
- return `${chain.join(' -> ')}`;
- };
+ const requestConversionDisplayValue = (conversionChain) => {
+ const chain = Array.isArray(conversionChain)
+ ? conversionChain.filter(Boolean)
+ : conversionChain
+ ? [conversionChain]
+ : [];
+ if (chain.length === 0) {
+ return t('原生格式');
+ }
+ return chain.join(' -> ');
+ };🤖 Prompt for AI Agents |
||
|
|
||
| let expandDatesLocal = {}; | ||
| for (let i = 0; i < logs.length; i++) { | ||
| logs[i].timestamp2string = timestamp2string(logs[i].created_at); | ||
|
|
@@ -482,6 +492,12 @@ export const useLogsData = () => { | |
| value: other.request_path, | ||
| }); | ||
| } | ||
| if (isAdminUser) { | ||
| expandDataLocal.push({ | ||
| key: t('请求转换'), | ||
| value: requestConversionDisplayValue(other?.request_conversion), | ||
| }); | ||
| } | ||
| if (isAdminUser) { | ||
| let localCountMode = ''; | ||
| if (other?.admin_info?.local_count_tokens) { | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Set RelayFormat for task/mj_proxy to initialize the conversion chain.
InitRequestConversionChainseeds fromRelayInfo.RelayFormat, but the Task/MjProxy cases only callgenBaseRelayInfo, leaving the chain empty. Assign the format in those cases so logs include the starting format.🔧 Suggested fix
🤖 Prompt for AI Agents