Skip to content

Commit 594373f

Browse files
Junyi-99kah-seng
andauthored
feat: gpt-5.2 & refactors & tools (#107)
Co-authored-by: 4ndrelim <tiltedaf3@gmail.com>, kah-seng <71002797+kah-seng@users.noreply.github.com>
1 parent 4b65823 commit 594373f

138 files changed

Lines changed: 7309 additions & 1747 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

README.md

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,11 @@
1-
![branding](docs/imgs/branding.png)
21

3-
**Explore the demo paper’s supporting assets in the [/demo](/demo/) folder.**
2+
<a href="https://chromewebstore.google.com/detail/paperdebugger/dfkedikhakpapbfcnbpmfhpklndgiaog" target="_blank"><img src="docs/imgs/branding.png" alt="PaperDebugger"/></a>
43

54
<div align="center">
65
<a href="https://chromewebstore.google.com/detail/paperdebugger/dfkedikhakpapbfcnbpmfhpklndgiaog" target="_blank"><img src="https://img.shields.io/chrome-web-store/users/dfkedikhakpapbfcnbpmfhpklndgiaog?label=Users" alt="Chrome Web Store Users"/></a>
76
<a href="https://chromewebstore.google.com/detail/paperdebugger/dfkedikhakpapbfcnbpmfhpklndgiaog" target="_blank"><img src="https://img.shields.io/chrome-web-store/v/dfkedikhakpapbfcnbpmfhpklndgiaog?label=Chrome%20Web%20Store&logo=google-chrome&logoColor=white" alt="Chrome Web Store Version"/></a>
87
<a href="https://github.com/PaperDebugger/paperdebugger/releases" target="_blank"><img src="https://img.shields.io/github/v/release/PaperDebugger/paperdebugger?label=Latest%20Release" alt="GitHub Release"/></a>
9-
<a href="https://github.com/PaperDebugger/paperdebugger/actions/workflows/release.yml" target="_blank"><img src="https://img.shields.io/github/actions/workflow/status/PaperDebugger/paperdebugger/build.yml?branch=main" alt="Build Status"/></a>
8+
<a href="https://github.com/PaperDebugger/paperdebugger/actions/workflows/build-backend-prd.yml" target="_blank"><img src="https://img.shields.io/github/actions/workflow/status/PaperDebugger/paperdebugger/build-backend-prd.yml?branch=main" alt="Build Status"/></a>
109
<a href="https://github.com/PaperDebugger/PaperDebugger?tab=AGPL-3.0-1-ov-file"><img src="https://img.shields.io/github/license/PaperDebugger/paperdebugger" alt="License"/></a>
1110
</div>
1211

@@ -64,19 +63,21 @@ https://github.com/user-attachments/assets/6c20924d-1eb6-44d5-95b0-207bd08b718b
6463
2. **Ready to use**
6564
- Open any Overleaf project
6665
- Click the PaperDebugger icon on the top-left
67-
- Begin chatting with your LaTeX assistant!
66+
- Begin chatting with your LaTeX document!
6867

6968
### Custom Endpoint Configuration
7069

7170
If you want to use a **self-hosted** PaperDebugger backend, you can configure a custom endpoint. Here are the steps:
7271

7372
1. Open the PaperDebugger extension
7473

75-
(a.) Go to Settings, click the version number 5 times to enable "Developer Tools"
74+
(a.) Go to Settings, click the version number **5 times** to enable "Developer Tools"
7675

7776
(b.) Enter your backend URL in the "Backend Endpoint" field
7877
2. Refresh the page
7978

79+
Note: you can only use "Login by Overleaf" if you are self-hosting the backend.
80+
8081
If you encounter endpoint errors after refresh, use the "Advanced Options" at the bottom of the login page to reconfigure.
8182

8283
<div align="center">

docs/imgs/wechat.jpg

-177 KB
Loading

hack/stg.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ ROOT_DIR=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")/.." &>/dev/null && pwd)
66
cd $ROOT_DIR
77

88
OPENAI_BASE_URL=${OPENAI_BASE_URL:-https://api.openai.com/v1}
9-
OPENAI_API_KEY=${OPENAI_API_KEY:-sk-dummy-OPENAI_API_KEY}
9+
OPENAI_API_KEY=${OPENAI_API_KEY:-}
1010
INFERENCE_BASE_URL=${INFERENCE_BASE_URL:-https://inference.paperdebugger.workers.dev}
1111
INFERENCE_API_KEY=${INFERENCE_API_KEY:-sk-dummy-OPEN-ROUTER}
1212
MCP_BASIC_KEY=${MCP_BASIC_KEY:-sk-dummy-MCP_BASIC_KEY}

internal/api/chat/create_conversation_message_stream_v2.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,7 @@ func (s *ChatServerV2) prepare(ctx context.Context, projectId string, conversati
195195
}
196196

197197
var latexFullSource string
198+
var projectInstructions string = ""
198199
switch conversationType {
199200
case chatv2.ConversationType_CONVERSATION_TYPE_DEBUG:
200201
latexFullSource = "latex_full_source is not available in debug mode"
@@ -207,6 +208,8 @@ func (s *ChatServerV2) prepare(ctx context.Context, projectId string, conversati
207208
if err != nil {
208209
return ctx, nil, nil, err
209210
}
211+
212+
projectInstructions = project.Instructions
210213
}
211214

212215
var conversation *models.Conversation
@@ -217,7 +220,7 @@ func (s *ChatServerV2) prepare(ctx context.Context, projectId string, conversati
217220
actor.ID,
218221
projectId,
219222
latexFullSource,
220-
project.Instructions,
223+
projectInstructions,
221224
userInstructions,
222225
userMessage,
223226
userSelectedText,

internal/api/chat/list_supported_models_v2.go

Lines changed: 227 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,202 @@ import (
1010
"github.com/openai/openai-go/v3"
1111
)
1212

13+
// modelConfig holds model configuration including whether it requires user's own API key
14+
type modelConfig struct {
15+
name string
16+
slugOpenRouter string // Slug for OpenRouter API (used when user doesn't provide own key)
17+
slugOpenAI string // Slug for OpenAI API (used when user provides own key)
18+
totalContext int64
19+
maxOutput int64
20+
inputPrice int64
21+
outputPrice int64
22+
requireOwnKey bool // If true, this model requires user to provide their own API key
23+
}
24+
25+
// allModels defines all available models in the system
26+
var allModels = []modelConfig{
27+
{
28+
name: "GPT-5.1",
29+
slugOpenRouter: "openai/gpt-5.1",
30+
slugOpenAI: openai.ChatModelGPT5_1,
31+
totalContext: 400000,
32+
maxOutput: 128000,
33+
inputPrice: 125, // $1.25
34+
outputPrice: 1000, // $10.00
35+
requireOwnKey: false,
36+
},
37+
{
38+
name: "GPT-5.2",
39+
slugOpenRouter: "openai/gpt-5.2",
40+
slugOpenAI: openai.ChatModelGPT5_2,
41+
totalContext: 400000,
42+
maxOutput: 128000,
43+
inputPrice: 175, // $1.75
44+
outputPrice: 1400, // $14.00
45+
requireOwnKey: true,
46+
},
47+
{
48+
name: "GPT-5 Mini",
49+
slugOpenRouter: "openai/gpt-5-mini",
50+
slugOpenAI: openai.ChatModelGPT5Mini,
51+
totalContext: 400000,
52+
maxOutput: 128000,
53+
inputPrice: 25,
54+
outputPrice: 200,
55+
requireOwnKey: false,
56+
},
57+
{
58+
name: "GPT-5 Nano",
59+
slugOpenRouter: "openai/gpt-5-nano",
60+
slugOpenAI: openai.ChatModelGPT5Nano,
61+
totalContext: 400000,
62+
maxOutput: 128000,
63+
inputPrice: 5, // $0.20
64+
outputPrice: 40, // $0.80
65+
requireOwnKey: false,
66+
},
67+
{
68+
name: "GPT-4.1",
69+
slugOpenRouter: "openai/gpt-4.1",
70+
slugOpenAI: openai.ChatModelGPT4_1,
71+
totalContext: 1050000,
72+
maxOutput: 32800,
73+
inputPrice: 200, // $2.00
74+
outputPrice: 800,
75+
requireOwnKey: false,
76+
},
77+
{
78+
name: "GPT-4.1-mini",
79+
slugOpenRouter: "openai/gpt-4.1-mini",
80+
slugOpenAI: openai.ChatModelGPT4_1Mini,
81+
totalContext: 128000,
82+
maxOutput: 16400,
83+
inputPrice: 15,
84+
outputPrice: 60,
85+
requireOwnKey: false,
86+
},
87+
{
88+
name: "GPT-4o",
89+
slugOpenRouter: "openai/gpt-4o",
90+
slugOpenAI: openai.ChatModelGPT4o,
91+
totalContext: 128000,
92+
maxOutput: 16400,
93+
inputPrice: 250,
94+
outputPrice: 1000,
95+
requireOwnKey: true,
96+
},
97+
{
98+
name: "OpenAI: gpt-oss-120b (free)",
99+
slugOpenRouter: "openai/gpt-oss-120b:free",
100+
slugOpenAI: "",
101+
totalContext: 131072,
102+
maxOutput: 131072,
103+
inputPrice: 0,
104+
outputPrice: 0,
105+
requireOwnKey: false,
106+
},
107+
{
108+
name: "Qwen Plus (balanced)",
109+
slugOpenRouter: "qwen/qwen-plus",
110+
slugOpenAI: "", // OpenAI doesn't support Qwen, use OpenRouter slug
111+
totalContext: 131100,
112+
maxOutput: 8200,
113+
inputPrice: 40,
114+
outputPrice: 120,
115+
requireOwnKey: false,
116+
},
117+
{
118+
name: "Qwen Turbo (fast)",
119+
slugOpenRouter: "qwen/qwen-turbo",
120+
slugOpenAI: "", // OpenAI doesn't support Qwen, use OpenRouter slug
121+
totalContext: 1000000,
122+
maxOutput: 8200,
123+
inputPrice: 5,
124+
outputPrice: 20,
125+
requireOwnKey: false,
126+
},
127+
{
128+
name: "Qwen3 Coder 480B A35B (free)",
129+
slugOpenRouter: "qwen/qwen3-coder:free",
130+
slugOpenAI: "",
131+
totalContext: 262000,
132+
maxOutput: 262000,
133+
inputPrice: 0,
134+
outputPrice: 0,
135+
requireOwnKey: false,
136+
},
137+
{
138+
name: "GLM 4.5 Air (free)",
139+
slugOpenRouter: "z-ai/glm-4.5-air:free",
140+
slugOpenAI: "",
141+
totalContext: 131072,
142+
maxOutput: 131072,
143+
inputPrice: 0,
144+
outputPrice: 0,
145+
requireOwnKey: false,
146+
},
147+
{
148+
name: "Gemini 2.5 Flash (fast)",
149+
slugOpenRouter: "google/gemini-2.5-flash",
150+
slugOpenAI: "", // OpenAI doesn't support Gemini, use OpenRouter slug
151+
totalContext: 1050000,
152+
maxOutput: 65500,
153+
inputPrice: 30,
154+
outputPrice: 250,
155+
requireOwnKey: false,
156+
},
157+
{
158+
name: "Gemini 3 Flash Preview",
159+
slugOpenRouter: "google/gemini-3-flash-preview",
160+
slugOpenAI: "", // OpenAI doesn't support Gemini, use OpenRouter slug
161+
totalContext: 1050000,
162+
maxOutput: 65500,
163+
inputPrice: 50,
164+
outputPrice: 300,
165+
requireOwnKey: false,
166+
},
167+
{
168+
name: "o1 Mini",
169+
slugOpenRouter: "openai/o1-mini",
170+
slugOpenAI: openai.ChatModelO1Mini,
171+
totalContext: 128000,
172+
maxOutput: 65536,
173+
inputPrice: 300, // $3.00
174+
outputPrice: 1200, // $12.00
175+
requireOwnKey: true,
176+
},
177+
{
178+
name: "o3",
179+
slugOpenRouter: "openai/o3",
180+
slugOpenAI: openai.ChatModelO3,
181+
totalContext: 200000,
182+
maxOutput: 100000,
183+
inputPrice: 200,
184+
outputPrice: 800,
185+
requireOwnKey: true,
186+
},
187+
{
188+
name: "o3 Mini",
189+
slugOpenRouter: "openai/o3-mini",
190+
slugOpenAI: openai.ChatModelO3Mini,
191+
totalContext: 200000,
192+
maxOutput: 100000,
193+
inputPrice: 110,
194+
outputPrice: 440,
195+
requireOwnKey: true,
196+
},
197+
{
198+
name: "o4 Mini",
199+
slugOpenRouter: "openai/o4-mini",
200+
slugOpenAI: openai.ChatModelO4Mini,
201+
totalContext: 128000,
202+
maxOutput: 65536,
203+
inputPrice: 110,
204+
outputPrice: 440,
205+
requireOwnKey: true,
206+
},
207+
}
208+
13209
func (s *ChatServerV2) ListSupportedModels(
14210
ctx context.Context,
15211
req *chatv2.ListSupportedModelsRequest,
@@ -24,89 +220,43 @@ func (s *ChatServerV2) ListSupportedModels(
24220
return nil, err
25221
}
26222

223+
hasOwnAPIKey := strings.TrimSpace(settings.OpenAIAPIKey) != ""
224+
27225
var models []*chatv2.SupportedModel
28-
if strings.TrimSpace(settings.OpenAIAPIKey) == "" {
29-
models = []*chatv2.SupportedModel{
30-
{
31-
Name: "GPT-4.1",
32-
Slug: "openai/gpt-4.1",
33-
TotalContext: 1050000,
34-
MaxOutput: 32800,
35-
InputPrice: 200,
36-
OutputPrice: 800,
37-
},
38-
{
39-
Name: "GPT-4.1-mini",
40-
Slug: "openai/gpt-4.1-mini",
41-
TotalContext: 128000,
42-
MaxOutput: 16400,
43-
InputPrice: 15,
44-
OutputPrice: 60,
45-
},
46-
{
47-
Name: "Qwen Plus (balanced)",
48-
Slug: "qwen/qwen-plus",
49-
TotalContext: 131100,
50-
MaxOutput: 8200,
51-
InputPrice: 40,
52-
OutputPrice: 120,
53-
},
54-
{
55-
Name: "Qwen Turbo (fast)",
56-
Slug: "qwen/qwen-turbo",
57-
TotalContext: 1000000,
58-
MaxOutput: 8200,
59-
InputPrice: 5,
60-
OutputPrice: 20,
61-
},
62-
{
63-
Name: "Gemini 2.5 Flash (fast)",
64-
Slug: "google/gemini-2.5-flash",
65-
TotalContext: 1050000,
66-
MaxOutput: 65500,
67-
InputPrice: 30,
68-
OutputPrice: 250,
69-
},
70-
{
71-
Name: "Gemini 3 Flash Preview",
72-
Slug: "google/gemini-3-flash-preview",
73-
TotalContext: 1050000,
74-
MaxOutput: 65500,
75-
InputPrice: 50,
76-
OutputPrice: 300,
77-
},
226+
for _, config := range allModels {
227+
// Choose the appropriate slug based on whether user has their own API key.
228+
//
229+
// Some models are only available via OpenRouter; for those, slugOpenAI may be empty.
230+
// In that case, keep using the OpenRouter slug to avoid returning an empty model slug.
231+
slug := config.slugOpenRouter
232+
if hasOwnAPIKey && strings.TrimSpace(config.slugOpenAI) != "" {
233+
slug = config.slugOpenAI
78234
}
79-
} else {
80-
models = []*chatv2.SupportedModel{
81-
{
82-
Name: "GPT-4.1",
83-
Slug: openai.ChatModelGPT4_1,
84-
TotalContext: 1050000,
85-
MaxOutput: 32800,
86-
InputPrice: 200,
87-
OutputPrice: 800,
88-
},
89-
{
90-
Name: "GPT-4o",
91-
Slug: openai.ChatModelGPT4o,
92-
TotalContext: 128000,
93-
MaxOutput: 16400,
94-
InputPrice: 250,
95-
OutputPrice: 1000,
96-
},
97-
{
98-
Name: "GPT-4.1-mini",
99-
Slug: openai.ChatModelGPT4_1Mini,
100-
TotalContext: 128000,
101-
MaxOutput: 16400,
102-
InputPrice: 15,
103-
OutputPrice: 60,
104-
},
105-
// TODO: add user custom models
235+
236+
model := &chatv2.SupportedModel{
237+
Name: config.name,
238+
Slug: slug,
239+
TotalContext: config.totalContext,
240+
MaxOutput: config.maxOutput,
241+
InputPrice: config.inputPrice,
242+
OutputPrice: config.outputPrice,
106243
}
244+
245+
// If model requires own key but user hasn't provided one, mark as disabled
246+
if config.requireOwnKey && !hasOwnAPIKey {
247+
model.Disabled = true
248+
model.DisabledReason = stringPtr("Requires your own OpenAI API key. Configure it in Settings.")
249+
}
250+
251+
models = append(models, model)
107252
}
108253

109254
return &chatv2.ListSupportedModelsResponse{
110255
Models: models,
111256
}, nil
112257
}
258+
259+
// stringPtr returns a pointer to the given string
260+
func stringPtr(s string) *string {
261+
return &s
262+
}

0 commit comments

Comments
 (0)