File size: 8,043 Bytes
5e16504
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
import json
# 外部モジュールのインポートをシミュレート (実際には適切な方法でインポートが必要)
# from model_initializer import initialize_tone_classifier, initialize_star_classifier
# from tone_analyzer import analyze_tone
# from star_checker import check_star_suitability

# NOTE: 実行環境の制約上、ここでは前のファイルの内容を直接関数として再定義し、
# 外部モジュールとして動作していることをシミュレーションします。

# --- 1. model_initializer.py からの関数 (ここでは再定義) ---
import torch
from transformers import pipeline, AutoModelForSequenceClassification, AutoTokenizer

def initialize_tone_classifier():
    TONE_MODEL_NAME = "cl-tohoku/bert-base-japanese-whole-word-masking"
    try:
        tone_classifier = pipeline(
            "sentiment-analysis",
            model="cl-tohoku/bert-base-japanese-whole-word-masking", 
            tokenizer="cl-tohoku/bert-base-japanese-whole-word-masking"
        )
        return tone_classifier
    except Exception:
        classifier = pipeline(
            "text-classification",
            model=AutoModelForSequenceClassification.from_pretrained(TONE_MODEL_NAME),
            tokenizer=AutoTokenizer.from_pretrained(TONE_MODEL_NAME),
            id2label={0: "Negative", 1: "Positive"}
        )
        return classifier

def initialize_star_classifier():
    try:
        star_classifier = pipeline(
            "zero-shot-classification",
            model="izumi-lab/bert-base-japanese-v2", 
            tokenizer="izumi-lab/bert-base-japanese-v2",
            device=0 if torch.cuda.is_available() else -1
        )
        return star_classifier
    except Exception:
        star_classifier = pipeline(
            "zero-shot-classification",
            model="cl-tohoku/bert-base-japanese-whole-word-masking",
            tokenizer="cl-tohoku/bert-base-japanese-whole-word-masking",
            device=0 if torch.cuda.is_available() else -1
        )
        return star_classifier

# --- 2. tone_analyzer.py からの関数 (ここでは再定義) ---
def analyze_tone(text, tone_classifier):
    results = tone_classifier(text)
    result = results[0]
    sentiment_label = result['label']
    sentiment_score = result['score']
    enthusiasm_score = round(sentiment_score * 100, 2)
    return {
        "label": sentiment_label,
        "raw_score": sentiment_score,
        "enthusiasm_score": enthusiasm_score
    }

# --- 3. star_checker.py からの関数 (ここでは再定義) ---
def check_star_suitability(self_pr_text, star_classifier):
    candidate_labels = ["状況 (Situation)", "課題 (Task)", "行動 (Action)", "結果 (Result)"]
    star_results = star_classifier(
        self_pr_text, 
        candidate_labels, 
        multi_label=True
    )
    star_scores = {label: round(score * 100, 2) for label, score in zip(star_results['labels'], star_results['scores'])}
    
    insufficiency_threshold = 70.0 
    missing_elements = []
    total_score = 0
    for label, score in star_scores.items():
        total_score += score
        if score < insufficiency_threshold:
            missing_elements.append(label)

    suitability_score = round(total_score / len(candidate_labels), 2)
    
    analysis_reason = {
        "suitability_score": suitability_score,
        "is_logical": suitability_score >= 75.0,
        "reason_code": "LOGICAL_STRUCTURE_GOOD" if not missing_elements else "ELEMENTS_MISSING",
        "missing_elements": missing_elements,
        "detail_scores": star_scores
    }

    return {
        "suitability_score": suitability_score,
        "analysis_json": analysis_reason
    }
# --- ここまでシミュレーションのための再定義 ---


def process_es_data(es_text, self_pr_text, tone_classifier, star_classifier):
    """
    ES全体のデータを受け取り、感情・トーン分析とSTAR適合度チェックを実行するメイン関数。
    """
    print("=========================================")
    print("🚀 新卒ES 自動評価パイプライン開始")
    print("=========================================")

    # 1. 感情・トーン分析
    print("\n--- 1. 感情・トーン分析の実行 ---")
    tone_analysis = analyze_tone(es_text, tone_classifier)
    print(f"熱意・トーン分析結果 (ポジティブ度): {tone_analysis['enthusiasm_score']} %")
    print(f"判定ラベル: {tone_analysis['label']}")
    
    # 2. STAR法適合度チェック
    print("\n--- 2. STAR法適合度チェックの実行 ---")
    star_analysis = check_star_suitability(self_pr_text, star_classifier)
    print(f"STAR法 総合適合度スコア: {star_analysis['suitability_score']} %")
    print(f"論理構造分析JSON (不足要素など):")
    print(json.dumps(star_analysis['analysis_json'], indent=4, ensure_ascii=False))
    
    # 最終スコアの統合(例: 感情スコア 50%, STARスコア 50% の重み付け)
    final_potential_score = (tone_analysis['enthusiasm_score'] * 0.5) + (star_analysis['suitability_score'] * 0.5)
    
    print("\n=========================================")
    print(f"✨ 最終ポテンシャル評価スコア (統合): {round(final_potential_score, 2)} / 100")
    print("=========================================")

    return {
        "final_score": round(final_potential_score, 2),
        "tone_analysis": tone_analysis,
        "star_analysis": star_analysis
    }


if __name__ == '__main__':
    # 1. モデルの初期化
    print("Hugging Face パイプラインの初期化を開始します...")
    tc = initialize_tone_classifier()
    sc = initialize_star_classifier()
    
    # 2. 実行例
    # 実際のESテキスト(全体)
    es_full_text = """
    貴社が推進する「グローバル×ローカル」のデジタル変革戦略に深く共感し、志望いたしました。私は大学時代、学園祭の実行委員長として、従来の集客方法に課題を感じ、SNSを活用した新しいプロモーション戦略を立案・実行しました。これにより、来場者数を前年比150%に増加させるという明確な結果を出しました。この経験から学んだ、現状を打破するための課題設定力と、関係者を巻き込む実行力を貴社で活かし、世界中の顧客に感動を届けるシステムを構築したいと強く願っています。
    """

    # STAR法チェックの対象となる自己PRセクション
    self_pr_text_star_focus = """
    私は大学時代、学園祭の実行委員長として、従来の集客方法に課題を感じ、SNSを活用した新しいプロモーション戦略を立案・実行しました。これにより、来場者数を前年比150%に増加させるという明確な結果を出しました。課題はSNSチームのメンバーのモチベーション管理でしたが、個別の面談を通じて主体的な関与を引き出し、最終的に全員が目標達成に貢献しました。
    """
    
    # ESデータの処理を実行
    results = process_es_data(es_full_text, self_pr_text_star_focus, tc, sc)
    
    # 例: 不足要素がある場合のシミュレーション (結果が弱いES)
    print("\n\n--- 不足要素がある場合のシミュレーション (結果が弱いES) ---")
    weak_result_es = """
    私はチームプロジェクトでリーダーシップを発揮しました(Action)。当初、目標達成が難しい状況(Situation)でしたが、諦めずにメンバーと協力し、最後までやり遂げました(Task)。結果、多くのことを学び、成長できました。
    """
    
    weak_results = check_star_suitability(weak_result_es, sc)
    print("STAR法 総合適合度スコア:", weak_results['suitability_score'], "%")
    print("論理構造分析JSON (結果が弱いES):")
    print(json.dumps(weak_results['analysis_json'], indent=4, ensure_ascii=False))