qwqcc commited on
Commit
34a45ef
·
verified ·
1 Parent(s): a7eca70

Upload 4 files

Browse files
Files changed (1) hide show
  1. bootstrap.py +98 -9
bootstrap.py CHANGED
@@ -1,4 +1,5 @@
1
  import os
 
2
  import importlib
3
  from pathlib import Path
4
 
@@ -79,19 +80,26 @@ def _openai_translate(text: str, lang_from: str = "auto", lang_to: str = "zh") -
79
 
80
  url = base_url.rstrip("/") + "/chat/completions"
81
  headers = {"Authorization": f"Bearer {api_key}", "Content-Type": "application/json"}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
82
  payload = {
83
  "model": model,
84
  "temperature": 0,
85
  "messages": [
86
- {
87
- "role": "system",
88
- "content": (
89
- "You are a professional translation engine. "
90
- f"Translate the user text to {target_lang}. "
91
- "Only output the translated text without any extra words, quotes, or explanations. "
92
- "Preserve numbers, emoji, and links."
93
- ),
94
- },
95
  {"role": "user", "content": text},
96
  ],
97
  }
@@ -109,6 +117,33 @@ def _openai_translate(text: str, lang_from: str = "auto", lang_to: str = "zh") -
109
  if not content:
110
  raise MemeFeedback("OpenAI 翻译失败:空结果")
111
  result = str(content).strip()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
112
  print(f"[translate/openai] success result_len={len(result)}", flush=True)
113
  return result
114
  except Exception as e:
@@ -165,6 +200,60 @@ def render_list(params: RenderMemeListRequest = RenderMemeListRequest()):
165
  from fastapi import Response
166
  return Response(content=content, media_type=media_type)
167
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
168
  # Load contrib + emoji
169
  load_memes("/app/meme-generator-contrib/memes")
170
  load_memes("/app/meme_emoji/emoji")
 
1
  import os
2
+ import re
3
  import importlib
4
  from pathlib import Path
5
 
 
80
 
81
  url = base_url.rstrip("/") + "/chat/completions"
82
  headers = {"Authorization": f"Bearer {api_key}", "Content-Type": "application/json"}
83
+ # Build a stronger instruction, especially for Japanese output
84
+ extra_rules = ""
85
+ if target_lang.lower().startswith("japan"):
86
+ extra_rules = (
87
+ " Use natural Japanese. Prefer including hiragana/katakana (kana) where appropriate; "
88
+ "do not just output Chinese hanzi. If the input is Chinese, do not return the same text."
89
+ )
90
+
91
+ system_prompt = (
92
+ "You are a professional translation engine."
93
+ f" Translate the user text to {target_lang}."
94
+ " Only output the translated text without any extra words, quotes, or explanations."
95
+ " Preserve numbers, emoji, and links." + extra_rules
96
+ )
97
+
98
  payload = {
99
  "model": model,
100
  "temperature": 0,
101
  "messages": [
102
+ {"role": "system", "content": system_prompt},
 
 
 
 
 
 
 
 
103
  {"role": "user", "content": text},
104
  ],
105
  }
 
117
  if not content:
118
  raise MemeFeedback("OpenAI 翻译失败:空结果")
119
  result = str(content).strip()
120
+ # If target is Japanese but no kana detected, attempt a single retry with stricter rule
121
+ def has_kana(s: str) -> bool:
122
+ return bool(re.search(r"[\u3040-\u30FF]", s))
123
+
124
+ if target_lang.lower().startswith("japan") and not has_kana(result):
125
+ print("[translate/openai] no kana detected, retrying with stricter Japanese rule", flush=True)
126
+ strict_prompt = (
127
+ system_prompt
128
+ + " Ensure the output contains kana (hiragana or katakana) and is not identical to the input."
129
+ )
130
+ payload_retry = {
131
+ "model": model,
132
+ "temperature": 0,
133
+ "messages": [
134
+ {"role": "system", "content": strict_prompt},
135
+ {"role": "user", "content": text},
136
+ ],
137
+ }
138
+ r2 = httpx.post(url, headers=headers, json=payload_retry, timeout=60)
139
+ print(f"[translate/openai] retry response status={r2.status_code}", flush=True)
140
+ r2.raise_for_status()
141
+ data2 = r2.json()
142
+ choices2 = data2.get("choices") or []
143
+ result2 = (choices2[0].get("message", {}).get("content") or "").strip() if choices2 else ""
144
+ if result2:
145
+ print(f"[translate/openai] retry success result_len={len(result2)}", flush=True)
146
+ return result2
147
  print(f"[translate/openai] success result_len={len(result)}", flush=True)
148
  return result
149
  except Exception as e:
 
200
  from fastapi import Response
201
  return Response(content=content, media_type=media_type)
202
 
203
+ # Dynamic infos.json and keyMap.json derived from loaded memes (not aggregated assets)
204
+ from collections import OrderedDict
205
+ from meme_generator.app import MemeInfoResponse, MemeParamsResponse
206
+
207
+ def build_infos_and_keymap():
208
+ infos = {}
209
+ pairs = [] # (keyword, meme_key)
210
+ for meme in sorted(get_memes(), key=lambda m: m.key):
211
+ args_type_response = None
212
+ if meme.params_type.args_type:
213
+ args_model = meme.params_type.args_type.args_model
214
+ args_type_response = {
215
+ "args_model": args_model.model_json_schema() if hasattr(args_model, "model_json_schema") else {},
216
+ "args_examples": [
217
+ getattr(x, "model_dump", lambda: x)() if hasattr(x, "model_dump") else x
218
+ for x in meme.params_type.args_type.args_examples
219
+ ],
220
+ "parser_options": meme.params_type.args_type.parser_options,
221
+ }
222
+ infos[meme.key] = {
223
+ "key": meme.key,
224
+ "params_type": {
225
+ "min_images": meme.params_type.min_images,
226
+ "max_images": meme.params_type.max_images,
227
+ "min_texts": meme.params_type.min_texts,
228
+ "max_texts": meme.params_type.max_texts,
229
+ "default_texts": meme.params_type.default_texts,
230
+ "args_type": args_type_response,
231
+ },
232
+ "keywords": meme.keywords,
233
+ "shortcuts": meme.shortcuts,
234
+ "tags": list(meme.tags),
235
+ "date_created": meme.date_created,
236
+ "date_modified": meme.date_modified,
237
+ }
238
+ for kw in meme.keywords:
239
+ pairs.append((kw, meme.key))
240
+
241
+ keymap = OrderedDict()
242
+ for kw, key in sorted(pairs, key=lambda x: len(x[0]), reverse=True):
243
+ if kw not in keymap:
244
+ keymap[kw] = key
245
+ return infos, keymap
246
+
247
+ @app.get("/memes/static/infos.json")
248
+ def infos_json():
249
+ infos, _ = build_infos_and_keymap()
250
+ return infos
251
+
252
+ @app.get("/memes/static/keyMap.json")
253
+ def keymap_json():
254
+ _, keymap = build_infos_and_keymap()
255
+ return keymap
256
+
257
  # Load contrib + emoji
258
  load_memes("/app/meme-generator-contrib/memes")
259
  load_memes("/app/meme_emoji/emoji")