Spaces:
Running
Running
Update app.py
Browse files
app.py
CHANGED
@@ -563,10 +563,11 @@ class NovelWritingSystem:
|
|
563 |
return full_content
|
564 |
|
565 |
def call_llm_streaming(self, messages: List[Dict[str, str]], role: str, language: str) -> Generator[str, None, None]:
|
566 |
-
"""LLM μ€νΈλ¦¬λ° νΈμΆ (
|
567 |
try:
|
568 |
system_prompts = self.get_system_prompts(language)
|
569 |
full_messages = [{"role": "system", "content": system_prompts.get(role, "You are a helpful assistant.")}, *messages]
|
|
|
570 |
payload = {
|
571 |
"model": self.model_id,
|
572 |
"messages": full_messages,
|
@@ -579,80 +580,114 @@ class NovelWritingSystem:
|
|
579 |
"stream_options": {"include_usage": True}
|
580 |
}
|
581 |
|
582 |
-
logger.info(f"API
|
583 |
-
|
584 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
585 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
586 |
buffer = ""
|
|
|
587 |
chunk_count = 0
|
588 |
-
|
|
|
589 |
for line in response.iter_lines():
|
590 |
-
if line:
|
591 |
-
|
592 |
-
|
593 |
-
|
594 |
-
|
595 |
-
|
596 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
597 |
|
598 |
-
|
599 |
-
|
600 |
-
|
601 |
-
|
602 |
-
|
603 |
-
|
604 |
-
|
605 |
-
|
606 |
-
|
607 |
-
|
608 |
-
|
609 |
-
|
610 |
-
|
611 |
-
if content:
|
612 |
-
buffer += content
|
613 |
-
chunk_count += 1
|
614 |
-
|
615 |
-
# λ²νΌκ° μΆ©λΆν μ°¨κ±°λ μ€λ°κΏμ΄ μμ λ yield
|
616 |
-
if len(buffer) > 100 or "\n" in buffer:
|
617 |
-
yield buffer
|
618 |
-
buffer = ""
|
619 |
-
|
620 |
-
# μλ¬ λ©μμ§ μ²΄ν¬
|
621 |
-
elif chunk.get("error"):
|
622 |
-
error_msg = chunk.get("error", {}).get("message", "Unknown error")
|
623 |
-
logger.error(f"API μλ¬ μλ΅: {error_msg}")
|
624 |
-
yield f"β API μ€λ₯: {error_msg}"
|
625 |
-
return
|
626 |
-
|
627 |
-
except json.JSONDecodeError as e:
|
628 |
-
logger.warning(f"JSON νμ± μ€λ₯: {e}, λ°μ΄ν°: {data[:100]}")
|
629 |
-
continue
|
630 |
-
except Exception as e:
|
631 |
-
logger.error(f"μ²ν¬ μ²λ¦¬ μ€ μμΈ: {e}")
|
632 |
-
continue
|
633 |
|
634 |
-
# λ¨μ λ²νΌ
|
635 |
-
if buffer:
|
636 |
yield buffer
|
637 |
-
|
638 |
-
|
639 |
if chunk_count == 0:
|
640 |
-
logger.error("
|
641 |
-
yield "β API
|
|
|
|
|
642 |
|
643 |
-
except requests.exceptions.
|
644 |
-
logger.error(
|
645 |
-
|
646 |
-
|
647 |
-
|
648 |
-
|
649 |
-
logger.error(f"API μμ² μ€λ₯: {e}")
|
650 |
-
yield f"β API μ€λ₯: {e}"
|
651 |
except Exception as e:
|
652 |
-
logger.error(f"μκΈ°μΉ μμ μ€λ₯: {e}", exc_info=True)
|
653 |
-
yield f"β
|
654 |
-
|
655 |
-
|
|
|
656 |
|
657 |
|
658 |
def get_system_prompts(self, language: str) -> Dict[str, str]:
|
|
|
563 |
return full_content
|
564 |
|
565 |
def call_llm_streaming(self, messages: List[Dict[str, str]], role: str, language: str) -> Generator[str, None, None]:
|
566 |
+
"""LLM μ€νΈλ¦¬λ° νΈμΆ (μμ ν μλ¬ μ²λ¦¬ λ° λλ²κΉ
)"""
|
567 |
try:
|
568 |
system_prompts = self.get_system_prompts(language)
|
569 |
full_messages = [{"role": "system", "content": system_prompts.get(role, "You are a helpful assistant.")}, *messages]
|
570 |
+
|
571 |
payload = {
|
572 |
"model": self.model_id,
|
573 |
"messages": full_messages,
|
|
|
580 |
"stream_options": {"include_usage": True}
|
581 |
}
|
582 |
|
583 |
+
logger.info(f"[{role}] API μ€νΈλ¦¬λ° μμ")
|
584 |
+
|
585 |
+
# API νΈμΆ
|
586 |
+
response = requests.post(
|
587 |
+
self.api_url,
|
588 |
+
headers=self.create_headers(),
|
589 |
+
json=payload,
|
590 |
+
stream=True,
|
591 |
+
timeout=180
|
592 |
+
)
|
593 |
|
594 |
+
# μν μ½λ νμΈ
|
595 |
+
if response.status_code != 200:
|
596 |
+
logger.error(f"API μλ΅ μ€λ₯: {response.status_code}")
|
597 |
+
logger.error(f"μλ΅ λ΄μ©: {response.text[:500]}")
|
598 |
+
yield f"β API μ€λ₯ (μν μ½λ: {response.status_code})"
|
599 |
+
return
|
600 |
+
|
601 |
+
response.raise_for_status()
|
602 |
+
|
603 |
+
# μ€νΈλ¦¬λ° μ²λ¦¬
|
604 |
buffer = ""
|
605 |
+
total_content = ""
|
606 |
chunk_count = 0
|
607 |
+
error_count = 0
|
608 |
+
|
609 |
for line in response.iter_lines():
|
610 |
+
if not line:
|
611 |
+
continue
|
612 |
+
|
613 |
+
try:
|
614 |
+
line_str = line.decode('utf-8').strip()
|
615 |
+
|
616 |
+
# SSE νμ νμΈ
|
617 |
+
if not line_str.startswith("data: "):
|
618 |
+
continue
|
619 |
+
|
620 |
+
data_str = line_str[6:] # "data: " μ κ±°
|
621 |
+
|
622 |
+
# μ€νΈλ¦Ό μ’
λ£ νμΈ
|
623 |
+
if data_str == "[DONE]":
|
624 |
+
logger.info(f"[{role}] μ€νΈλ¦¬λ° μλ£ - μ΄ {len(total_content)} λ¬Έμ")
|
625 |
+
break
|
626 |
+
|
627 |
+
# JSON νμ±
|
628 |
+
try:
|
629 |
+
data = json.loads(data_str)
|
630 |
+
except json.JSONDecodeError:
|
631 |
+
logger.warning(f"JSON νμ± μ€ν¨: {data_str[:100]}")
|
632 |
+
continue
|
633 |
+
|
634 |
+
# choices λ°°μ΄ μμ νκ² νμΈ
|
635 |
+
choices = data.get("choices", None)
|
636 |
+
if not choices or not isinstance(choices, list) or len(choices) == 0:
|
637 |
+
# μλ¬ μλ΅ νμΈ
|
638 |
+
if "error" in data:
|
639 |
+
error_msg = data.get("error", {}).get("message", "Unknown error")
|
640 |
+
logger.error(f"API μλ¬: {error_msg}")
|
641 |
+
yield f"β API μλ¬: {error_msg}"
|
642 |
+
return
|
643 |
+
continue
|
644 |
+
|
645 |
+
# deltaμμ content μΆμΆ
|
646 |
+
delta = choices[0].get("delta", {})
|
647 |
+
content = delta.get("content", "")
|
648 |
+
|
649 |
+
if content:
|
650 |
+
buffer += content
|
651 |
+
total_content += content
|
652 |
+
chunk_count += 1
|
653 |
|
654 |
+
# 100μ λλ μ€λ°κΏλ§λ€ yield
|
655 |
+
if len(buffer) >= 100 or '\n' in buffer:
|
656 |
+
yield buffer
|
657 |
+
buffer = ""
|
658 |
+
time.sleep(0.01) # UI μ
λ°μ΄νΈλ₯Ό μν μ§§μ λκΈ°
|
659 |
+
|
660 |
+
except Exception as e:
|
661 |
+
error_count += 1
|
662 |
+
logger.error(f"μ²ν¬ μ²λ¦¬ μ€λ₯ #{error_count}: {str(e)}")
|
663 |
+
if error_count > 10: # λ무 λ§μ μλ¬μ μ€λ¨
|
664 |
+
yield f"β μ€νΈλ¦¬λ° μ€ κ³Όλν μ€λ₯ λ°μ"
|
665 |
+
return
|
666 |
+
continue
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
667 |
|
668 |
+
# λ¨μ λ²νΌ μ²λ¦¬
|
669 |
+
if buffer:
|
670 |
yield buffer
|
671 |
+
|
672 |
+
# κ²°κ³Ό νμΈ
|
673 |
if chunk_count == 0:
|
674 |
+
logger.error(f"[{role}] μ½ν
μΈ κ° μ ν μμ λμ§ μμ")
|
675 |
+
yield "β APIλ‘λΆν° μλ΅μ λ°μ§ λͺ»νμ΅λλ€."
|
676 |
+
else:
|
677 |
+
logger.info(f"[{role}] μ±κ³΅μ μΌλ‘ {chunk_count}κ° μ²ν¬, μ΄ {len(total_content)}μ μμ ")
|
678 |
|
679 |
+
except requests.exceptions.Timeout:
|
680 |
+
logger.error("API μμ² μκ° μ΄κ³Ό")
|
681 |
+
yield "β API μμ² μκ°μ΄ μ΄κ³Όλμμ΅λλ€."
|
682 |
+
except requests.exceptions.ConnectionError:
|
683 |
+
logger.error("API μ°κ²° μ€ν¨")
|
684 |
+
yield "β API μλ²μ μ°κ²°ν μ μμ΅λλ€."
|
|
|
|
|
685 |
except Exception as e:
|
686 |
+
logger.error(f"μκΈ°μΉ μμ μ€λ₯: {type(e).__name__}: {str(e)}", exc_info=True)
|
687 |
+
yield f"β μ€λ₯ λ°μ: {str(e)}"
|
688 |
+
|
689 |
+
|
690 |
+
|
691 |
|
692 |
|
693 |
def get_system_prompts(self, language: str) -> Dict[str, str]:
|