-
Notifications
You must be signed in to change notification settings - Fork 2
添加情感分析prompt/类(暂未集成) #6
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,105 @@ | ||
| import re | ||
| import json | ||
| from enum import Enum | ||
|
|
||
| from astrbot.api import logger | ||
| from ..provider.llm.openai_source import ProviderOpenAI | ||
| from ..util.prompts import EMOTION_ANALYSIS_PROMPT | ||
|
|
||
|
|
||
| class EmotionTendency(Enum): | ||
| """情绪倾向枚举""" | ||
|
|
||
| POSITIVE = "positive" | ||
| """积极""" | ||
| NEGATIVE = "negative" | ||
| """消极""" | ||
| NEUTRAL = "neutral" | ||
| """中性""" | ||
|
|
||
|
|
||
| class Emotion(Enum): | ||
| """情绪枚举""" | ||
|
|
||
| JOY = "joy" | ||
| """喜悦""" | ||
| CONTENTMENT = "contentment" | ||
| """满足""" | ||
| SURPRISE = "surprise" | ||
| """惊讶""" | ||
| NEUTRAL = "neutral" | ||
| """中性""" | ||
| FEAR = "fear" | ||
| """恐惧""" | ||
| SADNESS = "sadness" | ||
| """悲伤""" | ||
| ANGER = "anger" | ||
| """愤怒""" | ||
| DISGUST = "disgust" | ||
| """厌恶""" | ||
| PANIC = "panic" | ||
| """恐慌""" | ||
|
|
||
| @property | ||
| def tendency(self) -> EmotionTendency: | ||
| """获取情绪倾向: POSITIVE(积极), NEGATIVE(消极), NEUTRAL(中性)""" | ||
| positive = {Emotion.JOY, Emotion.CONTENTMENT} | ||
| negative = { | ||
| Emotion.FEAR, | ||
| Emotion.SADNESS, | ||
| Emotion.ANGER, | ||
| Emotion.DISGUST, | ||
| Emotion.PANIC, | ||
| } | ||
|
|
||
| if self in positive: | ||
| return EmotionTendency.POSITIVE | ||
| elif self in negative: | ||
| return EmotionTendency.NEGATIVE | ||
| return EmotionTendency.NEUTRAL | ||
|
|
||
| @property | ||
| def prompt(self) -> str: | ||
| """返回情绪提示""" | ||
| return f"Your current emotion is {self.value}. The output should reflect this emotion. If there is an emotional shift, ensure the transition is natural to simulate human emotional changes." | ||
|
|
||
|
|
||
| class EmotionAnalysis: | ||
| """情绪分析类""" | ||
|
|
||
| def __init__(self, provider: ProviderOpenAI): | ||
| self.provider = provider | ||
|
|
||
| async def analyze(self, text: dict) -> dict | None: | ||
| """分析文本情绪""" | ||
| sys_prompt = EMOTION_ANALYSIS_PROMPT.format(Emotion=Emotion) | ||
| res = await self.provider.text_chat( | ||
| system_prompt=sys_prompt, | ||
| prompt=json.dumps(text), | ||
| ) | ||
|
|
||
| try: | ||
| json_pattern = r"```(?:json)?\s*([\s\S]*?)\s*```" | ||
| matches = re.findall(json_pattern, res.completion_text) | ||
|
|
||
| if matches: | ||
| json_content = matches[0] | ||
| else: | ||
| json_content = ( | ||
| res.completion_text.replace("```json", "") | ||
| .replace("```", "") | ||
| .strip() | ||
| ) | ||
|
|
||
| cleaned_content = json_content.replace("{{", "{").replace("}}", "}").strip() | ||
| resp = json.loads(cleaned_content) | ||
|
|
||
| return resp | ||
|
|
||
| except json.JSONDecodeError as e: | ||
| logger.error(f"JSON parsing error: {e!s}") | ||
| logger.error(f"Failed content: {cleaned_content}") | ||
| return None | ||
| except Exception as e: | ||
| logger.error(f"Unexpected error in emotion analysis: {e!s}") | ||
| return None | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -151,3 +151,60 @@ | |
| ``` | ||
|
|
||
| - You should use `USER_ID` as the source or target content for any self-references (e.g., "I", "me", "my" etc.) in user messages.""" | ||
|
|
||
| EMOTION_ANALYSIS_PROMPT = """ | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. issue (complexity): Consider moving the large prompt into a separate file and loading it dynamically to keep prompts.py concise and maintainable. 考虑将这个大的提示移动到一个单独的文件中,或者将它分解成更小的常量,这样`prompts.py`就可以保持简洁和可维护性。例如:
1) 将文字提示移动到`prompts/emotion_analysis.txt`中:
├── prompts/
│ ├── __init__.py
│ └── emotion_analysis.txt ← 你的50行模板
2) 在`prompts.py`中,在运行时加载它:
```python
import os
_TEMPLATE_PATH = os.path.join(
os.path.dirname(__file__),
"prompts",
"emotion_analysis.txt",
)
with open(_TEMPLATE_PATH, "r", encoding="utf-8") as _f:
EMOTION_ANALYSIS_PROMPT = _f.read()
这使得逻辑在您的代码中,而大型模板在它自己的文件中,以便于维护。 Original comment in Englishissue (complexity): Consider moving the large prompt into a separate file and loading it dynamically to keep prompts.py concise and maintainable. Consider extracting this big prompt into a separate file (or breaking it into smaller constants) so `prompts.py` stays concise. For example:
1) Move the literal prompt into `prompts/emotion_analysis.txt`:
├── prompts/
│ ├── __init__.py
│ └── emotion_analysis.txt ← your 50-line template
2) In `prompts.py`, load it at runtime:
```python
import os
_TEMPLATE_PATH = os.path.join(
os.path.dirname(__file__),
"prompts",
"emotion_analysis.txt",
)
with open(_TEMPLATE_PATH, "r", encoding="utf-8") as _f:
EMOTION_ANALYSIS_PROMPT = _f.read()
This keeps the logic in your code and the large template in its own file for easier maintenance. |
||
| You are an advanced sentiment analysis AI, specializing in persona-driven emotion detection. | ||
|
|
||
| You will be given: | ||
| 1. A JSON object with: | ||
| - "text": "the immediate text to analyze (latest message)" | ||
| - "personality": "string describing the persona's personality traits" | ||
| - "context": "previous conversation history (for reference only, to understand the nuance of the current text)" | ||
|
|
||
| ## Your Task | ||
| 1. **Analyze the "text" to determine the speaker's true emotional state**, focusing primarily on the explicit content. | ||
| 2. **Deeply consider the persona's traits**: How would this persona typically express or mask emotions? How do their personality, habits, or background influence their emotional expression? | ||
| 3. Use **context** (recent conversation, situation) only to clarify ambiguous or implicit emotions, or to resolve sarcasm/irony. | ||
| 4. Select from these emotions: {[e.value for e in Emotion]} | ||
| 5. Determine intensity ranging from [-1, 1] | ||
|
|
||
| ## Output Format | ||
| ```json | ||
| {{ | ||
| "emotion": "<emotion_name>", | ||
| "intensity": <float> | ||
| }} | ||
| ``` | ||
|
|
||
| ## Analysis Priority | ||
| 1. **Text Analysis (Primary Focus):** | ||
| - What emotion does the speaker actually express in this text? | ||
| - Emotional vocabulary, tone, punctuation, emojis, and markers. | ||
| - Intensity and clarity of emotional expression. | ||
|
|
||
| 2. **Persona Consideration (Secondary, but Critical):** | ||
| - How does the persona's character shape their emotional display? | ||
| - Would this persona exaggerate, suppress, or distort certain emotions? | ||
| - Adjust your judgment based on persona's typical emotional baseline and expression style. | ||
|
|
||
| 3. **Context Reference (Tertiary):** | ||
| - Use only to clarify ambiguous, sarcastic, or context-dependent emotions. | ||
| - Reference recent conversation or situation if it changes the meaning of the text. | ||
|
|
||
| ## Guidelines | ||
| 1. **Emotion Selection:** | ||
| - Choose from: {[e.value for e in Emotion]} | ||
| - Focus on the dominant, most likely emotion the speaker is experiencing. | ||
| - Only use "neutral" if the text is truly emotionless or ambiguous. | ||
|
|
||
| 2. **Intensity Calculation:** | ||
| - Consider word choice, expression strength, and emotional markers. | ||
| - Adjust for persona's typical emotional range and expression habits. | ||
| - Use context only if it clearly amplifies or dampens the emotion. | ||
|
|
||
| 3. **Principles:** | ||
| - Prioritize evidence from the text itself. | ||
| - Let persona traits guide your interpretation of ambiguous or subtle emotions. | ||
| - Use context to resolve uncertainty, not as the main basis. | ||
| - Be objective and avoid over-interpretation. | ||
| """ | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
suggestion (performance): Recreating emotion sets on each access
将
positive和negative移动到类级别的常量(例如POSITIVE_SET = frozenset([...])),以避免在每次属性访问时重新分配它们并简化方法。Original comment in English
suggestion (performance): Recreating emotion sets on each access
Move
positiveandnegativeto class-level constants (e.g.POSITIVE_SET = frozenset([...])) to avoid reallocating them on each property access and simplify the method.