Spaces:
Build error
Build error
| from fastapi import FastAPI | |
| from fastapi.responses import JSONResponse, HTMLResponse | |
| from fastapi.middleware.cors import CORSMiddleware | |
| import pandas as pd | |
| import networkx as nx | |
| import plotly.graph_objects as go | |
| import re | |
| import os | |
| # ---------- CONFIG ---------- | |
| DATA_FILE = "База философских концептов - База философских концептов.csv" | |
| # ---------- APP SETUP ---------- | |
| app = FastAPI( | |
| title="Philosophy Knowledge Graph", | |
| description="Онтологическая база философских концептов — Knowledge GraphRAG", | |
| version="3.3.0", | |
| ) | |
| app.add_middleware( | |
| CORSMiddleware, | |
| allow_origins=["*"], | |
| allow_credentials=True, | |
| allow_methods=["*"], | |
| allow_headers=["*"], | |
| ) | |
| # ---------- LOAD DATA ---------- | |
| if not os.path.exists(DATA_FILE): | |
| raise FileNotFoundError(f"Файл {DATA_FILE} не найден в корне проекта.") | |
| df = pd.read_csv(DATA_FILE) | |
| df = df.fillna("") | |
| # ---------- BUILD GRAPH ---------- | |
| G = nx.DiGraph() | |
| for _, row in df.iterrows(): | |
| G.add_node( | |
| row["concept"], | |
| definition=row["definition"], | |
| needs=row["needs_level"], | |
| tech=row["tech_problem"] | |
| ) | |
| # регулярка для формата: «A» → «B» | |
| for _, row in df.iterrows(): | |
| relations = re.findall(r'«([^»]+)»\s*[↔→]\s*«([^»]+)»', str(row["relations"])) | |
| for a, b in relations: | |
| if a in G.nodes and b in G.nodes: | |
| G.add_edge(a, b, label=row["tech_problem"]) | |
| # Цвета Маслоу | |
| color_map = { | |
| "Физиологические": "#f4a261", | |
| "Безопасность": "#2a9d8f", | |
| "Принадлежность": "#e9c46a", | |
| "Самоуважение": "#264653", | |
| "Самореализация": "#e76f51" | |
| } | |
| # ---------- PRECOMPUTE LAYOUT ---------- | |
| # БЫСТРЫЙ, ЛЁГКИЙ, НЕ ТРЕБУЕТ SCIPY | |
| POS = nx.spring_layout(G, k=0.7, iterations=30, seed=42) | |
| # ---------- API ---------- | |
| def root(): | |
| return {"message": "Philosophy Knowledge Graph API — работает!"} | |
| def get_concepts(): | |
| return JSONResponse([ | |
| {"concept": n, **G.nodes[n]} | |
| for n in G.nodes() | |
| ]) | |
| def get_relations(): | |
| return JSONResponse([ | |
| {"source": u, "target": v, "label": d.get("label", "")} | |
| for u, v, d in G.edges(data=True) | |
| ]) | |
| def get_jsonld(): | |
| jsonld = { | |
| "@context": { | |
| "concept": "http://example.org/concept", | |
| "definition": "http://example.org/definition", | |
| "relation": "http://example.org/relation" | |
| }, | |
| "@graph": [] | |
| } | |
| for node, data in G.nodes(data=True): | |
| jsonld["@graph"].append({ | |
| "@id": f"http://example.org/{node.replace(' ', '_')}", | |
| "concept": node, | |
| "definition": data.get("definition", ""), | |
| "tech_problem": data.get("tech", ""), | |
| "needs_level": data.get("needs", "") | |
| }) | |
| return JSONResponse(jsonld) | |
| # ---------- INTERACTIVE GRAPH ---------- | |
| def get_graph(): | |
| pos = POS | |
| # --- Рёбра --- | |
| edge_x, edge_y = [], [] | |
| for u, v in G.edges(): | |
| x0, y0 = pos[u] | |
| x1, y1 = pos[v] | |
| edge_x.extend([x0, x1, None]) | |
| edge_y.extend([y0, y1, None]) | |
| edge_trace = go.Scatter( | |
| x=edge_x, | |
| y=edge_y, | |
| mode="lines", | |
| line=dict(width=0.5, color="#888"), | |
| hoverinfo="none", | |
| ) | |
| # --- Узлы --- | |
| node_x, node_y, node_color, node_text = [], [], [], [] | |
| for node, data in G.nodes(data=True): | |
| x, y = pos[node] | |
| node_x.append(x) | |
| node_y.append(y) | |
| node_color.append(color_map.get(data["needs"], "#8d99ae")) | |
| node_text.append( | |
| f"<b>{node}</b><br>{data['definition']}<br><i>{data['tech']}</i>" | |
| ) | |
| node_trace = go.Scatter( | |
| x=node_x, | |
| y=node_y, | |
| mode="markers", | |
| hoverinfo="text", | |
| text=node_text, | |
| marker=dict( | |
| size=12, | |
| color=node_color, | |
| line=dict(width=1) | |
| ), | |
| ) | |
| fig = go.Figure( | |
| data=[edge_trace, node_trace], | |
| layout=go.Layout( | |
| title="Онтологическая база философских концептов", | |
| titlefont=dict(size=20), | |
| showlegend=False, | |
| hovermode="closest", | |
| margin=dict(b=0, l=0, r=0, t=40), | |
| xaxis=dict(showgrid=False, zeroline=False, visible=False), | |
| yaxis=dict(showgrid=False, zeroline=False, visible=False), | |
| ) | |
| ) | |
| return HTMLResponse(fig.to_html(full_html=False)) | |
| # ---------- RUN ---------- | |
| if __name__ == "__main__": | |
| import uvicorn | |
| uvicorn.run(app, host="0.0.0.0", port=7860) | |