Spaces:
Running
Running
Add support for compatible API services & update ui
Browse files- app.py +34 -16
- utils/langgraph_utils.py +33 -18
app.py
CHANGED
@@ -23,12 +23,16 @@ except ImportError as e:
|
|
23 |
print(f"Error importing modules: {e}")
|
24 |
sys.exit(1)
|
25 |
|
26 |
-
def set_api_keys(anthropic_key, openai_key):
|
27 |
-
"""Securely set API keys in environment"""
|
28 |
if anthropic_key and anthropic_key.strip():
|
29 |
os.environ["ANTHROPIC_API_KEY"] = anthropic_key.strip()
|
30 |
if openai_key and openai_key.strip():
|
31 |
os.environ["OPENAI_API_KEY"] = openai_key.strip()
|
|
|
|
|
|
|
|
|
32 |
|
33 |
AVAILABLE_MODELS = [
|
34 |
"claude-sonnet-4-20250514",
|
@@ -44,7 +48,7 @@ def create_job_directory() -> Path:
|
|
44 |
job_dir = Path(tempfile.mkdtemp(prefix=f"{dir_name}_"))
|
45 |
return job_dir
|
46 |
|
47 |
-
def validate_inputs(pdf_file, logo_file, aff_logo_file, text_model, vision_model, poster_width, poster_height, anthropic_key, openai_key):
|
48 |
if not pdf_file:
|
49 |
return "Please upload PDF paper"
|
50 |
if not logo_file:
|
@@ -83,12 +87,12 @@ def validate_inputs(pdf_file, logo_file, aff_logo_file, text_model, vision_model
|
|
83 |
|
84 |
return None
|
85 |
|
86 |
-
def generate_poster(pdf_file, logo_file, aff_logo_file, text_model, vision_model, poster_width, poster_height, anthropic_key, openai_key, progress=gr.Progress()):
|
87 |
try:
|
88 |
-
# Set API keys first
|
89 |
-
set_api_keys(anthropic_key, openai_key)
|
90 |
|
91 |
-
error_msg = validate_inputs(pdf_file, logo_file, aff_logo_file, text_model, vision_model, poster_width, poster_height, anthropic_key, openai_key)
|
92 |
if error_msg:
|
93 |
return None, None, f"β {error_msg}", ""
|
94 |
|
@@ -193,8 +197,18 @@ with gr.Blocks(title="PosterGen") as demo:
|
|
193 |
""")
|
194 |
|
195 |
with gr.Row():
|
|
|
196 |
with gr.Column(scale=1):
|
|
|
|
|
|
|
197 |
|
|
|
|
|
|
|
|
|
|
|
|
|
198 |
gr.Markdown("### π API Keys")
|
199 |
gr.Markdown("β οΈ Keys are processed securely and not stored")
|
200 |
|
@@ -211,14 +225,18 @@ with gr.Blocks(title="PosterGen") as demo:
|
|
211 |
placeholder="sk-...",
|
212 |
info="Required for GPT models"
|
213 |
)
|
214 |
-
|
215 |
-
gr.Markdown("### π Upload Files")
|
216 |
-
|
217 |
-
pdf_file = gr.File(label="PDF Paper", file_types=[".pdf"], type="binary")
|
218 |
-
|
219 |
with gr.Row():
|
220 |
-
|
221 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
222 |
|
223 |
gr.Markdown("### π€ Model Settings")
|
224 |
|
@@ -234,8 +252,8 @@ with gr.Blocks(title="PosterGen") as demo:
|
|
234 |
|
235 |
generate_btn = gr.Button("π Generate Poster", variant="primary", size="lg")
|
236 |
|
|
|
237 |
with gr.Column(scale=1):
|
238 |
-
|
239 |
gr.Markdown("### π Status")
|
240 |
status_output = gr.Textbox(label="Generation Status", placeholder="Click 'Generate Poster' to start...", lines=6)
|
241 |
|
@@ -248,7 +266,7 @@ with gr.Blocks(title="PosterGen") as demo:
|
|
248 |
|
249 |
generate_btn.click(
|
250 |
fn=generate_and_display,
|
251 |
-
inputs=[pdf_file, logo_file, aff_logo_file, text_model, vision_model, poster_width, poster_height, anthropic_key, openai_key],
|
252 |
outputs=[download_file, status_output]
|
253 |
)
|
254 |
|
|
|
23 |
print(f"Error importing modules: {e}")
|
24 |
sys.exit(1)
|
25 |
|
26 |
+
def set_api_keys(anthropic_key, openai_key, anthropic_base_url=None, openai_base_url=None):
|
27 |
+
"""Securely set API keys and base URLs in environment"""
|
28 |
if anthropic_key and anthropic_key.strip():
|
29 |
os.environ["ANTHROPIC_API_KEY"] = anthropic_key.strip()
|
30 |
if openai_key and openai_key.strip():
|
31 |
os.environ["OPENAI_API_KEY"] = openai_key.strip()
|
32 |
+
if anthropic_base_url and anthropic_base_url.strip():
|
33 |
+
os.environ["ANTHROPIC_BASE_URL"] = anthropic_base_url.strip()
|
34 |
+
if openai_base_url and openai_base_url.strip():
|
35 |
+
os.environ["OPENAI_BASE_URL"] = openai_base_url.strip()
|
36 |
|
37 |
AVAILABLE_MODELS = [
|
38 |
"claude-sonnet-4-20250514",
|
|
|
48 |
job_dir = Path(tempfile.mkdtemp(prefix=f"{dir_name}_"))
|
49 |
return job_dir
|
50 |
|
51 |
+
def validate_inputs(pdf_file, logo_file, aff_logo_file, text_model, vision_model, poster_width, poster_height, anthropic_key, openai_key, anthropic_base_url, openai_base_url):
|
52 |
if not pdf_file:
|
53 |
return "Please upload PDF paper"
|
54 |
if not logo_file:
|
|
|
87 |
|
88 |
return None
|
89 |
|
90 |
+
def generate_poster(pdf_file, logo_file, aff_logo_file, text_model, vision_model, poster_width, poster_height, anthropic_key, openai_key, anthropic_base_url, openai_base_url, progress=gr.Progress()):
|
91 |
try:
|
92 |
+
# Set API keys and base URLs first
|
93 |
+
set_api_keys(anthropic_key, openai_key, anthropic_base_url, openai_base_url)
|
94 |
|
95 |
+
error_msg = validate_inputs(pdf_file, logo_file, aff_logo_file, text_model, vision_model, poster_width, poster_height, anthropic_key, openai_key, anthropic_base_url, openai_base_url)
|
96 |
if error_msg:
|
97 |
return None, None, f"β {error_msg}", ""
|
98 |
|
|
|
197 |
""")
|
198 |
|
199 |
with gr.Row():
|
200 |
+
# Column 1: Upload Files
|
201 |
with gr.Column(scale=1):
|
202 |
+
gr.Markdown("### π Upload Files")
|
203 |
+
|
204 |
+
pdf_file = gr.File(label="PDF Paper", file_types=[".pdf"], type="binary")
|
205 |
|
206 |
+
with gr.Row():
|
207 |
+
logo_file = gr.File(label="Conference Logo", file_types=["image"], type="binary")
|
208 |
+
aff_logo_file = gr.File(label="Affiliation Logo", file_types=["image"], type="binary")
|
209 |
+
|
210 |
+
# Column 2: API Keys, Model Settings, Dimensions, Generate Button
|
211 |
+
with gr.Column(scale=1):
|
212 |
gr.Markdown("### π API Keys")
|
213 |
gr.Markdown("β οΈ Keys are processed securely and not stored")
|
214 |
|
|
|
225 |
placeholder="sk-...",
|
226 |
info="Required for GPT models"
|
227 |
)
|
228 |
+
|
|
|
|
|
|
|
|
|
229 |
with gr.Row():
|
230 |
+
anthropic_base_url = gr.Textbox(
|
231 |
+
label="Anthropic Base URL",
|
232 |
+
placeholder="https://api.anthropic.com",
|
233 |
+
info="(Optional) Set the Base URL if using compatible API services"
|
234 |
+
)
|
235 |
+
openai_base_url = gr.Textbox(
|
236 |
+
label="OpenAI Base URL",
|
237 |
+
placeholder="https://api.openai.com/v1",
|
238 |
+
info="(Optional) Set the Base URL if using compatible API services"
|
239 |
+
)
|
240 |
|
241 |
gr.Markdown("### π€ Model Settings")
|
242 |
|
|
|
252 |
|
253 |
generate_btn = gr.Button("π Generate Poster", variant="primary", size="lg")
|
254 |
|
255 |
+
# Column 3: Status and Download
|
256 |
with gr.Column(scale=1):
|
|
|
257 |
gr.Markdown("### π Status")
|
258 |
status_output = gr.Textbox(label="Generation Status", placeholder="Click 'Generate Poster' to start...", lines=6)
|
259 |
|
|
|
266 |
|
267 |
generate_btn.click(
|
268 |
fn=generate_and_display,
|
269 |
+
inputs=[pdf_file, logo_file, aff_logo_file, text_model, vision_model, poster_width, poster_height, anthropic_key, openai_key, anthropic_base_url, openai_base_url],
|
270 |
outputs=[download_file, status_output]
|
271 |
)
|
272 |
|
utils/langgraph_utils.py
CHANGED
@@ -21,26 +21,41 @@ load_dotenv()
|
|
21 |
def create_model(config: ModelConfig):
|
22 |
"""create chat model from config"""
|
23 |
if config.provider == 'openai':
|
24 |
-
|
25 |
-
model_name
|
26 |
-
temperature
|
27 |
-
max_tokens
|
28 |
-
api_key
|
29 |
-
|
|
|
|
|
|
|
|
|
|
|
30 |
elif config.provider == 'anthropic':
|
31 |
-
|
32 |
-
model
|
33 |
-
temperature
|
34 |
-
max_tokens
|
35 |
-
api_key
|
36 |
-
|
|
|
|
|
|
|
|
|
|
|
37 |
elif config.provider == 'google':
|
38 |
-
|
39 |
-
model
|
40 |
-
temperature
|
41 |
-
max_output_tokens
|
42 |
-
google_api_key
|
43 |
-
|
|
|
|
|
|
|
|
|
|
|
44 |
else:
|
45 |
raise ValueError(f"unsupported provider: {config.provider}")
|
46 |
|
|
|
21 |
def create_model(config: ModelConfig):
|
22 |
"""create chat model from config"""
|
23 |
if config.provider == 'openai':
|
24 |
+
openai_kwargs = {
|
25 |
+
'model_name': config.model_name,
|
26 |
+
'temperature': config.temperature,
|
27 |
+
'max_tokens': config.max_tokens,
|
28 |
+
'api_key': os.getenv('OPENAI_API_KEY')
|
29 |
+
}
|
30 |
+
base_url = os.getenv('OPENAI_BASE_URL')
|
31 |
+
if base_url:
|
32 |
+
openai_kwargs['base_url'] = base_url
|
33 |
+
|
34 |
+
return ChatOpenAI(**openai_kwargs)
|
35 |
elif config.provider == 'anthropic':
|
36 |
+
anthropic_kwargs = {
|
37 |
+
'model': config.model_name,
|
38 |
+
'temperature': config.temperature,
|
39 |
+
'max_tokens': config.max_tokens,
|
40 |
+
'api_key': os.getenv('ANTHROPIC_API_KEY')
|
41 |
+
}
|
42 |
+
base_url = os.getenv('ANTHROPIC_BASE_URL')
|
43 |
+
if base_url:
|
44 |
+
anthropic_kwargs['base_url'] = base_url
|
45 |
+
|
46 |
+
return ChatAnthropic(**anthropic_kwargs)
|
47 |
elif config.provider == 'google':
|
48 |
+
google_kwargs = {
|
49 |
+
'model': config.model_name,
|
50 |
+
'temperature': config.temperature,
|
51 |
+
'max_output_tokens': config.max_tokens,
|
52 |
+
'google_api_key': os.getenv('GOOGLE_API_KEY')
|
53 |
+
}
|
54 |
+
base_url = os.getenv('GOOGLE_BASE_URL')
|
55 |
+
if base_url:
|
56 |
+
google_kwargs['base_url'] = base_url
|
57 |
+
|
58 |
+
return ChatGoogleGenerativeAI(**google_kwargs)
|
59 |
else:
|
60 |
raise ValueError(f"unsupported provider: {config.provider}")
|
61 |
|