Skip to content

Commit eaa2fef

Browse files
authored
init
1 parent 6b5e71f commit eaa2fef

File tree

6 files changed

+47
-25
lines changed

6 files changed

+47
-25
lines changed

KimmyXYC/go.mod

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,9 @@ go 1.23
44

55
require (
66
github.com/gin-gonic/gin v1.10.0
7-
github.com/golang-jwt/jwt/v5 v5.2.1
7+
github.com/golang-jwt/jwt/v5 v5.2.2
88
github.com/joho/godotenv v1.5.1
9-
golang.org/x/crypto v0.26.0
9+
golang.org/x/crypto v0.27.0
1010
gorm.io/driver/postgres v1.5.9
1111
gorm.io/gorm v1.25.11
1212
)

KimmyXYC/internal/db/db.go

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,7 @@ import (
1212
// Connect opens a PostgreSQL connection using DATABASE_URL.
1313
func Connect(databaseURL string) (*gorm.DB, error) {
1414
if databaseURL == "" {
15-
// Provide a friendly default to help first run; it will still fail if DB not available.
16-
databaseURL = "postgres://postgres:postgres@localhost:5432/aibackend?sslmode=disable"
15+
return nil, fmt.Errorf("DATABASE_URL is required")
1716
}
1817
dsn := databaseURL
1918
db, err := gorm.Open(postgres.Open(dsn), &gorm.Config{})

KimmyXYC/internal/provider/openai.go

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -43,9 +43,9 @@ func NewOpenAIProviderFromEnv() *OpenAIProvider {
4343
}
4444

4545
type openAIChatRequest struct {
46-
Model string `json:"model"`
47-
Messages []openAIChatMessage `json:"messages"`
48-
Stream bool `json:"stream"`
46+
Model string `json:"model"`
47+
Messages []openAIChatMessage `json:"messages"`
48+
Stream bool `json:"stream"`
4949
}
5050

5151
type openAIChatMessage struct {
@@ -54,18 +54,18 @@ type openAIChatMessage struct {
5454
}
5555

5656
type openAIStreamChunk struct {
57-
ID string `json:"id"`
58-
Object string `json:"object"`
59-
Created int64 `json:"created"`
60-
Model string `json:"model"`
57+
ID string `json:"id"`
58+
Object string `json:"object"`
59+
Created int64 `json:"created"`
60+
Model string `json:"model"`
6161
Choices []openAIStreamChunkChoice `json:"choices"`
6262
}
6363

6464
type openAIStreamChunkChoice struct {
65-
Index int `json:"index"`
66-
Delta openAIStreamDelta `json:"delta"`
65+
Index int `json:"index"`
66+
Delta openAIStreamDelta `json:"delta"`
6767
// finish_reason may be "stop" etc.
68-
FinishReason *string `json:"finish_reason"`
68+
FinishReason *string `json:"finish_reason"`
6969
}
7070

7171
type openAIStreamDelta struct {
@@ -125,7 +125,10 @@ func (p *OpenAIProvider) ChatCompletionStream(ctx context.Context, model string,
125125
for {
126126
select {
127127
case <-ctx.Done():
128-
ch <- StreamChunk{Err: ctx.Err()}
128+
select {
129+
case ch <- StreamChunk{Err: ctx.Err()}:
130+
default:
131+
}
129132
return
130133
default:
131134
}

KimmyXYC/internal/services/chat_service.go

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,12 @@ func (s *ChatService) SendMessage(ctx context.Context, userID uint, convID uint,
8080
}
8181
// Load recent messages for context
8282
var msgs []models.Message
83-
s.DB.Where("conversation_id = ?", conv.ID).Order("id desc").Limit(s.MaxTurns * 2).Find(&msgs)
83+
if err := s.DB.Where("conversation_id = ?", conv.ID).
84+
Order("id desc").
85+
Limit(s.MaxTurns * 2).
86+
Find(&msgs).Error; err != nil {
87+
return conv.ID, "", err
88+
}
8489
// reverse to chronological
8590
for i, j := 0, len(msgs)-1; i < j; i, j = i+1, j-1 {
8691
msgs[i], msgs[j] = msgs[j], msgs[i]
@@ -118,5 +123,8 @@ func (s *ChatService) SendMessage(ctx context.Context, userID uint, convID uint,
118123
if err := s.DB.Create(am).Error; err != nil {
119124
return conv.ID, "", err
120125
}
126+
if err := s.DB.Model(conv).UpdateColumn("updated_at", time.Now()).Error; err != nil {
127+
return conv.ID, "", err
128+
}
121129
return conv.ID, am.Content, nil
122130
}

KimmyXYC/pkg/auth/token.go

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,12 @@ import (
88
"github.com/golang-jwt/jwt/v5"
99
)
1010

11-
var defaultSecret = []byte("dev-secret-change-me")
12-
13-
func jwtSecret() []byte {
14-
if s := os.Getenv("JWT_SECRET"); s != "" {
15-
return []byte(s)
11+
func jwtSecret() ([]byte, error) {
12+
s := os.Getenv("JWT_SECRET")
13+
if s == "" {
14+
return nil, errors.New("JWT_SECRET is not configured")
1615
}
17-
return defaultSecret
16+
return []byte(s), nil
1817
}
1918

2019
// Claims represents JWT claims for a user session.
@@ -36,14 +35,22 @@ func CreateToken(userID uint, email, role string, ttl time.Duration) (string, er
3635
IssuedAt: jwt.NewNumericDate(time.Now()),
3736
},
3837
}
38+
key, err := jwtSecret()
39+
if err != nil {
40+
return "", err
41+
}
3942
t := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
40-
return t.SignedString(jwtSecret())
43+
return t.SignedString(key)
4144
}
4245

4346
// ParseToken parses and validates a JWT, returning claims if valid.
4447
func ParseToken(token string) (*Claims, error) {
48+
key, err := jwtSecret()
49+
if err != nil {
50+
return nil, err
51+
}
4552
tok, err := jwt.ParseWithClaims(token, &Claims{}, func(t *jwt.Token) (interface{}, error) {
46-
return jwtSecret(), nil
53+
return key, nil
4754
})
4855
if err != nil {
4956
return nil, err

KimmyXYC/web/js/chat.js

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,12 @@ export function initChatUI() {
6868
li.dataset.id = c.id;
6969
li.className = (c.id === currentConv) ? 'active' : '';
7070
const title = c.title || `对话 #${c.id}`;
71-
li.innerHTML = `<div>${title}</div><small>${c.model || ''}</small>`;
71+
const titleDiv = document.createElement('div');
72+
titleDiv.textContent = title;
73+
const modelSmall = document.createElement('small');
74+
modelSmall.textContent = c.model || '';
75+
li.appendChild(titleDiv);
76+
li.appendChild(modelSmall);
7277
li.addEventListener('click', async () => {
7378
currentConv = c.id;
7479
document.querySelectorAll('#conv-list li').forEach(x => x.classList.remove('active'));

0 commit comments

Comments
 (0)