feat: 修改合并bug

This commit is contained in:
zerosaturation 2026-06-04 00:52:21 +08:00
parent f768613509
commit 456bf10352
5 changed files with 56 additions and 158 deletions

View File

@ -1,6 +0,0 @@
[mcp_servers.code-review-graph]
command = "uvx"
args = [
"code-review-graph",
"serve",
]

View File

@ -1,28 +0,0 @@
{
"hooks": {
"PostToolUse": [
{
"matcher": "Edit|Write|Bash",
"hooks": [
{
"type": "command",
"command": "git rev-parse --git-dir >/dev/null 2>&1 && code-review-graph update --skip-flows --repo \"/Users/liulujian/Documents/code/TopFansByGithub\" || true",
"timeout": 30
}
]
}
],
"SessionStart": [
{
"matcher": "",
"hooks": [
{
"type": "command",
"command": "git rev-parse --git-dir >/dev/null 2>&1 && code-review-graph status --repo \"/Users/liulujian/Documents/code/TopFansByGithub\" || echo 'Not a git repo, skipping'",
"timeout": 10
}
]
}
]
}
}

View File

@ -1,70 +0,0 @@
---
name: "karpathy-guidelines"
description: "Karpathy 启发的编码行为指南,包含四大原则:编码前思考、简洁优先、精准修改、目标驱动执行。适用于所有编码任务,自动引导模型减少常见 LLM 编码错误。"
---
# Karpathy 编码行为指南
源自 [Andrej Karpathy 的观察](https://x.com/karpathy/status/2015883857489522876) 关于 LLM 编码陷阱的总结。
**权衡说明:** 这些指南倾向于谨慎而非速度。对于琐碎任务(简单拼写错误修复、显而易见的一行修改),请自行判断。
## 1. 编码前思考
**不要假设。不要隐藏困惑。呈现权衡。**
在实现之前:
- 明确陈述你的假设。如果不确定,询问。
- 如果存在多种解释,呈现它们 —— 不要默默选择。
- 如果存在更简单的方法,说出来。适时提出异议。
- 如果有不清楚的地方,停下来。指出困惑之处。询问。
## 2. 简洁优先
**用最少的代码解决问题。不要过度推测。**
- 不添加要求之外的功能。
- 不为一次性代码创建抽象。
- 不添加未要求的"灵活性"或"可配置性"。
- 不为不可能发生的场景做错误处理。
- 如果你写了 200 行代码,而 50 行就能搞定,重写它。
**自问:** "资深工程师会觉得这过于复杂吗?" 如果是,简化。
## 3. 精准修改
**只碰必须碰的。只清理自己造成的混乱。**
编辑现有代码时:
- 不要"改进"相邻的代码、注释或格式。
- 不要重构没坏的东西。
- 匹配现有风格,即使你更倾向于不同的写法。
- 如果注意到无关的死代码,提一下 —— 不要删除它。
当你的改动产生孤儿代码时:
- 删除因你的改动而变得无用的导入/变量/函数。
- 不要删除预先存在的死代码,除非被要求。
**检验标准:** 每一行修改都应该能直接追溯到用户的请求。
## 4. 目标驱动执行
**定义成功标准。循环验证直到达成。**
将指令式任务转化为可验证的目标:
- "添加验证" → "为无效输入编写测试,然后让它们通过"
- "修复 bug" → "编写重现 bug 的测试,然后让它通过"
- "重构 X" → "确保重构前后测试都能通过"
对于多步骤任务,说明一个简短的计划:
```
1. [步骤] → 验证: [检查]
2. [步骤] → 验证: [检查]
3. [步骤] → 验证: [检查]
```
强有力的成功标准让你能够独立循环执行。弱标准("让它工作")需要不断澄清。
---
**这些指南在起作用的标志:** diff 中不必要的改动更少、因过度复杂而导致的重写更少、澄清问题在实现之前提出而不是在犯错之后。

View File

@ -8,17 +8,18 @@ import (
// Config 网关配置
type Config struct {
Server ServerConfig
Dubbo DubboConfig
JWT JWTConfig
OSS OSSConfig
Segment SegmentConfig
Dify DifyConfig
Minimax MinimaxConfig
Server ServerConfig
Dubbo DubboConfig
JWT JWTConfig
OSS OSSConfig
Segment SegmentConfig
Dify DifyConfig
Minimax MinimaxConfig
LaserCompositor LaserCompositorConfig
Redis RedisConfig
DB DBConfig
Root string
Redis RedisConfig
DB DBConfig
WebSocket WebSocketConfig
Root string
}
// MinimaxConfig MiniMax 图像生成配置
@ -36,13 +37,6 @@ type LaserCompositorConfig struct {
type DifyConfig struct {
APIBase string
APIKey string
Server ServerConfig
Dubbo DubboConfig
JWT JWTConfig
OSS OSSConfig
Redis RedisConfig
WebSocket WebSocketConfig
Root string
}
// RedisConfig Redis 配置
@ -175,6 +169,15 @@ func Load() *Config {
Password: getEnv("REDIS_PASSWORD", ""),
DB: getEnvInt("REDIS_DB", 0),
},
DB: DBConfig{
Host: getEnv("DB_HOST", "localhost"),
Port: getEnvInt("DB_PORT", 5432),
User: getEnv("DB_USER", "postgres"),
Password: getEnv("DB_PASSWORD", ""),
DBName: getEnv("DB_NAME", "top-fans"),
SSLMode: getEnv("DB_SSLMODE", "disable"),
TimeZone: getEnv("DB_TIMEZONE", "Asia/Shanghai"),
},
WebSocket: WebSocketConfig{
AIChatPath: getEnv("WS_AI_CHAT_PATH", "/ws/ai-chat"),
},

View File

@ -1046,16 +1046,10 @@ func (ctrl *AssetController) generateOSSPolicyTokenWithKey(
date := utcTime.Format("20060102")
expiration := utcTime.Add(time.Duration(ossConfig.TokenExpireTime) * time.Second)
baseDir := ossConfig.GetUploadDir(uploadType)
uploadDir := baseDir
if userID != nil && starID != nil {
uploadDir = fmt.Sprintf("%s%d/%d/", baseDir, userID, starID)
}
// 尝试 STS AssumeRole失败则降级到永久 AccessKey 直连
var accessKeyID, accessKeySecret, securityToken string
useSTS := false
// 尝试 STS AssumeRole失败则降级到永久 AccessKey 直连
// 1. 创建 STS 凭证提供器
credConfig := new(credentials.Config).
SetType("ram_role_arn").
@ -1079,32 +1073,23 @@ func (ctrl *AssetController) generateOSSPolicyTokenWithKey(
logger.Logger.Warn("STS credential provider failed, falling back to direct AK/SK", zap.Error(err))
}
if !useSTS {
accessKeyID = ossConfig.AccessKeyID
accessKeySecret = ossConfig.AccessKeySecret
}
// 2. 获取临时凭证
cred, err := provider.GetCredential()
if err != nil {
return nil, fmt.Errorf("获取临时凭证失败: %w", err)
}
// 3. 构建 Policy
utcTime := time.Now().UTC()
date := utcTime.Format("20060102")
expiration := utcTime.Add(time.Duration(ossConfig.TokenExpireTime) * time.Second)
// 构建 Policy 条件
// 2. 构建 Policy 条件
conditions := []interface{}{
map[string]string{"bucket": ossConfig.BucketName},
// 限制 key 必须等于指定完整 key更严前端只能写到该路径
[]interface{}{"eq", "$key", uploadKey},
map[string]string{"x-oss-signature-version": "OSS4-HMAC-SHA256"},
map[string]string{"x-oss-credential": fmt.Sprintf("%s/%s/%s/%s/aliyun_v4_request",
*cred.AccessKeyId, date, ossConfig.Region, "oss")},
accessKeyID, date, ossConfig.Region, "oss")},
map[string]string{"x-oss-date": utcTime.Format("20060102T150405Z")},
map[string]string{"x-oss-security-token": *cred.SecurityToken},
}
if useSTS && securityToken != "" {
conditions = append(conditions, map[string]string{"x-oss-security-token": securityToken})
}
policyMap := map[string]interface{}{
@ -1112,33 +1097,36 @@ func (ctrl *AssetController) generateOSSPolicyTokenWithKey(
"conditions": conditions,
}
// 4. 生成 Policy 的 Base64 编码
// 3. 生成 Policy 的 Base64 编码
policyJSON, err := json.Marshal(policyMap)
if err != nil {
return nil, fmt.Errorf("序列化 policy 失败: %w", err)
}
policyBase64 := base64.StdEncoding.EncodeToString(policyJSON)
// 5. 计算签名
signingKey := buildSigningKey(*cred.AccessKeySecret, date, ossConfig.Region, "oss")
// 4. 计算签名
signingKey := buildSigningKey(accessKeySecret, date, ossConfig.Region, "oss")
signature := calculateSignature(signingKey, policyBase64)
// 6. 构建返回数据
// 5. 构建返回数据
host := fmt.Sprintf("https://%s.oss-%s.aliyuncs.com", ossConfig.BucketName, ossConfig.Region)
return map[string]interface{}{
result := map[string]interface{}{
"policy": policyBase64,
"security_token": *cred.SecurityToken,
"x_oss_signature_version": "OSS4-HMAC-SHA256",
"x_oss_credential": fmt.Sprintf("%s/%s/%s/%s/aliyun_v4_request",
*cred.AccessKeyId, date, ossConfig.Region, "oss"),
accessKeyID, date, ossConfig.Region, "oss"),
"x_oss_date": utcTime.Format("20060102T150405Z"),
"signature": signature,
"host": host,
"dir": dirFromKey(uploadKey),
"key": uploadKey,
"expire_time": expiration.Unix(),
}, nil
}
if useSTS && securityToken != "" {
result["security_token"] = securityToken
}
return result, nil
}
// generateOSSPolicyTokenWithDir 按显式目录生成 OSS 上传策略和签名
@ -1157,15 +1145,26 @@ func (ctrl *AssetController) generateOSSPolicyTokenWithDir(
SetPolicy("").
SetRoleSessionExpiration(ossConfig.TokenExpireTime)
provider, err := credentials.NewCredential(credConfig)
if err != nil {
return nil, fmt.Errorf("创建凭证提供器失败: %w", err)
// 尝试 STS AssumeRole失败则降级到永久 AccessKey 直连
var accessKeyID, accessKeySecret, securityToken string
useSTS := false
if provider, err := credentials.NewCredential(credConfig); err == nil {
if cred, err := provider.GetCredential(); err == nil {
accessKeyID = *cred.AccessKeyId
accessKeySecret = *cred.AccessKeySecret
securityToken = *cred.SecurityToken
useSTS = true
} else {
logger.Logger.Warn("STS AssumeRole failed for WithDir, falling back to direct AK/SK", zap.Error(err))
}
} else {
logger.Logger.Warn("STS credential provider failed for WithDir, falling back to direct AK/SK", zap.Error(err))
}
// 2. 获取临时凭证
cred, err := provider.GetCredential()
if err != nil {
return nil, fmt.Errorf("获取临时凭证失败: %w", err)
if !useSTS {
accessKeyID = ossConfig.AccessKeyID
accessKeySecret = ossConfig.AccessKeySecret
}
// 3. 构建 Policy