DataOperation commited on
Commit
055962d
·
verified ·
1 Parent(s): f8e4295

1110수정ver일본어탭-로마자 (#10)

Browse files

- 1110수정ver일본어탭-로마자 (085e5d8942789440f16915f42b05fa82b150a417)

Files changed (2) hide show
  1. app.py +121 -18
  2. requirements.txt +3 -1
app.py CHANGED
@@ -288,6 +288,11 @@ jp_common_rules = """
288
  東国製薬(동국제약):ヒガシコクセイヤク(히가시코쿠세이야쿠-한자의 일본발음)トンクック製薬(통쿡쿠제약)
289
  """
290
 
 
 
 
 
 
291
  def get_jp_synonyms_formatted(category, word, official_eng=None, use_gpt=True, model="gpt-4o-mini", api_key=None, temperature=0.3, sleep_sec=1):
292
  jp_main = jp_syn = eng_syn = comment = ""
293
 
@@ -299,8 +304,109 @@ def get_jp_synonyms_formatted(category, word, official_eng=None, use_gpt=True, m
299
  import re
300
  is_japanese_input = bool(re.search(r'[\u3040-\u309F\u30A0-\u30FF]', word)) and not has_jp_notation
301
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
302
 
303
- # 카테고리별 프롬프트
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
304
  prompts = {
305
  "브랜드": f"""너는 한국어/일본어/영어 패션 브랜드 동의어 전문가야. '{word}'라는 브랜드 이름의 동의어를 최대한 정확하게 찾아서 정리해줘.
306
  {"⚠️ 중요: 입력에 '일문 표기'가 포함되어 있습니다. 이 일문 표기를 참고하여 동의어를 생성해주세요." if has_jp_notation else ""}
@@ -316,7 +422,6 @@ def get_jp_synonyms_formatted(category, word, official_eng=None, use_gpt=True, m
316
  f"(의미 번역 금지, 실제 브랜드의 음차 표기만 허용)"
317
  }
318
 
319
-
320
  - 동의어(일문): 브랜드 관련 일본어 동의어, 없으면 비워두기, 중복 제거, ex.마르디 메크르디 - 마르디 매크르디,마르디 (Typing 변경 관점)
321
  {f" * 참고: 제공된 일문 표기를 동의어 생성 시 참고하되, 동의어에 포함시키지 마세요" if has_jp_notation else ""}
322
  - 동의어(영문): '{word.split('(')[0].strip() if has_jp_notation else word}'의 영어 공식명 기반 최대 3개
@@ -334,7 +439,6 @@ def get_jp_synonyms_formatted(category, word, official_eng=None, use_gpt=True, m
334
  동의어(영문): word1|word2|word3
335
  생성 이유: (대표키워드와 동의어를 이렇게 정한 간단한 이유 1문장)""",
336
 
337
-
338
  "카테고리": f"""너는 한국어/일본어/영어 패션 카테고리 동의어 전문가야. '{word}' 카테고리 관련 동의어를 최대한 정확하게 찾아서 정리해줘.
339
  {"⚠️ 중요: 입력에 '일문 표기'가 포함되어 있습니다. 이 일문 표기를 참고하여 동의어를 생성해주세요." if has_jp_notation else ""}
340
  {"⚠️ 중요: 입력이 일본어입니다. 대표키워드(일문)는 '{word}'를 그대로 사용하고, 동의어만 생성해주세요." if is_japanese_input else ""}
@@ -436,18 +540,12 @@ def get_jp_synonyms_formatted(category, word, official_eng=None, use_gpt=True, m
436
  생성 이유: (대표키워드와 동의어를 이렇게 정한 간단한 이유 1문장)"""
437
  }
438
 
439
-
440
  prompt = prompts.get(category, f"'{word}' 단어의 동의어를 찾아 대표키워드, 일본어 동의어, 영어 동의어를 알려줘.")
441
 
442
  # 공식 영문명이 있으면 프롬프트 수정
443
  if official_eng:
444
  prompt += f" 영어 동의어는 반드시 '{official_eng}' 공식 영문명을 기준으로 정확히 3개까지만 제시해줘."
445
 
446
- # try:
447
- # response = openai.chat.completions.create(
448
- # model="gpt-5-mini",
449
- # messages=[{"role": "user", "content": prompt}]
450
- # )
451
  try:
452
  completion = generate_with_model(
453
  model_choice=model,
@@ -457,33 +555,30 @@ def get_jp_synonyms_formatted(category, word, official_eng=None, use_gpt=True, m
457
  )
458
  time.sleep(sleep_sec)
459
 
460
-
461
  for line in completion.splitlines():
462
  if line.startswith("대표키워드(일문):"):
463
  raw_main = line.split(":", 1)[1].strip()
464
- # | 로 구분된 경우 첫 번째 값만 사용
465
  jp_main = raw_main.split("|")[0].strip()
466
  elif line.startswith("동의어(일문):"):
467
  jp_syn = line.split(":", 1)[1].strip()
468
  elif line.startswith("동의어(영문):"):
469
  raw_eng = line.split(":", 1)[1].strip()
470
- # ✅ 영문 동의어 후처리: 소문자 변환 + 공백 제거
471
  eng_list = [x.strip().lower().replace(" ", "") for x in raw_eng.split("|") if x.strip()]
472
  eng_syn = "|".join(eng_list)
473
  elif line.lower().startswith("생성 이유") or line.lower().startswith("comment"):
474
  comment = line.split(":", 1)[1].strip()
475
- # ✅ 중복 제거 로직 추가
 
476
  if jp_main and jp_syn:
477
  jp_main_norm = normalize_word(jp_main)
478
  jp_syn_list = [x.strip() for x in jp_syn.split("|") if x.strip()]
479
- # 대표키워드와 중복 제거 + 동의어 내부 중복 제거
480
  jp_syn_list = [x for x in jp_syn_list if normalize_word(x) != jp_main_norm]
481
- jp_syn_list = list(dict.fromkeys(jp_syn_list)) # 순서 유지하며 중복 제거
482
  jp_syn = "|".join(jp_syn_list)
483
 
484
  if eng_syn:
485
  eng_syn_list = [x.strip().lower().replace(" ", "") for x in eng_syn.split("|") if x.strip()]
486
- eng_syn_list = list(dict.fromkeys(eng_syn_list)) # 중복 제거
487
  eng_syn = "|".join(eng_syn_list)
488
 
489
  except Exception as e:
@@ -494,19 +589,27 @@ def get_jp_synonyms_formatted(category, word, official_eng=None, use_gpt=True, m
494
  if not text:
495
  return ""
496
  text = text.strip()
497
- # なし, N/A, None, - 등을 빈 문자열로 처리
498
  if text.lower() in ["なし", "n/a", "none", "-", "없음"]:
499
  return ""
500
  return text
501
 
502
- # ✅ 항상 4개 반환 (비정상일 때도 안전)
503
  return (
504
  clean_none_value(jp_main),
505
  clean_none_value(jp_syn),
506
  clean_none_value(eng_syn),
507
  clean_none_value(comment)
508
  )
 
 
 
509
 
 
 
 
 
 
 
 
510
 
511
  # -------------------------------
512
  # GPT 기반 한국어 동의어 조회 (공식 영문명 지원)
 
288
  東国製薬(동국제약):ヒガシコクセイヤク(히가시코쿠세이야쿠-한자의 일본발음)トンクック製薬(통쿡쿠제약)
289
  """
290
 
291
+ # 상단 import 섹션에 추가
292
+ from hangul_romanize import Transliter
293
+ from hangul_romanize.rule import academic
294
+
295
+
296
  def get_jp_synonyms_formatted(category, word, official_eng=None, use_gpt=True, model="gpt-4o-mini", api_key=None, temperature=0.3, sleep_sec=1):
297
  jp_main = jp_syn = eng_syn = comment = ""
298
 
 
304
  import re
305
  is_japanese_input = bool(re.search(r'[\u3040-\u309F\u30A0-\u30FF]', word)) and not has_jp_notation
306
 
307
+ # ========================================
308
+ # 🆕 신규 로직: 국문만 입력 + 브랜드일 시 표준 로마자 변환!
309
+ # ========================================
310
+ if not has_jp_notation and not is_japanese_input and category == "브랜드":
311
+ try:
312
+ # Step 1: 한글 → 표준 로마자 변환
313
+ transliter = Transliter(academic)
314
+ romanized = transliter.translit(word)
315
+
316
+ # 각 단어별 첫 글자 대문자 변환
317
+ romanized_title = ' '.join([w.capitalize() for w in romanized.split()])
318
+
319
+ # Step 2: 표준 로마자 기반 프롬프트
320
+ prompt = f"""너는 일본어 가타카나 변환 전문가야.
321
+
322
+
323
+ 브랜드명(한글): {word}
324
+ 로마자 표기: {romanized_title}
325
+
326
+ 위 로마자 발음을 정확히 기준으로:
327
+ 1. 일본어 가타카나 대표키워드 1개 생성 (로마자 발음 그대로!)
328
+ 2. 발음 변형 동의어 생성 (히라가나, 장음/촉음 변형 등)
329
+ 3. 영문 동의어는 '{romanized_title}' 기준 소문자/공백제거 변형만
330
+
331
+ {jp_common_rules}
332
+
333
+ ⚠️ 중요 규칙:
334
+ - 대표키워드: {word}
335
+ - 대표키워드(일문)는 '{romanized_title}' 발음을 정확히 따를 것
336
+ - 의미 번역 절대 금지, 음차 표기만!
337
+ - 동의어에는 대표키워드와 동일한 단어 포함 금지
338
+ - 동의어 목록 내 중복 제거
339
 
340
+ 출력 형식:
341
+ 대표키워드: {word}
342
+ 대표키워드(일문): [가타카나]
343
+ 동의어(일문): [가타카나1|가타카나2]
344
+ 동의어(영문): [eng1|eng2]
345
+ 생성 이유: {romanized_title} 표준 로마자 철자 기반 생성"""
346
+
347
+ result = generate_with_model(
348
+ model_choice=model,
349
+ api_key=api_key,
350
+ prompt=prompt,
351
+ temperature=temperature
352
+ )
353
+
354
+ time.sleep(sleep_sec)
355
+
356
+ # 파싱
357
+ for line in result.splitlines():
358
+ if line.startswith("대표키워드(일문):"):
359
+ raw_main = line.split(":", 1)[1].strip()
360
+ jp_main = raw_main.split("|")[0].strip()
361
+ elif line.startswith("동의어(일문):"):
362
+ jp_syn = line.split(":", 1)[1].strip()
363
+ elif line.startswith("동의어(영문):"):
364
+ raw_eng = line.split(":", 1)[1].strip()
365
+ eng_list = [x.strip().lower().replace(" ", "") for x in raw_eng.split("|") if x.strip()]
366
+ eng_syn = "|".join(eng_list)
367
+ elif line.lower().startswith("생성 이유"):
368
+ comment = line.split(":", 1)[1].strip()
369
+
370
+ # 로마자 정보 추가
371
+ comment = f"🔤 {romanized_title} → {comment}" if comment else f"🔤 로마자 기반: {romanized_title}"
372
+
373
+ # ✅ 중복 제거
374
+ if jp_main and jp_syn:
375
+ jp_main_norm = normalize_word(jp_main)
376
+ jp_syn_list = [x.strip() for x in jp_syn.split("|") if x.strip()]
377
+ jp_syn_list = [x for x in jp_syn_list if normalize_word(x) != jp_main_norm]
378
+ jp_syn_list = list(dict.fromkeys(jp_syn_list))
379
+ jp_syn = "|".join(jp_syn_list)
380
+
381
+ if eng_syn:
382
+ eng_syn_list = [x.strip().lower().replace(" ", "") for x in eng_syn.split("|") if x.strip()]
383
+ eng_syn_list = list(dict.fromkeys(eng_syn_list))
384
+ eng_syn = "|".join(eng_syn_list)
385
+
386
+ # ✅ なし, N/A 처리
387
+ def clean_none_value(text):
388
+ if not text:
389
+ return ""
390
+ text = text.strip()
391
+ if text.lower() in ["なし", "n/a", "none", "-", "없음"]:
392
+ return ""
393
+ return text
394
+
395
+ return (
396
+ clean_none_value(jp_main),
397
+ clean_none_value(jp_syn),
398
+ clean_none_value(eng_syn),
399
+ clean_none_value(comment)
400
+ )
401
+
402
+ except Exception as e:
403
+ comment = f"⚠️ 로마자 변환 실패: {str(e)}"
404
+ # 실패하면 기존 로직으로 폴백
405
+
406
+ # ========================================
407
+ # 기존 로직 (일문 입력, 국문+일문, 카테고리/색상/속성/일반)
408
+ # ========================================
409
+ # 카테고리별 프롬프트
410
  prompts = {
411
  "브랜드": f"""너는 한국어/일본어/영어 패션 브랜드 동의어 전문가야. '{word}'라는 브랜드 이름의 동의어를 최대한 정확하게 찾아서 정리해줘.
412
  {"⚠️ 중요: 입력에 '일문 표기'가 포함되어 있습니다. 이 일문 표기를 참고하여 동의어를 생성해주세요." if has_jp_notation else ""}
 
422
  f"(의미 번역 금지, 실제 브랜드의 음차 표기만 허용)"
423
  }
424
 
 
425
  - 동의어(일문): 브랜드 관련 일본어 동의어, 없으면 비워두기, 중복 제거, ex.마르디 메크르디 - 마르디 매크르디,마르디 (Typing 변경 관점)
426
  {f" * 참고: 제공된 일문 표기를 동의어 생성 시 참고하되, 동의어에 포함시키지 마세요" if has_jp_notation else ""}
427
  - 동의어(영문): '{word.split('(')[0].strip() if has_jp_notation else word}'의 영어 공식명 기반 최대 3개
 
439
  동의어(영문): word1|word2|word3
440
  생성 이유: (대표키워드와 동의어를 이렇게 정한 간단한 이유 1문장)""",
441
 
 
442
  "카테고리": f"""너는 한국어/일본어/영어 패션 카테고리 동의어 전문가야. '{word}' 카테고리 관련 동의어를 최대한 정확하게 찾아서 정리해줘.
443
  {"⚠️ 중요: 입력에 '일문 표기'가 포함되어 있습니다. 이 일문 표기를 참고하여 동의어를 생성해주세요." if has_jp_notation else ""}
444
  {"⚠️ 중요: 입력이 일본어입니다. 대표키워드(일문)는 '{word}'를 그대로 사용하고, 동의어만 생성해주세요." if is_japanese_input else ""}
 
540
  생성 이유: (대표키워드와 동의어를 이렇게 정한 간단한 이유 1문장)"""
541
  }
542
 
 
543
  prompt = prompts.get(category, f"'{word}' 단어의 동의어를 찾아 대표키워드, 일본어 동의어, 영어 동의어를 알려줘.")
544
 
545
  # 공식 영문명이 있으면 프롬프트 수정
546
  if official_eng:
547
  prompt += f" 영어 동의어는 반드시 '{official_eng}' 공식 영문명을 기준으로 정확히 3개까지만 제시해줘."
548
 
 
 
 
 
 
549
  try:
550
  completion = generate_with_model(
551
  model_choice=model,
 
555
  )
556
  time.sleep(sleep_sec)
557
 
 
558
  for line in completion.splitlines():
559
  if line.startswith("대표키워드(일문):"):
560
  raw_main = line.split(":", 1)[1].strip()
 
561
  jp_main = raw_main.split("|")[0].strip()
562
  elif line.startswith("동의어(일문):"):
563
  jp_syn = line.split(":", 1)[1].strip()
564
  elif line.startswith("동의어(영문):"):
565
  raw_eng = line.split(":", 1)[1].strip()
 
566
  eng_list = [x.strip().lower().replace(" ", "") for x in raw_eng.split("|") if x.strip()]
567
  eng_syn = "|".join(eng_list)
568
  elif line.lower().startswith("생성 이유") or line.lower().startswith("comment"):
569
  comment = line.split(":", 1)[1].strip()
570
+
571
+ # ✅ 중복 제거 로직
572
  if jp_main and jp_syn:
573
  jp_main_norm = normalize_word(jp_main)
574
  jp_syn_list = [x.strip() for x in jp_syn.split("|") if x.strip()]
 
575
  jp_syn_list = [x for x in jp_syn_list if normalize_word(x) != jp_main_norm]
576
+ jp_syn_list = list(dict.fromkeys(jp_syn_list))
577
  jp_syn = "|".join(jp_syn_list)
578
 
579
  if eng_syn:
580
  eng_syn_list = [x.strip().lower().replace(" ", "") for x in eng_syn.split("|") if x.strip()]
581
+ eng_syn_list = list(dict.fromkeys(eng_syn_list))
582
  eng_syn = "|".join(eng_syn_list)
583
 
584
  except Exception as e:
 
589
  if not text:
590
  return ""
591
  text = text.strip()
 
592
  if text.lower() in ["なし", "n/a", "none", "-", "없음"]:
593
  return ""
594
  return text
595
 
 
596
  return (
597
  clean_none_value(jp_main),
598
  clean_none_value(jp_syn),
599
  clean_none_value(eng_syn),
600
  clean_none_value(comment)
601
  )
602
+ ```
603
+
604
+ ## 3. 테스트
605
 
606
+ 수정 후 테스트해보세요:
607
+ ```
608
+ 입력: "아크네스튜디오" (분류: 브랜드)
609
+ 예상 결과:
610
+ - 로마자: Akeuneseutyudio
611
+ - 일문: アクネスタジオ
612
+ - Comment: 🔤 Akeuneseutyudio → ...
613
 
614
  # -------------------------------
615
  # GPT 기반 한국어 동의어 조회 (공식 영문명 지원)
requirements.txt CHANGED
@@ -7,4 +7,6 @@ openpyxl
7
  jaconv
8
  pykakasi
9
  rapidfuzz
10
- huggingface_hub
 
 
 
7
  jaconv
8
  pykakasi
9
  rapidfuzz
10
+ huggingface_hub
11
+ korean-romanizer
12
+ hangul-romanize