{"id":115,"date":"2024-04-15T09:00:00","date_gmt":"2024-04-15T09:00:00","guid":{"rendered":"https:\/\/www.tb-software.ch\/ai\/kobai-dokumentenmanagement\/"},"modified":"2024-04-15T09:00:00","modified_gmt":"2024-04-15T09:00:00","slug":"kobai-dokumentenmanagement","status":"publish","type":"post","link":"https:\/\/www.tb-software.ch\/ai\/en\/kobai-dokumentenmanagement\/","title":{"rendered":"KOBAI: AI-powered document management at Schott Pharma"},"content":{"rendered":"<h1>KOBAI: AI-powered document management at Schott Pharma<\/h1>\n<p><strong>Winner of the Digital Game-Changer Award 2024<\/strong><\/p>\n<p>The digitalization of the pharmaceutical industry presents unique challenges for data privacy and compliance. With KOBAI, we\u2019ve developed an innovative AI solution that tackles these challenges while dramatically boosting efficiency.<\/p>\n<h2>Project challenge<\/h2>\n<p>Schott Pharma, a leading manufacturer of pharmaceutical packaging, faced the following challenges:<\/p>\n<h3>Initial situation<\/h3>\n<ul>\n<li><strong>document volume<\/strong>&gt;50,000 technical documents<\/li>\n<li><strong>search time<\/strong>Average of 45 minutes per request<\/li>\n<li><strong>Compliance<\/strong>Strict DSGVO and FDA requirements<\/li>\n<li><strong>Confidentiality<\/strong>No cloud solutions allowed<\/li>\n<li><strong>Mehrsprachigkeit<\/strong>: German, English, other EU languages<\/li>\n<\/ul>\n<h3>Business impact<\/h3>\n<ul>\n<li>Delays in product development<\/li>\n<li>High personnel costs for document search<\/li>\n<li>Risk of compliance violations<\/li>\n<li>Inefficient knowledge distribution<\/li>\n<\/ul>\n<h2>Solution approach: KOBAI<\/h2>\n<p><strong>KOBAI<\/strong> (Knowledge Organization with Business AI) is a fully local AI solution based on offline large language models.<\/p>\n<h3>Core components<\/h3>\n<h4>Local LLM integration<\/h4>\n<pre><code class=\"language-python\"># LM Studio Integration\nfrom openai import OpenAI\n\nclass LocalLLMClient:\n    def __init__(self, base_url=\"http:\/\/localhost:1234\/v1\"):\n        self.client = OpenAI(\n            base_url=base_url,\n            api_key=\"lm-studio\"  # Dummy-Key f\u00fcr lokale Instanz\n        )\n    \n    def query_documents(self, question, context):\n        response = self.client.chat.completions.create(\n            model=\"microsoft\/DialoGPT-medium\",  # Lokales Modell\n            messages=[\n                {\"role\": \"system\", \"content\": \"Du bist ein Experte f\u00fcr Pharmadokumentation.\"},\n                {\"role\": \"user\", \"content\": f\"Kontext: {context}nnFrage: {question}\"}\n            ],\n            temperature=0.1,  # Niedrige Temperatur f\u00fcr pr\u00e4zise Antworten\n            max_tokens=500\n        )\n        return response.choices[0].message.content<\/code><\/pre>\n<h4>Document indexing<\/h4>\n<pre><code class=\"language-csharp\">\/\/ C# Backend f\u00fcr Dokumentenverarbeitung\npublic class DocumentProcessor\n{\n    private readonly IVectorDatabase _vectorDb;\n    private readonly ITextExtractor _textExtractor;\n    \n    public async Task&lt;ProcessingResult&gt; ProcessDocument(DocumentInfo doc)\n    {\n        try\n        {\n            \/\/ Text extrahieren\n            var extractedText = await _textExtractor.ExtractAsync(doc.FilePath);\n            \n            \/\/ Chunking f\u00fcr bessere Verarbeitung\n            var chunks = SplitIntoChunks(extractedText, maxChunkSize: 1000);\n            \n            \/\/ Embeddings generieren (lokal)\n            var embeddings = await GenerateEmbeddings(chunks);\n            \n            \/\/ In Vektordatenbank speichern\n            await _vectorDb.StoreAsync(doc.Id, embeddings, chunks);\n            \n            return new ProcessingResult { Success = true, ChunksProcessed = chunks.Count };\n        }\n        catch (Exception ex)\n        {\n            _logger.LogError(ex, \"Fehler bei Dokumentenverarbeitung: {DocumentId}\", doc.Id);\n            return new ProcessingResult { Success = false, Error = ex.Message };\n        }\n    }\n    \n    private List&lt;string&gt; SplitIntoChunks(string text, int maxChunkSize)\n    {\n        var chunks = new List&lt;string&gt;();\n        var sentences = text.Split('.', StringSplitOptions.RemoveEmptyEntries);\n        var currentChunk = new StringBuilder();\n        \n        foreach (var sentence in sentences)\n        {\n            if (currentChunk.Length + sentence.Length &gt; maxChunkSize)\n            {\n                if (currentChunk.Length &gt; 0)\n                {\n                    chunks.Add(currentChunk.ToString().Trim());\n                    currentChunk.Clear();\n                }\n            }\n            currentChunk.Append(sentence + \". \");\n        }\n        \n        if (currentChunk.Length &gt; 0)\n        {\n            chunks.Add(currentChunk.ToString().Trim());\n        }\n        \n        return chunks;\n    }\n}<\/code><\/pre>\n<h4>Semantic search engine<\/h4>\n<pre><code class=\"language-csharp\">public class SemanticSearchEngine\n{\n    private readonly IVectorDatabase _vectorDb;\n    private readonly LocalLLMClient _llmClient;\n    \n    public async Task&lt;SearchResult&gt; SearchAsync(string query, SearchOptions options)\n    {\n        \/\/ Query-Embedding generieren\n        var queryEmbedding = await GenerateQueryEmbedding(query);\n        \n        \/\/ \u00c4hnliche Dokumente finden\n        var similarChunks = await _vectorDb.FindSimilarAsync(\n            queryEmbedding, \n            topK: options.MaxResults,\n            threshold: options.SimilarityThreshold\n        );\n        \n        \/\/ Kontext f\u00fcr LLM aufbauen\n        var context = BuildContext(similarChunks);\n        \n        \/\/ LLM-Antwort generieren\n        var llmResponse = await _llmClient.QueryDocuments(query, context);\n        \n        return new SearchResult\n        {\n            Answer = llmResponse,\n            SourceDocuments = similarChunks.Select(c =&gt; c.DocumentInfo).ToList(),\n            Confidence = CalculateConfidence(similarChunks),\n            ProcessingTime = stopwatch.ElapsedMilliseconds\n        };\n    }\n}<\/code><\/pre>\n<h2>Technical architecture<\/h2>\n<h3>System overview<\/h3>\n<pre><code>\u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510    \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510    \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n\u2502   Web Frontend  \u2502\u2500\u2500\u2500\u2500\u2502   C# Backend     \u2502\u2500\u2500\u2500\u2500\u2502  LM Studio      \u2502\n\u2502   - React       \u2502    \u2502   - .NET 8       \u2502    \u2502  - Offline LLM  \u2502\n\u2502   - TypeScript  \u2502    \u2502   - Entity FW    \u2502    \u2502  - Local API    \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518    \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518    \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n         \u2502                        \u2502                        \u2502\n         \u2502                        \u2502                        \u2502\n\u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510    \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510    \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n\u2502   User Auth     \u2502    \u2502  Vector Database \u2502    \u2502  Document Store \u2502\n\u2502   - Active Dir  \u2502    \u2502  - Chroma DB     \u2502    \u2502  - File System  \u2502\n\u2502   - LDAP        \u2502    \u2502  - Embeddings    \u2502    \u2502  - Metadata DB  \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518    \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518    \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518<\/code><\/pre>\n<h3>Security architecture<\/h3>\n<h4>Privacy features<\/h4>\n<pre><code class=\"language-csharp\">public class SecurityManager\n{\n    public async Task&lt;bool&gt; ValidateAccess(User user, Document document)\n    {\n        \/\/ Rollenbasierte Zugriffskontrolle\n        var userRoles = await GetUserRoles(user.Id);\n        var requiredRoles = document.AccessRequirements;\n        \n        if (!userRoles.Any(r =&gt; requiredRoles.Contains(r)))\n        {\n            await LogAccessDenied(user.Id, document.Id, \"Insufficient roles\");\n            return false;\n        }\n        \n        \/\/ Abteilungsbasierte Filterung\n        if (document.Department != null &amp;&amp; user.Department != document.Department)\n        {\n            await LogAccessDenied(user.Id, document.Id, \"Department mismatch\");\n            return false;\n        }\n        \n        \/\/ Audit-Log\n        await LogDocumentAccess(user.Id, document.Id, DateTime.UtcNow);\n        \n        return true;\n    }\n    \n    public string EncryptSensitiveData(string data)\n    {\n        using var aes = Aes.Create();\n        aes.Key = GetEncryptionKey();\n        aes.IV = GenerateIV();\n        \n        using var encryptor = aes.CreateEncryptor();\n        var dataBytes = Encoding.UTF8.GetBytes(data);\n        var encryptedBytes = encryptor.TransformFinalBlock(dataBytes, 0, dataBytes.Length);\n        \n        return Convert.ToBase64String(encryptedBytes);\n    }\n}<\/code><\/pre>\n<h2>Implementation Details<\/h2>\n<h3>Front-end development<\/h3>\n<pre><code class=\"language-typescript\">\/\/ React-Komponente f\u00fcr intelligente Suche\ninterface SearchComponentProps {\n  onResultsFound: (results: SearchResult[]) =&gt; void;\n}\n\nconst IntelligentSearch: React.FC&lt;SearchComponentProps&gt; = ({ onResultsFound }) =&gt; {\n  const [query, setQuery] = useState('');\n  const [isLoading, setIsLoading] = useState(false);\n  const [suggestions, setSuggestions] = useState&lt;string[]&gt;([]);\n  \n  const handleSearch = async () =&gt; {\n    setIsLoading(true);\n    try {\n      const response = await fetch('\/api\/search', {\n        method: 'POST',\n        headers: { 'Content-Type': 'application\/json' },\n        body: JSON.stringify({ \n          query, \n          options: {\n            maxResults: 10,\n            includeMetadata: true,\n            similarityThreshold: 0.7\n          }\n        })\n      });\n      \n      const results = await response.json();\n      onResultsFound(results);\n    } catch (error) {\n      console.error('Search failed:', error);\n    } finally {\n      setIsLoading(false);\n    }\n  };\n  \n  \/\/ Auto-Suggest Implementation\n  useEffect(() =&gt; {\n    const debounced = debounce(async (searchTerm: string) =&gt; {\n      if (searchTerm.length &gt; 2) {\n        const suggestions = await fetchSuggestions(searchTerm);\n        setSuggestions(suggestions);\n      }\n    }, 300);\n    \n    debounced(query);\n  }, [query]);\n  \n  return (\n    &lt;div className=\"search-container\"&gt;\n      &lt;SearchInput \n        value={query}\n        onChange={setQuery}\n        onSearch={handleSearch}\n        suggestions={suggestions}\n        isLoading={isLoading}\n      \/&gt;\n      &lt;SearchFilters \/&gt;\n      &lt;SearchHistory \/&gt;\n    &lt;\/div&gt;\n  );\n};<\/code><\/pre>\n<h3>Performance Optimization<\/h3>\n<pre><code class=\"language-csharp\">public class CacheManager\n{\n    private readonly IMemoryCache _memoryCache;\n    private readonly IDistributedCache _distributedCache;\n    \n    public async Task&lt;T&gt; GetOrSetAsync&lt;T&gt;(string key, Func&lt;Task&lt;T&gt;&gt; factory, TimeSpan expiration)\n    {\n        \/\/ Erst Memory Cache pr\u00fcfen\n        if (_memoryCache.TryGetValue(key, out T cachedValue))\n        {\n            return cachedValue;\n        }\n        \n        \/\/ Dann Distributed Cache\n        var distributedValue = await _distributedCache.GetStringAsync(key);\n        if (distributedValue != null)\n        {\n            var deserializedValue = JsonSerializer.Deserialize&lt;T&gt;(distributedValue);\n            _memoryCache.Set(key, deserializedValue, TimeSpan.FromMinutes(5));\n            return deserializedValue;\n        }\n        \n        \/\/ Wert generieren und cachen\n        var newValue = await factory();\n        var serializedValue = JsonSerializer.Serialize(newValue);\n        \n        await _distributedCache.SetStringAsync(key, serializedValue, new DistributedCacheEntryOptions\n        {\n            AbsoluteExpirationRelativeToNow = expiration\n        });\n        \n        _memoryCache.Set(key, newValue, TimeSpan.FromMinutes(5));\n        \n        return newValue;\n    }\n}<\/code><\/pre>\n<h2>Deployment and operation<\/h2>\n<h3>Containerization<\/h3>\n<pre><code class=\"language-dockerfile\"># Dockerfile f\u00fcr KOBAI Backend\nFROM mcr.microsoft.com\/dotnet\/aspnet:8.0 AS base\nWORKDIR \/app\nEXPOSE 80\nEXPOSE 443\n\nFROM mcr.microsoft.com\/dotnet\/sdk:8.0 AS build\nWORKDIR \/src\nCOPY [\"KOBAI.API\/KOBAI.API.csproj\", \"KOBAI.API\/\"]\nCOPY [\"KOBAI.Core\/KOBAI.Core.csproj\", \"KOBAI.Core\/\"]\nRUN dotnet restore \"KOBAI.API\/KOBAI.API.csproj\"\n\nCOPY . .\nWORKDIR \"\/src\/KOBAI.API\"\nRUN dotnet build \"KOBAI.API.csproj\" -c Release -o \/app\/build\n\nFROM build AS publish\nRUN dotnet publish \"KOBAI.API.csproj\" -c Release -o \/app\/publish\n\nFROM base AS final\nWORKDIR \/app\nCOPY --from=publish \/app\/publish .\n\n# LM Studio Installation\nRUN apt-get update &amp;&amp; apt-get install -y \n    curl \n    python3 \n    python3-pip\n\n# Lokale LLM-Modelle\nCOPY models\/ \/app\/models\/\n\nENTRYPOINT [\"dotnet\", \"KOBAI.API.dll\"]<\/code><\/pre>\n<h3>Monitoring and logging<\/h3>\n<pre><code class=\"language-csharp\">public class ApplicationInsights\n{\n    private readonly ILogger&lt;ApplicationInsights&gt; _logger;\n    private readonly TelemetryClient _telemetryClient;\n    \n    public void TrackSearchQuery(string query, int resultsCount, long processingTime)\n    {\n        _telemetryClient.TrackEvent(\"SearchQuery\", new Dictionary&lt;string, string&gt;\n        {\n            [\"Query\"] = HashQuery(query), \/\/ Anonymisiert\n            [\"ResultsCount\"] = resultsCount.ToString(),\n            [\"ProcessingTime\"] = processingTime.ToString()\n        });\n        \n        _logger.LogInformation(\"Search completed: {ResultsCount} results in {ProcessingTime}ms\", \n                              resultsCount, processingTime);\n    }\n    \n    public void TrackDocumentAccess(string userId, string documentId)\n    {\n        _telemetryClient.TrackEvent(\"DocumentAccess\", new Dictionary&lt;string, string&gt;\n        {\n            [\"UserId\"] = HashUserId(userId),\n            [\"DocumentType\"] = GetDocumentType(documentId)\n        });\n    }\n}<\/code><\/pre>\n<h2>Results and impact<\/h2>\n<h3>Quantitative improvements<\/h3>\n<ul>\n<li><strong>search time<\/strong>From 45 minutes to 30 seconds (-98.9%)<\/li>\n<li><strong>Hit accuracy<\/strong>: 94% relevant results<\/li>\n<li><strong>User acceptance<\/strong>7% positive ratings<\/li>\n<li><strong>time savings<\/strong>0 hours per week per department<\/li>\n<li><strong>return on investment<\/strong>40% increase in the first year<\/li>\n<\/ul>\n<h3>Qualitative improvements<\/h3>\n<ul>\n<li><strong>knowledge transfer<\/strong>Better dissemination of expert knowledge<\/li>\n<li><strong>Compliance<\/strong>: 100% GDPR-compliant<\/li>\n<li><strong>employee satisfaction<\/strong>Less frustration when searching for documents<\/li>\n<li><strong>Innovation<\/strong>Faster product development through enhanced information access<\/li>\n<\/ul>\n<h3>Technical KPIs<\/h3>\n<pre><code class=\"language-csharp\">public class PerformanceMetrics\n{\n    public class SearchMetrics\n    {\n        public double AverageResponseTime { get; set; } = 847; \/\/ ms\n        public double P95ResponseTime { get; set; } = 1200; \/\/ ms\n        public double AccuracyScore { get; set; } = 0.94;\n        public int QueriesPerDay { get; set; } = 1247;\n    }\n    \n    public class SystemMetrics\n    {\n        public double CpuUtilization { get; set; } = 0.23;\n        public double MemoryUtilization { get; set; } = 0.67;\n        public double DiskUtilization { get; set; } = 0.45;\n        public double Uptime { get; set; } = 0.9998; \/\/ 99.98%\n    }\n}<\/code><\/pre>\n<h2>Award: Digital Game-Changer Award<\/h2>\n<p>KOBAI was awarded the Digital Game-Changer Award in 2024 for:<\/p>\n<ul>\n<li><strong>Innovation<\/strong>First fully local AI solution in the pharmaceutical industry<\/li>\n<li><strong>Impact<\/strong>Dramatic efficiency increase with the highest security standards<\/li>\n<li><strong>scalability<\/strong>Transferability to other regulated industries<\/li>\n<li><strong>Sustainability<\/strong>Reducing CO2 footprint through local processing<\/li>\n<\/ul>\n<h2>Lessons Learned<\/h2>\n<h3>Technical Insights<\/h3>\n<ol>\n<li><strong>Local LLMs<\/strong>: Sufficient quality for business use<\/li>\n<li><strong>Hybrid approach<\/strong>Optimal combination of vector search and LLM<\/li>\n<li><strong>Chunking strategies<\/strong>Key to answer quality<\/li>\n<li><strong>Caching<\/strong>Critical for performance with repeated requests<\/li>\n<\/ol>\n<h3>Organizational insights<\/h3>\n<ol>\n<li><strong>Change Management<\/strong>Intensive training required<\/li>\n<li><strong>Stakeholder engagement<\/strong>Early involvement of all departments<\/li>\n<li><strong>Iterative development<\/strong>Agile methods for AI projects too<\/li>\n<li><strong>Compliance<\/strong>Early involvement of the legal department<\/li>\n<\/ol>\n<h2>Future Development<\/h2>\n<h3>Planned features<\/h3>\n<ul>\n<li><strong>Multimodal search<\/strong>Integration of images and diagrams<\/li>\n<li><strong>Automatic summaries<\/strong>KI-generierte Dokumentenzusammenfassungen<\/li>\n<li><strong>Vorhersagende Suche<\/strong>Vorhersage von Informationsbed\u00fcrfnissen<\/li>\n<li><strong>Integration<\/strong>Verbindung zu anderen Unternehmenssystemen<\/li>\n<\/ul>\n<h3>Skalierung<\/h3>\n<pre><code class=\"language-csharp\">public class ScalingStrategy\n{\n    public async Task&lt;DeploymentPlan&gt; PlanScaling(ScalingRequirements requirements)\n    {\n        return new DeploymentPlan\n        {\n            \/\/ Horizontale Skalierung\n            AdditionalNodes = CalculateRequiredNodes(requirements.ExpectedLoad),\n            \n            \/\/ Vertikale Skalierung\n            ResourceUpgrade = new ResourceUpgrade\n            {\n                CpuCores = requirements.CpuRequirement,\n                MemoryGB = requirements.MemoryRequirement,\n                StorageTB = requirements.StorageRequirement\n            },\n            \n            \/\/ Geografische Verteilung\n            RegionalDeployments = requirements.Regions.Select(r =&gt; new RegionalDeployment\n            {\n                Region = r,\n                LocalLLMModel = SelectOptimalModel(r.Language),\n                ComplianceRequirements = GetRegionalCompliance(r)\n            }).ToList()\n        };\n    }\n}<\/code><\/pre>\n<h2>Conclusion<\/h2>\n<p>KOBAI demonstriert beeindruckend, wie moderne KI-Technologien erfolgreich auch in stark regulierten Umgebungen eingesetzt werden k\u00f6nnen. Der Schl\u00fcssel liegt in der Kombination von technischer Innovation mit strikter Einhaltung von Datenschutz- und Compliance-Anforderungen.<\/p>\n<p>Die Anerkennung des Digital Game-Changer Awards unterstreicht die innovative Natur und den messbaren Gesch\u00e4ftswert der L\u00f6sung. KOBAI ist nicht nur ein technischer Erfolg, sondern ein Beispiel daf\u00fcr, wie KI den Arbeitsplatz positiv transformieren kann.<\/p>\n<p><strong>Interessiert an einer \u00e4hnlichen KI-L\u00f6sung f\u00fcr Ihr Unternehmen?<\/strong> Wir beraten Sie gerne bei der Entwicklung einer ma\u00dfgeschneiderten, DSGVO-konformen KI-Strategie!<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Successful implementation of an AI-based document management system with offline LLMs for maximum data privacy in the pharmaceutical industry.<\/p>\n","protected":false},"author":1,"featured_media":114,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[26],"tags":[25,21,22,19,20,24,23],"class_list":["post-115","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-ki-llms","tag-award","tag-dokumentenmanagement","tag-dsgvo","tag-ki","tag-llm","tag-lm-studio","tag-offline-ai"],"_links":{"self":[{"href":"https:\/\/www.tb-software.ch\/ai\/index.php?rest_route=\/wp\/v2\/posts\/115","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.tb-software.ch\/ai\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.tb-software.ch\/ai\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.tb-software.ch\/ai\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.tb-software.ch\/ai\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=115"}],"version-history":[{"count":0,"href":"https:\/\/www.tb-software.ch\/ai\/index.php?rest_route=\/wp\/v2\/posts\/115\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.tb-software.ch\/ai\/index.php?rest_route=\/wp\/v2\/media\/114"}],"wp:attachment":[{"href":"https:\/\/www.tb-software.ch\/ai\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=115"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.tb-software.ch\/ai\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=115"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.tb-software.ch\/ai\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=115"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}