import os import csv import json import itertools from datetime import datetime from flask import Flask, render_template, request, redirect, url_for, send_file # وارد کردن ماژول‌های پروژه from modules.segmenter import Segmenter from modules.api_handler import APIHandler from modules.data_manager import DataManager from modules.visualizer import Visualizer app = Flask(__name__) # مقداردهی اولیه ماژول‌ها segmenter = Segmenter() api_handler = APIHandler() data_manager = DataManager() visualizer = Visualizer() @app.route('/', methods=['GET']) def index(): """نمایش لیست پروژه‌های قبلی در داشبورد""" projects_dir = data_manager.base_projects_dir projects = [] if os.path.exists(projects_dir): projects = [d for d in os.listdir(projects_dir) if os.path.isdir(os.path.join(projects_dir, d))] projects.sort(reverse=True) return render_template('index.html', projects=projects) @app.route('/new_project', methods=['GET']) def new_project(): """فرم دریافت متن جدید""" return render_template('new_project.html') @app.route('/process', methods=['POST']) def process_text(): """اجرای الگوریتم پایین به بالا و ساخت درخت با یک ریشه کلان (ROOT)""" text = request.form.get('text') target_count = int(request.form.get('target_segments', 7)) if not text: return redirect(url_for('new_project')) project_name = datetime.now().strftime("%Y-%m-%d_%H-%M-%S") project_path = data_manager.create_project_folder(project_name) # مرحله ۱: استخراج جملات خام اولیه sentences = segmenter.extract_sentences(text) tree_data_list = [] current_level_items = [] for i, s in enumerate(sentences): node_id = f"node_L0_{i}" current_level_items.append({"id": node_id, "text": s}) tree_data_list.append({ "level": 0, "segment_id": node_id, "parent_segment_id": "", "original_sentences": [s], "semantic_unit": s }) level = 1 global_node_counter = 1 # مرحله ۲: سگمنت‌بندی بازگشتی تا رسیدن به تعداد هدف (مثلا 7 سگمنت) while len(current_level_items) > target_count: texts_to_segment = [item["text"] for item in current_level_items] # سگمنت‌بندی داینامیک grouped_segments_texts = segmenter.segment_items(texts_to_segment) # جلوگیری از پرش ناگهانی: اگر تعداد سگمنت‌ها کمتر از هدف شد، آن را وادار کن دقیقاً به اندازه هدف برش بزند if len(grouped_segments_texts) <= target_count: grouped_segments_texts = segmenter.segment_items(texts_to_segment, force_count=target_count) next_level_items = [] pointer = 0 for group in grouped_segments_texts: parent_node_id = f"node_L{level}_{global_node_counter}" global_node_counter += 1 children_ids = [] segment_content = [] for _ in group: child = current_level_items[pointer] children_ids.append(child["id"]) segment_content.append(child["text"]) # ثبت آیدی پدر برای نودهای فرزند for entry in tree_data_list: if entry["segment_id"] == child["id"]: entry["parent_segment_id"] = parent_node_id pointer += 1 # استخراج واحد معنایی semantic_unit = api_handler.get_semantic_unit(segment_content) next_level_items.append({"id": parent_node_id, "text": semantic_unit}) tree_data_list.append({ "level": level, "segment_id": parent_node_id, "parent_segment_id": "", "original_sentences": segment_content, "semantic_unit": semantic_unit }) current_level_items = next_level_items level += 1 # ========================================================================= # مرحله ۳: ساخت ریشه نهایی (ROOT) برای کل متن # اتصال تمامی سگمنت‌های نهایی (مثلا 7 تا) به یک رأس کلی و گرفتن معنای کلان # ========================================================================= if len(current_level_items) > 1: root_node_id = f"node_L{level}_ROOT" root_content = [] for item in current_level_items: root_content.append(item["text"]) for entry in tree_data_list: if entry["segment_id"] == item["id"]: entry["parent_segment_id"] = root_node_id # ارسال کل 7 واحد معنایی به API برای دریافت غایت نهایی متن root_semantic_unit = api_handler.get_semantic_unit(root_content) tree_data_list.append({ "level": level, "segment_id": root_node_id, "parent_segment_id": "", # این نود پدر ندارد "original_sentences": root_content, "semantic_unit": root_semantic_unit }) # ذخیره‌سازی داده‌های درخت و رسم آن data_manager.save_tree_data(project_path, tree_data_list) tree_html_path = os.path.join(project_path, "tree_visualization.html") visualizer.build_tree(tree_data_list, tree_html_path) return redirect(url_for('show_tree', project_name=project_name)) @app.route('/tree/') def show_tree(project_name): """نمایش صفحه وب حاوی درخت سلسله‌مراتبی""" return render_template('tree_view.html', project_name=project_name) @app.route('/tree_iframe/') def tree_iframe(project_name): """سرو کردن فایل HTML درخت برای نمایش در iframe""" project_path = os.path.join(data_manager.base_projects_dir, project_name) tree_html_path = os.path.join(project_path, "tree_visualization.html") return send_file(tree_html_path) @app.route('/graph//') def generate_and_show_graph(project_name, node_id): """ساخت گراف On-Demand در زمان کلیک روی نود (حتی نود ROOT)""" project_path = os.path.join(data_manager.base_projects_dir, project_name) graph_dir = os.path.join(project_path, f"{node_id}_graph") graph_html_path = os.path.join(graph_dir, "graph.html") # اگر از قبل ساخته شده بود، مجدداً پردازش نکن if os.path.exists(graph_html_path): return render_template('graph_view.html', project_name=project_name, node_id=node_id) # خواندن جملات نود از CSV node_sentences = [] tree_csv = os.path.join(project_path, "tree_data.csv") with open(tree_csv, mode='r', encoding='utf-8') as f: reader = csv.DictReader(f) for row in reader: if row["segment_id"] == node_id: node_sentences = json.loads(row["original_sentences"]) break if not node_sentences: return "خطا: دیتای نود یافت نشد.", 404 # ۱. استخراج گزاره‌ها از API raw_props = api_handler.extract_propositions(node_sentences) propositions = [ {"proposition_id": i + 1, "sentence": " ".join(node_sentences), "proposition_text": p} for i, p in enumerate(raw_props) ] # ۲. بررسی تمام روابط دو به دو بین گزاره‌ها relations = [] scores = [] rel_id_counter = 1 for p1, p2 in itertools.combinations(propositions, 2): rel_desc = api_handler.check_relation(p1["proposition_text"], p2["proposition_text"]) if rel_desc and "ارتباط وجود ندارد" not in rel_desc: score = api_handler.score_relation(rel_desc) if score > 0: relations.append({ "relation_id": rel_id_counter, "source_proposition_id": p1["proposition_id"], "target_proposition_id": p2["proposition_id"], "relation_type": rel_desc }) scores.append({ "relation_id": rel_id_counter, "score": score }) rel_id_counter += 1 # ۳. ذخیره و رسم گراف data_manager.save_graph_data(project_path, node_id, propositions, relations, scores) visualizer.build_graph(propositions, relations, scores, graph_html_path) return render_template('graph_view.html', project_name=project_name, node_id=node_id) @app.route('/graph_iframe//') def graph_iframe(project_name, node_id): """سرو کردن فایل HTML گراف برای نمایش در iframe""" project_path = os.path.join(data_manager.base_projects_dir, project_name) graph_html_path = os.path.join(project_path, f"{node_id}_graph", "graph.html") return send_file(graph_html_path) if __name__ == '__main__': for folder in ["projects", "templates", "static"]: if not os.path.exists(folder): os.makedirs(folder) app.run(debug=True, port=5000)